Merge tag 'fixes-v5.9a' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris...
[linux-2.6-microblaze.git] / tools / bpf / bpftool / link.c
1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2 /* Copyright (C) 2020 Facebook */
3
4 #include <errno.h>
5 #include <net/if.h>
6 #include <stdio.h>
7 #include <unistd.h>
8
9 #include <bpf/bpf.h>
10
11 #include "json_writer.h"
12 #include "main.h"
13
14 static const char * const link_type_name[] = {
15         [BPF_LINK_TYPE_UNSPEC]                  = "unspec",
16         [BPF_LINK_TYPE_RAW_TRACEPOINT]          = "raw_tracepoint",
17         [BPF_LINK_TYPE_TRACING]                 = "tracing",
18         [BPF_LINK_TYPE_CGROUP]                  = "cgroup",
19         [BPF_LINK_TYPE_ITER]                    = "iter",
20         [BPF_LINK_TYPE_NETNS]                   = "netns",
21 };
22
23 static int link_parse_fd(int *argc, char ***argv)
24 {
25         int fd;
26
27         if (is_prefix(**argv, "id")) {
28                 unsigned int id;
29                 char *endptr;
30
31                 NEXT_ARGP();
32
33                 id = strtoul(**argv, &endptr, 0);
34                 if (*endptr) {
35                         p_err("can't parse %s as ID", **argv);
36                         return -1;
37                 }
38                 NEXT_ARGP();
39
40                 fd = bpf_link_get_fd_by_id(id);
41                 if (fd < 0)
42                         p_err("failed to get link with ID %d: %s", id, strerror(errno));
43                 return fd;
44         } else if (is_prefix(**argv, "pinned")) {
45                 char *path;
46
47                 NEXT_ARGP();
48
49                 path = **argv;
50                 NEXT_ARGP();
51
52                 return open_obj_pinned_any(path, BPF_OBJ_LINK);
53         }
54
55         p_err("expected 'id' or 'pinned', got: '%s'?", **argv);
56         return -1;
57 }
58
59 static void
60 show_link_header_json(struct bpf_link_info *info, json_writer_t *wtr)
61 {
62         jsonw_uint_field(wtr, "id", info->id);
63         if (info->type < ARRAY_SIZE(link_type_name))
64                 jsonw_string_field(wtr, "type", link_type_name[info->type]);
65         else
66                 jsonw_uint_field(wtr, "type", info->type);
67
68         jsonw_uint_field(json_wtr, "prog_id", info->prog_id);
69 }
70
71 static void show_link_attach_type_json(__u32 attach_type, json_writer_t *wtr)
72 {
73         if (attach_type < ARRAY_SIZE(attach_type_name))
74                 jsonw_string_field(wtr, "attach_type",
75                                    attach_type_name[attach_type]);
76         else
77                 jsonw_uint_field(wtr, "attach_type", attach_type);
78 }
79
80 static int get_prog_info(int prog_id, struct bpf_prog_info *info)
81 {
82         __u32 len = sizeof(*info);
83         int err, prog_fd;
84
85         prog_fd = bpf_prog_get_fd_by_id(prog_id);
86         if (prog_fd < 0)
87                 return prog_fd;
88
89         memset(info, 0, sizeof(*info));
90         err = bpf_obj_get_info_by_fd(prog_fd, info, &len);
91         if (err)
92                 p_err("can't get prog info: %s", strerror(errno));
93         close(prog_fd);
94         return err;
95 }
96
97 static int show_link_close_json(int fd, struct bpf_link_info *info)
98 {
99         struct bpf_prog_info prog_info;
100         int err;
101
102         jsonw_start_object(json_wtr);
103
104         show_link_header_json(info, json_wtr);
105
106         switch (info->type) {
107         case BPF_LINK_TYPE_RAW_TRACEPOINT:
108                 jsonw_string_field(json_wtr, "tp_name",
109                                    u64_to_ptr(info->raw_tracepoint.tp_name));
110                 break;
111         case BPF_LINK_TYPE_TRACING:
112                 err = get_prog_info(info->prog_id, &prog_info);
113                 if (err)
114                         return err;
115
116                 if (prog_info.type < prog_type_name_size)
117                         jsonw_string_field(json_wtr, "prog_type",
118                                            prog_type_name[prog_info.type]);
119                 else
120                         jsonw_uint_field(json_wtr, "prog_type",
121                                          prog_info.type);
122
123                 show_link_attach_type_json(info->tracing.attach_type,
124                                            json_wtr);
125                 break;
126         case BPF_LINK_TYPE_CGROUP:
127                 jsonw_lluint_field(json_wtr, "cgroup_id",
128                                    info->cgroup.cgroup_id);
129                 show_link_attach_type_json(info->cgroup.attach_type, json_wtr);
130                 break;
131         case BPF_LINK_TYPE_NETNS:
132                 jsonw_uint_field(json_wtr, "netns_ino",
133                                  info->netns.netns_ino);
134                 show_link_attach_type_json(info->netns.attach_type, json_wtr);
135                 break;
136         default:
137                 break;
138         }
139
140         if (!hash_empty(link_table.table)) {
141                 struct pinned_obj *obj;
142
143                 jsonw_name(json_wtr, "pinned");
144                 jsonw_start_array(json_wtr);
145                 hash_for_each_possible(link_table.table, obj, hash, info->id) {
146                         if (obj->id == info->id)
147                                 jsonw_string(json_wtr, obj->path);
148                 }
149                 jsonw_end_array(json_wtr);
150         }
151
152         emit_obj_refs_json(&refs_table, info->id, json_wtr);
153
154         jsonw_end_object(json_wtr);
155
156         return 0;
157 }
158
159 static void show_link_header_plain(struct bpf_link_info *info)
160 {
161         printf("%u: ", info->id);
162         if (info->type < ARRAY_SIZE(link_type_name))
163                 printf("%s  ", link_type_name[info->type]);
164         else
165                 printf("type %u  ", info->type);
166
167         printf("prog %u  ", info->prog_id);
168 }
169
170 static void show_link_attach_type_plain(__u32 attach_type)
171 {
172         if (attach_type < ARRAY_SIZE(attach_type_name))
173                 printf("attach_type %s  ", attach_type_name[attach_type]);
174         else
175                 printf("attach_type %u  ", attach_type);
176 }
177
178 static int show_link_close_plain(int fd, struct bpf_link_info *info)
179 {
180         struct bpf_prog_info prog_info;
181         int err;
182
183         show_link_header_plain(info);
184
185         switch (info->type) {
186         case BPF_LINK_TYPE_RAW_TRACEPOINT:
187                 printf("\n\ttp '%s'  ",
188                        (const char *)u64_to_ptr(info->raw_tracepoint.tp_name));
189                 break;
190         case BPF_LINK_TYPE_TRACING:
191                 err = get_prog_info(info->prog_id, &prog_info);
192                 if (err)
193                         return err;
194
195                 if (prog_info.type < prog_type_name_size)
196                         printf("\n\tprog_type %s  ",
197                                prog_type_name[prog_info.type]);
198                 else
199                         printf("\n\tprog_type %u  ", prog_info.type);
200
201                 show_link_attach_type_plain(info->tracing.attach_type);
202                 break;
203         case BPF_LINK_TYPE_CGROUP:
204                 printf("\n\tcgroup_id %zu  ", (size_t)info->cgroup.cgroup_id);
205                 show_link_attach_type_plain(info->cgroup.attach_type);
206                 break;
207         case BPF_LINK_TYPE_NETNS:
208                 printf("\n\tnetns_ino %u  ", info->netns.netns_ino);
209                 show_link_attach_type_plain(info->netns.attach_type);
210                 break;
211         default:
212                 break;
213         }
214
215         if (!hash_empty(link_table.table)) {
216                 struct pinned_obj *obj;
217
218                 hash_for_each_possible(link_table.table, obj, hash, info->id) {
219                         if (obj->id == info->id)
220                                 printf("\n\tpinned %s", obj->path);
221                 }
222         }
223         emit_obj_refs_plain(&refs_table, info->id, "\n\tpids ");
224
225         printf("\n");
226
227         return 0;
228 }
229
230 static int do_show_link(int fd)
231 {
232         struct bpf_link_info info;
233         __u32 len = sizeof(info);
234         char raw_tp_name[256];
235         int err;
236
237         memset(&info, 0, sizeof(info));
238 again:
239         err = bpf_obj_get_info_by_fd(fd, &info, &len);
240         if (err) {
241                 p_err("can't get link info: %s",
242                       strerror(errno));
243                 close(fd);
244                 return err;
245         }
246         if (info.type == BPF_LINK_TYPE_RAW_TRACEPOINT &&
247             !info.raw_tracepoint.tp_name) {
248                 info.raw_tracepoint.tp_name = (unsigned long)&raw_tp_name;
249                 info.raw_tracepoint.tp_name_len = sizeof(raw_tp_name);
250                 goto again;
251         }
252
253         if (json_output)
254                 show_link_close_json(fd, &info);
255         else
256                 show_link_close_plain(fd, &info);
257
258         close(fd);
259         return 0;
260 }
261
262 static int do_show(int argc, char **argv)
263 {
264         __u32 id = 0;
265         int err, fd;
266
267         if (show_pinned)
268                 build_pinned_obj_table(&link_table, BPF_OBJ_LINK);
269         build_obj_refs_table(&refs_table, BPF_OBJ_LINK);
270
271         if (argc == 2) {
272                 fd = link_parse_fd(&argc, &argv);
273                 if (fd < 0)
274                         return fd;
275                 return do_show_link(fd);
276         }
277
278         if (argc)
279                 return BAD_ARG();
280
281         if (json_output)
282                 jsonw_start_array(json_wtr);
283         while (true) {
284                 err = bpf_link_get_next_id(id, &id);
285                 if (err) {
286                         if (errno == ENOENT)
287                                 break;
288                         p_err("can't get next link: %s%s", strerror(errno),
289                               errno == EINVAL ? " -- kernel too old?" : "");
290                         break;
291                 }
292
293                 fd = bpf_link_get_fd_by_id(id);
294                 if (fd < 0) {
295                         if (errno == ENOENT)
296                                 continue;
297                         p_err("can't get link by id (%u): %s",
298                               id, strerror(errno));
299                         break;
300                 }
301
302                 err = do_show_link(fd);
303                 if (err)
304                         break;
305         }
306         if (json_output)
307                 jsonw_end_array(json_wtr);
308
309         delete_obj_refs_table(&refs_table);
310
311         return errno == ENOENT ? 0 : -1;
312 }
313
314 static int do_pin(int argc, char **argv)
315 {
316         int err;
317
318         err = do_pin_any(argc, argv, link_parse_fd);
319         if (!err && json_output)
320                 jsonw_null(json_wtr);
321         return err;
322 }
323
324 static int do_detach(int argc, char **argv)
325 {
326         int err, fd;
327
328         if (argc != 2) {
329                 p_err("link specifier is invalid or missing\n");
330                 return 1;
331         }
332
333         fd = link_parse_fd(&argc, &argv);
334         if (fd < 0)
335                 return 1;
336
337         err = bpf_link_detach(fd);
338         if (err)
339                 err = -errno;
340         close(fd);
341         if (err) {
342                 p_err("failed link detach: %s", strerror(-err));
343                 return 1;
344         }
345
346         if (json_output)
347                 jsonw_null(json_wtr);
348
349         return 0;
350 }
351
352 static int do_help(int argc, char **argv)
353 {
354         if (json_output) {
355                 jsonw_null(json_wtr);
356                 return 0;
357         }
358
359         fprintf(stderr,
360                 "Usage: %1$s %2$s { show | list }   [LINK]\n"
361                 "       %1$s %2$s pin        LINK  FILE\n"
362                 "       %1$s %2$s detach     LINK\n"
363                 "       %1$s %2$s help\n"
364                 "\n"
365                 "       " HELP_SPEC_LINK "\n"
366                 "       " HELP_SPEC_OPTIONS "\n"
367                 "",
368                 bin_name, argv[-2]);
369
370         return 0;
371 }
372
373 static const struct cmd cmds[] = {
374         { "show",       do_show },
375         { "list",       do_show },
376         { "help",       do_help },
377         { "pin",        do_pin },
378         { "detach",     do_detach },
379         { 0 }
380 };
381
382 int do_link(int argc, char **argv)
383 {
384         return cmd_select(cmds, argc, argv, do_help);
385 }