From 5e27a30e1d7b64f056d666463aa6c6894531462d Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Thu, 8 Mar 2018 17:01:35 +0100 Subject: platform: print error message from netlink extended ack From v4.12 the kernel appends some attributes to netlink acks containing a textual description of the error and other fields (see commit [1]). Parse those attributes and print the error message. Example: platform-linux: netlink: recvmsg: error message from kernel: Network is unreachable (101) "Nexthop has invalid gateway" for request 12 [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=2d4bc93368f5a0ddb57c8c885cdad9c9b7a10ed5 --- src/platform/nm-linux-platform.c | 26 +++++++++++++++++++++++++- src/platform/nm-netlink.c | 20 ++++++++++++++++++++ src/platform/nm-netlink.h | 13 ++++++++++++- 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index dd5a52d265..74f55b5922 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -6596,11 +6596,31 @@ continue_reading: abort_parsing = TRUE; } else if (e->error) { int errsv = e->error > 0 ? e->error : -e->error; + const char *extack_msg = NULL; + + if (hdr->nlmsg_flags & NLM_F_ACK_TLVS) { + static const struct nla_policy policy[NLMSGERR_ATTR_MAX + 1] = { + [NLMSGERR_ATTR_MSG] = { .type = NLA_STRING }, + [NLMSGERR_ATTR_OFFS] = { .type = NLA_U32 }, + }; + struct nlattr *tb[NLMSGERR_ATTR_MAX + 1]; + struct nlattr *tlvs; + + nm_assert (hdr->nlmsg_len >= sizeof (*e) + e->msg.nlmsg_len); + + tlvs = (struct nlattr *) ((char *) e + sizeof (*e) + e->msg.nlmsg_len - NLMSG_HDRLEN); + if (!nla_parse (tb, NLMSGERR_ATTR_MAX, tlvs, + hdr->nlmsg_len - sizeof (*e) - e->msg.nlmsg_len, policy)) { + if (tb[NLMSGERR_ATTR_MSG]) + extack_msg = nla_get_string (tb[NLMSGERR_ATTR_MSG]); + } + } /* Error message reported back from kernel. */ - _LOGD ("netlink: recvmsg: error message from kernel: %s (%d) for request %d", + _LOGE ("netlink: recvmsg: error message from kernel: %s (%d)%s%s%s for request %d", strerror (errsv), errsv, + NM_PRINT_FMT_QUOTED (extack_msg, " \"", extack_msg, "\"", ""), nlmsg_hdr (msg)->nlmsg_seq); seq_result = -errsv; } else @@ -6948,6 +6968,10 @@ constructed (GObject *_object) nle = nl_socket_set_buffer_size (priv->nlh, 8*1024*1024, 0); g_assert (!nle); + nle = nl_socket_set_ext_ack (priv->nlh, TRUE); + if (nle) + _LOGD ("could not enable extended acks on netlink socket"); + /* explicitly set the msg buffer size and disable MSG_PEEK. * If we later encounter NLE_MSG_TRUNC, we will adjust the buffer size. */ nl_socket_disable_msg_peek (priv->nlh); diff --git a/src/platform/nm-netlink.c b/src/platform/nm-netlink.c index 7d794f7737..0baaaf0b47 100644 --- a/src/platform/nm-netlink.c +++ b/src/platform/nm-netlink.c @@ -38,6 +38,10 @@ #define NL_MSG_PEEK_EXPLICIT (1<<4) #define NL_NO_AUTO_ACK (1<<5) +#ifndef NETLINK_EXT_ACK +#define NETLINK_EXT_ACK 11 +#endif + #define NL_MSG_CRED_PRESENT 1 struct nl_msg { @@ -933,6 +937,22 @@ nl_socket_add_memberships (struct nl_sock *sk, int group, ...) return 0; } +int +nl_socket_set_ext_ack (struct nl_sock *sk, gboolean enable) +{ + int err; + + if (sk->s_fd == -1) + return -NLE_BAD_SOCK; + + enable = !!enable; + err = setsockopt (sk->s_fd, SOL_NETLINK, NETLINK_EXT_ACK, &enable, sizeof (enable)); + if (err < 0) + return -nl_syserr2nlerr (errno); + + return 0; +} + void nl_socket_disable_msg_peek (struct nl_sock *sk) { sk->s_flags |= NL_MSG_PEEK_EXPLICIT; diff --git a/src/platform/nm-netlink.h b/src/platform/nm-netlink.h index 42e46d6c69..bd8a9cfaf0 100644 --- a/src/platform/nm-netlink.h +++ b/src/platform/nm-netlink.h @@ -26,7 +26,6 @@ #include /*****************************************************************************/ - #define _NLE_BASE 100000 #define NLE_UNSPEC (_NLE_BASE + 0) #define NLE_BUG (_NLE_BASE + 1) @@ -42,6 +41,16 @@ #define _NLE_BASE_END (_NLE_BASE + 11) +#define NLMSGERR_ATTR_UNUSED 0 +#define NLMSGERR_ATTR_MSG 1 +#define NLMSGERR_ATTR_OFFS 2 +#define NLMSGERR_ATTR_COOKIE 3 +#define NLMSGERR_ATTR_MAX 3 + +#ifndef NLM_F_ACK_TLVS +#define NLM_F_ACK_TLVS 0x200 +#endif + static inline int nl_errno (int err) { @@ -484,6 +493,8 @@ int nl_recvmsgs (struct nl_sock *sk, const struct nl_cb *cb); int nl_wait_for_ack (struct nl_sock *sk, const struct nl_cb *cb); +int nl_socket_set_ext_ack (struct nl_sock *sk, gboolean enable); + /*****************************************************************************/ #endif /* __NM_NETLINK_H__ */ -- cgit v1.2.1