]>
Commit | Line | Data |
---|---|---|
c7272ca7 DB |
1 | /* |
2 | * iplink_xdp.c XDP program loader | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or | |
5 | * modify it under the terms of the GNU General Public License | |
6 | * as published by the Free Software Foundation; either version | |
7 | * 2 of the License, or (at your option) any later version. | |
8 | * | |
9 | * Authors: Daniel Borkmann <daniel@iogearbox.net> | |
10 | */ | |
11 | ||
12 | #include <stdio.h> | |
13 | #include <stdlib.h> | |
14 | ||
15 | #include <linux/bpf.h> | |
16 | ||
17 | #include "xdp.h" | |
18 | #include "bpf_util.h" | |
19 | ||
20 | extern int force; | |
21 | ||
a872b870 DB |
22 | struct xdp_req { |
23 | struct iplink_req *req; | |
24 | __u32 flags; | |
25 | }; | |
26 | ||
c7272ca7 DB |
27 | static void xdp_ebpf_cb(void *raw, int fd, const char *annotation) |
28 | { | |
a872b870 DB |
29 | struct xdp_req *xdp = raw; |
30 | struct iplink_req *req = xdp->req; | |
31 | struct rtattr *xdp_attr; | |
c7272ca7 | 32 | |
a872b870 | 33 | xdp_attr = addattr_nest(&req->n, sizeof(*req), IFLA_XDP); |
c7272ca7 | 34 | addattr32(&req->n, sizeof(*req), IFLA_XDP_FD, fd); |
a872b870 DB |
35 | if (xdp->flags) |
36 | addattr32(&req->n, sizeof(*req), IFLA_XDP_FLAGS, xdp->flags); | |
37 | addattr_nest_end(&req->n, xdp_attr); | |
c7272ca7 DB |
38 | } |
39 | ||
40 | static const struct bpf_cfg_ops bpf_cb_ops = { | |
41 | .ebpf_cb = xdp_ebpf_cb, | |
42 | }; | |
43 | ||
a872b870 | 44 | static int xdp_delete(struct xdp_req *xdp) |
c7272ca7 | 45 | { |
a872b870 | 46 | xdp_ebpf_cb(xdp, -1, NULL); |
c7272ca7 DB |
47 | return 0; |
48 | } | |
49 | ||
a872b870 | 50 | int xdp_parse(int *argc, char ***argv, struct iplink_req *req, bool generic) |
c7272ca7 DB |
51 | { |
52 | struct bpf_cfg_in cfg = { | |
53 | .argc = *argc, | |
54 | .argv = *argv, | |
55 | }; | |
a872b870 DB |
56 | struct xdp_req xdp = { |
57 | .req = req, | |
58 | }; | |
59 | ||
60 | if (!force) | |
61 | xdp.flags |= XDP_FLAGS_UPDATE_IF_NOEXIST; | |
62 | if (generic) | |
63 | xdp.flags |= XDP_FLAGS_SKB_MODE; | |
c7272ca7 DB |
64 | |
65 | if (*argc == 1) { | |
66 | if (strcmp(**argv, "none") == 0 || | |
67 | strcmp(**argv, "off") == 0) | |
a872b870 | 68 | return xdp_delete(&xdp); |
c7272ca7 | 69 | } |
a872b870 DB |
70 | |
71 | if (bpf_parse_common(BPF_PROG_TYPE_XDP, &cfg, &bpf_cb_ops, &xdp)) | |
c7272ca7 DB |
72 | return -1; |
73 | ||
74 | *argc = cfg.argc; | |
75 | *argv = cfg.argv; | |
76 | return 0; | |
77 | } | |
78 | ||
79 | void xdp_dump(FILE *fp, struct rtattr *xdp) | |
80 | { | |
81 | struct rtattr *tb[IFLA_XDP_MAX + 1]; | |
077bb180 | 82 | __u8 mode; |
c7272ca7 DB |
83 | |
84 | parse_rtattr_nested(tb, IFLA_XDP_MAX, xdp); | |
a872b870 | 85 | |
077bb180 | 86 | if (!tb[IFLA_XDP_ATTACHED]) |
c7272ca7 DB |
87 | return; |
88 | ||
077bb180 DB |
89 | mode = rta_getattr_u8(tb[IFLA_XDP_ATTACHED]); |
90 | if (mode == XDP_ATTACHED_NONE) | |
91 | return; | |
92 | else if (mode == XDP_ATTACHED_DRV) | |
93 | fprintf(fp, "xdp "); | |
94 | else if (mode == XDP_ATTACHED_SKB) | |
95 | fprintf(fp, "xdpgeneric "); | |
96 | else | |
97 | fprintf(fp, "xdp[%u] ", mode); | |
c7272ca7 | 98 | } |