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