]>
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 "northbound.h" | |
566bdaf6 | 25 | #include "printfrr.h" |
cad46cfd | 26 | #include "nexthop.h" |
8d0c8ff5 | 27 | #include "printfrr.h" |
1c2facd1 | 28 | |
3bb513c3 CH |
29 | |
30 | #define YANG_DNODE_XPATH_GET_VALUE(dnode, xpath_fmt) \ | |
31 | ({ \ | |
32 | va_list __ap; \ | |
33 | va_start(__ap, (xpath_fmt)); \ | |
34 | const struct lyd_value *__dvalue = \ | |
35 | yang_dnode_xpath_get_value(dnode, xpath_fmt, __ap); \ | |
36 | va_end(__ap); \ | |
37 | __dvalue; \ | |
38 | }) | |
39 | ||
40 | #define YANG_DNODE_XPATH_GET_CANON(dnode, xpath_fmt) \ | |
41 | ({ \ | |
42 | va_list __ap; \ | |
43 | va_start(__ap, (xpath_fmt)); \ | |
44 | const char *__canon = \ | |
45 | yang_dnode_xpath_get_canon(dnode, xpath_fmt, __ap); \ | |
46 | va_end(__ap); \ | |
47 | __canon; \ | |
48 | }) | |
49 | ||
50 | #define YANG_DNODE_GET_ASSERT(dnode, xpath) \ | |
51 | do { \ | |
52 | if ((dnode) == NULL) { \ | |
53 | flog_err(EC_LIB_YANG_DNODE_NOT_FOUND, \ | |
54 | "%s: couldn't find %s", __func__, (xpath)); \ | |
55 | zlog_backtrace(LOG_ERR); \ | |
56 | abort(); \ | |
57 | } \ | |
58 | } while (0) | |
59 | ||
60 | static inline const char * | |
61 | yang_dnode_xpath_get_canon(const struct lyd_node *dnode, const char *xpath_fmt, | |
62 | va_list ap) | |
63 | { | |
64 | const struct lyd_node_term *__dleaf = | |
65 | (const struct lyd_node_term *)dnode; | |
66 | assert(__dleaf); | |
67 | if (xpath_fmt) { | |
68 | char __xpath[XPATH_MAXLEN]; | |
69 | vsnprintf(__xpath, sizeof(__xpath), xpath_fmt, ap); | |
70 | __dleaf = (const struct lyd_node_term *)yang_dnode_get(dnode, | |
71 | __xpath); | |
72 | YANG_DNODE_GET_ASSERT(__dleaf, __xpath); | |
73 | } | |
74 | return lyd_get_value(&__dleaf->node); | |
75 | } | |
76 | ||
77 | static inline const struct lyd_value * | |
78 | yang_dnode_xpath_get_value(const struct lyd_node *dnode, const char *xpath_fmt, | |
79 | va_list ap) | |
80 | { | |
81 | const struct lyd_node_term *__dleaf = | |
82 | (const struct lyd_node_term *)dnode; | |
83 | assert(__dleaf); | |
84 | if (xpath_fmt) { | |
85 | char __xpath[XPATH_MAXLEN]; | |
86 | vsnprintf(__xpath, sizeof(__xpath), xpath_fmt, ap); | |
87 | __dleaf = (const struct lyd_node_term *)yang_dnode_get(dnode, | |
88 | __xpath); | |
89 | YANG_DNODE_GET_ASSERT(__dleaf, __xpath); | |
90 | } | |
91 | const struct lyd_value *__dvalue = &__dleaf->value; | |
92 | if (__dvalue->realtype->basetype == LY_TYPE_UNION) | |
93 | __dvalue = &__dvalue->subvalue->value; | |
94 | return __dvalue; | |
95 | } | |
96 | ||
1c2facd1 RW |
97 | static const char *yang_get_default_value(const char *xpath) |
98 | { | |
3bb513c3 | 99 | const struct lysc_node *snode; |
1c2facd1 RW |
100 | const char *value; |
101 | ||
3bb513c3 | 102 | snode = lys_find_path(ly_native_ctx, NULL, xpath, 0); |
1c2facd1 RW |
103 | if (snode == NULL) { |
104 | flog_err(EC_LIB_YANG_UNKNOWN_DATA_PATH, | |
105 | "%s: unknown data path: %s", __func__, xpath); | |
106 | zlog_backtrace(LOG_ERR); | |
107 | abort(); | |
108 | } | |
109 | ||
110 | value = yang_snode_get_default(snode); | |
111 | assert(value); | |
112 | ||
113 | return value; | |
114 | } | |
115 | ||
1c2facd1 RW |
116 | /* |
117 | * Primitive type: bool. | |
118 | */ | |
119 | bool yang_str2bool(const char *value) | |
120 | { | |
121 | return strmatch(value, "true"); | |
122 | } | |
123 | ||
124 | struct yang_data *yang_data_new_bool(const char *xpath, bool value) | |
125 | { | |
d8729f8c | 126 | return yang_data_new(xpath, (value) ? "true" : "false"); |
1c2facd1 RW |
127 | } |
128 | ||
129 | bool yang_dnode_get_bool(const struct lyd_node *dnode, const char *xpath_fmt, | |
130 | ...) | |
131 | { | |
3bb513c3 CH |
132 | const struct lyd_value *dvalue; |
133 | dvalue = YANG_DNODE_XPATH_GET_VALUE(dnode, xpath_fmt); | |
134 | assert(dvalue->realtype->basetype == LY_TYPE_BOOL); | |
135 | return dvalue->boolean; | |
1c2facd1 RW |
136 | } |
137 | ||
138 | bool yang_get_default_bool(const char *xpath_fmt, ...) | |
139 | { | |
140 | char xpath[XPATH_MAXLEN]; | |
141 | const char *value; | |
142 | va_list ap; | |
143 | ||
144 | va_start(ap, xpath_fmt); | |
145 | vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); | |
146 | va_end(ap); | |
147 | ||
148 | value = yang_get_default_value(xpath); | |
149 | return yang_str2bool(value); | |
150 | } | |
151 | ||
152 | /* | |
153 | * Primitive type: dec64. | |
154 | */ | |
155 | double yang_str2dec64(const char *xpath, const char *value) | |
156 | { | |
157 | double dbl = 0; | |
158 | ||
159 | if (sscanf(value, "%lf", &dbl) != 1) { | |
160 | flog_err(EC_LIB_YANG_DATA_CONVERT, | |
161 | "%s: couldn't convert string to decimal64 [xpath %s]", | |
162 | __func__, xpath); | |
163 | zlog_backtrace(LOG_ERR); | |
164 | abort(); | |
165 | } | |
166 | ||
167 | return dbl; | |
168 | } | |
169 | ||
170 | struct yang_data *yang_data_new_dec64(const char *xpath, double value) | |
171 | { | |
172 | char value_str[BUFSIZ]; | |
173 | ||
174 | snprintf(value_str, sizeof(value_str), "%lf", value); | |
175 | return yang_data_new(xpath, value_str); | |
176 | } | |
177 | ||
178 | double yang_dnode_get_dec64(const struct lyd_node *dnode, const char *xpath_fmt, | |
179 | ...) | |
180 | { | |
3bb513c3 CH |
181 | const double denom[19] = {1e0, 1e-1, 1e-2, 1e-3, 1e-4, |
182 | 1e-5, 1e-6, 1e-7, 1e-8, 1e-9, | |
183 | 1e-10, 1e-11, 1e-12, 1e-13, 1e-14, | |
184 | 1e-15, 1e-16, 1e-17, 1e-18}; | |
185 | const struct lysc_type_dec *dectype; | |
186 | const struct lyd_value *dvalue; | |
1c2facd1 | 187 | |
3bb513c3 CH |
188 | dvalue = YANG_DNODE_XPATH_GET_VALUE(dnode, xpath_fmt); |
189 | dectype = (const struct lysc_type_dec *)dvalue->realtype; | |
190 | assert(dectype->basetype == LY_TYPE_DEC64); | |
191 | assert(dectype->fraction_digits < sizeof(denom) / sizeof(*denom)); | |
192 | return (double)dvalue->dec64 * denom[dectype->fraction_digits]; | |
1c2facd1 RW |
193 | } |
194 | ||
195 | double yang_get_default_dec64(const char *xpath_fmt, ...) | |
196 | { | |
197 | char xpath[XPATH_MAXLEN]; | |
198 | const char *value; | |
199 | va_list ap; | |
200 | ||
201 | va_start(ap, xpath_fmt); | |
202 | vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); | |
203 | va_end(ap); | |
204 | ||
205 | value = yang_get_default_value(xpath); | |
206 | return yang_str2dec64(xpath, value); | |
207 | } | |
208 | ||
209 | /* | |
210 | * Primitive type: enum. | |
211 | */ | |
212 | int yang_str2enum(const char *xpath, const char *value) | |
213 | { | |
3bb513c3 CH |
214 | const struct lysc_node *snode; |
215 | const struct lysc_node_leaf *sleaf; | |
216 | const struct lysc_type_enum *type; | |
217 | const struct lysc_type_bitenum_item *enums; | |
1c2facd1 | 218 | |
3bb513c3 | 219 | snode = lys_find_path(ly_native_ctx, NULL, xpath, 0); |
1c2facd1 RW |
220 | if (snode == NULL) { |
221 | flog_err(EC_LIB_YANG_UNKNOWN_DATA_PATH, | |
222 | "%s: unknown data path: %s", __func__, xpath); | |
223 | zlog_backtrace(LOG_ERR); | |
224 | abort(); | |
225 | } | |
226 | ||
3bb513c3 CH |
227 | assert(snode->nodetype == LYS_LEAF); |
228 | sleaf = (const struct lysc_node_leaf *)snode; | |
229 | type = (const struct lysc_type_enum *)sleaf->type; | |
230 | assert(type->basetype == LY_TYPE_ENUM); | |
231 | enums = type->enums; | |
232 | unsigned int count = LY_ARRAY_COUNT(enums); | |
233 | for (unsigned int i = 0; i < count; i++) { | |
234 | if (strmatch(value, enums[i].name)) { | |
235 | assert(CHECK_FLAG(enums[i].flags, LYS_SET_VALUE)); | |
236 | return enums[i].value; | |
237 | } | |
1c2facd1 RW |
238 | } |
239 | ||
240 | flog_err(EC_LIB_YANG_DATA_CONVERT, | |
241 | "%s: couldn't convert string to enum [xpath %s]", __func__, | |
242 | xpath); | |
243 | zlog_backtrace(LOG_ERR); | |
244 | abort(); | |
245 | } | |
246 | ||
247 | struct yang_data *yang_data_new_enum(const char *xpath, int value) | |
248 | { | |
3bb513c3 CH |
249 | const struct lysc_node *snode; |
250 | const struct lysc_node_leaf *sleaf; | |
251 | const struct lysc_type_enum *type; | |
252 | const struct lysc_type_bitenum_item *enums; | |
1c2facd1 | 253 | |
3bb513c3 | 254 | snode = lys_find_path(ly_native_ctx, NULL, xpath, 0); |
1c2facd1 RW |
255 | if (snode == NULL) { |
256 | flog_err(EC_LIB_YANG_UNKNOWN_DATA_PATH, | |
257 | "%s: unknown data path: %s", __func__, xpath); | |
258 | zlog_backtrace(LOG_ERR); | |
259 | abort(); | |
260 | } | |
261 | ||
3bb513c3 CH |
262 | assert(snode->nodetype == LYS_LEAF); |
263 | sleaf = (const struct lysc_node_leaf *)snode; | |
264 | type = (const struct lysc_type_enum *)sleaf->type; | |
265 | assert(type->basetype == LY_TYPE_ENUM); | |
266 | enums = type->enums; | |
267 | unsigned int count = LY_ARRAY_COUNT(enums); | |
268 | for (unsigned int i = 0; i < count; i++) { | |
269 | if (CHECK_FLAG(enums[i].flags, LYS_SET_VALUE) | |
270 | && value == enums[i].value) | |
271 | return yang_data_new(xpath, enums[i].name); | |
1c2facd1 RW |
272 | } |
273 | ||
274 | flog_err(EC_LIB_YANG_DATA_CONVERT, | |
275 | "%s: couldn't convert enum to string [xpath %s]", __func__, | |
276 | xpath); | |
277 | zlog_backtrace(LOG_ERR); | |
278 | abort(); | |
279 | } | |
280 | ||
281 | int yang_dnode_get_enum(const struct lyd_node *dnode, const char *xpath_fmt, | |
282 | ...) | |
283 | { | |
3bb513c3 | 284 | const struct lyd_value *dvalue; |
1c2facd1 | 285 | |
3bb513c3 CH |
286 | dvalue = YANG_DNODE_XPATH_GET_VALUE(dnode, xpath_fmt); |
287 | assert(dvalue->realtype->basetype == LY_TYPE_ENUM); | |
288 | assert(dvalue->enum_item->flags & LYS_SET_VALUE); | |
289 | return dvalue->enum_item->value; | |
1c2facd1 RW |
290 | } |
291 | ||
292 | int yang_get_default_enum(const char *xpath_fmt, ...) | |
293 | { | |
294 | char xpath[XPATH_MAXLEN]; | |
295 | const char *value; | |
296 | va_list ap; | |
297 | ||
298 | va_start(ap, xpath_fmt); | |
299 | vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); | |
300 | va_end(ap); | |
301 | ||
302 | value = yang_get_default_value(xpath); | |
303 | return yang_str2enum(xpath, value); | |
304 | } | |
305 | ||
306 | /* | |
307 | * Primitive type: int8. | |
308 | */ | |
309 | int8_t yang_str2int8(const char *value) | |
310 | { | |
311 | return strtol(value, NULL, 10); | |
312 | } | |
313 | ||
314 | struct yang_data *yang_data_new_int8(const char *xpath, int8_t value) | |
315 | { | |
316 | char value_str[BUFSIZ]; | |
317 | ||
318 | snprintf(value_str, sizeof(value_str), "%d", value); | |
319 | return yang_data_new(xpath, value_str); | |
320 | } | |
321 | ||
322 | int8_t yang_dnode_get_int8(const struct lyd_node *dnode, const char *xpath_fmt, | |
323 | ...) | |
324 | { | |
3bb513c3 CH |
325 | const struct lyd_value *dvalue; |
326 | dvalue = YANG_DNODE_XPATH_GET_VALUE(dnode, xpath_fmt); | |
327 | assert(dvalue->realtype->basetype == LY_TYPE_INT8); | |
328 | return dvalue->int8; | |
1c2facd1 RW |
329 | } |
330 | ||
331 | int8_t yang_get_default_int8(const char *xpath_fmt, ...) | |
332 | { | |
333 | char xpath[XPATH_MAXLEN]; | |
334 | const char *value; | |
335 | va_list ap; | |
336 | ||
337 | va_start(ap, xpath_fmt); | |
338 | vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); | |
339 | va_end(ap); | |
340 | ||
341 | value = yang_get_default_value(xpath); | |
342 | return yang_str2int8(value); | |
343 | } | |
344 | ||
345 | /* | |
346 | * Primitive type: int16. | |
347 | */ | |
348 | int16_t yang_str2int16(const char *value) | |
349 | { | |
350 | return strtol(value, NULL, 10); | |
351 | } | |
352 | ||
353 | struct yang_data *yang_data_new_int16(const char *xpath, int16_t value) | |
354 | { | |
355 | char value_str[BUFSIZ]; | |
356 | ||
357 | snprintf(value_str, sizeof(value_str), "%d", value); | |
358 | return yang_data_new(xpath, value_str); | |
359 | } | |
360 | ||
361 | int16_t yang_dnode_get_int16(const struct lyd_node *dnode, | |
362 | const char *xpath_fmt, ...) | |
363 | { | |
3bb513c3 CH |
364 | const struct lyd_value *dvalue; |
365 | dvalue = YANG_DNODE_XPATH_GET_VALUE(dnode, xpath_fmt); | |
366 | assert(dvalue->realtype->basetype == LY_TYPE_INT16); | |
367 | return dvalue->int16; | |
1c2facd1 RW |
368 | } |
369 | ||
370 | int16_t yang_get_default_int16(const char *xpath_fmt, ...) | |
371 | { | |
372 | char xpath[XPATH_MAXLEN]; | |
373 | const char *value; | |
374 | va_list ap; | |
375 | ||
376 | va_start(ap, xpath_fmt); | |
377 | vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); | |
378 | va_end(ap); | |
379 | ||
380 | value = yang_get_default_value(xpath); | |
381 | return yang_str2int16(value); | |
382 | } | |
383 | ||
384 | /* | |
385 | * Primitive type: int32. | |
386 | */ | |
387 | int32_t yang_str2int32(const char *value) | |
388 | { | |
389 | return strtol(value, NULL, 10); | |
390 | } | |
391 | ||
392 | struct yang_data *yang_data_new_int32(const char *xpath, int32_t value) | |
393 | { | |
394 | char value_str[BUFSIZ]; | |
395 | ||
396 | snprintf(value_str, sizeof(value_str), "%d", value); | |
397 | return yang_data_new(xpath, value_str); | |
398 | } | |
399 | ||
400 | int32_t yang_dnode_get_int32(const struct lyd_node *dnode, | |
401 | const char *xpath_fmt, ...) | |
402 | { | |
3bb513c3 CH |
403 | const struct lyd_value *dvalue; |
404 | dvalue = YANG_DNODE_XPATH_GET_VALUE(dnode, xpath_fmt); | |
405 | assert(dvalue->realtype->basetype == LY_TYPE_INT32); | |
406 | return dvalue->int32; | |
1c2facd1 RW |
407 | } |
408 | ||
409 | int32_t yang_get_default_int32(const char *xpath_fmt, ...) | |
410 | { | |
411 | char xpath[XPATH_MAXLEN]; | |
412 | const char *value; | |
413 | va_list ap; | |
414 | ||
415 | va_start(ap, xpath_fmt); | |
416 | vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); | |
417 | va_end(ap); | |
418 | ||
419 | value = yang_get_default_value(xpath); | |
420 | return yang_str2int32(value); | |
421 | } | |
422 | ||
423 | /* | |
424 | * Primitive type: int64. | |
425 | */ | |
426 | int64_t yang_str2int64(const char *value) | |
427 | { | |
428 | return strtoll(value, NULL, 10); | |
429 | } | |
430 | ||
431 | struct yang_data *yang_data_new_int64(const char *xpath, int64_t value) | |
432 | { | |
433 | char value_str[BUFSIZ]; | |
434 | ||
566bdaf6 | 435 | snprintfrr(value_str, sizeof(value_str), "%" PRId64, value); |
1c2facd1 RW |
436 | return yang_data_new(xpath, value_str); |
437 | } | |
438 | ||
439 | int64_t yang_dnode_get_int64(const struct lyd_node *dnode, | |
440 | const char *xpath_fmt, ...) | |
441 | { | |
3bb513c3 CH |
442 | const struct lyd_value *dvalue; |
443 | dvalue = YANG_DNODE_XPATH_GET_VALUE(dnode, xpath_fmt); | |
444 | assert(dvalue->realtype->basetype == LY_TYPE_INT64); | |
445 | return dvalue->int64; | |
1c2facd1 RW |
446 | } |
447 | ||
448 | int64_t yang_get_default_int64(const char *xpath_fmt, ...) | |
449 | { | |
450 | char xpath[XPATH_MAXLEN]; | |
451 | const char *value; | |
452 | va_list ap; | |
453 | ||
454 | va_start(ap, xpath_fmt); | |
455 | vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); | |
456 | va_end(ap); | |
457 | ||
458 | value = yang_get_default_value(xpath); | |
459 | return yang_str2int64(value); | |
460 | } | |
461 | ||
462 | /* | |
463 | * Primitive type: uint8. | |
464 | */ | |
465 | uint8_t yang_str2uint8(const char *value) | |
466 | { | |
467 | return strtoul(value, NULL, 10); | |
468 | } | |
469 | ||
470 | struct yang_data *yang_data_new_uint8(const char *xpath, uint8_t value) | |
471 | { | |
472 | char value_str[BUFSIZ]; | |
473 | ||
474 | snprintf(value_str, sizeof(value_str), "%u", value); | |
475 | return yang_data_new(xpath, value_str); | |
476 | } | |
477 | ||
478 | uint8_t yang_dnode_get_uint8(const struct lyd_node *dnode, | |
479 | const char *xpath_fmt, ...) | |
480 | { | |
3bb513c3 CH |
481 | const struct lyd_value *dvalue; |
482 | dvalue = YANG_DNODE_XPATH_GET_VALUE(dnode, xpath_fmt); | |
483 | assert(dvalue->realtype->basetype == LY_TYPE_UINT8); | |
484 | return dvalue->uint8; | |
1c2facd1 RW |
485 | } |
486 | ||
487 | uint8_t yang_get_default_uint8(const char *xpath_fmt, ...) | |
488 | { | |
489 | char xpath[XPATH_MAXLEN]; | |
490 | const char *value; | |
491 | va_list ap; | |
492 | ||
493 | va_start(ap, xpath_fmt); | |
494 | vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); | |
495 | va_end(ap); | |
496 | ||
497 | value = yang_get_default_value(xpath); | |
498 | return yang_str2uint8(value); | |
499 | } | |
500 | ||
501 | /* | |
502 | * Primitive type: uint16. | |
503 | */ | |
504 | uint16_t yang_str2uint16(const char *value) | |
505 | { | |
506 | return strtoul(value, NULL, 10); | |
507 | } | |
508 | ||
509 | struct yang_data *yang_data_new_uint16(const char *xpath, uint16_t value) | |
510 | { | |
511 | char value_str[BUFSIZ]; | |
512 | ||
513 | snprintf(value_str, sizeof(value_str), "%u", value); | |
514 | return yang_data_new(xpath, value_str); | |
515 | } | |
516 | ||
517 | uint16_t yang_dnode_get_uint16(const struct lyd_node *dnode, | |
518 | const char *xpath_fmt, ...) | |
519 | { | |
3bb513c3 CH |
520 | const struct lyd_value *dvalue; |
521 | dvalue = YANG_DNODE_XPATH_GET_VALUE(dnode, xpath_fmt); | |
522 | assert(dvalue->realtype->basetype == LY_TYPE_UINT16); | |
523 | return dvalue->uint16; | |
1c2facd1 RW |
524 | } |
525 | ||
526 | uint16_t yang_get_default_uint16(const char *xpath_fmt, ...) | |
527 | { | |
528 | char xpath[XPATH_MAXLEN]; | |
529 | const char *value; | |
530 | va_list ap; | |
531 | ||
532 | va_start(ap, xpath_fmt); | |
533 | vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); | |
534 | va_end(ap); | |
535 | ||
536 | value = yang_get_default_value(xpath); | |
537 | return yang_str2uint16(value); | |
538 | } | |
539 | ||
540 | /* | |
541 | * Primitive type: uint32. | |
542 | */ | |
543 | uint32_t yang_str2uint32(const char *value) | |
544 | { | |
545 | return strtoul(value, NULL, 10); | |
546 | } | |
547 | ||
548 | struct yang_data *yang_data_new_uint32(const char *xpath, uint32_t value) | |
549 | { | |
550 | char value_str[BUFSIZ]; | |
551 | ||
552 | snprintf(value_str, sizeof(value_str), "%u", value); | |
553 | return yang_data_new(xpath, value_str); | |
554 | } | |
555 | ||
556 | uint32_t yang_dnode_get_uint32(const struct lyd_node *dnode, | |
557 | const char *xpath_fmt, ...) | |
558 | { | |
3bb513c3 CH |
559 | const struct lyd_value *dvalue; |
560 | dvalue = YANG_DNODE_XPATH_GET_VALUE(dnode, xpath_fmt); | |
561 | assert(dvalue->realtype->basetype == LY_TYPE_UINT32); | |
562 | return dvalue->uint32; | |
1c2facd1 RW |
563 | } |
564 | ||
565 | uint32_t yang_get_default_uint32(const char *xpath_fmt, ...) | |
566 | { | |
567 | char xpath[XPATH_MAXLEN]; | |
568 | const char *value; | |
569 | va_list ap; | |
570 | ||
571 | va_start(ap, xpath_fmt); | |
572 | vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); | |
573 | va_end(ap); | |
574 | ||
575 | value = yang_get_default_value(xpath); | |
576 | return yang_str2uint32(value); | |
577 | } | |
578 | ||
579 | /* | |
580 | * Primitive type: uint64. | |
581 | */ | |
582 | uint64_t yang_str2uint64(const char *value) | |
583 | { | |
584 | return strtoull(value, NULL, 10); | |
585 | } | |
586 | ||
587 | struct yang_data *yang_data_new_uint64(const char *xpath, uint64_t value) | |
588 | { | |
589 | char value_str[BUFSIZ]; | |
590 | ||
566bdaf6 | 591 | snprintfrr(value_str, sizeof(value_str), "%" PRIu64, value); |
1c2facd1 RW |
592 | return yang_data_new(xpath, value_str); |
593 | } | |
594 | ||
595 | uint64_t yang_dnode_get_uint64(const struct lyd_node *dnode, | |
596 | const char *xpath_fmt, ...) | |
597 | { | |
3bb513c3 CH |
598 | const struct lyd_value *dvalue; |
599 | dvalue = YANG_DNODE_XPATH_GET_VALUE(dnode, xpath_fmt); | |
600 | assert(dvalue->realtype->basetype == LY_TYPE_UINT64); | |
601 | return dvalue->uint64; | |
1c2facd1 RW |
602 | } |
603 | ||
604 | uint64_t yang_get_default_uint64(const char *xpath_fmt, ...) | |
605 | { | |
606 | char xpath[XPATH_MAXLEN]; | |
607 | const char *value; | |
608 | va_list ap; | |
609 | ||
610 | va_start(ap, xpath_fmt); | |
611 | vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); | |
612 | va_end(ap); | |
613 | ||
614 | value = yang_get_default_value(xpath); | |
615 | return yang_str2uint64(value); | |
616 | } | |
617 | ||
618 | /* | |
619 | * Primitive type: string. | |
620 | * | |
621 | * All string wrappers can be used with non-string types. | |
622 | */ | |
623 | struct yang_data *yang_data_new_string(const char *xpath, const char *value) | |
624 | { | |
625 | return yang_data_new(xpath, value); | |
626 | } | |
627 | ||
628 | const char *yang_dnode_get_string(const struct lyd_node *dnode, | |
629 | const char *xpath_fmt, ...) | |
630 | { | |
3bb513c3 | 631 | return YANG_DNODE_XPATH_GET_CANON(dnode, xpath_fmt); |
1c2facd1 RW |
632 | } |
633 | ||
634 | void yang_dnode_get_string_buf(char *buf, size_t size, | |
635 | const struct lyd_node *dnode, | |
636 | const char *xpath_fmt, ...) | |
637 | { | |
3bb513c3 CH |
638 | const char *canon = YANG_DNODE_XPATH_GET_CANON(dnode, xpath_fmt); |
639 | if (strlcpy(buf, canon, size) >= size) { | |
1c2facd1 RW |
640 | char xpath[XPATH_MAXLEN]; |
641 | ||
642 | yang_dnode_get_path(dnode, xpath, sizeof(xpath)); | |
643 | flog_warn(EC_LIB_YANG_DATA_TRUNCATED, | |
644 | "%s: value was truncated [xpath %s]", __func__, | |
645 | xpath); | |
646 | } | |
647 | } | |
648 | ||
649 | const char *yang_get_default_string(const char *xpath_fmt, ...) | |
650 | { | |
651 | char xpath[XPATH_MAXLEN]; | |
652 | va_list ap; | |
653 | ||
654 | va_start(ap, xpath_fmt); | |
655 | vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); | |
656 | va_end(ap); | |
657 | ||
658 | return yang_get_default_value(xpath); | |
659 | } | |
660 | ||
661 | void yang_get_default_string_buf(char *buf, size_t size, const char *xpath_fmt, | |
662 | ...) | |
663 | { | |
664 | char xpath[XPATH_MAXLEN]; | |
665 | const char *value; | |
666 | va_list ap; | |
667 | ||
668 | va_start(ap, xpath_fmt); | |
669 | vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); | |
670 | va_end(ap); | |
671 | ||
672 | value = yang_get_default_value(xpath); | |
673 | if (strlcpy(buf, value, size) >= size) | |
674 | flog_warn(EC_LIB_YANG_DATA_TRUNCATED, | |
675 | "%s: value was truncated [xpath %s]", __func__, | |
676 | xpath); | |
677 | } | |
678 | ||
b71df689 CS |
679 | /* |
680 | * Primitive type: empty. | |
681 | */ | |
682 | struct yang_data *yang_data_new_empty(const char *xpath) | |
683 | { | |
684 | return yang_data_new(xpath, NULL); | |
685 | } | |
686 | ||
47cd2234 CS |
687 | bool yang_dnode_get_empty(const struct lyd_node *dnode, const char *xpath_fmt, |
688 | ...) | |
689 | { | |
690 | va_list ap; | |
691 | char xpath[XPATH_MAXLEN]; | |
3bb513c3 | 692 | const struct lyd_node_term *dleaf; |
47cd2234 CS |
693 | |
694 | assert(dnode); | |
695 | ||
696 | va_start(ap, xpath_fmt); | |
697 | vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); | |
698 | va_end(ap); | |
699 | ||
700 | dnode = yang_dnode_get(dnode, xpath); | |
701 | if (dnode) { | |
3bb513c3 CH |
702 | dleaf = (const struct lyd_node_term *)dnode; |
703 | if (dleaf->value.realtype->basetype == LY_TYPE_EMPTY) | |
47cd2234 CS |
704 | return true; |
705 | } | |
706 | ||
707 | return false; | |
708 | } | |
709 | ||
eed84494 RW |
710 | /* |
711 | * Derived type: IP prefix. | |
712 | */ | |
713 | void yang_str2prefix(const char *value, union prefixptr prefix) | |
714 | { | |
715 | (void)str2prefix(value, prefix.p); | |
716 | apply_mask(prefix.p); | |
717 | } | |
718 | ||
719 | struct yang_data *yang_data_new_prefix(const char *xpath, | |
720 | union prefixconstptr prefix) | |
721 | { | |
722 | char value_str[PREFIX2STR_BUFFER]; | |
723 | ||
724 | (void)prefix2str(prefix.p, value_str, sizeof(value_str)); | |
725 | return yang_data_new(xpath, value_str); | |
726 | } | |
727 | ||
46fcb2df | 728 | void yang_dnode_get_prefix(struct prefix *prefix, const struct lyd_node *dnode, |
eed84494 RW |
729 | const char *xpath_fmt, ...) |
730 | { | |
3bb513c3 | 731 | const char *canon; |
46fcb2df RZ |
732 | /* |
733 | * Initialize prefix to avoid static analyzer complaints about | |
734 | * uninitialized memory. | |
735 | */ | |
736 | memset(prefix, 0, sizeof(*prefix)); | |
737 | ||
3bb513c3 CH |
738 | /* XXX ip_prefix is a native type now in ly2, leverage? */ |
739 | canon = YANG_DNODE_XPATH_GET_CANON(dnode, xpath_fmt); | |
740 | (void)str2prefix(canon, prefix); | |
eed84494 RW |
741 | } |
742 | ||
743 | void yang_get_default_prefix(union prefixptr var, const char *xpath_fmt, ...) | |
744 | { | |
745 | char xpath[XPATH_MAXLEN]; | |
746 | const char *value; | |
747 | va_list ap; | |
748 | ||
749 | va_start(ap, xpath_fmt); | |
750 | vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); | |
751 | va_end(ap); | |
752 | ||
753 | value = yang_get_default_value(xpath); | |
754 | yang_str2prefix(value, var); | |
755 | } | |
756 | ||
1c2facd1 RW |
757 | /* |
758 | * Derived type: ipv4. | |
759 | */ | |
760 | void yang_str2ipv4(const char *value, struct in_addr *addr) | |
761 | { | |
762 | (void)inet_pton(AF_INET, value, addr); | |
763 | } | |
764 | ||
765 | struct yang_data *yang_data_new_ipv4(const char *xpath, | |
766 | const struct in_addr *addr) | |
767 | { | |
768 | char value_str[INET_ADDRSTRLEN]; | |
769 | ||
770 | (void)inet_ntop(AF_INET, addr, value_str, sizeof(value_str)); | |
771 | return yang_data_new(xpath, value_str); | |
772 | } | |
773 | ||
774 | void yang_dnode_get_ipv4(struct in_addr *addr, const struct lyd_node *dnode, | |
775 | const char *xpath_fmt, ...) | |
776 | { | |
3bb513c3 CH |
777 | /* XXX libyang2 IPv4 address is a native type now in ly2 */ |
778 | const char *canon = YANG_DNODE_XPATH_GET_CANON(dnode, xpath_fmt); | |
779 | (void)inet_pton(AF_INET, canon, addr); | |
1c2facd1 RW |
780 | } |
781 | ||
782 | void yang_get_default_ipv4(struct in_addr *var, const char *xpath_fmt, ...) | |
783 | { | |
784 | char xpath[XPATH_MAXLEN]; | |
785 | const char *value; | |
786 | va_list ap; | |
787 | ||
788 | va_start(ap, xpath_fmt); | |
789 | vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); | |
790 | va_end(ap); | |
791 | ||
792 | value = yang_get_default_value(xpath); | |
793 | yang_str2ipv4(value, var); | |
794 | } | |
795 | ||
796 | /* | |
797 | * Derived type: ipv4p. | |
798 | */ | |
799 | void yang_str2ipv4p(const char *value, union prefixptr prefix) | |
800 | { | |
801 | struct prefix_ipv4 *prefix4 = prefix.p4; | |
802 | ||
803 | (void)str2prefix_ipv4(value, prefix4); | |
804 | apply_mask_ipv4(prefix4); | |
805 | } | |
806 | ||
807 | struct yang_data *yang_data_new_ipv4p(const char *xpath, | |
70065793 | 808 | union prefixconstptr prefix) |
1c2facd1 RW |
809 | { |
810 | char value_str[PREFIX2STR_BUFFER]; | |
811 | ||
812 | (void)prefix2str(prefix.p, value_str, sizeof(value_str)); | |
813 | return yang_data_new(xpath, value_str); | |
814 | } | |
815 | ||
816 | void yang_dnode_get_ipv4p(union prefixptr prefix, const struct lyd_node *dnode, | |
817 | const char *xpath_fmt, ...) | |
818 | { | |
1c2facd1 | 819 | struct prefix_ipv4 *prefix4 = prefix.p4; |
3bb513c3 CH |
820 | /* XXX libyang2: ipv4/6 address is a native type now in ly2 */ |
821 | const char *canon = YANG_DNODE_XPATH_GET_CANON(dnode, xpath_fmt); | |
822 | (void)str2prefix_ipv4(canon, prefix4); | |
1c2facd1 RW |
823 | } |
824 | ||
825 | void yang_get_default_ipv4p(union prefixptr var, const char *xpath_fmt, ...) | |
826 | { | |
827 | char xpath[XPATH_MAXLEN]; | |
828 | const char *value; | |
829 | va_list ap; | |
830 | ||
831 | va_start(ap, xpath_fmt); | |
832 | vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); | |
833 | va_end(ap); | |
834 | ||
835 | value = yang_get_default_value(xpath); | |
836 | yang_str2ipv4p(value, var); | |
837 | } | |
838 | ||
839 | /* | |
840 | * Derived type: ipv6. | |
841 | */ | |
842 | void yang_str2ipv6(const char *value, struct in6_addr *addr) | |
843 | { | |
844 | (void)inet_pton(AF_INET6, value, addr); | |
845 | } | |
846 | ||
847 | struct yang_data *yang_data_new_ipv6(const char *xpath, | |
848 | const struct in6_addr *addr) | |
849 | { | |
850 | char value_str[INET6_ADDRSTRLEN]; | |
851 | ||
852 | (void)inet_ntop(AF_INET6, addr, value_str, sizeof(value_str)); | |
853 | return yang_data_new(xpath, value_str); | |
854 | } | |
855 | ||
856 | void yang_dnode_get_ipv6(struct in6_addr *addr, const struct lyd_node *dnode, | |
857 | const char *xpath_fmt, ...) | |
858 | { | |
3bb513c3 CH |
859 | /* XXX libyang2: IPv6 address is a native type now, leverage. */ |
860 | const char *canon = YANG_DNODE_XPATH_GET_CANON(dnode, xpath_fmt); | |
861 | (void)inet_pton(AF_INET6, canon, addr); | |
1c2facd1 RW |
862 | } |
863 | ||
864 | void yang_get_default_ipv6(struct in6_addr *var, const char *xpath_fmt, ...) | |
865 | { | |
866 | char xpath[XPATH_MAXLEN]; | |
867 | const char *value; | |
868 | va_list ap; | |
869 | ||
870 | va_start(ap, xpath_fmt); | |
871 | vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); | |
872 | va_end(ap); | |
873 | ||
874 | value = yang_get_default_value(xpath); | |
875 | yang_str2ipv6(value, var); | |
876 | } | |
877 | ||
878 | /* | |
879 | * Derived type: ipv6p. | |
880 | */ | |
881 | void yang_str2ipv6p(const char *value, union prefixptr prefix) | |
882 | { | |
883 | struct prefix_ipv6 *prefix6 = prefix.p6; | |
884 | ||
885 | (void)str2prefix_ipv6(value, prefix6); | |
886 | apply_mask_ipv6(prefix6); | |
887 | } | |
888 | ||
889 | struct yang_data *yang_data_new_ipv6p(const char *xpath, | |
70065793 | 890 | union prefixconstptr prefix) |
1c2facd1 RW |
891 | { |
892 | char value_str[PREFIX2STR_BUFFER]; | |
893 | ||
894 | (void)prefix2str(prefix.p, value_str, sizeof(value_str)); | |
895 | return yang_data_new(xpath, value_str); | |
896 | } | |
897 | ||
898 | void yang_dnode_get_ipv6p(union prefixptr prefix, const struct lyd_node *dnode, | |
899 | const char *xpath_fmt, ...) | |
900 | { | |
1c2facd1 RW |
901 | struct prefix_ipv6 *prefix6 = prefix.p6; |
902 | ||
3bb513c3 CH |
903 | /* XXX IPv6 address is a native type now in ly2 -- can we leverage? */ |
904 | const char *canon = YANG_DNODE_XPATH_GET_CANON(dnode, xpath_fmt); | |
905 | (void)str2prefix_ipv6(canon, prefix6); | |
1c2facd1 RW |
906 | } |
907 | ||
908 | void yang_get_default_ipv6p(union prefixptr var, const char *xpath_fmt, ...) | |
909 | { | |
910 | char xpath[XPATH_MAXLEN]; | |
911 | const char *value; | |
912 | va_list ap; | |
913 | ||
914 | va_start(ap, xpath_fmt); | |
915 | vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); | |
916 | va_end(ap); | |
917 | ||
918 | value = yang_get_default_value(xpath); | |
919 | yang_str2ipv6p(value, var); | |
920 | } | |
b0584ad3 QY |
921 | |
922 | /* | |
923 | * Derived type: ip. | |
924 | */ | |
925 | void yang_str2ip(const char *value, struct ipaddr *ip) | |
926 | { | |
927 | (void)str2ipaddr(value, ip); | |
928 | } | |
929 | ||
930 | struct yang_data *yang_data_new_ip(const char *xpath, const struct ipaddr *addr) | |
931 | { | |
932 | size_t sz = IS_IPADDR_V4(addr) ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN; | |
933 | char value_str[sz]; | |
934 | ||
935 | ipaddr2str(addr, value_str, sizeof(value_str)); | |
936 | return yang_data_new(xpath, value_str); | |
937 | } | |
938 | ||
939 | void yang_dnode_get_ip(struct ipaddr *addr, const struct lyd_node *dnode, | |
940 | const char *xpath_fmt, ...) | |
941 | { | |
3bb513c3 CH |
942 | /* XXX IPv4 address could be a plugin type now in ly2, leverage? */ |
943 | const char *canon = YANG_DNODE_XPATH_GET_CANON(dnode, xpath_fmt); | |
944 | (void)str2ipaddr(canon, addr); | |
b0584ad3 QY |
945 | } |
946 | ||
947 | void yang_get_default_ip(struct ipaddr *var, const char *xpath_fmt, ...) | |
948 | { | |
949 | char xpath[XPATH_MAXLEN]; | |
950 | const char *value; | |
951 | va_list ap; | |
952 | ||
953 | va_start(ap, xpath_fmt); | |
954 | vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); | |
955 | va_end(ap); | |
956 | ||
957 | value = yang_get_default_value(xpath); | |
958 | yang_str2ip(value, var); | |
959 | } | |
dd9ef518 CS |
960 | |
961 | struct yang_data *yang_data_new_mac(const char *xpath, | |
962 | const struct ethaddr *mac) | |
963 | { | |
964 | char value_str[ETHER_ADDR_STRLEN]; | |
965 | ||
966 | prefix_mac2str(mac, value_str, sizeof(value_str)); | |
967 | return yang_data_new(xpath, value_str); | |
968 | } | |
969 | ||
970 | void yang_str2mac(const char *value, struct ethaddr *mac) | |
971 | { | |
bec74cc8 | 972 | (void)prefix_str2mac(value, mac); |
dd9ef518 | 973 | } |
cad46cfd | 974 | |
8d0c8ff5 CS |
975 | struct yang_data *yang_data_new_date_and_time(const char *xpath, time_t time) |
976 | { | |
977 | struct tm tm; | |
978 | char timebuf[MONOTIME_STRLEN]; | |
979 | struct timeval _time, time_real; | |
980 | char *ts_dot; | |
981 | uint16_t buflen; | |
982 | ||
983 | _time.tv_sec = time; | |
984 | _time.tv_usec = 0; | |
985 | monotime_to_realtime(&_time, &time_real); | |
986 | ||
987 | gmtime_r(&time_real.tv_sec, &tm); | |
988 | ||
989 | /* rfc-3339 format */ | |
990 | strftime(timebuf, sizeof(timebuf), "%Y-%m-%dT%H:%M:%S", &tm); | |
991 | buflen = strlen(timebuf); | |
992 | ts_dot = timebuf + buflen; | |
993 | ||
994 | /* microseconds and appends Z */ | |
995 | snprintfrr(ts_dot, sizeof(timebuf) - buflen, ".%06luZ", | |
996 | (unsigned long)time_real.tv_usec); | |
997 | ||
998 | return yang_data_new(xpath, timebuf); | |
999 | } | |
1000 | ||
cad46cfd CS |
1001 | const char *yang_nexthop_type2str(uint32_t ntype) |
1002 | { | |
1003 | switch (ntype) { | |
1004 | case NEXTHOP_TYPE_IFINDEX: | |
1005 | return "ifindex"; | |
1006 | break; | |
1007 | case NEXTHOP_TYPE_IPV4: | |
1008 | return "ip4"; | |
1009 | break; | |
1010 | case NEXTHOP_TYPE_IPV4_IFINDEX: | |
1011 | return "ip4-ifindex"; | |
1012 | break; | |
1013 | case NEXTHOP_TYPE_IPV6: | |
1014 | return "ip6"; | |
1015 | break; | |
1016 | case NEXTHOP_TYPE_IPV6_IFINDEX: | |
1017 | return "ip6-ifindex"; | |
1018 | break; | |
1019 | case NEXTHOP_TYPE_BLACKHOLE: | |
1020 | return "blackhole"; | |
1021 | break; | |
1022 | default: | |
1023 | return "unknown"; | |
1024 | break; | |
1025 | } | |
1026 | } | |
755100ac | 1027 | |
1028 | ||
1029 | const char *yang_afi_safi_value2identity(afi_t afi, safi_t safi) | |
1030 | { | |
1031 | if (afi == AFI_IP && safi == SAFI_UNICAST) | |
1032 | return "frr-routing:ipv4-unicast"; | |
1033 | if (afi == AFI_IP6 && safi == SAFI_UNICAST) | |
1034 | return "frr-routing:ipv6-unicast"; | |
1035 | if (afi == AFI_IP && safi == SAFI_MULTICAST) | |
1036 | return "frr-routing:ipv4-multicast"; | |
1037 | if (afi == AFI_IP6 && safi == SAFI_MULTICAST) | |
1038 | return "frr-routing:ipv6-multicast"; | |
532f9f17 CS |
1039 | if (afi == AFI_IP && safi == SAFI_MPLS_VPN) |
1040 | return "frr-routing:l3vpn-ipv4-unicast"; | |
1041 | if (afi == AFI_IP6 && safi == SAFI_MPLS_VPN) | |
1042 | return "frr-routing:l3vpn-ipv6-unicast"; | |
1043 | if (afi == AFI_L2VPN && safi == SAFI_EVPN) | |
1044 | return "frr-routing:l2vpn-evpn"; | |
1045 | if (afi == AFI_IP && safi == SAFI_LABELED_UNICAST) | |
1046 | return "frr-routing:ipv4-labeled-unicast"; | |
1047 | if (afi == AFI_IP6 && safi == SAFI_LABELED_UNICAST) | |
1048 | return "frr-routing:ipv6-labeled-unicast"; | |
fbace230 CS |
1049 | if (afi == AFI_IP && safi == SAFI_FLOWSPEC) |
1050 | return "frr-routing:ipv4-flowspec"; | |
1051 | if (afi == AFI_IP6 && safi == SAFI_FLOWSPEC) | |
1052 | return "frr-routing:ipv6-flowspec"; | |
755100ac | 1053 | |
1054 | return NULL; | |
1055 | } | |
1056 | ||
1057 | void yang_afi_safi_identity2value(const char *key, afi_t *afi, safi_t *safi) | |
1058 | { | |
1059 | if (strmatch(key, "frr-routing:ipv4-unicast")) { | |
1060 | *afi = AFI_IP; | |
1061 | *safi = SAFI_UNICAST; | |
1062 | } else if (strmatch(key, "frr-routing:ipv6-unicast")) { | |
1063 | *afi = AFI_IP6; | |
1064 | *safi = SAFI_UNICAST; | |
1065 | } else if (strmatch(key, "frr-routing:ipv4-multicast")) { | |
1066 | *afi = AFI_IP; | |
1067 | *safi = SAFI_MULTICAST; | |
1068 | } else if (strmatch(key, "frr-routing:ipv6-multicast")) { | |
1069 | *afi = AFI_IP6; | |
1070 | *safi = SAFI_MULTICAST; | |
532f9f17 CS |
1071 | } else if (strmatch(key, "frr-routing:l3vpn-ipv4-unicast")) { |
1072 | *afi = AFI_IP; | |
1073 | *safi = SAFI_MPLS_VPN; | |
1074 | } else if (strmatch(key, "frr-routing:l3vpn-ipv6-unicast")) { | |
1075 | *afi = AFI_IP6; | |
1076 | *safi = SAFI_MPLS_VPN; | |
1077 | } else if (strmatch(key, "frr-routing:ipv4-labeled-unicast")) { | |
1078 | *afi = AFI_IP; | |
1079 | *safi = SAFI_LABELED_UNICAST; | |
1080 | } else if (strmatch(key, "frr-routing:ipv6-labeled-unicast")) { | |
1081 | *afi = AFI_IP6; | |
1082 | *safi = SAFI_LABELED_UNICAST; | |
1083 | } else if (strmatch(key, "frr-routing:l2vpn-evpn")) { | |
1084 | *afi = AFI_L2VPN; | |
1085 | *safi = SAFI_EVPN; | |
fbace230 CS |
1086 | } else if (strmatch(key, "frr-routing:ipv4-flowspec")) { |
1087 | *afi = AFI_IP; | |
1088 | *safi = SAFI_FLOWSPEC; | |
1089 | } else if (strmatch(key, "frr-routing:ipv6-flowspec")) { | |
1090 | *afi = AFI_IP6; | |
1091 | *safi = SAFI_FLOWSPEC; | |
755100ac | 1092 | } else { |
1093 | *afi = AFI_UNSPEC; | |
1094 | *safi = SAFI_UNSPEC; | |
1095 | } | |
1096 | } |