clixon/lib/src/clixon_yang_cardinality.c
Olof hagsand fcdfbd23cc Re-optimized yang cardinality
Misc rearrangements
2024-05-02 13:34:46 +02:00

618 lines
23 KiB
C

/*
*
***** BEGIN LICENSE BLOCK *****
Copyright (C) 2009-2019 Olof Hagsand
Copyright (C) 2020-2022 Olof Hagsand and Rubicon Communications, LLC(Netgate)
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
* That is, how many children any yang node has
*/
#ifdef HAVE_CONFIG_H
#include "clixon_config.h" /* generated by config & autoconf */
#endif
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include <ctype.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <regex.h>
#include <dirent.h>
#include <sys/types.h>
#include <fcntl.h>
#include <syslog.h>
#include <sys/stat.h>
#include <netinet/in.h>
/* cligen */
#include <cligen/cligen.h>
/* clixon */
#include "clixon_queue.h"
#include "clixon_hash.h"
#include "clixon_handle.h"
#include "clixon_yang.h"
#include "clixon_xml.h"
#include "clixon_err.h"
#include "clixon_yang_cardinality.h"
/*
* Types
*/
/* Encode cardinality and ordering according to RFC 7950
* Example:
* 7.1.1. The module's Substatements (subset)
* +--------------+----------+-------------+----------+
* | substatement | section | cardinality | ordering |
* +--------------+----------+-------------+----------+
* | contact | 7.1.8 | 0..1 | 2 |
* | import | 7.1.5 | 0..n | 1 |
* | include | 7.1.6 | 0..n | 1 |
* | namespace | 7.1.3 | 1 | 0 |
* | organization | 7.1.7 | 0..1 | 2 |
* | yang-version | 7.1.2 | 1 | 0 |
* +--------------+----------+-------------+----------+
* 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
*
* Ordering means in which order the statements may occur. If same ordering the may occur
* in any order. In the example above, namespace and yang-version occurs before
* import and include which in turn preceedes contact and organization
* Note: order is only relevant for modules and sub-modules
*/
struct ycard{
enum rfc_6020 yc_parent;
enum rfc_6020 yc_child;
int yc_min;
int yc_max;
int yc_order;
};
/*
* 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 The array MUST be ordered wrt parent and child for ycard_find_binary to use binary search
* @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_ACTION, Y_DESCRIPTION, 0, 1, 0},
{Y_ACTION, Y_GROUPING, 0, NMAX, 0},
{Y_ACTION, Y_IF_FEATURE, 0, NMAX, 0},
{Y_ACTION, Y_INPUT, 0, 1, 0},
{Y_ACTION, Y_OUTPUT, 0, 1, 0},
{Y_ACTION, Y_REFERENCE, 0, 1, 0},
{Y_ACTION, Y_STATUS, 0, 1, 0},
{Y_ACTION, Y_TYPEDEF, 0, NMAX, 0},
{Y_ANYDATA, Y_CONFIG, 0, 1, 0},
{Y_ANYDATA, Y_DESCRIPTION, 0, 1, 0},
{Y_ANYDATA, Y_IF_FEATURE, 0, NMAX, 0},
{Y_ANYDATA, Y_MANDATORY, 0, 1, 0},
{Y_ANYDATA, Y_MUST, 0, NMAX, 0},
{Y_ANYDATA, Y_REFERENCE, 0, 1, 0},
{Y_ANYDATA, Y_STATUS, 0, 1, 0},
{Y_ANYDATA, Y_WHEN, 0, 1, 0},
{Y_ANYXML, Y_CONFIG, 0, 1, 0},
{Y_ANYXML, Y_DESCRIPTION, 0, 1, 0},
{Y_ANYXML, Y_IF_FEATURE, 0, NMAX, 0},
{Y_ANYXML, Y_MANDATORY, 0, 1, 0},
{Y_ANYXML, Y_MUST, 0, NMAX, 0},
{Y_ANYXML, Y_REFERENCE, 0, 1, 0},
{Y_ANYXML, Y_STATUS, 0, 1, 0},
{Y_ANYXML, Y_WHEN, 0, 1, 0},
{Y_ARGUMENT, Y_YIN_ELEMENT, 0, 1, 0},
{Y_AUGMENT, Y_ACTION, 0, NMAX, 0},
{Y_AUGMENT, Y_ANYDATA, 0, NMAX, 0},
{Y_AUGMENT, Y_ANYXML, 0, NMAX, 0},
{Y_AUGMENT, Y_CASE, 0, NMAX, 0},
{Y_AUGMENT, Y_CHOICE, 0, NMAX, 0},
{Y_AUGMENT, Y_CONTAINER, 0, NMAX, 0},
{Y_AUGMENT, Y_DESCRIPTION, 0, 1, 0},
{Y_AUGMENT, Y_IF_FEATURE, 0, NMAX, 0},
{Y_AUGMENT, Y_LEAF, 0, NMAX, 0},
{Y_AUGMENT, Y_LEAF_LIST, 0, NMAX, 0},
{Y_AUGMENT, Y_LIST, 0, NMAX, 0},
{Y_AUGMENT, Y_NOTIFICATION, 0, NMAX, 0},
{Y_AUGMENT, Y_REFERENCE, 0, 1, 0},
{Y_AUGMENT, Y_STATUS, 0, 1, 0},
{Y_AUGMENT, Y_USES, 0, NMAX, 0},
{Y_AUGMENT, Y_WHEN, 0, 1, 0},
{Y_BELONGS_TO, Y_PREFIX, 1, 1, 0},
{Y_BIT, Y_DESCRIPTION, 0, 1, 0},
{Y_BIT, Y_IF_FEATURE, 0, NMAX, 0},
{Y_BIT, Y_POSITION, 0, 1, 0},
{Y_BIT, Y_REFERENCE, 0, 1, 0},
{Y_BIT, Y_STATUS, 0, 1, 0},
{Y_CASE, Y_ANYDATA, 0, NMAX, 0},
{Y_CASE, Y_ANYXML, 0, NMAX, 0},
{Y_CASE, Y_CHOICE, 0, NMAX, 0},
{Y_CASE, Y_CONTAINER, 0, NMAX, 0},
{Y_CASE, Y_DESCRIPTION, 0, 1, 0},
{Y_CASE, Y_IF_FEATURE, 0, NMAX, 0},
{Y_CASE, Y_LEAF, 0, NMAX, 0},
{Y_CASE, Y_LEAF_LIST, 0, NMAX, 0},
{Y_CASE, Y_LIST, 0, NMAX, 0},
{Y_CASE, Y_REFERENCE, 0, 1, 0},
{Y_CASE, Y_STATUS, 0, 1, 0},
{Y_CASE, Y_USES, 0, NMAX, 0},
{Y_CASE, Y_WHEN, 0, 1, 0},
{Y_CHOICE, Y_ANYDATA, 0, NMAX, 0},
{Y_CHOICE, Y_ANYXML, 0, NMAX, 0},
{Y_CHOICE, Y_CASE, 0, NMAX, 0},
{Y_CHOICE, Y_CHOICE, 0, NMAX, 0},
{Y_CHOICE, Y_CONFIG, 0, 1, 0},
{Y_CHOICE, Y_CONTAINER, 0, NMAX, 0},
{Y_CHOICE, Y_DEFAULT, 0, 1, 0},
{Y_CHOICE, Y_DESCRIPTION, 0, 1, 0},
{Y_CHOICE, Y_IF_FEATURE, 0, NMAX, 0},
{Y_CHOICE, Y_LEAF, 0, NMAX, 0},
{Y_CHOICE, Y_LEAF_LIST, 0, NMAX, 0},
{Y_CHOICE, Y_LIST, 0, NMAX, 0},
{Y_CHOICE, Y_MANDATORY, 0, 1, 0},
{Y_CHOICE, Y_REFERENCE, 0, 1, 0},
{Y_CHOICE, Y_STATUS, 0, 1, 0},
{Y_CHOICE, Y_WHEN, 0, 1, 0},
{Y_CONTAINER, Y_ACTION, 0, NMAX, 0},
{Y_CONTAINER, Y_ANYDATA, 0, NMAX, 0},
{Y_CONTAINER, Y_ANYXML, 0, NMAX, 0},
{Y_CONTAINER, Y_CHOICE, 0, NMAX, 0},
{Y_CONTAINER, Y_CONFIG, 0, 1, 0},
{Y_CONTAINER, Y_CONTAINER, 0, NMAX, 0},
{Y_CONTAINER, Y_DESCRIPTION, 0, 1, 0},
{Y_CONTAINER, Y_GROUPING, 0, NMAX, 0},
{Y_CONTAINER, Y_IF_FEATURE, 0, NMAX, 0},
{Y_CONTAINER, Y_LEAF, 0, NMAX, 0},
{Y_CONTAINER, Y_LEAF_LIST, 0, NMAX, 0},
{Y_CONTAINER, Y_LIST, 0, NMAX, 0},
{Y_CONTAINER, Y_MUST, 0, NMAX, 0},
{Y_CONTAINER, Y_NOTIFICATION, 0, NMAX, 0},
{Y_CONTAINER, Y_PRESENCE, 0, 1, 0},
{Y_CONTAINER, Y_REFERENCE, 0, 1, 0},
{Y_CONTAINER, Y_STATUS, 0, 1, 0},
{Y_CONTAINER, Y_TYPEDEF, 0, NMAX, 0},
{Y_CONTAINER, Y_USES, 0, NMAX, 0},
{Y_CONTAINER, Y_WHEN, 0, 1, 0},
{Y_DEVIATE, Y_CONFIG, 0, 1, 0},
{Y_DEVIATE, Y_DEFAULT, 0, NMAX, 0},
{Y_DEVIATE, Y_MANDATORY, 0, 1, 0},
{Y_DEVIATE, Y_MAX_ELEMENTS, 0, 1, 0},
{Y_DEVIATE, Y_MIN_ELEMENTS, 0, 1, 0},
{Y_DEVIATE, Y_MUST, 0, NMAX, 0},
{Y_DEVIATE, Y_TYPE, 0, 1, 0},
{Y_DEVIATE, Y_UNIQUE, 0, NMAX, 0},
{Y_DEVIATE, Y_UNITS, 0, 1, 0},
{Y_DEVIATION, Y_DESCRIPTION, 0, 1, 0},
{Y_DEVIATION, Y_DEVIATE, 1, NMAX, 0},
{Y_DEVIATION, Y_REFERENCE, 0, 1, 0},
{Y_ENUM, Y_DESCRIPTION, 0, 1, 0},
{Y_ENUM, Y_IF_FEATURE, 0, NMAX, 0},
{Y_ENUM, Y_REFERENCE, 0, 1, 0},
{Y_ENUM, Y_STATUS, 0, 1, 0},
{Y_ENUM, Y_VALUE, 0, 1, 0},
{Y_EXTENSION, Y_ARGUMENT, 0, 1, 0},
{Y_EXTENSION, Y_DESCRIPTION, 0, 1, 0},
{Y_EXTENSION, Y_REFERENCE, 0, 1, 0},
{Y_EXTENSION, Y_STATUS, 0, 1, 0},
{Y_FEATURE, Y_DESCRIPTION, 0, 1, 0},
{Y_FEATURE, Y_IF_FEATURE, 0, NMAX, 0},
{Y_FEATURE, Y_REFERENCE, 0, 1, 0},
{Y_FEATURE, Y_STATUS, 0, 1, 0},
{Y_GROUPING, Y_ACTION, 0, NMAX, 0},
{Y_GROUPING, Y_ANYDATA, 0, NMAX, 0},
{Y_GROUPING, Y_ANYXML, 0, NMAX, 0},
{Y_GROUPING, Y_CHOICE, 0, NMAX, 0},
{Y_GROUPING, Y_CONTAINER, 0, NMAX, 0},
{Y_GROUPING, Y_DESCRIPTION, 0, 1, 0},
{Y_GROUPING, Y_GROUPING, 0, NMAX, 0},
{Y_GROUPING, Y_LEAF, 0, NMAX, 0},
{Y_GROUPING, Y_LEAF_LIST, 0, NMAX, 0},
{Y_GROUPING, Y_LIST, 0, NMAX, 0},
{Y_GROUPING, Y_NOTIFICATION, 0, NMAX, 0},
{Y_GROUPING, Y_REFERENCE, 0, 1, 0},
{Y_GROUPING, Y_STATUS, 0, 1, 0},
{Y_GROUPING, Y_TYPEDEF, 0, NMAX, 0},
{Y_GROUPING, Y_USES, 0, NMAX, 0},
{Y_IDENTITY, Y_BASE, 0, NMAX, 0},
{Y_IDENTITY, Y_DESCRIPTION, 0, 1, 0},
{Y_IDENTITY, Y_IF_FEATURE, 0, NMAX, 0},
{Y_IDENTITY, Y_REFERENCE, 0, 1, 0},
{Y_IDENTITY, Y_STATUS, 0, 1, 0},
{Y_IMPORT, Y_DESCRIPTION, 0, 1, 0},
{Y_IMPORT, Y_PREFIX, 1, 1, 0},
{Y_IMPORT, Y_REFERENCE, 0, 1, 0},
{Y_IMPORT, Y_REVISION_DATE,0, 1, 0},
{Y_INCLUDE, Y_DESCRIPTION, 0, 1, 0},
{Y_INCLUDE, Y_REFERENCE, 0, 1, 0},
{Y_INCLUDE, Y_REVISION_DATE,0, 1, 0},
{Y_INPUT, Y_ANYDATA, 0, NMAX, 0},
{Y_INPUT, Y_ANYXML, 0, NMAX, 0},
{Y_INPUT, Y_CHOICE, 0, NMAX, 0},
{Y_INPUT, Y_CONTAINER, 0, NMAX, 0},
{Y_INPUT, Y_GROUPING, 0, NMAX, 0},
{Y_INPUT, Y_LEAF, 0, NMAX, 0},
{Y_INPUT, Y_LEAF_LIST, 0, NMAX, 0},
{Y_INPUT, Y_LIST, 0, NMAX, 0},
{Y_INPUT, Y_MUST, 0, NMAX, 0},
{Y_INPUT, Y_TYPEDEF, 0, NMAX, 0},
{Y_INPUT, Y_USES, 0, NMAX, 0},
{Y_LEAF, Y_CONFIG, 0, 1, 0},
{Y_LEAF, Y_DEFAULT, 0, 1, 0},
{Y_LEAF, Y_DESCRIPTION, 0, 1, 0},
{Y_LEAF, Y_IF_FEATURE, 0, NMAX, 0},
{Y_LEAF, Y_MANDATORY, 0, 1, 0},
{Y_LEAF, Y_MUST, 0, NMAX, 0},
{Y_LEAF, Y_REFERENCE, 0, 1, 0},
{Y_LEAF, Y_STATUS, 0, 1, 0},
{Y_LEAF, Y_TYPE, 1, 1, 0},
{Y_LEAF, Y_UNITS, 0, 1, 0},
{Y_LEAF, Y_WHEN, 0, 1, 0},
{Y_LEAF_LIST, Y_CONFIG, 0, 1, 0},
{Y_LEAF_LIST, Y_DEFAULT, 0, NMAX, 0},
{Y_LEAF_LIST, Y_DESCRIPTION, 0, 1, 0},
{Y_LEAF_LIST, Y_IF_FEATURE, 0, NMAX, 0},
{Y_LEAF_LIST, Y_MAX_ELEMENTS, 0, 1, 0},
{Y_LEAF_LIST, Y_MIN_ELEMENTS, 0, 1, 0},
{Y_LEAF_LIST, Y_MUST, 0, NMAX, 0},
{Y_LEAF_LIST, Y_ORDERED_BY, 0, 1, 0},
{Y_LEAF_LIST, Y_REFERENCE, 0, 1, 0},
{Y_LEAF_LIST, Y_STATUS, 0, 1, 0},
{Y_LEAF_LIST, Y_TYPE, 1, 1, 0},
{Y_LEAF_LIST, Y_UNITS, 0, 1, 0},
{Y_LEAF_LIST, Y_WHEN, 0, 1, 0},
{Y_LENGTH, Y_DESCRIPTION, 0, 1, 0},
{Y_LENGTH, Y_ERROR_APP_TAG, 0, 1, 0},
{Y_LENGTH, Y_ERROR_MESSAGE, 0, 1, 0},
{Y_LENGTH, Y_REFERENCE, 0, 1, 0},
{Y_LIST, Y_ACTION, 0, NMAX, 0},
{Y_LIST, Y_ANYDATA, 0, NMAX, 0},
{Y_LIST, Y_ANYXML, 0, NMAX, 0},
{Y_LIST, Y_CHOICE, 0, NMAX, 0},
{Y_LIST, Y_CONFIG, 0, 1, 0},
{Y_LIST, Y_CONTAINER, 0, NMAX, 0},
{Y_LIST, Y_DESCRIPTION, 0, 1, 0},
{Y_LIST, Y_GROUPING, 0, NMAX, 0},
{Y_LIST, Y_IF_FEATURE, 0, NMAX, 0},
{Y_LIST, Y_KEY, 0, 1, 0},
{Y_LIST, Y_LEAF, 0, NMAX, 0},
{Y_LIST, Y_LEAF_LIST, 0, NMAX, 0},
{Y_LIST, Y_LIST, 0, NMAX, 0},
{Y_LIST, Y_MAX_ELEMENTS, 0, 1, 0},
{Y_LIST, Y_MIN_ELEMENTS, 0, 1, 0},
{Y_LIST, Y_MUST, 0, NMAX, 0},
{Y_LIST, Y_NOTIFICATION, 0, NMAX, 0},
{Y_LIST, Y_ORDERED_BY, 0, 1, 0},
{Y_LIST, Y_REFERENCE, 0, 1, 0},
{Y_LIST, Y_STATUS, 0, 1, 0},
{Y_LIST, Y_TYPEDEF, 0, NMAX, 0},
{Y_LIST, Y_UNIQUE, 0, NMAX, 0},
{Y_LIST, Y_USES, 0, NMAX, 0},
{Y_LIST, Y_WHEN, 0,1, 0},
{Y_MODULE, Y_ANYDATA, 0, NMAX, 4},
{Y_MODULE, Y_ANYXML, 0, NMAX, 4},
{Y_MODULE, Y_AUGMENT, 0, NMAX, 4},
{Y_MODULE, Y_CHOICE, 0, NMAX, 4},
{Y_MODULE, Y_CONTACT, 0, 1, 2},
{Y_MODULE, Y_CONTAINER, 0, NMAX, 4},
{Y_MODULE, Y_DESCRIPTION, 0, 1, 2},
{Y_MODULE, Y_DEVIATION, 0, NMAX, 4},
{Y_MODULE, Y_EXTENSION, 0, NMAX, 4},
{Y_MODULE, Y_FEATURE, 0, NMAX, 4},
{Y_MODULE, Y_GROUPING, 0, NMAX, 4},
{Y_MODULE, Y_IDENTITY, 0, NMAX, 4},
{Y_MODULE, Y_IMPORT, 0, NMAX, 1},
{Y_MODULE, Y_INCLUDE, 0, NMAX, 1},
{Y_MODULE, Y_LEAF, 0, NMAX, 4},
{Y_MODULE, Y_LEAF_LIST, 0, NMAX, 4},
{Y_MODULE, Y_LIST, 0, NMAX, 4},
{Y_MODULE, Y_NAMESPACE, 1, 1, 0},
{Y_MODULE, Y_NOTIFICATION, 0, NMAX, 4},
{Y_MODULE, Y_ORGANIZATION, 0, 1, 2},
{Y_MODULE, Y_PREFIX, 1, 1, 0},
{Y_MODULE, Y_REFERENCE, 0, 1, 2},
{Y_MODULE, Y_REVISION, 0, NMAX, 3},
{Y_MODULE, Y_RPC, 0, NMAX, 4},
{Y_MODULE, Y_TYPEDEF, 0, NMAX, 4},
{Y_MODULE, Y_USES, 0, NMAX, 4},
{Y_MODULE, Y_YANG_VERSION, 0, 1, 0},
{Y_MUST, Y_DESCRIPTION, 0, 1, 0},
{Y_MUST, Y_ERROR_APP_TAG, 0, 1, 0},
{Y_MUST, Y_ERROR_MESSAGE, 0, 1, 0},
{Y_MUST, Y_REFERENCE, 0, 1, 0},
{Y_NOTIFICATION, Y_ANYDATA, 0, NMAX, 0},
{Y_NOTIFICATION, Y_ANYXML, 0, NMAX, 0},
{Y_NOTIFICATION, Y_CHOICE, 0, NMAX, 0},
{Y_NOTIFICATION, Y_CONTAINER, 0, NMAX, 0},
{Y_NOTIFICATION, Y_DESCRIPTION, 0, 1, 0},
{Y_NOTIFICATION, Y_GROUPING, 0, NMAX, 0},
{Y_NOTIFICATION, Y_IF_FEATURE, 0, NMAX, 0},
{Y_NOTIFICATION, Y_LEAF, 0, NMAX, 0},
{Y_NOTIFICATION, Y_LEAF_LIST, 0, NMAX, 0},
{Y_NOTIFICATION, Y_LIST, 0, NMAX, 0},
{Y_NOTIFICATION, Y_MUST, 0, NMAX, 0},
{Y_NOTIFICATION, Y_REFERENCE, 0, 1, 0},
{Y_NOTIFICATION, Y_STATUS, 0, 1, 0},
{Y_NOTIFICATION, Y_TYPEDEF, 0, NMAX, 0},
{Y_NOTIFICATION, Y_USES, 0, NMAX, 0},
{Y_OUTPUT, Y_ANYDATA, 0, NMAX, 0},
{Y_OUTPUT, Y_ANYXML, 0, NMAX, 0},
{Y_OUTPUT, Y_CHOICE, 0, NMAX, 0},
{Y_OUTPUT, Y_CONTAINER, 0, NMAX, 0},
{Y_OUTPUT, Y_GROUPING, 0, NMAX, 0},
{Y_OUTPUT, Y_LEAF, 0, NMAX, 0},
{Y_OUTPUT, Y_LEAF_LIST, 0, NMAX, 0},
{Y_OUTPUT, Y_LIST, 0, NMAX, 0},
{Y_OUTPUT, Y_MUST, 0, NMAX, 0},
{Y_OUTPUT, Y_TYPEDEF, 0, NMAX, 0},
{Y_OUTPUT, Y_USES, 0, NMAX, 0},
{Y_PATTERN, Y_DESCRIPTION, 0, 1, 0},
{Y_PATTERN, Y_ERROR_APP_TAG, 0, 1, 0},
{Y_PATTERN, Y_ERROR_MESSAGE, 0, 1, 0},
{Y_PATTERN, Y_MODIFIER, 0, 1, 0},
{Y_PATTERN, Y_REFERENCE, 0, 1, 0},
{Y_RANGE, Y_DESCRIPTION, 0, 1, 0},
{Y_RANGE, Y_ERROR_APP_TAG, 0, 1, 0},
{Y_RANGE, Y_ERROR_MESSAGE, 0, 1, 0},
{Y_RANGE, Y_REFERENCE, 0, 1, 0},
{Y_REVISION, Y_DESCRIPTION, 0, 1, 0},
{Y_REVISION, Y_REFERENCE, 0, 1, 0},
{Y_RPC, Y_DESCRIPTION, 0, 1, 0},
{Y_RPC, Y_GROUPING, 0, NMAX, 0},
{Y_RPC, Y_IF_FEATURE, 0, NMAX, 0},
{Y_RPC, Y_INPUT, 0, 1, 0},
{Y_RPC, Y_OUTPUT, 0, 1, 0},
{Y_RPC, Y_REFERENCE, 0, 1, 0},
{Y_RPC, Y_STATUS, 0, 1, 0},
{Y_RPC, Y_TYPEDEF, 0, NMAX, 0},
{Y_SUBMODULE, Y_ANYDATA, 0, NMAX, 4},
{Y_SUBMODULE, Y_AUGMENT, 0, NMAX, 4},
{Y_SUBMODULE, Y_BELONGS_TO, 1, 1, 0},
{Y_SUBMODULE, Y_CHOICE, 0, NMAX, 4},
{Y_SUBMODULE, Y_CONTACT, 0, 1, 2},
{Y_SUBMODULE, Y_CONTAINER, 0, NMAX, 4},
{Y_SUBMODULE, Y_DESCRIPTION,0, 1, 2},
{Y_SUBMODULE, Y_DEVIATION, 0, NMAX, 4},
{Y_SUBMODULE, Y_EXTENSION, 0, NMAX, 4},
{Y_SUBMODULE, Y_FEATURE, 0, NMAX, 4},
{Y_SUBMODULE, Y_GROUPING, 0, NMAX, 4},
{Y_SUBMODULE, Y_IDENTITY, 0, NMAX, 4},
{Y_SUBMODULE, Y_IMPORT, 0, NMAX, 1},
{Y_SUBMODULE, Y_INCLUDE, 0, NMAX, 1},
{Y_SUBMODULE, Y_LEAF, 0, NMAX, 4},
{Y_SUBMODULE, Y_LEAF_LIST, 0, NMAX, 4},
{Y_SUBMODULE, Y_LIST, 0, NMAX, 4},
{Y_SUBMODULE, Y_NOTIFICATION,0, NMAX, 4},
{Y_SUBMODULE, Y_ORGANIZATION,0, 1, 2},
{Y_SUBMODULE, Y_REFERENCE, 0, 1, 2},
{Y_SUBMODULE, Y_REVISION, 0, NMAX, 3},
{Y_SUBMODULE, Y_RPC, 0, NMAX, 4},
{Y_SUBMODULE, Y_TYPEDEF, 0, NMAX, 4},
{Y_SUBMODULE, Y_USES, 0, NMAX, 4},
{Y_SUBMODULE, Y_YANG_VERSION,0, 1, 0}, /* "yang-version" statement is mandatory in YANG version "1.1". */
{Y_TYPE, Y_BASE, 0, NMAX, 0},
{Y_TYPE, Y_BIT, 0, NMAX, 0},
{Y_TYPE, Y_ENUM, 0, NMAX, 0},
{Y_TYPE, Y_FRACTION_DIGITS, 0, 1, 0},
{Y_TYPE, Y_LENGTH, 0, 1, 0},
{Y_TYPE, Y_PATH, 0, 1, 0},
{Y_TYPE, Y_PATTERN, 0, NMAX, 0},
{Y_TYPE, Y_RANGE, 0, 1, 0},
{Y_TYPE, Y_REQUIRE_INSTANCE, 0, 1, 0},
{Y_TYPE, Y_TYPE, 0, NMAX, 0},
{Y_TYPEDEF, Y_DEFAULT, 0, 1, 0},
{Y_TYPEDEF, Y_DESCRIPTION,0, 1, 0},
{Y_TYPEDEF, Y_REFERENCE, 0, 1, 0},
{Y_TYPEDEF, Y_STATUS, 0, 1, 0},
{Y_TYPEDEF, Y_TYPE, 1, 1, 0},
{Y_TYPEDEF, Y_UNITS, 0, 1, 0},
{Y_USES, Y_AUGMENT, 0, NMAX, 0},
{Y_USES, Y_DESCRIPTION, 0, 1, 0},
{Y_USES, Y_IF_FEATURE, 0, NMAX, 0},
{Y_USES, Y_REFERENCE, 0, 1, 0},
{Y_USES, Y_REFINE, 0, NMAX, 0},
{Y_USES, Y_STATUS, 0, 1, 0},
{Y_USES, Y_WHEN, 0, 1, 0},
{Y_WHEN, Y_DESCRIPTION, 0, 1, 0},
{Y_WHEN, Y_REFERENCE, 0, 1, 0},
{0,}
};
/* Search matrix for lookups */
static const struct ycard *_yc_search[Y_SPEC][Y_SPEC] = {{0,},{0,}};
/*! Set to 1 if exists in search
*
* Some yang statements are not explicitly given cardinalities in RFC7950, although they are
* present in Section 14 BNF.
* But since the table above is from the explicit cardinalities in the RFC the others are skipped
* and = 0 in the following vector.
* Example: Y_REFINE
*/
static const struct ycard *_yc_exist[Y_SPEC] = {NULL,}; /* First */
/*! Check cardinality, ie if each yang node has the expected nr of children
*
* @param[in] h Clixon handle
* @param[in] yt Yang statement
* @param[in] modname Name of module (for debug message)
* @retval 0 OK
* @retval -1 Error
* 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(clixon_handle h,
yang_stmt *yt,
char *modname)
{
int retval = -1;
yang_stmt *ys = NULL;
int pk;
int ck;
const struct ycard *yc0;
const struct ycard *yc;
int order;
yang_stmt *yprev = NULL;
int nr;
int yc_count[Y_SPEC] = {0,};
pk = yang_keyword_get(yt);
if ((yc0 = _yc_exist[pk]) == NULL)
goto ok;
/* 1) For all children, if neither in 0..n, 0..1, 1 or 1..n ->ERROR
* Also: check monotonically increasing order
*/
order = 0;
ys = NULL;
while ((ys = yn_each(yt, ys)) != NULL) {
ck = yang_keyword_get(ys);
if (pk == Y_UNKNOWN || ck == Y_UNKNOWN) /* special case */
continue;
/* Find entry in yang cardinality table from parent/child keyword pair */
if ((yc = _yc_search[pk][ck]) == NULL){
clixon_err(OE_YANG, 0, "%s: \"%s\"(%s) is child of \"%s\"(%s), but should not be",
modname,
yang_key2str(ck),
yang_argument_get(ys),
yang_key2str(pk),
yang_argument_get(yt));
goto done;
}
if (order > yc->yc_order){
clixon_err(OE_YANG, 0, "%s: yang node \"%s\"(%s) which is child of \"%s\"(%s) is not in correct order (should not be after \"%s\"(%s))",
modname,
yang_key2str(ck),
yang_argument_get(ys),
yang_key2str(pk),
yang_argument_get(yt),
yang_key2str(yang_keyword_get(yprev)),
yang_argument_get(yprev));
goto done;
}
if (order < yc->yc_order)
order = yc->yc_order;
yc_count[yang_keyword_get(ys)]++; /* used in loop (2) */
/* 4) Recurse */
if (yang_cardinality(h, ys, modname) < 0)
goto done;
yprev = ys;
}
/* 2) For all in 1 and 1..n list, if 0 such children -> ERROR
*/
for (yc = yc0; (int)yc->yc_parent && yc->yc_parent == pk; yc++){
if (yc->yc_min &&
yang_find(yt, yc->yc_child, NULL) == NULL){
clixon_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;
}
if (yc->yc_max<NMAX){
nr = yc_count[yc->yc_child];
if (nr > yc->yc_max){
clixon_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;
}
}
}
ok:
retval = 0;
done:
return retval;
}
/*! Return cardinality interval [min,max] given yang parent and child keyword.
*
* @param[in] h Clixon handle
* @param[in] parent_key
* @param[in] child_key
* @param[out] minp 0 or 1
* @param[out] maxp 1 or NMAX (large number)
* @retval 0 OK
* @retval -1 Error
*/
int
yang_cardinality_interval(clixon_handle h,
enum rfc_6020 parent_key,
enum rfc_6020 child_key,
int *min,
int *max)
{
int retval = -1;
const struct ycard *ycplist; /* ycard parent table*/
if ((ycplist = _yc_search[parent_key][child_key]) == NULL){
clixon_err(OE_YANG, EINVAL, "keys %d %d do not have cardinality",
parent_key, child_key);
goto done;
}
*min = ycplist->yc_min;
*max = ycplist->yc_max;
retval = 0;
done:
return retval;
}
/*! Init
*
* @param[in] h Clixon handle
*/
int
yang_cardinality_init(clixon_handle h)
{
const struct ycard *yc;
for (yc = &_yclist[0]; (int)yc->yc_parent; yc++){
if (_yc_exist[yc->yc_parent] == NULL)
_yc_exist[yc->yc_parent] = yc;
_yc_search[yc->yc_parent][yc->yc_child] = yc;
}
return 0;
}