Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding context based extensions plugins support #2213

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/context.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions src/ly_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
};

/**
Expand Down
147 changes: 103 additions & 44 deletions src/plugins.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -156,15 +157,15 @@ 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;

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;
Expand All @@ -180,47 +181,77 @@ 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
* @return LY_EINVAL for invalid information in @p recs.
* @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;
}

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));
}
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
}
18 changes: 18 additions & 0 deletions src/plugins.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
michalvasko marked this conversation as resolved.
Show resolved Hide resolved
/** @} plugins */

#ifdef __cplusplus
Expand Down
6 changes: 4 additions & 2 deletions src/plugins_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,24 +63,26 @@ 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
* only the plugins with NULL revision specified.
* @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_ */
6 changes: 3 additions & 3 deletions src/schema_compile_node.c
Original file line number Diff line number Diff line change
Expand Up @@ -2263,15 +2263,15 @@ 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 */
plugin = base->plugin;
}
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);

Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/tree_schema.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down
Loading
Loading