From: Eric Leblond <eric@regit.org>
To: netdev@vger.kernel.org, daniel@iogearbox.net
Cc: linux-kernel@vger.kernel.org, ast@kernel.org,
Eric Leblond <eric@regit.org>
Subject: [PATCH bpf-next 2/3] libbpf: add error reporting in XDP
Date: Mon, 25 Dec 2017 23:13:24 +0100 [thread overview]
Message-ID: <20171225221325.9680-3-eric@regit.org> (raw)
In-Reply-To: <20171225221325.9680-1-eric@regit.org>
Parse netlink ext attribute to get the error message returned by
the card.
Signed-off-by: Eric Leblond <eric@regit.org>
---
tools/lib/bpf/Build | 2 +-
tools/lib/bpf/bpf.c | 9 +++
tools/lib/bpf/nlattr.c | 188 +++++++++++++++++++++++++++++++++++++++++++++++++
tools/lib/bpf/nlattr.h | 164 ++++++++++++++++++++++++++++++++++++++++++
4 files changed, 362 insertions(+), 1 deletion(-)
create mode 100644 tools/lib/bpf/nlattr.c
create mode 100644 tools/lib/bpf/nlattr.h
diff --git a/tools/lib/bpf/Build b/tools/lib/bpf/Build
index d8749756352d..64c679d67109 100644
--- a/tools/lib/bpf/Build
+++ b/tools/lib/bpf/Build
@@ -1 +1 @@
-libbpf-y := libbpf.o bpf.o
+libbpf-y := libbpf.o bpf.o nlattr.o
diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index 1e3cfe6b9fce..cfd30a0cbce4 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -26,6 +26,7 @@
#include <linux/bpf.h>
#include "bpf.h"
#include "libbpf.h"
+#include "nlattr.h"
#include <linux/rtnetlink.h>
#include <sys/socket.h>
#include <errno.h>
@@ -436,6 +437,7 @@ int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags)
struct nlmsghdr *nh;
struct nlmsgerr *err;
socklen_t addrlen;
+ int one;
memset(&sa, 0, sizeof(sa));
sa.nl_family = AF_NETLINK;
@@ -445,6 +447,12 @@ int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags)
return -errno;
}
+ if (setsockopt(sock, SOL_NETLINK, NETLINK_EXT_ACK,
+ &one, sizeof(one)) < 0) {
+ /* debug/verbose message that it is not supported */
+ fprintf(stderr, "Netlink error reporting not supported\n");
+ }
+
if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
ret = -errno;
goto cleanup;
@@ -521,6 +529,7 @@ int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags)
if (!err->error)
continue;
ret = err->error;
+ nla_dump_errormsg(nh);
goto cleanup;
case NLMSG_DONE:
break;
diff --git a/tools/lib/bpf/nlattr.c b/tools/lib/bpf/nlattr.c
new file mode 100644
index 000000000000..962de14f74e3
--- /dev/null
+++ b/tools/lib/bpf/nlattr.c
@@ -0,0 +1,188 @@
+
+/*
+ * NETLINK Netlink attributes
+ *
+ * Authors: Thomas Graf <tgraf@suug.ch>
+ * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
+ */
+
+#include <errno.h>
+#include "nlattr.h"
+#include <linux/rtnetlink.h>
+#include <string.h>
+#include <stdio.h>
+
+static const __u8 nla_attr_minlen[NLA_TYPE_MAX+1] = {
+ [NLA_U8] = sizeof(__u8),
+ [NLA_U16] = sizeof(__u16),
+ [NLA_U32] = sizeof(__u32),
+ [NLA_U64] = sizeof(__u64),
+ [NLA_MSECS] = sizeof(__u64),
+ [NLA_NESTED] = NLA_HDRLEN,
+ [NLA_S8] = sizeof(__s8),
+ [NLA_S16] = sizeof(__s16),
+ [NLA_S32] = sizeof(__s32),
+ [NLA_S64] = sizeof(__s64),
+};
+
+static int validate_nla(const struct nlattr *nla, int maxtype,
+ const struct nla_policy *policy)
+{
+ const struct nla_policy *pt;
+ int minlen = 0, attrlen = nla_len(nla), type = nla_type(nla);
+
+ if (type <= 0 || type > maxtype)
+ return 0;
+
+ pt = &policy[type];
+
+ if (pt->type > NLA_TYPE_MAX)
+ return -EINVAL;
+
+ switch (pt->type) {
+ case NLA_FLAG:
+ if (attrlen > 0)
+ return -ERANGE;
+ break;
+
+ case NLA_NUL_STRING:
+ if (pt->len)
+ minlen = min(attrlen, pt->len + 1);
+ else
+ minlen = attrlen;
+
+ if (!minlen || memchr(nla_data(nla), '\0', minlen) == NULL)
+ return -EINVAL;
+ /* fall through */
+
+ case NLA_STRING:
+ if (attrlen < 1)
+ return -ERANGE;
+
+ if (pt->len) {
+ char *buf = nla_data(nla);
+
+ if (buf[attrlen - 1] == '\0')
+ attrlen--;
+
+ if (attrlen > pt->len)
+ return -ERANGE;
+ }
+ break;
+
+ case NLA_BINARY:
+ if (pt->len && attrlen > pt->len)
+ return -ERANGE;
+ break;
+
+ case NLA_NESTED_COMPAT:
+ if (attrlen < pt->len)
+ return -ERANGE;
+ if (attrlen < NLA_ALIGN(pt->len))
+ break;
+ if (attrlen < NLA_ALIGN(pt->len) + NLA_HDRLEN)
+ return -ERANGE;
+ nla = nla_data(nla) + NLA_ALIGN(pt->len);
+ if (attrlen < NLA_ALIGN(pt->len) + NLA_HDRLEN + nla_len(nla))
+ return -ERANGE;
+ break;
+ case NLA_NESTED:
+ /* a nested attributes is allowed to be empty; if its not,
+ * it must have a size of at least NLA_HDRLEN.
+ */
+ if (attrlen == 0)
+ break;
+ default:
+ if (pt->len)
+ minlen = pt->len;
+ else if (pt->type != NLA_UNSPEC)
+ minlen = nla_attr_minlen[pt->type];
+
+ if (attrlen < minlen)
+ return -ERANGE;
+ }
+
+ return 0;
+}
+
+/**
+ * nla_parse - Parse a stream of attributes into a tb buffer
+ * @tb: destination array with maxtype+1 elements
+ * @maxtype: maximum attribute type to be expected
+ * @head: head of attribute stream
+ * @len: length of attribute stream
+ * @policy: validation policy
+ *
+ * Parses a stream of attributes and stores a pointer to each attribute in
+ * the tb array accessible via the attribute type. Attributes with a type
+ * exceeding maxtype will be silently ignored for backwards compatibility
+ * reasons. policy may be set to NULL if no validation is required.
+ *
+ * Returns 0 on success or a negative error code.
+ */
+static int nla_parse(struct nlattr **tb, int maxtype, const struct nlattr *head,
+ int len, const struct nla_policy *policy)
+{
+ const struct nlattr *nla;
+ int rem, err;
+
+ memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
+
+ nla_for_each_attr(nla, head, len, rem) {
+ __u16 type = nla_type(nla);
+
+ if (type > 0 && type <= maxtype) {
+ if (policy) {
+ err = validate_nla(nla, maxtype, policy);
+ if (err < 0)
+ goto errout;
+ }
+
+ tb[type] = (struct nlattr *)nla;
+ }
+ }
+
+ err = 0;
+errout:
+ return err;
+}
+
+/* dump netlink extended ack error message */
+int nla_dump_errormsg(struct nlmsghdr *nlh)
+{
+ const struct nla_policy extack_policy[NLMSGERR_ATTR_MAX + 1] = {
+ [NLMSGERR_ATTR_MSG] = { .type = NLA_STRING },
+ [NLMSGERR_ATTR_OFFS] = { .type = NLA_U32 },
+ };
+ struct nlattr *tb[NLMSGERR_ATTR_MAX + 1], *attr;
+ struct nlmsgerr *err;
+ char *errmsg = NULL;
+ int hlen, alen;
+
+ /* no TLVs, nothing to do here */
+ if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS))
+ return 0;
+
+ err = (struct nlmsgerr *)NLMSG_DATA(nlh);
+ hlen = sizeof(*err);
+
+ /* if NLM_F_CAPPED is set then the inner err msg was capped */
+ if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
+ hlen += nlmsg_len(&err->msg);
+
+ attr = (struct nlattr *) ((void *) err + hlen);
+ alen = nlh->nlmsg_len - hlen;
+
+ if (nla_parse(tb, NLMSGERR_ATTR_MAX, attr, alen, extack_policy) != 0) {
+ fprintf(stderr,
+ "Failed to parse extended error attributes\n");
+ return 0;
+ }
+
+ if (tb[NLMSGERR_ATTR_MSG])
+ errmsg = (char *) nla_data(tb[NLMSGERR_ATTR_MSG]);
+
+ fprintf(stderr, "Kernel error message: %s\n", errmsg);
+
+ return 0;
+}
diff --git a/tools/lib/bpf/nlattr.h b/tools/lib/bpf/nlattr.h
new file mode 100644
index 000000000000..b95f3e64c14d
--- /dev/null
+++ b/tools/lib/bpf/nlattr.h
@@ -0,0 +1,164 @@
+#ifndef __NLATTR_H
+#define __NLATTR_H
+
+#include <linux/netlink.h>
+
+/**
+ * Standard attribute types to specify validation policy
+ */
+enum {
+ NLA_UNSPEC,
+ NLA_U8,
+ NLA_U16,
+ NLA_U32,
+ NLA_U64,
+ NLA_STRING,
+ NLA_FLAG,
+ NLA_MSECS,
+ NLA_NESTED,
+ NLA_NESTED_COMPAT,
+ NLA_NUL_STRING,
+ NLA_BINARY,
+ NLA_S8,
+ NLA_S16,
+ NLA_S32,
+ NLA_S64,
+ __NLA_TYPE_MAX,
+};
+
+#define NLA_TYPE_MAX (__NLA_TYPE_MAX - 1)
+
+/**
+ * nla_type - attribute type
+ * @nla: netlink attribute
+ */
+static inline int nla_type(const struct nlattr *nla)
+{
+ return nla->nla_type & NLA_TYPE_MASK;
+}
+
+/**
+ * nla_len - length of payload
+ * @nla: netlink attribute
+ */
+static inline int nla_len(const struct nlattr *nla)
+{
+ return nla->nla_len - NLA_HDRLEN;
+}
+
+/**
+ * struct nla_policy - attribute validation policy
+ * @type: Type of attribute or NLA_UNSPEC
+ * @len: Type specific length of payload
+ *
+ * Policies are defined as arrays of this struct, the array must be
+ * accessible by attribute type up to the highest identifier to be expected.
+ *
+ * Meaning of `len' field:
+ * NLA_STRING Maximum length of string
+ * NLA_NUL_STRING Maximum length of string (excluding NUL)
+ * NLA_FLAG Unused
+ * NLA_BINARY Maximum length of attribute payload
+ * NLA_NESTED Don't use `len' field -- length verification is
+ * done by checking len of nested header (or empty)
+ * NLA_NESTED_COMPAT Minimum length of structure payload
+ * NLA_U8, NLA_U16,
+ * NLA_U32, NLA_U64,
+ * NLA_S8, NLA_S16,
+ * NLA_S32, NLA_S64,
+ * NLA_MSECS Leaving the length field zero will verify the
+ * given type fits, using it verifies minimum length
+ * just like "All other"
+ * All other Minimum length of attribute payload
+ *
+ * Example:
+ * static const struct nla_policy my_policy[ATTR_MAX+1] = {
+ * [ATTR_FOO] = { .type = NLA_U16 },
+ * [ATTR_BAR] = { .type = NLA_STRING, .len = BARSIZ },
+ * [ATTR_BAZ] = { .len = sizeof(struct mystruct) },
+ * };
+ */
+struct nla_policy {
+ __u16 type;
+ __u16 len;
+};
+
+/**
+ * nla_ok - check if the netlink attribute fits into the remaining bytes
+ * @nla: netlink attribute
+ * @remaining: number of bytes remaining in attribute stream
+ */
+static inline int nla_ok(const struct nlattr *nla, int remaining)
+{
+ return remaining >= (int) sizeof(*nla) &&
+ nla->nla_len >= sizeof(*nla) &&
+ nla->nla_len <= remaining;
+}
+
+/**
+ * nla_next - next netlink attribute in attribute stream
+ * @nla: netlink attribute
+ * @remaining: number of bytes remaining in attribute stream
+ *
+ * Returns the next netlink attribute in the attribute stream and
+ * decrements remaining by the size of the current attribute.
+ */
+static inline struct nlattr *nla_next(const struct nlattr *nla, int *remaining)
+{
+ unsigned int totlen = NLA_ALIGN(nla->nla_len);
+
+ *remaining -= totlen;
+ return (struct nlattr *) ((char *) nla + totlen);
+}
+
+/**
+ * nla_for_each_attr - iterate over a stream of attributes
+ * @pos: loop counter, set to current attribute
+ * @head: head of attribute stream
+ * @len: length of attribute stream
+ * @rem: initialized to len, holds bytes currently remaining in stream
+ */
+#define nla_for_each_attr(pos, head, len, rem) \
+ for (pos = head, rem = len; \
+ nla_ok(pos, rem); \
+ pos = nla_next(pos, &(rem)))
+
+/**
+ * nla_data - head of payload
+ * @nla: netlink attribute
+ */
+static inline void *nla_data(const struct nlattr *nla)
+{
+ return (char *) nla + NLA_HDRLEN;
+}
+
+/**
+ * nla_get_u32 - return payload of u32 attribute
+ * @nla: u32 netlink attribute
+ */
+static inline __u32 nla_get_u32(const struct nlattr *nla)
+{
+ return *(__u32 *) nla_data(nla);
+}
+
+/**
+ * nla_get_u16 - return payload of u16 attribute
+ * @nla: u16 netlink attribute
+ */
+static inline __u16 nla_get_u16(const struct nlattr *nla)
+{
+ return *(__u16 *) nla_data(nla);
+}
+
+/**
+ * nlmsg_len - length of message payload
+ * @nlh: netlink message header
+ */
+static inline int nlmsg_len(const struct nlmsghdr *nlh)
+{
+ return nlh->nlmsg_len - NLMSG_HDRLEN;
+}
+
+int nla_dump_errormsg(struct nlmsghdr *nlh);
+
+#endif /* __NLATTR_H */
--
2.15.1
next prev parent reply other threads:[~2017-12-25 22:14 UTC|newest]
Thread overview: 63+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-12-25 22:13 [PATCH bpf-next 0/3] add XDP loading support to libbpf Eric Leblond
2017-12-25 22:13 ` [PATCH bpf-next 1/3] libbpf: add function to setup XDP Eric Leblond
2017-12-25 22:13 ` Eric Leblond [this message]
2017-12-27 2:27 ` [PATCH bpf-next 2/3] libbpf: add error reporting in XDP Alexei Starovoitov
2017-12-27 18:02 ` [PATCH bpf-next v2 0/4] libbpf: add function to setup XDP Eric Leblond
2017-12-27 18:02 ` [PATCH 1/4] " Eric Leblond
2017-12-27 18:57 ` Alexei Starovoitov
2017-12-28 0:59 ` Toshiaki Makita
2017-12-27 18:02 ` [PATCH 2/4] libbpf: add error reporting in XDP Eric Leblond
2017-12-27 18:57 ` Alexei Starovoitov
2017-12-27 18:02 ` [PATCH 3/4] libbpf: break loop earlier Eric Leblond
2017-12-27 19:00 ` Alexei Starovoitov
2017-12-27 20:30 ` Eric Leblond
2017-12-27 23:05 ` Daniel Borkmann
2017-12-28 8:04 ` [PATCH bpf-next v3 0/3] libbpf: add XDP setup support Eric Leblond
2017-12-28 8:04 ` [PATCH bpf-next v3 1/3] libbpf: add function to setup XDP Eric Leblond
2017-12-28 8:18 ` Toshiaki Makita
2017-12-30 20:41 ` [PATCH bpf-next v4 0/3] " Eric Leblond
2017-12-30 20:41 ` [PATCH bpf-next v4 1/3] " Eric Leblond
2018-01-03 23:59 ` Eric Leblond
2018-01-04 8:21 ` [PATCH bpf-next v5 1/4] " Eric Leblond
2018-01-04 8:21 ` [PATCH bpf-next v5 2/4] libbpf: add error reporting in XDP Eric Leblond
2018-01-06 21:16 ` Daniel Borkmann
2018-01-18 23:35 ` Eric Leblond
2018-01-18 23:43 ` [PATCH bpf-next 0/4] libbpf: add XDP binding support Eric Leblond
2018-01-18 23:43 ` [PATCH bpf-next v6 1/4] libbpf: add function to setup XDP Eric Leblond
2018-01-18 23:43 ` [PATCH bpf-next v6 2/4] libbpf: add error reporting in XDP Eric Leblond
2018-01-18 23:43 ` [PATCH bpf-next v6 3/4] libbpf: add missing SPDX-License-Identifier Eric Leblond
2018-01-18 23:43 ` [PATCH bpf-next v6 4/4] samples/bpf: use bpf_set_link_xdp_fd Eric Leblond
2018-01-20 2:00 ` [PATCH bpf-next 0/4] libbpf: add XDP binding support Daniel Borkmann
2018-01-20 2:27 ` Alexei Starovoitov
2018-01-20 8:21 ` Daniel Borkmann
2018-01-25 0:05 ` [PATCH bpf-next v7 0/5] libbpf: add XDP setup support Eric Leblond
2018-01-25 0:05 ` [PATCH bpf-next v7 1/5] tools: import netlink header in tools uapi Eric Leblond
2018-01-25 0:05 ` [PATCH bpf-next v7 2/5] libbpf: add function to setup XDP Eric Leblond
2018-01-27 1:23 ` Daniel Borkmann
2018-01-27 10:22 ` Eric Leblond
2018-01-25 0:05 ` [PATCH bpf-next v7 3/5] libbpf: add error reporting in XDP Eric Leblond
2018-01-27 1:28 ` Daniel Borkmann
2018-01-27 10:32 ` Eric Leblond
2018-01-30 10:58 ` Daniel Borkmann
2018-01-30 20:50 ` [PATCH bpf-next v8 0/5] libbpf: add XDP binding support Eric Leblond
2018-01-31 16:53 ` Daniel Borkmann
2018-02-03 2:01 ` Alexei Starovoitov
2018-01-30 20:55 ` [PATCH bpf-next v8 1/5] tools: add netlink.h and if_link.h in tools uapi Eric Leblond
2018-01-30 20:55 ` [PATCH bpf-next v8 2/5] libbpf: add function to setup XDP Eric Leblond
2018-01-30 20:55 ` [PATCH bpf-next v8 3/5] libbpf: add error reporting in XDP Eric Leblond
2018-01-30 20:55 ` [PATCH bpf-next v8 4/5] libbpf: add missing SPDX-License-Identifier Eric Leblond
2018-01-30 20:55 ` [PATCH bpf-next v8 5/5] samples/bpf: use bpf_set_link_xdp_fd Eric Leblond
2018-01-25 0:05 ` [PATCH bpf-next v7 4/5] libbpf: add missing SPDX-License-Identifier Eric Leblond
2018-01-25 0:05 ` [PATCH bpf-next v7 5/5] samples/bpf: use bpf_set_link_xdp_fd Eric Leblond
2018-01-04 8:21 ` [PATCH bpf-next v5 3/4] libbpf: add missing SPDX-License-Identifier Eric Leblond
2018-01-04 9:49 ` Philippe Ombredanne
2018-01-04 8:21 ` [PATCH bpf-next v5 4/4] samples/bpf: use bpf_set_link_xdp_fd Eric Leblond
2017-12-30 20:41 ` [PATCH bpf-next v4 2/3] libbpf: add error reporting in XDP Eric Leblond
2017-12-31 11:20 ` Philippe Ombredanne
2017-12-30 20:41 ` [PATCH bpf-next v4 3/3] libbpf: add missing SPDX-License-Identifier Eric Leblond
2017-12-28 8:04 ` [PATCH bpf-next v3 2/3] libbpf: add error reporting in XDP Eric Leblond
2017-12-28 8:04 ` [PATCH bpf-next v3 3/3] libbpf: add missing SPDX-License-Identifier Eric Leblond
2017-12-29 12:35 ` Philippe Ombredanne
2017-12-27 18:02 ` [PATCH 4/4] " Eric Leblond
2017-12-27 19:01 ` Alexei Starovoitov
2017-12-25 22:13 ` [PATCH bpf-next 3/3] libbpf: break loop earlier Eric Leblond
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20171225221325.9680-3-eric@regit.org \
--to=eric@regit.org \
--cc=ast@kernel.org \
--cc=daniel@iogearbox.net \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.