1 /**
2  * @file metadata.c
3  * @author Radek Krejci <rkrejci@cesnet.cz>
4  * @brief libyang extension plugin - YANG Metadata (annotations) (RFC 7952)
5  *
6  * Copyright (c) 2016-2017 CESNET, z.s.p.o.
7  *
8  * This source code is licensed under BSD 3-Clause License (the "License").
9  * You may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *     https://opensource.org/licenses/BSD-3-Clause
13  */
14 
15 #ifdef __GNUC__
16 #  define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
17 #else
18 #  define UNUSED(x) UNUSED_ ## x
19 #endif
20 
21 #include "../extensions.h"
22 
23 /**
24  * @brief Storage for ID used to check plugin API version compatibility.
25  */
26 LYEXT_VERSION_CHECK
27 
28 /**
29  * @brief Callback to check that the annotation can be instantiated inside the provided node
30  *
31  * @param[in] parent The parent of the instantiated extension.
32  * @param[in] parent_type The type of the structure provided as \p parent.
33  * @param[in] substmt_type libyang does not store all the extension instances in the structures where they are
34  *                         instantiated in the module. In some cases (see #LYEXT_SUBSTMT) they are stored in parent
35  *                         structure and marked with flag to know in which substatement of the parent the extension
36  *                         was originally instantiated.
37  * @return 0 - ok
38  *         1 - error
39  */
annotation_position(const void * UNUSED (parent),LYEXT_PAR parent_type,LYEXT_SUBSTMT UNUSED (substmt_type))40 int annotation_position(const void * UNUSED(parent), LYEXT_PAR parent_type, LYEXT_SUBSTMT UNUSED(substmt_type))
41 {
42     /* annotations can appear only at the top level of a YANG module or submodule */
43     if (parent_type == LYEXT_PAR_MODULE) {
44         return 0;
45     } else {
46         return 1;
47     }
48 }
49 
50 /**
51  * @brief Callback to check that the extension instance is correct - have
52  * the valid argument, cardinality, etc.
53  *
54  * In Metadata case, we are checking for the annotation names duplication.
55  *
56  * @param[in] ext Extension instance to be checked.
57  * @return 0 - ok
58  *         1 - error
59  */
60 int
annotation_final_check(struct lys_ext_instance * ext)61 annotation_final_check(struct lys_ext_instance *ext)
62 {
63     uint8_t  i, j, c;
64     struct lys_module *mod;
65     struct lys_submodule *submod;
66     struct lys_type *type;
67 
68     /*
69      * check type - leafref is not allowed
70      */
71     type = *(struct lys_type**)lys_ext_complex_get_substmt(LY_STMT_TYPE, (struct lys_ext_instance_complex *)ext, NULL);
72     if (type->base == LY_TYPE_LEAFREF) {
73         LYEXT_LOG(ext->module->ctx, LY_LLERR, "Annotations", "The leafref type is not supported for annotations (annotation %s).",
74                   ext->arg_value);
75         return 1;
76     }
77 
78     /*
79      * check duplication
80      */
81     if (ext->flags & LYEXT_OPT_PLUGIN1) {
82         /* already checked */
83         ext->flags &= ~LYEXT_OPT_PLUGIN1;
84         return 0;
85     }
86 
87     mod = lys_main_module((struct lys_module *)ext->parent);
88 
89     for (i = c = 0; i < mod->ext_size; i++) {
90         /* note, that it is not necessary to check also ext->insubstmt since
91          * annotation_position() ensures that annotation instances are placed only
92          * in module or submodule */
93         if (mod->ext[i]->def == ext->def && mod->ext[i]->arg_value == ext->arg_value) {
94             if (mod->ext[i] != ext) {
95                 /* do not mark the instance being checked */
96                 mod->ext[i]->flags |= LYEXT_OPT_PLUGIN1;
97             }
98             c++;
99         }
100     }
101     /* similarly, go through the all extensions in the main module submodules */
102     for (j = 0; j < mod->inc_size; j++) {
103         submod = mod->inc[j].submodule; /* shortcut */
104         for (i = 0; i < submod->ext_size; i++) {
105             if (submod->ext[i]->def == ext->def && submod->ext[i]->arg_value == ext->arg_value) {
106                 if (submod->ext[i] != ext) {
107                     /* do not mark the instance being checked */
108                     submod->ext[i]->flags |= LYEXT_OPT_PLUGIN1;
109                 }
110                 c++;
111             }
112         }
113     }
114 
115     if (c > 1) {
116         LYEXT_LOG(ext->module->ctx, LY_LLERR, "Annotations",
117                   "Annotation instance %s is not unique, there are %d instances with the same name in module %s.",
118                   ext->arg_value, c, ((struct lys_module *)ext->parent)->name);
119         return 1;
120     } else {
121         return 0;
122     }
123 }
124 /**
125  * extension instance's content:
126  * struct lys_type *type;
127  * const char* dsc;
128  * const char* ref;
129  * const char* units;
130  * struct lys_iffeature **iff;
131  * uint16_t status;
132  *
133  * - placement in the structure is specified via offsets
134  * - the order in lyext_substmt structure specified the canonical order in which the items are printed
135  */
136 struct lyext_substmt annotation_substmt[] = {
137     {LY_STMT_IFFEATURE, 4 * sizeof(void *),  LY_STMT_CARD_ANY},
138     {LY_STMT_TYPE, 0, LY_STMT_CARD_MAND},
139     {LY_STMT_UNITS, 3 * sizeof(void *),  LY_STMT_CARD_OPT},
140     {LY_STMT_STATUS, 5 * sizeof(void *),  LY_STMT_CARD_OPT},
141     {LY_STMT_DESCRIPTION, 1 * sizeof(void *),  LY_STMT_CARD_OPT},
142     {LY_STMT_REFERENCE, 2 * sizeof(void *),  LY_STMT_CARD_OPT},
143     {0, 0, 0} /* terminating item */
144 };
145 
146 /**
147  * @brief Plugin for the RFC 7952's annotation extension
148  */
149 struct lyext_plugin_complex annotation = {
150     .type = LYEXT_COMPLEX,
151     .flags = 0,
152     .check_position = &annotation_position,
153     .check_result = &annotation_final_check,
154     .check_inherit = NULL,
155 
156     /* specification of allowed substatements of the extension instance */
157     .substmt = annotation_substmt,
158 
159     /* final size of the extension instance structure with the space for storing the substatements */
160     .instance_size = (sizeof(struct lys_ext_instance_complex) - 1) + 5 * sizeof(void*) + sizeof(uint16_t)
161 };
162 
163 /**
164  * @brief list of all extension plugins implemented here
165  *
166  * MANDATORY object for all libyang extension plugins, the name must match the <name>.so
167  */
168 struct lyext_plugin_list metadata[] = {
169     {"ietf-yang-metadata", "2016-08-05", "annotation", (struct lyext_plugin*)&annotation},
170     {NULL, NULL, NULL, NULL} /* terminating item */
171 };
172