]>
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 | ||
c7272ca7 | 17 | #include "bpf_util.h" |
f7af0dc5 SP |
18 | #include "utils.h" |
19 | #include "ip_common.h" | |
c7272ca7 DB |
20 | |
21 | extern int force; | |
22 | ||
a872b870 DB |
23 | struct xdp_req { |
24 | struct iplink_req *req; | |
25 | __u32 flags; | |
26 | }; | |
27 | ||
c7272ca7 DB |
28 | static void xdp_ebpf_cb(void *raw, int fd, const char *annotation) |
29 | { | |
a872b870 DB |
30 | struct xdp_req *xdp = raw; |
31 | struct iplink_req *req = xdp->req; | |
32 | struct rtattr *xdp_attr; | |
c7272ca7 | 33 | |
a872b870 | 34 | xdp_attr = addattr_nest(&req->n, sizeof(*req), IFLA_XDP); |
c7272ca7 | 35 | addattr32(&req->n, sizeof(*req), IFLA_XDP_FD, fd); |
a872b870 DB |
36 | if (xdp->flags) |
37 | addattr32(&req->n, sizeof(*req), IFLA_XDP_FLAGS, xdp->flags); | |
38 | addattr_nest_end(&req->n, xdp_attr); | |
c7272ca7 DB |
39 | } |
40 | ||
41 | static const struct bpf_cfg_ops bpf_cb_ops = { | |
42 | .ebpf_cb = xdp_ebpf_cb, | |
43 | }; | |
44 | ||
a872b870 | 45 | static int xdp_delete(struct xdp_req *xdp) |
c7272ca7 | 46 | { |
a872b870 | 47 | xdp_ebpf_cb(xdp, -1, NULL); |
c7272ca7 DB |
48 | return 0; |
49 | } | |
50 | ||
65083b5f SH |
51 | int xdp_parse(int *argc, char ***argv, struct iplink_req *req, |
52 | const char *ifname, bool generic, bool drv, bool offload) | |
c7272ca7 DB |
53 | { |
54 | struct bpf_cfg_in cfg = { | |
658cfebc | 55 | .type = BPF_PROG_TYPE_XDP, |
c7272ca7 DB |
56 | .argc = *argc, |
57 | .argv = *argv, | |
58 | }; | |
a872b870 DB |
59 | struct xdp_req xdp = { |
60 | .req = req, | |
61 | }; | |
62 | ||
4f2eb14f | 63 | if (offload) { |
65083b5f SH |
64 | int ifindex = ll_name_to_index(ifname); |
65 | ||
4f2eb14f JK |
66 | if (!ifindex) |
67 | incomplete_command(); | |
68 | cfg.ifindex = ifindex; | |
69 | } | |
70 | ||
a872b870 DB |
71 | if (!force) |
72 | xdp.flags |= XDP_FLAGS_UPDATE_IF_NOEXIST; | |
73 | if (generic) | |
74 | xdp.flags |= XDP_FLAGS_SKB_MODE; | |
14683814 JK |
75 | if (drv) |
76 | xdp.flags |= XDP_FLAGS_DRV_MODE; | |
1b5e8094 JK |
77 | if (offload) |
78 | xdp.flags |= XDP_FLAGS_HW_MODE; | |
c7272ca7 DB |
79 | |
80 | if (*argc == 1) { | |
81 | if (strcmp(**argv, "none") == 0 || | |
82 | strcmp(**argv, "off") == 0) | |
a872b870 | 83 | return xdp_delete(&xdp); |
c7272ca7 | 84 | } |
a872b870 | 85 | |
399db839 | 86 | if (bpf_parse_and_load_common(&cfg, &bpf_cb_ops, &xdp)) |
c7272ca7 DB |
87 | return -1; |
88 | ||
89 | *argc = cfg.argc; | |
90 | *argv = cfg.argv; | |
91 | return 0; | |
92 | } | |
93 | ||
da083b5a JK |
94 | static void xdp_dump_json_one(struct rtattr *tb[IFLA_XDP_MAX + 1], __u32 attr, |
95 | __u8 mode) | |
96 | { | |
97 | if (!tb[attr]) | |
98 | return; | |
99 | ||
100 | open_json_object(NULL); | |
101 | print_uint(PRINT_JSON, "mode", NULL, mode); | |
102 | bpf_dump_prog_info(NULL, rta_getattr_u32(tb[attr])); | |
103 | close_json_object(); | |
104 | } | |
105 | ||
bc2d4d83 DB |
106 | static void xdp_dump_json(struct rtattr *tb[IFLA_XDP_MAX + 1]) |
107 | { | |
108 | __u32 prog_id = 0; | |
109 | __u8 mode; | |
110 | ||
111 | mode = rta_getattr_u8(tb[IFLA_XDP_ATTACHED]); | |
112 | if (tb[IFLA_XDP_PROG_ID]) | |
113 | prog_id = rta_getattr_u32(tb[IFLA_XDP_PROG_ID]); | |
114 | ||
115 | open_json_object("xdp"); | |
116 | print_uint(PRINT_JSON, "mode", NULL, mode); | |
117 | if (prog_id) | |
118 | bpf_dump_prog_info(NULL, prog_id); | |
da083b5a JK |
119 | |
120 | open_json_array(PRINT_JSON, "attached"); | |
121 | if (tb[IFLA_XDP_SKB_PROG_ID] || | |
122 | tb[IFLA_XDP_DRV_PROG_ID] || | |
123 | tb[IFLA_XDP_HW_PROG_ID]) { | |
124 | xdp_dump_json_one(tb, IFLA_XDP_SKB_PROG_ID, XDP_ATTACHED_SKB); | |
125 | xdp_dump_json_one(tb, IFLA_XDP_DRV_PROG_ID, XDP_ATTACHED_DRV); | |
126 | xdp_dump_json_one(tb, IFLA_XDP_HW_PROG_ID, XDP_ATTACHED_HW); | |
127 | } else if (tb[IFLA_XDP_PROG_ID]) { | |
128 | /* Older kernel - use IFLA_XDP_PROG_ID */ | |
129 | xdp_dump_json_one(tb, IFLA_XDP_PROG_ID, mode); | |
130 | } | |
131 | close_json_array(PRINT_JSON, NULL); | |
132 | ||
bc2d4d83 DB |
133 | close_json_object(); |
134 | } | |
135 | ||
da083b5a JK |
136 | static void xdp_dump_prog_one(FILE *fp, struct rtattr *tb[IFLA_XDP_MAX + 1], |
137 | __u32 attr, bool link, bool details, | |
138 | const char *pfx) | |
139 | { | |
140 | __u32 prog_id; | |
141 | ||
142 | if (!tb[attr]) | |
143 | return; | |
144 | ||
145 | prog_id = rta_getattr_u32(tb[attr]); | |
146 | if (!details) { | |
147 | if (prog_id && !link && attr == IFLA_XDP_PROG_ID) | |
148 | fprintf(fp, "/id:%u", prog_id); | |
149 | return; | |
150 | } | |
151 | ||
152 | if (prog_id) { | |
153 | fprintf(fp, "%s prog/xdp%s ", _SL_, pfx); | |
154 | bpf_dump_prog_info(fp, prog_id); | |
155 | } | |
156 | } | |
157 | ||
a0b5b7cf | 158 | void xdp_dump(FILE *fp, struct rtattr *xdp, bool link, bool details) |
c7272ca7 DB |
159 | { |
160 | struct rtattr *tb[IFLA_XDP_MAX + 1]; | |
077bb180 | 161 | __u8 mode; |
c7272ca7 DB |
162 | |
163 | parse_rtattr_nested(tb, IFLA_XDP_MAX, xdp); | |
a872b870 | 164 | |
077bb180 | 165 | if (!tb[IFLA_XDP_ATTACHED]) |
c7272ca7 DB |
166 | return; |
167 | ||
077bb180 | 168 | mode = rta_getattr_u8(tb[IFLA_XDP_ATTACHED]); |
bc2d4d83 DB |
169 | if (mode == XDP_ATTACHED_NONE) |
170 | return; | |
171 | else if (is_json_context()) | |
172 | return details ? (void)0 : xdp_dump_json(tb); | |
173 | else if (details && link) | |
da083b5a | 174 | /* don't print mode */; |
bc2d4d83 DB |
175 | else if (mode == XDP_ATTACHED_DRV) |
176 | fprintf(fp, "xdp"); | |
177 | else if (mode == XDP_ATTACHED_SKB) | |
178 | fprintf(fp, "xdpgeneric"); | |
179 | else if (mode == XDP_ATTACHED_HW) | |
180 | fprintf(fp, "xdpoffload"); | |
da083b5a JK |
181 | else if (mode == XDP_ATTACHED_MULTI) |
182 | fprintf(fp, "xdpmulti"); | |
bc2d4d83 DB |
183 | else |
184 | fprintf(fp, "xdp[%u]", mode); | |
185 | ||
da083b5a JK |
186 | xdp_dump_prog_one(fp, tb, IFLA_XDP_PROG_ID, link, details, ""); |
187 | ||
188 | if (mode == XDP_ATTACHED_MULTI) { | |
189 | xdp_dump_prog_one(fp, tb, IFLA_XDP_SKB_PROG_ID, link, details, | |
190 | "generic"); | |
191 | xdp_dump_prog_one(fp, tb, IFLA_XDP_DRV_PROG_ID, link, details, | |
192 | "drv"); | |
193 | xdp_dump_prog_one(fp, tb, IFLA_XDP_HW_PROG_ID, link, details, | |
194 | "offload"); | |
bc2d4d83 DB |
195 | } |
196 | ||
da083b5a | 197 | if (!details || !link) |
bc2d4d83 | 198 | fprintf(fp, " "); |
c7272ca7 | 199 | } |