aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Leblond <eric@regit.org>2018-01-30 15:55:02 -0500
committerAlexei Starovoitov <ast@kernel.org>2018-02-02 20:53:48 -0500
commitbbf48c18ee0cd18b53712aa09aefa29b64b3976e (patch)
treeb8cb67b2922bdd88e43371158a0094fcf09129f3
parent949abbe88436c000cc63fce2bdfeb48b7d06a7df (diff)
libbpf: add error reporting in XDP
Parse netlink ext attribute to get the error message returned by the card. Code is partially take from libnl. We add netlink.h to the uapi include of tools. And we need to avoid include of userspace netlink header to have a successful build of sample so nlattr.h has a define to avoid the inclusion. Using a direct define could have been an issue as NLMSGERR_ATTR_MAX can change in the future. We also define SOL_NETLINK if not defined to avoid to have to copy socket.h for a fixed value. Signed-off-by: Eric Leblond <eric@regit.org> Acked-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
-rw-r--r--samples/bpf/Makefile2
-rw-r--r--tools/lib/bpf/Build2
-rw-r--r--tools/lib/bpf/bpf.c11
-rw-r--r--tools/lib/bpf/nlattr.c187
-rw-r--r--tools/lib/bpf/nlattr.h72
5 files changed, 272 insertions, 2 deletions
diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index 64335bb94f9f..ec3fc8d88e87 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -45,7 +45,7 @@ hostprogs-y += xdp_rxq_info
45hostprogs-y += syscall_tp 45hostprogs-y += syscall_tp
46 46
47# Libbpf dependencies 47# Libbpf dependencies
48LIBBPF := ../../tools/lib/bpf/bpf.o 48LIBBPF := ../../tools/lib/bpf/bpf.o ../../tools/lib/bpf/nlattr.o
49CGROUP_HELPERS := ../../tools/testing/selftests/bpf/cgroup_helpers.o 49CGROUP_HELPERS := ../../tools/testing/selftests/bpf/cgroup_helpers.o
50 50
51test_lru_dist-objs := test_lru_dist.o $(LIBBPF) 51test_lru_dist-objs := test_lru_dist.o $(LIBBPF)
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 bf2772566240..9c88f6e4156d 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -32,6 +32,10 @@
32#include <sys/socket.h> 32#include <sys/socket.h>
33#include <errno.h> 33#include <errno.h>
34 34
35#ifndef SOL_NETLINK
36#define SOL_NETLINK 270
37#endif
38
35/* 39/*
36 * When building perf, unistd.h is overridden. __NR_bpf is 40 * When building perf, unistd.h is overridden. __NR_bpf is
37 * required to be defined explicitly. 41 * required to be defined explicitly.
@@ -436,6 +440,7 @@ int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags)
436 struct nlmsghdr *nh; 440 struct nlmsghdr *nh;
437 struct nlmsgerr *err; 441 struct nlmsgerr *err;
438 socklen_t addrlen; 442 socklen_t addrlen;
443 int one = 1;
439 444
440 memset(&sa, 0, sizeof(sa)); 445 memset(&sa, 0, sizeof(sa));
441 sa.nl_family = AF_NETLINK; 446 sa.nl_family = AF_NETLINK;
@@ -445,6 +450,11 @@ int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags)
445 return -errno; 450 return -errno;
446 } 451 }
447 452
453 if (setsockopt(sock, SOL_NETLINK, NETLINK_EXT_ACK,
454 &one, sizeof(one)) < 0) {
455 fprintf(stderr, "Netlink error reporting not supported\n");
456 }
457
448 if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) { 458 if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
449 ret = -errno; 459 ret = -errno;
450 goto cleanup; 460 goto cleanup;
@@ -521,6 +531,7 @@ int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags)
521 if (!err->error) 531 if (!err->error)
522 continue; 532 continue;
523 ret = err->error; 533 ret = err->error;
534 nla_dump_errormsg(nh);
524 goto cleanup; 535 goto cleanup;
525 case NLMSG_DONE: 536 case NLMSG_DONE:
526 break; 537 break;
diff --git a/tools/lib/bpf/nlattr.c b/tools/lib/bpf/nlattr.c
new file mode 100644
index 000000000000..4719434278b2
--- /dev/null
+++ b/tools/lib/bpf/nlattr.c
@@ -0,0 +1,187 @@
1// SPDX-License-Identifier: LGPL-2.1
2
3/*
4 * NETLINK Netlink attributes
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation version 2.1
9 * of the License.
10 *
11 * Copyright (c) 2003-2013 Thomas Graf <tgraf@suug.ch>
12 */
13
14#include <errno.h>
15#include "nlattr.h"
16#include <linux/rtnetlink.h>
17#include <string.h>
18#include <stdio.h>
19
20static uint16_t nla_attr_minlen[NLA_TYPE_MAX+1] = {
21 [NLA_U8] = sizeof(uint8_t),
22 [NLA_U16] = sizeof(uint16_t),
23 [NLA_U32] = sizeof(uint32_t),
24 [NLA_U64] = sizeof(uint64_t),
25 [NLA_STRING] = 1,
26 [NLA_FLAG] = 0,
27};
28
29static int nla_len(const struct nlattr *nla)
30{
31 return nla->nla_len - NLA_HDRLEN;
32}
33
34static struct nlattr *nla_next(const struct nlattr *nla, int *remaining)
35{
36 int totlen = NLA_ALIGN(nla->nla_len);
37
38 *remaining -= totlen;
39 return (struct nlattr *) ((char *) nla + totlen);
40}
41
42static int nla_ok(const struct nlattr *nla, int remaining)
43{
44 return remaining >= sizeof(*nla) &&
45 nla->nla_len >= sizeof(*nla) &&
46 nla->nla_len <= remaining;
47}
48
49static void *nla_data(const struct nlattr *nla)
50{
51 return (char *) nla + NLA_HDRLEN;
52}
53
54static int nla_type(const struct nlattr *nla)
55{
56 return nla->nla_type & NLA_TYPE_MASK;
57}
58
59static int validate_nla(struct nlattr *nla, int maxtype,
60 struct nla_policy *policy)
61{
62 struct nla_policy *pt;
63 unsigned int minlen = 0;
64 int type = nla_type(nla);
65
66 if (type < 0 || type > maxtype)
67 return 0;
68
69 pt = &policy[type];
70
71 if (pt->type > NLA_TYPE_MAX)
72 return 0;
73
74 if (pt->minlen)
75 minlen = pt->minlen;
76 else if (pt->type != NLA_UNSPEC)
77 minlen = nla_attr_minlen[pt->type];
78
79 if (nla_len(nla) < minlen)
80 return -1;
81
82 if (pt->maxlen && nla_len(nla) > pt->maxlen)
83 return -1;
84
85 if (pt->type == NLA_STRING) {
86 char *data = nla_data(nla);
87 if (data[nla_len(nla) - 1] != '\0')
88 return -1;
89 }
90
91 return 0;
92}
93
94static inline int nlmsg_len(const struct nlmsghdr *nlh)
95{
96 return nlh->nlmsg_len - NLMSG_HDRLEN;
97}
98
99/**
100 * Create attribute index based on a stream of attributes.
101 * @arg tb Index array to be filled (maxtype+1 elements).
102 * @arg maxtype Maximum attribute type expected and accepted.
103 * @arg head Head of attribute stream.
104 * @arg len Length of attribute stream.
105 * @arg policy Attribute validation policy.
106 *
107 * Iterates over the stream of attributes and stores a pointer to each
108 * attribute in the index array using the attribute type as index to
109 * the array. Attribute with a type greater than the maximum type
110 * specified will be silently ignored in order to maintain backwards
111 * compatibility. If \a policy is not NULL, the attribute will be
112 * validated using the specified policy.
113 *
114 * @see nla_validate
115 * @return 0 on success or a negative error code.
116 */
117static int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len,
118 struct nla_policy *policy)
119{
120 struct nlattr *nla;
121 int rem, err;
122
123 memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
124
125 nla_for_each_attr(nla, head, len, rem) {
126 int type = nla_type(nla);
127
128 if (type > maxtype)
129 continue;
130
131 if (policy) {
132 err = validate_nla(nla, maxtype, policy);
133 if (err < 0)
134 goto errout;
135 }
136
137 if (tb[type])
138 fprintf(stderr, "Attribute of type %#x found multiple times in message, "
139 "previous attribute is being ignored.\n", type);
140
141 tb[type] = nla;
142 }
143
144 err = 0;
145errout:
146 return err;
147}
148
149/* dump netlink extended ack error message */
150int nla_dump_errormsg(struct nlmsghdr *nlh)
151{
152 struct nla_policy extack_policy[NLMSGERR_ATTR_MAX + 1] = {
153 [NLMSGERR_ATTR_MSG] = { .type = NLA_STRING },
154 [NLMSGERR_ATTR_OFFS] = { .type = NLA_U32 },
155 };
156 struct nlattr *tb[NLMSGERR_ATTR_MAX + 1], *attr;
157 struct nlmsgerr *err;
158 char *errmsg = NULL;
159 int hlen, alen;
160
161 /* no TLVs, nothing to do here */
162 if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS))
163 return 0;
164
165 err = (struct nlmsgerr *)NLMSG_DATA(nlh);
166 hlen = sizeof(*err);
167
168 /* if NLM_F_CAPPED is set then the inner err msg was capped */
169 if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
170 hlen += nlmsg_len(&err->msg);
171
172 attr = (struct nlattr *) ((void *) err + hlen);
173 alen = nlh->nlmsg_len - hlen;
174
175 if (nla_parse(tb, NLMSGERR_ATTR_MAX, attr, alen, extack_policy) != 0) {
176 fprintf(stderr,
177 "Failed to parse extended error attributes\n");
178 return 0;
179 }
180
181 if (tb[NLMSGERR_ATTR_MSG])
182 errmsg = (char *) nla_data(tb[NLMSGERR_ATTR_MSG]);
183
184 fprintf(stderr, "Kernel error message: %s\n", errmsg);
185
186 return 0;
187}
diff --git a/tools/lib/bpf/nlattr.h b/tools/lib/bpf/nlattr.h
new file mode 100644
index 000000000000..931a71f68f93
--- /dev/null
+++ b/tools/lib/bpf/nlattr.h
@@ -0,0 +1,72 @@
1/* SPDX-License-Identifier: LGPL-2.1 */
2
3/*
4 * NETLINK Netlink attributes
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation version 2.1
9 * of the License.
10 *
11 * Copyright (c) 2003-2013 Thomas Graf <tgraf@suug.ch>
12 */
13
14#ifndef __NLATTR_H
15#define __NLATTR_H
16
17#include <stdint.h>
18#include <linux/netlink.h>
19/* avoid multiple definition of netlink features */
20#define __LINUX_NETLINK_H
21
22/**
23 * Standard attribute types to specify validation policy
24 */
25enum {
26 NLA_UNSPEC, /**< Unspecified type, binary data chunk */
27 NLA_U8, /**< 8 bit integer */
28 NLA_U16, /**< 16 bit integer */
29 NLA_U32, /**< 32 bit integer */
30 NLA_U64, /**< 64 bit integer */
31 NLA_STRING, /**< NUL terminated character string */
32 NLA_FLAG, /**< Flag */
33 NLA_MSECS, /**< Micro seconds (64bit) */
34 NLA_NESTED, /**< Nested attributes */
35 __NLA_TYPE_MAX,
36};
37
38#define NLA_TYPE_MAX (__NLA_TYPE_MAX - 1)
39
40/**
41 * @ingroup attr
42 * Attribute validation policy.
43 *
44 * See section @core_doc{core_attr_parse,Attribute Parsing} for more details.
45 */
46struct nla_policy {
47 /** Type of attribute or NLA_UNSPEC */
48 uint16_t type;
49
50 /** Minimal length of payload required */
51 uint16_t minlen;
52
53 /** Maximal length of payload allowed */
54 uint16_t maxlen;
55};
56
57/**
58 * @ingroup attr
59 * Iterate over a stream of attributes
60 * @arg pos loop counter, set to current attribute
61 * @arg head head of attribute stream
62 * @arg len length of attribute stream
63 * @arg rem initialized to len, holds bytes currently remaining in stream
64 */
65#define nla_for_each_attr(pos, head, len, rem) \
66 for (pos = head, rem = len; \
67 nla_ok(pos, rem); \
68 pos = nla_next(pos, &(rem)))
69
70int nla_dump_errormsg(struct nlmsghdr *nlh);
71
72#endif /* __NLATTR_H */