Skip to content

Commit 472aeb3

Browse files
author
Alexei Starovoitov
committed
Merge branch 'map-pinning'
Toke Høiland-Jørgensen says: ==================== This series fixes a few bugs in libbpf that I discovered while playing around with the new auto-pinning code, and writing the first utility in xdp-tools[0]: - If object loading fails, libbpf does not clean up the pinnings created by the auto-pinning mechanism. - EPERM is not propagated to the caller on program load - Netlink functions write error messages directly to stderr In addition, libbpf currently only has a somewhat limited getter function for XDP link info, which makes it impossible to discover whether an attached program is in SKB mode or not. So the last patch in the series adds a new getter for XDP link info which returns all the information returned via netlink (and which can be extended later). Finally, add a getter for BPF program size, which can be used by the caller to estimate the amount of locked memory needed to load a program. A selftest is added for the pinning change, while the other features were tested in the xdp-filter tool from the xdp-tools repo. The 'new-libbpf-features' branch contains the commits that make use of the new XDP getter and the corrected EPERM error code. [0] https://github.com/xdp-project/xdp-tools Changelog: v4: - Don't do any size checks on struct xdp_info, just copy (and/or zero) whatever size the caller supplied. v3: - Pass through all kernel error codes on program load (instead of just EPERM). - No new bpf_object__unload() variant, just do the loop at the caller - Don't reject struct xdp_info sizes that are bigger than what we expect. - Add a comment noting that bpf_program__size() returns the size in bytes v2: - Keep function names in libbpf.map sorted properly ==================== Signed-off-by: Alexei Starovoitov <[email protected]>
2 parents 451d1dc + 1a734ef commit 472aeb3

File tree

7 files changed

+120
-55
lines changed

7 files changed

+120
-55
lines changed

tools/lib/bpf/libbpf.c

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ struct bpf_map {
229229
enum libbpf_map_type libbpf_type;
230230
char *pin_path;
231231
bool pinned;
232+
bool reused;
232233
};
233234

234235
struct bpf_secdata {
@@ -1995,6 +1996,7 @@ int bpf_map__reuse_fd(struct bpf_map *map, int fd)
19951996
map->def.map_flags = info.map_flags;
19961997
map->btf_key_type_id = info.btf_key_type_id;
19971998
map->btf_value_type_id = info.btf_value_type_id;
1999+
map->reused = true;
19982000

19992001
return 0;
20002002

@@ -3719,7 +3721,7 @@ load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt,
37193721
free(log_buf);
37203722
goto retry_load;
37213723
}
3722-
ret = -LIBBPF_ERRNO__LOAD;
3724+
ret = -errno;
37233725
cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg));
37243726
pr_warn("load bpf program failed: %s\n", cp);
37253727

@@ -3732,23 +3734,18 @@ load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt,
37323734
pr_warn("Program too large (%zu insns), at most %d insns\n",
37333735
load_attr.insns_cnt, BPF_MAXINSNS);
37343736
ret = -LIBBPF_ERRNO__PROG2BIG;
3735-
} else {
3737+
} else if (load_attr.prog_type != BPF_PROG_TYPE_KPROBE) {
37363738
/* Wrong program type? */
3737-
if (load_attr.prog_type != BPF_PROG_TYPE_KPROBE) {
3738-
int fd;
3739-
3740-
load_attr.prog_type = BPF_PROG_TYPE_KPROBE;
3741-
load_attr.expected_attach_type = 0;
3742-
fd = bpf_load_program_xattr(&load_attr, NULL, 0);
3743-
if (fd >= 0) {
3744-
close(fd);
3745-
ret = -LIBBPF_ERRNO__PROGTYPE;
3746-
goto out;
3747-
}
3748-
}
3739+
int fd;
37493740

3750-
if (log_buf)
3751-
ret = -LIBBPF_ERRNO__KVER;
3741+
load_attr.prog_type = BPF_PROG_TYPE_KPROBE;
3742+
load_attr.expected_attach_type = 0;
3743+
fd = bpf_load_program_xattr(&load_attr, NULL, 0);
3744+
if (fd >= 0) {
3745+
close(fd);
3746+
ret = -LIBBPF_ERRNO__PROGTYPE;
3747+
goto out;
3748+
}
37523749
}
37533750

37543751
out:
@@ -4026,7 +4023,7 @@ int bpf_object__unload(struct bpf_object *obj)
40264023
int bpf_object__load_xattr(struct bpf_object_load_attr *attr)
40274024
{
40284025
struct bpf_object *obj;
4029-
int err;
4026+
int err, i;
40304027

40314028
if (!attr)
40324029
return -EINVAL;
@@ -4047,6 +4044,11 @@ int bpf_object__load_xattr(struct bpf_object_load_attr *attr)
40474044

40484045
return 0;
40494046
out:
4047+
/* unpin any maps that were auto-pinned during load */
4048+
for (i = 0; i < obj->nr_maps; i++)
4049+
if (obj->maps[i].pinned && !obj->maps[i].reused)
4050+
bpf_map__unpin(&obj->maps[i], NULL);
4051+
40504052
bpf_object__unload(obj);
40514053
pr_warn("failed to load object '%s'\n", obj->path);
40524054
return err;
@@ -4780,6 +4782,11 @@ int bpf_program__fd(const struct bpf_program *prog)
47804782
return bpf_program__nth_fd(prog, 0);
47814783
}
47824784

4785+
size_t bpf_program__size(const struct bpf_program *prog)
4786+
{
4787+
return prog->insns_cnt * sizeof(struct bpf_insn);
4788+
}
4789+
47834790
int bpf_program__set_prep(struct bpf_program *prog, int nr_instances,
47844791
bpf_program_prep_t prep)
47854792
{

tools/lib/bpf/libbpf.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,9 @@ LIBBPF_API void bpf_program__set_ifindex(struct bpf_program *prog,
214214
LIBBPF_API const char *bpf_program__title(const struct bpf_program *prog,
215215
bool needs_copy);
216216

217+
/* returns program size in bytes */
218+
LIBBPF_API size_t bpf_program__size(const struct bpf_program *prog);
219+
217220
LIBBPF_API int bpf_program__load(struct bpf_program *prog, char *license,
218221
__u32 kern_version);
219222
LIBBPF_API int bpf_program__fd(const struct bpf_program *prog);
@@ -427,8 +430,18 @@ LIBBPF_API int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,
427430
LIBBPF_API int bpf_prog_load(const char *file, enum bpf_prog_type type,
428431
struct bpf_object **pobj, int *prog_fd);
429432

433+
struct xdp_link_info {
434+
__u32 prog_id;
435+
__u32 drv_prog_id;
436+
__u32 hw_prog_id;
437+
__u32 skb_prog_id;
438+
__u8 attach_mode;
439+
};
440+
430441
LIBBPF_API int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags);
431442
LIBBPF_API int bpf_get_link_xdp_id(int ifindex, __u32 *prog_id, __u32 flags);
443+
LIBBPF_API int bpf_get_link_xdp_info(int ifindex, struct xdp_link_info *info,
444+
size_t info_size, __u32 flags);
432445

433446
struct perf_buffer;
434447

tools/lib/bpf/libbpf.map

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ LIBBPF_0.0.5 {
193193

194194
LIBBPF_0.0.6 {
195195
global:
196+
bpf_get_link_xdp_info;
196197
bpf_map__get_pin_path;
197198
bpf_map__is_pinned;
198199
bpf_map__set_pin_path;
@@ -202,4 +203,5 @@ LIBBPF_0.0.6 {
202203
bpf_program__get_type;
203204
bpf_program__is_tracing;
204205
bpf_program__set_tracing;
206+
bpf_program__size;
205207
} LIBBPF_0.0.5;

tools/lib/bpf/netlink.c

Lines changed: 58 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include "bpf.h"
1414
#include "libbpf.h"
15+
#include "libbpf_internal.h"
1516
#include "nlattr.h"
1617

1718
#ifndef SOL_NETLINK
@@ -24,7 +25,7 @@ typedef int (*__dump_nlmsg_t)(struct nlmsghdr *nlmsg, libbpf_dump_nlmsg_t,
2425
struct xdp_id_md {
2526
int ifindex;
2627
__u32 flags;
27-
__u32 id;
28+
struct xdp_link_info info;
2829
};
2930

3031
int libbpf_netlink_open(__u32 *nl_pid)
@@ -43,7 +44,7 @@ int libbpf_netlink_open(__u32 *nl_pid)
4344

4445
if (setsockopt(sock, SOL_NETLINK, NETLINK_EXT_ACK,
4546
&one, sizeof(one)) < 0) {
46-
fprintf(stderr, "Netlink error reporting not supported\n");
47+
pr_warn("Netlink error reporting not supported\n");
4748
}
4849

4950
if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
@@ -202,26 +203,11 @@ static int __dump_link_nlmsg(struct nlmsghdr *nlh,
202203
return dump_link_nlmsg(cookie, ifi, tb);
203204
}
204205

205-
static unsigned char get_xdp_id_attr(unsigned char mode, __u32 flags)
206-
{
207-
if (mode != XDP_ATTACHED_MULTI)
208-
return IFLA_XDP_PROG_ID;
209-
if (flags & XDP_FLAGS_DRV_MODE)
210-
return IFLA_XDP_DRV_PROG_ID;
211-
if (flags & XDP_FLAGS_HW_MODE)
212-
return IFLA_XDP_HW_PROG_ID;
213-
if (flags & XDP_FLAGS_SKB_MODE)
214-
return IFLA_XDP_SKB_PROG_ID;
215-
216-
return IFLA_XDP_UNSPEC;
217-
}
218-
219-
static int get_xdp_id(void *cookie, void *msg, struct nlattr **tb)
206+
static int get_xdp_info(void *cookie, void *msg, struct nlattr **tb)
220207
{
221208
struct nlattr *xdp_tb[IFLA_XDP_MAX + 1];
222209
struct xdp_id_md *xdp_id = cookie;
223210
struct ifinfomsg *ifinfo = msg;
224-
unsigned char mode, xdp_attr;
225211
int ret;
226212

227213
if (xdp_id->ifindex && xdp_id->ifindex != ifinfo->ifi_index)
@@ -237,27 +223,40 @@ static int get_xdp_id(void *cookie, void *msg, struct nlattr **tb)
237223
if (!xdp_tb[IFLA_XDP_ATTACHED])
238224
return 0;
239225

240-
mode = libbpf_nla_getattr_u8(xdp_tb[IFLA_XDP_ATTACHED]);
241-
if (mode == XDP_ATTACHED_NONE)
242-
return 0;
226+
xdp_id->info.attach_mode = libbpf_nla_getattr_u8(
227+
xdp_tb[IFLA_XDP_ATTACHED]);
243228

244-
xdp_attr = get_xdp_id_attr(mode, xdp_id->flags);
245-
if (!xdp_attr || !xdp_tb[xdp_attr])
229+
if (xdp_id->info.attach_mode == XDP_ATTACHED_NONE)
246230
return 0;
247231

248-
xdp_id->id = libbpf_nla_getattr_u32(xdp_tb[xdp_attr]);
232+
if (xdp_tb[IFLA_XDP_PROG_ID])
233+
xdp_id->info.prog_id = libbpf_nla_getattr_u32(
234+
xdp_tb[IFLA_XDP_PROG_ID]);
235+
236+
if (xdp_tb[IFLA_XDP_SKB_PROG_ID])
237+
xdp_id->info.skb_prog_id = libbpf_nla_getattr_u32(
238+
xdp_tb[IFLA_XDP_SKB_PROG_ID]);
239+
240+
if (xdp_tb[IFLA_XDP_DRV_PROG_ID])
241+
xdp_id->info.drv_prog_id = libbpf_nla_getattr_u32(
242+
xdp_tb[IFLA_XDP_DRV_PROG_ID]);
243+
244+
if (xdp_tb[IFLA_XDP_HW_PROG_ID])
245+
xdp_id->info.hw_prog_id = libbpf_nla_getattr_u32(
246+
xdp_tb[IFLA_XDP_HW_PROG_ID]);
249247

250248
return 0;
251249
}
252250

253-
int bpf_get_link_xdp_id(int ifindex, __u32 *prog_id, __u32 flags)
251+
int bpf_get_link_xdp_info(int ifindex, struct xdp_link_info *info,
252+
size_t info_size, __u32 flags)
254253
{
255254
struct xdp_id_md xdp_id = {};
256255
int sock, ret;
257256
__u32 nl_pid;
258257
__u32 mask;
259258

260-
if (flags & ~XDP_FLAGS_MASK)
259+
if (flags & ~XDP_FLAGS_MASK || !info_size)
261260
return -EINVAL;
262261

263262
/* Check whether the single {HW,DRV,SKB} mode is set */
@@ -273,14 +272,44 @@ int bpf_get_link_xdp_id(int ifindex, __u32 *prog_id, __u32 flags)
273272
xdp_id.ifindex = ifindex;
274273
xdp_id.flags = flags;
275274

276-
ret = libbpf_nl_get_link(sock, nl_pid, get_xdp_id, &xdp_id);
277-
if (!ret)
278-
*prog_id = xdp_id.id;
275+
ret = libbpf_nl_get_link(sock, nl_pid, get_xdp_info, &xdp_id);
276+
if (!ret) {
277+
size_t sz = min(info_size, sizeof(xdp_id.info));
278+
279+
memcpy(info, &xdp_id.info, sz);
280+
memset((void *) info + sz, 0, info_size - sz);
281+
}
279282

280283
close(sock);
281284
return ret;
282285
}
283286

287+
static __u32 get_xdp_id(struct xdp_link_info *info, __u32 flags)
288+
{
289+
if (info->attach_mode != XDP_ATTACHED_MULTI)
290+
return info->prog_id;
291+
if (flags & XDP_FLAGS_DRV_MODE)
292+
return info->drv_prog_id;
293+
if (flags & XDP_FLAGS_HW_MODE)
294+
return info->hw_prog_id;
295+
if (flags & XDP_FLAGS_SKB_MODE)
296+
return info->skb_prog_id;
297+
298+
return 0;
299+
}
300+
301+
int bpf_get_link_xdp_id(int ifindex, __u32 *prog_id, __u32 flags)
302+
{
303+
struct xdp_link_info info;
304+
int ret;
305+
306+
ret = bpf_get_link_xdp_info(ifindex, &info, sizeof(info), flags);
307+
if (!ret)
308+
*prog_id = get_xdp_id(&info, flags);
309+
310+
return ret;
311+
}
312+
284313
int libbpf_nl_get_link(int sock, unsigned int nl_pid,
285314
libbpf_dump_nlmsg_t dump_link_nlmsg, void *cookie)
286315
{

tools/lib/bpf/nlattr.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include <errno.h>
1010
#include "nlattr.h"
11+
#include "libbpf_internal.h"
1112
#include <linux/rtnetlink.h>
1213
#include <string.h>
1314
#include <stdio.h>
@@ -121,8 +122,8 @@ int libbpf_nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head,
121122
}
122123

123124
if (tb[type])
124-
fprintf(stderr, "Attribute of type %#x found multiple times in message, "
125-
"previous attribute is being ignored.\n", type);
125+
pr_warn("Attribute of type %#x found multiple times in message, "
126+
"previous attribute is being ignored.\n", type);
126127

127128
tb[type] = nla;
128129
}
@@ -181,15 +182,14 @@ int libbpf_nla_dump_errormsg(struct nlmsghdr *nlh)
181182

182183
if (libbpf_nla_parse(tb, NLMSGERR_ATTR_MAX, attr, alen,
183184
extack_policy) != 0) {
184-
fprintf(stderr,
185-
"Failed to parse extended error attributes\n");
185+
pr_warn("Failed to parse extended error attributes\n");
186186
return 0;
187187
}
188188

189189
if (tb[NLMSGERR_ATTR_MSG])
190190
errmsg = (char *) libbpf_nla_data(tb[NLMSGERR_ATTR_MSG]);
191191

192-
fprintf(stderr, "Kernel error message: %s\n", errmsg);
192+
pr_warn("Kernel error message: %s\n", errmsg);
193193

194194
return 0;
195195
}

tools/testing/selftests/bpf/prog_tests/pinning.c

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,12 +163,15 @@ void test_pinning(void)
163163
goto out;
164164
}
165165

166-
/* swap pin paths of the two maps */
166+
/* set pin paths so that nopinmap2 will attempt to reuse the map at
167+
* pinpath (which will fail), but not before pinmap has already been
168+
* reused
169+
*/
167170
bpf_object__for_each_map(map, obj) {
168171
if (!strcmp(bpf_map__name(map), "nopinmap"))
172+
err = bpf_map__set_pin_path(map, nopinpath2);
173+
else if (!strcmp(bpf_map__name(map), "nopinmap2"))
169174
err = bpf_map__set_pin_path(map, pinpath);
170-
else if (!strcmp(bpf_map__name(map), "pinmap"))
171-
err = bpf_map__set_pin_path(map, NULL);
172175
else
173176
continue;
174177

@@ -181,6 +184,17 @@ void test_pinning(void)
181184
if (CHECK(err != -EINVAL, "param mismatch load", "err %d errno %d\n", err, errno))
182185
goto out;
183186

187+
/* nopinmap2 should have been pinned and cleaned up again */
188+
err = stat(nopinpath2, &statbuf);
189+
if (CHECK(!err || errno != ENOENT, "stat nopinpath2",
190+
"err %d errno %d\n", err, errno))
191+
goto out;
192+
193+
/* pinmap should still be there */
194+
err = stat(pinpath, &statbuf);
195+
if (CHECK(err, "stat pinpath", "err %d errno %d\n", err, errno))
196+
goto out;
197+
184198
bpf_object__close(obj);
185199

186200
/* test auto-pinning at custom path with open opt */

tools/testing/selftests/bpf/progs/test_pinning.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ struct {
2121
} nopinmap SEC(".maps");
2222

2323
struct {
24-
__uint(type, BPF_MAP_TYPE_ARRAY);
24+
__uint(type, BPF_MAP_TYPE_HASH);
2525
__uint(max_entries, 1);
2626
__type(key, __u32);
2727
__type(value, __u64);

0 commit comments

Comments
 (0)