Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Quentin Monnet and committed by
David S. Miller
743cc665 d35efba9

+111 -36
+111 -36
tools/bpf/bpftool/prog.c
··· 195 195 if (err || !info.nr_map_ids) 196 196 return; 197 197 198 - printf(" map_ids "); 199 - for (i = 0; i < info.nr_map_ids; i++) 200 - printf("%u%s", map_ids[i], 201 - i == info.nr_map_ids - 1 ? "" : ","); 198 + if (json_output) { 199 + jsonw_name(json_wtr, "map_ids"); 200 + jsonw_start_array(json_wtr); 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 214 char *memlock; 209 - int err; 210 215 211 - err = bpf_obj_get_info_by_fd(fd, &info, &len); 212 - if (err) { 213 - err("can't get prog info: %s\n", strerror(errno)); 214 - return -1; 215 - } 216 - 217 - printf("%u: ", info.id); 218 - if (info.type < ARRAY_SIZE(prog_type_name)) 219 - printf("%s ", prog_type_name[info.type]); 216 + jsonw_start_object(json_wtr); 217 + jsonw_uint_field(json_wtr, "id", info->id); 218 + if (info->type < ARRAY_SIZE(prog_type_name)) 219 + jsonw_string_field(json_wtr, "type", 220 + prog_type_name[info->type]); 220 221 else 221 - printf("type %u ", info.type); 222 + jsonw_uint_field(json_wtr, "type", info->type); 222 223 223 - if (*info.name) 224 - printf("name %s ", info.name); 224 + if (*info->name) 225 + jsonw_string_field(json_wtr, "name", info->name); 225 226 226 - printf("tag "); 227 - fprint_hex(stdout, info.tag, BPF_TAG_SIZE, ""); 228 - printf("\n"); 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]); 229 231 230 - if (info.load_time) { 232 + if (info->load_time) { 231 233 char buf[32]; 232 234 233 - print_boot_time(info.load_time, buf, sizeof(buf)); 235 + print_boot_time(info->load_time, buf, sizeof(buf)); 234 236 235 237 /* 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); 238 + jsonw_string_field(json_wtr, "loaded_at", buf); 239 + jsonw_uint_field(json_wtr, "uid", info->created_by_uid); 237 240 } 238 241 239 - printf("\txlated %uB", info.xlated_prog_len); 242 + jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len); 240 243 241 - if (info.jited_prog_len) 242 - printf(" jited %uB", info.jited_prog_len); 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]); 269 + else 270 + printf("type %u ", info->type); 271 + 272 + if (*info->name) 273 + printf("name %s ", info->name); 274 + 275 + printf("tag "); 276 + fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); 277 + printf("\n"); 278 + 279 + if (info->load_time) { 280 + char buf[32]; 281 + 282 + print_boot_time(info->load_time, buf, sizeof(buf)); 283 + 284 + /* Piggy back on load_time, since 0 uid is a valid one */ 285 + printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid); 286 + } 287 + 288 + printf("\txlated %uB", info->xlated_prog_len); 289 + 290 + if (info->jited_prog_len) 291 + printf(" jited %uB", info->jited_prog_len); 243 292 else 244 293 printf(" not jited"); 245 294 ··· 297 248 printf(" memlock %sB", memlock); 298 249 free(memlock); 299 250 300 - if (info.nr_map_ids) 301 - show_prog_maps(fd, info.nr_map_ids); 251 + if (info->nr_map_ids) 252 + show_prog_maps(fd, info->nr_map_ids); 302 253 303 254 printf("\n"); 255 + } 256 + 257 + static int show_prog(int fd) 258 + { 259 + struct bpf_prog_info info = {}; 260 + __u32 len = sizeof(info); 261 + int err; 262 + 263 + err = bpf_obj_get_info_by_fd(fd, &info, &len); 264 + if (err) { 265 + err("can't get prog info: %s\n", strerror(errno)); 266 + return -1; 267 + } 268 + 269 + if (json_output) 270 + print_prog_json(&info, fd); 271 + else 272 + print_prog_plain(&info, fd); 304 273 305 274 return 0; 306 275 } 307 276 308 277 static int do_show(int argc, char **argv) 309 - { __u32 id = 0; 278 + { 279 + __u32 id = 0; 310 280 int err; 311 281 int fd; 312 282 ··· 340 272 if (argc) 341 273 return BAD_ARG(); 342 274 275 + if (json_output) 276 + jsonw_start_array(json_wtr); 343 277 while (true) { 344 278 err = bpf_prog_get_next_id(id, &id); 345 279 if (err) { ··· 352 282 err("can't get next program: %s\n", strerror(errno)); 353 283 if (errno == EINVAL) 354 284 err("kernel too old?\n"); 355 - return -1; 285 + err = -1; 286 + break; 356 287 } 357 288 358 289 fd = bpf_prog_get_fd_by_id(id); 359 290 if (fd < 0) { 360 291 err("can't get prog by id (%u): %s\n", 361 292 id, strerror(errno)); 362 - return -1; 293 + err = -1; 294 + break; 363 295 } 364 296 365 297 err = show_prog(fd); 366 298 close(fd); 367 299 if (err) 368 - return err; 300 + break; 369 301 } 370 302 371 - return 0; 303 + if (json_output) 304 + jsonw_end_array(json_wtr); 305 + 306 + return err; 372 307 } 373 308 374 309 static void print_insn(struct bpf_verifier_env *env, const char *fmt, ...)