From 71bb428fe2c19512ac671d5ee16ef3e73e1b49a8 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 4 Oct 2017 20:10:04 -0700 Subject: tools: bpf: add bpftool Add a simple tool for querying and updating BPF objects on the system. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Acked-by: Daniel Borkmann Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller --- tools/bpf/bpftool/Makefile | 80 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 tools/bpf/bpftool/Makefile (limited to 'tools/bpf/bpftool/Makefile') diff --git a/tools/bpf/bpftool/Makefile b/tools/bpf/bpftool/Makefile new file mode 100644 index 000000000000..a7151f47fb40 --- /dev/null +++ b/tools/bpf/bpftool/Makefile @@ -0,0 +1,80 @@ +include ../../scripts/Makefile.include + +include ../../scripts/utilities.mak + +ifeq ($(srctree),) +srctree := $(patsubst %/,%,$(dir $(CURDIR))) +srctree := $(patsubst %/,%,$(dir $(srctree))) +srctree := $(patsubst %/,%,$(dir $(srctree))) +#$(info Determined 'srctree' to be $(srctree)) +endif + +ifneq ($(objtree),) +#$(info Determined 'objtree' to be $(objtree)) +endif + +ifneq ($(OUTPUT),) +#$(info Determined 'OUTPUT' to be $(OUTPUT)) +# Adding $(OUTPUT) as a directory to look for source files, +# because use generated output files as sources dependency +# for flex/bison parsers. +VPATH += $(OUTPUT) +export VPATH +endif + +ifeq ($(V),1) + Q = +else + Q = @ +endif + +BPF_DIR = $(srctree)/tools/lib/bpf/ + +ifneq ($(OUTPUT),) + BPF_PATH=$(OUTPUT) +else + BPF_PATH=$(BPF_DIR) +endif + +LIBBPF = $(BPF_PATH)libbpf.a + +$(LIBBPF): FORCE + $(Q)$(MAKE) -C $(BPF_DIR) OUTPUT=$(OUTPUT) $(OUTPUT)libbpf.a FEATURES_DUMP=$(FEATURE_DUMP_EXPORT) + +$(LIBBPF)-clean: + $(call QUIET_CLEAN, libbpf) + $(Q)$(MAKE) -C $(BPF_DIR) OUTPUT=$(OUTPUT) clean >/dev/null + +prefix = /usr + +CC = gcc + +CFLAGS += -O2 +CFLAGS += -W -Wall -Wextra -Wno-unused-parameter -Wshadow +CFLAGS += -D__EXPORTED_HEADERS__ -I$(srctree)/tools/include/uapi -I$(srctree)/tools/include -I$(srctree)/tools/lib/bpf +LIBS = -lelf -lbfd -lopcodes $(LIBBPF) + +include $(wildcard *.d) + +all: $(OUTPUT)bpftool + +SRCS=$(wildcard *.c) +OBJS=$(patsubst %.c,$(OUTPUT)%.o,$(SRCS)) + +$(OUTPUT)bpftool: $(OBJS) $(LIBBPF) + $(QUIET_LINK)$(CC) $(CFLAGS) -o $@ $^ $(LIBS) + +$(OUTPUT)%.o: %.c + $(QUIET_CC)$(COMPILE.c) -MMD -o $@ $< + +clean: $(LIBBPF)-clean + $(call QUIET_CLEAN, bpftool) + $(Q)rm -rf $(OUTPUT)bpftool $(OUTPUT)*.o $(OUTPUT)*.d + +install: + install $(OUTPUT)bpftool $(prefix)/sbin/bpftool + +FORCE: + +.PHONY: all clean FORCE +.DEFAULT_GOAL := all -- cgit v1.2.3-59-g8ed1b From ff69c21a85a4ed3d8dcf79dd750a0a9eda4fca83 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 4 Oct 2017 20:10:05 -0700 Subject: tools: bpftool: add documentation Add documentation for bpftool. Separate files for each subcommand. Use rst format. Documentation is compiled into man pages using rst2man. Signed-off-by: David Beckett Signed-off-by: Jakub Kicinski Acked-by: Alexei Starovoitov Acked-by: Daniel Borkmann Signed-off-by: David S. Miller --- tools/bpf/bpftool/Documentation/Makefile | 34 +++++++ tools/bpf/bpftool/Documentation/bpftool-map.rst | 110 +++++++++++++++++++++++ tools/bpf/bpftool/Documentation/bpftool-prog.rst | 79 ++++++++++++++++ tools/bpf/bpftool/Documentation/bpftool.rst | 34 +++++++ tools/bpf/bpftool/Makefile | 6 ++ 5 files changed, 263 insertions(+) create mode 100644 tools/bpf/bpftool/Documentation/Makefile create mode 100644 tools/bpf/bpftool/Documentation/bpftool-map.rst create mode 100644 tools/bpf/bpftool/Documentation/bpftool-prog.rst create mode 100644 tools/bpf/bpftool/Documentation/bpftool.rst (limited to 'tools/bpf/bpftool/Makefile') diff --git a/tools/bpf/bpftool/Documentation/Makefile b/tools/bpf/bpftool/Documentation/Makefile new file mode 100644 index 000000000000..bde77d7c4390 --- /dev/null +++ b/tools/bpf/bpftool/Documentation/Makefile @@ -0,0 +1,34 @@ +include ../../../scripts/Makefile.include +include ../../../scripts/utilities.mak + +INSTALL ?= install +RM ?= rm -f + +# Make the path relative to DESTDIR, not prefix +ifndef DESTDIR +prefix?=$(HOME) +endif +mandir ?= $(prefix)/share/man +man8dir = $(mandir)/man8 + +MAN8_RST = $(wildcard *.rst) + +_DOC_MAN8 = $(patsubst %.rst,%.8,$(MAN8_RST)) +DOC_MAN8 = $(addprefix $(OUTPUT),$(_DOC_MAN8)) + +man: man8 +man8: $(DOC_MAN8) + +$(OUTPUT)%.8: %.rst + rst2man $< > $@ + +clean: + $(call QUIET_CLEAN, Documentation) $(RM) $(DOC_MAN8) + +install: man + $(call QUIET_INSTALL, Documentation-man) \ + $(INSTALL) -d -m 755 $(DESTDIR)$(man8dir); \ + $(INSTALL) -m 644 $(DOC_MAN8) $(DESTDIR)$(man8dir); + +.PHONY: man man8 clean install +.DEFAULT_GOAL := man diff --git a/tools/bpf/bpftool/Documentation/bpftool-map.rst b/tools/bpf/bpftool/Documentation/bpftool-map.rst new file mode 100644 index 000000000000..ff63e89e4b6c --- /dev/null +++ b/tools/bpf/bpftool/Documentation/bpftool-map.rst @@ -0,0 +1,110 @@ +================ +bpftool-map +================ +------------------------------------------------------------------------------- +tool for inspection and simple manipulation of eBPF maps +------------------------------------------------------------------------------- + +:Manual section: 8 + +SYNOPSIS +======== + + **bpftool** **map** *COMMAND* + + *COMMANDS* := + { 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 +| +| *MAP* := { id MAP_ID | pinned FILE } +| *VALUE* := { BYTES | MAP | PROGRAM } +| *UPDATE_FLAGS* := { any | exist | noexist } + +DESCRIPTION +=========== + **bpftool map show** [*MAP*] + Show information about loaded maps. If *MAP* is specified + show information only about given map, otherwise list all + maps currently loaded on the system. + + Output will start with map ID followed by map type and + zero or more named attributes (depending on kernel version). + + **bpftool map dump** *MAP* + Dump all entries in a given *MAP*. + + **bpftool map update** *MAP* **key** *BYTES* **value** *VALUE* [*UPDATE_FLAGS*] + Update map entry for a given *KEY*. + + *UPDATE_FLAGS* can be one of: **any** update existing entry + or add if doesn't exit; **exist** update only if entry already + exists; **noexist** update only if entry doesn't exist. + + **bpftool map lookup** *MAP* **key** *BYTES* + Lookup **key** in the map. + + **bpftool map getnext** *MAP* [**key** *BYTES*] + Get next key. If *key* is not specified, get first key. + + **bpftool map delete** *MAP* **key** *BYTES* + Remove entry from the map. + + **bpftool map pin** *MAP* *FILE* + Pin map *MAP* as *FILE*. + + Note: *FILE* must be located in *bpffs* mount. + + **bpftool map help** + Print short help message. + +EXAMPLES +======== +**# bpftool map show** +:: + + 10: hash name some_map flags 0x0 + key 4B value 8B max_entries 2048 memlock 167936B + +**# bpftool map update id 10 key 13 00 07 00 value 02 00 00 00 01 02 03 04** + +**# bpftool map lookup id 10 key 0 1 2 3** + +:: + + key: 00 01 02 03 value: 00 01 02 03 04 05 06 07 + + +**# bpftool map dump id 10** +:: + + key: 00 01 02 03 value: 00 01 02 03 04 05 06 07 + key: 0d 00 07 00 value: 02 00 00 00 01 02 03 04 + Found 2 elements + +**# bpftool map getnext id 10 key 0 1 2 3** +:: + + key: + 00 01 02 03 + next key: + 0d 00 07 00 + +| +| **# mount -t bpf none /sys/fs/bpf/** +| **# bpftool map pin id 10 /sys/fs/bpf/map** +| **# bpftool map del pinned /sys/fs/bpf/map key 13 00 07 00** + +SEE ALSO +======== + **bpftool**\ (8), **bpftool-prog**\ (8) diff --git a/tools/bpf/bpftool/Documentation/bpftool-prog.rst b/tools/bpf/bpftool/Documentation/bpftool-prog.rst new file mode 100644 index 000000000000..57fc4b9924ea --- /dev/null +++ b/tools/bpf/bpftool/Documentation/bpftool-prog.rst @@ -0,0 +1,79 @@ +================ +bpftool-prog +================ +------------------------------------------------------------------------------- +tool for inspection and simple manipulation of eBPF progs +------------------------------------------------------------------------------- + +:Manual section: 8 + +SYNOPSIS +======== + +| **bpftool** prog show [*PROG*] +| **bpftool** prog dump xlated *PROG* file *FILE* +| **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* } + +DESCRIPTION +=========== + **bpftool prog show** [*PROG*] + Show information about loaded programs. If *PROG* is + specified show information only about given program, otherwise + list all programs currently loaded on the system. + + Output will start with program ID followed by program type and + zero or more named attributes (depending on kernel version). + + **bpftool prog dump xlated** *PROG* **file** *FILE* + Dump eBPF instructions of the program from the kernel to a + file. + + **bpftool prog dump jited** *PROG* [**file** *FILE*] [**opcodes**] + Dump jited image (host machine code) of the program. + If *FILE* is specified image will be written to a file, + otherwise it will be disassembled and printed to stdout. + + **opcodes** controls if raw opcodes will be printed. + + **bpftool prog pin** *PROG* *FILE* + Pin program *PROG* as *FILE*. + + Note: *FILE* must be located in *bpffs* mount. + + **bpftool prog help** + Print short help message. + +EXAMPLES +======== +**# bpftool prog show** +:: + + 10: xdp name some_prog tag 00:5a:3d:21:23:62:0c:8b + loaded_at Sep 29/20:11 uid 0 + xlated 528B jited 370B memlock 4096B 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** + +:: + + push %rbp + mov %rsp,%rbp + sub $0x228,%rsp + sub $0x28,%rbp + mov %rbx,0x0(%rbp) + + + +SEE ALSO +======== + **bpftool**\ (8), **bpftool-map**\ (8) diff --git a/tools/bpf/bpftool/Documentation/bpftool.rst b/tools/bpf/bpftool/Documentation/bpftool.rst new file mode 100644 index 000000000000..f1df1893fb54 --- /dev/null +++ b/tools/bpf/bpftool/Documentation/bpftool.rst @@ -0,0 +1,34 @@ +================ +BPFTOOL +================ +------------------------------------------------------------------------------- +tool for inspection and simple manipulation of eBPF programs and maps +------------------------------------------------------------------------------- + +:Manual section: 8 + +SYNOPSIS +======== + + **bpftool** *OBJECT* { *COMMAND* | help } + + **bpftool** batch file *FILE* + + *OBJECT* := { **map** | **program** } + + *MAP-COMMANDS* := + { show | dump | update | lookup | getnext | delete | pin | help } + + *PROG-COMMANDS* := { show | dump jited | dump xlated | pin | help } + +DESCRIPTION +=========== + *bpftool* allows for inspection and simple modification of BPF objects + on the system. + + Note that format of the output of all tools is not guaranteed to be + stable and should not be depended upon. + +SEE ALSO +======== + **bpftool-map**\ (8), **bpftool-prog**\ (8) diff --git a/tools/bpf/bpftool/Makefile b/tools/bpf/bpftool/Makefile index a7151f47fb40..8705ee44664d 100644 --- a/tools/bpf/bpftool/Makefile +++ b/tools/bpf/bpftool/Makefile @@ -74,6 +74,12 @@ clean: $(LIBBPF)-clean install: install $(OUTPUT)bpftool $(prefix)/sbin/bpftool +doc: + $(Q)$(MAKE) -C Documentation/ + +doc-install: + $(Q)$(MAKE) -C Documentation/ install + FORCE: .PHONY: all clean FORCE -- cgit v1.2.3-59-g8ed1b From c9c35995bcf812ee8136f634c25bc6ccc3021d4c Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 9 Oct 2017 10:30:13 -0700 Subject: tools: bpftool: use the kernel's instruction printer Compile the instruction printer from kernel/bpf and use it for disassembling "translated" eBPF code. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Acked-by: Alexei Starovoitov Acked-by: Daniel Borkmann Signed-off-by: David S. Miller --- tools/bpf/bpftool/Documentation/bpftool-prog.rst | 11 +++--- tools/bpf/bpftool/Makefile | 7 ++-- tools/bpf/bpftool/main.h | 10 ++---- tools/bpf/bpftool/prog.c | 44 +++++++++++++++++++----- 4 files changed, 51 insertions(+), 21 deletions(-) (limited to 'tools/bpf/bpftool/Makefile') diff --git a/tools/bpf/bpftool/Documentation/bpftool-prog.rst b/tools/bpf/bpftool/Documentation/bpftool-prog.rst index 57fc4b9924ea..04d12f768f06 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-prog.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-prog.rst @@ -11,7 +11,7 @@ SYNOPSIS ======== | **bpftool** prog show [*PROG*] -| **bpftool** prog dump xlated *PROG* file *FILE* +| **bpftool** prog dump xlated *PROG* [file *FILE*] [opcodes] | **bpftool** prog dump jited *PROG* [file *FILE*] [opcodes] | **bpftool** prog pin *PROG* *FILE* | **bpftool** prog help @@ -28,9 +28,12 @@ DESCRIPTION Output will start with program ID followed by program type and zero or more named attributes (depending on kernel version). - **bpftool prog dump xlated** *PROG* **file** *FILE* - Dump eBPF instructions of the program from the kernel to a - file. + **bpftool prog dump xlated** *PROG* [**file** *FILE*] [**opcodes**] + Dump eBPF instructions of the program from the kernel. + If *FILE* is specified image will be written to a file, + otherwise it will be disassembled and printed to stdout. + + **opcodes** controls if raw opcodes will be printed. **bpftool prog dump jited** *PROG* [**file** *FILE*] [**opcodes**] Dump jited image (host machine code) of the program. diff --git a/tools/bpf/bpftool/Makefile b/tools/bpf/bpftool/Makefile index 8705ee44664d..4f339824ca57 100644 --- a/tools/bpf/bpftool/Makefile +++ b/tools/bpf/bpftool/Makefile @@ -51,7 +51,7 @@ CC = gcc CFLAGS += -O2 CFLAGS += -W -Wall -Wextra -Wno-unused-parameter -Wshadow -CFLAGS += -D__EXPORTED_HEADERS__ -I$(srctree)/tools/include/uapi -I$(srctree)/tools/include -I$(srctree)/tools/lib/bpf +CFLAGS += -D__EXPORTED_HEADERS__ -I$(srctree)/tools/include/uapi -I$(srctree)/tools/include -I$(srctree)/tools/lib/bpf -I$(srctree)/kernel/bpf/ LIBS = -lelf -lbfd -lopcodes $(LIBBPF) include $(wildcard *.d) @@ -59,7 +59,10 @@ include $(wildcard *.d) all: $(OUTPUT)bpftool SRCS=$(wildcard *.c) -OBJS=$(patsubst %.c,$(OUTPUT)%.o,$(SRCS)) +OBJS=$(patsubst %.c,$(OUTPUT)%.o,$(SRCS)) $(OUTPUT)disasm.o + +$(OUTPUT)disasm.o: $(srctree)/kernel/bpf/disasm.c + $(QUIET_CC)$(COMPILE.c) -MMD -o $@ $< $(OUTPUT)bpftool: $(OBJS) $(LIBBPF) $(QUIET_LINK)$(CC) $(CFLAGS) -o $@ $^ $(LIBS) diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h index 85d2d7870a58..8e809b2bb311 100644 --- a/tools/bpf/bpftool/main.h +++ b/tools/bpf/bpftool/main.h @@ -36,11 +36,12 @@ #ifndef __BPF_TOOL_H #define __BPF_TOOL_H +/* BFD and kernel.h both define GCC_VERSION, differently */ +#undef GCC_VERSION #include #include #include - -#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) +#include #define err(msg...) fprintf(stderr, "Error: " msg) #define warn(msg...) fprintf(stderr, "Warning: " msg) @@ -48,11 +49,6 @@ #define ptr_to_u64(ptr) ((__u64)(unsigned long)(ptr)) -#define min(a, b) \ - ({ typeof(a) _a = (a); typeof(b) _b = (b); _a > _b ? _b : _a; }) -#define max(a, b) \ - ({ typeof(a) _a = (a); typeof(b) _b = (b); _a < _b ? _b : _a; }) - #define NEXT_ARG() ({ argc--; argv++; if (argc < 0) usage(); }) #define NEXT_ARGP() ({ (*argc)--; (*argv)++; if (*argc < 0) usage(); }) #define BAD_ARG() ({ err("what is '%s'?\n", *argv); -1; }) diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c index 421ba89ce86a..9e2681c83717 100644 --- a/tools/bpf/bpftool/prog.c +++ b/tools/bpf/bpftool/prog.c @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -46,6 +47,7 @@ #include #include "main.h" +#include "disasm.h" static const char * const prog_type_name[] = { [BPF_PROG_TYPE_UNSPEC] = "unspec", @@ -297,11 +299,39 @@ static int do_show(int argc, char **argv) return 0; } +static void print_insn(struct bpf_verifier_env *env, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); +} + +static void dump_xlated(void *buf, unsigned int len, bool opcodes) +{ + struct bpf_insn *insn = buf; + unsigned int i; + + for (i = 0; i < len / sizeof(*insn); i++) { + printf("% 4d: ", i); + print_bpf_insn(print_insn, NULL, insn + i, true); + + if (opcodes) { + printf(" "); + print_hex(insn + i, 8, " "); + printf("\n"); + } + + if (insn[i].code == (BPF_LD | BPF_IMM | BPF_DW)) + i++; + } +} + static int do_dump(int argc, char **argv) { struct bpf_prog_info info = {}; __u32 len = sizeof(info); - bool can_disasm = false; unsigned int buf_size; char *filepath = NULL; bool opcodes = false; @@ -315,7 +345,6 @@ static int do_dump(int argc, char **argv) if (is_prefix(*argv, "jited")) { member_len = &info.jited_prog_len; member_ptr = &info.jited_prog_insns; - can_disasm = true; } else if (is_prefix(*argv, "xlated")) { member_len = &info.xlated_prog_len; member_ptr = &info.xlated_prog_insns; @@ -346,10 +375,6 @@ static int do_dump(int argc, char **argv) NEXT_ARG(); } - if (!filepath && !can_disasm) { - err("expected 'file' got %s\n", *argv); - return -1; - } if (argc) { usage(); return -1; @@ -409,7 +434,10 @@ static int do_dump(int argc, char **argv) goto err_free; } } else { - disasm_print_insn(buf, *member_len, opcodes); + if (member_len == &info.jited_prog_len) + disasm_print_insn(buf, *member_len, opcodes); + else + dump_xlated(buf, *member_len, opcodes); } free(buf); @@ -430,7 +458,7 @@ static int do_help(int argc, char **argv) { fprintf(stderr, "Usage: %s %s show [PROG]\n" - " %s %s dump xlated PROG file FILE\n" + " %s %s dump xlated PROG [file FILE] [opcodes]\n" " %s %s dump jited PROG [file FILE] [opcodes]\n" " %s %s pin PROG FILE\n" " %s %s help\n" -- cgit v1.2.3-59-g8ed1b From 995231c820e3bd3633cb38bf4ea6f2541e1da331 Mon Sep 17 00:00:00 2001 From: Quentin Monnet Date: Thu, 26 Oct 2017 14:16:05 -0700 Subject: tools: bpftool: add bash completion for bpftool Add a completion file for bash. The completion function runs bpftool when needed, making it smart enough to help users complete ids or tags for eBPF programs and maps currently on the system. Update Makefile to install completion file to /usr/share/bash-completion/completions when running `make install`. Emacs file mode and (at the end) Vim modeline have been added, to keep the style in use for most existing bash completion files. In this, it differs from tools/perf/perf-completion.sh, which seems to be the only other completion file among the kernel sources repository. This is also valid for indent style: 4-space indents, as in other completion files. Signed-off-by: Quentin Monnet Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- tools/bpf/bpftool/Makefile | 3 + tools/bpf/bpftool/bash-completion/bpftool | 354 ++++++++++++++++++++++++++++++ 2 files changed, 357 insertions(+) create mode 100644 tools/bpf/bpftool/bash-completion/bpftool (limited to 'tools/bpf/bpftool/Makefile') diff --git a/tools/bpf/bpftool/Makefile b/tools/bpf/bpftool/Makefile index 4f339824ca57..813826c50936 100644 --- a/tools/bpf/bpftool/Makefile +++ b/tools/bpf/bpftool/Makefile @@ -46,6 +46,7 @@ $(LIBBPF)-clean: $(Q)$(MAKE) -C $(BPF_DIR) OUTPUT=$(OUTPUT) clean >/dev/null prefix = /usr +bash_compdir ?= $(prefix)/share/bash-completion/completions CC = gcc @@ -76,6 +77,8 @@ clean: $(LIBBPF)-clean install: install $(OUTPUT)bpftool $(prefix)/sbin/bpftool + install -m 0755 -d $(bash_compdir) + install -m 0644 bash-completion/bpftool $(bash_compdir) doc: $(Q)$(MAKE) -C Documentation/ diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool new file mode 100644 index 000000000000..7febee05c8e7 --- /dev/null +++ b/tools/bpf/bpftool/bash-completion/bpftool @@ -0,0 +1,354 @@ +# bpftool(8) bash completion -*- shell-script -*- +# +# Copyright (C) 2017 Netronome Systems, Inc. +# +# This software is dual licensed under the GNU General License +# Version 2, June 1991 as shown in the file COPYING in the top-level +# directory of this source tree or the BSD 2-Clause License provided +# below. You have the option to license this software under the +# complete terms of either license. +# +# The BSD 2-Clause License: +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# 1. Redistributions of source code must retain the above +# copyright notice, this list of conditions and the following +# disclaimer. +# +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials +# provided with the distribution. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# Author: Quentin Monnet + +# Takes a list of words in argument; each one of them is added to COMPREPLY if +# it is not already present on the command line. Returns no value. +_bpftool_once_attr() +{ + local w idx found + for w in $*; do + found=0 + for (( idx=3; idx < ${#words[@]}-1; idx++ )); do + if [[ $w == ${words[idx]} ]]; then + found=1 + break + fi + done + [[ $found -eq 0 ]] && \ + COMPREPLY+=( $( compgen -W "$w" -- "$cur" ) ) + done +} + +# Takes a list of words in argument; adds them all to COMPREPLY if none of them +# is already present on the command line. Returns no value. +_bpftool_one_of_list() +{ + local w idx + for w in $*; do + for (( idx=3; idx < ${#words[@]}-1; idx++ )); do + [[ $w == ${words[idx]} ]] && return 1 + done + done + COMPREPLY+=( $( compgen -W "$*" -- "$cur" ) ) +} + +_bpftool_get_map_ids() +{ + COMPREPLY+=( $( compgen -W "$( bpftool -jp map 2>&1 | \ + command sed -n 's/.*"id": \(.*\),$/\1/p' )" -- "$cur" ) ) +} + +_bpftool_get_prog_ids() +{ + COMPREPLY+=( $( compgen -W "$( bpftool -jp prog 2>&1 | \ + command sed -n 's/.*"id": \(.*\),$/\1/p' )" -- "$cur" ) ) +} + +_bpftool_get_prog_tags() +{ + COMPREPLY+=( $( compgen -W "$( bpftool -jp prog 2>&1 | \ + command sed -n 's/.*"tag": "\(.*\)",$/\1/p' )" -- "$cur" ) ) +} + +# For bpftool map update: retrieve type of the map to update. +_bpftool_map_update_map_type() +{ + local keyword ref + for (( idx=3; idx < ${#words[@]}-1; idx++ )); do + if [[ ${words[$((idx-2))]} == "update" ]]; then + keyword=${words[$((idx-1))]} + ref=${words[$((idx))]} + fi + done + [[ -z $ref ]] && return 0 + + local type + type=$(bpftool -jp map show $keyword $ref | \ + command sed -n 's/.*"type": "\(.*\)",$/\1/p') + printf $type +} + +_bpftool_map_update_get_id() +{ + # Is it the map to update, or a map to insert into the map to update? + # Search for "value" keyword. + local idx value + for (( idx=7; idx < ${#words[@]}-1; idx++ )); do + if [[ ${words[idx]} == "value" ]]; then + value=1 + break + fi + done + [[ $value -eq 0 ]] && _bpftool_get_map_ids && return 0 + + # Id to complete is for a value. It can be either prog id or map id. This + # depends on the type of the map to update. + local type=$(_bpftool_map_update_map_type) + case $type in + array_of_maps|hash_of_maps) + _bpftool_get_map_ids + return 0 + ;; + prog_array) + _bpftool_get_prog_ids + return 0 + ;; + *) + return 0 + ;; + esac +} + +_bpftool() +{ + local cur prev words objword + _init_completion || return + + # Deal with simplest keywords + case $prev in + help|key|opcodes) + return 0 + ;; + tag) + _bpftool_get_prog_tags + return 0 + ;; + file|pinned) + _filedir + return 0 + ;; + batch) + COMPREPLY=( $( compgen -W 'file' -- "$cur" ) ) + return 0 + ;; + esac + + # Search for object and command + local object command cmdword + for (( cmdword=1; cmdword < ${#words[@]}-1; cmdword++ )); do + [[ -n $object ]] && command=${words[cmdword]} && break + [[ ${words[cmdword]} != -* ]] && object=${words[cmdword]} + done + + if [[ -z $object ]]; then + case $cur in + -*) + local c='--version --json --pretty' + COMPREPLY=( $( compgen -W "$c" -- "$cur" ) ) + return 0 + ;; + *) + COMPREPLY=( $( compgen -W "$( bpftool help 2>&1 | \ + command sed \ + -e '/OBJECT := /!d' \ + -e 's/.*{//' \ + -e 's/}.*//' \ + -e 's/|//g' )" -- "$cur" ) ) + COMPREPLY+=( $( compgen -W 'batch help' -- "$cur" ) ) + return 0 + ;; + esac + fi + + [[ $command == help ]] && return 0 + + # Completion depends on object and command in use + case $object in + prog) + case $prev in + id) + _bpftool_get_prog_ids + return 0 + ;; + esac + + local PROG_TYPE='id pinned tag' + case $command in + show) + [[ $prev != "$command" ]] && return 0 + COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) ) + return 0 + ;; + dump) + case $prev in + $command) + COMPREPLY+=( $( compgen -W "xlated jited" -- \ + "$cur" ) ) + return 0 + ;; + xlated|jited) + COMPREPLY=( $( compgen -W "$PROG_TYPE" -- \ + "$cur" ) ) + return 0 + ;; + *) + _bpftool_once_attr 'file' + COMPREPLY+=( $( compgen -W 'opcodes' -- \ + "$cur" ) ) + return 0 + ;; + esac + ;; + pin) + if [[ $prev == "$command" ]]; then + COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) ) + else + _filedir + fi + return 0 + ;; + *) + [[ $prev == $object ]] && \ + COMPREPLY=( $( compgen -W 'dump help pin show' -- \ + "$cur" ) ) + ;; + esac + ;; + map) + local MAP_TYPE='id pinned' + case $command in + show|dump) + case $prev in + $command) + COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) ) + return 0 + ;; + id) + _bpftool_get_map_ids + return 0 + ;; + *) + return 0 + ;; + esac + ;; + lookup|getnext|delete) + case $prev in + $command) + COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) ) + return 0 + ;; + id) + _bpftool_get_map_ids + return 0 + ;; + key) + return 0 + ;; + *) + _bpftool_once_attr 'key' + return 0 + ;; + esac + ;; + update) + case $prev in + $command) + COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) ) + return 0 + ;; + id) + _bpftool_map_update_get_id + return 0 + ;; + key) + return 0 + ;; + value) + # We can have bytes, or references to a prog or a + # map, depending on the type of the map to update. + case $(_bpftool_map_update_map_type) in + array_of_maps|hash_of_maps) + local MAP_TYPE='id pinned' + COMPREPLY+=( $( compgen -W "$MAP_TYPE" \ + -- "$cur" ) ) + return 0 + ;; + prog_array) + local PROG_TYPE='id pinned tag' + COMPREPLY+=( $( compgen -W "$PROG_TYPE" \ + -- "$cur" ) ) + return 0 + ;; + *) + return 0 + ;; + esac + return 0 + ;; + *) + _bpftool_once_attr 'key' + local UPDATE_FLAGS='any exist noexist' + for (( idx=3; idx < ${#words[@]}-1; idx++ )); do + if [[ ${words[idx]} == 'value' ]]; then + # 'value' is present, but is not the last + # word i.e. we can now have UPDATE_FLAGS. + _bpftool_one_of_list "$UPDATE_FLAGS" + return 0 + fi + done + for (( idx=3; idx < ${#words[@]}-1; idx++ )); do + if [[ ${words[idx]} == 'key' ]]; then + # 'key' is present, but is not the last + # word i.e. we can now have 'value'. + _bpftool_once_attr 'value' + return 0 + fi + done + return 0 + ;; + esac + ;; + pin) + if [[ $prev == "$command" ]]; then + COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) ) + else + _filedir + fi + return 0 + ;; + *) + [[ $prev == $object ]] && \ + COMPREPLY=( $( compgen -W 'delete dump getnext help \ + lookup pin show update' -- "$cur" ) ) + ;; + esac + ;; + esac +} && +complete -F _bpftool bpftool + +# ex: ts=4 sw=4 et filetype=sh -- cgit v1.2.3-59-g8ed1b