forked from Mirror/frr
lib: nb: fix oper-state queries that involve choice/case nodes
Signed-off-by: Christian Hopps <chopps@labn.net>
This commit is contained in:
parent
67985ba8ec
commit
b9ff10b086
|
@ -140,6 +140,11 @@ nb_op_create_yield_state(const char *xpath, struct yang_translator *translator,
|
||||||
|
|
||||||
ys = XCALLOC(MTYPE_NB_YIELD_STATE, sizeof(*ys));
|
ys = XCALLOC(MTYPE_NB_YIELD_STATE, sizeof(*ys));
|
||||||
ys->xpath = darr_strdup_cap(xpath, (size_t)XPATH_MAXLEN);
|
ys->xpath = darr_strdup_cap(xpath, (size_t)XPATH_MAXLEN);
|
||||||
|
/* remove trailing '/'s */
|
||||||
|
while (darr_len(ys->xpath) > 1 && ys->xpath[darr_len(ys->xpath) - 2] == '/') {
|
||||||
|
darr_setlen(ys->xpath, darr_len(ys->xpath) - 1);
|
||||||
|
*darr_last(ys->xpath) = 0;
|
||||||
|
}
|
||||||
ys->xpath_orig = darr_strdup(xpath);
|
ys->xpath_orig = darr_strdup(xpath);
|
||||||
ys->translator = translator;
|
ys->translator = translator;
|
||||||
ys->flags = flags;
|
ys->flags = flags;
|
||||||
|
@ -417,8 +422,7 @@ static enum nb_error nb_op_ys_finalize_node_info(struct nb_op_yield_state *ys,
|
||||||
/* Assert that we are walking the rightmost branch */
|
/* Assert that we are walking the rightmost branch */
|
||||||
assert(!inner->parent || inner == inner->parent->child->prev);
|
assert(!inner->parent || inner == inner->parent->child->prev);
|
||||||
|
|
||||||
if (CHECK_FLAG(inner->schema->nodetype,
|
if (CHECK_FLAG(inner->schema->nodetype, LYS_CONTAINER)) {
|
||||||
LYS_CASE | LYS_CHOICE | LYS_CONTAINER)) {
|
|
||||||
/* containers have only zero or one child on a branch of a tree */
|
/* containers have only zero or one child on a branch of a tree */
|
||||||
inner = ((struct lyd_node_inner *)inner)->child;
|
inner = ((struct lyd_node_inner *)inner)->child;
|
||||||
assert(!inner || inner->prev == inner);
|
assert(!inner || inner->prev == inner);
|
||||||
|
@ -568,7 +572,8 @@ static enum nb_error nb_op_ys_init_node_infos(struct nb_op_yield_state *ys)
|
||||||
inner = node;
|
inner = node;
|
||||||
prevlen = 0;
|
prevlen = 0;
|
||||||
xplen = strlen(xpath);
|
xplen = strlen(xpath);
|
||||||
darr_free(xpath);
|
darr_free(ys->xpath);
|
||||||
|
ys->xpath = xpath;
|
||||||
for (i = len; i > 0; i--, inner = &inner->parent->node) {
|
for (i = len; i > 0; i--, inner = &inner->parent->node) {
|
||||||
ni = &ys->node_infos[i - 1];
|
ni = &ys->node_infos[i - 1];
|
||||||
ni->inner = inner;
|
ni->inner = inner;
|
||||||
|
@ -897,8 +902,7 @@ static const struct lysc_node *nb_op_sib_first(struct nb_op_yield_state *ys,
|
||||||
* base of the user query, return the next schema node from the query
|
* base of the user query, return the next schema node from the query
|
||||||
* string (schema_path).
|
* string (schema_path).
|
||||||
*/
|
*/
|
||||||
if (last != NULL &&
|
if (last != NULL)
|
||||||
!CHECK_FLAG(last->schema->nodetype, LYS_CASE | LYS_CHOICE))
|
|
||||||
assert(last->schema == parent);
|
assert(last->schema == parent);
|
||||||
if (darr_lasti(ys->node_infos) < ys->query_base_level)
|
if (darr_lasti(ys->node_infos) < ys->query_base_level)
|
||||||
return ys->schema_path[darr_lasti(ys->node_infos) + 1];
|
return ys->schema_path[darr_lasti(ys->node_infos) + 1];
|
||||||
|
@ -975,7 +979,8 @@ static enum nb_error __walk(struct nb_op_yield_state *ys, bool is_resume)
|
||||||
if (!walk_stem_tip)
|
if (!walk_stem_tip)
|
||||||
return NB_ERR_NOT_FOUND;
|
return NB_ERR_NOT_FOUND;
|
||||||
|
|
||||||
if (ys->schema_path[0]->nodetype == LYS_CHOICE) {
|
if (ys->schema_path[0]->parent &&
|
||||||
|
CHECK_FLAG(ys->schema_path[0]->parent->nodetype, LYS_CHOICE|LYS_CASE)) {
|
||||||
flog_err(EC_LIB_NB_OPERATIONAL_DATA,
|
flog_err(EC_LIB_NB_OPERATIONAL_DATA,
|
||||||
"%s: unable to walk root level choice node from module: %s",
|
"%s: unable to walk root level choice node from module: %s",
|
||||||
__func__, ys->schema_path[0]->module->name);
|
__func__, ys->schema_path[0]->module->name);
|
||||||
|
@ -1082,8 +1087,12 @@ static enum nb_error __walk(struct nb_op_yield_state *ys, bool is_resume)
|
||||||
LYS_LEAF | LYS_LEAFLIST | LYS_CONTAINER))
|
LYS_LEAF | LYS_LEAFLIST | LYS_CONTAINER))
|
||||||
xpath_child = nb_op_get_child_path(ys->xpath, sib,
|
xpath_child = nb_op_get_child_path(ys->xpath, sib,
|
||||||
xpath_child);
|
xpath_child);
|
||||||
else if (CHECK_FLAG(sib->nodetype, LYS_CASE | LYS_CHOICE))
|
else if (CHECK_FLAG(sib->nodetype, LYS_CASE | LYS_CHOICE)) {
|
||||||
darr_in_strdup(xpath_child, ys->xpath);
|
darr_in_strdup(xpath_child, ys->xpath);
|
||||||
|
len = darr_last(ys->node_infos)->xpath_len;
|
||||||
|
darr_setlen(xpath_child, len + 1);
|
||||||
|
xpath_child[len] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
nn = sib->priv;
|
nn = sib->priv;
|
||||||
|
|
||||||
|
@ -1703,22 +1712,22 @@ static enum nb_error nb_op_ys_init_schema_path(struct nb_op_yield_state *ys,
|
||||||
* NOTE: appears to be a bug in nb_node linkage where parent can be NULL,
|
* NOTE: appears to be a bug in nb_node linkage where parent can be NULL,
|
||||||
* or I'm misunderstanding the code, in any case we use the libyang
|
* or I'm misunderstanding the code, in any case we use the libyang
|
||||||
* linkage to walk which works fine.
|
* linkage to walk which works fine.
|
||||||
*
|
|
||||||
* XXX: we don't actually support choice/case yet, they are container
|
|
||||||
* types in the libyang schema, but won't be in data so our length
|
|
||||||
* checking gets messed up.
|
|
||||||
*/
|
*/
|
||||||
for (sn = nblast->snode, count = 0; sn; count++, sn = sn->parent)
|
for (sn = nblast->snode, count = 0; sn; sn = sn->parent) {
|
||||||
if (sn != nblast->snode)
|
if (sn != nblast->snode)
|
||||||
assert(CHECK_FLAG(sn->nodetype,
|
assert(CHECK_FLAG(sn->nodetype,
|
||||||
LYS_CONTAINER | LYS_LIST |
|
LYS_CONTAINER | LYS_LIST | LYS_CHOICE | LYS_CASE));
|
||||||
LYS_CHOICE | LYS_CASE));
|
if (!CHECK_FLAG(sn->nodetype, LYS_CHOICE | LYS_CASE))
|
||||||
|
count++;
|
||||||
|
}
|
||||||
/* create our arrays */
|
/* create our arrays */
|
||||||
darr_append_n(ys->schema_path, count);
|
darr_append_n(ys->schema_path, count);
|
||||||
darr_append_n(ys->query_tokens, count);
|
darr_append_n(ys->query_tokens, count);
|
||||||
darr_append_nz(ys->non_specific_predicate, count);
|
darr_append_nz(ys->non_specific_predicate, count);
|
||||||
for (sn = nblast->snode; sn; sn = sn->parent)
|
for (sn = nblast->snode; sn; sn = sn->parent) {
|
||||||
ys->schema_path[--count] = sn;
|
if (!CHECK_FLAG(sn->nodetype, LYS_CHOICE | LYS_CASE))
|
||||||
|
ys->schema_path[--count] = sn;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now tokenize the query string and get pointers to each token
|
* Now tokenize the query string and get pointers to each token
|
||||||
|
@ -1737,50 +1746,42 @@ static enum nb_error nb_op_ys_init_schema_path(struct nb_op_yield_state *ys,
|
||||||
int nlen = strlen(name);
|
int nlen = strlen(name);
|
||||||
int mnlen = 0;
|
int mnlen = 0;
|
||||||
|
|
||||||
/*
|
s2 = s;
|
||||||
* Technically the query_token for choice/case should probably be pointing at
|
|
||||||
* the child (leaf) rather than the parent (container), however,
|
|
||||||
* we only use these for processing list nodes so KISS.
|
|
||||||
*/
|
|
||||||
if (CHECK_FLAG(ys->schema_path[i]->nodetype,
|
|
||||||
LYS_CASE | LYS_CHOICE)) {
|
|
||||||
ys->query_tokens[i] = ys->query_tokens[i - 1];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
s2 = strstr(s, name);
|
/* skip past any module name prefix */
|
||||||
|
s2 = strstr(s2, name);
|
||||||
if (!s2)
|
if (!s2)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (s2[-1] == ':') {
|
if (s2 > s && s2[-1] == ':') {
|
||||||
mnlen = strlen(modname) + 1;
|
mnlen = strlen(modname) + 1;
|
||||||
if (ys->query_tokstr > s2 - mnlen ||
|
if (s2 - s < mnlen || strncmp(s2 - mnlen, modname, mnlen - 1)) {
|
||||||
strncmp(s2 - mnlen, modname, mnlen - 1))
|
/* No match of module prefix, advance and try again */
|
||||||
goto error;
|
s2 += strlen(name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
s2 -= mnlen;
|
s2 -= mnlen;
|
||||||
nlen += mnlen;
|
nlen += mnlen;
|
||||||
}
|
}
|
||||||
|
|
||||||
s = s2;
|
if ((i == 0 || s2[-1] == '/') &&
|
||||||
if ((i == 0 || s[-1] == '/') &&
|
(s2[nlen] == 0 || s2[nlen] == '[' || s2[nlen] == '/')) {
|
||||||
(s[nlen] == 0 || s[nlen] == '[' || s[nlen] == '/'))
|
s = s2;
|
||||||
break;
|
break;
|
||||||
/*
|
}
|
||||||
* Advance past the incorrect match, must have been
|
/* No exact match at end, advance and try again */
|
||||||
* part of previous predicate.
|
s2 += strlen(name);
|
||||||
*/
|
|
||||||
s += nlen;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NUL terminate previous token and save this one */
|
/* NUL terminate previous token and save this one */
|
||||||
if (i > 0)
|
if (i > 0) {
|
||||||
|
assert(s[-1] == '/');
|
||||||
s[-1] = 0;
|
s[-1] = 0;
|
||||||
|
}
|
||||||
ys->query_tokens[i] = s;
|
ys->query_tokens[i] = s;
|
||||||
s += nlen;
|
s += nlen;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NOTE: need to subtract choice/case nodes when these are supported */
|
|
||||||
ys->query_base_level = darr_lasti(ys->schema_path);
|
ys->query_base_level = darr_lasti(ys->schema_path);
|
||||||
|
|
||||||
return NB_OK;
|
return NB_OK;
|
||||||
|
|
Loading…
Reference in a new issue