Skip to content

Commit 8a84b4b

Browse files
committed
session client UPDATE set module features when parsing
... instead of doing it separately because in specific cases the module may fail to be parsed without its features. Also, make loading new session modules more efficient. Refs #358
1 parent 6ce9c56 commit 8a84b4b

2 files changed

Lines changed: 110 additions & 44 deletions

File tree

src/session_client.c

Lines changed: 103 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,46 @@ free_with_user_data(void *data, void *user_data)
485485
*
486486
* @param[in] mod_name Schema name.
487487
* @param[in] mod_rev Schema revision.
488+
* @param[in] user_data get-schema callback data.
489+
* @param[out] format Schema format.
490+
* @param[out] module_data Schema content.
491+
* @param[out] free_module_data Callback for freeing @p module_data.
492+
* @return LY_ERR value.
493+
*/
494+
static LY_ERR
495+
retrieve_schema_data(const char *mod_name, const char *mod_rev, void *user_data, LYS_INFORMAT *format,
496+
const char **module_data, void (**free_module_data)(void *model_data, void *user_data))
497+
{
498+
struct clb_data_s *clb_data = (struct clb_data_s *)user_data;
499+
char *model_data = NULL;
500+
501+
VRB(clb_data->session, "Retrieving data for schema \"%s\", revision \"%s\".", mod_name, mod_rev ? mod_rev : "<latest>");
502+
503+
/* 1. try to get data locally */
504+
model_data = retrieve_schema_data_localfile(mod_name, mod_rev, clb_data, format);
505+
506+
/* 2. try to use <get-schema> */
507+
if (!model_data && clb_data->has_get_schema) {
508+
model_data = retrieve_schema_data_getschema(mod_name, mod_rev, clb_data, format);
509+
}
510+
511+
/* 3. try to use user callback */
512+
if (!model_data && clb_data->user_clb) {
513+
VRB(clb_data->session, "Reading schema via user callback.");
514+
clb_data->user_clb(mod_name, mod_rev, NULL, NULL, clb_data->user_data, format, (const char **)&model_data,
515+
free_module_data);
516+
}
517+
518+
*free_module_data = free_with_user_data;
519+
*module_data = model_data;
520+
return *module_data ? LY_SUCCESS : LY_ENOTFOUND;
521+
}
522+
523+
/**
524+
* @brief Retrieve YANG import schema content.
525+
*
526+
* @param[in] mod_name Schema name.
527+
* @param[in] mod_rev Schema revision.
488528
* @param[in] submod_name Optional submodule name.
489529
* @param[in] sub_rev Submodule revision.
490530
* @param[in] user_data get-schema callback data.
@@ -494,12 +534,12 @@ free_with_user_data(void *data, void *user_data)
494534
* @return LY_ERR value.
495535
*/
496536
static LY_ERR
497-
retrieve_schema_data(const char *mod_name, const char *mod_rev, const char *submod_name, const char *sub_rev,
537+
retrieve_schema_data_imp(const char *mod_name, const char *mod_rev, const char *submod_name, const char *sub_rev,
498538
void *user_data, LYS_INFORMAT *format, const char **module_data,
499539
void (**free_module_data)(void *model_data, void *user_data))
500540
{
501541
struct clb_data_s *clb_data = (struct clb_data_s *)user_data;
502-
unsigned int u, v, match = 1;
542+
uint32_t u, v, match = 1;
503543
const char *name = NULL, *rev = NULL;
504544
char *model_data = NULL;
505545

@@ -519,7 +559,7 @@ retrieve_schema_data(const char *mod_name, const char *mod_rev, const char *subm
519559
if (!match) {
520560
/* valid situation if we are retrieving YANG 1.1 schema and have only capabilities for now
521561
* (when loading ietf-datastore for ietf-yang-library) */
522-
VRB(clb_data->session, "Unable to identify revision of the schema \"%s\" from "
562+
VRB(clb_data->session, "Unable to identify revision of the import schema \"%s\" from "
523563
"the available server side information.", mod_name);
524564
}
525565
}
@@ -530,15 +570,15 @@ retrieve_schema_data(const char *mod_name, const char *mod_rev, const char *subm
530570
} else if (match) {
531571
if (!clb_data->schemas[match - 1].submodules) {
532572
VRB(clb_data->session, "Unable to identify revision of the requested submodule \"%s\", "
533-
"in schema \"%s\", from the available server side information.", submod_name, mod_name);
573+
"in import schema \"%s\", from the available server side information.", submod_name, mod_name);
534574
} else {
535575
for (v = 0; clb_data->schemas[match - 1].submodules[v].name; ++v) {
536576
if (!strcmp(submod_name, clb_data->schemas[match - 1].submodules[v].name)) {
537577
rev = sub_rev = clb_data->schemas[match - 1].submodules[v].revision;
538578
}
539579
}
540580
if (!rev) {
541-
ERR(clb_data->session, "Requested submodule \"%s\" is not known for schema \"%s\" on server side.",
581+
ERR(clb_data->session, "Requested submodule \"%s\" is not found in import schema \"%s\" on server side.",
542582
submod_name, mod_name);
543583
return LY_ENOTFOUND;
544584
}
@@ -549,11 +589,10 @@ retrieve_schema_data(const char *mod_name, const char *mod_rev, const char *subm
549589
rev = mod_rev;
550590
}
551591

552-
VRB(clb_data->session, "Retrieving data for schema \"%s\", revision \"%s\".", name, rev ? rev : "<latest>");
592+
VRB(clb_data->session, "Retrieving data for import schema \"%s\", revision \"%s\".", name, rev ? rev : "<latest>");
553593

554594
if (match) {
555-
/* we have enough information to avoid communication with server and try to get
556-
* the schema locally */
595+
/* we have enough information to avoid communication with server and try to get the schema locally */
557596

558597
/* 1. try to get data locally */
559598
model_data = retrieve_schema_data_localfile(name, rev, clb_data, format);
@@ -598,6 +637,7 @@ retrieve_schema_data(const char *mod_name, const char *mod_rev, const char *subm
598637
* @param[in] session NC session.
599638
* @param[in] name Schema name.
600639
* @param[in] revision Schema revision.
640+
* @param[in] features Enabled schema features.
601641
* @param[in] schemas Server schema info built from capabilities.
602642
* @param[in] user_clb User callback for retireving schema data.
603643
* @param[in] user_data User data for @p user_clb.
@@ -607,28 +647,33 @@ retrieve_schema_data(const char *mod_name, const char *mod_rev, const char *subm
607647
* @return -1 on error.
608648
*/
609649
static int
610-
nc_ctx_load_module(struct nc_session *session, const char *name, const char *revision, struct schema_info *schemas,
611-
ly_module_imp_clb user_clb, void *user_data, int has_get_schema, struct lys_module **mod)
650+
nc_ctx_load_module(struct nc_session *session, const char *name, const char *revision, const char **features,
651+
struct schema_info *schemas, ly_module_imp_clb user_clb, void *user_data, int has_get_schema, struct lys_module **mod)
612652
{
613653
int ret = 0;
614654
struct ly_err_item *eitem;
615655
const char *module_data = NULL;
656+
struct ly_in *in;
616657
LYS_INFORMAT format;
617658

618659
void (*free_module_data)(void *, void *) = NULL;
619660
struct clb_data_s clb_data;
620661

621-
*mod = NULL;
662+
/* try to use a module from the context */
622663
if (revision) {
623664
*mod = ly_ctx_get_module(session->ctx, name, revision);
665+
} else {
666+
*mod = ly_ctx_get_module_implemented(session->ctx, name);
667+
if (!*mod) {
668+
*mod = ly_ctx_get_module_latest(session->ctx, name);
669+
}
624670
}
671+
625672
if (*mod) {
626-
if (!(*mod)->implemented) {
627-
/* make the present module implemented */
628-
if (lys_set_implemented(*mod, NULL)) {
629-
ERR(session, "Failed to implement model \"%s\".", (*mod)->name);
630-
ret = -1;
631-
}
673+
/* make the present module implemented and/or enable all its features */
674+
if (lys_set_implemented(*mod, features)) {
675+
ERR(session, "Failed to implement schema \"%s\".", (*mod)->name);
676+
ret = -1;
632677
}
633678
} else {
634679
/* missing implemented module, load it ... */
@@ -643,13 +688,16 @@ nc_ctx_load_module(struct nc_session *session, const char *name, const char *rev
643688
ly_log_options(LY_LOSTORE);
644689

645690
/* get module data */
646-
retrieve_schema_data(name, revision, NULL, NULL, &clb_data, &format, &module_data, &free_module_data);
691+
retrieve_schema_data(name, revision, &clb_data, &format, &module_data, &free_module_data);
647692

648693
if (module_data) {
649-
/* parse the schema */
650-
ly_ctx_set_module_imp_clb(session->ctx, retrieve_schema_data, &clb_data);
694+
/* set import callback */
695+
ly_ctx_set_module_imp_clb(session->ctx, retrieve_schema_data_imp, &clb_data);
651696

652-
lys_parse_mem(session->ctx, module_data, format, mod);
697+
/* parse the schema */
698+
ly_in_new_memory(module_data, &in);
699+
lys_parse(session->ctx, in, format, features, mod);
700+
ly_in_free(in, 0);
653701
if (*free_module_data) {
654702
(*free_module_data)((char *)module_data, user_data);
655703
}
@@ -660,13 +708,13 @@ nc_ctx_load_module(struct nc_session *session, const char *name, const char *rev
660708
/* restore logging options, then print errors on definite failure */
661709
ly_log_options(LY_LOLOG | LY_LOSTORE_LAST);
662710
if (!(*mod)) {
663-
for (eitem = ly_err_first(session->ctx); eitem && eitem->next; eitem = eitem->next) {
711+
for (eitem = ly_err_first(session->ctx); eitem; eitem = eitem->next) {
664712
ly_err_print(session->ctx, eitem);
665713
}
666714
ret = -1;
667715
} else {
668716
/* print only warnings */
669-
for (eitem = ly_err_first(session->ctx); eitem && eitem->next; eitem = eitem->next) {
717+
for (eitem = ly_err_first(session->ctx); eitem; eitem = eitem->next) {
670718
if (eitem->level == LY_LLWRN) {
671719
ly_err_print(session->ctx, eitem);
672720
}
@@ -985,7 +1033,8 @@ nc_ctx_fill(struct nc_session *session, struct schema_info *modules, ly_module_i
9851033
}
9861034

9871035
/* we can continue even if it fails */
988-
nc_ctx_load_module(session, modules[u].name, modules[u].revision, modules, user_clb, user_data, has_get_schema, &mod);
1036+
nc_ctx_load_module(session, modules[u].name, modules[u].revision, (const char **)modules[u].features, modules,
1037+
user_clb, user_data, has_get_schema, &mod);
9891038

9901039
if (!mod) {
9911040
if (session->status != NC_STATUS_RUNNING) {
@@ -998,9 +1047,6 @@ nc_ctx_fill(struct nc_session *session, struct schema_info *modules, ly_module_i
9981047
WRN(session, "Failed to load schema \"%s@%s\".", modules[u].name, modules[u].revision ?
9991048
modules[u].revision : "<latest>");
10001049
session->flags |= NC_SESSION_CLIENT_NOT_STRICT;
1001-
} else {
1002-
/* set the features */
1003-
lys_set_implemented(mod, (const char **)modules[u].features);
10041050
}
10051051
}
10061052

@@ -1027,29 +1073,41 @@ nc_ctx_fill_ietf_netconf(struct nc_session *session, struct schema_info *modules
10271073
void *user_data, int has_get_schema)
10281074
{
10291075
uint32_t u;
1076+
const char **features = NULL;
1077+
struct ly_in *in;
10301078
struct lys_module *ietfnc;
10311079

1080+
/* find supported features (capabilities) in ietf-netconf */
1081+
for (u = 0; modules[u].name; ++u) {
1082+
if (!strcmp(modules[u].name, "ietf-netconf")) {
1083+
assert(modules[u].implemented);
1084+
features = (const char **)modules[u].features;
1085+
break;
1086+
}
1087+
}
1088+
if (!modules[u].name) {
1089+
ERR(session, "Base NETCONF schema not supported by the server.");
1090+
return -1;
1091+
}
1092+
10321093
ietfnc = ly_ctx_get_module_implemented(session->ctx, "ietf-netconf");
1033-
if (!ietfnc) {
1034-
nc_ctx_load_module(session, "ietf-netconf", NULL, modules, user_clb, user_data, has_get_schema, &ietfnc);
1094+
if (ietfnc) {
1095+
/* make sure to enable all the features if already loaded */
1096+
lys_set_implemented(ietfnc, features);
1097+
} else {
1098+
/* load the module */
1099+
nc_ctx_load_module(session, "ietf-netconf", NULL, features, modules, user_clb, user_data, has_get_schema, &ietfnc);
10351100
if (!ietfnc) {
1036-
lys_parse_mem(session->ctx, ietf_netconf_2013_09_29_yang, LYS_IN_YANG, &ietfnc);
1101+
ly_in_new_memory(ietf_netconf_2013_09_29_yang, &in);
1102+
lys_parse(session->ctx, in, LYS_IN_YANG, features, &ietfnc);
1103+
ly_in_free(in, 0);
10371104
}
10381105
}
10391106
if (!ietfnc) {
10401107
ERR(session, "Loading base NETCONF schema failed.");
10411108
return -1;
10421109
}
10431110

1044-
/* set supported capabilities from ietf-netconf */
1045-
for (u = 0; modules[u].name; ++u) {
1046-
if (strcmp(modules[u].name, "ietf-netconf") || !modules[u].implemented) {
1047-
continue;
1048-
}
1049-
1050-
lys_set_implemented(ietfnc, (const char **)modules[u].features);
1051-
}
1052-
10531111
return 0;
10541112
}
10551113

@@ -1127,15 +1185,15 @@ nc_ctx_check_and_fill(struct nc_session *session)
11271185
yanglib_support = 0;
11281186
} else {
11291187
revision = strndup(&revision[9], 10);
1130-
if (nc_ctx_load_module(session, "ietf-yang-library", revision, server_modules, old_clb, old_data,
1188+
if (nc_ctx_load_module(session, "ietf-yang-library", revision, NULL, server_modules, old_clb, old_data,
11311189
get_schema_support, &mod)) {
11321190
WRN(session, "Loading NETCONF ietf-yang-library schema failed, unable to use it to learn all "
11331191
"the supported modules.");
11341192
yanglib_support = 0;
11351193
}
11361194
if (strcmp(revision, "2019-01-04") >= 0) {
11371195
/* we also need ietf-datastores to be implemented */
1138-
if (nc_ctx_load_module(session, "ietf-datastores", NULL, server_modules, old_clb, old_data,
1196+
if (nc_ctx_load_module(session, "ietf-datastores", NULL, NULL, server_modules, old_clb, old_data,
11391197
get_schema_support, &mod)) {
11401198
WRN(session, "Loading NETCONF ietf-datastores schema failed, unable to use yang-library "
11411199
"to learn all the supported modules.");
@@ -1145,10 +1203,12 @@ nc_ctx_check_and_fill(struct nc_session *session)
11451203
free(revision);
11461204

11471205
/* ietf-netconf-nmda is needed to issue get-data */
1148-
if (!nc_ctx_load_module(session, "ietf-netconf-nmda", NULL, server_modules, old_clb, old_data,
1206+
if (!nc_ctx_load_module(session, "ietf-netconf-nmda", NULL, NULL, server_modules, old_clb, old_data,
11491207
get_schema_support, &mod)) {
1150-
VRB(session, "Support for <get-data> from ietf-netcon-nmda found.");
1208+
VRB(session, "Support for <get-data> from ietf-netconf-nmda found.");
11511209
get_data_support = 1;
1210+
} else {
1211+
VRB(session, "Support for <get-data> from ietf-netconf-nmda not found.");
11521212
}
11531213
}
11541214
}

tests/test_thread_messages.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,15 @@ server_thread(void *arg)
9090
ps = nc_ps_new();
9191
nc_assert(ps);
9292
nc_ps_add_session(ps, sess);
93+
94+
/* get for ietf-yang-library data; delete-config in test */
95+
poll = nc_ps_poll(ps, 1000, &sess);
96+
nc_assert(poll == NC_PSPOLL_RPC);
9397
poll = nc_ps_poll(ps, 1000, &sess);
94-
nc_server_notif_send(sess, notif, 1000);
9598
nc_assert(poll == NC_PSPOLL_RPC);
99+
100+
nc_server_notif_send(sess, notif, 1000);
101+
96102
nc_ps_clear(ps, 1, NULL);
97103
nc_ps_free(ps);
98104

0 commit comments

Comments
 (0)