diff options
author | Quentin Monnet <quentin.monnet@netronome.com> | 2017-10-23 12:24:08 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-10-23 20:25:08 -0400 |
commit | 743cc665d5f62d2c75eceb59c461e653ad6ea58c (patch) | |
tree | 1977c8d47d0674d8d1601bdc4a0252a3ab0a4936 /tools/bpf | |
parent | d35efba99d9221d9fe1715a23247ad9b703544ec (diff) |
tools: bpftool: add JSON output for `bpftool prog show *` command
Reuse the json_writer API introduced in an earlier commit to make
bpftool able to generate JSON output on `bpftool prog show *` commands.
For readability, the code from show_prog() has been split into two
functions, one for plain output, one for JSON.
Outputs from sample programs have been successfully tested against a
JSON validator.
Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'tools/bpf')
-rw-r--r-- | tools/bpf/bpftool/prog.c | 139 |
1 files changed, 107 insertions, 32 deletions
diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c index 7838206a455b..f373f2baef5a 100644 --- a/tools/bpf/bpftool/prog.c +++ b/tools/bpf/bpftool/prog.c | |||
@@ -195,51 +195,100 @@ static void show_prog_maps(int fd, u32 num_maps) | |||
195 | if (err || !info.nr_map_ids) | 195 | if (err || !info.nr_map_ids) |
196 | return; | 196 | return; |
197 | 197 | ||
198 | printf(" map_ids "); | 198 | if (json_output) { |
199 | for (i = 0; i < info.nr_map_ids; i++) | 199 | jsonw_name(json_wtr, "map_ids"); |
200 | printf("%u%s", map_ids[i], | 200 | jsonw_start_array(json_wtr); |
201 | i == info.nr_map_ids - 1 ? "" : ","); | 201 | for (i = 0; i < info.nr_map_ids; i++) |
202 | jsonw_uint(json_wtr, map_ids[i]); | ||
203 | jsonw_end_array(json_wtr); | ||
204 | } else { | ||
205 | printf(" map_ids "); | ||
206 | for (i = 0; i < info.nr_map_ids; i++) | ||
207 | printf("%u%s", map_ids[i], | ||
208 | i == info.nr_map_ids - 1 ? "" : ","); | ||
209 | } | ||
202 | } | 210 | } |
203 | 211 | ||
204 | static int show_prog(int fd) | 212 | static void print_prog_json(struct bpf_prog_info *info, int fd) |
205 | { | 213 | { |
206 | struct bpf_prog_info info = {}; | ||
207 | __u32 len = sizeof(info); | ||
208 | char *memlock; | 214 | char *memlock; |
209 | int err; | ||
210 | 215 | ||
211 | err = bpf_obj_get_info_by_fd(fd, &info, &len); | 216 | jsonw_start_object(json_wtr); |
212 | if (err) { | 217 | jsonw_uint_field(json_wtr, "id", info->id); |
213 | err("can't get prog info: %s\n", strerror(errno)); | 218 | if (info->type < ARRAY_SIZE(prog_type_name)) |
214 | return -1; | 219 | jsonw_string_field(json_wtr, "type", |
220 | prog_type_name[info->type]); | ||
221 | else | ||
222 | jsonw_uint_field(json_wtr, "type", info->type); | ||
223 | |||
224 | if (*info->name) | ||
225 | jsonw_string_field(json_wtr, "name", info->name); | ||
226 | |||
227 | jsonw_name(json_wtr, "tag"); | ||
228 | jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"", | ||
229 | info->tag[0], info->tag[1], info->tag[2], info->tag[3], | ||
230 | info->tag[4], info->tag[5], info->tag[6], info->tag[7]); | ||
231 | |||
232 | if (info->load_time) { | ||
233 | char buf[32]; | ||
234 | |||
235 | print_boot_time(info->load_time, buf, sizeof(buf)); | ||
236 | |||
237 | /* Piggy back on load_time, since 0 uid is a valid one */ | ||
238 | jsonw_string_field(json_wtr, "loaded_at", buf); | ||
239 | jsonw_uint_field(json_wtr, "uid", info->created_by_uid); | ||
215 | } | 240 | } |
216 | 241 | ||
217 | printf("%u: ", info.id); | 242 | jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len); |
218 | if (info.type < ARRAY_SIZE(prog_type_name)) | 243 | |
219 | printf("%s ", prog_type_name[info.type]); | 244 | if (info->jited_prog_len) { |
245 | jsonw_bool_field(json_wtr, "jited", true); | ||
246 | jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len); | ||
247 | } else { | ||
248 | jsonw_bool_field(json_wtr, "jited", false); | ||
249 | } | ||
250 | |||
251 | memlock = get_fdinfo(fd, "memlock"); | ||
252 | if (memlock) | ||
253 | jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock)); | ||
254 | free(memlock); | ||
255 | |||
256 | if (info->nr_map_ids) | ||
257 | show_prog_maps(fd, info->nr_map_ids); | ||
258 | |||
259 | jsonw_end_object(json_wtr); | ||
260 | } | ||
261 | |||
262 | static void print_prog_plain(struct bpf_prog_info *info, int fd) | ||
263 | { | ||
264 | char *memlock; | ||
265 | |||
266 | printf("%u: ", info->id); | ||
267 | if (info->type < ARRAY_SIZE(prog_type_name)) | ||
268 | printf("%s ", prog_type_name[info->type]); | ||
220 | else | 269 | else |
221 | printf("type %u ", info.type); | 270 | printf("type %u ", info->type); |
222 | 271 | ||
223 | if (*info.name) | 272 | if (*info->name) |
224 | printf("name %s ", info.name); | 273 | printf("name %s ", info->name); |
225 | 274 | ||
226 | printf("tag "); | 275 | printf("tag "); |
227 | fprint_hex(stdout, info.tag, BPF_TAG_SIZE, ""); | 276 | fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); |
228 | printf("\n"); | 277 | printf("\n"); |
229 | 278 | ||
230 | if (info.load_time) { | 279 | if (info->load_time) { |
231 | char buf[32]; | 280 | char buf[32]; |
232 | 281 | ||
233 | print_boot_time(info.load_time, buf, sizeof(buf)); | 282 | print_boot_time(info->load_time, buf, sizeof(buf)); |
234 | 283 | ||
235 | /* Piggy back on load_time, since 0 uid is a valid one */ | 284 | /* Piggy back on load_time, since 0 uid is a valid one */ |
236 | printf("\tloaded_at %s uid %u\n", buf, info.created_by_uid); | 285 | printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid); |
237 | } | 286 | } |
238 | 287 | ||
239 | printf("\txlated %uB", info.xlated_prog_len); | 288 | printf("\txlated %uB", info->xlated_prog_len); |
240 | 289 | ||
241 | if (info.jited_prog_len) | 290 | if (info->jited_prog_len) |
242 | printf(" jited %uB", info.jited_prog_len); | 291 | printf(" jited %uB", info->jited_prog_len); |
243 | else | 292 | else |
244 | printf(" not jited"); | 293 | printf(" not jited"); |
245 | 294 | ||
@@ -248,16 +297,35 @@ static int show_prog(int fd) | |||
248 | printf(" memlock %sB", memlock); | 297 | printf(" memlock %sB", memlock); |
249 | free(memlock); | 298 | free(memlock); |
250 | 299 | ||
251 | if (info.nr_map_ids) | 300 | if (info->nr_map_ids) |
252 | show_prog_maps(fd, info.nr_map_ids); | 301 | show_prog_maps(fd, info->nr_map_ids); |
253 | 302 | ||
254 | printf("\n"); | 303 | printf("\n"); |
304 | } | ||
305 | |||
306 | static int show_prog(int fd) | ||
307 | { | ||
308 | struct bpf_prog_info info = {}; | ||
309 | __u32 len = sizeof(info); | ||
310 | int err; | ||
311 | |||
312 | err = bpf_obj_get_info_by_fd(fd, &info, &len); | ||
313 | if (err) { | ||
314 | err("can't get prog info: %s\n", strerror(errno)); | ||
315 | return -1; | ||
316 | } | ||
317 | |||
318 | if (json_output) | ||
319 | print_prog_json(&info, fd); | ||
320 | else | ||
321 | print_prog_plain(&info, fd); | ||
255 | 322 | ||
256 | return 0; | 323 | return 0; |
257 | } | 324 | } |
258 | 325 | ||
259 | static int do_show(int argc, char **argv) | 326 | static int do_show(int argc, char **argv) |
260 | { __u32 id = 0; | 327 | { |
328 | __u32 id = 0; | ||
261 | int err; | 329 | int err; |
262 | int fd; | 330 | int fd; |
263 | 331 | ||
@@ -272,6 +340,8 @@ static int do_show(int argc, char **argv) | |||
272 | if (argc) | 340 | if (argc) |
273 | return BAD_ARG(); | 341 | return BAD_ARG(); |
274 | 342 | ||
343 | if (json_output) | ||
344 | jsonw_start_array(json_wtr); | ||
275 | while (true) { | 345 | while (true) { |
276 | err = bpf_prog_get_next_id(id, &id); | 346 | err = bpf_prog_get_next_id(id, &id); |
277 | if (err) { | 347 | if (err) { |
@@ -282,23 +352,28 @@ static int do_show(int argc, char **argv) | |||
282 | err("can't get next program: %s\n", strerror(errno)); | 352 | err("can't get next program: %s\n", strerror(errno)); |
283 | if (errno == EINVAL) | 353 | if (errno == EINVAL) |
284 | err("kernel too old?\n"); | 354 | err("kernel too old?\n"); |
285 | return -1; | 355 | err = -1; |
356 | break; | ||
286 | } | 357 | } |
287 | 358 | ||
288 | fd = bpf_prog_get_fd_by_id(id); | 359 | fd = bpf_prog_get_fd_by_id(id); |
289 | if (fd < 0) { | 360 | if (fd < 0) { |
290 | err("can't get prog by id (%u): %s\n", | 361 | err("can't get prog by id (%u): %s\n", |
291 | id, strerror(errno)); | 362 | id, strerror(errno)); |
292 | return -1; | 363 | err = -1; |
364 | break; | ||
293 | } | 365 | } |
294 | 366 | ||
295 | err = show_prog(fd); | 367 | err = show_prog(fd); |
296 | close(fd); | 368 | close(fd); |
297 | if (err) | 369 | if (err) |
298 | return err; | 370 | break; |
299 | } | 371 | } |
300 | 372 | ||
301 | return 0; | 373 | if (json_output) |
374 | jsonw_end_array(json_wtr); | ||
375 | |||
376 | return err; | ||
302 | } | 377 | } |
303 | 378 | ||
304 | static void print_insn(struct bpf_verifier_env *env, const char *fmt, ...) | 379 | static void print_insn(struct bpf_verifier_env *env, const char *fmt, ...) |