]>
Commit | Line | Data |
---|---|---|
1c2facd1 RW |
1 | /* |
2 | * Copyright (C) 2018 NetDEF, Inc. | |
3 | * Renato Westphal | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify it | |
6 | * under the terms of the GNU General Public License as published by the Free | |
7 | * Software Foundation; either version 2 of the License, or (at your option) | |
8 | * any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
13 | * more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License along | |
16 | * with this program; see the file COPYING; if not, write to the Free Software | |
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
18 | */ | |
19 | ||
20 | #include <zebra.h> | |
21 | ||
22 | #include "log.h" | |
23 | #include "lib_errors.h" | |
24 | #include "hash.h" | |
25 | #include "yang.h" | |
26 | #include "yang_translator.h" | |
f9ce1142 | 27 | #include "frrstr.h" |
1c2facd1 | 28 | |
bf8d3d6a DL |
29 | DEFINE_MTYPE_STATIC(LIB, YANG_TRANSLATOR, "YANG Translator"); |
30 | DEFINE_MTYPE_STATIC(LIB, YANG_TRANSLATOR_MODULE, "YANG Translator Module"); | |
31 | DEFINE_MTYPE_STATIC(LIB, YANG_TRANSLATOR_MAPPING, "YANG Translator Mapping"); | |
1c2facd1 RW |
32 | |
33 | /* Generate the yang_translators tree. */ | |
34 | static inline int yang_translator_compare(const struct yang_translator *a, | |
35 | const struct yang_translator *b) | |
36 | { | |
37 | return strcmp(a->family, b->family); | |
38 | } | |
39 | RB_GENERATE(yang_translators, yang_translator, entry, yang_translator_compare) | |
40 | ||
41 | struct yang_translators yang_translators = RB_INITIALIZER(&yang_translators); | |
42 | ||
43 | /* Separate libyang context for the translator module. */ | |
44 | static struct ly_ctx *ly_translator_ctx; | |
45 | ||
46 | static unsigned int | |
47 | yang_translator_validate(struct yang_translator *translator); | |
48 | static unsigned int yang_module_nodes_count(const struct lys_module *module); | |
1c2facd1 RW |
49 | |
50 | struct yang_mapping_node { | |
51 | char xpath_from_canonical[XPATH_MAXLEN]; | |
52 | char xpath_from_fmt[XPATH_MAXLEN]; | |
53 | char xpath_to_fmt[XPATH_MAXLEN]; | |
54 | }; | |
55 | ||
56 | static bool yang_mapping_hash_cmp(const void *value1, const void *value2) | |
57 | { | |
58 | const struct yang_mapping_node *c1 = value1; | |
59 | const struct yang_mapping_node *c2 = value2; | |
60 | ||
61 | return strmatch(c1->xpath_from_canonical, c2->xpath_from_canonical); | |
62 | } | |
63 | ||
d8b87afe | 64 | static unsigned int yang_mapping_hash_key(const void *value) |
1c2facd1 RW |
65 | { |
66 | return string_hash_make(value); | |
67 | } | |
68 | ||
69 | static void *yang_mapping_hash_alloc(void *p) | |
70 | { | |
71 | struct yang_mapping_node *new, *key = p; | |
72 | ||
73 | new = XCALLOC(MTYPE_YANG_TRANSLATOR_MAPPING, sizeof(*new)); | |
74 | strlcpy(new->xpath_from_canonical, key->xpath_from_canonical, | |
75 | sizeof(new->xpath_from_canonical)); | |
76 | ||
77 | return new; | |
78 | } | |
79 | ||
80 | static void yang_mapping_hash_free(void *arg) | |
81 | { | |
82 | XFREE(MTYPE_YANG_TRANSLATOR_MAPPING, arg); | |
83 | } | |
84 | ||
85 | static struct yang_mapping_node * | |
86 | yang_mapping_lookup(const struct yang_translator *translator, int dir, | |
87 | const char *xpath) | |
88 | { | |
89 | struct yang_mapping_node s; | |
90 | ||
91 | strlcpy(s.xpath_from_canonical, xpath, sizeof(s.xpath_from_canonical)); | |
92 | return hash_lookup(translator->mappings[dir], &s); | |
93 | } | |
94 | ||
95 | static void yang_mapping_add(struct yang_translator *translator, int dir, | |
3bb513c3 | 96 | const struct lysc_node *snode, |
1c2facd1 RW |
97 | const char *xpath_from_fmt, |
98 | const char *xpath_to_fmt) | |
99 | { | |
100 | struct yang_mapping_node *mapping, s; | |
101 | ||
102 | yang_snode_get_path(snode, YANG_PATH_DATA, s.xpath_from_canonical, | |
103 | sizeof(s.xpath_from_canonical)); | |
104 | mapping = hash_get(translator->mappings[dir], &s, | |
105 | yang_mapping_hash_alloc); | |
106 | strlcpy(mapping->xpath_from_fmt, xpath_from_fmt, | |
107 | sizeof(mapping->xpath_from_fmt)); | |
108 | strlcpy(mapping->xpath_to_fmt, xpath_to_fmt, | |
109 | sizeof(mapping->xpath_to_fmt)); | |
f9ce1142 QY |
110 | |
111 | const char *keys[] = {"KEY1", "KEY2", "KEY3", "KEY4"}; | |
112 | char *xpfmt; | |
113 | ||
114 | for (unsigned int i = 0; i < array_size(keys); i++) { | |
115 | xpfmt = frrstr_replace(mapping->xpath_from_fmt, keys[i], | |
116 | "%[^']"); | |
117 | strlcpy(mapping->xpath_from_fmt, xpfmt, | |
118 | sizeof(mapping->xpath_from_fmt)); | |
119 | XFREE(MTYPE_TMP, xpfmt); | |
120 | } | |
121 | ||
122 | for (unsigned int i = 0; i < array_size(keys); i++) { | |
123 | xpfmt = frrstr_replace(mapping->xpath_to_fmt, keys[i], "%s"); | |
124 | strlcpy(mapping->xpath_to_fmt, xpfmt, | |
125 | sizeof(mapping->xpath_to_fmt)); | |
126 | XFREE(MTYPE_TMP, xpfmt); | |
127 | } | |
1c2facd1 RW |
128 | } |
129 | ||
130 | struct yang_translator *yang_translator_load(const char *path) | |
131 | { | |
132 | struct yang_translator *translator; | |
133 | struct yang_tmodule *tmodule; | |
134 | const char *family; | |
135 | struct lyd_node *dnode; | |
136 | struct ly_set *set; | |
137 | struct listnode *ln; | |
3bb513c3 | 138 | LY_ERR err; |
1c2facd1 RW |
139 | |
140 | /* Load module translator (JSON file). */ | |
3bb513c3 CH |
141 | err = lyd_parse_data_path(ly_translator_ctx, path, LYD_JSON, |
142 | LYD_PARSE_NO_STATE, LYD_VALIDATE_NO_STATE, | |
143 | &dnode); | |
144 | if (err) { | |
1c2facd1 | 145 | flog_warn(EC_LIB_YANG_TRANSLATOR_LOAD, |
3bb513c3 | 146 | "%s: lyd_parse_path() failed: %d", __func__, err); |
1c2facd1 RW |
147 | return NULL; |
148 | } | |
149 | dnode = yang_dnode_get(dnode, | |
150 | "/frr-module-translator:frr-module-translator"); | |
151 | /* | |
152 | * libyang guarantees the "frr-module-translator" top-level container is | |
153 | * always present since it contains mandatory child nodes. | |
154 | */ | |
155 | assert(dnode); | |
156 | ||
157 | family = yang_dnode_get_string(dnode, "./family"); | |
158 | translator = yang_translator_find(family); | |
159 | if (translator != NULL) { | |
160 | flog_warn(EC_LIB_YANG_TRANSLATOR_LOAD, | |
161 | "%s: module translator \"%s\" is loaded already", | |
162 | __func__, family); | |
163 | return NULL; | |
164 | } | |
165 | ||
166 | translator = XCALLOC(MTYPE_YANG_TRANSLATOR, sizeof(*translator)); | |
167 | strlcpy(translator->family, family, sizeof(translator->family)); | |
168 | translator->modules = list_new(); | |
169 | for (size_t i = 0; i < YANG_TRANSLATE_MAX; i++) | |
170 | translator->mappings[i] = hash_create(yang_mapping_hash_key, | |
171 | yang_mapping_hash_cmp, | |
172 | "YANG translation table"); | |
173 | RB_INSERT(yang_translators, &yang_translators, translator); | |
174 | ||
175 | /* Initialize the translator libyang context. */ | |
3bb513c3 | 176 | translator->ly_ctx = yang_ctx_new_setup(false, false); |
1c2facd1 RW |
177 | if (!translator->ly_ctx) { |
178 | flog_warn(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__); | |
179 | goto error; | |
180 | } | |
1c2facd1 | 181 | |
3bb513c3 CH |
182 | /* Load modules */ |
183 | if (lyd_find_xpath(dnode, "./module", &set) != LY_SUCCESS) | |
184 | assert(0); /* XXX libyang2: old ly1 code asserted success */ | |
185 | ||
186 | for (size_t i = 0; i < set->count; i++) { | |
1c2facd1 RW |
187 | const char *module_name; |
188 | ||
189 | tmodule = | |
190 | XCALLOC(MTYPE_YANG_TRANSLATOR_MODULE, sizeof(*tmodule)); | |
191 | ||
3bb513c3 | 192 | module_name = yang_dnode_get_string(set->dnodes[i], "./name"); |
1c2facd1 | 193 | tmodule->module = ly_ctx_load_module(translator->ly_ctx, |
3bb513c3 | 194 | module_name, NULL, NULL); |
1c2facd1 RW |
195 | if (!tmodule->module) { |
196 | flog_warn(EC_LIB_YANG_TRANSLATOR_LOAD, | |
197 | "%s: failed to load module: %s", __func__, | |
198 | module_name); | |
3bb513c3 | 199 | ly_set_free(set, NULL); |
1c2facd1 RW |
200 | goto error; |
201 | } | |
3bb513c3 | 202 | } |
1c2facd1 | 203 | |
3bb513c3 CH |
204 | /* Count nodes in modules. */ |
205 | for (ALL_LIST_ELEMENTS_RO(translator->modules, ln, tmodule)) { | |
206 | tmodule->nodes_before_deviations = | |
207 | yang_module_nodes_count(tmodule->module); | |
208 | } | |
209 | ||
210 | /* Load the deviations and count nodes again */ | |
211 | for (ALL_LIST_ELEMENTS_RO(translator->modules, ln, tmodule)) { | |
212 | const char *module_name = tmodule->module->name; | |
213 | tmodule->deviations = ly_ctx_load_module( | |
214 | translator->ly_ctx, module_name, NULL, NULL); | |
1c2facd1 RW |
215 | if (!tmodule->deviations) { |
216 | flog_warn(EC_LIB_YANG_TRANSLATOR_LOAD, | |
217 | "%s: failed to load module: %s", __func__, | |
218 | module_name); | |
3bb513c3 | 219 | ly_set_free(set, NULL); |
1c2facd1 RW |
220 | goto error; |
221 | } | |
1c2facd1 | 222 | |
3bb513c3 CH |
223 | tmodule->nodes_after_deviations = |
224 | yang_module_nodes_count(tmodule->module); | |
1c2facd1 | 225 | } |
3bb513c3 | 226 | ly_set_free(set, NULL); |
1c2facd1 RW |
227 | |
228 | /* Calculate the coverage. */ | |
229 | for (ALL_LIST_ELEMENTS_RO(translator->modules, ln, tmodule)) { | |
1c2facd1 RW |
230 | tmodule->coverage = ((double)tmodule->nodes_after_deviations |
231 | / (double)tmodule->nodes_before_deviations) | |
232 | * 100; | |
233 | } | |
234 | ||
235 | /* Load mappings. */ | |
3bb513c3 CH |
236 | if (lyd_find_xpath(dnode, "./module/mappings", &set) != LY_SUCCESS) |
237 | assert(0); /* XXX libyang2: old ly1 code asserted success */ | |
238 | for (size_t i = 0; i < set->count; i++) { | |
1c2facd1 | 239 | const char *xpath_custom, *xpath_native; |
3bb513c3 CH |
240 | const struct lysc_node *snode_custom, *snode_native; |
241 | ||
242 | xpath_custom = | |
243 | yang_dnode_get_string(set->dnodes[i], "./custom"); | |
1c2facd1 | 244 | |
3bb513c3 CH |
245 | snode_custom = lys_find_path(translator->ly_ctx, NULL, |
246 | xpath_custom, 0); | |
1c2facd1 RW |
247 | if (!snode_custom) { |
248 | flog_warn(EC_LIB_YANG_TRANSLATOR_LOAD, | |
249 | "%s: unknown data path: %s", __func__, | |
250 | xpath_custom); | |
3bb513c3 | 251 | ly_set_free(set, NULL); |
1c2facd1 RW |
252 | goto error; |
253 | } | |
254 | ||
3bb513c3 CH |
255 | xpath_native = |
256 | yang_dnode_get_string(set->dnodes[i], "./native"); | |
1c2facd1 | 257 | snode_native = |
3bb513c3 | 258 | lys_find_path(ly_native_ctx, NULL, xpath_native, 0); |
1c2facd1 RW |
259 | if (!snode_native) { |
260 | flog_warn(EC_LIB_YANG_TRANSLATOR_LOAD, | |
261 | "%s: unknown data path: %s", __func__, | |
262 | xpath_native); | |
3bb513c3 | 263 | ly_set_free(set, NULL); |
1c2facd1 RW |
264 | goto error; |
265 | } | |
266 | ||
267 | yang_mapping_add(translator, YANG_TRANSLATE_TO_NATIVE, | |
268 | snode_custom, xpath_custom, xpath_native); | |
269 | yang_mapping_add(translator, YANG_TRANSLATE_FROM_NATIVE, | |
270 | snode_native, xpath_native, xpath_custom); | |
271 | } | |
3bb513c3 | 272 | ly_set_free(set, NULL); |
1c2facd1 RW |
273 | |
274 | /* Validate mappings. */ | |
275 | if (yang_translator_validate(translator) != 0) | |
276 | goto error; | |
277 | ||
278 | yang_dnode_free(dnode); | |
279 | ||
280 | return translator; | |
281 | ||
282 | error: | |
283 | yang_dnode_free(dnode); | |
284 | yang_translator_unload(translator); | |
285 | ||
286 | return NULL; | |
287 | } | |
288 | ||
289 | static void yang_tmodule_delete(struct yang_tmodule *tmodule) | |
290 | { | |
291 | XFREE(MTYPE_YANG_TRANSLATOR_MODULE, tmodule); | |
292 | } | |
293 | ||
294 | void yang_translator_unload(struct yang_translator *translator) | |
295 | { | |
296 | for (size_t i = 0; i < YANG_TRANSLATE_MAX; i++) | |
297 | hash_clean(translator->mappings[i], yang_mapping_hash_free); | |
298 | translator->modules->del = (void (*)(void *))yang_tmodule_delete; | |
299 | list_delete(&translator->modules); | |
3bb513c3 | 300 | ly_ctx_destroy(translator->ly_ctx); |
1c2facd1 RW |
301 | RB_REMOVE(yang_translators, &yang_translators, translator); |
302 | XFREE(MTYPE_YANG_TRANSLATOR, translator); | |
303 | } | |
304 | ||
305 | struct yang_translator *yang_translator_find(const char *family) | |
306 | { | |
307 | struct yang_translator s; | |
308 | ||
309 | strlcpy(s.family, family, sizeof(s.family)); | |
310 | return RB_FIND(yang_translators, &yang_translators, &s); | |
311 | } | |
312 | ||
313 | enum yang_translate_result | |
314 | yang_translate_xpath(const struct yang_translator *translator, int dir, | |
315 | char *xpath, size_t xpath_len) | |
316 | { | |
317 | struct ly_ctx *ly_ctx; | |
3bb513c3 | 318 | const struct lysc_node *snode; |
1c2facd1 RW |
319 | struct yang_mapping_node *mapping; |
320 | char xpath_canonical[XPATH_MAXLEN]; | |
321 | char keys[4][LIST_MAXKEYLEN]; | |
322 | int n; | |
323 | ||
324 | if (dir == YANG_TRANSLATE_TO_NATIVE) | |
325 | ly_ctx = translator->ly_ctx; | |
326 | else | |
327 | ly_ctx = ly_native_ctx; | |
328 | ||
3bb513c3 | 329 | snode = lys_find_path(ly_ctx, NULL, xpath, 0); |
1c2facd1 RW |
330 | if (!snode) { |
331 | flog_warn(EC_LIB_YANG_TRANSLATION_ERROR, | |
332 | "%s: unknown data path: %s", __func__, xpath); | |
333 | return YANG_TRANSLATE_FAILURE; | |
334 | } | |
335 | ||
336 | yang_snode_get_path(snode, YANG_PATH_DATA, xpath_canonical, | |
337 | sizeof(xpath_canonical)); | |
338 | mapping = yang_mapping_lookup(translator, dir, xpath_canonical); | |
339 | if (!mapping) | |
340 | return YANG_TRANSLATE_NOTFOUND; | |
341 | ||
342 | n = sscanf(xpath, mapping->xpath_from_fmt, keys[0], keys[1], keys[2], | |
343 | keys[3]); | |
344 | if (n < 0) { | |
345 | flog_warn(EC_LIB_YANG_TRANSLATION_ERROR, | |
346 | "%s: sscanf() failed: %s", __func__, | |
347 | safe_strerror(errno)); | |
348 | return YANG_TRANSLATE_FAILURE; | |
349 | } | |
350 | ||
351 | snprintf(xpath, xpath_len, mapping->xpath_to_fmt, keys[0], keys[1], | |
352 | keys[2], keys[3]); | |
353 | ||
354 | return YANG_TRANSLATE_SUCCESS; | |
355 | } | |
356 | ||
357 | int yang_translate_dnode(const struct yang_translator *translator, int dir, | |
358 | struct lyd_node **dnode) | |
359 | { | |
360 | struct ly_ctx *ly_ctx; | |
361 | struct lyd_node *new; | |
3bb513c3 | 362 | struct lyd_node *root, *dnode_iter; |
1c2facd1 RW |
363 | |
364 | /* Create new libyang data node to hold the translated data. */ | |
365 | if (dir == YANG_TRANSLATE_TO_NATIVE) | |
366 | ly_ctx = ly_native_ctx; | |
367 | else | |
368 | ly_ctx = translator->ly_ctx; | |
5e02643a | 369 | new = yang_dnode_new(ly_ctx, false); |
1c2facd1 RW |
370 | |
371 | /* Iterate over all nodes from the data tree. */ | |
3bb513c3 CH |
372 | LY_LIST_FOR (*dnode, root) { |
373 | LYD_TREE_DFS_BEGIN (root, dnode_iter) { | |
1c2facd1 RW |
374 | char xpath[XPATH_MAXLEN]; |
375 | enum yang_translate_result ret; | |
376 | ||
377 | yang_dnode_get_path(dnode_iter, xpath, sizeof(xpath)); | |
378 | ret = yang_translate_xpath(translator, dir, xpath, | |
379 | sizeof(xpath)); | |
380 | switch (ret) { | |
381 | case YANG_TRANSLATE_SUCCESS: | |
382 | break; | |
383 | case YANG_TRANSLATE_NOTFOUND: | |
384 | goto next; | |
385 | case YANG_TRANSLATE_FAILURE: | |
386 | goto error; | |
387 | } | |
388 | ||
389 | /* Create new node in the tree of translated data. */ | |
3bb513c3 CH |
390 | if (lyd_new_path(new, ly_ctx, xpath, |
391 | (void *)yang_dnode_get_string( | |
392 | dnode_iter, NULL), | |
393 | LYD_NEW_PATH_UPDATE, NULL)) { | |
1c2facd1 RW |
394 | flog_err(EC_LIB_LIBYANG, |
395 | "%s: lyd_new_path() failed", __func__); | |
396 | goto error; | |
397 | } | |
398 | ||
399 | next: | |
3bb513c3 | 400 | LYD_TREE_DFS_END(root, dnode_iter); |
1c2facd1 RW |
401 | } |
402 | } | |
403 | ||
404 | /* Replace dnode by the new translated dnode. */ | |
405 | yang_dnode_free(*dnode); | |
406 | *dnode = new; | |
407 | ||
408 | return YANG_TRANSLATE_SUCCESS; | |
409 | ||
410 | error: | |
411 | yang_dnode_free(new); | |
412 | ||
413 | return YANG_TRANSLATE_FAILURE; | |
414 | } | |
415 | ||
e0ccfad2 RW |
416 | struct translator_validate_args { |
417 | struct yang_translator *translator; | |
418 | unsigned int errors; | |
419 | }; | |
420 | ||
3bb513c3 | 421 | static int yang_translator_validate_cb(const struct lysc_node *snode_custom, |
e0ccfad2 | 422 | void *arg) |
1c2facd1 | 423 | { |
e0ccfad2 | 424 | struct translator_validate_args *args = arg; |
1c2facd1 | 425 | struct yang_mapping_node *mapping; |
3bb513c3 CH |
426 | const struct lysc_node *snode_native; |
427 | const struct lysc_type *stype_custom, *stype_native; | |
1c2facd1 RW |
428 | char xpath[XPATH_MAXLEN]; |
429 | ||
430 | yang_snode_get_path(snode_custom, YANG_PATH_DATA, xpath, sizeof(xpath)); | |
e0ccfad2 RW |
431 | mapping = yang_mapping_lookup(args->translator, |
432 | YANG_TRANSLATE_TO_NATIVE, xpath); | |
1c2facd1 RW |
433 | if (!mapping) { |
434 | flog_warn(EC_LIB_YANG_TRANSLATOR_LOAD, | |
435 | "%s: missing mapping for \"%s\"", __func__, xpath); | |
e0ccfad2 RW |
436 | args->errors += 1; |
437 | return YANG_ITER_CONTINUE; | |
1c2facd1 RW |
438 | } |
439 | ||
440 | snode_native = | |
3bb513c3 | 441 | lys_find_path(ly_native_ctx, NULL, mapping->xpath_to_fmt, 0); |
1c2facd1 RW |
442 | assert(snode_native); |
443 | ||
444 | /* Check if the YANG types are compatible. */ | |
445 | stype_custom = yang_snode_get_type(snode_custom); | |
446 | stype_native = yang_snode_get_type(snode_native); | |
447 | if (stype_custom && stype_native) { | |
3bb513c3 | 448 | if (stype_custom->basetype != stype_native->basetype) { |
1c2facd1 RW |
449 | flog_warn( |
450 | EC_LIB_YANG_TRANSLATOR_LOAD, | |
451 | "%s: YANG types are incompatible (xpath: \"%s\")", | |
452 | __func__, xpath); | |
e0ccfad2 RW |
453 | args->errors += 1; |
454 | return YANG_ITER_CONTINUE; | |
1c2facd1 RW |
455 | } |
456 | ||
457 | /* TODO: check if the value spaces are identical. */ | |
458 | } | |
e0ccfad2 RW |
459 | |
460 | return YANG_ITER_CONTINUE; | |
1c2facd1 RW |
461 | } |
462 | ||
463 | /* | |
464 | * Check if the modules from the translator have a mapping for all of their | |
465 | * schema nodes (after loading the deviations). | |
466 | */ | |
467 | static unsigned int yang_translator_validate(struct yang_translator *translator) | |
468 | { | |
469 | struct yang_tmodule *tmodule; | |
470 | struct listnode *ln; | |
e0ccfad2 RW |
471 | struct translator_validate_args args; |
472 | ||
473 | args.translator = translator; | |
474 | args.errors = 0; | |
1c2facd1 RW |
475 | |
476 | for (ALL_LIST_ELEMENTS_RO(translator->modules, ln, tmodule)) { | |
8d869d37 RW |
477 | yang_snodes_iterate(tmodule->module, |
478 | yang_translator_validate_cb, | |
479 | YANG_ITER_FILTER_NPCONTAINERS | |
480 | | YANG_ITER_FILTER_LIST_KEYS | |
481 | | YANG_ITER_FILTER_INPUT_OUTPUT, | |
482 | &args); | |
1c2facd1 RW |
483 | } |
484 | ||
e0ccfad2 | 485 | if (args.errors) |
1c2facd1 RW |
486 | flog_warn( |
487 | EC_LIB_YANG_TRANSLATOR_LOAD, | |
488 | "%s: failed to validate \"%s\" module translator: %u error(s)", | |
e0ccfad2 | 489 | __func__, translator->family, args.errors); |
1c2facd1 | 490 | |
e0ccfad2 | 491 | return args.errors; |
1c2facd1 RW |
492 | } |
493 | ||
3bb513c3 | 494 | static int yang_module_nodes_count_cb(const struct lysc_node *snode, void *arg) |
1c2facd1 | 495 | { |
e0ccfad2 | 496 | unsigned int *total = arg; |
1c2facd1 RW |
497 | |
498 | *total += 1; | |
e0ccfad2 RW |
499 | |
500 | return YANG_ITER_CONTINUE; | |
1c2facd1 RW |
501 | } |
502 | ||
503 | /* Calculate the number of nodes for the given module. */ | |
504 | static unsigned int yang_module_nodes_count(const struct lys_module *module) | |
505 | { | |
506 | unsigned int total = 0; | |
507 | ||
8d869d37 RW |
508 | yang_snodes_iterate(module, yang_module_nodes_count_cb, |
509 | YANG_ITER_FILTER_NPCONTAINERS | |
510 | | YANG_ITER_FILTER_LIST_KEYS | |
511 | | YANG_ITER_FILTER_INPUT_OUTPUT, | |
512 | &total); | |
1c2facd1 RW |
513 | |
514 | return total; | |
515 | } | |
516 | ||
1c2facd1 RW |
517 | void yang_translator_init(void) |
518 | { | |
3bb513c3 | 519 | ly_translator_ctx = yang_ctx_new_setup(true, false); |
1c2facd1 RW |
520 | if (!ly_translator_ctx) { |
521 | flog_err(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__); | |
522 | exit(1); | |
523 | } | |
1c2facd1 RW |
524 | |
525 | if (!ly_ctx_load_module(ly_translator_ctx, "frr-module-translator", | |
3bb513c3 | 526 | NULL, NULL)) { |
1c2facd1 RW |
527 | flog_err( |
528 | EC_LIB_YANG_MODULE_LOAD, | |
529 | "%s: failed to load the \"frr-module-translator\" module", | |
530 | __func__); | |
531 | exit(1); | |
532 | } | |
533 | } | |
534 | ||
535 | void yang_translator_terminate(void) | |
536 | { | |
537 | while (!RB_EMPTY(yang_translators, &yang_translators)) { | |
538 | struct yang_translator *translator; | |
539 | ||
540 | translator = RB_ROOT(yang_translators, &yang_translators); | |
541 | yang_translator_unload(translator); | |
542 | } | |
543 | ||
3bb513c3 | 544 | ly_ctx_destroy(ly_translator_ctx); |
1c2facd1 | 545 | } |