From 43034069577985e2fe591136a67110df77d16b76 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Sun, 18 Nov 2018 20:58:18 +0100 Subject: [PATCH] clixon_yang_cardinality files added --- lib/src/clixon_yang_cardinality.c | 246 ++++++++++++++++++++++++++++++ lib/src/clixon_yang_cardinality.h | 42 +++++ 2 files changed, 288 insertions(+) create mode 100644 lib/src/clixon_yang_cardinality.c create mode 100644 lib/src/clixon_yang_cardinality.h diff --git a/lib/src/clixon_yang_cardinality.c b/lib/src/clixon_yang_cardinality.c new file mode 100644 index 00000000..ab6a43d6 --- /dev/null +++ b/lib/src/clixon_yang_cardinality.c @@ -0,0 +1,246 @@ +/* + * + ***** BEGIN LICENSE BLOCK ***** + + Copyright (C) 2009-2018 Olof Hagsand and Benny Holmgren + + This file is part of CLIXON. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Alternatively, the contents of this file may be used under the terms of + the GNU General Public License Version 3 or later (the "GPL"), + in which case the provisions of the GPL are applicable instead + of those above. If you wish to allow use of your version of this file only + under the terms of the GPL, and not to allow others to + use your version of this file under the terms of Apache License version 2, + indicate your decision by deleting the provisions above and replace them with + the notice and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this file under + the terms of any one of the Apache License version 2 or the GPL. + + ***** END LICENSE BLOCK ***** + + * Yang cardinality functions according to RFC 7950 + */ + +#ifdef HAVE_CONFIG_H +#include "clixon_config.h" /* generated by config & autoconf */ +#endif + +#include +#include +#include +#include +#include +#include +#define __USE_GNU /* strverscmp */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* cligen */ +#include + +/* clicon */ +#include "clixon_queue.h" +#include "clixon_hash.h" +#include "clixon_handle.h" +#include "clixon_err.h" +#include "clixon_yang.h" +#include "clixon_yang_cardinality.h" + +/* + * Types + */ +/* Encode cardinality according to RFC 7950 + * Example: + * 7.20.3.1. The deviation's Substatements + * + * +--------------+----------+-------------+ + * | substatement | section | cardinality | + * +--------------+----------+-------------+ + * | description | 7.21.3 | 0..1 | + * | deviate | 7.20.3.2 | 1..n | + * | reference | 7.21.4 | 0..1 | + * +--------------+----------+-------------+ + * The cardinalities are (and how many time they occur) + * 0..1 149 See ycardmap_01 + * 1..n, 1 + * 0..n 176 (no restrictions) + * 1 10 + */ +struct ycard{ + enum rfc_6020 yc_parent; + enum rfc_6020 yc_child; + int yc_min; + int yc_max; +}; + +/* + * Local variables + */ +/* Yang statements cardinality map + * The cardinalities are (and how many time they occur) + * 1..n, 1 + * 1 10 + * 0..1 149 + * 0..n 176 (no restrictions) + * @note assume array is ordered wrt parent + * @note yang-version is optional in RFC6020 but mandatory in RFC7950, if not given, it defaults to 1. + */ +#define NMAX 1000000 /* Just a large number */ +static const struct ycard yclist[] = { + {Y_MODULE, Y_ANYDATA, 0, NMAX}, + {Y_MODULE, Y_ANYXML, 0, NMAX}, + {Y_MODULE, Y_AUGMENT, 0, NMAX}, + {Y_MODULE, Y_CHOICE, 0, NMAX}, + {Y_MODULE, Y_CONTACT, 0, 1}, + {Y_MODULE, Y_CONTAINER, 0, NMAX}, + {Y_MODULE, Y_DESCRIPTION, 0, 1}, + {Y_MODULE, Y_DEVIATION, 0, NMAX}, + {Y_MODULE, Y_EXTENSION, 0, NMAX}, + {Y_MODULE, Y_FEATURE, 0, NMAX}, + {Y_MODULE, Y_GROUPING, 0, NMAX}, + {Y_MODULE, Y_IDENTITY, 0, NMAX}, + {Y_MODULE, Y_IMPORT, 0, NMAX}, + {Y_MODULE, Y_INCLUDE, 0, NMAX}, + {Y_MODULE, Y_LEAF, 0, NMAX}, + {Y_MODULE, Y_LEAF_LIST, 0, NMAX}, + {Y_MODULE, Y_LIST, 0, NMAX}, + {Y_MODULE, Y_NAMESPACE, 1, 1}, + {Y_MODULE, Y_NOTIFICATION, 0, NMAX}, + {Y_MODULE, Y_ORGANIZATION, 0, 1}, + {Y_MODULE, Y_PREFIX, 1, 1}, + {Y_MODULE, Y_REFERENCE, 0, 1}, + {Y_MODULE, Y_REVISION, 0, NMAX}, + {Y_MODULE, Y_RPC, 0, NMAX}, + {Y_MODULE, Y_TYPEDEF, 0, NMAX}, + {Y_MODULE, Y_USES, 0, NMAX}, + {Y_MODULE, Y_YANG_VERSION, 0, 1}, + {0,} +}; + +/*! Find yang parent and child combination in yang cardinality table + * @param[in] parent Parent Yang spec + * @param[in] child Child yang spec if -1 first + * @param[in] yc Yang cardinality map + * @param[in] p If set, quit as soon as parents dont match + * @retval NULL Not found + * @retval yp Found + */ +static const struct ycard * +ycard_find(enum rfc_6020 parent, + enum rfc_6020 child, + const struct ycard *yclist, + int p) + +{ + const struct ycard *yc; + + for (yc = &yclist[0]; (int)yc->yc_parent; yc++){ + if (yc->yc_parent == parent){ + if (!child || yc->yc_child == child) + return yc; + } + else + if (p) + return NULL; /* premature quit */ + } + return NULL; +} + +/*! Check cardinality, ie if each yang node has the expected nr of children + * @param[in] h Clicon handle + * @param[in] yt Yang statement + * @param[in] modname Name of module (for debug message) + * 1) For all children, if neither in 0..n, 0..1, 1 or 1..n ->ERROR + * 2) For all in 1 and 1..n list, if 0 such children ->ERROR + * 3) For all in 0..1 and 1 list, if >1 such children ->ERROR + * 4) Recurse + * @note always accept UNKNOWN (due to extension) + */ +int +yang_cardinality(clicon_handle h, + yang_stmt *yt, + char *modname) +{ + int retval = -1; + yang_stmt *ys = NULL; + int pk; + int ck; + int i; + int nr; + const struct ycard *ycplist; /* ycard parent table*/ + const struct ycard *yc; + + pk = yt->ys_keyword; + /* 0) Find parent sub-parts of cardinality vector */ + ycplist = ycard_find(pk, 0, yclist, 0); + /* 1) For all children, if neither in 0..n, 0..1, 1 or 1..n ->ERROR */ + i = 0; + while (iys_len){ + ys = yt->ys_stmt[i++]; + ck = ys->ys_keyword; + if (ck == Y_UNKNOWN) /* special case */ + continue; + if ((yc = ycard_find(pk, ck, ycplist, 1)) == NULL){ + clicon_err(OE_YANG, 0, "%s: \"%s\" is child of \"%s\", but should not be", + modname, yang_key2str(ck), yang_key2str(pk)); + goto done; + } + } + /* 2) For all in 1 and 1..n list, if 0 such children ->ERROR */ + for (yc = &ycplist[0]; (int)yc->yc_parent == pk; yc++){ + if (yc->yc_min && + yang_find((yang_node*)yt, yc->yc_child, NULL) == NULL){ + clicon_err(OE_YANG, 0, "%s: \"%s\" is missing but is mandatory child of \"%s\"", + modname, yang_key2str(yc->yc_child), yang_key2str(pk)); + goto done; + } + } + /* 3) For all in 0..1 and 1 list, if >1 such children ->ERROR */ + for (yc = &ycplist[0]; (int)yc->yc_parent == pk; yc++){ + if (yc->yc_maxyc_child, NULL)) > yc->yc_max){ + clicon_err(OE_YANG, 0, "%s: \"%s\" has %d children of type \"%s\", but only %d allowed", + modname, + yang_key2str(pk), + nr, + yang_key2str(yc->yc_child), + yc->yc_max); + goto done; + } + } + + if (0) { /* Notyet */ + /* 4) Recurse */ + i = 0; + while (iys_len){ /* Note, children may be removed */ + ys = yt->ys_stmt[i++]; + if (yang_cardinality(h, ys, modname) < 0) + goto done; + } + } + retval = 0; + done: + return retval; +} + diff --git a/lib/src/clixon_yang_cardinality.h b/lib/src/clixon_yang_cardinality.h new file mode 100644 index 00000000..eb71e8ea --- /dev/null +++ b/lib/src/clixon_yang_cardinality.h @@ -0,0 +1,42 @@ +/* + ***** BEGIN LICENSE BLOCK ***** + + Copyright (C) 2009-2018 Olof Hagsand and Benny Holmgren + + This file is part of CLIXON. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Alternatively, the contents of this file may be used under the terms of + the GNU General Public License Version 3 or later (the "GPL"), + in which case the provisions of the GPL are applicable instead + of those above. If you wish to allow use of your version of this file only + under the terms of the GPL, and not to allow others to + use your version of this file under the terms of Apache License version 2, + indicate your decision by deleting the provisions above and replace them with + the notice and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this file under + the terms of any one of the Apache License version 2 or the GPL. + + ***** END LICENSE BLOCK ***** + * Yang cardinality functions according to RFC 7950 + */ +#ifndef _CLIXON_YANG_CARDINALITY_H_ +#define _CLIXON_YANG_CARDINALITY_H_ + +/* + * Prototypes + */ +int yang_cardinality(clicon_handle h, yang_stmt *yt, char *modname); + +#endif /* _CLIXON_YANG_CARDINALITY_H_ */