1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2 /* Copyright (C) 2020 Facebook */
11 #include "json_writer.h"
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",
23 static int link_parse_fd(int *argc
, char ***argv
)
27 if (is_prefix(**argv
, "id")) {
33 id
= strtoul(**argv
, &endptr
, 0);
35 p_err("can't parse %s as ID", **argv
);
40 fd
= bpf_link_get_fd_by_id(id
);
42 p_err("failed to get link with ID %d: %s", id
, strerror(errno
));
44 } else if (is_prefix(**argv
, "pinned")) {
52 return open_obj_pinned_any(path
, BPF_OBJ_LINK
);
55 p_err("expected 'id' or 'pinned', got: '%s'?", **argv
);
60 show_link_header_json(struct bpf_link_info
*info
, json_writer_t
*wtr
)
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
]);
66 jsonw_uint_field(wtr
, "type", info
->type
);
68 jsonw_uint_field(json_wtr
, "prog_id", info
->prog_id
);
71 static void show_link_attach_type_json(__u32 attach_type
, json_writer_t
*wtr
)
73 if (attach_type
< ARRAY_SIZE(attach_type_name
))
74 jsonw_string_field(wtr
, "attach_type",
75 attach_type_name
[attach_type
]);
77 jsonw_uint_field(wtr
, "attach_type", attach_type
);
80 static bool is_iter_map_target(const char *target_name
)
82 return strcmp(target_name
, "bpf_map_elem") == 0 ||
83 strcmp(target_name
, "bpf_sk_storage_map") == 0;
86 static void show_iter_json(struct bpf_link_info
*info
, json_writer_t
*wtr
)
88 const char *target_name
= u64_to_ptr(info
->iter
.target_name
);
90 jsonw_string_field(wtr
, "target_name", target_name
);
92 if (is_iter_map_target(target_name
))
93 jsonw_uint_field(wtr
, "map_id", info
->iter
.map
.map_id
);
96 static int get_prog_info(int prog_id
, struct bpf_prog_info
*info
)
98 __u32 len
= sizeof(*info
);
101 prog_fd
= bpf_prog_get_fd_by_id(prog_id
);
105 memset(info
, 0, sizeof(*info
));
106 err
= bpf_obj_get_info_by_fd(prog_fd
, info
, &len
);
108 p_err("can't get prog info: %s", strerror(errno
));
113 static int show_link_close_json(int fd
, struct bpf_link_info
*info
)
115 struct bpf_prog_info prog_info
;
118 jsonw_start_object(json_wtr
);
120 show_link_header_json(info
, json_wtr
);
122 switch (info
->type
) {
123 case BPF_LINK_TYPE_RAW_TRACEPOINT
:
124 jsonw_string_field(json_wtr
, "tp_name",
125 u64_to_ptr(info
->raw_tracepoint
.tp_name
));
127 case BPF_LINK_TYPE_TRACING
:
128 err
= get_prog_info(info
->prog_id
, &prog_info
);
132 if (prog_info
.type
< prog_type_name_size
)
133 jsonw_string_field(json_wtr
, "prog_type",
134 prog_type_name
[prog_info
.type
]);
136 jsonw_uint_field(json_wtr
, "prog_type",
139 show_link_attach_type_json(info
->tracing
.attach_type
,
142 case BPF_LINK_TYPE_CGROUP
:
143 jsonw_lluint_field(json_wtr
, "cgroup_id",
144 info
->cgroup
.cgroup_id
);
145 show_link_attach_type_json(info
->cgroup
.attach_type
, json_wtr
);
147 case BPF_LINK_TYPE_ITER
:
148 show_iter_json(info
, json_wtr
);
150 case BPF_LINK_TYPE_NETNS
:
151 jsonw_uint_field(json_wtr
, "netns_ino",
152 info
->netns
.netns_ino
);
153 show_link_attach_type_json(info
->netns
.attach_type
, json_wtr
);
159 if (!hash_empty(link_table
.table
)) {
160 struct pinned_obj
*obj
;
162 jsonw_name(json_wtr
, "pinned");
163 jsonw_start_array(json_wtr
);
164 hash_for_each_possible(link_table
.table
, obj
, hash
, info
->id
) {
165 if (obj
->id
== info
->id
)
166 jsonw_string(json_wtr
, obj
->path
);
168 jsonw_end_array(json_wtr
);
171 emit_obj_refs_json(&refs_table
, info
->id
, json_wtr
);
173 jsonw_end_object(json_wtr
);
178 static void show_link_header_plain(struct bpf_link_info
*info
)
180 printf("%u: ", info
->id
);
181 if (info
->type
< ARRAY_SIZE(link_type_name
))
182 printf("%s ", link_type_name
[info
->type
]);
184 printf("type %u ", info
->type
);
186 printf("prog %u ", info
->prog_id
);
189 static void show_link_attach_type_plain(__u32 attach_type
)
191 if (attach_type
< ARRAY_SIZE(attach_type_name
))
192 printf("attach_type %s ", attach_type_name
[attach_type
]);
194 printf("attach_type %u ", attach_type
);
197 static void show_iter_plain(struct bpf_link_info
*info
)
199 const char *target_name
= u64_to_ptr(info
->iter
.target_name
);
201 printf("target_name %s ", target_name
);
203 if (is_iter_map_target(target_name
))
204 printf("map_id %u ", info
->iter
.map
.map_id
);
207 static int show_link_close_plain(int fd
, struct bpf_link_info
*info
)
209 struct bpf_prog_info prog_info
;
212 show_link_header_plain(info
);
214 switch (info
->type
) {
215 case BPF_LINK_TYPE_RAW_TRACEPOINT
:
216 printf("\n\ttp '%s' ",
217 (const char *)u64_to_ptr(info
->raw_tracepoint
.tp_name
));
219 case BPF_LINK_TYPE_TRACING
:
220 err
= get_prog_info(info
->prog_id
, &prog_info
);
224 if (prog_info
.type
< prog_type_name_size
)
225 printf("\n\tprog_type %s ",
226 prog_type_name
[prog_info
.type
]);
228 printf("\n\tprog_type %u ", prog_info
.type
);
230 show_link_attach_type_plain(info
->tracing
.attach_type
);
232 case BPF_LINK_TYPE_CGROUP
:
233 printf("\n\tcgroup_id %zu ", (size_t)info
->cgroup
.cgroup_id
);
234 show_link_attach_type_plain(info
->cgroup
.attach_type
);
236 case BPF_LINK_TYPE_ITER
:
237 show_iter_plain(info
);
239 case BPF_LINK_TYPE_NETNS
:
240 printf("\n\tnetns_ino %u ", info
->netns
.netns_ino
);
241 show_link_attach_type_plain(info
->netns
.attach_type
);
247 if (!hash_empty(link_table
.table
)) {
248 struct pinned_obj
*obj
;
250 hash_for_each_possible(link_table
.table
, obj
, hash
, info
->id
) {
251 if (obj
->id
== info
->id
)
252 printf("\n\tpinned %s", obj
->path
);
255 emit_obj_refs_plain(&refs_table
, info
->id
, "\n\tpids ");
262 static int do_show_link(int fd
)
264 struct bpf_link_info info
;
265 __u32 len
= sizeof(info
);
269 memset(&info
, 0, sizeof(info
));
271 err
= bpf_obj_get_info_by_fd(fd
, &info
, &len
);
273 p_err("can't get link info: %s",
278 if (info
.type
== BPF_LINK_TYPE_RAW_TRACEPOINT
&&
279 !info
.raw_tracepoint
.tp_name
) {
280 info
.raw_tracepoint
.tp_name
= (unsigned long)&buf
;
281 info
.raw_tracepoint
.tp_name_len
= sizeof(buf
);
284 if (info
.type
== BPF_LINK_TYPE_ITER
&&
285 !info
.iter
.target_name
) {
286 info
.iter
.target_name
= (unsigned long)&buf
;
287 info
.iter
.target_name_len
= sizeof(buf
);
292 show_link_close_json(fd
, &info
);
294 show_link_close_plain(fd
, &info
);
300 static int do_show(int argc
, char **argv
)
306 build_pinned_obj_table(&link_table
, BPF_OBJ_LINK
);
307 build_obj_refs_table(&refs_table
, BPF_OBJ_LINK
);
310 fd
= link_parse_fd(&argc
, &argv
);
313 return do_show_link(fd
);
320 jsonw_start_array(json_wtr
);
322 err
= bpf_link_get_next_id(id
, &id
);
326 p_err("can't get next link: %s%s", strerror(errno
),
327 errno
== EINVAL
? " -- kernel too old?" : "");
331 fd
= bpf_link_get_fd_by_id(id
);
335 p_err("can't get link by id (%u): %s",
336 id
, strerror(errno
));
340 err
= do_show_link(fd
);
345 jsonw_end_array(json_wtr
);
347 delete_obj_refs_table(&refs_table
);
349 return errno
== ENOENT
? 0 : -1;
352 static int do_pin(int argc
, char **argv
)
356 err
= do_pin_any(argc
, argv
, link_parse_fd
);
357 if (!err
&& json_output
)
358 jsonw_null(json_wtr
);
362 static int do_detach(int argc
, char **argv
)
367 p_err("link specifier is invalid or missing\n");
371 fd
= link_parse_fd(&argc
, &argv
);
375 err
= bpf_link_detach(fd
);
380 p_err("failed link detach: %s", strerror(-err
));
385 jsonw_null(json_wtr
);
390 static int do_help(int argc
, char **argv
)
393 jsonw_null(json_wtr
);
398 "Usage: %1$s %2$s { show | list } [LINK]\n"
399 " %1$s %2$s pin LINK FILE\n"
400 " %1$s %2$s detach LINK\n"
403 " " HELP_SPEC_LINK
"\n"
404 " " HELP_SPEC_OPTIONS
"\n"
411 static const struct cmd cmds
[] = {
416 { "detach", do_detach
},
420 int do_link(int argc
, char **argv
)
422 return cmd_select(cmds
, argc
, argv
, do_help
);