From 70149f4ea89aa9f5c002b63f56d0c98afcafbad9 Mon Sep 17 00:00:00 2001 From: James Simmons Date: Sat, 16 Jul 2022 15:34:48 -0400 Subject: [PATCH] LU-9680 utils: fix Netlink / YAML library handling Testing the implementation of Netlink with lustre with early code revealed some userland lnetconfig library bugs. Several bugs fixed are: 1) First issue was that the YAML parser and emitter can share an netlink socket. This means the netlink callbacks will expect that same void argument passed in. We were in the case of error handling expecting an struct yaml_netlink_output but all other callbacks were using struct yaml_netlink_input. This mismatch can cause the application to segfault. So move all netlink callback handling to use just the yaml_parser. The yaml emittter now is used to just send Netlink packets to the kernel. Also fix the Netlink ext_ack error message handling. 2) In my board testing I found various bugs related to the paring of the YAML to create Netlink packet to send to the kernel. This patch resolves all the known issues. Most related to the complex layering of sequences, mappings and flows in a YAML block. 3) Fix up nla_strlcpy autoconf test which always fails with Oleg's special setup. 4) Add a Netlink protocol version YAML function. Test-Parameters: trivial Change-Id: I7e7c755ceaa969dffff8c6f771c2ac048dc55720 Signed-off-by: James Simmons Reviewed-on: https://review.whamcloud.com/47802 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Joe Atzinger Reviewed-by: Serguei Smirnov Reviewed-by: Oleg Drokin --- libcfs/autoconf/lustre-libcfs.m4 | 36 +-- libcfs/include/libcfs/linux/linux-net.h | 4 +- lnet/utils/lnetconfig/liblnetconfig.h | 10 + lnet/utils/lnetconfig/liblnetconfig_netlink.c | 420 ++++++++++++++------------ 4 files changed, 258 insertions(+), 212 deletions(-) diff --git a/libcfs/autoconf/lustre-libcfs.m4 b/libcfs/autoconf/lustre-libcfs.m4 index 211bfef..9b98dab 100644 --- a/libcfs/autoconf/lustre-libcfs.m4 +++ b/libcfs/autoconf/lustre-libcfs.m4 @@ -1790,30 +1790,23 @@ EXTRA_KCFLAGS="$tmp_flags" ]) # LIBCFS_HAVE_LIST_CMP_FUNC_T # -# LIBCFS_NLA_STRSCPY +# LIBCFS_NLA_STRLCPY # # Kernel version 5.10-rc3 commit 872f690341948b502c93318f806d821c56772c42 # replaced nla_strlcpy() with nla_strscpy(). # -AC_DEFUN([LIBCFS_SRC_NLA_STRSCPY], [ - LB2_LINUX_TEST_SRC([nla_strscpy], [ - #include - ],[ - if (nla_strscpy(NULL, NULL, 0) < 0) - return -EINVAL; - ],[ - ],[]) +AC_DEFUN([LIBCFS_NLA_STRLCPY], [ +LB_CHECK_COMPILE([if 'nla_strlcpy()' still exists], +nla_strlcpy, [ + #include +],[ + if (nla_strlcpy(NULL, NULL, 0) == 0) + return -EINVAL; +],[ + AC_DEFINE(HAVE_NLA_STRLCPY, 1, + ['nla_strlcpy' is available]) ]) -AC_DEFUN([LIBCFS_NLA_STRSCPY], [ - AC_MSG_CHECKING([if 'nla_strscpy()' exists]) - LB2_LINUX_TEST_RESULT([nla_strscpy], [ - AC_DEFINE(HAVE_NLA_STRSCPY, 1, - ['nla_strscpy' is available]) - AC_MSG_RESULT(yes) - ],[ - AC_MSG_RESULT(no) - ]) -]) # LIBCFS_NLA_STRSCPY +]) # LIBCFS_NLA_STRLCPY # # LIBCFS_HAVE_CIPHER_HEADER @@ -1905,8 +1898,6 @@ param_set_uint_minmax, [ AC_DEFUN([LIBCFS_PROG_LINUX_SRC], [ # 5.6 LIBCFS_SRC_HAVE_PROC_OPS - # 5.10 - LIBCFS_SRC_NLA_STRSCPY AC_MSG_CHECKING([for available kernel interfaces to libcfs]) LB2_LINUX_TEST_COMPILE_ALL([libcfs]) @@ -1915,8 +1906,6 @@ AC_DEFUN([LIBCFS_PROG_LINUX_SRC], [ AC_DEFUN([LIBCFS_PROG_LINUX_RESULTS], [ # 5.6 LIBCFS_HAVE_PROC_OPS - # 5.10 - LIBCFS_NLA_STRSCPY ]) # @@ -2069,6 +2058,7 @@ LIBCFS_SEC_RELEASE_SECCTX LIBCFS_HAVE_KFREE_SENSITIVE LIBCFS_HAVE_CRYPTO_SHA2_HEADER LIBCFS_HAVE_LIST_CMP_FUNC_T +LIBCFS_NLA_STRLCPY # 5.12 LIBCFS_HAVE_CIPHER_HEADER # 5.13 diff --git a/libcfs/include/libcfs/linux/linux-net.h b/libcfs/include/libcfs/linux/linux-net.h index 4d43894..17b1b30 100644 --- a/libcfs/include/libcfs/linux/linux-net.h +++ b/libcfs/include/libcfs/linux/linux-net.h @@ -30,9 +30,9 @@ char *nla_strdup(const struct nlattr *nla, gfp_t flags); #endif /* !HAVE_NLA_STRDUP */ -#ifndef HAVE_NLA_STRSCPY +#ifdef HAVE_NLA_STRLCPY #define nla_strscpy nla_strlcpy -#endif /* !HAVE_NLA_STRSCPY */ +#endif /* HAVE_NLA_STRLCPY */ #ifndef HAVE_NL_PARSE_WITH_EXT_ACK diff --git a/lnet/utils/lnetconfig/liblnetconfig.h b/lnet/utils/lnetconfig/liblnetconfig.h index f7bc7c1..bea08c5 100644 --- a/lnet/utils/lnetconfig/liblnetconfig.h +++ b/lnet/utils/lnetconfig/liblnetconfig.h @@ -820,6 +820,16 @@ int yaml_parser_set_input_netlink(yaml_parser_t *parser, struct nl_sock *nl, bool stream); /** + * yaml_parser_get_reader_proto_version + * + * This function retrieves the Neltink version the kernel module + * is set to. + * + * parser - YAML parser being used for Netlink communication. + */ +int yaml_parser_get_reader_proto_version(yaml_parser_t *parser); + +/** * yaml_parser_get_reader_error * * By default libyaml reports a generic write error. We need a way diff --git a/lnet/utils/lnetconfig/liblnetconfig_netlink.c b/lnet/utils/lnetconfig/liblnetconfig_netlink.c index dd159dd..5c59ec6 100644 --- a/lnet/utils/lnetconfig/liblnetconfig_netlink.c +++ b/lnet/utils/lnetconfig/liblnetconfig_netlink.c @@ -317,6 +317,7 @@ struct yaml_netlink_input { bool complete; bool async; unsigned int indent; + unsigned int version; struct yaml_nl_node *cur; struct yaml_nl_node *root; }; @@ -608,10 +609,15 @@ static void yaml_parse_value_list(struct yaml_netlink_input *data, int *size, LNKF_SEQUENCE) indent += 2; - len = snprintf(data->buffer, *size, - "%*s%s:\n", - data->indent, "", - keys[i].lkp_value); + if (keys[i].lkp_value) { + len = snprintf(data->buffer, + *size, + "%*s%s:\n", + data->indent, "", + keys[i].lkp_value); + } else { + len = 0; + } } if (len < 0) goto unwind; @@ -717,6 +723,10 @@ not_first: strcat((char *)data->buffer, ", "); len += 2; } else { + if ((mapping == LNKF_SEQUENCE) && + !keys[i].lkp_value) + ((char *)data->buffer)[len++] = ':'; + ((char *)data->buffer)[len++] = '\n'; } data->buffer += len; @@ -742,6 +752,7 @@ static int yaml_netlink_msg_parse(struct nl_msg *msg, void *arg) struct nlmsghdr *nlh = nlmsg_hdr(msg); if (nlh->nlmsg_flags & NLM_F_CREATE) { + struct genlmsghdr *ghdr = genlmsg_hdr(nlh); struct nlattr *attrs[LN_SCALAR_MAX + 1]; if (genlmsg_parse(nlh, 0, attrs, LN_SCALAR_MAX + 1, @@ -769,6 +780,7 @@ static int yaml_netlink_msg_parse(struct nl_msg *msg, void *arg) strncpy(data->buffer, start_doc, len); data->buffer += len - 1; } + data->version = ghdr->version; } else { uint16_t maxtype = data->cur->keys.lkl_maxattr; struct nla_policy policy[maxtype]; @@ -792,6 +804,45 @@ static int yaml_netlink_msg_parse(struct nl_msg *msg, void *arg) return NL_OK; } +/* This is the libnl callback for when an error has happened + * kernel side. An error message is sent back to the user. + */ +static int yaml_netlink_msg_error(struct sockaddr_nl *who, + struct nlmsgerr *errmsg, void *arg) +{ + struct nlmsghdr *nlh = (void *)errmsg - NLMSG_HDRLEN; + struct yaml_netlink_input *data = arg; + + if ((nlh->nlmsg_type == NLMSG_ERROR || + nlh->nlmsg_flags & NLM_F_ACK_TLVS) && errmsg->error) { + /* libyaml stomps on the reader error so we need to + * cache the source of the error. + */ + const char *errstr = nl_geterror(nl_syserr2nlerr(errmsg->error)); + +#ifdef HAVE_USRSPC_NLMSGERR + /* Newer kernels support NLM_F_ACK_TLVS in nlmsg_flags + * which gives greater detail why we failed. + */ + if ((nlh->nlmsg_flags & NLM_F_ACK_TLVS) && + !(nlh->nlmsg_flags & NLM_F_CAPPED)) { + struct nlattr *head = ((void *)&errmsg->msg); + struct nlattr *tb[NLMSGERR_ATTR_MAX]; + + if (nla_parse(tb, NLMSGERR_ATTR_MAX, head, + nlmsg_attrlen(nlh, 0), NULL) == 0) { + if (tb[NLMSGERR_ATTR_MSG]) + errstr = nla_strdup(tb[NLMSGERR_ATTR_MSG]); + } + } +#endif /* HAVE_USRSPC_NLMSGERR */ + data->errmsg = errstr; + data->parser->error = YAML_READER_ERROR; + data->complete = true; + } + return NL_STOP; +} + static bool cleanup_children(struct yaml_nl_node *parent) { struct yaml_nl_node *child; @@ -823,51 +874,33 @@ static int yaml_netlink_msg_complete(struct nl_msg *msg, void *arg) { struct yaml_netlink_input *data = arg; struct nlmsghdr *nlh = nlmsg_hdr(msg); - struct nlmsgerr *errmsg = nlmsg_data(nlh); - if ((nlh->nlmsg_type == NLMSG_ERROR || - nlh->nlmsg_flags & NLM_F_ACK_TLVS) && errmsg->error) { - /* libyaml stomps on the reader error so we need to - * cache the source of the error. - */ - data->errmsg = nl_geterror(nl_syserr2nlerr(errmsg->error)); -#ifdef HAVE_USRSPC_NLMSGERR - /* Newer kernels support NLM_F_ACK_TLVS in nlmsg_flags - * which gives greater detail why we failed. - */ - if (nlh->nlmsg_flags & NLM_F_ACK_TLVS && - !(nlh->nlmsg_flags & NLM_F_CAPPED)) { - struct nlattr *head = ((void *)&errmsg->msg); - struct nlattr *tb[NLMSGERR_ATTR_MAX + 1]; + /* For the case of NLM_F_DUMP the kernel will send error msgs + * yet not be labled NLMSG_ERROR which results in this code + * path being executed. + */ + yaml_netlink_msg_error(NULL, nlmsg_data(nlh), arg); + if (data->parser->error == YAML_READER_ERROR) + return NL_STOP; - if (nla_parse(tb, NLMSGERR_ATTR_MAX + 1, head, - nlmsg_attrlen(nlh, 0), NULL) == 0) { - if (tb[NLMSGERR_ATTR_MSG]) - data->errmsg = nla_strdup(tb[NLMSGERR_ATTR_MSG]); - } - } -#endif /* HAVE_USRSPC_NLMSGERR */ - data->parser->error = YAML_READER_ERROR; - data->complete = true; + /* Free internal data. */ + if (data->root) { + cleanup_children(data->root); + free(data->root); + data->root = NULL; + } - return NL_STOP; - } else { - if (data->root) { - cleanup_children(data->root); - free(data->root); - data->root = NULL; - } - /* For streaming insert '...' to define end of - * YAML document - */ - if (data->async) { - char *end_doc = "...\n"; - size_t len = strlen(end_doc) + 1; + /* For streaming insert '...' to define end of + * YAML document + */ + if (data->async) { + char *end_doc = "...\n"; + size_t len = strlen(end_doc) + 1; - strncpy(data->buffer, end_doc, len); - data->buffer += len - 1; - } else - data->complete = true; + strncpy(data->buffer, end_doc, len); + data->buffer += len - 1; + } else { + data->complete = true; } return data->async ? NL_OK : NL_STOP; @@ -899,7 +932,7 @@ static int yaml_netlink_read_handler(void *arg, unsigned char *buffer, if (rc == -NLE_INTR) { *size_read = 0; return 1; - } else if (rc < 0) { + } else if (!data->errmsg && rc < 0) { data->errmsg = nl_geterror(rc); return 0; } else if (data->parser->error) { @@ -930,6 +963,17 @@ yaml_parser_get_reader_error(yaml_parser_t *parser) return buf->errmsg; } +YAML_DECLARE(int) +yaml_parser_get_reader_proto_version(yaml_parser_t *parser) +{ + struct yaml_netlink_input *buf = parser->read_handler_data; + + if (!buf) + return 0; + + return buf->version; +} + /* yaml_parser_set_input_netlink() mirrors the libyaml function * yaml_parser_set_input_file(). Internally it does setup of the * libnl socket callbacks to parse the Netlink messages received @@ -977,9 +1021,19 @@ yaml_parser_set_input_netlink(yaml_parser_t *reply, struct nl_sock *nl, yaml_parser_set_reader_error(reply, "netlink msg cleanup setup failed", 0, -rc); + goto failed; + } + + rc = nl_socket_modify_err_cb(nl, NL_CB_CUSTOM, yaml_netlink_msg_error, + buf); + if (rc < 0) { + yaml_parser_set_reader_error(reply, + "failed to register error handling", + 0, -rc); failed: free(buf); } + return rc < 0 ? false : true; } @@ -1024,19 +1078,11 @@ static unsigned int indent_level(const char *str) static enum lnet_nl_key_format yaml_format_type(yaml_emitter_t *emitter, char *line, - unsigned int *offset, - enum lnet_nl_key_format prev) + unsigned int *offset) { + unsigned int indent = *offset, new_indent = 0; enum lnet_nl_key_format fmt = 0; - unsigned int indent = *offset; - unsigned int new_indent = 0; - - if (strchr(line, '{') || strchr(line, '[')) { - fmt = LNKF_FLOW; - if (strchr(line, '{')) - fmt |= LNKF_MAPPING; - return fmt; - } + char *tmp; new_indent = indent_level(line); if (new_indent < indent) { @@ -1045,18 +1091,27 @@ static enum lnet_nl_key_format yaml_format_type(yaml_emitter_t *emitter, } if (strncmp(line + new_indent, "- ", 2) == 0) { - *offset = new_indent + emitter->best_indent; - fmt = LNKF_SEQUENCE; + memset(line + new_indent, ' ', 2); + new_indent += 2; + } - if (strstr(line + new_indent, ": ")) - fmt |= LNKF_MAPPING; - return fmt; + /* hdr: [ a : 1, b : 2, c : 3 ] */ + tmp = strstr(line + new_indent, ": "); + if (!tmp) + tmp = line + new_indent; + else + fmt |= LNKF_MAPPING; + + if (strchr(tmp, '{') || strchr(tmp, '[')) { + fmt |= LNKF_FLOW; + } else if (strchr(tmp, '}') || strchr(tmp, ']')) { + fmt &= ~LNKF_MAPPING; + fmt |= LNKF_FLOW; } if (indent != new_indent) { *offset = new_indent; - if (prev != LNKF_MAPPING) - return LNKF_MAPPING; + fmt |= LNKF_SEQUENCE; } return fmt; @@ -1068,18 +1123,30 @@ static int yaml_fill_scalar_data(struct nl_msg *msg, { char *sep = strchr(line, ':'); int rc = 0; + long num; if (sep) *sep++ = '\0'; - NLA_PUT_STRING(msg, LN_SCALAR_ATTR_VALUE, line); - if (fmt & LNKF_MAPPING && sep) { + if (strspn(line, "-0123456789") == strlen(line)) { + num = strtoll(line, NULL, 0); + + NLA_PUT_S64(msg, LN_SCALAR_ATTR_INT_VALUE, num); + } else { + NLA_PUT_STRING(msg, LN_SCALAR_ATTR_VALUE, line); + } + + if (fmt & LNKF_FLOW) { + memset(line, ' ', strlen(line) + 1); + goto nla_put_failure; + } + + if (fmt & LNKF_MAPPING && sep && strlen(sep)) { while (isspace(*sep)) ++sep; - if (strspn(sep, "0123456789") == strlen(sep)) { - unsigned long num = strtoull(sep, NULL, 0); - + if (strspn(sep, "-0123456789") == strlen(sep)) { + num = strtoll(sep, NULL, 0); NLA_PUT_S64(msg, LN_SCALAR_ATTR_INT_VALUE, num); } else { NLA_PUT_STRING(msg, LN_SCALAR_ATTR_VALUE, sep); @@ -1094,22 +1161,32 @@ static int yaml_create_nested_list(struct yaml_netlink_output *out, char **entry, unsigned int *indent, enum lnet_nl_key_format fmt) { + bool nested = fmt & LNKF_SEQUENCE; struct nlattr *list = NULL; char *line; int rc = 0; - list = nla_nest_start(msg, LN_SCALAR_ATTR_LIST); - if (!list) { - yaml_emitter_set_writer_error(out->emitter, - "Emmitter netlink list creation failed"); - rc = -EINVAL; - goto nla_put_failure; + /* Not needed for FLOW only case */ + if (nested) { + list = nla_nest_start(msg, LN_SCALAR_ATTR_LIST); + if (!list) { + yaml_emitter_set_writer_error(out->emitter, + "Emmitter netlink list creation failed"); + rc = -EINVAL; + goto nla_put_failure; + } + } + + if (fmt != LNKF_FLOW) { + rc = yaml_fill_scalar_data(msg, fmt, *hdr + *indent); + if (rc < 0) + goto nla_put_failure; } if (fmt & LNKF_FLOW) { - char *tmp = NULL; + char *tmp = strchr(*hdr, '{'); + bool format = false; - tmp = strchr(*hdr, '{'); if (!tmp) { tmp = strchr(*hdr, '['); if (!tmp) { @@ -1118,64 +1195,89 @@ static int yaml_create_nested_list(struct yaml_netlink_output *out, rc = -EINVAL; goto nla_put_failure; } - } + fmt |= LNKF_SEQUENCE; + } else + fmt |= LNKF_MAPPING; *tmp = ' '; - tmp = strchr(*hdr, '}'); - if (!tmp) { - tmp = strchr(*hdr, ']'); - if (!tmp) { - yaml_emitter_set_writer_error(out->emitter, - "Emmitter flow format invalid"); - rc = -EINVAL; - goto nla_put_failure; - } + list = nla_nest_start(msg, LN_SCALAR_ATTR_LIST); + if (!list) { + yaml_emitter_set_writer_error(out->emitter, + "Emmitter netlink list creation failed"); + rc = -EINVAL; + goto nla_put_failure; } - *tmp = '\0'; while ((line = strsep(hdr, ",")) != NULL) { - if (isspace(line[0])) + while (!isalnum(line[0])) line++; + + /* Flow can be splt across lines by libyaml library. + * This is executed only once. + */ + tmp = strchr(line, '}'); + if (!tmp) + tmp = strchr(line, ']'); + if (tmp) { + format = true; + *tmp = '\0'; + } + rc = yaml_fill_scalar_data(msg, fmt, line); if (rc < 0) goto nla_put_failure; + + /* Move to next YAML line */ + tmp = strstr(*entry, line); + if (tmp && strcmp(tmp, line) == 0) + strsep(entry, "\n"); } - nla_nest_end(msg, list); - return 0; - } - rc = yaml_fill_scalar_data(msg, fmt, *hdr + *indent); - if (rc < 0) - goto nla_put_failure; - do { - line = strsep(entry, "\n"); + if (!format) { + yaml_emitter_set_writer_error(out->emitter, + "Emmitter flow format invalid"); + rc = -EINVAL; + goto nla_put_failure; + } + + nla_nest_end(msg, list); + } else { + do { + line = strsep(entry, "\n"); have_next_line: - if (!line || !strlen(line) || strcmp(line, "...") == 0) - break; + if (!line || !strlen(line) || strcmp(line, "...") == 0) + break; - fmt = yaml_format_type(out->emitter, line, indent, fmt); - if (fmt == LNKF_END) - break; + fmt = yaml_format_type(out->emitter, line, indent); + if (fmt == LNKF_END) + break; - if (fmt & ~LNKF_MAPPING) { /* Filter out mappings */ - rc = yaml_create_nested_list(out, msg, &line, entry, - indent, fmt); - if (rc) - goto nla_put_failure; + if (fmt & ~LNKF_MAPPING) { /* Filter out mappings */ + rc = yaml_create_nested_list(out, msg, &line, + entry, indent, + fmt); + if (rc < 0) + goto nla_put_failure; - goto have_next_line; - } else { - rc = yaml_fill_scalar_data(msg, fmt, line + *indent); - if (rc) - goto nla_put_failure; - } - } while (strcmp(line, "")); + if (line) + goto have_next_line; + } else { + rc = yaml_fill_scalar_data(msg, fmt, + line + *indent); + if (rc < 0) + goto nla_put_failure; + } + } while (strcmp(*entry, "")); - nla_nest_end(msg, list); - /* strsep in the above loop moves entry to a value pass the end of the - * nested list. So to avoid losing this value we replace hdr with line - */ - *hdr = line; + /* strsep in the above loop moves entry to a value pass the + * end of the nested list. So to avoid losing this value we + * replace hdr with line. + */ + *hdr = line; + } + + if (nested) + nla_nest_end(msg, list); nla_put_failure: return rc; } @@ -1236,6 +1338,11 @@ already_have_line: * libyaml prevents this from happing */ if (line[0] != ' ' && line[0] != '-') { + bool extra = false; + + if (strchr(line, '{') || strchr(line, '[')) + extra = true; + tmp = strchr(line, ':'); if (!tmp) continue; @@ -1249,15 +1356,15 @@ already_have_line: goto nla_put_failure; } nogroups = false; - /* Handle case first line contains more than a * simple key */ - line = tmp + 2; - if (strchr(line, '{') || strchr(line, '[')) - goto complicated; + if (extra) { + line = ++tmp; + indent = 1; + goto already_have_line; + } } else { -complicated: if (!msg) { void *usr_hdr; @@ -1279,8 +1386,7 @@ complicated: } } - fmt = yaml_format_type(out->emitter, line, &indent, - fmt); + fmt = yaml_format_type(out->emitter, line, &indent); if (fmt & ~LNKF_MAPPING) { rc = yaml_create_nested_list(out, msg, &line, &entry, &indent, @@ -1291,7 +1397,7 @@ complicated: nlmsg_free(msg); goto nla_put_failure; } - /* yaml_created_nested_list set line to the next + /* yaml_create_nested_list set line to the next * entry. We can just add it to the msg directly. */ if (line) @@ -1331,40 +1437,6 @@ nla_put_failure: return out->emitter->error == YAML_NO_ERROR ? 1 : 0; } -/* This is the libnl callback for when an error has happened - * kernel side. An error message is sent back to the user. - */ -static int yaml_netlink_write_error(struct sockaddr_nl *who, - struct nlmsgerr *errmsg, void *arg) -{ - struct yaml_netlink_output *data = arg; - struct nlmsghdr *nlh = &errmsg->msg; - - if ((nlh->nlmsg_type == NLMSG_ERROR || - nlh->nlmsg_flags & NLM_F_ACK_TLVS) && errmsg->error) { - const char *errstr = nl_geterror(nl_syserr2nlerr(errmsg->error)); - -#ifdef HAVE_USRSPC_NLMSGERR - /* Newer kernels support NLM_F_ACK_TLVS in nlmsg_flags - * which gives greater detail why we failed. - */ - if (nlh->nlmsg_flags & NLM_F_ACK_TLVS && - !(nlh->nlmsg_flags & NLM_F_CAPPED)) { - struct nlattr *head = ((void *)&errmsg->msg); - struct nlattr *tb[NLMSGERR_ATTR_MAX + 1]; - - if (nla_parse(tb, NLMSGERR_ATTR_MAX + 1, head, - nlmsg_attrlen(nlh, 0), NULL) == 0) { - if (tb[NLMSGERR_ATTR_MSG]) - errstr = nla_strdup(tb[NLMSGERR_ATTR_MSG]); - } - } -#endif /* HAVE_USRSPC_NLMSGERR */ - yaml_emitter_set_writer_error(data->emitter, errstr); - } - return NL_STOP; -} - /* This function is used by external utilities to use Netlink with * libyaml so we can turn YAML documentations into Netlink message * to send. This behavior mirrors yaml_emitter_set_output_file() @@ -1375,7 +1447,6 @@ yaml_emitter_set_output_netlink(yaml_emitter_t *sender, struct nl_sock *nl, char *family, int version, int cmd, int flags) { struct yaml_netlink_output *out; - int rc; out = calloc(1, sizeof(*out)); if (!out) { @@ -1392,31 +1463,6 @@ yaml_emitter_set_output_netlink(yaml_emitter_t *sender, struct nl_sock *nl, return false; } - rc = nl_socket_modify_err_cb(nl, NL_CB_CUSTOM, - yaml_netlink_write_error, out); - if (rc < 0) { - yaml_emitter_set_writer_error(sender, - "failed to register error handling"); - free(out); - return false; - } - - rc = nl_socket_enable_broadcast_error(nl); - if (rc < 0) { - yaml_emitter_set_writer_error(sender, - "failed to enable broadcast errors"); - free(out); - return false; - } - - rc = nl_socket_set_ext_ack(nl, true); - if (rc < 0) { - yaml_emitter_set_writer_error(sender, - "failed to enable ext ack"); - free(out); - return false; - } - out->emitter = sender; out->nl = nl; out->family = family; -- 1.8.3.1