Parse netlink ext attribute to get the error message returned by
the card.
Signed-off-by: Eric Leblond
---
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
#include "bpf.h"
#include "libbpf.h"
+#include "nlattr.h"
#include
#include
#include
@@ -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(, 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,
+ , sizeof(one)) < 0) {
+ /* debug/verbose message that it is not supported */
+ fprintf(stderr, "Netlink error reporting not supported\n");
+ }
+
if (bind(sock, (struct sockaddr *), 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 ..962de14f74e3
--- /dev/null
+++ b/tools/lib/bpf/nlattr.c
@@ -0,0 +1,188 @@
+
+/*
+ * NETLINK Netlink attributes
+ *
+ * Authors:Thomas Graf
+ * Alexey Kuznetsov
+ */
+
+#include
+#include "nlattr.h"
+#include
+#include
+#include
+
+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 = [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