Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a5dd4982 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'bpftool-JSON'



Jakub Kicinski says:

====================
tools: bpftool: Add JSON output to bpftool

Quentin says:

This series introduces support for JSON output to all bpftool commands. It
adds option parsing, and several options are created:

  * -j, --json     Switch to JSON output.
  * -p, --pretty   Switch to JSON and print it in a human-friendly fashion.
  * -h, --help     Print generic help message.
  * -V, --version  Print version number.

This code uses a "json_writer", which is a copy of the one written by
Stephen Hemminger in iproute2.
---
I don't know if there is an easy way to share the code for json_write
without copying the file, so I am very open to suggestions on this matter.
====================

Acked-by: default avatarAlexei Starovoitov <ast@kernel.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 4c4fde21 0641c3c8
Loading
Loading
Loading
Loading
+31 −13
Original line number Diff line number Diff line
@@ -10,26 +10,29 @@ tool for inspection and simple manipulation of eBPF maps
SYNOPSIS
========

	**bpftool** **map** *COMMAND*
	**bpftool** [*OPTIONS*] **map** *COMMAND*

	*OPTIONS* := { { **-j** | **--json** } [{ **-p** | **--pretty** }] }

	*COMMANDS* :=
	{ show | dump | update | lookup | getnext | delete | pin | help }
	{ **show** | **dump** | **update** | **lookup** | **getnext** | **delete**
	| **pin** | **help** }

MAP COMMANDS
=============

|	**bpftool** map show   [*MAP*]
|	**bpftool** map dump    *MAP*
|	**bpftool** map update  *MAP*  key *BYTES*   value *VALUE* [*UPDATE_FLAGS*]
|	**bpftool** map lookup  *MAP*  key *BYTES*
|	**bpftool** map getnext *MAP* [key *BYTES*]
|	**bpftool** map delete  *MAP*  key *BYTES*
|	**bpftool** map pin     *MAP*  *FILE*
|	**bpftool** map help
|	**bpftool** **map show**   [*MAP*]
|	**bpftool** **map dump**    *MAP*
|	**bpftool** **map update**  *MAP*  **key** *BYTES*   **value** *VALUE* [*UPDATE_FLAGS*]
|	**bpftool** **map lookup**  *MAP*  **key** *BYTES*
|	**bpftool** **map getnext** *MAP* [**key** *BYTES*]
|	**bpftool** **map delete**  *MAP*  **key** *BYTES*
|	**bpftool** **map pin**     *MAP*  *FILE*
|	**bpftool** **map help**
|
|	*MAP* := { id MAP_ID | pinned FILE }
|	*VALUE* := { BYTES | MAP | PROGRAM }
|	*UPDATE_FLAGS* := { any | exist | noexist }
|	*MAP* := { **id** *MAP_ID* | **pinned** *FILE* }
|	*VALUE* := { *BYTES* | *MAP* | *PROGRAM* }
|	*UPDATE_FLAGS* := { **any** | **exist** | **noexist** }

DESCRIPTION
===========
@@ -68,6 +71,21 @@ DESCRIPTION
	**bpftool map help**
		  Print short help message.

OPTIONS
=======
	-h, --help
		  Print short generic help message (similar to **bpftool help**).

	-v, --version
		  Print version number (similar to **bpftool version**).

	-j, --json
		  Generate JSON output. For commands that cannot produce JSON, this
		  option has no effect.

	-p, --pretty
		  Generate human-readable JSON output. Implies **-j**.

EXAMPLES
========
**# bpftool map show**
+73 −8
Original line number Diff line number Diff line
@@ -10,13 +10,23 @@ tool for inspection and simple manipulation of eBPF progs
SYNOPSIS
========

|	**bpftool** prog show [*PROG*]
|	**bpftool** prog dump xlated *PROG* [{file *FILE* | opcodes }]
|	**bpftool** prog dump jited  *PROG* [{file *FILE* | opcodes }]
|	**bpftool** prog pin *PROG* *FILE*
|	**bpftool** prog help
	**bpftool** [*OPTIONS*] **prog** *COMMAND*

	*OPTIONS* := { { **-j** | **--json** } [{ **-p** | **--pretty** }] }

	*COMMANDS* :=
	{ **show** | **dump xlated** | **dump jited** | **pin** | **help** }

MAP COMMANDS
=============

|	**bpftool** **prog show** [*PROG*]
|	**bpftool** **prog dump xlated** *PROG* [{**file** *FILE* | **opcodes**}]
|	**bpftool** **prog dump jited**  *PROG* [{**file** *FILE* | **opcodes**}]
|	**bpftool** **prog pin** *PROG* *FILE*
|	**bpftool** **prog help**
|
|	*PROG* := { id *PROG_ID* | pinned *FILE* | tag *PROG_TAG* }
|	*PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* }

DESCRIPTION
===========
@@ -50,6 +60,21 @@ DESCRIPTION
	**bpftool prog help**
		  Print short help message.

OPTIONS
=======
	-h, --help
		  Print short generic help message (similar to **bpftool help**).

	-v, --version
		  Print version number (similar to **bpftool version**).

	-j, --json
		  Generate JSON output. For commands that cannot produce JSON, this
		  option has no effect.

	-p, --pretty
		  Generate human-readable JSON output. Implies **-j**.

EXAMPLES
========
**# bpftool prog show**
@@ -59,13 +84,33 @@ EXAMPLES
	loaded_at Sep 29/20:11  uid 0
	xlated 528B  jited 370B  memlock 4096B  map_ids 10

**# bpftool --json --pretty prog show**

::

    {
        "programs": [{
                "id": 10,
                "type": "xdp",
                "tag": "005a3d2123620c8b",
                "loaded_at": "Sep 29/20:11",
                "uid": 0,
                "bytes_xlated": 528,
                "jited": true,
                "bytes_jited": 370,
                "bytes_memlock": 4096,
                "map_ids": [10
                ]
            }
        ]
    }

|
| **# bpftool prog dump xlated id 10 file /tmp/t**
| **# ls -l /tmp/t**
|   -rw------- 1 root root 560 Jul 22 01:42 /tmp/t

|
| **# bpftool prog dum jited pinned /sys/fs/bpf/prog**
**# bpftool prog dum jited tag 005a3d2123620c8b**

::

@@ -75,6 +120,26 @@ EXAMPLES
    sub    $0x28,%rbp
    mov    %rbx,0x0(%rbp)

|
| **# mount -t bpf none /sys/fs/bpf/**
| **# bpftool prog pin id 10 /sys/fs/bpf/prog**
| **# ls -l /sys/fs/bpf/**
|   -rw------- 1 root root 0 Jul 22 01:43 prog

**# bpftool prog dum jited pinned /sys/fs/bpf/prog opcodes**

::

    push   %rbp
    55
    mov    %rsp,%rbp
    48 89 e5
    sub    $0x228,%rsp
    48 81 ec 28 02 00 00
    sub    $0x28,%rbp
    48 83 ed 28
    mov    %rbx,0x0(%rbp)
    48 89 5d 00


SEE ALSO
+25 −5
Original line number Diff line number Diff line
@@ -10,18 +10,23 @@ tool for inspection and simple manipulation of eBPF programs and maps
SYNOPSIS
========

	**bpftool** *OBJECT* { *COMMAND* | help }
	**bpftool** [*OPTIONS*] *OBJECT* { *COMMAND* | **help** }

	**bpftool** batch file *FILE*
	**bpftool** **batch file** *FILE*

	**bpftool** version
	**bpftool** **version**

	*OBJECT* := { **map** | **program** }

	*OPTIONS* := { { **-V** | **--version** } | { **-h** | **--help** }
	| { **-j** | **--json** } [{ **-p** | **--pretty** }] }

	*MAP-COMMANDS* :=
	{ show | dump | update | lookup | getnext | delete | pin | help }
	{ **show** | **dump** | **update** | **lookup** | **getnext** | **delete**
	| **pin** | **help** }

	*PROG-COMMANDS* := { show | dump jited | dump xlated | pin | help }
	*PROG-COMMANDS* := { **show** | **dump jited** | **dump xlated** | **pin**
	| **help** }

DESCRIPTION
===========
@@ -31,6 +36,21 @@ DESCRIPTION
	Note that format of the output of all tools is not guaranteed to be
	stable and should not be depended upon.

OPTIONS
=======
	-h, --help
		  Print short help message (similar to **bpftool help**).

	-v, --version
		  Print version number (similar to **bpftool version**).

	-j, --json
		  Generate JSON output. For commands that cannot produce JSON, this
		  option has no effect.

	-p, --pretty
		  Generate human-readable JSON output. Implies **-j**.

SEE ALSO
========
	**bpftool-map**\ (8), **bpftool-prog**\ (8)
+23 −13
Original line number Diff line number Diff line
@@ -66,7 +66,7 @@ int open_obj_pinned_any(char *path, enum bpf_obj_type exp_type)

	fd = bpf_obj_get(path);
	if (fd < 0) {
		err("bpf obj get (%s): %s\n", path,
		p_err("bpf obj get (%s): %s", path,
		      errno == EACCES && !is_bpffs(dirname(path)) ?
		    "directory not in bpf file system (bpffs)" :
		    strerror(errno));
@@ -79,7 +79,7 @@ int open_obj_pinned_any(char *path, enum bpf_obj_type exp_type)
		return type;
	}
	if (type != exp_type) {
		err("incorrect object type: %s\n", get_fd_type_name(type));
		p_err("incorrect object type: %s", get_fd_type_name(type));
		close(fd);
		return -1;
	}
@@ -95,14 +95,14 @@ int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(__u32))
	int fd;

	if (!is_prefix(*argv, "id")) {
		err("expected 'id' got %s\n", *argv);
		p_err("expected 'id' got %s", *argv);
		return -1;
	}
	NEXT_ARG();

	id = strtoul(*argv, &endptr, 0);
	if (*endptr) {
		err("can't parse %s as ID\n", *argv);
		p_err("can't parse %s as ID", *argv);
		return -1;
	}
	NEXT_ARG();
@@ -112,14 +112,14 @@ int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(__u32))

	fd = get_fd_by_id(id);
	if (fd < 0) {
		err("can't get prog by id (%u): %s\n", id, strerror(errno));
		p_err("can't get prog by id (%u): %s", id, strerror(errno));
		return -1;
	}

	err = bpf_obj_pin(fd, *argv);
	close(fd);
	if (err) {
		err("can't pin the object (%s): %s\n", *argv,
		p_err("can't pin the object (%s): %s", *argv,
		      errno == EACCES && !is_bpffs(dirname(*argv)) ?
		    "directory not in bpf file system (bpffs)" :
		    strerror(errno));
@@ -153,11 +153,11 @@ int get_fd_type(int fd)

	n = readlink(path, buf, sizeof(buf));
	if (n < 0) {
		err("can't read link type: %s\n", strerror(errno));
		p_err("can't read link type: %s", strerror(errno));
		return -1;
	}
	if (n == sizeof(path)) {
		err("can't read link type: path too long!\n");
		p_err("can't read link type: path too long!");
		return -1;
	}

@@ -181,7 +181,7 @@ char *get_fdinfo(int fd, const char *key)

	fdi = fopen(path, "r");
	if (!fdi) {
		err("can't open fdinfo: %s\n", strerror(errno));
		p_err("can't open fdinfo: %s", strerror(errno));
		return NULL;
	}

@@ -196,7 +196,7 @@ char *get_fdinfo(int fd, const char *key)

		value = strchr(line, '\t');
		if (!value || !value[1]) {
			err("malformed fdinfo!?\n");
			p_err("malformed fdinfo!?");
			free(line);
			return NULL;
		}
@@ -209,8 +209,18 @@ char *get_fdinfo(int fd, const char *key)
		return line;
	}

	err("key '%s' not found in fdinfo\n", key);
	p_err("key '%s' not found in fdinfo", key);
	free(line);
	fclose(fdi);
	return NULL;
}

void print_hex_data_json(uint8_t *data, size_t len)
{
	unsigned int i;

	jsonw_start_array(json_wtr);
	for (i = 0; i < len; i++)
		jsonw_printf(json_wtr, "\"0x%02hhx\"", data[i]);
	jsonw_end_array(json_wtr);
}
+80 −6
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
 * Licensed under the GNU General Public License, version 2.0 (GPLv2)
 */

#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -21,6 +22,9 @@
#include <sys/types.h>
#include <sys/stat.h>

#include "json_writer.h"
#include "main.h"

static void get_exec_path(char *tpath, size_t size)
{
	ssize_t len;
@@ -39,6 +43,38 @@ static void get_exec_path(char *tpath, size_t size)
	free(path);
}

static int oper_count;
static int fprintf_json(void *out, const char *fmt, ...)
{
	va_list ap;
	char *s;

	va_start(ap, fmt);
	if (!oper_count) {
		int i;

		s = va_arg(ap, char *);

		/* Strip trailing spaces */
		i = strlen(s) - 1;
		while (s[i] == ' ')
			s[i--] = '\0';

		jsonw_string_field(json_wtr, "operation", s);
		jsonw_name(json_wtr, "operands");
		jsonw_start_array(json_wtr);
		oper_count++;
	} else if (!strcmp(fmt, ",")) {
		   /* Skip */
	} else {
		s = va_arg(ap, char *);
		jsonw_string(json_wtr, s);
		oper_count++;
	}
	va_end(ap);
	return 0;
}

void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes)
{
	disassembler_ftype disassemble;
@@ -57,7 +93,12 @@ void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes)
	assert(bfdf);
	assert(bfd_check_format(bfdf, bfd_object));

	init_disassemble_info(&info, stdout, (fprintf_ftype) fprintf);
	if (json_output)
		init_disassemble_info(&info, stdout,
				      (fprintf_ftype) fprintf_json);
	else
		init_disassemble_info(&info, stdout,
				      (fprintf_ftype) fprintf);
	info.arch = bfd_get_arch(bfdf);
	info.mach = bfd_get_mach(bfdf);
	info.buffer = image;
@@ -68,20 +109,53 @@ void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes)
	disassemble = disassembler(bfdf);
	assert(disassemble);

	if (json_output)
		jsonw_start_array(json_wtr);
	do {
		if (json_output) {
			jsonw_start_object(json_wtr);
			oper_count = 0;
			jsonw_name(json_wtr, "pc");
			jsonw_printf(json_wtr, "\"0x%x\"", pc);
		} else {
			printf("%4x:\t", pc);
		}

		count = disassemble(pc, &info);
		if (json_output) {
			/* Operand array, was started in fprintf_json. Before
			 * that, make sure we have a _null_ value if no operand
			 * other than operation code was present.
			 */
			if (oper_count == 1)
				jsonw_null(json_wtr);
			jsonw_end_array(json_wtr);
		}

		if (opcodes) {
			if (json_output) {
				jsonw_name(json_wtr, "opcodes");
				jsonw_start_array(json_wtr);
				for (i = 0; i < count; ++i)
					jsonw_printf(json_wtr, "\"0x%02hhx\"",
						     (uint8_t)image[pc + i]);
				jsonw_end_array(json_wtr);
			} else {
				printf("\n\t");
				for (i = 0; i < count; ++i)
				printf("%02x ", (uint8_t) image[pc + i]);
					printf("%02x ",
					       (uint8_t)image[pc + i]);
			}
		}
		if (json_output)
			jsonw_end_object(json_wtr);
		else
			printf("\n");

		pc += count;
	} while (count > 0 && pc < len);
	if (json_output)
		jsonw_end_array(json_wtr);

	bfd_close(bfdf);
}
Loading