Skip to content

Commit 3f290c9

Browse files
authored
Merge pull request FRRouting#18231 from LabNConsulting/chopps/fix-case-choice-queries
Fix oper-state queries that involve choice/case nodes
2 parents 67985ba + 73df7da commit 3f290c9

File tree

3 files changed

+77
-42
lines changed

3 files changed

+77
-42
lines changed

lib/northbound_oper.c

Lines changed: 43 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,11 @@ nb_op_create_yield_state(const char *xpath, struct yang_translator *translator,
140140

141141
ys = XCALLOC(MTYPE_NB_YIELD_STATE, sizeof(*ys));
142142
ys->xpath = darr_strdup_cap(xpath, (size_t)XPATH_MAXLEN);
143+
/* remove trailing '/'s */
144+
while (darr_len(ys->xpath) > 1 && ys->xpath[darr_len(ys->xpath) - 2] == '/') {
145+
darr_setlen(ys->xpath, darr_len(ys->xpath) - 1);
146+
*darr_last(ys->xpath) = 0;
147+
}
143148
ys->xpath_orig = darr_strdup(xpath);
144149
ys->translator = translator;
145150
ys->flags = flags;
@@ -417,8 +422,7 @@ static enum nb_error nb_op_ys_finalize_node_info(struct nb_op_yield_state *ys,
417422
/* Assert that we are walking the rightmost branch */
418423
assert(!inner->parent || inner == inner->parent->child->prev);
419424

420-
if (CHECK_FLAG(inner->schema->nodetype,
421-
LYS_CASE | LYS_CHOICE | LYS_CONTAINER)) {
425+
if (CHECK_FLAG(inner->schema->nodetype, LYS_CONTAINER)) {
422426
/* containers have only zero or one child on a branch of a tree */
423427
inner = ((struct lyd_node_inner *)inner)->child;
424428
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)
568572
inner = node;
569573
prevlen = 0;
570574
xplen = strlen(xpath);
571-
darr_free(xpath);
575+
darr_free(ys->xpath);
576+
ys->xpath = xpath;
572577
for (i = len; i > 0; i--, inner = &inner->parent->node) {
573578
ni = &ys->node_infos[i - 1];
574579
ni->inner = inner;
@@ -897,8 +902,7 @@ static const struct lysc_node *nb_op_sib_first(struct nb_op_yield_state *ys,
897902
* base of the user query, return the next schema node from the query
898903
* string (schema_path).
899904
*/
900-
if (last != NULL &&
901-
!CHECK_FLAG(last->schema->nodetype, LYS_CASE | LYS_CHOICE))
905+
if (last != NULL)
902906
assert(last->schema == parent);
903907
if (darr_lasti(ys->node_infos) < ys->query_base_level)
904908
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)
975979
if (!walk_stem_tip)
976980
return NB_ERR_NOT_FOUND;
977981

978-
if (ys->schema_path[0]->nodetype == LYS_CHOICE) {
982+
if (ys->schema_path[0]->parent &&
983+
CHECK_FLAG(ys->schema_path[0]->parent->nodetype, LYS_CHOICE|LYS_CASE)) {
979984
flog_err(EC_LIB_NB_OPERATIONAL_DATA,
980985
"%s: unable to walk root level choice node from module: %s",
981986
__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)
10821087
LYS_LEAF | LYS_LEAFLIST | LYS_CONTAINER))
10831088
xpath_child = nb_op_get_child_path(ys->xpath, sib,
10841089
xpath_child);
1085-
else if (CHECK_FLAG(sib->nodetype, LYS_CASE | LYS_CHOICE))
1090+
else if (CHECK_FLAG(sib->nodetype, LYS_CASE | LYS_CHOICE)) {
10861091
darr_in_strdup(xpath_child, ys->xpath);
1092+
len = darr_last(ys->node_infos)->xpath_len;
1093+
darr_setlen(xpath_child, len + 1);
1094+
xpath_child[len] = 0;
1095+
}
10871096

10881097
nn = sib->priv;
10891098

@@ -1703,22 +1712,22 @@ static enum nb_error nb_op_ys_init_schema_path(struct nb_op_yield_state *ys,
17031712
* NOTE: appears to be a bug in nb_node linkage where parent can be NULL,
17041713
* or I'm misunderstanding the code, in any case we use the libyang
17051714
* linkage to walk which works fine.
1706-
*
1707-
* XXX: we don't actually support choice/case yet, they are container
1708-
* types in the libyang schema, but won't be in data so our length
1709-
* checking gets messed up.
17101715
*/
1711-
for (sn = nblast->snode, count = 0; sn; count++, sn = sn->parent)
1716+
for (sn = nblast->snode, count = 0; sn; sn = sn->parent) {
17121717
if (sn != nblast->snode)
17131718
assert(CHECK_FLAG(sn->nodetype,
1714-
LYS_CONTAINER | LYS_LIST |
1715-
LYS_CHOICE | LYS_CASE));
1719+
LYS_CONTAINER | LYS_LIST | LYS_CHOICE | LYS_CASE));
1720+
if (!CHECK_FLAG(sn->nodetype, LYS_CHOICE | LYS_CASE))
1721+
count++;
1722+
}
17161723
/* create our arrays */
17171724
darr_append_n(ys->schema_path, count);
17181725
darr_append_n(ys->query_tokens, count);
17191726
darr_append_nz(ys->non_specific_predicate, count);
1720-
for (sn = nblast->snode; sn; sn = sn->parent)
1721-
ys->schema_path[--count] = sn;
1727+
for (sn = nblast->snode; sn; sn = sn->parent) {
1728+
if (!CHECK_FLAG(sn->nodetype, LYS_CHOICE | LYS_CASE))
1729+
ys->schema_path[--count] = sn;
1730+
}
17221731

17231732
/*
17241733
* 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,
17371746
int nlen = strlen(name);
17381747
int mnlen = 0;
17391748

1740-
/*
1741-
* Technically the query_token for choice/case should probably be pointing at
1742-
* the child (leaf) rather than the parent (container), however,
1743-
* we only use these for processing list nodes so KISS.
1744-
*/
1745-
if (CHECK_FLAG(ys->schema_path[i]->nodetype,
1746-
LYS_CASE | LYS_CHOICE)) {
1747-
ys->query_tokens[i] = ys->query_tokens[i - 1];
1748-
continue;
1749-
}
1750-
1749+
s2 = s;
17511750
while (true) {
1752-
s2 = strstr(s, name);
1751+
/* skip past any module name prefix */
1752+
s2 = strstr(s2, name);
17531753
if (!s2)
17541754
goto error;
17551755

1756-
if (s2[-1] == ':') {
1756+
if (s2 > s && s2[-1] == ':') {
17571757
mnlen = strlen(modname) + 1;
1758-
if (ys->query_tokstr > s2 - mnlen ||
1759-
strncmp(s2 - mnlen, modname, mnlen - 1))
1760-
goto error;
1758+
if (s2 - s < mnlen || strncmp(s2 - mnlen, modname, mnlen - 1)) {
1759+
/* No match of module prefix, advance and try again */
1760+
s2 += strlen(name);
1761+
continue;
1762+
}
17611763
s2 -= mnlen;
17621764
nlen += mnlen;
17631765
}
17641766

1765-
s = s2;
1766-
if ((i == 0 || s[-1] == '/') &&
1767-
(s[nlen] == 0 || s[nlen] == '[' || s[nlen] == '/'))
1767+
if ((i == 0 || s2[-1] == '/') &&
1768+
(s2[nlen] == 0 || s2[nlen] == '[' || s2[nlen] == '/')) {
1769+
s = s2;
17681770
break;
1769-
/*
1770-
* Advance past the incorrect match, must have been
1771-
* part of previous predicate.
1772-
*/
1773-
s += nlen;
1771+
}
1772+
/* No exact match at end, advance and try again */
1773+
s2 += strlen(name);
17741774
}
17751775

17761776
/* NUL terminate previous token and save this one */
1777-
if (i > 0)
1777+
if (i > 0) {
1778+
assert(s[-1] == '/');
17781779
s[-1] = 0;
1780+
}
17791781
ys->query_tokens[i] = s;
17801782
s += nlen;
17811783
}
17821784

1783-
/* NOTE: need to subtract choice/case nodes when these are supported */
17841785
ys->query_base_level = darr_lasti(ys->schema_path);
17851786

17861787
return NB_OK;

tests/lib/northbound/test_oper_data.in

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,8 @@ show yang operational-data /frr-test-module:frr-test-module
22
show yang operational-data /frr-test-module:frr-test-module/vrfs/vrf[name='vrf0']/routes/route[2]
33
show yang operational-data /frr-test-module:frr-test-module/vrfs/vrf[name='vrf0']/routes/route[3]/interface
44
show yang operational-data /frr-test-module:frr-test-module/vrfs/vrf[name='vrf0']/routes/route[10]
5+
show yang operational-data /frr-test-module:frr-test-module/c1value
6+
show yang operational-data /frr-test-module:frr-test-module/c2cont
7+
show yang operational-data /frr-test-module:frr-test-module/c2cont/
8+
show yang operational-data /frr-test-module:frr-test-module/c2cont/c2value
59
test rpc

tests/lib/northbound/test_oper_data.refout

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,36 @@ test# show yang operational-data /frr-test-module:frr-test-module/vrfs/vrf[name=
174174
}
175175
test# show yang operational-data /frr-test-module:frr-test-module/vrfs/vrf[name='vrf0']/routes/route[10]
176176
{}
177+
test# show yang operational-data /frr-test-module:frr-test-module/c1value
178+
{
179+
"frr-test-module:frr-test-module": {
180+
"c1value": 21
181+
}
182+
}
183+
test# show yang operational-data /frr-test-module:frr-test-module/c2cont
184+
{
185+
"frr-test-module:frr-test-module": {
186+
"c2cont": {
187+
"c2value": 2868969987
188+
}
189+
}
190+
}
191+
test# show yang operational-data /frr-test-module:frr-test-module/c2cont/
192+
{
193+
"frr-test-module:frr-test-module": {
194+
"c2cont": {
195+
"c2value": 2868969987
196+
}
197+
}
198+
}
199+
test# show yang operational-data /frr-test-module:frr-test-module/c2cont/c2value
200+
{
201+
"frr-test-module:frr-test-module": {
202+
"c2cont": {
203+
"c2value": 2868969987
204+
}
205+
}
206+
}
177207
test# test rpc
178208
vrf testname data testdata
179209
test#

0 commit comments

Comments
 (0)