// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2018 NetDEF, Inc. * Renato Westphal */ #include #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) PRINTFRR(2, 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); } PRINTFRR(2, 0) 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 = yang_find_snode(ly_native_ctx, 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, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18 }; 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 = yang_find_snode(ly_native_ctx, 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 = yang_find_snode(ly_native_ctx, 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); } void yang_dnode_get_mac(struct ethaddr *mac, const struct lyd_node *dnode, const char *xpath_fmt, ...) { const char *canon = YANG_DNODE_XPATH_GET_CANON(dnode, xpath_fmt); (void)prefix_str2mac(canon, 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); } float yang_dnode_get_bandwidth_ieee_float32(const struct lyd_node *dnode, const char *xpath_fmt, ...) { const char *canon = YANG_DNODE_XPATH_GET_CANON(dnode, xpath_fmt); float value; assert(sscanf(canon, "%a", &value) == 1); return value; } 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; } }