diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:53:30 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:53:30 +0000 |
commit | 2c7cac91ed6e7db0f6937923d2b57f97dbdbc337 (patch) | |
tree | c05dc0f8e6aa3accc84e3e5cffc933ed94941383 /lib/yang_wrappers.c | |
parent | Initial commit. (diff) | |
download | frr-upstream/8.4.4.tar.xz frr-upstream/8.4.4.zip |
Adding upstream version 8.4.4.upstream/8.4.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | lib/yang_wrappers.c | 1155 |
1 files changed, 1155 insertions, 0 deletions
diff --git a/lib/yang_wrappers.c b/lib/yang_wrappers.c new file mode 100644 index 0000000..ea21d13 --- /dev/null +++ b/lib/yang_wrappers.c @@ -0,0 +1,1155 @@ +/* + * Copyright (C) 2018 NetDEF, Inc. + * Renato Westphal + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <zebra.h> + +#include "base64.h" +#include "log.h" +#include "lib_errors.h" +#include "northbound.h" +#include "printfrr.h" +#include "nexthop.h" +#include "printfrr.h" + + +#define YANG_DNODE_XPATH_GET_VALUE(dnode, xpath_fmt) \ + ({ \ + va_list __ap; \ + va_start(__ap, (xpath_fmt)); \ + const struct lyd_value *__dvalue = \ + yang_dnode_xpath_get_value(dnode, xpath_fmt, __ap); \ + va_end(__ap); \ + __dvalue; \ + }) + +#define YANG_DNODE_XPATH_GET_CANON(dnode, xpath_fmt) \ + ({ \ + va_list __ap; \ + va_start(__ap, (xpath_fmt)); \ + const char *__canon = \ + yang_dnode_xpath_get_canon(dnode, xpath_fmt, __ap); \ + va_end(__ap); \ + __canon; \ + }) + +#define YANG_DNODE_GET_ASSERT(dnode, xpath) \ + do { \ + if ((dnode) == NULL) { \ + flog_err(EC_LIB_YANG_DNODE_NOT_FOUND, \ + "%s: couldn't find %s", __func__, (xpath)); \ + zlog_backtrace(LOG_ERR); \ + abort(); \ + } \ + } while (0) + +static inline const char * +yang_dnode_xpath_get_canon(const struct lyd_node *dnode, const char *xpath_fmt, + va_list ap) +{ + const struct lyd_node_term *__dleaf = + (const struct lyd_node_term *)dnode; + assert(__dleaf); + if (xpath_fmt) { + char __xpath[XPATH_MAXLEN]; + vsnprintf(__xpath, sizeof(__xpath), xpath_fmt, ap); + __dleaf = (const struct lyd_node_term *)yang_dnode_get(dnode, + __xpath); + YANG_DNODE_GET_ASSERT(__dleaf, __xpath); + } + return lyd_get_value(&__dleaf->node); +} + +static inline const struct lyd_value * +yang_dnode_xpath_get_value(const struct lyd_node *dnode, const char *xpath_fmt, + va_list ap) +{ + const struct lyd_node_term *__dleaf = + (const struct lyd_node_term *)dnode; + assert(__dleaf); + if (xpath_fmt) { + char __xpath[XPATH_MAXLEN]; + vsnprintf(__xpath, sizeof(__xpath), xpath_fmt, ap); + __dleaf = (const struct lyd_node_term *)yang_dnode_get(dnode, + __xpath); + YANG_DNODE_GET_ASSERT(__dleaf, __xpath); + } + const struct lyd_value *__dvalue = &__dleaf->value; + if (__dvalue->realtype->basetype == LY_TYPE_UNION) + __dvalue = &__dvalue->subvalue->value; + return __dvalue; +} + +static const char *yang_get_default_value(const char *xpath) +{ + const struct lysc_node *snode; + const char *value; + + snode = lys_find_path(ly_native_ctx, NULL, xpath, 0); + if (snode == NULL) { + flog_err(EC_LIB_YANG_UNKNOWN_DATA_PATH, + "%s: unknown data path: %s", __func__, xpath); + zlog_backtrace(LOG_ERR); + abort(); + } + + value = yang_snode_get_default(snode); + assert(value); + + return value; +} + +/* + * Primitive type: bool. + */ +bool yang_str2bool(const char *value) +{ + return strmatch(value, "true"); +} + +struct yang_data *yang_data_new_bool(const char *xpath, bool value) +{ + return yang_data_new(xpath, (value) ? "true" : "false"); +} + +bool yang_dnode_get_bool(const struct lyd_node *dnode, const char *xpath_fmt, + ...) +{ + const struct lyd_value *dvalue; + dvalue = YANG_DNODE_XPATH_GET_VALUE(dnode, xpath_fmt); + assert(dvalue->realtype->basetype == LY_TYPE_BOOL); + return dvalue->boolean; +} + +bool yang_get_default_bool(const char *xpath_fmt, ...) +{ + char xpath[XPATH_MAXLEN]; + const char *value; + va_list ap; + + va_start(ap, xpath_fmt); + vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); + va_end(ap); + + value = yang_get_default_value(xpath); + return yang_str2bool(value); +} + +/* + * Primitive type: dec64. + */ +double yang_str2dec64(const char *xpath, const char *value) +{ + double dbl = 0; + + if (sscanf(value, "%lf", &dbl) != 1) { + flog_err(EC_LIB_YANG_DATA_CONVERT, + "%s: couldn't convert string to decimal64 [xpath %s]", + __func__, xpath); + zlog_backtrace(LOG_ERR); + abort(); + } + + return dbl; +} + +struct yang_data *yang_data_new_dec64(const char *xpath, double value) +{ + char value_str[BUFSIZ]; + + snprintf(value_str, sizeof(value_str), "%lf", value); + return yang_data_new(xpath, value_str); +} + +double yang_dnode_get_dec64(const struct lyd_node *dnode, const char *xpath_fmt, + ...) +{ + const double denom[19] = {1e0, 1e-1, 1e-2, 1e-3, 1e-4, + 1e-5, 1e-6, 1e-7, 1e-8, 1e-9, + 1e-10, 1e-11, 1e-12, 1e-13, 1e-14, + 1e-15, 1e-16, 1e-17, 1e-18}; + const struct lysc_type_dec *dectype; + const struct lyd_value *dvalue; + + dvalue = YANG_DNODE_XPATH_GET_VALUE(dnode, xpath_fmt); + dectype = (const struct lysc_type_dec *)dvalue->realtype; + assert(dectype->basetype == LY_TYPE_DEC64); + assert(dectype->fraction_digits < sizeof(denom) / sizeof(*denom)); + return (double)dvalue->dec64 * denom[dectype->fraction_digits]; +} + +double yang_get_default_dec64(const char *xpath_fmt, ...) +{ + char xpath[XPATH_MAXLEN]; + const char *value; + va_list ap; + + va_start(ap, xpath_fmt); + vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); + va_end(ap); + + value = yang_get_default_value(xpath); + return yang_str2dec64(xpath, value); +} + +/* + * Primitive type: enum. + */ +int yang_str2enum(const char *xpath, const char *value) +{ + const struct lysc_node *snode; + const struct lysc_node_leaf *sleaf; + const struct lysc_type_enum *type; + const struct lysc_type_bitenum_item *enums; + + snode = lys_find_path(ly_native_ctx, NULL, xpath, 0); + if (snode == NULL) { + flog_err(EC_LIB_YANG_UNKNOWN_DATA_PATH, + "%s: unknown data path: %s", __func__, xpath); + zlog_backtrace(LOG_ERR); + abort(); + } + + assert(snode->nodetype == LYS_LEAF); + sleaf = (const struct lysc_node_leaf *)snode; + type = (const struct lysc_type_enum *)sleaf->type; + assert(type->basetype == LY_TYPE_ENUM); + enums = type->enums; + unsigned int count = LY_ARRAY_COUNT(enums); + for (unsigned int i = 0; i < count; i++) { + if (strmatch(value, enums[i].name)) { + assert(CHECK_FLAG(enums[i].flags, LYS_SET_VALUE)); + return enums[i].value; + } + } + + flog_err(EC_LIB_YANG_DATA_CONVERT, + "%s: couldn't convert string to enum [xpath %s]", __func__, + xpath); + zlog_backtrace(LOG_ERR); + abort(); +} + +struct yang_data *yang_data_new_enum(const char *xpath, int value) +{ + const struct lysc_node *snode; + const struct lysc_node_leaf *sleaf; + const struct lysc_type_enum *type; + const struct lysc_type_bitenum_item *enums; + + snode = lys_find_path(ly_native_ctx, NULL, xpath, 0); + if (snode == NULL) { + flog_err(EC_LIB_YANG_UNKNOWN_DATA_PATH, + "%s: unknown data path: %s", __func__, xpath); + zlog_backtrace(LOG_ERR); + abort(); + } + + assert(snode->nodetype == LYS_LEAF); + sleaf = (const struct lysc_node_leaf *)snode; + type = (const struct lysc_type_enum *)sleaf->type; + assert(type->basetype == LY_TYPE_ENUM); + enums = type->enums; + unsigned int count = LY_ARRAY_COUNT(enums); + for (unsigned int i = 0; i < count; i++) { + if (CHECK_FLAG(enums[i].flags, LYS_SET_VALUE) + && value == enums[i].value) + return yang_data_new(xpath, enums[i].name); + } + + flog_err(EC_LIB_YANG_DATA_CONVERT, + "%s: couldn't convert enum to string [xpath %s]", __func__, + xpath); + zlog_backtrace(LOG_ERR); + abort(); +} + +int yang_dnode_get_enum(const struct lyd_node *dnode, const char *xpath_fmt, + ...) +{ + const struct lyd_value *dvalue; + + dvalue = YANG_DNODE_XPATH_GET_VALUE(dnode, xpath_fmt); + assert(dvalue->realtype->basetype == LY_TYPE_ENUM); + assert(dvalue->enum_item->flags & LYS_SET_VALUE); + return dvalue->enum_item->value; +} + +int yang_get_default_enum(const char *xpath_fmt, ...) +{ + char xpath[XPATH_MAXLEN]; + const char *value; + va_list ap; + + va_start(ap, xpath_fmt); + vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); + va_end(ap); + + value = yang_get_default_value(xpath); + return yang_str2enum(xpath, value); +} + +/* + * Primitive type: int8. + */ +int8_t yang_str2int8(const char *value) +{ + return strtol(value, NULL, 10); +} + +struct yang_data *yang_data_new_int8(const char *xpath, int8_t value) +{ + char value_str[BUFSIZ]; + + snprintf(value_str, sizeof(value_str), "%d", value); + return yang_data_new(xpath, value_str); +} + +int8_t yang_dnode_get_int8(const struct lyd_node *dnode, const char *xpath_fmt, + ...) +{ + const struct lyd_value *dvalue; + dvalue = YANG_DNODE_XPATH_GET_VALUE(dnode, xpath_fmt); + assert(dvalue->realtype->basetype == LY_TYPE_INT8); + return dvalue->int8; +} + +int8_t yang_get_default_int8(const char *xpath_fmt, ...) +{ + char xpath[XPATH_MAXLEN]; + const char *value; + va_list ap; + + va_start(ap, xpath_fmt); + vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); + va_end(ap); + + value = yang_get_default_value(xpath); + return yang_str2int8(value); +} + +/* + * Primitive type: int16. + */ +int16_t yang_str2int16(const char *value) +{ + return strtol(value, NULL, 10); +} + +struct yang_data *yang_data_new_int16(const char *xpath, int16_t value) +{ + char value_str[BUFSIZ]; + + snprintf(value_str, sizeof(value_str), "%d", value); + return yang_data_new(xpath, value_str); +} + +int16_t yang_dnode_get_int16(const struct lyd_node *dnode, + const char *xpath_fmt, ...) +{ + const struct lyd_value *dvalue; + dvalue = YANG_DNODE_XPATH_GET_VALUE(dnode, xpath_fmt); + assert(dvalue->realtype->basetype == LY_TYPE_INT16); + return dvalue->int16; +} + +int16_t yang_get_default_int16(const char *xpath_fmt, ...) +{ + char xpath[XPATH_MAXLEN]; + const char *value; + va_list ap; + + va_start(ap, xpath_fmt); + vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); + va_end(ap); + + value = yang_get_default_value(xpath); + return yang_str2int16(value); +} + +/* + * Primitive type: int32. + */ +int32_t yang_str2int32(const char *value) +{ + return strtol(value, NULL, 10); +} + +struct yang_data *yang_data_new_int32(const char *xpath, int32_t value) +{ + char value_str[BUFSIZ]; + + snprintf(value_str, sizeof(value_str), "%d", value); + return yang_data_new(xpath, value_str); +} + +int32_t yang_dnode_get_int32(const struct lyd_node *dnode, + const char *xpath_fmt, ...) +{ + const struct lyd_value *dvalue; + dvalue = YANG_DNODE_XPATH_GET_VALUE(dnode, xpath_fmt); + assert(dvalue->realtype->basetype == LY_TYPE_INT32); + return dvalue->int32; +} + +int32_t yang_get_default_int32(const char *xpath_fmt, ...) +{ + char xpath[XPATH_MAXLEN]; + const char *value; + va_list ap; + + va_start(ap, xpath_fmt); + vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); + va_end(ap); + + value = yang_get_default_value(xpath); + return yang_str2int32(value); +} + +/* + * Primitive type: int64. + */ +int64_t yang_str2int64(const char *value) +{ + return strtoll(value, NULL, 10); +} + +struct yang_data *yang_data_new_int64(const char *xpath, int64_t value) +{ + char value_str[BUFSIZ]; + + snprintfrr(value_str, sizeof(value_str), "%" PRId64, value); + return yang_data_new(xpath, value_str); +} + +int64_t yang_dnode_get_int64(const struct lyd_node *dnode, + const char *xpath_fmt, ...) +{ + const struct lyd_value *dvalue; + dvalue = YANG_DNODE_XPATH_GET_VALUE(dnode, xpath_fmt); + assert(dvalue->realtype->basetype == LY_TYPE_INT64); + return dvalue->int64; +} + +int64_t yang_get_default_int64(const char *xpath_fmt, ...) +{ + char xpath[XPATH_MAXLEN]; + const char *value; + va_list ap; + + va_start(ap, xpath_fmt); + vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); + va_end(ap); + + value = yang_get_default_value(xpath); + return yang_str2int64(value); +} + +/* + * Primitive type: uint8. + */ +uint8_t yang_str2uint8(const char *value) +{ + return strtoul(value, NULL, 10); +} + +struct yang_data *yang_data_new_uint8(const char *xpath, uint8_t value) +{ + char value_str[BUFSIZ]; + + snprintf(value_str, sizeof(value_str), "%u", value); + return yang_data_new(xpath, value_str); +} + +uint8_t yang_dnode_get_uint8(const struct lyd_node *dnode, + const char *xpath_fmt, ...) +{ + const struct lyd_value *dvalue; + dvalue = YANG_DNODE_XPATH_GET_VALUE(dnode, xpath_fmt); + assert(dvalue->realtype->basetype == LY_TYPE_UINT8); + return dvalue->uint8; +} + +uint8_t yang_get_default_uint8(const char *xpath_fmt, ...) +{ + char xpath[XPATH_MAXLEN]; + const char *value; + va_list ap; + + va_start(ap, xpath_fmt); + vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); + va_end(ap); + + value = yang_get_default_value(xpath); + return yang_str2uint8(value); +} + +/* + * Primitive type: uint16. + */ +uint16_t yang_str2uint16(const char *value) +{ + return strtoul(value, NULL, 10); +} + +struct yang_data *yang_data_new_uint16(const char *xpath, uint16_t value) +{ + char value_str[BUFSIZ]; + + snprintf(value_str, sizeof(value_str), "%u", value); + return yang_data_new(xpath, value_str); +} + +uint16_t yang_dnode_get_uint16(const struct lyd_node *dnode, + const char *xpath_fmt, ...) +{ + const struct lyd_value *dvalue; + dvalue = YANG_DNODE_XPATH_GET_VALUE(dnode, xpath_fmt); + assert(dvalue->realtype->basetype == LY_TYPE_UINT16); + return dvalue->uint16; +} + +uint16_t yang_get_default_uint16(const char *xpath_fmt, ...) +{ + char xpath[XPATH_MAXLEN]; + const char *value; + va_list ap; + + va_start(ap, xpath_fmt); + vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); + va_end(ap); + + value = yang_get_default_value(xpath); + return yang_str2uint16(value); +} + +/* + * Primitive type: uint32. + */ +uint32_t yang_str2uint32(const char *value) +{ + return strtoul(value, NULL, 10); +} + +struct yang_data *yang_data_new_uint32(const char *xpath, uint32_t value) +{ + char value_str[BUFSIZ]; + + snprintf(value_str, sizeof(value_str), "%u", value); + return yang_data_new(xpath, value_str); +} + +uint32_t yang_dnode_get_uint32(const struct lyd_node *dnode, + const char *xpath_fmt, ...) +{ + const struct lyd_value *dvalue; + dvalue = YANG_DNODE_XPATH_GET_VALUE(dnode, xpath_fmt); + assert(dvalue->realtype->basetype == LY_TYPE_UINT32); + return dvalue->uint32; +} + +uint32_t yang_get_default_uint32(const char *xpath_fmt, ...) +{ + char xpath[XPATH_MAXLEN]; + const char *value; + va_list ap; + + va_start(ap, xpath_fmt); + vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); + va_end(ap); + + value = yang_get_default_value(xpath); + return yang_str2uint32(value); +} + +/* + * Primitive type: uint64. + */ +uint64_t yang_str2uint64(const char *value) +{ + return strtoull(value, NULL, 10); +} + +struct yang_data *yang_data_new_uint64(const char *xpath, uint64_t value) +{ + char value_str[BUFSIZ]; + + snprintfrr(value_str, sizeof(value_str), "%" PRIu64, value); + return yang_data_new(xpath, value_str); +} + +uint64_t yang_dnode_get_uint64(const struct lyd_node *dnode, + const char *xpath_fmt, ...) +{ + const struct lyd_value *dvalue; + dvalue = YANG_DNODE_XPATH_GET_VALUE(dnode, xpath_fmt); + assert(dvalue->realtype->basetype == LY_TYPE_UINT64); + return dvalue->uint64; +} + +uint64_t yang_get_default_uint64(const char *xpath_fmt, ...) +{ + char xpath[XPATH_MAXLEN]; + const char *value; + va_list ap; + + va_start(ap, xpath_fmt); + vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); + va_end(ap); + + value = yang_get_default_value(xpath); + return yang_str2uint64(value); +} + +/* + * Primitive type: string. + * + * All string wrappers can be used with non-string types. + */ +struct yang_data *yang_data_new_string(const char *xpath, const char *value) +{ + return yang_data_new(xpath, value); +} + +const char *yang_dnode_get_string(const struct lyd_node *dnode, + const char *xpath_fmt, ...) +{ + return YANG_DNODE_XPATH_GET_CANON(dnode, xpath_fmt); +} + +void yang_dnode_get_string_buf(char *buf, size_t size, + const struct lyd_node *dnode, + const char *xpath_fmt, ...) +{ + const char *canon = YANG_DNODE_XPATH_GET_CANON(dnode, xpath_fmt); + if (strlcpy(buf, canon, size) >= size) { + char xpath[XPATH_MAXLEN]; + + yang_dnode_get_path(dnode, xpath, sizeof(xpath)); + flog_warn(EC_LIB_YANG_DATA_TRUNCATED, + "%s: value was truncated [xpath %s]", __func__, + xpath); + } +} + +const char *yang_get_default_string(const char *xpath_fmt, ...) +{ + char xpath[XPATH_MAXLEN]; + va_list ap; + + va_start(ap, xpath_fmt); + vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); + va_end(ap); + + return yang_get_default_value(xpath); +} + +void yang_get_default_string_buf(char *buf, size_t size, const char *xpath_fmt, + ...) +{ + char xpath[XPATH_MAXLEN]; + const char *value; + va_list ap; + + va_start(ap, xpath_fmt); + vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); + va_end(ap); + + value = yang_get_default_value(xpath); + if (strlcpy(buf, value, size) >= size) + flog_warn(EC_LIB_YANG_DATA_TRUNCATED, + "%s: value was truncated [xpath %s]", __func__, + xpath); +} + +/* + * Primitive type: binary. + */ +struct yang_data *yang_data_new_binary(const char *xpath, const char *value, + size_t len) +{ + char *value_str; + struct base64_encodestate s; + int cnt; + char *c; + struct yang_data *data; + + value_str = (char *)malloc(len * 2); + base64_init_encodestate(&s); + cnt = base64_encode_block(value, len, value_str, &s); + c = value_str + cnt; + cnt = base64_encode_blockend(c, &s); + c += cnt; + *c = 0; + data = yang_data_new(xpath, value_str); + free(value_str); + return data; +} + +size_t yang_dnode_get_binary_buf(char *buf, size_t size, + const struct lyd_node *dnode, + const char *xpath_fmt, ...) +{ + const char *canon; + size_t cannon_len; + size_t decode_len; + size_t ret_len; + size_t cnt; + char *value_str; + struct base64_decodestate s; + + canon = YANG_DNODE_XPATH_GET_CANON(dnode, xpath_fmt); + cannon_len = strlen(canon); + decode_len = cannon_len + 1; + value_str = (char *)malloc(decode_len); + base64_init_decodestate(&s); + cnt = base64_decode_block(canon, cannon_len, value_str, &s); + + ret_len = size > cnt ? cnt : size; + memcpy(buf, value_str, ret_len); + if (size < cnt) { + char xpath[XPATH_MAXLEN]; + + yang_dnode_get_path(dnode, xpath, sizeof(xpath)); + flog_warn(EC_LIB_YANG_DATA_TRUNCATED, + "%s: value was truncated [xpath %s]", __func__, + xpath); + } + free(value_str); + return ret_len; +} + + +/* + * Primitive type: empty. + */ +struct yang_data *yang_data_new_empty(const char *xpath) +{ + return yang_data_new(xpath, NULL); +} + +bool yang_dnode_get_empty(const struct lyd_node *dnode, const char *xpath_fmt, + ...) +{ + va_list ap; + char xpath[XPATH_MAXLEN]; + const struct lyd_node_term *dleaf; + + assert(dnode); + + va_start(ap, xpath_fmt); + vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); + va_end(ap); + + dnode = yang_dnode_get(dnode, xpath); + if (dnode) { + dleaf = (const struct lyd_node_term *)dnode; + if (dleaf->value.realtype->basetype == LY_TYPE_EMPTY) + return true; + } + + return false; +} + +/* + * Derived type: IP prefix. + */ +void yang_str2prefix(const char *value, union prefixptr prefix) +{ + (void)str2prefix(value, prefix.p); + apply_mask(prefix.p); +} + +struct yang_data *yang_data_new_prefix(const char *xpath, + union prefixconstptr prefix) +{ + char value_str[PREFIX2STR_BUFFER]; + + (void)prefix2str(prefix.p, value_str, sizeof(value_str)); + return yang_data_new(xpath, value_str); +} + +void yang_dnode_get_prefix(struct prefix *prefix, const struct lyd_node *dnode, + const char *xpath_fmt, ...) +{ + const char *canon; + /* + * Initialize prefix to avoid static analyzer complaints about + * uninitialized memory. + */ + memset(prefix, 0, sizeof(*prefix)); + + /* XXX ip_prefix is a native type now in ly2, leverage? */ + canon = YANG_DNODE_XPATH_GET_CANON(dnode, xpath_fmt); + (void)str2prefix(canon, prefix); +} + +void yang_get_default_prefix(union prefixptr var, const char *xpath_fmt, ...) +{ + char xpath[XPATH_MAXLEN]; + const char *value; + va_list ap; + + va_start(ap, xpath_fmt); + vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); + va_end(ap); + + value = yang_get_default_value(xpath); + yang_str2prefix(value, var); +} + +/* + * Derived type: ipv4. + */ +void yang_str2ipv4(const char *value, struct in_addr *addr) +{ + (void)inet_pton(AF_INET, value, addr); +} + +struct yang_data *yang_data_new_ipv4(const char *xpath, + const struct in_addr *addr) +{ + char value_str[INET_ADDRSTRLEN]; + + (void)inet_ntop(AF_INET, addr, value_str, sizeof(value_str)); + return yang_data_new(xpath, value_str); +} + +void yang_dnode_get_ipv4(struct in_addr *addr, const struct lyd_node *dnode, + const char *xpath_fmt, ...) +{ + /* XXX libyang2 IPv4 address is a native type now in ly2 */ + const char *canon = YANG_DNODE_XPATH_GET_CANON(dnode, xpath_fmt); + (void)inet_pton(AF_INET, canon, addr); +} + +void yang_get_default_ipv4(struct in_addr *var, const char *xpath_fmt, ...) +{ + char xpath[XPATH_MAXLEN]; + const char *value; + va_list ap; + + va_start(ap, xpath_fmt); + vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); + va_end(ap); + + value = yang_get_default_value(xpath); + yang_str2ipv4(value, var); +} + +/* + * Derived type: ipv4p. + */ +void yang_str2ipv4p(const char *value, union prefixptr prefix) +{ + struct prefix_ipv4 *prefix4 = prefix.p4; + + (void)str2prefix_ipv4(value, prefix4); + apply_mask_ipv4(prefix4); +} + +struct yang_data *yang_data_new_ipv4p(const char *xpath, + union prefixconstptr prefix) +{ + char value_str[PREFIX2STR_BUFFER]; + + (void)prefix2str(prefix.p, value_str, sizeof(value_str)); + return yang_data_new(xpath, value_str); +} + +void yang_dnode_get_ipv4p(union prefixptr prefix, const struct lyd_node *dnode, + const char *xpath_fmt, ...) +{ + struct prefix_ipv4 *prefix4 = prefix.p4; + /* XXX libyang2: ipv4/6 address is a native type now in ly2 */ + const char *canon = YANG_DNODE_XPATH_GET_CANON(dnode, xpath_fmt); + (void)str2prefix_ipv4(canon, prefix4); +} + +void yang_get_default_ipv4p(union prefixptr var, const char *xpath_fmt, ...) +{ + char xpath[XPATH_MAXLEN]; + const char *value; + va_list ap; + + va_start(ap, xpath_fmt); + vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); + va_end(ap); + + value = yang_get_default_value(xpath); + yang_str2ipv4p(value, var); +} + +/* + * Derived type: ipv6. + */ +void yang_str2ipv6(const char *value, struct in6_addr *addr) +{ + (void)inet_pton(AF_INET6, value, addr); +} + +struct yang_data *yang_data_new_ipv6(const char *xpath, + const struct in6_addr *addr) +{ + char value_str[INET6_ADDRSTRLEN]; + + (void)inet_ntop(AF_INET6, addr, value_str, sizeof(value_str)); + return yang_data_new(xpath, value_str); +} + +void yang_dnode_get_ipv6(struct in6_addr *addr, const struct lyd_node *dnode, + const char *xpath_fmt, ...) +{ + /* XXX libyang2: IPv6 address is a native type now, leverage. */ + const char *canon = YANG_DNODE_XPATH_GET_CANON(dnode, xpath_fmt); + (void)inet_pton(AF_INET6, canon, addr); +} + +void yang_get_default_ipv6(struct in6_addr *var, const char *xpath_fmt, ...) +{ + char xpath[XPATH_MAXLEN]; + const char *value; + va_list ap; + + va_start(ap, xpath_fmt); + vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); + va_end(ap); + + value = yang_get_default_value(xpath); + yang_str2ipv6(value, var); +} + +/* + * Derived type: ipv6p. + */ +void yang_str2ipv6p(const char *value, union prefixptr prefix) +{ + struct prefix_ipv6 *prefix6 = prefix.p6; + + (void)str2prefix_ipv6(value, prefix6); + apply_mask_ipv6(prefix6); +} + +struct yang_data *yang_data_new_ipv6p(const char *xpath, + union prefixconstptr prefix) +{ + char value_str[PREFIX2STR_BUFFER]; + + (void)prefix2str(prefix.p, value_str, sizeof(value_str)); + return yang_data_new(xpath, value_str); +} + +void yang_dnode_get_ipv6p(union prefixptr prefix, const struct lyd_node *dnode, + const char *xpath_fmt, ...) +{ + struct prefix_ipv6 *prefix6 = prefix.p6; + + /* XXX IPv6 address is a native type now in ly2 -- can we leverage? */ + const char *canon = YANG_DNODE_XPATH_GET_CANON(dnode, xpath_fmt); + (void)str2prefix_ipv6(canon, prefix6); +} + +void yang_get_default_ipv6p(union prefixptr var, const char *xpath_fmt, ...) +{ + char xpath[XPATH_MAXLEN]; + const char *value; + va_list ap; + + va_start(ap, xpath_fmt); + vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); + va_end(ap); + + value = yang_get_default_value(xpath); + yang_str2ipv6p(value, var); +} + +/* + * Derived type: ip. + */ +void yang_str2ip(const char *value, struct ipaddr *ip) +{ + (void)str2ipaddr(value, ip); +} + +struct yang_data *yang_data_new_ip(const char *xpath, const struct ipaddr *addr) +{ + size_t sz = IS_IPADDR_V4(addr) ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN; + char value_str[sz]; + + ipaddr2str(addr, value_str, sizeof(value_str)); + return yang_data_new(xpath, value_str); +} + +void yang_dnode_get_ip(struct ipaddr *addr, const struct lyd_node *dnode, + const char *xpath_fmt, ...) +{ + /* XXX IPv4 address could be a plugin type now in ly2, leverage? */ + const char *canon = YANG_DNODE_XPATH_GET_CANON(dnode, xpath_fmt); + (void)str2ipaddr(canon, addr); +} + +void yang_get_default_ip(struct ipaddr *var, const char *xpath_fmt, ...) +{ + char xpath[XPATH_MAXLEN]; + const char *value; + va_list ap; + + va_start(ap, xpath_fmt); + vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); + va_end(ap); + + value = yang_get_default_value(xpath); + yang_str2ip(value, var); +} + +struct yang_data *yang_data_new_mac(const char *xpath, + const struct ethaddr *mac) +{ + char value_str[ETHER_ADDR_STRLEN]; + + prefix_mac2str(mac, value_str, sizeof(value_str)); + return yang_data_new(xpath, value_str); +} + +void yang_str2mac(const char *value, struct ethaddr *mac) +{ + (void)prefix_str2mac(value, mac); +} + +struct yang_data *yang_data_new_date_and_time(const char *xpath, time_t time) +{ + struct tm tm; + char timebuf[MONOTIME_STRLEN]; + struct timeval _time, time_real; + char *ts_dot; + uint16_t buflen; + + _time.tv_sec = time; + _time.tv_usec = 0; + monotime_to_realtime(&_time, &time_real); + + gmtime_r(&time_real.tv_sec, &tm); + + /* rfc-3339 format */ + strftime(timebuf, sizeof(timebuf), "%Y-%m-%dT%H:%M:%S", &tm); + buflen = strlen(timebuf); + ts_dot = timebuf + buflen; + + /* microseconds and appends Z */ + snprintfrr(ts_dot, sizeof(timebuf) - buflen, ".%06luZ", + (unsigned long)time_real.tv_usec); + + return yang_data_new(xpath, timebuf); +} + +const char *yang_nexthop_type2str(uint32_t ntype) +{ + switch (ntype) { + case NEXTHOP_TYPE_IFINDEX: + return "ifindex"; + break; + case NEXTHOP_TYPE_IPV4: + return "ip4"; + break; + case NEXTHOP_TYPE_IPV4_IFINDEX: + return "ip4-ifindex"; + break; + case NEXTHOP_TYPE_IPV6: + return "ip6"; + break; + case NEXTHOP_TYPE_IPV6_IFINDEX: + return "ip6-ifindex"; + break; + case NEXTHOP_TYPE_BLACKHOLE: + return "blackhole"; + break; + default: + return "unknown"; + break; + } +} + + +const char *yang_afi_safi_value2identity(afi_t afi, safi_t safi) +{ + if (afi == AFI_IP && safi == SAFI_UNICAST) + return "frr-routing:ipv4-unicast"; + if (afi == AFI_IP6 && safi == SAFI_UNICAST) + return "frr-routing:ipv6-unicast"; + if (afi == AFI_IP && safi == SAFI_MULTICAST) + return "frr-routing:ipv4-multicast"; + if (afi == AFI_IP6 && safi == SAFI_MULTICAST) + return "frr-routing:ipv6-multicast"; + if (afi == AFI_IP && safi == SAFI_MPLS_VPN) + return "frr-routing:l3vpn-ipv4-unicast"; + if (afi == AFI_IP6 && safi == SAFI_MPLS_VPN) + return "frr-routing:l3vpn-ipv6-unicast"; + if (afi == AFI_L2VPN && safi == SAFI_EVPN) + return "frr-routing:l2vpn-evpn"; + if (afi == AFI_IP && safi == SAFI_LABELED_UNICAST) + return "frr-routing:ipv4-labeled-unicast"; + if (afi == AFI_IP6 && safi == SAFI_LABELED_UNICAST) + return "frr-routing:ipv6-labeled-unicast"; + if (afi == AFI_IP && safi == SAFI_FLOWSPEC) + return "frr-routing:ipv4-flowspec"; + if (afi == AFI_IP6 && safi == SAFI_FLOWSPEC) + return "frr-routing:ipv6-flowspec"; + + return NULL; +} + +void yang_afi_safi_identity2value(const char *key, afi_t *afi, safi_t *safi) +{ + if (strmatch(key, "frr-routing:ipv4-unicast")) { + *afi = AFI_IP; + *safi = SAFI_UNICAST; + } else if (strmatch(key, "frr-routing:ipv6-unicast")) { + *afi = AFI_IP6; + *safi = SAFI_UNICAST; + } else if (strmatch(key, "frr-routing:ipv4-multicast")) { + *afi = AFI_IP; + *safi = SAFI_MULTICAST; + } else if (strmatch(key, "frr-routing:ipv6-multicast")) { + *afi = AFI_IP6; + *safi = SAFI_MULTICAST; + } else if (strmatch(key, "frr-routing:l3vpn-ipv4-unicast")) { + *afi = AFI_IP; + *safi = SAFI_MPLS_VPN; + } else if (strmatch(key, "frr-routing:l3vpn-ipv6-unicast")) { + *afi = AFI_IP6; + *safi = SAFI_MPLS_VPN; + } else if (strmatch(key, "frr-routing:ipv4-labeled-unicast")) { + *afi = AFI_IP; + *safi = SAFI_LABELED_UNICAST; + } else if (strmatch(key, "frr-routing:ipv6-labeled-unicast")) { + *afi = AFI_IP6; + *safi = SAFI_LABELED_UNICAST; + } else if (strmatch(key, "frr-routing:l2vpn-evpn")) { + *afi = AFI_L2VPN; + *safi = SAFI_EVPN; + } else if (strmatch(key, "frr-routing:ipv4-flowspec")) { + *afi = AFI_IP; + *safi = SAFI_FLOWSPEC; + } else if (strmatch(key, "frr-routing:ipv6-flowspec")) { + *afi = AFI_IP6; + *safi = SAFI_FLOWSPEC; + } else { + *afi = AFI_UNSPEC; + *safi = SAFI_UNSPEC; + } +} |