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. Examples: platform-linux: netlink: recvmsg: error message from kernel: Network is unreachable (101) "Nexthop has invalid gateway" for request 12 platform-linux: netlink: recvmsg: error message from kernel: Invalid argument (22) "Local address cannot be multicast" for request 21 [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=2d4bc93368f5a0ddb57c8c885cdad9c9b7a10ed5
This commit is contained in:
@@ -6596,11 +6596,30 @@ continue_reading:
|
|||||||
abort_parsing = TRUE;
|
abort_parsing = TRUE;
|
||||||
} else if (e->error) {
|
} else if (e->error) {
|
||||||
int errsv = e->error > 0 ? e->error : -e->error;
|
int errsv = e->error > 0 ? e->error : -e->error;
|
||||||
|
const char *extack_msg = NULL;
|
||||||
|
|
||||||
|
if ( NM_FLAGS_HAS (hdr->nlmsg_flags, NLM_F_ACK_TLVS)
|
||||||
|
&& hdr->nlmsg_len >= sizeof (*e) + e->msg.nlmsg_len) {
|
||||||
|
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;
|
||||||
|
|
||||||
|
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. */
|
/* Error message reported back from kernel. */
|
||||||
_LOGD ("netlink: recvmsg: error message from kernel: %s (%d) for request %d",
|
_LOGD ("netlink: recvmsg: error message from kernel: %s (%d)%s%s%s for request %d",
|
||||||
strerror (errsv),
|
strerror (errsv),
|
||||||
errsv,
|
errsv,
|
||||||
|
NM_PRINT_FMT_QUOTED (extack_msg, " \"", extack_msg, "\"", ""),
|
||||||
nlmsg_hdr (msg)->nlmsg_seq);
|
nlmsg_hdr (msg)->nlmsg_seq);
|
||||||
seq_result = -errsv;
|
seq_result = -errsv;
|
||||||
} else
|
} else
|
||||||
@@ -6948,6 +6967,10 @@ constructed (GObject *_object)
|
|||||||
nle = nl_socket_set_buffer_size (priv->nlh, 8*1024*1024, 0);
|
nle = nl_socket_set_buffer_size (priv->nlh, 8*1024*1024, 0);
|
||||||
g_assert (!nle);
|
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.
|
/* explicitly set the msg buffer size and disable MSG_PEEK.
|
||||||
* If we later encounter NLE_MSG_TRUNC, we will adjust the buffer size. */
|
* If we later encounter NLE_MSG_TRUNC, we will adjust the buffer size. */
|
||||||
nl_socket_disable_msg_peek (priv->nlh);
|
nl_socket_disable_msg_peek (priv->nlh);
|
||||||
|
@@ -38,6 +38,10 @@
|
|||||||
#define NL_MSG_PEEK_EXPLICIT (1<<4)
|
#define NL_MSG_PEEK_EXPLICIT (1<<4)
|
||||||
#define NL_NO_AUTO_ACK (1<<5)
|
#define NL_NO_AUTO_ACK (1<<5)
|
||||||
|
|
||||||
|
#ifndef NETLINK_EXT_ACK
|
||||||
|
#define NETLINK_EXT_ACK 11
|
||||||
|
#endif
|
||||||
|
|
||||||
#define NL_MSG_CRED_PRESENT 1
|
#define NL_MSG_CRED_PRESENT 1
|
||||||
|
|
||||||
struct nl_msg {
|
struct nl_msg {
|
||||||
@@ -933,6 +937,22 @@ nl_socket_add_memberships (struct nl_sock *sk, int group, ...)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
nl_socket_set_ext_ack (struct nl_sock *sk, gboolean enable)
|
||||||
|
{
|
||||||
|
int err, val;
|
||||||
|
|
||||||
|
if (sk->s_fd == -1)
|
||||||
|
return -NLE_BAD_SOCK;
|
||||||
|
|
||||||
|
val = !!enable;
|
||||||
|
err = setsockopt (sk->s_fd, SOL_NETLINK, NETLINK_EXT_ACK, &val, sizeof (val));
|
||||||
|
if (err < 0)
|
||||||
|
return -nl_syserr2nlerr (errno);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void nl_socket_disable_msg_peek (struct nl_sock *sk)
|
void nl_socket_disable_msg_peek (struct nl_sock *sk)
|
||||||
{
|
{
|
||||||
sk->s_flags |= NL_MSG_PEEK_EXPLICIT;
|
sk->s_flags |= NL_MSG_PEEK_EXPLICIT;
|
||||||
|
@@ -26,7 +26,6 @@
|
|||||||
#include <linux/genetlink.h>
|
#include <linux/genetlink.h>
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
#define _NLE_BASE 100000
|
#define _NLE_BASE 100000
|
||||||
#define NLE_UNSPEC (_NLE_BASE + 0)
|
#define NLE_UNSPEC (_NLE_BASE + 0)
|
||||||
#define NLE_BUG (_NLE_BASE + 1)
|
#define NLE_BUG (_NLE_BASE + 1)
|
||||||
@@ -42,6 +41,16 @@
|
|||||||
|
|
||||||
#define _NLE_BASE_END (_NLE_BASE + 11)
|
#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
|
static inline int
|
||||||
nl_errno (int err)
|
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,
|
int nl_wait_for_ack (struct nl_sock *sk,
|
||||||
const struct nl_cb *cb);
|
const struct nl_cb *cb);
|
||||||
|
|
||||||
|
int nl_socket_set_ext_ack (struct nl_sock *sk, gboolean enable);
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
#endif /* __NM_NETLINK_H__ */
|
#endif /* __NM_NETLINK_H__ */
|
||||||
|
Reference in New Issue
Block a user