Skip to content

Commit f7aeeae

Browse files
authored
context UPDATE run-time plugin support (#2213)
* 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 * Refactored based on PR comments
1 parent 2063f20 commit f7aeeae

18 files changed

+257
-79
lines changed

src/context.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1384,7 +1384,11 @@ ly_ctx_destroy(struct ly_ctx *ctx)
13841384
/* LYB hash lock */
13851385
pthread_mutex_destroy(&ctx->lyb_hash_lock);
13861386

1387-
/* plugins - will be removed only if this is the last context */
1387+
/* context specific plugins */
1388+
ly_set_erase(&ctx->plugins_types, NULL);
1389+
ly_set_erase(&ctx->plugins_extensions, NULL);
1390+
1391+
/* shared plugins - will be removed only if this is the last context */
13881392
lyplg_clean();
13891393

13901394
free(ctx);

src/ly_common.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,8 @@ struct ly_ctx {
356356
struct ly_ht *err_ht; /**< hash table of thread-specific list of errors related to the context */
357357
pthread_mutex_t lyb_hash_lock; /**< lock for storing LYB schema hashes in schema nodes */
358358
struct ly_ht *leafref_links_ht; /**< hash table of leafref links between term data nodes */
359+
struct ly_set plugins_types; /**< context specific set of type plugins */
360+
struct ly_set plugins_extensions; /**< contets specific set of extension plugins */
359361
};
360362

361363
/**

src/plugins.c

Lines changed: 132 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -130,21 +130,22 @@ static struct ly_set plugins_extensions = {0};
130130
/**
131131
* @brief Iterate over list of loaded plugins of the given @p type.
132132
*
133+
* @param[in] ctx The context for which the plugin is searched for
133134
* @param[in] type Type of the plugins to iterate.
134135
* @param[in,out] index The iterator - set to 0 for the first call.
135136
* @return The plugin records, NULL if no more record is available.
136137
*/
137138
static struct lyplg_record *
138-
plugins_iter(enum LYPLG type, uint32_t *index)
139+
plugins_iter(const struct ly_ctx *ctx, enum LYPLG type, uint32_t *index)
139140
{
140-
struct ly_set *plugins;
141+
const struct ly_set *plugins;
141142

142143
assert(index);
143144

144145
if (type == LYPLG_EXTENSION) {
145-
plugins = &plugins_extensions;
146+
plugins = ctx ? &ctx->plugins_extensions : &plugins_extensions;
146147
} else {
147-
plugins = &plugins_types;
148+
plugins = ctx ? &ctx->plugins_types : &plugins_types;
148149
}
149150

150151
if (*index == plugins->count) {
@@ -156,15 +157,15 @@ plugins_iter(enum LYPLG type, uint32_t *index)
156157
}
157158

158159
static void *
159-
lyplg_record_find(enum LYPLG type, const char *module, const char *revision, const char *name)
160+
lyplg_record_find(const struct ly_ctx *ctx, enum LYPLG type, const char *module, const char *revision, const char *name)
160161
{
161162
uint32_t i = 0;
162163
struct lyplg_record *item;
163164

164165
assert(module);
165166
assert(name);
166167

167-
while ((item = plugins_iter(type, &i)) != NULL) {
168+
while ((item = plugins_iter(ctx, type, &i)) != NULL) {
168169
if (!strcmp(item->module, module) && !strcmp(item->name, name)) {
169170
if (item->revision && revision && strcmp(item->revision, revision)) {
170171
continue;
@@ -180,47 +181,77 @@ lyplg_record_find(enum LYPLG type, const char *module, const char *revision, con
180181
}
181182

182183
struct lyplg_type *
183-
lyplg_type_plugin_find(const char *module, const char *revision, const char *name)
184+
lyplg_type_plugin_find(const struct ly_ctx *ctx, const char *module, const char *revision, const char *name)
184185
{
185-
struct lyplg_record *record;
186+
struct lyplg_record *record = NULL;
187+
188+
if (ctx) {
189+
/* try to find context specific plugin */
190+
record = lyplg_record_find(ctx, LYPLG_TYPE, module, revision, name);
191+
}
192+
193+
if (!record) {
194+
/* try to find shared plugin */
195+
record = lyplg_record_find(NULL, LYPLG_TYPE, module, revision, name);
196+
}
186197

187-
record = lyplg_record_find(LYPLG_TYPE, module, revision, name);
188198
return record ? &((struct lyplg_type_record *)record)->plugin : NULL;
189199
}
190200

191201
struct lyplg_ext_record *
192-
lyplg_ext_record_find(const char *module, const char *revision, const char *name)
202+
lyplg_ext_record_find(const struct ly_ctx *ctx, const char *module, const char *revision, const char *name)
193203
{
194-
return lyplg_record_find(LYPLG_EXTENSION, module, revision, name);
204+
struct lyplg_ext_record *record = NULL;
205+
206+
if (ctx) {
207+
/* try to find context specific plugin */
208+
record = lyplg_record_find(ctx, LYPLG_EXTENSION, module, revision, name);
209+
}
210+
211+
if (!record) {
212+
/* try to find shared plugin */
213+
record = lyplg_record_find(NULL, LYPLG_EXTENSION, module, revision, name);
214+
}
215+
216+
return record;
195217
}
196218

197219
/**
198220
* @brief Insert the provided extension plugin records into the internal set of extension plugins for use by libyang.
199221
*
222+
* @param[in] ctx The context to which the plugin should be associated with. If NULL, the plugin is considered to be shared
223+
* between all existing contexts.
224+
* @param[in] type The type of plugins records
200225
* @param[in] recs An array of plugin records provided by the plugin implementation. The array must be terminated by a zeroed
201226
* record.
202227
* @return LY_SUCCESS in case of success
203228
* @return LY_EINVAL for invalid information in @p recs.
204229
* @return LY_EMEM in case of memory allocation failure.
205230
*/
206231
static LY_ERR
207-
plugins_insert(enum LYPLG type, const void *recs)
232+
plugins_insert(struct ly_ctx *ctx, enum LYPLG type, const void *recs)
208233
{
234+
struct ly_set *plugins;
235+
209236
if (!recs) {
210237
return LY_SUCCESS;
211238
}
212239

213240
if (type == LYPLG_EXTENSION) {
214241
const struct lyplg_ext_record *rec = (const struct lyplg_ext_record *)recs;
215242

243+
plugins = ctx ? &ctx->plugins_extensions : &plugins_extensions;
244+
216245
for (uint32_t i = 0; rec[i].name; i++) {
217-
LY_CHECK_RET(ly_set_add(&plugins_extensions, (void *)&rec[i], 0, NULL));
246+
LY_CHECK_RET(ly_set_add(plugins, (void *)&rec[i], 0, NULL));
218247
}
219248
} else { /* LYPLG_TYPE */
220249
const struct lyplg_type_record *rec = (const struct lyplg_type_record *)recs;
221250

251+
plugins = ctx ? &ctx->plugins_types : &plugins_types;
252+
222253
for (uint32_t i = 0; rec[i].name; i++) {
223-
LY_CHECK_RET(ly_set_add(&plugins_types, (void *)&rec[i], 0, NULL));
254+
LY_CHECK_RET(ly_set_add(plugins, (void *)&rec[i], 0, NULL));
224255
}
225256
}
226257

@@ -329,7 +360,7 @@ plugins_load(void *dlhandler, const char *pathname, enum LYPLG type)
329360
}
330361

331362
/* ... and load all the types plugins */
332-
LY_CHECK_RET(plugins_insert(type, plugins));
363+
LY_CHECK_RET(plugins_insert(NULL, type, plugins));
333364
}
334365

335366
return LY_SUCCESS;
@@ -457,48 +488,48 @@ lyplg_init(ly_bool builtin_type_plugins_only)
457488
}
458489

459490
/* internal types */
460-
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_binary), error);
461-
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_bits), error);
462-
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_boolean), error);
463-
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_decimal64), error);
464-
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_empty), error);
465-
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_enumeration), error);
466-
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_identityref), error);
467-
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_instanceid), error);
468-
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_integer), error);
469-
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_leafref), error);
470-
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_string), error);
471-
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_union), error);
491+
LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_binary), error);
492+
LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_bits), error);
493+
LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_boolean), error);
494+
LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_decimal64), error);
495+
LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_empty), error);
496+
LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_enumeration), error);
497+
LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_identityref), error);
498+
LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_instanceid), error);
499+
LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_integer), error);
500+
LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_leafref), error);
501+
LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_string), error);
502+
LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_union), error);
472503

473504
if (!builtin_type_plugins_only) {
474505
/* yang */
475-
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_instanceid_keys), error);
506+
LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_instanceid_keys), error);
476507

477508
/* ietf-inet-types */
478-
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_address), error);
479-
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_address_no_zone), error);
480-
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_address), error);
481-
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_address_no_zone), error);
482-
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_prefix), error);
483-
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_prefix), error);
509+
LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_ipv4_address), error);
510+
LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_ipv4_address_no_zone), error);
511+
LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_ipv6_address), error);
512+
LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_ipv6_address_no_zone), error);
513+
LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_ipv4_prefix), error);
514+
LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_ipv6_prefix), error);
484515

485516
/* ietf-yang-types */
486-
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_date_and_time), error);
487-
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_hex_string), error);
488-
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_xpath10), error);
517+
LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_date_and_time), error);
518+
LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_hex_string), error);
519+
LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_xpath10), error);
489520

490521
/* ietf-netconf-acm */
491-
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_node_instanceid), error);
522+
LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_node_instanceid), error);
492523

493524
/* lyds_tree */
494-
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_lyds_tree), error);
525+
LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_lyds_tree), error);
495526

496527
/* internal extensions */
497-
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_metadata), error);
498-
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_nacm), error);
499-
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_yangdata), error);
500-
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_schema_mount), error);
501-
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_structure), error);
528+
LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_EXTENSION, plugins_metadata), error);
529+
LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_EXTENSION, plugins_nacm), error);
530+
LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_EXTENSION, plugins_yangdata), error);
531+
LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_EXTENSION, plugins_schema_mount), error);
532+
LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_EXTENSION, plugins_structure), error);
502533
}
503534

504535
#ifndef STATIC
@@ -562,3 +593,60 @@ lyplg_add(const char *pathname)
562593
return ret;
563594
#endif
564595
}
596+
597+
/**
598+
* @brief Manually load an extension plugins from memory
599+
*
600+
* Note, that a plugin can be loaded only if there is at least one context. The loaded plugins are connected with the
601+
* existence of a context. When all the contexts are destroyed, all the plugins are unloaded.
602+
*
603+
* @param[in] ctx The context to which the plugin should be associated with. If NULL, the plugin is considered to be shared
604+
* between all existing contexts.
605+
* @param[in] version The version of plugin records.
606+
* @param[in] type The type of plugins records.
607+
* @param[in] recs An array of plugin records provided by the plugin implementation. The array must be terminated by a zeroed
608+
* record.
609+
*
610+
* @return LY_SUCCESS if the plugins with compatible version were successfully loaded.
611+
* @return LY_EDENIED in case there is no context and the plugin cannot be loaded.
612+
* @return LY_EINVAL when recs is NULL or the plugin contains invalid content for this libyang version.
613+
*/
614+
static LY_ERR
615+
lyplg_add_plugin(struct ly_ctx *ctx, uint32_t version, enum LYPLG type, const void *recs)
616+
{
617+
LY_ERR ret = LY_SUCCESS;
618+
619+
LY_CHECK_ARG_RET(NULL, recs, LY_EINVAL);
620+
621+
if (version != plugins_load_info[type].apiver) {
622+
LOGERR(ctx, LY_EINVAL, "Adding user %s plugin failed, wrong API version - %d expected, %d found.",
623+
plugins_load_info[type].id, plugins_load_info[type].apiver, version);
624+
return LY_EINVAL;
625+
}
626+
627+
/* works only in case a context exists */
628+
pthread_mutex_lock(&plugins_guard);
629+
if (!context_refcount) {
630+
/* no context */
631+
pthread_mutex_unlock(&plugins_guard);
632+
LOGERR(NULL, LY_EDENIED, "To add a plugin, at least one context must exists.");
633+
return LY_EDENIED;
634+
}
635+
636+
plugins_insert(ctx, type, recs);
637+
pthread_mutex_unlock(&plugins_guard);
638+
639+
return ret;
640+
}
641+
642+
LIBYANG_API_DEF LY_ERR
643+
lyplg_add_extension_plugin(struct ly_ctx *ctx, uint32_t version, const struct lyplg_ext_record *recs)
644+
{
645+
return lyplg_add_plugin(ctx, version, LYPLG_EXTENSION, recs);
646+
}
647+
648+
LIBYANG_API_DEF LY_ERR
649+
lyplg_add_type_plugin(struct ly_ctx *ctx, uint32_t version, const struct lyplg_type_record *recs)
650+
{
651+
return lyplg_add_plugin(ctx, version, LYPLG_TYPE, recs);
652+
}

src/plugins.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717

1818
#include "log.h"
1919

20+
struct lyplg_ext_record;
21+
struct lyplg_type_record;
22+
2023
#ifdef __cplusplus
2124
extern "C" {
2225
#endif
@@ -85,6 +88,41 @@ enum LYPLG {
8588
*/
8689
LIBYANG_API_DECL LY_ERR lyplg_add(const char *pathname);
8790

91+
/**
92+
* @brief Manually load extension plugins from memory
93+
*
94+
* Note, that a plugin can be loaded only if there is at least one context. The loaded plugins are connected with the
95+
* existence of a context. When all the contexts are destroyed, all the plugins are unloaded.
96+
*
97+
* @param[in] ctx The context to which the plugin should be associated with. If NULL, the plugin is considered to be shared
98+
* between all existing contexts.
99+
* @param[in] version The version of plugin records.
100+
* @param[in] recs An array of plugin records provided by the plugin implementation. The array must be terminated by a zeroed
101+
* record.
102+
*
103+
* @return LY_SUCCESS if the plugins with compatible version were successfully loaded.
104+
* @return LY_EDENIED in case there is no context and the plugin cannot be loaded.
105+
* @return LY_EINVAL when recs is NULL or the plugin contains invalid content for this libyang version.
106+
*/
107+
LIBYANG_API_DECL LY_ERR lyplg_add_extension_plugin(struct ly_ctx *ctx, uint32_t version, const struct lyplg_ext_record *recs);
108+
109+
/**
110+
* @brief Manually load type plugins from memory
111+
*
112+
* Note, that a plugin can be loaded only if there is at least one context. The loaded plugins are connected with the
113+
* existence of a context. When all the contexts are destroyed, all the plugins are unloaded.
114+
*
115+
* @param[in] ctx The context to which the plugin should be associated with. If NULL, the plugin is considered to be shared
116+
* between all existing contexts.
117+
* @param[in] version The version of plugin records.
118+
* @param[in] recs An array of plugin records provided by the plugin implementation. The array must be terminated by a zeroed
119+
* record.
120+
*
121+
* @return LY_SUCCESS if the plugins with compatible version were successfully loaded.
122+
* @return LY_EDENIED in case there is no context and the plugin cannot be loaded.
123+
* @return LY_EINVAL when recs is NULL or the plugin contains invalid content for this libyang version.
124+
*/
125+
LIBYANG_API_DECL LY_ERR lyplg_add_type_plugin(struct ly_ctx *ctx, uint32_t version, const struct lyplg_type_record *recs);
88126
/** @} plugins */
89127

90128
#ifdef __cplusplus

src/plugins_internal.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,24 +63,26 @@ void lyplg_clean(void);
6363
/**
6464
* @brief Find a type plugin.
6565
*
66+
* @param[in] ctx The optional context for which the plugin should be find. If NULL, only shared plugins will be searched
6667
* @param[in] module Name of the module where the type is defined. Must not be NULL, in case of plugins for
6768
* built-in types, the module is "".
6869
* @param[in] revision Revision of the module for which the plugin is implemented. NULL is not a wildcard, it matches
6970
* only the plugins with NULL revision specified.
7071
* @param[in] name Name of the type which the plugin implements.
7172
* @return Found type plugin, NULL if none found.
7273
*/
73-
struct lyplg_type *lyplg_type_plugin_find(const char *module, const char *revision, const char *name);
74+
struct lyplg_type *lyplg_type_plugin_find(const struct ly_ctx *ctx, const char *module, const char *revision, const char *name);
7475

7576
/**
7677
* @brief Find an extension plugin.
7778
*
79+
* @param[in] ctx The optional context for which the plugin should be find. If NULL, only shared plugins will be searched
7880
* @param[in] module Name of the module where the extension is defined.
7981
* @param[in] revision Revision of the module for which the plugin is implemented. NULL is not a wildcard, it matches
8082
* only the plugins with NULL revision specified.
8183
* @param[in] name Name of the extension which the plugin implements.
8284
* @return Found extension record, NULL if none found.
8385
*/
84-
struct lyplg_ext_record *lyplg_ext_record_find(const char *module, const char *revision, const char *name);
86+
struct lyplg_ext_record *lyplg_ext_record_find(const struct ly_ctx *ctx, const char *module, const char *revision, const char *name);
8587

8688
#endif /* LY_PLUGINS_INTERNAL_H_ */

0 commit comments

Comments
 (0)