diff options
author | Ingo Molnar <mingo@kernel.org> | 2017-12-06 16:39:39 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2017-12-06 16:39:39 -0500 |
commit | d6eabce2577a695197e9433302fd6a9f0e1a7666 (patch) | |
tree | e5c5bcc7803879d5d911cc8faeb74a946c242395 /tools | |
parent | 6e948c67c47211afcc65c9ccdeedbd5db5c57077 (diff) | |
parent | 328b4ed93b69a6f2083d52f31a240a09e5de386a (diff) |
Merge branch 'linus' into perf/urgent, to synchronize UAPI headers
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools')
184 files changed, 13161 insertions, 1640 deletions
diff --git a/tools/Makefile b/tools/Makefile index c4f41ef9a7a7..be02c8b904db 100644 --- a/tools/Makefile +++ b/tools/Makefile | |||
@@ -20,7 +20,7 @@ help: | |||
20 | @echo ' kvm_stat - top-like utility for displaying kvm statistics' | 20 | @echo ' kvm_stat - top-like utility for displaying kvm statistics' |
21 | @echo ' leds - LEDs tools' | 21 | @echo ' leds - LEDs tools' |
22 | @echo ' liblockdep - user-space wrapper for kernel locking-validator' | 22 | @echo ' liblockdep - user-space wrapper for kernel locking-validator' |
23 | @echo ' net - misc networking tools' | 23 | @echo ' bpf - misc BPF tools' |
24 | @echo ' perf - Linux performance measurement and analysis tool' | 24 | @echo ' perf - Linux performance measurement and analysis tool' |
25 | @echo ' selftests - various kernel selftests' | 25 | @echo ' selftests - various kernel selftests' |
26 | @echo ' spi - spi tools' | 26 | @echo ' spi - spi tools' |
@@ -30,6 +30,7 @@ help: | |||
30 | @echo ' usb - USB testing tools' | 30 | @echo ' usb - USB testing tools' |
31 | @echo ' virtio - vhost test module' | 31 | @echo ' virtio - vhost test module' |
32 | @echo ' vm - misc vm tools' | 32 | @echo ' vm - misc vm tools' |
33 | @echo ' wmi - WMI interface examples' | ||
33 | @echo ' x86_energy_perf_policy - Intel energy policy tool' | 34 | @echo ' x86_energy_perf_policy - Intel energy policy tool' |
34 | @echo '' | 35 | @echo '' |
35 | @echo 'You can do:' | 36 | @echo 'You can do:' |
@@ -58,7 +59,7 @@ acpi: FORCE | |||
58 | cpupower: FORCE | 59 | cpupower: FORCE |
59 | $(call descend,power/$@) | 60 | $(call descend,power/$@) |
60 | 61 | ||
61 | cgroup firewire hv guest spi usb virtio vm net iio gpio objtool leds: FORCE | 62 | cgroup firewire hv guest spi usb virtio vm bpf iio gpio objtool leds wmi: FORCE |
62 | $(call descend,$@) | 63 | $(call descend,$@) |
63 | 64 | ||
64 | liblockdep: FORCE | 65 | liblockdep: FORCE |
@@ -92,8 +93,8 @@ kvm_stat: FORCE | |||
92 | 93 | ||
93 | all: acpi cgroup cpupower gpio hv firewire liblockdep \ | 94 | all: acpi cgroup cpupower gpio hv firewire liblockdep \ |
94 | perf selftests spi turbostat usb \ | 95 | perf selftests spi turbostat usb \ |
95 | virtio vm net x86_energy_perf_policy \ | 96 | virtio vm bpf x86_energy_perf_policy \ |
96 | tmon freefall iio objtool kvm_stat | 97 | tmon freefall iio objtool kvm_stat wmi |
97 | 98 | ||
98 | acpi_install: | 99 | acpi_install: |
99 | $(call descend,power/$(@:_install=),install) | 100 | $(call descend,power/$(@:_install=),install) |
@@ -101,7 +102,7 @@ acpi_install: | |||
101 | cpupower_install: | 102 | cpupower_install: |
102 | $(call descend,power/$(@:_install=),install) | 103 | $(call descend,power/$(@:_install=),install) |
103 | 104 | ||
104 | cgroup_install firewire_install gpio_install hv_install iio_install perf_install spi_install usb_install virtio_install vm_install net_install objtool_install: | 105 | cgroup_install firewire_install gpio_install hv_install iio_install perf_install spi_install usb_install virtio_install vm_install bpf_install objtool_install wmi_install: |
105 | $(call descend,$(@:_install=),install) | 106 | $(call descend,$(@:_install=),install) |
106 | 107 | ||
107 | liblockdep_install: | 108 | liblockdep_install: |
@@ -125,8 +126,9 @@ kvm_stat_install: | |||
125 | install: acpi_install cgroup_install cpupower_install gpio_install \ | 126 | install: acpi_install cgroup_install cpupower_install gpio_install \ |
126 | hv_install firewire_install iio_install liblockdep_install \ | 127 | hv_install firewire_install iio_install liblockdep_install \ |
127 | perf_install selftests_install turbostat_install usb_install \ | 128 | perf_install selftests_install turbostat_install usb_install \ |
128 | virtio_install vm_install net_install x86_energy_perf_policy_install \ | 129 | virtio_install vm_install bpf_install x86_energy_perf_policy_install \ |
129 | tmon_install freefall_install objtool_install kvm_stat_install | 130 | tmon_install freefall_install objtool_install kvm_stat_install \ |
131 | wmi_install | ||
130 | 132 | ||
131 | acpi_clean: | 133 | acpi_clean: |
132 | $(call descend,power/acpi,clean) | 134 | $(call descend,power/acpi,clean) |
@@ -134,7 +136,7 @@ acpi_clean: | |||
134 | cpupower_clean: | 136 | cpupower_clean: |
135 | $(call descend,power/cpupower,clean) | 137 | $(call descend,power/cpupower,clean) |
136 | 138 | ||
137 | cgroup_clean hv_clean firewire_clean spi_clean usb_clean virtio_clean vm_clean net_clean iio_clean gpio_clean objtool_clean leds_clean: | 139 | cgroup_clean hv_clean firewire_clean spi_clean usb_clean virtio_clean vm_clean wmi_clean bpf_clean iio_clean gpio_clean objtool_clean leds_clean: |
138 | $(call descend,$(@:_clean=),clean) | 140 | $(call descend,$(@:_clean=),clean) |
139 | 141 | ||
140 | liblockdep_clean: | 142 | liblockdep_clean: |
@@ -170,8 +172,8 @@ build_clean: | |||
170 | 172 | ||
171 | clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean \ | 173 | clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean \ |
172 | perf_clean selftests_clean turbostat_clean spi_clean usb_clean virtio_clean \ | 174 | perf_clean selftests_clean turbostat_clean spi_clean usb_clean virtio_clean \ |
173 | vm_clean net_clean iio_clean x86_energy_perf_policy_clean tmon_clean \ | 175 | vm_clean bpf_clean iio_clean x86_energy_perf_policy_clean tmon_clean \ |
174 | freefall_clean build_clean libbpf_clean libsubcmd_clean liblockdep_clean \ | 176 | freefall_clean build_clean libbpf_clean libsubcmd_clean liblockdep_clean \ |
175 | gpio_clean objtool_clean leds_clean | 177 | gpio_clean objtool_clean leds_clean wmi_clean |
176 | 178 | ||
177 | .PHONY: FORCE | 179 | .PHONY: FORCE |
diff --git a/tools/net/Makefile b/tools/bpf/Makefile index 5830670feae1..07a6697466ef 100644 --- a/tools/net/Makefile +++ b/tools/bpf/Makefile | |||
@@ -4,6 +4,7 @@ prefix = /usr | |||
4 | CC = gcc | 4 | CC = gcc |
5 | LEX = flex | 5 | LEX = flex |
6 | YACC = bison | 6 | YACC = bison |
7 | MAKE = make | ||
7 | 8 | ||
8 | CFLAGS += -Wall -O2 | 9 | CFLAGS += -Wall -O2 |
9 | CFLAGS += -D__EXPORTED_HEADERS__ -I../../include/uapi -I../../include | 10 | CFLAGS += -D__EXPORTED_HEADERS__ -I../../include/uapi -I../../include |
@@ -14,7 +15,7 @@ CFLAGS += -D__EXPORTED_HEADERS__ -I../../include/uapi -I../../include | |||
14 | %.lex.c: %.l | 15 | %.lex.c: %.l |
15 | $(LEX) -o $@ $< | 16 | $(LEX) -o $@ $< |
16 | 17 | ||
17 | all : bpf_jit_disasm bpf_dbg bpf_asm | 18 | all: bpf_jit_disasm bpf_dbg bpf_asm bpftool |
18 | 19 | ||
19 | bpf_jit_disasm : CFLAGS += -DPACKAGE='bpf_jit_disasm' | 20 | bpf_jit_disasm : CFLAGS += -DPACKAGE='bpf_jit_disasm' |
20 | bpf_jit_disasm : LDLIBS = -lopcodes -lbfd -ldl | 21 | bpf_jit_disasm : LDLIBS = -lopcodes -lbfd -ldl |
@@ -27,10 +28,21 @@ bpf_asm : LDLIBS = | |||
27 | bpf_asm : bpf_asm.o bpf_exp.yacc.o bpf_exp.lex.o | 28 | bpf_asm : bpf_asm.o bpf_exp.yacc.o bpf_exp.lex.o |
28 | bpf_exp.lex.o : bpf_exp.yacc.c | 29 | bpf_exp.lex.o : bpf_exp.yacc.c |
29 | 30 | ||
30 | clean : | 31 | clean: bpftool_clean |
31 | rm -rf *.o bpf_jit_disasm bpf_dbg bpf_asm bpf_exp.yacc.* bpf_exp.lex.* | 32 | rm -rf *.o bpf_jit_disasm bpf_dbg bpf_asm bpf_exp.yacc.* bpf_exp.lex.* |
32 | 33 | ||
33 | install : | 34 | install: bpftool_install |
34 | install bpf_jit_disasm $(prefix)/bin/bpf_jit_disasm | 35 | install bpf_jit_disasm $(prefix)/bin/bpf_jit_disasm |
35 | install bpf_dbg $(prefix)/bin/bpf_dbg | 36 | install bpf_dbg $(prefix)/bin/bpf_dbg |
36 | install bpf_asm $(prefix)/bin/bpf_asm | 37 | install bpf_asm $(prefix)/bin/bpf_asm |
38 | |||
39 | bpftool: | ||
40 | $(MAKE) -C bpftool | ||
41 | |||
42 | bpftool_install: | ||
43 | $(MAKE) -C bpftool install | ||
44 | |||
45 | bpftool_clean: | ||
46 | $(MAKE) -C bpftool clean | ||
47 | |||
48 | .PHONY: bpftool FORCE | ||
diff --git a/tools/net/bpf_asm.c b/tools/bpf/bpf_asm.c index c15aef097b04..c15aef097b04 100644 --- a/tools/net/bpf_asm.c +++ b/tools/bpf/bpf_asm.c | |||
diff --git a/tools/net/bpf_dbg.c b/tools/bpf/bpf_dbg.c index 4f254bcc4423..4f254bcc4423 100644 --- a/tools/net/bpf_dbg.c +++ b/tools/bpf/bpf_dbg.c | |||
diff --git a/tools/net/bpf_exp.l b/tools/bpf/bpf_exp.l index bd83149e7be0..bd83149e7be0 100644 --- a/tools/net/bpf_exp.l +++ b/tools/bpf/bpf_exp.l | |||
diff --git a/tools/net/bpf_exp.y b/tools/bpf/bpf_exp.y index 56ba1de50784..56ba1de50784 100644 --- a/tools/net/bpf_exp.y +++ b/tools/bpf/bpf_exp.y | |||
diff --git a/tools/net/bpf_jit_disasm.c b/tools/bpf/bpf_jit_disasm.c index 422d9abd666a..75bf526a0168 100644 --- a/tools/net/bpf_jit_disasm.c +++ b/tools/bpf/bpf_jit_disasm.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <sys/klog.h> | 27 | #include <sys/klog.h> |
28 | #include <sys/types.h> | 28 | #include <sys/types.h> |
29 | #include <sys/stat.h> | 29 | #include <sys/stat.h> |
30 | #include <limits.h> | ||
30 | 31 | ||
31 | #define CMD_ACTION_SIZE_BUFFER 10 | 32 | #define CMD_ACTION_SIZE_BUFFER 10 |
32 | #define CMD_ACTION_READ_ALL 3 | 33 | #define CMD_ACTION_READ_ALL 3 |
@@ -51,7 +52,7 @@ static void get_exec_path(char *tpath, size_t size) | |||
51 | static void get_asm_insns(uint8_t *image, size_t len, int opcodes) | 52 | static void get_asm_insns(uint8_t *image, size_t len, int opcodes) |
52 | { | 53 | { |
53 | int count, i, pc = 0; | 54 | int count, i, pc = 0; |
54 | char tpath[256]; | 55 | char tpath[PATH_MAX]; |
55 | struct disassemble_info info; | 56 | struct disassemble_info info; |
56 | disassembler_ftype disassemble; | 57 | disassembler_ftype disassemble; |
57 | bfd *bfdf; | 58 | bfd *bfdf; |
diff --git a/tools/bpf/bpftool/Documentation/Makefile b/tools/bpf/bpftool/Documentation/Makefile new file mode 100644 index 000000000000..37292bb5ce60 --- /dev/null +++ b/tools/bpf/bpftool/Documentation/Makefile | |||
@@ -0,0 +1,34 @@ | |||
1 | include ../../../scripts/Makefile.include | ||
2 | include ../../../scripts/utilities.mak | ||
3 | |||
4 | INSTALL ?= install | ||
5 | RM ?= rm -f | ||
6 | |||
7 | # Make the path relative to DESTDIR, not prefix | ||
8 | ifndef DESTDIR | ||
9 | prefix ?= /usr/local | ||
10 | endif | ||
11 | mandir ?= $(prefix)/share/man | ||
12 | man8dir = $(mandir)/man8 | ||
13 | |||
14 | MAN8_RST = $(wildcard *.rst) | ||
15 | |||
16 | _DOC_MAN8 = $(patsubst %.rst,%.8,$(MAN8_RST)) | ||
17 | DOC_MAN8 = $(addprefix $(OUTPUT),$(_DOC_MAN8)) | ||
18 | |||
19 | man: man8 | ||
20 | man8: $(DOC_MAN8) | ||
21 | |||
22 | $(OUTPUT)%.8: %.rst | ||
23 | rst2man $< > $@ | ||
24 | |||
25 | clean: | ||
26 | $(call QUIET_CLEAN, Documentation) $(RM) $(DOC_MAN8) | ||
27 | |||
28 | install: man | ||
29 | $(call QUIET_INSTALL, Documentation-man) \ | ||
30 | $(INSTALL) -d -m 755 $(DESTDIR)$(man8dir); \ | ||
31 | $(INSTALL) -m 644 $(DOC_MAN8) $(DESTDIR)$(man8dir); | ||
32 | |||
33 | .PHONY: man man8 clean install | ||
34 | .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..9f51a268eb06 --- /dev/null +++ b/tools/bpf/bpftool/Documentation/bpftool-map.rst | |||
@@ -0,0 +1,131 @@ | |||
1 | ================ | ||
2 | bpftool-map | ||
3 | ================ | ||
4 | ------------------------------------------------------------------------------- | ||
5 | tool for inspection and simple manipulation of eBPF maps | ||
6 | ------------------------------------------------------------------------------- | ||
7 | |||
8 | :Manual section: 8 | ||
9 | |||
10 | SYNOPSIS | ||
11 | ======== | ||
12 | |||
13 | **bpftool** [*OPTIONS*] **map** *COMMAND* | ||
14 | |||
15 | *OPTIONS* := { { **-j** | **--json** } [{ **-p** | **--pretty** }] | { **-f** | **--bpffs** } } | ||
16 | |||
17 | *COMMANDS* := | ||
18 | { **show** | **dump** | **update** | **lookup** | **getnext** | **delete** | ||
19 | | **pin** | **help** } | ||
20 | |||
21 | MAP COMMANDS | ||
22 | ============= | ||
23 | |||
24 | | **bpftool** **map show** [*MAP*] | ||
25 | | **bpftool** **map dump** *MAP* | ||
26 | | **bpftool** **map update** *MAP* **key** *BYTES* **value** *VALUE* [*UPDATE_FLAGS*] | ||
27 | | **bpftool** **map lookup** *MAP* **key** *BYTES* | ||
28 | | **bpftool** **map getnext** *MAP* [**key** *BYTES*] | ||
29 | | **bpftool** **map delete** *MAP* **key** *BYTES* | ||
30 | | **bpftool** **map pin** *MAP* *FILE* | ||
31 | | **bpftool** **map help** | ||
32 | | | ||
33 | | *MAP* := { **id** *MAP_ID* | **pinned** *FILE* } | ||
34 | | *VALUE* := { *BYTES* | *MAP* | *PROGRAM* } | ||
35 | | *UPDATE_FLAGS* := { **any** | **exist** | **noexist** } | ||
36 | |||
37 | DESCRIPTION | ||
38 | =========== | ||
39 | **bpftool map show** [*MAP*] | ||
40 | Show information about loaded maps. If *MAP* is specified | ||
41 | show information only about given map, otherwise list all | ||
42 | maps currently loaded on the system. | ||
43 | |||
44 | Output will start with map ID followed by map type and | ||
45 | zero or more named attributes (depending on kernel version). | ||
46 | |||
47 | **bpftool map dump** *MAP* | ||
48 | Dump all entries in a given *MAP*. | ||
49 | |||
50 | **bpftool map update** *MAP* **key** *BYTES* **value** *VALUE* [*UPDATE_FLAGS*] | ||
51 | Update map entry for a given *KEY*. | ||
52 | |||
53 | *UPDATE_FLAGS* can be one of: **any** update existing entry | ||
54 | or add if doesn't exit; **exist** update only if entry already | ||
55 | exists; **noexist** update only if entry doesn't exist. | ||
56 | |||
57 | **bpftool map lookup** *MAP* **key** *BYTES* | ||
58 | Lookup **key** in the map. | ||
59 | |||
60 | **bpftool map getnext** *MAP* [**key** *BYTES*] | ||
61 | Get next key. If *key* is not specified, get first key. | ||
62 | |||
63 | **bpftool map delete** *MAP* **key** *BYTES* | ||
64 | Remove entry from the map. | ||
65 | |||
66 | **bpftool map pin** *MAP* *FILE* | ||
67 | Pin map *MAP* as *FILE*. | ||
68 | |||
69 | Note: *FILE* must be located in *bpffs* mount. | ||
70 | |||
71 | **bpftool map help** | ||
72 | Print short help message. | ||
73 | |||
74 | OPTIONS | ||
75 | ======= | ||
76 | -h, --help | ||
77 | Print short generic help message (similar to **bpftool help**). | ||
78 | |||
79 | -v, --version | ||
80 | Print version number (similar to **bpftool version**). | ||
81 | |||
82 | -j, --json | ||
83 | Generate JSON output. For commands that cannot produce JSON, this | ||
84 | option has no effect. | ||
85 | |||
86 | -p, --pretty | ||
87 | Generate human-readable JSON output. Implies **-j**. | ||
88 | |||
89 | -f, --bpffs | ||
90 | Show file names of pinned maps. | ||
91 | |||
92 | EXAMPLES | ||
93 | ======== | ||
94 | **# bpftool map show** | ||
95 | :: | ||
96 | |||
97 | 10: hash name some_map flags 0x0 | ||
98 | key 4B value 8B max_entries 2048 memlock 167936B | ||
99 | |||
100 | **# bpftool map update id 10 key 13 00 07 00 value 02 00 00 00 01 02 03 04** | ||
101 | |||
102 | **# bpftool map lookup id 10 key 0 1 2 3** | ||
103 | |||
104 | :: | ||
105 | |||
106 | key: 00 01 02 03 value: 00 01 02 03 04 05 06 07 | ||
107 | |||
108 | |||
109 | **# bpftool map dump id 10** | ||
110 | :: | ||
111 | |||
112 | key: 00 01 02 03 value: 00 01 02 03 04 05 06 07 | ||
113 | key: 0d 00 07 00 value: 02 00 00 00 01 02 03 04 | ||
114 | Found 2 elements | ||
115 | |||
116 | **# bpftool map getnext id 10 key 0 1 2 3** | ||
117 | :: | ||
118 | |||
119 | key: | ||
120 | 00 01 02 03 | ||
121 | next key: | ||
122 | 0d 00 07 00 | ||
123 | |||
124 | | | ||
125 | | **# mount -t bpf none /sys/fs/bpf/** | ||
126 | | **# bpftool map pin id 10 /sys/fs/bpf/map** | ||
127 | | **# bpftool map del pinned /sys/fs/bpf/map key 13 00 07 00** | ||
128 | |||
129 | SEE ALSO | ||
130 | ======== | ||
131 | **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..36e8d1c3c40d --- /dev/null +++ b/tools/bpf/bpftool/Documentation/bpftool-prog.rst | |||
@@ -0,0 +1,150 @@ | |||
1 | ================ | ||
2 | bpftool-prog | ||
3 | ================ | ||
4 | ------------------------------------------------------------------------------- | ||
5 | tool for inspection and simple manipulation of eBPF progs | ||
6 | ------------------------------------------------------------------------------- | ||
7 | |||
8 | :Manual section: 8 | ||
9 | |||
10 | SYNOPSIS | ||
11 | ======== | ||
12 | |||
13 | **bpftool** [*OPTIONS*] **prog** *COMMAND* | ||
14 | |||
15 | *OPTIONS* := { { **-j** | **--json** } [{ **-p** | **--pretty** }] | { **-f** | **--bpffs** } } | ||
16 | |||
17 | *COMMANDS* := | ||
18 | { **show** | **dump xlated** | **dump jited** | **pin** | **help** } | ||
19 | |||
20 | MAP COMMANDS | ||
21 | ============= | ||
22 | |||
23 | | **bpftool** **prog show** [*PROG*] | ||
24 | | **bpftool** **prog dump xlated** *PROG* [{**file** *FILE* | **opcodes**}] | ||
25 | | **bpftool** **prog dump jited** *PROG* [{**file** *FILE* | **opcodes**}] | ||
26 | | **bpftool** **prog pin** *PROG* *FILE* | ||
27 | | **bpftool** **prog help** | ||
28 | | | ||
29 | | *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* } | ||
30 | |||
31 | DESCRIPTION | ||
32 | =========== | ||
33 | **bpftool prog show** [*PROG*] | ||
34 | Show information about loaded programs. If *PROG* is | ||
35 | specified show information only about given program, otherwise | ||
36 | list all programs currently loaded on the system. | ||
37 | |||
38 | Output will start with program ID followed by program type and | ||
39 | zero or more named attributes (depending on kernel version). | ||
40 | |||
41 | **bpftool prog dump xlated** *PROG* [{ **file** *FILE* | **opcodes** }] | ||
42 | Dump eBPF instructions of the program from the kernel. | ||
43 | If *FILE* is specified image will be written to a file, | ||
44 | otherwise it will be disassembled and printed to stdout. | ||
45 | |||
46 | **opcodes** controls if raw opcodes will be printed. | ||
47 | |||
48 | **bpftool prog dump jited** *PROG* [{ **file** *FILE* | **opcodes** }] | ||
49 | Dump jited image (host machine code) of the program. | ||
50 | If *FILE* is specified image will be written to a file, | ||
51 | otherwise it will be disassembled and printed to stdout. | ||
52 | |||
53 | **opcodes** controls if raw opcodes will be printed. | ||
54 | |||
55 | **bpftool prog pin** *PROG* *FILE* | ||
56 | Pin program *PROG* as *FILE*. | ||
57 | |||
58 | Note: *FILE* must be located in *bpffs* mount. | ||
59 | |||
60 | **bpftool prog help** | ||
61 | Print short help message. | ||
62 | |||
63 | OPTIONS | ||
64 | ======= | ||
65 | -h, --help | ||
66 | Print short generic help message (similar to **bpftool help**). | ||
67 | |||
68 | -v, --version | ||
69 | Print version number (similar to **bpftool version**). | ||
70 | |||
71 | -j, --json | ||
72 | Generate JSON output. For commands that cannot produce JSON, this | ||
73 | option has no effect. | ||
74 | |||
75 | -p, --pretty | ||
76 | Generate human-readable JSON output. Implies **-j**. | ||
77 | |||
78 | -f, --bpffs | ||
79 | Show file names of pinned programs. | ||
80 | |||
81 | EXAMPLES | ||
82 | ======== | ||
83 | **# bpftool prog show** | ||
84 | :: | ||
85 | |||
86 | 10: xdp name some_prog tag 005a3d2123620c8b | ||
87 | loaded_at Sep 29/20:11 uid 0 | ||
88 | xlated 528B jited 370B memlock 4096B map_ids 10 | ||
89 | |||
90 | **# bpftool --json --pretty prog show** | ||
91 | |||
92 | :: | ||
93 | |||
94 | { | ||
95 | "programs": [{ | ||
96 | "id": 10, | ||
97 | "type": "xdp", | ||
98 | "tag": "005a3d2123620c8b", | ||
99 | "loaded_at": "Sep 29/20:11", | ||
100 | "uid": 0, | ||
101 | "bytes_xlated": 528, | ||
102 | "jited": true, | ||
103 | "bytes_jited": 370, | ||
104 | "bytes_memlock": 4096, | ||
105 | "map_ids": [10 | ||
106 | ] | ||
107 | } | ||
108 | ] | ||
109 | } | ||
110 | |||
111 | | | ||
112 | | **# bpftool prog dump xlated id 10 file /tmp/t** | ||
113 | | **# ls -l /tmp/t** | ||
114 | | -rw------- 1 root root 560 Jul 22 01:42 /tmp/t | ||
115 | |||
116 | **# bpftool prog dum jited tag 005a3d2123620c8b** | ||
117 | |||
118 | :: | ||
119 | |||
120 | push %rbp | ||
121 | mov %rsp,%rbp | ||
122 | sub $0x228,%rsp | ||
123 | sub $0x28,%rbp | ||
124 | mov %rbx,0x0(%rbp) | ||
125 | |||
126 | | | ||
127 | | **# mount -t bpf none /sys/fs/bpf/** | ||
128 | | **# bpftool prog pin id 10 /sys/fs/bpf/prog** | ||
129 | | **# ls -l /sys/fs/bpf/** | ||
130 | | -rw------- 1 root root 0 Jul 22 01:43 prog | ||
131 | |||
132 | **# bpftool prog dum jited pinned /sys/fs/bpf/prog opcodes** | ||
133 | |||
134 | :: | ||
135 | |||
136 | push %rbp | ||
137 | 55 | ||
138 | mov %rsp,%rbp | ||
139 | 48 89 e5 | ||
140 | sub $0x228,%rsp | ||
141 | 48 81 ec 28 02 00 00 | ||
142 | sub $0x28,%rbp | ||
143 | 48 83 ed 28 | ||
144 | mov %rbx,0x0(%rbp) | ||
145 | 48 89 5d 00 | ||
146 | |||
147 | |||
148 | SEE ALSO | ||
149 | ======== | ||
150 | **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..926c03d5a8da --- /dev/null +++ b/tools/bpf/bpftool/Documentation/bpftool.rst | |||
@@ -0,0 +1,56 @@ | |||
1 | ================ | ||
2 | BPFTOOL | ||
3 | ================ | ||
4 | ------------------------------------------------------------------------------- | ||
5 | tool for inspection and simple manipulation of eBPF programs and maps | ||
6 | ------------------------------------------------------------------------------- | ||
7 | |||
8 | :Manual section: 8 | ||
9 | |||
10 | SYNOPSIS | ||
11 | ======== | ||
12 | |||
13 | **bpftool** [*OPTIONS*] *OBJECT* { *COMMAND* | **help** } | ||
14 | |||
15 | **bpftool** **batch file** *FILE* | ||
16 | |||
17 | **bpftool** **version** | ||
18 | |||
19 | *OBJECT* := { **map** | **program** } | ||
20 | |||
21 | *OPTIONS* := { { **-V** | **--version** } | { **-h** | **--help** } | ||
22 | | { **-j** | **--json** } [{ **-p** | **--pretty** }] } | ||
23 | |||
24 | *MAP-COMMANDS* := | ||
25 | { **show** | **dump** | **update** | **lookup** | **getnext** | **delete** | ||
26 | | **pin** | **help** } | ||
27 | |||
28 | *PROG-COMMANDS* := { **show** | **dump jited** | **dump xlated** | **pin** | ||
29 | | **help** } | ||
30 | |||
31 | DESCRIPTION | ||
32 | =========== | ||
33 | *bpftool* allows for inspection and simple modification of BPF objects | ||
34 | on the system. | ||
35 | |||
36 | Note that format of the output of all tools is not guaranteed to be | ||
37 | stable and should not be depended upon. | ||
38 | |||
39 | OPTIONS | ||
40 | ======= | ||
41 | -h, --help | ||
42 | Print short help message (similar to **bpftool help**). | ||
43 | |||
44 | -v, --version | ||
45 | Print version number (similar to **bpftool version**). | ||
46 | |||
47 | -j, --json | ||
48 | Generate JSON output. For commands that cannot produce JSON, this | ||
49 | option has no effect. | ||
50 | |||
51 | -p, --pretty | ||
52 | Generate human-readable JSON output. Implies **-j**. | ||
53 | |||
54 | SEE ALSO | ||
55 | ======== | ||
56 | **bpftool-map**\ (8), **bpftool-prog**\ (8) | ||
diff --git a/tools/bpf/bpftool/Makefile b/tools/bpf/bpftool/Makefile new file mode 100644 index 000000000000..ec3052c0b004 --- /dev/null +++ b/tools/bpf/bpftool/Makefile | |||
@@ -0,0 +1,93 @@ | |||
1 | include ../../scripts/Makefile.include | ||
2 | |||
3 | include ../../scripts/utilities.mak | ||
4 | |||
5 | ifeq ($(srctree),) | ||
6 | srctree := $(patsubst %/,%,$(dir $(CURDIR))) | ||
7 | srctree := $(patsubst %/,%,$(dir $(srctree))) | ||
8 | srctree := $(patsubst %/,%,$(dir $(srctree))) | ||
9 | #$(info Determined 'srctree' to be $(srctree)) | ||
10 | endif | ||
11 | |||
12 | ifneq ($(objtree),) | ||
13 | #$(info Determined 'objtree' to be $(objtree)) | ||
14 | endif | ||
15 | |||
16 | ifneq ($(OUTPUT),) | ||
17 | #$(info Determined 'OUTPUT' to be $(OUTPUT)) | ||
18 | # Adding $(OUTPUT) as a directory to look for source files, | ||
19 | # because use generated output files as sources dependency | ||
20 | # for flex/bison parsers. | ||
21 | VPATH += $(OUTPUT) | ||
22 | export VPATH | ||
23 | endif | ||
24 | |||
25 | ifeq ($(V),1) | ||
26 | Q = | ||
27 | else | ||
28 | Q = @ | ||
29 | endif | ||
30 | |||
31 | BPF_DIR = $(srctree)/tools/lib/bpf/ | ||
32 | |||
33 | ifneq ($(OUTPUT),) | ||
34 | BPF_PATH=$(OUTPUT) | ||
35 | else | ||
36 | BPF_PATH=$(BPF_DIR) | ||
37 | endif | ||
38 | |||
39 | LIBBPF = $(BPF_PATH)libbpf.a | ||
40 | |||
41 | $(LIBBPF): FORCE | ||
42 | $(Q)$(MAKE) -C $(BPF_DIR) OUTPUT=$(OUTPUT) $(OUTPUT)libbpf.a FEATURES_DUMP=$(FEATURE_DUMP_EXPORT) | ||
43 | |||
44 | $(LIBBPF)-clean: | ||
45 | $(call QUIET_CLEAN, libbpf) | ||
46 | $(Q)$(MAKE) -C $(BPF_DIR) OUTPUT=$(OUTPUT) clean >/dev/null | ||
47 | |||
48 | prefix = /usr/local | ||
49 | bash_compdir ?= /usr/share/bash-completion/completions | ||
50 | |||
51 | CC = gcc | ||
52 | |||
53 | CFLAGS += -O2 | ||
54 | CFLAGS += -W -Wall -Wextra -Wno-unused-parameter -Wshadow | ||
55 | CFLAGS += -D__EXPORTED_HEADERS__ -I$(srctree)/tools/include/uapi -I$(srctree)/tools/include -I$(srctree)/tools/lib/bpf -I$(srctree)/kernel/bpf/ | ||
56 | LIBS = -lelf -lbfd -lopcodes $(LIBBPF) | ||
57 | |||
58 | include $(wildcard *.d) | ||
59 | |||
60 | all: $(OUTPUT)bpftool | ||
61 | |||
62 | SRCS=$(wildcard *.c) | ||
63 | OBJS=$(patsubst %.c,$(OUTPUT)%.o,$(SRCS)) $(OUTPUT)disasm.o | ||
64 | |||
65 | $(OUTPUT)disasm.o: $(srctree)/kernel/bpf/disasm.c | ||
66 | $(QUIET_CC)$(COMPILE.c) -MMD -o $@ $< | ||
67 | |||
68 | $(OUTPUT)bpftool: $(OBJS) $(LIBBPF) | ||
69 | $(QUIET_LINK)$(CC) $(CFLAGS) -o $@ $^ $(LIBS) | ||
70 | |||
71 | $(OUTPUT)%.o: %.c | ||
72 | $(QUIET_CC)$(COMPILE.c) -MMD -o $@ $< | ||
73 | |||
74 | clean: $(LIBBPF)-clean | ||
75 | $(call QUIET_CLEAN, bpftool) | ||
76 | $(Q)rm -rf $(OUTPUT)bpftool $(OUTPUT)*.o $(OUTPUT)*.d | ||
77 | |||
78 | install: | ||
79 | install -m 0755 -d $(prefix)/sbin | ||
80 | install $(OUTPUT)bpftool $(prefix)/sbin/bpftool | ||
81 | install -m 0755 -d $(bash_compdir) | ||
82 | install -m 0644 bash-completion/bpftool $(bash_compdir) | ||
83 | |||
84 | doc: | ||
85 | $(Q)$(MAKE) -C Documentation/ | ||
86 | |||
87 | doc-install: | ||
88 | $(Q)$(MAKE) -C Documentation/ install | ||
89 | |||
90 | FORCE: | ||
91 | |||
92 | .PHONY: all clean FORCE install doc doc-install | ||
93 | .DEFAULT_GOAL := all | ||
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 @@ | |||
1 | # bpftool(8) bash completion -*- shell-script -*- | ||
2 | # | ||
3 | # Copyright (C) 2017 Netronome Systems, Inc. | ||
4 | # | ||
5 | # This software is dual licensed under the GNU General License | ||
6 | # Version 2, June 1991 as shown in the file COPYING in the top-level | ||
7 | # directory of this source tree or the BSD 2-Clause License provided | ||
8 | # below. You have the option to license this software under the | ||
9 | # complete terms of either license. | ||
10 | # | ||
11 | # The BSD 2-Clause License: | ||
12 | # | ||
13 | # Redistribution and use in source and binary forms, with or | ||
14 | # without modification, are permitted provided that the following | ||
15 | # conditions are met: | ||
16 | # | ||
17 | # 1. Redistributions of source code must retain the above | ||
18 | # copyright notice, this list of conditions and the following | ||
19 | # disclaimer. | ||
20 | # | ||
21 | # 2. Redistributions in binary form must reproduce the above | ||
22 | # copyright notice, this list of conditions and the following | ||
23 | # disclaimer in the documentation and/or other materials | ||
24 | # provided with the distribution. | ||
25 | # | ||
26 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
27 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
28 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
29 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
30 | # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
31 | # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
32 | # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
33 | # SOFTWARE. | ||
34 | # | ||
35 | # Author: Quentin Monnet <quentin.monnet@netronome.com> | ||
36 | |||
37 | # Takes a list of words in argument; each one of them is added to COMPREPLY if | ||
38 | # it is not already present on the command line. Returns no value. | ||
39 | _bpftool_once_attr() | ||
40 | { | ||
41 | local w idx found | ||
42 | for w in $*; do | ||
43 | found=0 | ||
44 | for (( idx=3; idx < ${#words[@]}-1; idx++ )); do | ||
45 | if [[ $w == ${words[idx]} ]]; then | ||
46 | found=1 | ||
47 | break | ||
48 | fi | ||
49 | done | ||
50 | [[ $found -eq 0 ]] && \ | ||
51 | COMPREPLY+=( $( compgen -W "$w" -- "$cur" ) ) | ||
52 | done | ||
53 | } | ||
54 | |||
55 | # Takes a list of words in argument; adds them all to COMPREPLY if none of them | ||
56 | # is already present on the command line. Returns no value. | ||
57 | _bpftool_one_of_list() | ||
58 | { | ||
59 | local w idx | ||
60 | for w in $*; do | ||
61 | for (( idx=3; idx < ${#words[@]}-1; idx++ )); do | ||
62 | [[ $w == ${words[idx]} ]] && return 1 | ||
63 | done | ||
64 | done | ||
65 | COMPREPLY+=( $( compgen -W "$*" -- "$cur" ) ) | ||
66 | } | ||
67 | |||
68 | _bpftool_get_map_ids() | ||
69 | { | ||
70 | COMPREPLY+=( $( compgen -W "$( bpftool -jp map 2>&1 | \ | ||
71 | command sed -n 's/.*"id": \(.*\),$/\1/p' )" -- "$cur" ) ) | ||
72 | } | ||
73 | |||
74 | _bpftool_get_prog_ids() | ||
75 | { | ||
76 | COMPREPLY+=( $( compgen -W "$( bpftool -jp prog 2>&1 | \ | ||
77 | command sed -n 's/.*"id": \(.*\),$/\1/p' )" -- "$cur" ) ) | ||
78 | } | ||
79 | |||
80 | _bpftool_get_prog_tags() | ||
81 | { | ||
82 | COMPREPLY+=( $( compgen -W "$( bpftool -jp prog 2>&1 | \ | ||
83 | command sed -n 's/.*"tag": "\(.*\)",$/\1/p' )" -- "$cur" ) ) | ||
84 | } | ||
85 | |||
86 | # For bpftool map update: retrieve type of the map to update. | ||
87 | _bpftool_map_update_map_type() | ||
88 | { | ||
89 | local keyword ref | ||
90 | for (( idx=3; idx < ${#words[@]}-1; idx++ )); do | ||
91 | if [[ ${words[$((idx-2))]} == "update" ]]; then | ||
92 | keyword=${words[$((idx-1))]} | ||
93 | ref=${words[$((idx))]} | ||
94 | fi | ||
95 | done | ||
96 | [[ -z $ref ]] && return 0 | ||
97 | |||
98 | local type | ||
99 | type=$(bpftool -jp map show $keyword $ref | \ | ||
100 | command sed -n 's/.*"type": "\(.*\)",$/\1/p') | ||
101 | printf $type | ||
102 | } | ||
103 | |||
104 | _bpftool_map_update_get_id() | ||
105 | { | ||
106 | # Is it the map to update, or a map to insert into the map to update? | ||
107 | # Search for "value" keyword. | ||
108 | local idx value | ||
109 | for (( idx=7; idx < ${#words[@]}-1; idx++ )); do | ||
110 | if [[ ${words[idx]} == "value" ]]; then | ||
111 | value=1 | ||
112 | break | ||
113 | fi | ||
114 | done | ||
115 | [[ $value -eq 0 ]] && _bpftool_get_map_ids && return 0 | ||
116 | |||
117 | # Id to complete is for a value. It can be either prog id or map id. This | ||
118 | # depends on the type of the map to update. | ||
119 | local type=$(_bpftool_map_update_map_type) | ||
120 | case $type in | ||
121 | array_of_maps|hash_of_maps) | ||
122 | _bpftool_get_map_ids | ||
123 | return 0 | ||
124 | ;; | ||
125 | prog_array) | ||
126 | _bpftool_get_prog_ids | ||
127 | return 0 | ||
128 | ;; | ||
129 | *) | ||
130 | return 0 | ||
131 | ;; | ||
132 | esac | ||
133 | } | ||
134 | |||
135 | _bpftool() | ||
136 | { | ||
137 | local cur prev words objword | ||
138 | _init_completion || return | ||
139 | |||
140 | # Deal with simplest keywords | ||
141 | case $prev in | ||
142 | help|key|opcodes) | ||
143 | return 0 | ||
144 | ;; | ||
145 | tag) | ||
146 | _bpftool_get_prog_tags | ||
147 | return 0 | ||
148 | ;; | ||
149 | file|pinned) | ||
150 | _filedir | ||
151 | return 0 | ||
152 | ;; | ||
153 | batch) | ||
154 | COMPREPLY=( $( compgen -W 'file' -- "$cur" ) ) | ||
155 | return 0 | ||
156 | ;; | ||
157 | esac | ||
158 | |||
159 | # Search for object and command | ||
160 | local object command cmdword | ||
161 | for (( cmdword=1; cmdword < ${#words[@]}-1; cmdword++ )); do | ||
162 | [[ -n $object ]] && command=${words[cmdword]} && break | ||
163 | [[ ${words[cmdword]} != -* ]] && object=${words[cmdword]} | ||
164 | done | ||
165 | |||
166 | if [[ -z $object ]]; then | ||
167 | case $cur in | ||
168 | -*) | ||
169 | local c='--version --json --pretty' | ||
170 | COMPREPLY=( $( compgen -W "$c" -- "$cur" ) ) | ||
171 | return 0 | ||
172 | ;; | ||
173 | *) | ||
174 | COMPREPLY=( $( compgen -W "$( bpftool help 2>&1 | \ | ||
175 | command sed \ | ||
176 | -e '/OBJECT := /!d' \ | ||
177 | -e 's/.*{//' \ | ||
178 | -e 's/}.*//' \ | ||
179 | -e 's/|//g' )" -- "$cur" ) ) | ||
180 | COMPREPLY+=( $( compgen -W 'batch help' -- "$cur" ) ) | ||
181 | return 0 | ||
182 | ;; | ||
183 | esac | ||
184 | fi | ||
185 | |||
186 | [[ $command == help ]] && return 0 | ||
187 | |||
188 | # Completion depends on object and command in use | ||
189 | case $object in | ||
190 | prog) | ||
191 | case $prev in | ||
192 | id) | ||
193 | _bpftool_get_prog_ids | ||
194 | return 0 | ||
195 | ;; | ||
196 | esac | ||
197 | |||
198 | local PROG_TYPE='id pinned tag' | ||
199 | case $command in | ||
200 | show) | ||
201 | [[ $prev != "$command" ]] && return 0 | ||
202 | COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) ) | ||
203 | return 0 | ||
204 | ;; | ||
205 | dump) | ||
206 | case $prev in | ||
207 | $command) | ||
208 | COMPREPLY+=( $( compgen -W "xlated jited" -- \ | ||
209 | "$cur" ) ) | ||
210 | return 0 | ||
211 | ;; | ||
212 | xlated|jited) | ||
213 | COMPREPLY=( $( compgen -W "$PROG_TYPE" -- \ | ||
214 | "$cur" ) ) | ||
215 | return 0 | ||
216 | ;; | ||
217 | *) | ||
218 | _bpftool_once_attr 'file' | ||
219 | COMPREPLY+=( $( compgen -W 'opcodes' -- \ | ||
220 | "$cur" ) ) | ||
221 | return 0 | ||
222 | ;; | ||
223 | esac | ||
224 | ;; | ||
225 | pin) | ||
226 | if [[ $prev == "$command" ]]; then | ||
227 | COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) ) | ||
228 | else | ||
229 | _filedir | ||
230 | fi | ||
231 | return 0 | ||
232 | ;; | ||
233 | *) | ||
234 | [[ $prev == $object ]] && \ | ||
235 | COMPREPLY=( $( compgen -W 'dump help pin show' -- \ | ||
236 | "$cur" ) ) | ||
237 | ;; | ||
238 | esac | ||
239 | ;; | ||
240 | map) | ||
241 | local MAP_TYPE='id pinned' | ||
242 | case $command in | ||
243 | show|dump) | ||
244 | case $prev in | ||
245 | $command) | ||
246 | COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) ) | ||
247 | return 0 | ||
248 | ;; | ||
249 | id) | ||
250 | _bpftool_get_map_ids | ||
251 | return 0 | ||
252 | ;; | ||
253 | *) | ||
254 | return 0 | ||
255 | ;; | ||
256 | esac | ||
257 | ;; | ||
258 | lookup|getnext|delete) | ||
259 | case $prev in | ||
260 | $command) | ||
261 | COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) ) | ||
262 | return 0 | ||
263 | ;; | ||
264 | id) | ||
265 | _bpftool_get_map_ids | ||
266 | return 0 | ||
267 | ;; | ||
268 | key) | ||
269 | return 0 | ||
270 | ;; | ||
271 | *) | ||
272 | _bpftool_once_attr 'key' | ||
273 | return 0 | ||
274 | ;; | ||
275 | esac | ||
276 | ;; | ||
277 | update) | ||
278 | case $prev in | ||
279 | $command) | ||
280 | COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) ) | ||
281 | return 0 | ||
282 | ;; | ||
283 | id) | ||
284 | _bpftool_map_update_get_id | ||
285 | return 0 | ||
286 | ;; | ||
287 | key) | ||
288 | return 0 | ||
289 | ;; | ||
290 | value) | ||
291 | # We can have bytes, or references to a prog or a | ||
292 | # map, depending on the type of the map to update. | ||
293 | case $(_bpftool_map_update_map_type) in | ||
294 | array_of_maps|hash_of_maps) | ||
295 | local MAP_TYPE='id pinned' | ||
296 | COMPREPLY+=( $( compgen -W "$MAP_TYPE" \ | ||
297 | -- "$cur" ) ) | ||
298 | return 0 | ||
299 | ;; | ||
300 | prog_array) | ||
301 | local PROG_TYPE='id pinned tag' | ||
302 | COMPREPLY+=( $( compgen -W "$PROG_TYPE" \ | ||
303 | -- "$cur" ) ) | ||
304 | return 0 | ||
305 | ;; | ||
306 | *) | ||
307 | return 0 | ||
308 | ;; | ||
309 | esac | ||
310 | return 0 | ||
311 | ;; | ||
312 | *) | ||
313 | _bpftool_once_attr 'key' | ||
314 | local UPDATE_FLAGS='any exist noexist' | ||
315 | for (( idx=3; idx < ${#words[@]}-1; idx++ )); do | ||
316 | if [[ ${words[idx]} == 'value' ]]; then | ||
317 | # 'value' is present, but is not the last | ||
318 | # word i.e. we can now have UPDATE_FLAGS. | ||
319 | _bpftool_one_of_list "$UPDATE_FLAGS" | ||
320 | return 0 | ||
321 | fi | ||
322 | done | ||
323 | for (( idx=3; idx < ${#words[@]}-1; idx++ )); do | ||
324 | if [[ ${words[idx]} == 'key' ]]; then | ||
325 | # 'key' is present, but is not the last | ||
326 | # word i.e. we can now have 'value'. | ||
327 | _bpftool_once_attr 'value' | ||
328 | return 0 | ||
329 | fi | ||
330 | done | ||
331 | return 0 | ||
332 | ;; | ||
333 | esac | ||
334 | ;; | ||
335 | pin) | ||
336 | if [[ $prev == "$command" ]]; then | ||
337 | COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) ) | ||
338 | else | ||
339 | _filedir | ||
340 | fi | ||
341 | return 0 | ||
342 | ;; | ||
343 | *) | ||
344 | [[ $prev == $object ]] && \ | ||
345 | COMPREPLY=( $( compgen -W 'delete dump getnext help \ | ||
346 | lookup pin show update' -- "$cur" ) ) | ||
347 | ;; | ||
348 | esac | ||
349 | ;; | ||
350 | esac | ||
351 | } && | ||
352 | complete -F _bpftool bpftool | ||
353 | |||
354 | # ex: ts=4 sw=4 et filetype=sh | ||
diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c new file mode 100644 index 000000000000..2bd3b280e6dd --- /dev/null +++ b/tools/bpf/bpftool/common.c | |||
@@ -0,0 +1,405 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 Netronome Systems, Inc. | ||
3 | * | ||
4 | * This software is dual licensed under the GNU General License Version 2, | ||
5 | * June 1991 as shown in the file COPYING in the top-level directory of this | ||
6 | * source tree or the BSD 2-Clause License provided below. You have the | ||
7 | * option to license this software under the complete terms of either license. | ||
8 | * | ||
9 | * The BSD 2-Clause License: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or | ||
12 | * without modification, are permitted provided that the following | ||
13 | * conditions are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above | ||
16 | * copyright notice, this list of conditions and the following | ||
17 | * disclaimer. | ||
18 | * | ||
19 | * 2. Redistributions in binary form must reproduce the above | ||
20 | * copyright notice, this list of conditions and the following | ||
21 | * disclaimer in the documentation and/or other materials | ||
22 | * provided with the distribution. | ||
23 | * | ||
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
28 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
29 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
31 | * SOFTWARE. | ||
32 | */ | ||
33 | |||
34 | /* Author: Jakub Kicinski <kubakici@wp.pl> */ | ||
35 | |||
36 | #include <errno.h> | ||
37 | #include <fts.h> | ||
38 | #include <libgen.h> | ||
39 | #include <mntent.h> | ||
40 | #include <stdbool.h> | ||
41 | #include <stdio.h> | ||
42 | #include <stdlib.h> | ||
43 | #include <string.h> | ||
44 | #include <unistd.h> | ||
45 | #include <linux/limits.h> | ||
46 | #include <linux/magic.h> | ||
47 | #include <sys/mount.h> | ||
48 | #include <sys/types.h> | ||
49 | #include <sys/vfs.h> | ||
50 | |||
51 | #include <bpf.h> | ||
52 | |||
53 | #include "main.h" | ||
54 | |||
55 | void p_err(const char *fmt, ...) | ||
56 | { | ||
57 | va_list ap; | ||
58 | |||
59 | va_start(ap, fmt); | ||
60 | if (json_output) { | ||
61 | jsonw_start_object(json_wtr); | ||
62 | jsonw_name(json_wtr, "error"); | ||
63 | jsonw_vprintf_enquote(json_wtr, fmt, ap); | ||
64 | jsonw_end_object(json_wtr); | ||
65 | } else { | ||
66 | fprintf(stderr, "Error: "); | ||
67 | vfprintf(stderr, fmt, ap); | ||
68 | fprintf(stderr, "\n"); | ||
69 | } | ||
70 | va_end(ap); | ||
71 | } | ||
72 | |||
73 | void p_info(const char *fmt, ...) | ||
74 | { | ||
75 | va_list ap; | ||
76 | |||
77 | if (json_output) | ||
78 | return; | ||
79 | |||
80 | va_start(ap, fmt); | ||
81 | vfprintf(stderr, fmt, ap); | ||
82 | fprintf(stderr, "\n"); | ||
83 | va_end(ap); | ||
84 | } | ||
85 | |||
86 | static bool is_bpffs(char *path) | ||
87 | { | ||
88 | struct statfs st_fs; | ||
89 | |||
90 | if (statfs(path, &st_fs) < 0) | ||
91 | return false; | ||
92 | |||
93 | return (unsigned long)st_fs.f_type == BPF_FS_MAGIC; | ||
94 | } | ||
95 | |||
96 | static int mnt_bpffs(const char *target, char *buff, size_t bufflen) | ||
97 | { | ||
98 | bool bind_done = false; | ||
99 | |||
100 | while (mount("", target, "none", MS_PRIVATE | MS_REC, NULL)) { | ||
101 | if (errno != EINVAL || bind_done) { | ||
102 | snprintf(buff, bufflen, | ||
103 | "mount --make-private %s failed: %s", | ||
104 | target, strerror(errno)); | ||
105 | return -1; | ||
106 | } | ||
107 | |||
108 | if (mount(target, target, "none", MS_BIND, NULL)) { | ||
109 | snprintf(buff, bufflen, | ||
110 | "mount --bind %s %s failed: %s", | ||
111 | target, target, strerror(errno)); | ||
112 | return -1; | ||
113 | } | ||
114 | |||
115 | bind_done = true; | ||
116 | } | ||
117 | |||
118 | if (mount("bpf", target, "bpf", 0, "mode=0700")) { | ||
119 | snprintf(buff, bufflen, "mount -t bpf bpf %s failed: %s", | ||
120 | target, strerror(errno)); | ||
121 | return -1; | ||
122 | } | ||
123 | |||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | int open_obj_pinned(char *path) | ||
128 | { | ||
129 | int fd; | ||
130 | |||
131 | fd = bpf_obj_get(path); | ||
132 | if (fd < 0) { | ||
133 | p_err("bpf obj get (%s): %s", path, | ||
134 | errno == EACCES && !is_bpffs(dirname(path)) ? | ||
135 | "directory not in bpf file system (bpffs)" : | ||
136 | strerror(errno)); | ||
137 | return -1; | ||
138 | } | ||
139 | |||
140 | return fd; | ||
141 | } | ||
142 | |||
143 | int open_obj_pinned_any(char *path, enum bpf_obj_type exp_type) | ||
144 | { | ||
145 | enum bpf_obj_type type; | ||
146 | int fd; | ||
147 | |||
148 | fd = open_obj_pinned(path); | ||
149 | if (fd < 0) | ||
150 | return -1; | ||
151 | |||
152 | type = get_fd_type(fd); | ||
153 | if (type < 0) { | ||
154 | close(fd); | ||
155 | return type; | ||
156 | } | ||
157 | if (type != exp_type) { | ||
158 | p_err("incorrect object type: %s", get_fd_type_name(type)); | ||
159 | close(fd); | ||
160 | return -1; | ||
161 | } | ||
162 | |||
163 | return fd; | ||
164 | } | ||
165 | |||
166 | int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(__u32)) | ||
167 | { | ||
168 | char err_str[ERR_MAX_LEN]; | ||
169 | unsigned int id; | ||
170 | char *endptr; | ||
171 | char *file; | ||
172 | char *dir; | ||
173 | int err; | ||
174 | int fd; | ||
175 | |||
176 | if (!is_prefix(*argv, "id")) { | ||
177 | p_err("expected 'id' got %s", *argv); | ||
178 | return -1; | ||
179 | } | ||
180 | NEXT_ARG(); | ||
181 | |||
182 | id = strtoul(*argv, &endptr, 0); | ||
183 | if (*endptr) { | ||
184 | p_err("can't parse %s as ID", *argv); | ||
185 | return -1; | ||
186 | } | ||
187 | NEXT_ARG(); | ||
188 | |||
189 | if (argc != 1) | ||
190 | usage(); | ||
191 | |||
192 | fd = get_fd_by_id(id); | ||
193 | if (fd < 0) { | ||
194 | p_err("can't get prog by id (%u): %s", id, strerror(errno)); | ||
195 | return -1; | ||
196 | } | ||
197 | |||
198 | err = bpf_obj_pin(fd, *argv); | ||
199 | if (!err) | ||
200 | goto out_close; | ||
201 | |||
202 | file = malloc(strlen(*argv) + 1); | ||
203 | strcpy(file, *argv); | ||
204 | dir = dirname(file); | ||
205 | |||
206 | if (errno != EPERM || is_bpffs(dir)) { | ||
207 | p_err("can't pin the object (%s): %s", *argv, strerror(errno)); | ||
208 | goto out_free; | ||
209 | } | ||
210 | |||
211 | /* Attempt to mount bpffs, then retry pinning. */ | ||
212 | err = mnt_bpffs(dir, err_str, ERR_MAX_LEN); | ||
213 | if (!err) { | ||
214 | err = bpf_obj_pin(fd, *argv); | ||
215 | if (err) | ||
216 | p_err("can't pin the object (%s): %s", *argv, | ||
217 | strerror(errno)); | ||
218 | } else { | ||
219 | err_str[ERR_MAX_LEN - 1] = '\0'; | ||
220 | p_err("can't mount BPF file system to pin the object (%s): %s", | ||
221 | *argv, err_str); | ||
222 | } | ||
223 | |||
224 | out_free: | ||
225 | free(file); | ||
226 | out_close: | ||
227 | close(fd); | ||
228 | return err; | ||
229 | } | ||
230 | |||
231 | const char *get_fd_type_name(enum bpf_obj_type type) | ||
232 | { | ||
233 | static const char * const names[] = { | ||
234 | [BPF_OBJ_UNKNOWN] = "unknown", | ||
235 | [BPF_OBJ_PROG] = "prog", | ||
236 | [BPF_OBJ_MAP] = "map", | ||
237 | }; | ||
238 | |||
239 | if (type < 0 || type >= ARRAY_SIZE(names) || !names[type]) | ||
240 | return names[BPF_OBJ_UNKNOWN]; | ||
241 | |||
242 | return names[type]; | ||
243 | } | ||
244 | |||
245 | int get_fd_type(int fd) | ||
246 | { | ||
247 | char path[PATH_MAX]; | ||
248 | char buf[512]; | ||
249 | ssize_t n; | ||
250 | |||
251 | snprintf(path, sizeof(path), "/proc/%d/fd/%d", getpid(), fd); | ||
252 | |||
253 | n = readlink(path, buf, sizeof(buf)); | ||
254 | if (n < 0) { | ||
255 | p_err("can't read link type: %s", strerror(errno)); | ||
256 | return -1; | ||
257 | } | ||
258 | if (n == sizeof(path)) { | ||
259 | p_err("can't read link type: path too long!"); | ||
260 | return -1; | ||
261 | } | ||
262 | |||
263 | if (strstr(buf, "bpf-map")) | ||
264 | return BPF_OBJ_MAP; | ||
265 | else if (strstr(buf, "bpf-prog")) | ||
266 | return BPF_OBJ_PROG; | ||
267 | |||
268 | return BPF_OBJ_UNKNOWN; | ||
269 | } | ||
270 | |||
271 | char *get_fdinfo(int fd, const char *key) | ||
272 | { | ||
273 | char path[PATH_MAX]; | ||
274 | char *line = NULL; | ||
275 | size_t line_n = 0; | ||
276 | ssize_t n; | ||
277 | FILE *fdi; | ||
278 | |||
279 | snprintf(path, sizeof(path), "/proc/%d/fdinfo/%d", getpid(), fd); | ||
280 | |||
281 | fdi = fopen(path, "r"); | ||
282 | if (!fdi) { | ||
283 | p_err("can't open fdinfo: %s", strerror(errno)); | ||
284 | return NULL; | ||
285 | } | ||
286 | |||
287 | while ((n = getline(&line, &line_n, fdi))) { | ||
288 | char *value; | ||
289 | int len; | ||
290 | |||
291 | if (!strstr(line, key)) | ||
292 | continue; | ||
293 | |||
294 | fclose(fdi); | ||
295 | |||
296 | value = strchr(line, '\t'); | ||
297 | if (!value || !value[1]) { | ||
298 | p_err("malformed fdinfo!?"); | ||
299 | free(line); | ||
300 | return NULL; | ||
301 | } | ||
302 | value++; | ||
303 | |||
304 | len = strlen(value); | ||
305 | memmove(line, value, len); | ||
306 | line[len - 1] = '\0'; | ||
307 | |||
308 | return line; | ||
309 | } | ||
310 | |||
311 | p_err("key '%s' not found in fdinfo", key); | ||
312 | free(line); | ||
313 | fclose(fdi); | ||
314 | return NULL; | ||
315 | } | ||
316 | |||
317 | void print_hex_data_json(uint8_t *data, size_t len) | ||
318 | { | ||
319 | unsigned int i; | ||
320 | |||
321 | jsonw_start_array(json_wtr); | ||
322 | for (i = 0; i < len; i++) | ||
323 | jsonw_printf(json_wtr, "\"0x%02hhx\"", data[i]); | ||
324 | jsonw_end_array(json_wtr); | ||
325 | } | ||
326 | |||
327 | int build_pinned_obj_table(struct pinned_obj_table *tab, | ||
328 | enum bpf_obj_type type) | ||
329 | { | ||
330 | struct bpf_prog_info pinned_info = {}; | ||
331 | struct pinned_obj *obj_node = NULL; | ||
332 | __u32 len = sizeof(pinned_info); | ||
333 | struct mntent *mntent = NULL; | ||
334 | enum bpf_obj_type objtype; | ||
335 | FILE *mntfile = NULL; | ||
336 | FTSENT *ftse = NULL; | ||
337 | FTS *fts = NULL; | ||
338 | int fd, err; | ||
339 | |||
340 | mntfile = setmntent("/proc/mounts", "r"); | ||
341 | if (!mntfile) | ||
342 | return -1; | ||
343 | |||
344 | while ((mntent = getmntent(mntfile))) { | ||
345 | char *path[] = { mntent->mnt_dir, NULL }; | ||
346 | |||
347 | if (strncmp(mntent->mnt_type, "bpf", 3) != 0) | ||
348 | continue; | ||
349 | |||
350 | fts = fts_open(path, 0, NULL); | ||
351 | if (!fts) | ||
352 | continue; | ||
353 | |||
354 | while ((ftse = fts_read(fts))) { | ||
355 | if (!(ftse->fts_info & FTS_F)) | ||
356 | continue; | ||
357 | fd = open_obj_pinned(ftse->fts_path); | ||
358 | if (fd < 0) | ||
359 | continue; | ||
360 | |||
361 | objtype = get_fd_type(fd); | ||
362 | if (objtype != type) { | ||
363 | close(fd); | ||
364 | continue; | ||
365 | } | ||
366 | memset(&pinned_info, 0, sizeof(pinned_info)); | ||
367 | err = bpf_obj_get_info_by_fd(fd, &pinned_info, &len); | ||
368 | if (err) { | ||
369 | close(fd); | ||
370 | continue; | ||
371 | } | ||
372 | |||
373 | obj_node = malloc(sizeof(*obj_node)); | ||
374 | if (!obj_node) { | ||
375 | close(fd); | ||
376 | fts_close(fts); | ||
377 | fclose(mntfile); | ||
378 | return -1; | ||
379 | } | ||
380 | |||
381 | memset(obj_node, 0, sizeof(*obj_node)); | ||
382 | obj_node->id = pinned_info.id; | ||
383 | obj_node->path = strdup(ftse->fts_path); | ||
384 | hash_add(tab->table, &obj_node->hash, obj_node->id); | ||
385 | |||
386 | close(fd); | ||
387 | } | ||
388 | fts_close(fts); | ||
389 | } | ||
390 | fclose(mntfile); | ||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | void delete_pinned_obj_table(struct pinned_obj_table *tab) | ||
395 | { | ||
396 | struct pinned_obj *obj; | ||
397 | struct hlist_node *tmp; | ||
398 | unsigned int bkt; | ||
399 | |||
400 | hash_for_each_safe(tab->table, bkt, tmp, obj, hash) { | ||
401 | hash_del(&obj->hash); | ||
402 | free(obj->path); | ||
403 | free(obj); | ||
404 | } | ||
405 | } | ||
diff --git a/tools/bpf/bpftool/jit_disasm.c b/tools/bpf/bpftool/jit_disasm.c new file mode 100644 index 000000000000..1551d3918d4c --- /dev/null +++ b/tools/bpf/bpftool/jit_disasm.c | |||
@@ -0,0 +1,162 @@ | |||
1 | /* | ||
2 | * Based on: | ||
3 | * | ||
4 | * Minimal BPF JIT image disassembler | ||
5 | * | ||
6 | * Disassembles BPF JIT compiler emitted opcodes back to asm insn's for | ||
7 | * debugging or verification purposes. | ||
8 | * | ||
9 | * Copyright 2013 Daniel Borkmann <daniel@iogearbox.net> | ||
10 | * Licensed under the GNU General Public License, version 2.0 (GPLv2) | ||
11 | */ | ||
12 | |||
13 | #include <stdarg.h> | ||
14 | #include <stdint.h> | ||
15 | #include <stdio.h> | ||
16 | #include <stdlib.h> | ||
17 | #include <assert.h> | ||
18 | #include <unistd.h> | ||
19 | #include <string.h> | ||
20 | #include <bfd.h> | ||
21 | #include <dis-asm.h> | ||
22 | #include <sys/types.h> | ||
23 | #include <sys/stat.h> | ||
24 | #include <limits.h> | ||
25 | |||
26 | #include "json_writer.h" | ||
27 | #include "main.h" | ||
28 | |||
29 | static void get_exec_path(char *tpath, size_t size) | ||
30 | { | ||
31 | ssize_t len; | ||
32 | char *path; | ||
33 | |||
34 | snprintf(tpath, size, "/proc/%d/exe", (int) getpid()); | ||
35 | tpath[size - 1] = 0; | ||
36 | |||
37 | path = strdup(tpath); | ||
38 | assert(path); | ||
39 | |||
40 | len = readlink(path, tpath, size - 1); | ||
41 | assert(len > 0); | ||
42 | tpath[len] = 0; | ||
43 | |||
44 | free(path); | ||
45 | } | ||
46 | |||
47 | static int oper_count; | ||
48 | static int fprintf_json(void *out, const char *fmt, ...) | ||
49 | { | ||
50 | va_list ap; | ||
51 | char *s; | ||
52 | |||
53 | va_start(ap, fmt); | ||
54 | if (!oper_count) { | ||
55 | int i; | ||
56 | |||
57 | s = va_arg(ap, char *); | ||
58 | |||
59 | /* Strip trailing spaces */ | ||
60 | i = strlen(s) - 1; | ||
61 | while (s[i] == ' ') | ||
62 | s[i--] = '\0'; | ||
63 | |||
64 | jsonw_string_field(json_wtr, "operation", s); | ||
65 | jsonw_name(json_wtr, "operands"); | ||
66 | jsonw_start_array(json_wtr); | ||
67 | oper_count++; | ||
68 | } else if (!strcmp(fmt, ",")) { | ||
69 | /* Skip */ | ||
70 | } else { | ||
71 | s = va_arg(ap, char *); | ||
72 | jsonw_string(json_wtr, s); | ||
73 | oper_count++; | ||
74 | } | ||
75 | va_end(ap); | ||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes) | ||
80 | { | ||
81 | disassembler_ftype disassemble; | ||
82 | struct disassemble_info info; | ||
83 | int count, i, pc = 0; | ||
84 | char tpath[PATH_MAX]; | ||
85 | bfd *bfdf; | ||
86 | |||
87 | if (!len) | ||
88 | return; | ||
89 | |||
90 | memset(tpath, 0, sizeof(tpath)); | ||
91 | get_exec_path(tpath, sizeof(tpath)); | ||
92 | |||
93 | bfdf = bfd_openr(tpath, NULL); | ||
94 | assert(bfdf); | ||
95 | assert(bfd_check_format(bfdf, bfd_object)); | ||
96 | |||
97 | if (json_output) | ||
98 | init_disassemble_info(&info, stdout, | ||
99 | (fprintf_ftype) fprintf_json); | ||
100 | else | ||
101 | init_disassemble_info(&info, stdout, | ||
102 | (fprintf_ftype) fprintf); | ||
103 | info.arch = bfd_get_arch(bfdf); | ||
104 | info.mach = bfd_get_mach(bfdf); | ||
105 | info.buffer = image; | ||
106 | info.buffer_length = len; | ||
107 | |||
108 | disassemble_init_for_target(&info); | ||
109 | |||
110 | disassemble = disassembler(bfdf); | ||
111 | assert(disassemble); | ||
112 | |||
113 | if (json_output) | ||
114 | jsonw_start_array(json_wtr); | ||
115 | do { | ||
116 | if (json_output) { | ||
117 | jsonw_start_object(json_wtr); | ||
118 | oper_count = 0; | ||
119 | jsonw_name(json_wtr, "pc"); | ||
120 | jsonw_printf(json_wtr, "\"0x%x\"", pc); | ||
121 | } else { | ||
122 | printf("%4x:\t", pc); | ||
123 | } | ||
124 | |||
125 | count = disassemble(pc, &info); | ||
126 | if (json_output) { | ||
127 | /* Operand array, was started in fprintf_json. Before | ||
128 | * that, make sure we have a _null_ value if no operand | ||
129 | * other than operation code was present. | ||
130 | */ | ||
131 | if (oper_count == 1) | ||
132 | jsonw_null(json_wtr); | ||
133 | jsonw_end_array(json_wtr); | ||
134 | } | ||
135 | |||
136 | if (opcodes) { | ||
137 | if (json_output) { | ||
138 | jsonw_name(json_wtr, "opcodes"); | ||
139 | jsonw_start_array(json_wtr); | ||
140 | for (i = 0; i < count; ++i) | ||
141 | jsonw_printf(json_wtr, "\"0x%02hhx\"", | ||
142 | (uint8_t)image[pc + i]); | ||
143 | jsonw_end_array(json_wtr); | ||
144 | } else { | ||
145 | printf("\n\t"); | ||
146 | for (i = 0; i < count; ++i) | ||
147 | printf("%02x ", | ||
148 | (uint8_t)image[pc + i]); | ||
149 | } | ||
150 | } | ||
151 | if (json_output) | ||
152 | jsonw_end_object(json_wtr); | ||
153 | else | ||
154 | printf("\n"); | ||
155 | |||
156 | pc += count; | ||
157 | } while (count > 0 && pc < len); | ||
158 | if (json_output) | ||
159 | jsonw_end_array(json_wtr); | ||
160 | |||
161 | bfd_close(bfdf); | ||
162 | } | ||
diff --git a/tools/bpf/bpftool/json_writer.c b/tools/bpf/bpftool/json_writer.c new file mode 100644 index 000000000000..c6eef76322ae --- /dev/null +++ b/tools/bpf/bpftool/json_writer.c | |||
@@ -0,0 +1,356 @@ | |||
1 | /* | ||
2 | * Simple streaming JSON writer | ||
3 | * | ||
4 | * This takes care of the annoying bits of JSON syntax like the commas | ||
5 | * after elements | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version | ||
10 | * 2 of the License, or (at your option) any later version. | ||
11 | * | ||
12 | * Authors: Stephen Hemminger <stephen@networkplumber.org> | ||
13 | */ | ||
14 | |||
15 | #include <stdio.h> | ||
16 | #include <stdbool.h> | ||
17 | #include <stdarg.h> | ||
18 | #include <assert.h> | ||
19 | #include <malloc.h> | ||
20 | #include <inttypes.h> | ||
21 | #include <stdint.h> | ||
22 | |||
23 | #include "json_writer.h" | ||
24 | |||
25 | struct json_writer { | ||
26 | FILE *out; /* output file */ | ||
27 | unsigned depth; /* nesting */ | ||
28 | bool pretty; /* optional whitepace */ | ||
29 | char sep; /* either nul or comma */ | ||
30 | }; | ||
31 | |||
32 | /* indentation for pretty print */ | ||
33 | static void jsonw_indent(json_writer_t *self) | ||
34 | { | ||
35 | unsigned i; | ||
36 | for (i = 0; i < self->depth; ++i) | ||
37 | fputs(" ", self->out); | ||
38 | } | ||
39 | |||
40 | /* end current line and indent if pretty printing */ | ||
41 | static void jsonw_eol(json_writer_t *self) | ||
42 | { | ||
43 | if (!self->pretty) | ||
44 | return; | ||
45 | |||
46 | putc('\n', self->out); | ||
47 | jsonw_indent(self); | ||
48 | } | ||
49 | |||
50 | /* If current object is not empty print a comma */ | ||
51 | static void jsonw_eor(json_writer_t *self) | ||
52 | { | ||
53 | if (self->sep != '\0') | ||
54 | putc(self->sep, self->out); | ||
55 | self->sep = ','; | ||
56 | } | ||
57 | |||
58 | |||
59 | /* Output JSON encoded string */ | ||
60 | /* Handles C escapes, does not do Unicode */ | ||
61 | static void jsonw_puts(json_writer_t *self, const char *str) | ||
62 | { | ||
63 | putc('"', self->out); | ||
64 | for (; *str; ++str) | ||
65 | switch (*str) { | ||
66 | case '\t': | ||
67 | fputs("\\t", self->out); | ||
68 | break; | ||
69 | case '\n': | ||
70 | fputs("\\n", self->out); | ||
71 | break; | ||
72 | case '\r': | ||
73 | fputs("\\r", self->out); | ||
74 | break; | ||
75 | case '\f': | ||
76 | fputs("\\f", self->out); | ||
77 | break; | ||
78 | case '\b': | ||
79 | fputs("\\b", self->out); | ||
80 | break; | ||
81 | case '\\': | ||
82 | fputs("\\n", self->out); | ||
83 | break; | ||
84 | case '"': | ||
85 | fputs("\\\"", self->out); | ||
86 | break; | ||
87 | case '\'': | ||
88 | fputs("\\\'", self->out); | ||
89 | break; | ||
90 | default: | ||
91 | putc(*str, self->out); | ||
92 | } | ||
93 | putc('"', self->out); | ||
94 | } | ||
95 | |||
96 | /* Create a new JSON stream */ | ||
97 | json_writer_t *jsonw_new(FILE *f) | ||
98 | { | ||
99 | json_writer_t *self = malloc(sizeof(*self)); | ||
100 | if (self) { | ||
101 | self->out = f; | ||
102 | self->depth = 0; | ||
103 | self->pretty = false; | ||
104 | self->sep = '\0'; | ||
105 | } | ||
106 | return self; | ||
107 | } | ||
108 | |||
109 | /* End output to JSON stream */ | ||
110 | void jsonw_destroy(json_writer_t **self_p) | ||
111 | { | ||
112 | json_writer_t *self = *self_p; | ||
113 | |||
114 | assert(self->depth == 0); | ||
115 | fputs("\n", self->out); | ||
116 | fflush(self->out); | ||
117 | free(self); | ||
118 | *self_p = NULL; | ||
119 | } | ||
120 | |||
121 | void jsonw_pretty(json_writer_t *self, bool on) | ||
122 | { | ||
123 | self->pretty = on; | ||
124 | } | ||
125 | |||
126 | /* Basic blocks */ | ||
127 | static void jsonw_begin(json_writer_t *self, int c) | ||
128 | { | ||
129 | jsonw_eor(self); | ||
130 | putc(c, self->out); | ||
131 | ++self->depth; | ||
132 | self->sep = '\0'; | ||
133 | } | ||
134 | |||
135 | static void jsonw_end(json_writer_t *self, int c) | ||
136 | { | ||
137 | assert(self->depth > 0); | ||
138 | |||
139 | --self->depth; | ||
140 | if (self->sep != '\0') | ||
141 | jsonw_eol(self); | ||
142 | putc(c, self->out); | ||
143 | self->sep = ','; | ||
144 | } | ||
145 | |||
146 | |||
147 | /* Add a JSON property name */ | ||
148 | void jsonw_name(json_writer_t *self, const char *name) | ||
149 | { | ||
150 | jsonw_eor(self); | ||
151 | jsonw_eol(self); | ||
152 | self->sep = '\0'; | ||
153 | jsonw_puts(self, name); | ||
154 | putc(':', self->out); | ||
155 | if (self->pretty) | ||
156 | putc(' ', self->out); | ||
157 | } | ||
158 | |||
159 | void jsonw_vprintf_enquote(json_writer_t *self, const char *fmt, va_list ap) | ||
160 | { | ||
161 | jsonw_eor(self); | ||
162 | putc('"', self->out); | ||
163 | vfprintf(self->out, fmt, ap); | ||
164 | putc('"', self->out); | ||
165 | } | ||
166 | |||
167 | void jsonw_printf(json_writer_t *self, const char *fmt, ...) | ||
168 | { | ||
169 | va_list ap; | ||
170 | |||
171 | va_start(ap, fmt); | ||
172 | jsonw_eor(self); | ||
173 | vfprintf(self->out, fmt, ap); | ||
174 | va_end(ap); | ||
175 | } | ||
176 | |||
177 | /* Collections */ | ||
178 | void jsonw_start_object(json_writer_t *self) | ||
179 | { | ||
180 | jsonw_begin(self, '{'); | ||
181 | } | ||
182 | |||
183 | void jsonw_end_object(json_writer_t *self) | ||
184 | { | ||
185 | jsonw_end(self, '}'); | ||
186 | } | ||
187 | |||
188 | void jsonw_start_array(json_writer_t *self) | ||
189 | { | ||
190 | jsonw_begin(self, '['); | ||
191 | } | ||
192 | |||
193 | void jsonw_end_array(json_writer_t *self) | ||
194 | { | ||
195 | jsonw_end(self, ']'); | ||
196 | } | ||
197 | |||
198 | /* JSON value types */ | ||
199 | void jsonw_string(json_writer_t *self, const char *value) | ||
200 | { | ||
201 | jsonw_eor(self); | ||
202 | jsonw_puts(self, value); | ||
203 | } | ||
204 | |||
205 | void jsonw_bool(json_writer_t *self, bool val) | ||
206 | { | ||
207 | jsonw_printf(self, "%s", val ? "true" : "false"); | ||
208 | } | ||
209 | |||
210 | void jsonw_null(json_writer_t *self) | ||
211 | { | ||
212 | jsonw_printf(self, "null"); | ||
213 | } | ||
214 | |||
215 | void jsonw_float_fmt(json_writer_t *self, const char *fmt, double num) | ||
216 | { | ||
217 | jsonw_printf(self, fmt, num); | ||
218 | } | ||
219 | |||
220 | #ifdef notused | ||
221 | void jsonw_float(json_writer_t *self, double num) | ||
222 | { | ||
223 | jsonw_printf(self, "%g", num); | ||
224 | } | ||
225 | #endif | ||
226 | |||
227 | void jsonw_hu(json_writer_t *self, unsigned short num) | ||
228 | { | ||
229 | jsonw_printf(self, "%hu", num); | ||
230 | } | ||
231 | |||
232 | void jsonw_uint(json_writer_t *self, uint64_t num) | ||
233 | { | ||
234 | jsonw_printf(self, "%"PRIu64, num); | ||
235 | } | ||
236 | |||
237 | void jsonw_lluint(json_writer_t *self, unsigned long long int num) | ||
238 | { | ||
239 | jsonw_printf(self, "%llu", num); | ||
240 | } | ||
241 | |||
242 | void jsonw_int(json_writer_t *self, int64_t num) | ||
243 | { | ||
244 | jsonw_printf(self, "%"PRId64, num); | ||
245 | } | ||
246 | |||
247 | /* Basic name/value objects */ | ||
248 | void jsonw_string_field(json_writer_t *self, const char *prop, const char *val) | ||
249 | { | ||
250 | jsonw_name(self, prop); | ||
251 | jsonw_string(self, val); | ||
252 | } | ||
253 | |||
254 | void jsonw_bool_field(json_writer_t *self, const char *prop, bool val) | ||
255 | { | ||
256 | jsonw_name(self, prop); | ||
257 | jsonw_bool(self, val); | ||
258 | } | ||
259 | |||
260 | #ifdef notused | ||
261 | void jsonw_float_field(json_writer_t *self, const char *prop, double val) | ||
262 | { | ||
263 | jsonw_name(self, prop); | ||
264 | jsonw_float(self, val); | ||
265 | } | ||
266 | #endif | ||
267 | |||
268 | void jsonw_float_field_fmt(json_writer_t *self, | ||
269 | const char *prop, | ||
270 | const char *fmt, | ||
271 | double val) | ||
272 | { | ||
273 | jsonw_name(self, prop); | ||
274 | jsonw_float_fmt(self, fmt, val); | ||
275 | } | ||
276 | |||
277 | void jsonw_uint_field(json_writer_t *self, const char *prop, uint64_t num) | ||
278 | { | ||
279 | jsonw_name(self, prop); | ||
280 | jsonw_uint(self, num); | ||
281 | } | ||
282 | |||
283 | void jsonw_hu_field(json_writer_t *self, const char *prop, unsigned short num) | ||
284 | { | ||
285 | jsonw_name(self, prop); | ||
286 | jsonw_hu(self, num); | ||
287 | } | ||
288 | |||
289 | void jsonw_lluint_field(json_writer_t *self, | ||
290 | const char *prop, | ||
291 | unsigned long long int num) | ||
292 | { | ||
293 | jsonw_name(self, prop); | ||
294 | jsonw_lluint(self, num); | ||
295 | } | ||
296 | |||
297 | void jsonw_int_field(json_writer_t *self, const char *prop, int64_t num) | ||
298 | { | ||
299 | jsonw_name(self, prop); | ||
300 | jsonw_int(self, num); | ||
301 | } | ||
302 | |||
303 | void jsonw_null_field(json_writer_t *self, const char *prop) | ||
304 | { | ||
305 | jsonw_name(self, prop); | ||
306 | jsonw_null(self); | ||
307 | } | ||
308 | |||
309 | #ifdef TEST | ||
310 | int main(int argc, char **argv) | ||
311 | { | ||
312 | json_writer_t *wr = jsonw_new(stdout); | ||
313 | |||
314 | jsonw_start_object(wr); | ||
315 | jsonw_pretty(wr, true); | ||
316 | jsonw_name(wr, "Vyatta"); | ||
317 | jsonw_start_object(wr); | ||
318 | jsonw_string_field(wr, "url", "http://vyatta.com"); | ||
319 | jsonw_uint_field(wr, "downloads", 2000000ul); | ||
320 | jsonw_float_field(wr, "stock", 8.16); | ||
321 | |||
322 | jsonw_name(wr, "ARGV"); | ||
323 | jsonw_start_array(wr); | ||
324 | while (--argc) | ||
325 | jsonw_string(wr, *++argv); | ||
326 | jsonw_end_array(wr); | ||
327 | |||
328 | jsonw_name(wr, "empty"); | ||
329 | jsonw_start_array(wr); | ||
330 | jsonw_end_array(wr); | ||
331 | |||
332 | jsonw_name(wr, "NIL"); | ||
333 | jsonw_start_object(wr); | ||
334 | jsonw_end_object(wr); | ||
335 | |||
336 | jsonw_null_field(wr, "my_null"); | ||
337 | |||
338 | jsonw_name(wr, "special chars"); | ||
339 | jsonw_start_array(wr); | ||
340 | jsonw_string_field(wr, "slash", "/"); | ||
341 | jsonw_string_field(wr, "newline", "\n"); | ||
342 | jsonw_string_field(wr, "tab", "\t"); | ||
343 | jsonw_string_field(wr, "ff", "\f"); | ||
344 | jsonw_string_field(wr, "quote", "\""); | ||
345 | jsonw_string_field(wr, "tick", "\'"); | ||
346 | jsonw_string_field(wr, "backslash", "\\"); | ||
347 | jsonw_end_array(wr); | ||
348 | |||
349 | jsonw_end_object(wr); | ||
350 | |||
351 | jsonw_end_object(wr); | ||
352 | jsonw_destroy(&wr); | ||
353 | return 0; | ||
354 | } | ||
355 | |||
356 | #endif | ||
diff --git a/tools/bpf/bpftool/json_writer.h b/tools/bpf/bpftool/json_writer.h new file mode 100644 index 000000000000..0fa2fb1b6351 --- /dev/null +++ b/tools/bpf/bpftool/json_writer.h | |||
@@ -0,0 +1,72 @@ | |||
1 | /* | ||
2 | * Simple streaming JSON writer | ||
3 | * | ||
4 | * This takes care of the annoying bits of JSON syntax like the commas | ||
5 | * after elements | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version | ||
10 | * 2 of the License, or (at your option) any later version. | ||
11 | * | ||
12 | * Authors: Stephen Hemminger <stephen@networkplumber.org> | ||
13 | */ | ||
14 | |||
15 | #ifndef _JSON_WRITER_H_ | ||
16 | #define _JSON_WRITER_H_ | ||
17 | |||
18 | #include <stdbool.h> | ||
19 | #include <stdint.h> | ||
20 | #include <stdarg.h> | ||
21 | |||
22 | /* Opaque class structure */ | ||
23 | typedef struct json_writer json_writer_t; | ||
24 | |||
25 | /* Create a new JSON stream */ | ||
26 | json_writer_t *jsonw_new(FILE *f); | ||
27 | /* End output to JSON stream */ | ||
28 | void jsonw_destroy(json_writer_t **self_p); | ||
29 | |||
30 | /* Cause output to have pretty whitespace */ | ||
31 | void jsonw_pretty(json_writer_t *self, bool on); | ||
32 | |||
33 | /* Add property name */ | ||
34 | void jsonw_name(json_writer_t *self, const char *name); | ||
35 | |||
36 | /* Add value */ | ||
37 | void jsonw_vprintf_enquote(json_writer_t *self, const char *fmt, va_list ap); | ||
38 | void jsonw_printf(json_writer_t *self, const char *fmt, ...); | ||
39 | void jsonw_string(json_writer_t *self, const char *value); | ||
40 | void jsonw_bool(json_writer_t *self, bool value); | ||
41 | void jsonw_float(json_writer_t *self, double number); | ||
42 | void jsonw_float_fmt(json_writer_t *self, const char *fmt, double num); | ||
43 | void jsonw_uint(json_writer_t *self, uint64_t number); | ||
44 | void jsonw_hu(json_writer_t *self, unsigned short number); | ||
45 | void jsonw_int(json_writer_t *self, int64_t number); | ||
46 | void jsonw_null(json_writer_t *self); | ||
47 | void jsonw_lluint(json_writer_t *self, unsigned long long int num); | ||
48 | |||
49 | /* Useful Combinations of name and value */ | ||
50 | void jsonw_string_field(json_writer_t *self, const char *prop, const char *val); | ||
51 | void jsonw_bool_field(json_writer_t *self, const char *prop, bool value); | ||
52 | void jsonw_float_field(json_writer_t *self, const char *prop, double num); | ||
53 | void jsonw_uint_field(json_writer_t *self, const char *prop, uint64_t num); | ||
54 | void jsonw_hu_field(json_writer_t *self, const char *prop, unsigned short num); | ||
55 | void jsonw_int_field(json_writer_t *self, const char *prop, int64_t num); | ||
56 | void jsonw_null_field(json_writer_t *self, const char *prop); | ||
57 | void jsonw_lluint_field(json_writer_t *self, const char *prop, | ||
58 | unsigned long long int num); | ||
59 | void jsonw_float_field_fmt(json_writer_t *self, const char *prop, | ||
60 | const char *fmt, double val); | ||
61 | |||
62 | /* Collections */ | ||
63 | void jsonw_start_object(json_writer_t *self); | ||
64 | void jsonw_end_object(json_writer_t *self); | ||
65 | |||
66 | void jsonw_start_array(json_writer_t *self); | ||
67 | void jsonw_end_array(json_writer_t *self); | ||
68 | |||
69 | /* Override default exception handling */ | ||
70 | typedef void (jsonw_err_handler_fn)(const char *); | ||
71 | |||
72 | #endif /* _JSON_WRITER_H_ */ | ||
diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c new file mode 100644 index 000000000000..d294bc8168be --- /dev/null +++ b/tools/bpf/bpftool/main.c | |||
@@ -0,0 +1,343 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 Netronome Systems, Inc. | ||
3 | * | ||
4 | * This software is dual licensed under the GNU General License Version 2, | ||
5 | * June 1991 as shown in the file COPYING in the top-level directory of this | ||
6 | * source tree or the BSD 2-Clause License provided below. You have the | ||
7 | * option to license this software under the complete terms of either license. | ||
8 | * | ||
9 | * The BSD 2-Clause License: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or | ||
12 | * without modification, are permitted provided that the following | ||
13 | * conditions are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above | ||
16 | * copyright notice, this list of conditions and the following | ||
17 | * disclaimer. | ||
18 | * | ||
19 | * 2. Redistributions in binary form must reproduce the above | ||
20 | * copyright notice, this list of conditions and the following | ||
21 | * disclaimer in the documentation and/or other materials | ||
22 | * provided with the distribution. | ||
23 | * | ||
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
28 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
29 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
31 | * SOFTWARE. | ||
32 | */ | ||
33 | |||
34 | /* Author: Jakub Kicinski <kubakici@wp.pl> */ | ||
35 | |||
36 | #include <bfd.h> | ||
37 | #include <ctype.h> | ||
38 | #include <errno.h> | ||
39 | #include <getopt.h> | ||
40 | #include <linux/bpf.h> | ||
41 | #include <linux/version.h> | ||
42 | #include <stdio.h> | ||
43 | #include <stdlib.h> | ||
44 | #include <string.h> | ||
45 | |||
46 | #include <bpf.h> | ||
47 | |||
48 | #include "main.h" | ||
49 | |||
50 | const char *bin_name; | ||
51 | static int last_argc; | ||
52 | static char **last_argv; | ||
53 | static int (*last_do_help)(int argc, char **argv); | ||
54 | json_writer_t *json_wtr; | ||
55 | bool pretty_output; | ||
56 | bool json_output; | ||
57 | bool show_pinned; | ||
58 | struct pinned_obj_table prog_table; | ||
59 | struct pinned_obj_table map_table; | ||
60 | |||
61 | static void __noreturn clean_and_exit(int i) | ||
62 | { | ||
63 | if (json_output) | ||
64 | jsonw_destroy(&json_wtr); | ||
65 | |||
66 | exit(i); | ||
67 | } | ||
68 | |||
69 | void usage(void) | ||
70 | { | ||
71 | last_do_help(last_argc - 1, last_argv + 1); | ||
72 | |||
73 | clean_and_exit(-1); | ||
74 | } | ||
75 | |||
76 | static int do_help(int argc, char **argv) | ||
77 | { | ||
78 | if (json_output) { | ||
79 | jsonw_null(json_wtr); | ||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | fprintf(stderr, | ||
84 | "Usage: %s [OPTIONS] OBJECT { COMMAND | help }\n" | ||
85 | " %s batch file FILE\n" | ||
86 | " %s version\n" | ||
87 | "\n" | ||
88 | " OBJECT := { prog | map }\n" | ||
89 | " " HELP_SPEC_OPTIONS "\n" | ||
90 | "", | ||
91 | bin_name, bin_name, bin_name); | ||
92 | |||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static int do_version(int argc, char **argv) | ||
97 | { | ||
98 | unsigned int version[3]; | ||
99 | |||
100 | version[0] = LINUX_VERSION_CODE >> 16; | ||
101 | version[1] = LINUX_VERSION_CODE >> 8 & 0xf; | ||
102 | version[2] = LINUX_VERSION_CODE & 0xf; | ||
103 | |||
104 | if (json_output) { | ||
105 | jsonw_start_object(json_wtr); | ||
106 | jsonw_name(json_wtr, "version"); | ||
107 | jsonw_printf(json_wtr, "\"%u.%u.%u\"", | ||
108 | version[0], version[1], version[2]); | ||
109 | jsonw_end_object(json_wtr); | ||
110 | } else { | ||
111 | printf("%s v%u.%u.%u\n", bin_name, | ||
112 | version[0], version[1], version[2]); | ||
113 | } | ||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | int cmd_select(const struct cmd *cmds, int argc, char **argv, | ||
118 | int (*help)(int argc, char **argv)) | ||
119 | { | ||
120 | unsigned int i; | ||
121 | |||
122 | last_argc = argc; | ||
123 | last_argv = argv; | ||
124 | last_do_help = help; | ||
125 | |||
126 | if (argc < 1 && cmds[0].func) | ||
127 | return cmds[0].func(argc, argv); | ||
128 | |||
129 | for (i = 0; cmds[i].func; i++) | ||
130 | if (is_prefix(*argv, cmds[i].cmd)) | ||
131 | return cmds[i].func(argc - 1, argv + 1); | ||
132 | |||
133 | help(argc - 1, argv + 1); | ||
134 | |||
135 | return -1; | ||
136 | } | ||
137 | |||
138 | bool is_prefix(const char *pfx, const char *str) | ||
139 | { | ||
140 | if (!pfx) | ||
141 | return false; | ||
142 | if (strlen(str) < strlen(pfx)) | ||
143 | return false; | ||
144 | |||
145 | return !memcmp(str, pfx, strlen(pfx)); | ||
146 | } | ||
147 | |||
148 | void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep) | ||
149 | { | ||
150 | unsigned char *data = arg; | ||
151 | unsigned int i; | ||
152 | |||
153 | for (i = 0; i < n; i++) { | ||
154 | const char *pfx = ""; | ||
155 | |||
156 | if (!i) | ||
157 | /* nothing */; | ||
158 | else if (!(i % 16)) | ||
159 | fprintf(f, "\n"); | ||
160 | else if (!(i % 8)) | ||
161 | fprintf(f, " "); | ||
162 | else | ||
163 | pfx = sep; | ||
164 | |||
165 | fprintf(f, "%s%02hhx", i ? pfx : "", data[i]); | ||
166 | } | ||
167 | } | ||
168 | |||
169 | static int do_batch(int argc, char **argv); | ||
170 | |||
171 | static const struct cmd cmds[] = { | ||
172 | { "help", do_help }, | ||
173 | { "batch", do_batch }, | ||
174 | { "prog", do_prog }, | ||
175 | { "map", do_map }, | ||
176 | { "version", do_version }, | ||
177 | { 0 } | ||
178 | }; | ||
179 | |||
180 | static int do_batch(int argc, char **argv) | ||
181 | { | ||
182 | unsigned int lines = 0; | ||
183 | char *n_argv[4096]; | ||
184 | char buf[65536]; | ||
185 | int n_argc; | ||
186 | FILE *fp; | ||
187 | int err; | ||
188 | int i; | ||
189 | |||
190 | if (argc < 2) { | ||
191 | p_err("too few parameters for batch"); | ||
192 | return -1; | ||
193 | } else if (!is_prefix(*argv, "file")) { | ||
194 | p_err("expected 'file', got: %s", *argv); | ||
195 | return -1; | ||
196 | } else if (argc > 2) { | ||
197 | p_err("too many parameters for batch"); | ||
198 | return -1; | ||
199 | } | ||
200 | NEXT_ARG(); | ||
201 | |||
202 | fp = fopen(*argv, "r"); | ||
203 | if (!fp) { | ||
204 | p_err("Can't open file (%s): %s", *argv, strerror(errno)); | ||
205 | return -1; | ||
206 | } | ||
207 | |||
208 | if (json_output) | ||
209 | jsonw_start_array(json_wtr); | ||
210 | while (fgets(buf, sizeof(buf), fp)) { | ||
211 | if (strlen(buf) == sizeof(buf) - 1) { | ||
212 | errno = E2BIG; | ||
213 | break; | ||
214 | } | ||
215 | |||
216 | n_argc = 0; | ||
217 | n_argv[n_argc] = strtok(buf, " \t\n"); | ||
218 | |||
219 | while (n_argv[n_argc]) { | ||
220 | n_argc++; | ||
221 | if (n_argc == ARRAY_SIZE(n_argv)) { | ||
222 | p_err("line %d has too many arguments, skip", | ||
223 | lines); | ||
224 | n_argc = 0; | ||
225 | break; | ||
226 | } | ||
227 | n_argv[n_argc] = strtok(NULL, " \t\n"); | ||
228 | } | ||
229 | |||
230 | if (!n_argc) | ||
231 | continue; | ||
232 | |||
233 | if (json_output) { | ||
234 | jsonw_start_object(json_wtr); | ||
235 | jsonw_name(json_wtr, "command"); | ||
236 | jsonw_start_array(json_wtr); | ||
237 | for (i = 0; i < n_argc; i++) | ||
238 | jsonw_string(json_wtr, n_argv[i]); | ||
239 | jsonw_end_array(json_wtr); | ||
240 | jsonw_name(json_wtr, "output"); | ||
241 | } | ||
242 | |||
243 | err = cmd_select(cmds, n_argc, n_argv, do_help); | ||
244 | |||
245 | if (json_output) | ||
246 | jsonw_end_object(json_wtr); | ||
247 | |||
248 | if (err) | ||
249 | goto err_close; | ||
250 | |||
251 | lines++; | ||
252 | } | ||
253 | |||
254 | if (errno && errno != ENOENT) { | ||
255 | perror("reading batch file failed"); | ||
256 | err = -1; | ||
257 | } else { | ||
258 | p_info("processed %d lines", lines); | ||
259 | err = 0; | ||
260 | } | ||
261 | err_close: | ||
262 | fclose(fp); | ||
263 | |||
264 | if (json_output) | ||
265 | jsonw_end_array(json_wtr); | ||
266 | |||
267 | return err; | ||
268 | } | ||
269 | |||
270 | int main(int argc, char **argv) | ||
271 | { | ||
272 | static const struct option options[] = { | ||
273 | { "json", no_argument, NULL, 'j' }, | ||
274 | { "help", no_argument, NULL, 'h' }, | ||
275 | { "pretty", no_argument, NULL, 'p' }, | ||
276 | { "version", no_argument, NULL, 'V' }, | ||
277 | { "bpffs", no_argument, NULL, 'f' }, | ||
278 | { 0 } | ||
279 | }; | ||
280 | int opt, ret; | ||
281 | |||
282 | last_do_help = do_help; | ||
283 | pretty_output = false; | ||
284 | json_output = false; | ||
285 | show_pinned = false; | ||
286 | bin_name = argv[0]; | ||
287 | |||
288 | hash_init(prog_table.table); | ||
289 | hash_init(map_table.table); | ||
290 | |||
291 | opterr = 0; | ||
292 | while ((opt = getopt_long(argc, argv, "Vhpjf", | ||
293 | options, NULL)) >= 0) { | ||
294 | switch (opt) { | ||
295 | case 'V': | ||
296 | return do_version(argc, argv); | ||
297 | case 'h': | ||
298 | return do_help(argc, argv); | ||
299 | case 'p': | ||
300 | pretty_output = true; | ||
301 | /* fall through */ | ||
302 | case 'j': | ||
303 | if (!json_output) { | ||
304 | json_wtr = jsonw_new(stdout); | ||
305 | if (!json_wtr) { | ||
306 | p_err("failed to create JSON writer"); | ||
307 | return -1; | ||
308 | } | ||
309 | json_output = true; | ||
310 | } | ||
311 | jsonw_pretty(json_wtr, pretty_output); | ||
312 | break; | ||
313 | case 'f': | ||
314 | show_pinned = true; | ||
315 | break; | ||
316 | default: | ||
317 | p_err("unrecognized option '%s'", argv[optind - 1]); | ||
318 | if (json_output) | ||
319 | clean_and_exit(-1); | ||
320 | else | ||
321 | usage(); | ||
322 | } | ||
323 | } | ||
324 | |||
325 | argc -= optind; | ||
326 | argv += optind; | ||
327 | if (argc < 0) | ||
328 | usage(); | ||
329 | |||
330 | bfd_init(); | ||
331 | |||
332 | ret = cmd_select(cmds, argc, argv, do_help); | ||
333 | |||
334 | if (json_output) | ||
335 | jsonw_destroy(&json_wtr); | ||
336 | |||
337 | if (show_pinned) { | ||
338 | delete_pinned_obj_table(&prog_table); | ||
339 | delete_pinned_obj_table(&map_table); | ||
340 | } | ||
341 | |||
342 | return ret; | ||
343 | } | ||
diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h new file mode 100644 index 000000000000..bff330b49791 --- /dev/null +++ b/tools/bpf/bpftool/main.h | |||
@@ -0,0 +1,123 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 Netronome Systems, Inc. | ||
3 | * | ||
4 | * This software is dual licensed under the GNU General License Version 2, | ||
5 | * June 1991 as shown in the file COPYING in the top-level directory of this | ||
6 | * source tree or the BSD 2-Clause License provided below. You have the | ||
7 | * option to license this software under the complete terms of either license. | ||
8 | * | ||
9 | * The BSD 2-Clause License: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or | ||
12 | * without modification, are permitted provided that the following | ||
13 | * conditions are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above | ||
16 | * copyright notice, this list of conditions and the following | ||
17 | * disclaimer. | ||
18 | * | ||
19 | * 2. Redistributions in binary form must reproduce the above | ||
20 | * copyright notice, this list of conditions and the following | ||
21 | * disclaimer in the documentation and/or other materials | ||
22 | * provided with the distribution. | ||
23 | * | ||
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
28 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
29 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
31 | * SOFTWARE. | ||
32 | */ | ||
33 | |||
34 | /* Author: Jakub Kicinski <kubakici@wp.pl> */ | ||
35 | |||
36 | #ifndef __BPF_TOOL_H | ||
37 | #define __BPF_TOOL_H | ||
38 | |||
39 | /* BFD and kernel.h both define GCC_VERSION, differently */ | ||
40 | #undef GCC_VERSION | ||
41 | #include <stdbool.h> | ||
42 | #include <stdio.h> | ||
43 | #include <linux/bpf.h> | ||
44 | #include <linux/compiler.h> | ||
45 | #include <linux/kernel.h> | ||
46 | #include <linux/hashtable.h> | ||
47 | |||
48 | #include "json_writer.h" | ||
49 | |||
50 | #define ptr_to_u64(ptr) ((__u64)(unsigned long)(ptr)) | ||
51 | |||
52 | #define NEXT_ARG() ({ argc--; argv++; if (argc < 0) usage(); }) | ||
53 | #define NEXT_ARGP() ({ (*argc)--; (*argv)++; if (*argc < 0) usage(); }) | ||
54 | #define BAD_ARG() ({ p_err("what is '%s'?", *argv); -1; }) | ||
55 | |||
56 | #define ERR_MAX_LEN 1024 | ||
57 | |||
58 | #define BPF_TAG_FMT "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx" | ||
59 | |||
60 | #define HELP_SPEC_PROGRAM \ | ||
61 | "PROG := { id PROG_ID | pinned FILE | tag PROG_TAG }" | ||
62 | #define HELP_SPEC_OPTIONS \ | ||
63 | "OPTIONS := { {-j|--json} [{-p|--pretty}] | {-f|--bpffs} }" | ||
64 | |||
65 | enum bpf_obj_type { | ||
66 | BPF_OBJ_UNKNOWN, | ||
67 | BPF_OBJ_PROG, | ||
68 | BPF_OBJ_MAP, | ||
69 | }; | ||
70 | |||
71 | extern const char *bin_name; | ||
72 | |||
73 | extern json_writer_t *json_wtr; | ||
74 | extern bool json_output; | ||
75 | extern bool show_pinned; | ||
76 | extern struct pinned_obj_table prog_table; | ||
77 | extern struct pinned_obj_table map_table; | ||
78 | |||
79 | void p_err(const char *fmt, ...); | ||
80 | void p_info(const char *fmt, ...); | ||
81 | |||
82 | bool is_prefix(const char *pfx, const char *str); | ||
83 | void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep); | ||
84 | void usage(void) __noreturn; | ||
85 | |||
86 | struct pinned_obj_table { | ||
87 | DECLARE_HASHTABLE(table, 16); | ||
88 | }; | ||
89 | |||
90 | struct pinned_obj { | ||
91 | __u32 id; | ||
92 | char *path; | ||
93 | struct hlist_node hash; | ||
94 | }; | ||
95 | |||
96 | int build_pinned_obj_table(struct pinned_obj_table *table, | ||
97 | enum bpf_obj_type type); | ||
98 | void delete_pinned_obj_table(struct pinned_obj_table *tab); | ||
99 | |||
100 | struct cmd { | ||
101 | const char *cmd; | ||
102 | int (*func)(int argc, char **argv); | ||
103 | }; | ||
104 | |||
105 | int cmd_select(const struct cmd *cmds, int argc, char **argv, | ||
106 | int (*help)(int argc, char **argv)); | ||
107 | |||
108 | int get_fd_type(int fd); | ||
109 | const char *get_fd_type_name(enum bpf_obj_type type); | ||
110 | char *get_fdinfo(int fd, const char *key); | ||
111 | int open_obj_pinned(char *path); | ||
112 | int open_obj_pinned_any(char *path, enum bpf_obj_type exp_type); | ||
113 | int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(__u32)); | ||
114 | |||
115 | int do_prog(int argc, char **arg); | ||
116 | int do_map(int argc, char **arg); | ||
117 | |||
118 | int prog_parse_fd(int *argc, char ***argv); | ||
119 | |||
120 | void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes); | ||
121 | void print_hex_data_json(uint8_t *data, size_t len); | ||
122 | |||
123 | #endif | ||
diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c new file mode 100644 index 000000000000..e2450c8e88e6 --- /dev/null +++ b/tools/bpf/bpftool/map.c | |||
@@ -0,0 +1,899 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 Netronome Systems, Inc. | ||
3 | * | ||
4 | * This software is dual licensed under the GNU General License Version 2, | ||
5 | * June 1991 as shown in the file COPYING in the top-level directory of this | ||
6 | * source tree or the BSD 2-Clause License provided below. You have the | ||
7 | * option to license this software under the complete terms of either license. | ||
8 | * | ||
9 | * The BSD 2-Clause License: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or | ||
12 | * without modification, are permitted provided that the following | ||
13 | * conditions are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above | ||
16 | * copyright notice, this list of conditions and the following | ||
17 | * disclaimer. | ||
18 | * | ||
19 | * 2. Redistributions in binary form must reproduce the above | ||
20 | * copyright notice, this list of conditions and the following | ||
21 | * disclaimer in the documentation and/or other materials | ||
22 | * provided with the distribution. | ||
23 | * | ||
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
28 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
29 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
31 | * SOFTWARE. | ||
32 | */ | ||
33 | |||
34 | /* Author: Jakub Kicinski <kubakici@wp.pl> */ | ||
35 | |||
36 | #include <assert.h> | ||
37 | #include <ctype.h> | ||
38 | #include <errno.h> | ||
39 | #include <fcntl.h> | ||
40 | #include <stdbool.h> | ||
41 | #include <stdio.h> | ||
42 | #include <stdlib.h> | ||
43 | #include <string.h> | ||
44 | #include <unistd.h> | ||
45 | #include <sys/types.h> | ||
46 | #include <sys/stat.h> | ||
47 | |||
48 | #include <bpf.h> | ||
49 | |||
50 | #include "main.h" | ||
51 | |||
52 | static const char * const map_type_name[] = { | ||
53 | [BPF_MAP_TYPE_UNSPEC] = "unspec", | ||
54 | [BPF_MAP_TYPE_HASH] = "hash", | ||
55 | [BPF_MAP_TYPE_ARRAY] = "array", | ||
56 | [BPF_MAP_TYPE_PROG_ARRAY] = "prog_array", | ||
57 | [BPF_MAP_TYPE_PERF_EVENT_ARRAY] = "perf_event_array", | ||
58 | [BPF_MAP_TYPE_PERCPU_HASH] = "percpu_hash", | ||
59 | [BPF_MAP_TYPE_PERCPU_ARRAY] = "percpu_array", | ||
60 | [BPF_MAP_TYPE_STACK_TRACE] = "stack_trace", | ||
61 | [BPF_MAP_TYPE_CGROUP_ARRAY] = "cgroup_array", | ||
62 | [BPF_MAP_TYPE_LRU_HASH] = "lru_hash", | ||
63 | [BPF_MAP_TYPE_LRU_PERCPU_HASH] = "lru_percpu_hash", | ||
64 | [BPF_MAP_TYPE_LPM_TRIE] = "lpm_trie", | ||
65 | [BPF_MAP_TYPE_ARRAY_OF_MAPS] = "array_of_maps", | ||
66 | [BPF_MAP_TYPE_HASH_OF_MAPS] = "hash_of_maps", | ||
67 | [BPF_MAP_TYPE_DEVMAP] = "devmap", | ||
68 | [BPF_MAP_TYPE_SOCKMAP] = "sockmap", | ||
69 | }; | ||
70 | |||
71 | static unsigned int get_possible_cpus(void) | ||
72 | { | ||
73 | static unsigned int result; | ||
74 | char buf[128]; | ||
75 | long int n; | ||
76 | char *ptr; | ||
77 | int fd; | ||
78 | |||
79 | if (result) | ||
80 | return result; | ||
81 | |||
82 | fd = open("/sys/devices/system/cpu/possible", O_RDONLY); | ||
83 | if (fd < 0) { | ||
84 | p_err("can't open sysfs possible cpus"); | ||
85 | exit(-1); | ||
86 | } | ||
87 | |||
88 | n = read(fd, buf, sizeof(buf)); | ||
89 | if (n < 2) { | ||
90 | p_err("can't read sysfs possible cpus"); | ||
91 | exit(-1); | ||
92 | } | ||
93 | close(fd); | ||
94 | |||
95 | if (n == sizeof(buf)) { | ||
96 | p_err("read sysfs possible cpus overflow"); | ||
97 | exit(-1); | ||
98 | } | ||
99 | |||
100 | ptr = buf; | ||
101 | n = 0; | ||
102 | while (*ptr && *ptr != '\n') { | ||
103 | unsigned int a, b; | ||
104 | |||
105 | if (sscanf(ptr, "%u-%u", &a, &b) == 2) { | ||
106 | n += b - a + 1; | ||
107 | |||
108 | ptr = strchr(ptr, '-') + 1; | ||
109 | } else if (sscanf(ptr, "%u", &a) == 1) { | ||
110 | n++; | ||
111 | } else { | ||
112 | assert(0); | ||
113 | } | ||
114 | |||
115 | while (isdigit(*ptr)) | ||
116 | ptr++; | ||
117 | if (*ptr == ',') | ||
118 | ptr++; | ||
119 | } | ||
120 | |||
121 | result = n; | ||
122 | |||
123 | return result; | ||
124 | } | ||
125 | |||
126 | static bool map_is_per_cpu(__u32 type) | ||
127 | { | ||
128 | return type == BPF_MAP_TYPE_PERCPU_HASH || | ||
129 | type == BPF_MAP_TYPE_PERCPU_ARRAY || | ||
130 | type == BPF_MAP_TYPE_LRU_PERCPU_HASH; | ||
131 | } | ||
132 | |||
133 | static bool map_is_map_of_maps(__u32 type) | ||
134 | { | ||
135 | return type == BPF_MAP_TYPE_ARRAY_OF_MAPS || | ||
136 | type == BPF_MAP_TYPE_HASH_OF_MAPS; | ||
137 | } | ||
138 | |||
139 | static bool map_is_map_of_progs(__u32 type) | ||
140 | { | ||
141 | return type == BPF_MAP_TYPE_PROG_ARRAY; | ||
142 | } | ||
143 | |||
144 | static void *alloc_value(struct bpf_map_info *info) | ||
145 | { | ||
146 | if (map_is_per_cpu(info->type)) | ||
147 | return malloc(info->value_size * get_possible_cpus()); | ||
148 | else | ||
149 | return malloc(info->value_size); | ||
150 | } | ||
151 | |||
152 | static int map_parse_fd(int *argc, char ***argv) | ||
153 | { | ||
154 | int fd; | ||
155 | |||
156 | if (is_prefix(**argv, "id")) { | ||
157 | unsigned int id; | ||
158 | char *endptr; | ||
159 | |||
160 | NEXT_ARGP(); | ||
161 | |||
162 | id = strtoul(**argv, &endptr, 0); | ||
163 | if (*endptr) { | ||
164 | p_err("can't parse %s as ID", **argv); | ||
165 | return -1; | ||
166 | } | ||
167 | NEXT_ARGP(); | ||
168 | |||
169 | fd = bpf_map_get_fd_by_id(id); | ||
170 | if (fd < 0) | ||
171 | p_err("get map by id (%u): %s", id, strerror(errno)); | ||
172 | return fd; | ||
173 | } else if (is_prefix(**argv, "pinned")) { | ||
174 | char *path; | ||
175 | |||
176 | NEXT_ARGP(); | ||
177 | |||
178 | path = **argv; | ||
179 | NEXT_ARGP(); | ||
180 | |||
181 | return open_obj_pinned_any(path, BPF_OBJ_MAP); | ||
182 | } | ||
183 | |||
184 | p_err("expected 'id' or 'pinned', got: '%s'?", **argv); | ||
185 | return -1; | ||
186 | } | ||
187 | |||
188 | static int | ||
189 | map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len) | ||
190 | { | ||
191 | int err; | ||
192 | int fd; | ||
193 | |||
194 | fd = map_parse_fd(argc, argv); | ||
195 | if (fd < 0) | ||
196 | return -1; | ||
197 | |||
198 | err = bpf_obj_get_info_by_fd(fd, info, info_len); | ||
199 | if (err) { | ||
200 | p_err("can't get map info: %s", strerror(errno)); | ||
201 | close(fd); | ||
202 | return err; | ||
203 | } | ||
204 | |||
205 | return fd; | ||
206 | } | ||
207 | |||
208 | static void print_entry_json(struct bpf_map_info *info, unsigned char *key, | ||
209 | unsigned char *value) | ||
210 | { | ||
211 | jsonw_start_object(json_wtr); | ||
212 | |||
213 | if (!map_is_per_cpu(info->type)) { | ||
214 | jsonw_name(json_wtr, "key"); | ||
215 | print_hex_data_json(key, info->key_size); | ||
216 | jsonw_name(json_wtr, "value"); | ||
217 | print_hex_data_json(value, info->value_size); | ||
218 | } else { | ||
219 | unsigned int i, n; | ||
220 | |||
221 | n = get_possible_cpus(); | ||
222 | |||
223 | jsonw_name(json_wtr, "key"); | ||
224 | print_hex_data_json(key, info->key_size); | ||
225 | |||
226 | jsonw_name(json_wtr, "values"); | ||
227 | jsonw_start_array(json_wtr); | ||
228 | for (i = 0; i < n; i++) { | ||
229 | jsonw_start_object(json_wtr); | ||
230 | |||
231 | jsonw_int_field(json_wtr, "cpu", i); | ||
232 | |||
233 | jsonw_name(json_wtr, "value"); | ||
234 | print_hex_data_json(value + i * info->value_size, | ||
235 | info->value_size); | ||
236 | |||
237 | jsonw_end_object(json_wtr); | ||
238 | } | ||
239 | jsonw_end_array(json_wtr); | ||
240 | } | ||
241 | |||
242 | jsonw_end_object(json_wtr); | ||
243 | } | ||
244 | |||
245 | static void print_entry_plain(struct bpf_map_info *info, unsigned char *key, | ||
246 | unsigned char *value) | ||
247 | { | ||
248 | if (!map_is_per_cpu(info->type)) { | ||
249 | bool single_line, break_names; | ||
250 | |||
251 | break_names = info->key_size > 16 || info->value_size > 16; | ||
252 | single_line = info->key_size + info->value_size <= 24 && | ||
253 | !break_names; | ||
254 | |||
255 | printf("key:%c", break_names ? '\n' : ' '); | ||
256 | fprint_hex(stdout, key, info->key_size, " "); | ||
257 | |||
258 | printf(single_line ? " " : "\n"); | ||
259 | |||
260 | printf("value:%c", break_names ? '\n' : ' '); | ||
261 | fprint_hex(stdout, value, info->value_size, " "); | ||
262 | |||
263 | printf("\n"); | ||
264 | } else { | ||
265 | unsigned int i, n; | ||
266 | |||
267 | n = get_possible_cpus(); | ||
268 | |||
269 | printf("key:\n"); | ||
270 | fprint_hex(stdout, key, info->key_size, " "); | ||
271 | printf("\n"); | ||
272 | for (i = 0; i < n; i++) { | ||
273 | printf("value (CPU %02d):%c", | ||
274 | i, info->value_size > 16 ? '\n' : ' '); | ||
275 | fprint_hex(stdout, value + i * info->value_size, | ||
276 | info->value_size, " "); | ||
277 | printf("\n"); | ||
278 | } | ||
279 | } | ||
280 | } | ||
281 | |||
282 | static char **parse_bytes(char **argv, const char *name, unsigned char *val, | ||
283 | unsigned int n) | ||
284 | { | ||
285 | unsigned int i = 0; | ||
286 | char *endptr; | ||
287 | |||
288 | while (i < n && argv[i]) { | ||
289 | val[i] = strtoul(argv[i], &endptr, 0); | ||
290 | if (*endptr) { | ||
291 | p_err("error parsing byte: %s", argv[i]); | ||
292 | return NULL; | ||
293 | } | ||
294 | i++; | ||
295 | } | ||
296 | |||
297 | if (i != n) { | ||
298 | p_err("%s expected %d bytes got %d", name, n, i); | ||
299 | return NULL; | ||
300 | } | ||
301 | |||
302 | return argv + i; | ||
303 | } | ||
304 | |||
305 | static int parse_elem(char **argv, struct bpf_map_info *info, | ||
306 | void *key, void *value, __u32 key_size, __u32 value_size, | ||
307 | __u32 *flags, __u32 **value_fd) | ||
308 | { | ||
309 | if (!*argv) { | ||
310 | if (!key && !value) | ||
311 | return 0; | ||
312 | p_err("did not find %s", key ? "key" : "value"); | ||
313 | return -1; | ||
314 | } | ||
315 | |||
316 | if (is_prefix(*argv, "key")) { | ||
317 | if (!key) { | ||
318 | if (key_size) | ||
319 | p_err("duplicate key"); | ||
320 | else | ||
321 | p_err("unnecessary key"); | ||
322 | return -1; | ||
323 | } | ||
324 | |||
325 | argv = parse_bytes(argv + 1, "key", key, key_size); | ||
326 | if (!argv) | ||
327 | return -1; | ||
328 | |||
329 | return parse_elem(argv, info, NULL, value, key_size, value_size, | ||
330 | flags, value_fd); | ||
331 | } else if (is_prefix(*argv, "value")) { | ||
332 | int fd; | ||
333 | |||
334 | if (!value) { | ||
335 | if (value_size) | ||
336 | p_err("duplicate value"); | ||
337 | else | ||
338 | p_err("unnecessary value"); | ||
339 | return -1; | ||
340 | } | ||
341 | |||
342 | argv++; | ||
343 | |||
344 | if (map_is_map_of_maps(info->type)) { | ||
345 | int argc = 2; | ||
346 | |||
347 | if (value_size != 4) { | ||
348 | p_err("value smaller than 4B for map in map?"); | ||
349 | return -1; | ||
350 | } | ||
351 | if (!argv[0] || !argv[1]) { | ||
352 | p_err("not enough value arguments for map in map"); | ||
353 | return -1; | ||
354 | } | ||
355 | |||
356 | fd = map_parse_fd(&argc, &argv); | ||
357 | if (fd < 0) | ||
358 | return -1; | ||
359 | |||
360 | *value_fd = value; | ||
361 | **value_fd = fd; | ||
362 | } else if (map_is_map_of_progs(info->type)) { | ||
363 | int argc = 2; | ||
364 | |||
365 | if (value_size != 4) { | ||
366 | p_err("value smaller than 4B for map of progs?"); | ||
367 | return -1; | ||
368 | } | ||
369 | if (!argv[0] || !argv[1]) { | ||
370 | p_err("not enough value arguments for map of progs"); | ||
371 | return -1; | ||
372 | } | ||
373 | |||
374 | fd = prog_parse_fd(&argc, &argv); | ||
375 | if (fd < 0) | ||
376 | return -1; | ||
377 | |||
378 | *value_fd = value; | ||
379 | **value_fd = fd; | ||
380 | } else { | ||
381 | argv = parse_bytes(argv, "value", value, value_size); | ||
382 | if (!argv) | ||
383 | return -1; | ||
384 | } | ||
385 | |||
386 | return parse_elem(argv, info, key, NULL, key_size, value_size, | ||
387 | flags, NULL); | ||
388 | } else if (is_prefix(*argv, "any") || is_prefix(*argv, "noexist") || | ||
389 | is_prefix(*argv, "exist")) { | ||
390 | if (!flags) { | ||
391 | p_err("flags specified multiple times: %s", *argv); | ||
392 | return -1; | ||
393 | } | ||
394 | |||
395 | if (is_prefix(*argv, "any")) | ||
396 | *flags = BPF_ANY; | ||
397 | else if (is_prefix(*argv, "noexist")) | ||
398 | *flags = BPF_NOEXIST; | ||
399 | else if (is_prefix(*argv, "exist")) | ||
400 | *flags = BPF_EXIST; | ||
401 | |||
402 | return parse_elem(argv + 1, info, key, value, key_size, | ||
403 | value_size, NULL, value_fd); | ||
404 | } | ||
405 | |||
406 | p_err("expected key or value, got: %s", *argv); | ||
407 | return -1; | ||
408 | } | ||
409 | |||
410 | static int show_map_close_json(int fd, struct bpf_map_info *info) | ||
411 | { | ||
412 | char *memlock; | ||
413 | |||
414 | memlock = get_fdinfo(fd, "memlock"); | ||
415 | close(fd); | ||
416 | |||
417 | jsonw_start_object(json_wtr); | ||
418 | |||
419 | jsonw_uint_field(json_wtr, "id", info->id); | ||
420 | if (info->type < ARRAY_SIZE(map_type_name)) | ||
421 | jsonw_string_field(json_wtr, "type", | ||
422 | map_type_name[info->type]); | ||
423 | else | ||
424 | jsonw_uint_field(json_wtr, "type", info->type); | ||
425 | |||
426 | if (*info->name) | ||
427 | jsonw_string_field(json_wtr, "name", info->name); | ||
428 | |||
429 | jsonw_name(json_wtr, "flags"); | ||
430 | jsonw_printf(json_wtr, "%#x", info->map_flags); | ||
431 | jsonw_uint_field(json_wtr, "bytes_key", info->key_size); | ||
432 | jsonw_uint_field(json_wtr, "bytes_value", info->value_size); | ||
433 | jsonw_uint_field(json_wtr, "max_entries", info->max_entries); | ||
434 | |||
435 | if (memlock) | ||
436 | jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock)); | ||
437 | free(memlock); | ||
438 | |||
439 | if (!hash_empty(map_table.table)) { | ||
440 | struct pinned_obj *obj; | ||
441 | |||
442 | jsonw_name(json_wtr, "pinned"); | ||
443 | jsonw_start_array(json_wtr); | ||
444 | hash_for_each_possible(map_table.table, obj, hash, info->id) { | ||
445 | if (obj->id == info->id) | ||
446 | jsonw_string(json_wtr, obj->path); | ||
447 | } | ||
448 | jsonw_end_array(json_wtr); | ||
449 | } | ||
450 | |||
451 | jsonw_end_object(json_wtr); | ||
452 | |||
453 | return 0; | ||
454 | } | ||
455 | |||
456 | static int show_map_close_plain(int fd, struct bpf_map_info *info) | ||
457 | { | ||
458 | char *memlock; | ||
459 | |||
460 | memlock = get_fdinfo(fd, "memlock"); | ||
461 | close(fd); | ||
462 | |||
463 | printf("%u: ", info->id); | ||
464 | if (info->type < ARRAY_SIZE(map_type_name)) | ||
465 | printf("%s ", map_type_name[info->type]); | ||
466 | else | ||
467 | printf("type %u ", info->type); | ||
468 | |||
469 | if (*info->name) | ||
470 | printf("name %s ", info->name); | ||
471 | |||
472 | printf("flags 0x%x\n", info->map_flags); | ||
473 | printf("\tkey %uB value %uB max_entries %u", | ||
474 | info->key_size, info->value_size, info->max_entries); | ||
475 | |||
476 | if (memlock) | ||
477 | printf(" memlock %sB", memlock); | ||
478 | free(memlock); | ||
479 | |||
480 | printf("\n"); | ||
481 | if (!hash_empty(map_table.table)) { | ||
482 | struct pinned_obj *obj; | ||
483 | |||
484 | hash_for_each_possible(map_table.table, obj, hash, info->id) { | ||
485 | if (obj->id == info->id) | ||
486 | printf("\tpinned %s\n", obj->path); | ||
487 | } | ||
488 | } | ||
489 | return 0; | ||
490 | } | ||
491 | |||
492 | static int do_show(int argc, char **argv) | ||
493 | { | ||
494 | struct bpf_map_info info = {}; | ||
495 | __u32 len = sizeof(info); | ||
496 | __u32 id = 0; | ||
497 | int err; | ||
498 | int fd; | ||
499 | |||
500 | if (show_pinned) | ||
501 | build_pinned_obj_table(&map_table, BPF_OBJ_MAP); | ||
502 | |||
503 | if (argc == 2) { | ||
504 | fd = map_parse_fd_and_info(&argc, &argv, &info, &len); | ||
505 | if (fd < 0) | ||
506 | return -1; | ||
507 | |||
508 | if (json_output) | ||
509 | return show_map_close_json(fd, &info); | ||
510 | else | ||
511 | return show_map_close_plain(fd, &info); | ||
512 | } | ||
513 | |||
514 | if (argc) | ||
515 | return BAD_ARG(); | ||
516 | |||
517 | if (json_output) | ||
518 | jsonw_start_array(json_wtr); | ||
519 | while (true) { | ||
520 | err = bpf_map_get_next_id(id, &id); | ||
521 | if (err) { | ||
522 | if (errno == ENOENT) | ||
523 | break; | ||
524 | p_err("can't get next map: %s%s", strerror(errno), | ||
525 | errno == EINVAL ? " -- kernel too old?" : ""); | ||
526 | return -1; | ||
527 | } | ||
528 | |||
529 | fd = bpf_map_get_fd_by_id(id); | ||
530 | if (fd < 0) { | ||
531 | p_err("can't get map by id (%u): %s", | ||
532 | id, strerror(errno)); | ||
533 | return -1; | ||
534 | } | ||
535 | |||
536 | err = bpf_obj_get_info_by_fd(fd, &info, &len); | ||
537 | if (err) { | ||
538 | p_err("can't get map info: %s", strerror(errno)); | ||
539 | close(fd); | ||
540 | return -1; | ||
541 | } | ||
542 | |||
543 | if (json_output) | ||
544 | show_map_close_json(fd, &info); | ||
545 | else | ||
546 | show_map_close_plain(fd, &info); | ||
547 | } | ||
548 | if (json_output) | ||
549 | jsonw_end_array(json_wtr); | ||
550 | |||
551 | return errno == ENOENT ? 0 : -1; | ||
552 | } | ||
553 | |||
554 | static int do_dump(int argc, char **argv) | ||
555 | { | ||
556 | void *key, *value, *prev_key; | ||
557 | unsigned int num_elems = 0; | ||
558 | struct bpf_map_info info = {}; | ||
559 | __u32 len = sizeof(info); | ||
560 | int err; | ||
561 | int fd; | ||
562 | |||
563 | if (argc != 2) | ||
564 | usage(); | ||
565 | |||
566 | fd = map_parse_fd_and_info(&argc, &argv, &info, &len); | ||
567 | if (fd < 0) | ||
568 | return -1; | ||
569 | |||
570 | if (map_is_map_of_maps(info.type) || map_is_map_of_progs(info.type)) { | ||
571 | p_err("Dumping maps of maps and program maps not supported"); | ||
572 | close(fd); | ||
573 | return -1; | ||
574 | } | ||
575 | |||
576 | key = malloc(info.key_size); | ||
577 | value = alloc_value(&info); | ||
578 | if (!key || !value) { | ||
579 | p_err("mem alloc failed"); | ||
580 | err = -1; | ||
581 | goto exit_free; | ||
582 | } | ||
583 | |||
584 | prev_key = NULL; | ||
585 | if (json_output) | ||
586 | jsonw_start_array(json_wtr); | ||
587 | while (true) { | ||
588 | err = bpf_map_get_next_key(fd, prev_key, key); | ||
589 | if (err) { | ||
590 | if (errno == ENOENT) | ||
591 | err = 0; | ||
592 | break; | ||
593 | } | ||
594 | |||
595 | if (!bpf_map_lookup_elem(fd, key, value)) { | ||
596 | if (json_output) | ||
597 | print_entry_json(&info, key, value); | ||
598 | else | ||
599 | print_entry_plain(&info, key, value); | ||
600 | } else { | ||
601 | if (json_output) { | ||
602 | jsonw_name(json_wtr, "key"); | ||
603 | print_hex_data_json(key, info.key_size); | ||
604 | jsonw_name(json_wtr, "value"); | ||
605 | jsonw_start_object(json_wtr); | ||
606 | jsonw_string_field(json_wtr, "error", | ||
607 | "can't lookup element"); | ||
608 | jsonw_end_object(json_wtr); | ||
609 | } else { | ||
610 | p_info("can't lookup element with key: "); | ||
611 | fprint_hex(stderr, key, info.key_size, " "); | ||
612 | fprintf(stderr, "\n"); | ||
613 | } | ||
614 | } | ||
615 | |||
616 | prev_key = key; | ||
617 | num_elems++; | ||
618 | } | ||
619 | |||
620 | if (json_output) | ||
621 | jsonw_end_array(json_wtr); | ||
622 | else | ||
623 | printf("Found %u element%s\n", num_elems, | ||
624 | num_elems != 1 ? "s" : ""); | ||
625 | |||
626 | exit_free: | ||
627 | free(key); | ||
628 | free(value); | ||
629 | close(fd); | ||
630 | |||
631 | return err; | ||
632 | } | ||
633 | |||
634 | static int do_update(int argc, char **argv) | ||
635 | { | ||
636 | struct bpf_map_info info = {}; | ||
637 | __u32 len = sizeof(info); | ||
638 | __u32 *value_fd = NULL; | ||
639 | __u32 flags = BPF_ANY; | ||
640 | void *key, *value; | ||
641 | int fd, err; | ||
642 | |||
643 | if (argc < 2) | ||
644 | usage(); | ||
645 | |||
646 | fd = map_parse_fd_and_info(&argc, &argv, &info, &len); | ||
647 | if (fd < 0) | ||
648 | return -1; | ||
649 | |||
650 | key = malloc(info.key_size); | ||
651 | value = alloc_value(&info); | ||
652 | if (!key || !value) { | ||
653 | p_err("mem alloc failed"); | ||
654 | err = -1; | ||
655 | goto exit_free; | ||
656 | } | ||
657 | |||
658 | err = parse_elem(argv, &info, key, value, info.key_size, | ||
659 | info.value_size, &flags, &value_fd); | ||
660 | if (err) | ||
661 | goto exit_free; | ||
662 | |||
663 | err = bpf_map_update_elem(fd, key, value, flags); | ||
664 | if (err) { | ||
665 | p_err("update failed: %s", strerror(errno)); | ||
666 | goto exit_free; | ||
667 | } | ||
668 | |||
669 | exit_free: | ||
670 | if (value_fd) | ||
671 | close(*value_fd); | ||
672 | free(key); | ||
673 | free(value); | ||
674 | close(fd); | ||
675 | |||
676 | if (!err && json_output) | ||
677 | jsonw_null(json_wtr); | ||
678 | return err; | ||
679 | } | ||
680 | |||
681 | static int do_lookup(int argc, char **argv) | ||
682 | { | ||
683 | struct bpf_map_info info = {}; | ||
684 | __u32 len = sizeof(info); | ||
685 | void *key, *value; | ||
686 | int err; | ||
687 | int fd; | ||
688 | |||
689 | if (argc < 2) | ||
690 | usage(); | ||
691 | |||
692 | fd = map_parse_fd_and_info(&argc, &argv, &info, &len); | ||
693 | if (fd < 0) | ||
694 | return -1; | ||
695 | |||
696 | key = malloc(info.key_size); | ||
697 | value = alloc_value(&info); | ||
698 | if (!key || !value) { | ||
699 | p_err("mem alloc failed"); | ||
700 | err = -1; | ||
701 | goto exit_free; | ||
702 | } | ||
703 | |||
704 | err = parse_elem(argv, &info, key, NULL, info.key_size, 0, NULL, NULL); | ||
705 | if (err) | ||
706 | goto exit_free; | ||
707 | |||
708 | err = bpf_map_lookup_elem(fd, key, value); | ||
709 | if (!err) { | ||
710 | if (json_output) | ||
711 | print_entry_json(&info, key, value); | ||
712 | else | ||
713 | print_entry_plain(&info, key, value); | ||
714 | } else if (errno == ENOENT) { | ||
715 | if (json_output) { | ||
716 | jsonw_null(json_wtr); | ||
717 | } else { | ||
718 | printf("key:\n"); | ||
719 | fprint_hex(stdout, key, info.key_size, " "); | ||
720 | printf("\n\nNot found\n"); | ||
721 | } | ||
722 | } else { | ||
723 | p_err("lookup failed: %s", strerror(errno)); | ||
724 | } | ||
725 | |||
726 | exit_free: | ||
727 | free(key); | ||
728 | free(value); | ||
729 | close(fd); | ||
730 | |||
731 | return err; | ||
732 | } | ||
733 | |||
734 | static int do_getnext(int argc, char **argv) | ||
735 | { | ||
736 | struct bpf_map_info info = {}; | ||
737 | __u32 len = sizeof(info); | ||
738 | void *key, *nextkey; | ||
739 | int err; | ||
740 | int fd; | ||
741 | |||
742 | if (argc < 2) | ||
743 | usage(); | ||
744 | |||
745 | fd = map_parse_fd_and_info(&argc, &argv, &info, &len); | ||
746 | if (fd < 0) | ||
747 | return -1; | ||
748 | |||
749 | key = malloc(info.key_size); | ||
750 | nextkey = malloc(info.key_size); | ||
751 | if (!key || !nextkey) { | ||
752 | p_err("mem alloc failed"); | ||
753 | err = -1; | ||
754 | goto exit_free; | ||
755 | } | ||
756 | |||
757 | if (argc) { | ||
758 | err = parse_elem(argv, &info, key, NULL, info.key_size, 0, | ||
759 | NULL, NULL); | ||
760 | if (err) | ||
761 | goto exit_free; | ||
762 | } else { | ||
763 | free(key); | ||
764 | key = NULL; | ||
765 | } | ||
766 | |||
767 | err = bpf_map_get_next_key(fd, key, nextkey); | ||
768 | if (err) { | ||
769 | p_err("can't get next key: %s", strerror(errno)); | ||
770 | goto exit_free; | ||
771 | } | ||
772 | |||
773 | if (json_output) { | ||
774 | jsonw_start_object(json_wtr); | ||
775 | if (key) { | ||
776 | jsonw_name(json_wtr, "key"); | ||
777 | print_hex_data_json(key, info.key_size); | ||
778 | } else { | ||
779 | jsonw_null_field(json_wtr, "key"); | ||
780 | } | ||
781 | jsonw_name(json_wtr, "next_key"); | ||
782 | print_hex_data_json(nextkey, info.key_size); | ||
783 | jsonw_end_object(json_wtr); | ||
784 | } else { | ||
785 | if (key) { | ||
786 | printf("key:\n"); | ||
787 | fprint_hex(stdout, key, info.key_size, " "); | ||
788 | printf("\n"); | ||
789 | } else { | ||
790 | printf("key: None\n"); | ||
791 | } | ||
792 | printf("next key:\n"); | ||
793 | fprint_hex(stdout, nextkey, info.key_size, " "); | ||
794 | printf("\n"); | ||
795 | } | ||
796 | |||
797 | exit_free: | ||
798 | free(nextkey); | ||
799 | free(key); | ||
800 | close(fd); | ||
801 | |||
802 | return err; | ||
803 | } | ||
804 | |||
805 | static int do_delete(int argc, char **argv) | ||
806 | { | ||
807 | struct bpf_map_info info = {}; | ||
808 | __u32 len = sizeof(info); | ||
809 | void *key; | ||
810 | int err; | ||
811 | int fd; | ||
812 | |||
813 | if (argc < 2) | ||
814 | usage(); | ||
815 | |||
816 | fd = map_parse_fd_and_info(&argc, &argv, &info, &len); | ||
817 | if (fd < 0) | ||
818 | return -1; | ||
819 | |||
820 | key = malloc(info.key_size); | ||
821 | if (!key) { | ||
822 | p_err("mem alloc failed"); | ||
823 | err = -1; | ||
824 | goto exit_free; | ||
825 | } | ||
826 | |||
827 | err = parse_elem(argv, &info, key, NULL, info.key_size, 0, NULL, NULL); | ||
828 | if (err) | ||
829 | goto exit_free; | ||
830 | |||
831 | err = bpf_map_delete_elem(fd, key); | ||
832 | if (err) | ||
833 | p_err("delete failed: %s", strerror(errno)); | ||
834 | |||
835 | exit_free: | ||
836 | free(key); | ||
837 | close(fd); | ||
838 | |||
839 | if (!err && json_output) | ||
840 | jsonw_null(json_wtr); | ||
841 | return err; | ||
842 | } | ||
843 | |||
844 | static int do_pin(int argc, char **argv) | ||
845 | { | ||
846 | int err; | ||
847 | |||
848 | err = do_pin_any(argc, argv, bpf_map_get_fd_by_id); | ||
849 | if (!err && json_output) | ||
850 | jsonw_null(json_wtr); | ||
851 | return err; | ||
852 | } | ||
853 | |||
854 | static int do_help(int argc, char **argv) | ||
855 | { | ||
856 | if (json_output) { | ||
857 | jsonw_null(json_wtr); | ||
858 | return 0; | ||
859 | } | ||
860 | |||
861 | fprintf(stderr, | ||
862 | "Usage: %s %s show [MAP]\n" | ||
863 | " %s %s dump MAP\n" | ||
864 | " %s %s update MAP key BYTES value VALUE [UPDATE_FLAGS]\n" | ||
865 | " %s %s lookup MAP key BYTES\n" | ||
866 | " %s %s getnext MAP [key BYTES]\n" | ||
867 | " %s %s delete MAP key BYTES\n" | ||
868 | " %s %s pin MAP FILE\n" | ||
869 | " %s %s help\n" | ||
870 | "\n" | ||
871 | " MAP := { id MAP_ID | pinned FILE }\n" | ||
872 | " " HELP_SPEC_PROGRAM "\n" | ||
873 | " VALUE := { BYTES | MAP | PROG }\n" | ||
874 | " UPDATE_FLAGS := { any | exist | noexist }\n" | ||
875 | " " HELP_SPEC_OPTIONS "\n" | ||
876 | "", | ||
877 | bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], | ||
878 | bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], | ||
879 | bin_name, argv[-2], bin_name, argv[-2]); | ||
880 | |||
881 | return 0; | ||
882 | } | ||
883 | |||
884 | static const struct cmd cmds[] = { | ||
885 | { "show", do_show }, | ||
886 | { "help", do_help }, | ||
887 | { "dump", do_dump }, | ||
888 | { "update", do_update }, | ||
889 | { "lookup", do_lookup }, | ||
890 | { "getnext", do_getnext }, | ||
891 | { "delete", do_delete }, | ||
892 | { "pin", do_pin }, | ||
893 | { 0 } | ||
894 | }; | ||
895 | |||
896 | int do_map(int argc, char **argv) | ||
897 | { | ||
898 | return cmd_select(cmds, argc, argv, do_help); | ||
899 | } | ||
diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c new file mode 100644 index 000000000000..ad619b96c276 --- /dev/null +++ b/tools/bpf/bpftool/prog.c | |||
@@ -0,0 +1,672 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 Netronome Systems, Inc. | ||
3 | * | ||
4 | * This software is dual licensed under the GNU General License Version 2, | ||
5 | * June 1991 as shown in the file COPYING in the top-level directory of this | ||
6 | * source tree or the BSD 2-Clause License provided below. You have the | ||
7 | * option to license this software under the complete terms of either license. | ||
8 | * | ||
9 | * The BSD 2-Clause License: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or | ||
12 | * without modification, are permitted provided that the following | ||
13 | * conditions are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above | ||
16 | * copyright notice, this list of conditions and the following | ||
17 | * disclaimer. | ||
18 | * | ||
19 | * 2. Redistributions in binary form must reproduce the above | ||
20 | * copyright notice, this list of conditions and the following | ||
21 | * disclaimer in the documentation and/or other materials | ||
22 | * provided with the distribution. | ||
23 | * | ||
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
28 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
29 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
31 | * SOFTWARE. | ||
32 | */ | ||
33 | |||
34 | /* Author: Jakub Kicinski <kubakici@wp.pl> */ | ||
35 | |||
36 | #include <errno.h> | ||
37 | #include <fcntl.h> | ||
38 | #include <stdarg.h> | ||
39 | #include <stdio.h> | ||
40 | #include <stdlib.h> | ||
41 | #include <string.h> | ||
42 | #include <time.h> | ||
43 | #include <unistd.h> | ||
44 | #include <sys/types.h> | ||
45 | #include <sys/stat.h> | ||
46 | |||
47 | #include <bpf.h> | ||
48 | |||
49 | #include "main.h" | ||
50 | #include "disasm.h" | ||
51 | |||
52 | static const char * const prog_type_name[] = { | ||
53 | [BPF_PROG_TYPE_UNSPEC] = "unspec", | ||
54 | [BPF_PROG_TYPE_SOCKET_FILTER] = "socket_filter", | ||
55 | [BPF_PROG_TYPE_KPROBE] = "kprobe", | ||
56 | [BPF_PROG_TYPE_SCHED_CLS] = "sched_cls", | ||
57 | [BPF_PROG_TYPE_SCHED_ACT] = "sched_act", | ||
58 | [BPF_PROG_TYPE_TRACEPOINT] = "tracepoint", | ||
59 | [BPF_PROG_TYPE_XDP] = "xdp", | ||
60 | [BPF_PROG_TYPE_PERF_EVENT] = "perf_event", | ||
61 | [BPF_PROG_TYPE_CGROUP_SKB] = "cgroup_skb", | ||
62 | [BPF_PROG_TYPE_CGROUP_SOCK] = "cgroup_sock", | ||
63 | [BPF_PROG_TYPE_LWT_IN] = "lwt_in", | ||
64 | [BPF_PROG_TYPE_LWT_OUT] = "lwt_out", | ||
65 | [BPF_PROG_TYPE_LWT_XMIT] = "lwt_xmit", | ||
66 | [BPF_PROG_TYPE_SOCK_OPS] = "sock_ops", | ||
67 | [BPF_PROG_TYPE_SK_SKB] = "sk_skb", | ||
68 | }; | ||
69 | |||
70 | static void print_boot_time(__u64 nsecs, char *buf, unsigned int size) | ||
71 | { | ||
72 | struct timespec real_time_ts, boot_time_ts; | ||
73 | time_t wallclock_secs; | ||
74 | struct tm load_tm; | ||
75 | |||
76 | buf[--size] = '\0'; | ||
77 | |||
78 | if (clock_gettime(CLOCK_REALTIME, &real_time_ts) || | ||
79 | clock_gettime(CLOCK_BOOTTIME, &boot_time_ts)) { | ||
80 | perror("Can't read clocks"); | ||
81 | snprintf(buf, size, "%llu", nsecs / 1000000000); | ||
82 | return; | ||
83 | } | ||
84 | |||
85 | wallclock_secs = (real_time_ts.tv_sec - boot_time_ts.tv_sec) + | ||
86 | nsecs / 1000000000; | ||
87 | |||
88 | if (!localtime_r(&wallclock_secs, &load_tm)) { | ||
89 | snprintf(buf, size, "%llu", nsecs / 1000000000); | ||
90 | return; | ||
91 | } | ||
92 | |||
93 | strftime(buf, size, "%b %d/%H:%M", &load_tm); | ||
94 | } | ||
95 | |||
96 | static int prog_fd_by_tag(unsigned char *tag) | ||
97 | { | ||
98 | struct bpf_prog_info info = {}; | ||
99 | __u32 len = sizeof(info); | ||
100 | unsigned int id = 0; | ||
101 | int err; | ||
102 | int fd; | ||
103 | |||
104 | while (true) { | ||
105 | err = bpf_prog_get_next_id(id, &id); | ||
106 | if (err) { | ||
107 | p_err("%s", strerror(errno)); | ||
108 | return -1; | ||
109 | } | ||
110 | |||
111 | fd = bpf_prog_get_fd_by_id(id); | ||
112 | if (fd < 0) { | ||
113 | p_err("can't get prog by id (%u): %s", | ||
114 | id, strerror(errno)); | ||
115 | return -1; | ||
116 | } | ||
117 | |||
118 | err = bpf_obj_get_info_by_fd(fd, &info, &len); | ||
119 | if (err) { | ||
120 | p_err("can't get prog info (%u): %s", | ||
121 | id, strerror(errno)); | ||
122 | close(fd); | ||
123 | return -1; | ||
124 | } | ||
125 | |||
126 | if (!memcmp(tag, info.tag, BPF_TAG_SIZE)) | ||
127 | return fd; | ||
128 | |||
129 | close(fd); | ||
130 | } | ||
131 | } | ||
132 | |||
133 | int prog_parse_fd(int *argc, char ***argv) | ||
134 | { | ||
135 | int fd; | ||
136 | |||
137 | if (is_prefix(**argv, "id")) { | ||
138 | unsigned int id; | ||
139 | char *endptr; | ||
140 | |||
141 | NEXT_ARGP(); | ||
142 | |||
143 | id = strtoul(**argv, &endptr, 0); | ||
144 | if (*endptr) { | ||
145 | p_err("can't parse %s as ID", **argv); | ||
146 | return -1; | ||
147 | } | ||
148 | NEXT_ARGP(); | ||
149 | |||
150 | fd = bpf_prog_get_fd_by_id(id); | ||
151 | if (fd < 0) | ||
152 | p_err("get by id (%u): %s", id, strerror(errno)); | ||
153 | return fd; | ||
154 | } else if (is_prefix(**argv, "tag")) { | ||
155 | unsigned char tag[BPF_TAG_SIZE]; | ||
156 | |||
157 | NEXT_ARGP(); | ||
158 | |||
159 | if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2, | ||
160 | tag + 3, tag + 4, tag + 5, tag + 6, tag + 7) | ||
161 | != BPF_TAG_SIZE) { | ||
162 | p_err("can't parse tag"); | ||
163 | return -1; | ||
164 | } | ||
165 | NEXT_ARGP(); | ||
166 | |||
167 | return prog_fd_by_tag(tag); | ||
168 | } else if (is_prefix(**argv, "pinned")) { | ||
169 | char *path; | ||
170 | |||
171 | NEXT_ARGP(); | ||
172 | |||
173 | path = **argv; | ||
174 | NEXT_ARGP(); | ||
175 | |||
176 | return open_obj_pinned_any(path, BPF_OBJ_PROG); | ||
177 | } | ||
178 | |||
179 | p_err("expected 'id', 'tag' or 'pinned', got: '%s'?", **argv); | ||
180 | return -1; | ||
181 | } | ||
182 | |||
183 | static void show_prog_maps(int fd, u32 num_maps) | ||
184 | { | ||
185 | struct bpf_prog_info info = {}; | ||
186 | __u32 len = sizeof(info); | ||
187 | __u32 map_ids[num_maps]; | ||
188 | unsigned int i; | ||
189 | int err; | ||
190 | |||
191 | info.nr_map_ids = num_maps; | ||
192 | info.map_ids = ptr_to_u64(map_ids); | ||
193 | |||
194 | err = bpf_obj_get_info_by_fd(fd, &info, &len); | ||
195 | if (err || !info.nr_map_ids) | ||
196 | return; | ||
197 | |||
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 | } | ||
210 | } | ||
211 | |||
212 | static void print_prog_json(struct bpf_prog_info *info, int fd) | ||
213 | { | ||
214 | char *memlock; | ||
215 | |||
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]); | ||
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); | ||
240 | } | ||
241 | |||
242 | jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len); | ||
243 | |||
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 | if (!hash_empty(prog_table.table)) { | ||
260 | struct pinned_obj *obj; | ||
261 | |||
262 | jsonw_name(json_wtr, "pinned"); | ||
263 | jsonw_start_array(json_wtr); | ||
264 | hash_for_each_possible(prog_table.table, obj, hash, info->id) { | ||
265 | if (obj->id == info->id) | ||
266 | jsonw_string(json_wtr, obj->path); | ||
267 | } | ||
268 | jsonw_end_array(json_wtr); | ||
269 | } | ||
270 | |||
271 | jsonw_end_object(json_wtr); | ||
272 | } | ||
273 | |||
274 | static void print_prog_plain(struct bpf_prog_info *info, int fd) | ||
275 | { | ||
276 | char *memlock; | ||
277 | |||
278 | printf("%u: ", info->id); | ||
279 | if (info->type < ARRAY_SIZE(prog_type_name)) | ||
280 | printf("%s ", prog_type_name[info->type]); | ||
281 | else | ||
282 | printf("type %u ", info->type); | ||
283 | |||
284 | if (*info->name) | ||
285 | printf("name %s ", info->name); | ||
286 | |||
287 | printf("tag "); | ||
288 | fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); | ||
289 | printf("\n"); | ||
290 | |||
291 | if (info->load_time) { | ||
292 | char buf[32]; | ||
293 | |||
294 | print_boot_time(info->load_time, buf, sizeof(buf)); | ||
295 | |||
296 | /* Piggy back on load_time, since 0 uid is a valid one */ | ||
297 | printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid); | ||
298 | } | ||
299 | |||
300 | printf("\txlated %uB", info->xlated_prog_len); | ||
301 | |||
302 | if (info->jited_prog_len) | ||
303 | printf(" jited %uB", info->jited_prog_len); | ||
304 | else | ||
305 | printf(" not jited"); | ||
306 | |||
307 | memlock = get_fdinfo(fd, "memlock"); | ||
308 | if (memlock) | ||
309 | printf(" memlock %sB", memlock); | ||
310 | free(memlock); | ||
311 | |||
312 | if (info->nr_map_ids) | ||
313 | show_prog_maps(fd, info->nr_map_ids); | ||
314 | |||
315 | if (!hash_empty(prog_table.table)) { | ||
316 | struct pinned_obj *obj; | ||
317 | |||
318 | printf("\n"); | ||
319 | hash_for_each_possible(prog_table.table, obj, hash, info->id) { | ||
320 | if (obj->id == info->id) | ||
321 | printf("\tpinned %s\n", obj->path); | ||
322 | } | ||
323 | } | ||
324 | |||
325 | printf("\n"); | ||
326 | } | ||
327 | |||
328 | static int show_prog(int fd) | ||
329 | { | ||
330 | struct bpf_prog_info info = {}; | ||
331 | __u32 len = sizeof(info); | ||
332 | int err; | ||
333 | |||
334 | err = bpf_obj_get_info_by_fd(fd, &info, &len); | ||
335 | if (err) { | ||
336 | p_err("can't get prog info: %s", strerror(errno)); | ||
337 | return -1; | ||
338 | } | ||
339 | |||
340 | if (json_output) | ||
341 | print_prog_json(&info, fd); | ||
342 | else | ||
343 | print_prog_plain(&info, fd); | ||
344 | |||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | static int do_show(int argc, char **argv) | ||
349 | { | ||
350 | __u32 id = 0; | ||
351 | int err; | ||
352 | int fd; | ||
353 | |||
354 | if (show_pinned) | ||
355 | build_pinned_obj_table(&prog_table, BPF_OBJ_PROG); | ||
356 | |||
357 | if (argc == 2) { | ||
358 | fd = prog_parse_fd(&argc, &argv); | ||
359 | if (fd < 0) | ||
360 | return -1; | ||
361 | |||
362 | return show_prog(fd); | ||
363 | } | ||
364 | |||
365 | if (argc) | ||
366 | return BAD_ARG(); | ||
367 | |||
368 | if (json_output) | ||
369 | jsonw_start_array(json_wtr); | ||
370 | while (true) { | ||
371 | err = bpf_prog_get_next_id(id, &id); | ||
372 | if (err) { | ||
373 | if (errno == ENOENT) { | ||
374 | err = 0; | ||
375 | break; | ||
376 | } | ||
377 | p_err("can't get next program: %s%s", strerror(errno), | ||
378 | errno == EINVAL ? " -- kernel too old?" : ""); | ||
379 | err = -1; | ||
380 | break; | ||
381 | } | ||
382 | |||
383 | fd = bpf_prog_get_fd_by_id(id); | ||
384 | if (fd < 0) { | ||
385 | p_err("can't get prog by id (%u): %s", | ||
386 | id, strerror(errno)); | ||
387 | err = -1; | ||
388 | break; | ||
389 | } | ||
390 | |||
391 | err = show_prog(fd); | ||
392 | close(fd); | ||
393 | if (err) | ||
394 | break; | ||
395 | } | ||
396 | |||
397 | if (json_output) | ||
398 | jsonw_end_array(json_wtr); | ||
399 | |||
400 | return err; | ||
401 | } | ||
402 | |||
403 | static void print_insn(struct bpf_verifier_env *env, const char *fmt, ...) | ||
404 | { | ||
405 | va_list args; | ||
406 | |||
407 | va_start(args, fmt); | ||
408 | vprintf(fmt, args); | ||
409 | va_end(args); | ||
410 | } | ||
411 | |||
412 | static void dump_xlated_plain(void *buf, unsigned int len, bool opcodes) | ||
413 | { | ||
414 | struct bpf_insn *insn = buf; | ||
415 | bool double_insn = false; | ||
416 | unsigned int i; | ||
417 | |||
418 | for (i = 0; i < len / sizeof(*insn); i++) { | ||
419 | if (double_insn) { | ||
420 | double_insn = false; | ||
421 | continue; | ||
422 | } | ||
423 | |||
424 | double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW); | ||
425 | |||
426 | printf("% 4d: ", i); | ||
427 | print_bpf_insn(print_insn, NULL, insn + i, true); | ||
428 | |||
429 | if (opcodes) { | ||
430 | printf(" "); | ||
431 | fprint_hex(stdout, insn + i, 8, " "); | ||
432 | if (double_insn && i < len - 1) { | ||
433 | printf(" "); | ||
434 | fprint_hex(stdout, insn + i + 1, 8, " "); | ||
435 | } | ||
436 | printf("\n"); | ||
437 | } | ||
438 | } | ||
439 | } | ||
440 | |||
441 | static void print_insn_json(struct bpf_verifier_env *env, const char *fmt, ...) | ||
442 | { | ||
443 | unsigned int l = strlen(fmt); | ||
444 | char chomped_fmt[l]; | ||
445 | va_list args; | ||
446 | |||
447 | va_start(args, fmt); | ||
448 | if (l > 0) { | ||
449 | strncpy(chomped_fmt, fmt, l - 1); | ||
450 | chomped_fmt[l - 1] = '\0'; | ||
451 | } | ||
452 | jsonw_vprintf_enquote(json_wtr, chomped_fmt, args); | ||
453 | va_end(args); | ||
454 | } | ||
455 | |||
456 | static void dump_xlated_json(void *buf, unsigned int len, bool opcodes) | ||
457 | { | ||
458 | struct bpf_insn *insn = buf; | ||
459 | bool double_insn = false; | ||
460 | unsigned int i; | ||
461 | |||
462 | jsonw_start_array(json_wtr); | ||
463 | for (i = 0; i < len / sizeof(*insn); i++) { | ||
464 | if (double_insn) { | ||
465 | double_insn = false; | ||
466 | continue; | ||
467 | } | ||
468 | double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW); | ||
469 | |||
470 | jsonw_start_object(json_wtr); | ||
471 | jsonw_name(json_wtr, "disasm"); | ||
472 | print_bpf_insn(print_insn_json, NULL, insn + i, true); | ||
473 | |||
474 | if (opcodes) { | ||
475 | jsonw_name(json_wtr, "opcodes"); | ||
476 | jsonw_start_object(json_wtr); | ||
477 | |||
478 | jsonw_name(json_wtr, "code"); | ||
479 | jsonw_printf(json_wtr, "\"0x%02hhx\"", insn[i].code); | ||
480 | |||
481 | jsonw_name(json_wtr, "src_reg"); | ||
482 | jsonw_printf(json_wtr, "\"0x%hhx\"", insn[i].src_reg); | ||
483 | |||
484 | jsonw_name(json_wtr, "dst_reg"); | ||
485 | jsonw_printf(json_wtr, "\"0x%hhx\"", insn[i].dst_reg); | ||
486 | |||
487 | jsonw_name(json_wtr, "off"); | ||
488 | print_hex_data_json((uint8_t *)(&insn[i].off), 2); | ||
489 | |||
490 | jsonw_name(json_wtr, "imm"); | ||
491 | if (double_insn && i < len - 1) | ||
492 | print_hex_data_json((uint8_t *)(&insn[i].imm), | ||
493 | 12); | ||
494 | else | ||
495 | print_hex_data_json((uint8_t *)(&insn[i].imm), | ||
496 | 4); | ||
497 | jsonw_end_object(json_wtr); | ||
498 | } | ||
499 | jsonw_end_object(json_wtr); | ||
500 | } | ||
501 | jsonw_end_array(json_wtr); | ||
502 | } | ||
503 | |||
504 | static int do_dump(int argc, char **argv) | ||
505 | { | ||
506 | struct bpf_prog_info info = {}; | ||
507 | __u32 len = sizeof(info); | ||
508 | unsigned int buf_size; | ||
509 | char *filepath = NULL; | ||
510 | bool opcodes = false; | ||
511 | unsigned char *buf; | ||
512 | __u32 *member_len; | ||
513 | __u64 *member_ptr; | ||
514 | ssize_t n; | ||
515 | int err; | ||
516 | int fd; | ||
517 | |||
518 | if (is_prefix(*argv, "jited")) { | ||
519 | member_len = &info.jited_prog_len; | ||
520 | member_ptr = &info.jited_prog_insns; | ||
521 | } else if (is_prefix(*argv, "xlated")) { | ||
522 | member_len = &info.xlated_prog_len; | ||
523 | member_ptr = &info.xlated_prog_insns; | ||
524 | } else { | ||
525 | p_err("expected 'xlated' or 'jited', got: %s", *argv); | ||
526 | return -1; | ||
527 | } | ||
528 | NEXT_ARG(); | ||
529 | |||
530 | if (argc < 2) | ||
531 | usage(); | ||
532 | |||
533 | fd = prog_parse_fd(&argc, &argv); | ||
534 | if (fd < 0) | ||
535 | return -1; | ||
536 | |||
537 | if (is_prefix(*argv, "file")) { | ||
538 | NEXT_ARG(); | ||
539 | if (!argc) { | ||
540 | p_err("expected file path"); | ||
541 | return -1; | ||
542 | } | ||
543 | |||
544 | filepath = *argv; | ||
545 | NEXT_ARG(); | ||
546 | } else if (is_prefix(*argv, "opcodes")) { | ||
547 | opcodes = true; | ||
548 | NEXT_ARG(); | ||
549 | } | ||
550 | |||
551 | if (argc) { | ||
552 | usage(); | ||
553 | return -1; | ||
554 | } | ||
555 | |||
556 | err = bpf_obj_get_info_by_fd(fd, &info, &len); | ||
557 | if (err) { | ||
558 | p_err("can't get prog info: %s", strerror(errno)); | ||
559 | return -1; | ||
560 | } | ||
561 | |||
562 | if (!*member_len) { | ||
563 | p_info("no instructions returned"); | ||
564 | close(fd); | ||
565 | return 0; | ||
566 | } | ||
567 | |||
568 | buf_size = *member_len; | ||
569 | |||
570 | buf = malloc(buf_size); | ||
571 | if (!buf) { | ||
572 | p_err("mem alloc failed"); | ||
573 | close(fd); | ||
574 | return -1; | ||
575 | } | ||
576 | |||
577 | memset(&info, 0, sizeof(info)); | ||
578 | |||
579 | *member_ptr = ptr_to_u64(buf); | ||
580 | *member_len = buf_size; | ||
581 | |||
582 | err = bpf_obj_get_info_by_fd(fd, &info, &len); | ||
583 | close(fd); | ||
584 | if (err) { | ||
585 | p_err("can't get prog info: %s", strerror(errno)); | ||
586 | goto err_free; | ||
587 | } | ||
588 | |||
589 | if (*member_len > buf_size) { | ||
590 | p_err("too many instructions returned"); | ||
591 | goto err_free; | ||
592 | } | ||
593 | |||
594 | if (filepath) { | ||
595 | fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); | ||
596 | if (fd < 0) { | ||
597 | p_err("can't open file %s: %s", filepath, | ||
598 | strerror(errno)); | ||
599 | goto err_free; | ||
600 | } | ||
601 | |||
602 | n = write(fd, buf, *member_len); | ||
603 | close(fd); | ||
604 | if (n != *member_len) { | ||
605 | p_err("error writing output file: %s", | ||
606 | n < 0 ? strerror(errno) : "short write"); | ||
607 | goto err_free; | ||
608 | } | ||
609 | } else { | ||
610 | if (member_len == &info.jited_prog_len) | ||
611 | disasm_print_insn(buf, *member_len, opcodes); | ||
612 | else | ||
613 | if (json_output) | ||
614 | dump_xlated_json(buf, *member_len, opcodes); | ||
615 | else | ||
616 | dump_xlated_plain(buf, *member_len, opcodes); | ||
617 | } | ||
618 | |||
619 | free(buf); | ||
620 | |||
621 | return 0; | ||
622 | |||
623 | err_free: | ||
624 | free(buf); | ||
625 | return -1; | ||
626 | } | ||
627 | |||
628 | static int do_pin(int argc, char **argv) | ||
629 | { | ||
630 | int err; | ||
631 | |||
632 | err = do_pin_any(argc, argv, bpf_prog_get_fd_by_id); | ||
633 | if (!err && json_output) | ||
634 | jsonw_null(json_wtr); | ||
635 | return err; | ||
636 | } | ||
637 | |||
638 | static int do_help(int argc, char **argv) | ||
639 | { | ||
640 | if (json_output) { | ||
641 | jsonw_null(json_wtr); | ||
642 | return 0; | ||
643 | } | ||
644 | |||
645 | fprintf(stderr, | ||
646 | "Usage: %s %s show [PROG]\n" | ||
647 | " %s %s dump xlated PROG [{ file FILE | opcodes }]\n" | ||
648 | " %s %s dump jited PROG [{ file FILE | opcodes }]\n" | ||
649 | " %s %s pin PROG FILE\n" | ||
650 | " %s %s help\n" | ||
651 | "\n" | ||
652 | " " HELP_SPEC_PROGRAM "\n" | ||
653 | " " HELP_SPEC_OPTIONS "\n" | ||
654 | "", | ||
655 | bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], | ||
656 | bin_name, argv[-2], bin_name, argv[-2]); | ||
657 | |||
658 | return 0; | ||
659 | } | ||
660 | |||
661 | static const struct cmd cmds[] = { | ||
662 | { "show", do_show }, | ||
663 | { "help", do_help }, | ||
664 | { "dump", do_dump }, | ||
665 | { "pin", do_pin }, | ||
666 | { 0 } | ||
667 | }; | ||
668 | |||
669 | int do_prog(int argc, char **argv) | ||
670 | { | ||
671 | return cmd_select(cmds, argc, argv, do_help); | ||
672 | } | ||
diff --git a/tools/gpio/gpio-utils.c b/tools/gpio/gpio-utils.c index b86a32d90d88..cf7e2f3419ee 100644 --- a/tools/gpio/gpio-utils.c +++ b/tools/gpio/gpio-utils.c | |||
@@ -76,7 +76,8 @@ int gpiotools_request_linehandle(const char *device_name, unsigned int *lines, | |||
76 | fd = open(chrdev_name, 0); | 76 | fd = open(chrdev_name, 0); |
77 | if (fd == -1) { | 77 | if (fd == -1) { |
78 | ret = -errno; | 78 | ret = -errno; |
79 | fprintf(stderr, "Failed to open %s\n", chrdev_name); | 79 | fprintf(stderr, "Failed to open %s, %s\n", |
80 | chrdev_name, strerror(errno)); | ||
80 | goto exit_close_error; | 81 | goto exit_close_error; |
81 | } | 82 | } |
82 | 83 | ||
@@ -92,8 +93,8 @@ int gpiotools_request_linehandle(const char *device_name, unsigned int *lines, | |||
92 | ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req); | 93 | ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req); |
93 | if (ret == -1) { | 94 | if (ret == -1) { |
94 | ret = -errno; | 95 | ret = -errno; |
95 | fprintf(stderr, "Failed to issue GET LINEHANDLE IOCTL (%d)\n", | 96 | fprintf(stderr, "Failed to issue %s (%d), %s\n", |
96 | ret); | 97 | "GPIO_GET_LINEHANDLE_IOCTL", ret, strerror(errno)); |
97 | } | 98 | } |
98 | 99 | ||
99 | exit_close_error: | 100 | exit_close_error: |
@@ -118,8 +119,9 @@ int gpiotools_set_values(const int fd, struct gpiohandle_data *data) | |||
118 | ret = ioctl(fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, data); | 119 | ret = ioctl(fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, data); |
119 | if (ret == -1) { | 120 | if (ret == -1) { |
120 | ret = -errno; | 121 | ret = -errno; |
121 | fprintf(stderr, "Failed to issue %s (%d)\n", | 122 | fprintf(stderr, "Failed to issue %s (%d), %s\n", |
122 | "GPIOHANDLE_SET_LINE_VALUES_IOCTL", ret); | 123 | "GPIOHANDLE_SET_LINE_VALUES_IOCTL", ret, |
124 | strerror(errno)); | ||
123 | } | 125 | } |
124 | 126 | ||
125 | return ret; | 127 | return ret; |
@@ -141,8 +143,9 @@ int gpiotools_get_values(const int fd, struct gpiohandle_data *data) | |||
141 | ret = ioctl(fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, data); | 143 | ret = ioctl(fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, data); |
142 | if (ret == -1) { | 144 | if (ret == -1) { |
143 | ret = -errno; | 145 | ret = -errno; |
144 | fprintf(stderr, "Failed to issue %s (%d)\n", | 146 | fprintf(stderr, "Failed to issue %s (%d), %s\n", |
145 | "GPIOHANDLE_GET_LINE_VALUES_IOCTL", ret); | 147 | "GPIOHANDLE_GET_LINE_VALUES_IOCTL", ret, |
148 | strerror(errno)); | ||
146 | } | 149 | } |
147 | 150 | ||
148 | return ret; | 151 | return ret; |
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index eaa3bec273c8..4c99c57736ce 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c | |||
@@ -193,11 +193,14 @@ static void kvp_update_mem_state(int pool) | |||
193 | for (;;) { | 193 | for (;;) { |
194 | readp = &record[records_read]; | 194 | readp = &record[records_read]; |
195 | records_read += fread(readp, sizeof(struct kvp_record), | 195 | records_read += fread(readp, sizeof(struct kvp_record), |
196 | ENTRIES_PER_BLOCK * num_blocks, | 196 | ENTRIES_PER_BLOCK * num_blocks - records_read, |
197 | filep); | 197 | filep); |
198 | 198 | ||
199 | if (ferror(filep)) { | 199 | if (ferror(filep)) { |
200 | syslog(LOG_ERR, "Failed to read file, pool: %d", pool); | 200 | syslog(LOG_ERR, |
201 | "Failed to read file, pool: %d; error: %d %s", | ||
202 | pool, errno, strerror(errno)); | ||
203 | kvp_release_lock(pool); | ||
201 | exit(EXIT_FAILURE); | 204 | exit(EXIT_FAILURE); |
202 | } | 205 | } |
203 | 206 | ||
@@ -210,6 +213,7 @@ static void kvp_update_mem_state(int pool) | |||
210 | 213 | ||
211 | if (record == NULL) { | 214 | if (record == NULL) { |
212 | syslog(LOG_ERR, "malloc failed"); | 215 | syslog(LOG_ERR, "malloc failed"); |
216 | kvp_release_lock(pool); | ||
213 | exit(EXIT_FAILURE); | 217 | exit(EXIT_FAILURE); |
214 | } | 218 | } |
215 | continue; | 219 | continue; |
@@ -224,15 +228,11 @@ static void kvp_update_mem_state(int pool) | |||
224 | fclose(filep); | 228 | fclose(filep); |
225 | kvp_release_lock(pool); | 229 | kvp_release_lock(pool); |
226 | } | 230 | } |
231 | |||
227 | static int kvp_file_init(void) | 232 | static int kvp_file_init(void) |
228 | { | 233 | { |
229 | int fd; | 234 | int fd; |
230 | FILE *filep; | ||
231 | size_t records_read; | ||
232 | char *fname; | 235 | char *fname; |
233 | struct kvp_record *record; | ||
234 | struct kvp_record *readp; | ||
235 | int num_blocks; | ||
236 | int i; | 236 | int i; |
237 | int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK; | 237 | int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK; |
238 | 238 | ||
@@ -246,61 +246,19 @@ static int kvp_file_init(void) | |||
246 | 246 | ||
247 | for (i = 0; i < KVP_POOL_COUNT; i++) { | 247 | for (i = 0; i < KVP_POOL_COUNT; i++) { |
248 | fname = kvp_file_info[i].fname; | 248 | fname = kvp_file_info[i].fname; |
249 | records_read = 0; | ||
250 | num_blocks = 1; | ||
251 | sprintf(fname, "%s/.kvp_pool_%d", KVP_CONFIG_LOC, i); | 249 | sprintf(fname, "%s/.kvp_pool_%d", KVP_CONFIG_LOC, i); |
252 | fd = open(fname, O_RDWR | O_CREAT | O_CLOEXEC, 0644 /* rw-r--r-- */); | 250 | fd = open(fname, O_RDWR | O_CREAT | O_CLOEXEC, 0644 /* rw-r--r-- */); |
253 | 251 | ||
254 | if (fd == -1) | 252 | if (fd == -1) |
255 | return 1; | 253 | return 1; |
256 | 254 | ||
257 | |||
258 | filep = fopen(fname, "re"); | ||
259 | if (!filep) { | ||
260 | close(fd); | ||
261 | return 1; | ||
262 | } | ||
263 | |||
264 | record = malloc(alloc_unit * num_blocks); | ||
265 | if (record == NULL) { | ||
266 | fclose(filep); | ||
267 | close(fd); | ||
268 | return 1; | ||
269 | } | ||
270 | for (;;) { | ||
271 | readp = &record[records_read]; | ||
272 | records_read += fread(readp, sizeof(struct kvp_record), | ||
273 | ENTRIES_PER_BLOCK, | ||
274 | filep); | ||
275 | |||
276 | if (ferror(filep)) { | ||
277 | syslog(LOG_ERR, "Failed to read file, pool: %d", | ||
278 | i); | ||
279 | exit(EXIT_FAILURE); | ||
280 | } | ||
281 | |||
282 | if (!feof(filep)) { | ||
283 | /* | ||
284 | * We have more data to read. | ||
285 | */ | ||
286 | num_blocks++; | ||
287 | record = realloc(record, alloc_unit * | ||
288 | num_blocks); | ||
289 | if (record == NULL) { | ||
290 | fclose(filep); | ||
291 | close(fd); | ||
292 | return 1; | ||
293 | } | ||
294 | continue; | ||
295 | } | ||
296 | break; | ||
297 | } | ||
298 | kvp_file_info[i].fd = fd; | 255 | kvp_file_info[i].fd = fd; |
299 | kvp_file_info[i].num_blocks = num_blocks; | 256 | kvp_file_info[i].num_blocks = 1; |
300 | kvp_file_info[i].records = record; | 257 | kvp_file_info[i].records = malloc(alloc_unit); |
301 | kvp_file_info[i].num_records = records_read; | 258 | if (kvp_file_info[i].records == NULL) |
302 | fclose(filep); | 259 | return 1; |
303 | 260 | kvp_file_info[i].num_records = 0; | |
261 | kvp_update_mem_state(i); | ||
304 | } | 262 | } |
305 | 263 | ||
306 | return 0; | 264 | return 0; |
diff --git a/tools/include/linux/kmemcheck.h b/tools/include/linux/kmemcheck.h index 2bccd2c7b897..ea32a7d3cf1b 100644 --- a/tools/include/linux/kmemcheck.h +++ b/tools/include/linux/kmemcheck.h | |||
@@ -1,9 +1 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | /* SPDX-License-Identifier: GPL-2.0 */ | |
2 | #ifndef _LIBLOCKDEP_LINUX_KMEMCHECK_H_ | ||
3 | #define _LIBLOCKDEP_LINUX_KMEMCHECK_H_ | ||
4 | |||
5 | static inline void kmemcheck_mark_initialized(void *address, unsigned int n) | ||
6 | { | ||
7 | } | ||
8 | |||
9 | #endif | ||
diff --git a/tools/include/uapi/asm-generic/mman-common.h b/tools/include/uapi/asm-generic/mman-common.h index 6d319c46fd90..f8b134f5608f 100644 --- a/tools/include/uapi/asm-generic/mman-common.h +++ b/tools/include/uapi/asm-generic/mman-common.h | |||
@@ -17,6 +17,7 @@ | |||
17 | 17 | ||
18 | #define MAP_SHARED 0x01 /* Share changes */ | 18 | #define MAP_SHARED 0x01 /* Share changes */ |
19 | #define MAP_PRIVATE 0x02 /* Changes are private */ | 19 | #define MAP_PRIVATE 0x02 /* Changes are private */ |
20 | #define MAP_SHARED_VALIDATE 0x03 /* share + validate extension flags */ | ||
20 | #define MAP_TYPE 0x0f /* Mask for type of mapping */ | 21 | #define MAP_TYPE 0x0f /* Mask for type of mapping */ |
21 | #define MAP_FIXED 0x10 /* Interpret addr exactly */ | 22 | #define MAP_FIXED 0x10 /* Interpret addr exactly */ |
22 | #define MAP_ANONYMOUS 0x20 /* don't use a file */ | 23 | #define MAP_ANONYMOUS 0x20 /* don't use a file */ |
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 30f2ce76b517..4c223ab30293 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h | |||
@@ -93,6 +93,7 @@ enum bpf_cmd { | |||
93 | BPF_PROG_GET_FD_BY_ID, | 93 | BPF_PROG_GET_FD_BY_ID, |
94 | BPF_MAP_GET_FD_BY_ID, | 94 | BPF_MAP_GET_FD_BY_ID, |
95 | BPF_OBJ_GET_INFO_BY_FD, | 95 | BPF_OBJ_GET_INFO_BY_FD, |
96 | BPF_PROG_QUERY, | ||
96 | }; | 97 | }; |
97 | 98 | ||
98 | enum bpf_map_type { | 99 | enum bpf_map_type { |
@@ -112,6 +113,7 @@ enum bpf_map_type { | |||
112 | BPF_MAP_TYPE_HASH_OF_MAPS, | 113 | BPF_MAP_TYPE_HASH_OF_MAPS, |
113 | BPF_MAP_TYPE_DEVMAP, | 114 | BPF_MAP_TYPE_DEVMAP, |
114 | BPF_MAP_TYPE_SOCKMAP, | 115 | BPF_MAP_TYPE_SOCKMAP, |
116 | BPF_MAP_TYPE_CPUMAP, | ||
115 | }; | 117 | }; |
116 | 118 | ||
117 | enum bpf_prog_type { | 119 | enum bpf_prog_type { |
@@ -130,6 +132,7 @@ enum bpf_prog_type { | |||
130 | BPF_PROG_TYPE_LWT_XMIT, | 132 | BPF_PROG_TYPE_LWT_XMIT, |
131 | BPF_PROG_TYPE_SOCK_OPS, | 133 | BPF_PROG_TYPE_SOCK_OPS, |
132 | BPF_PROG_TYPE_SK_SKB, | 134 | BPF_PROG_TYPE_SK_SKB, |
135 | BPF_PROG_TYPE_CGROUP_DEVICE, | ||
133 | }; | 136 | }; |
134 | 137 | ||
135 | enum bpf_attach_type { | 138 | enum bpf_attach_type { |
@@ -139,16 +142,53 @@ enum bpf_attach_type { | |||
139 | BPF_CGROUP_SOCK_OPS, | 142 | BPF_CGROUP_SOCK_OPS, |
140 | BPF_SK_SKB_STREAM_PARSER, | 143 | BPF_SK_SKB_STREAM_PARSER, |
141 | BPF_SK_SKB_STREAM_VERDICT, | 144 | BPF_SK_SKB_STREAM_VERDICT, |
145 | BPF_CGROUP_DEVICE, | ||
142 | __MAX_BPF_ATTACH_TYPE | 146 | __MAX_BPF_ATTACH_TYPE |
143 | }; | 147 | }; |
144 | 148 | ||
145 | #define MAX_BPF_ATTACH_TYPE __MAX_BPF_ATTACH_TYPE | 149 | #define MAX_BPF_ATTACH_TYPE __MAX_BPF_ATTACH_TYPE |
146 | 150 | ||
147 | /* If BPF_F_ALLOW_OVERRIDE flag is used in BPF_PROG_ATTACH command | 151 | /* cgroup-bpf attach flags used in BPF_PROG_ATTACH command |
148 | * to the given target_fd cgroup the descendent cgroup will be able to | 152 | * |
149 | * override effective bpf program that was inherited from this cgroup | 153 | * NONE(default): No further bpf programs allowed in the subtree. |
154 | * | ||
155 | * BPF_F_ALLOW_OVERRIDE: If a sub-cgroup installs some bpf program, | ||
156 | * the program in this cgroup yields to sub-cgroup program. | ||
157 | * | ||
158 | * BPF_F_ALLOW_MULTI: If a sub-cgroup installs some bpf program, | ||
159 | * that cgroup program gets run in addition to the program in this cgroup. | ||
160 | * | ||
161 | * Only one program is allowed to be attached to a cgroup with | ||
162 | * NONE or BPF_F_ALLOW_OVERRIDE flag. | ||
163 | * Attaching another program on top of NONE or BPF_F_ALLOW_OVERRIDE will | ||
164 | * release old program and attach the new one. Attach flags has to match. | ||
165 | * | ||
166 | * Multiple programs are allowed to be attached to a cgroup with | ||
167 | * BPF_F_ALLOW_MULTI flag. They are executed in FIFO order | ||
168 | * (those that were attached first, run first) | ||
169 | * The programs of sub-cgroup are executed first, then programs of | ||
170 | * this cgroup and then programs of parent cgroup. | ||
171 | * When children program makes decision (like picking TCP CA or sock bind) | ||
172 | * parent program has a chance to override it. | ||
173 | * | ||
174 | * A cgroup with MULTI or OVERRIDE flag allows any attach flags in sub-cgroups. | ||
175 | * A cgroup with NONE doesn't allow any programs in sub-cgroups. | ||
176 | * Ex1: | ||
177 | * cgrp1 (MULTI progs A, B) -> | ||
178 | * cgrp2 (OVERRIDE prog C) -> | ||
179 | * cgrp3 (MULTI prog D) -> | ||
180 | * cgrp4 (OVERRIDE prog E) -> | ||
181 | * cgrp5 (NONE prog F) | ||
182 | * the event in cgrp5 triggers execution of F,D,A,B in that order. | ||
183 | * if prog F is detached, the execution is E,D,A,B | ||
184 | * if prog F and D are detached, the execution is E,A,B | ||
185 | * if prog F, E and D are detached, the execution is C,A,B | ||
186 | * | ||
187 | * All eligible programs are executed regardless of return code from | ||
188 | * earlier programs. | ||
150 | */ | 189 | */ |
151 | #define BPF_F_ALLOW_OVERRIDE (1U << 0) | 190 | #define BPF_F_ALLOW_OVERRIDE (1U << 0) |
191 | #define BPF_F_ALLOW_MULTI (1U << 1) | ||
152 | 192 | ||
153 | /* If BPF_F_STRICT_ALIGNMENT is used in BPF_PROG_LOAD command, the | 193 | /* If BPF_F_STRICT_ALIGNMENT is used in BPF_PROG_LOAD command, the |
154 | * verifier will perform strict alignment checking as if the kernel | 194 | * verifier will perform strict alignment checking as if the kernel |
@@ -176,6 +216,15 @@ enum bpf_attach_type { | |||
176 | /* Specify numa node during map creation */ | 216 | /* Specify numa node during map creation */ |
177 | #define BPF_F_NUMA_NODE (1U << 2) | 217 | #define BPF_F_NUMA_NODE (1U << 2) |
178 | 218 | ||
219 | /* flags for BPF_PROG_QUERY */ | ||
220 | #define BPF_F_QUERY_EFFECTIVE (1U << 0) | ||
221 | |||
222 | #define BPF_OBJ_NAME_LEN 16U | ||
223 | |||
224 | /* Flags for accessing BPF object */ | ||
225 | #define BPF_F_RDONLY (1U << 3) | ||
226 | #define BPF_F_WRONLY (1U << 4) | ||
227 | |||
179 | union bpf_attr { | 228 | union bpf_attr { |
180 | struct { /* anonymous struct used by BPF_MAP_CREATE command */ | 229 | struct { /* anonymous struct used by BPF_MAP_CREATE command */ |
181 | __u32 map_type; /* one of enum bpf_map_type */ | 230 | __u32 map_type; /* one of enum bpf_map_type */ |
@@ -189,6 +238,7 @@ union bpf_attr { | |||
189 | __u32 numa_node; /* numa node (effective only if | 238 | __u32 numa_node; /* numa node (effective only if |
190 | * BPF_F_NUMA_NODE is set). | 239 | * BPF_F_NUMA_NODE is set). |
191 | */ | 240 | */ |
241 | char map_name[BPF_OBJ_NAME_LEN]; | ||
192 | }; | 242 | }; |
193 | 243 | ||
194 | struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */ | 244 | struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */ |
@@ -211,11 +261,14 @@ union bpf_attr { | |||
211 | __aligned_u64 log_buf; /* user supplied buffer */ | 261 | __aligned_u64 log_buf; /* user supplied buffer */ |
212 | __u32 kern_version; /* checked when prog_type=kprobe */ | 262 | __u32 kern_version; /* checked when prog_type=kprobe */ |
213 | __u32 prog_flags; | 263 | __u32 prog_flags; |
264 | char prog_name[BPF_OBJ_NAME_LEN]; | ||
265 | __u32 prog_ifindex; /* ifindex of netdev to prep for */ | ||
214 | }; | 266 | }; |
215 | 267 | ||
216 | struct { /* anonymous struct used by BPF_OBJ_* commands */ | 268 | struct { /* anonymous struct used by BPF_OBJ_* commands */ |
217 | __aligned_u64 pathname; | 269 | __aligned_u64 pathname; |
218 | __u32 bpf_fd; | 270 | __u32 bpf_fd; |
271 | __u32 file_flags; | ||
219 | }; | 272 | }; |
220 | 273 | ||
221 | struct { /* anonymous struct used by BPF_PROG_ATTACH/DETACH commands */ | 274 | struct { /* anonymous struct used by BPF_PROG_ATTACH/DETACH commands */ |
@@ -243,6 +296,7 @@ union bpf_attr { | |||
243 | __u32 map_id; | 296 | __u32 map_id; |
244 | }; | 297 | }; |
245 | __u32 next_id; | 298 | __u32 next_id; |
299 | __u32 open_flags; | ||
246 | }; | 300 | }; |
247 | 301 | ||
248 | struct { /* anonymous struct used by BPF_OBJ_GET_INFO_BY_FD */ | 302 | struct { /* anonymous struct used by BPF_OBJ_GET_INFO_BY_FD */ |
@@ -250,6 +304,15 @@ union bpf_attr { | |||
250 | __u32 info_len; | 304 | __u32 info_len; |
251 | __aligned_u64 info; | 305 | __aligned_u64 info; |
252 | } info; | 306 | } info; |
307 | |||
308 | struct { /* anonymous struct used by BPF_PROG_QUERY command */ | ||
309 | __u32 target_fd; /* container object to query */ | ||
310 | __u32 attach_type; | ||
311 | __u32 query_flags; | ||
312 | __u32 attach_flags; | ||
313 | __aligned_u64 prog_ids; | ||
314 | __u32 prog_cnt; | ||
315 | } query; | ||
253 | } __attribute__((aligned(8))); | 316 | } __attribute__((aligned(8))); |
254 | 317 | ||
255 | /* BPF helper function descriptions: | 318 | /* BPF helper function descriptions: |
@@ -554,12 +617,22 @@ union bpf_attr { | |||
554 | * int bpf_setsockopt(bpf_socket, level, optname, optval, optlen) | 617 | * int bpf_setsockopt(bpf_socket, level, optname, optval, optlen) |
555 | * Calls setsockopt. Not all opts are available, only those with | 618 | * Calls setsockopt. Not all opts are available, only those with |
556 | * integer optvals plus TCP_CONGESTION. | 619 | * integer optvals plus TCP_CONGESTION. |
557 | * Supported levels: SOL_SOCKET and IPROTO_TCP | 620 | * Supported levels: SOL_SOCKET and IPPROTO_TCP |
621 | * @bpf_socket: pointer to bpf_socket | ||
622 | * @level: SOL_SOCKET or IPPROTO_TCP | ||
623 | * @optname: option name | ||
624 | * @optval: pointer to option value | ||
625 | * @optlen: length of optval in bytes | ||
626 | * Return: 0 or negative error | ||
627 | * | ||
628 | * int bpf_getsockopt(bpf_socket, level, optname, optval, optlen) | ||
629 | * Calls getsockopt. Not all opts are available. | ||
630 | * Supported levels: IPPROTO_TCP | ||
558 | * @bpf_socket: pointer to bpf_socket | 631 | * @bpf_socket: pointer to bpf_socket |
559 | * @level: SOL_SOCKET or IPROTO_TCP | 632 | * @level: IPPROTO_TCP |
560 | * @optname: option name | 633 | * @optname: option name |
561 | * @optval: pointer to option value | 634 | * @optval: pointer to option value |
562 | * @optlen: length of optval in byes | 635 | * @optlen: length of optval in bytes |
563 | * Return: 0 or negative error | 636 | * Return: 0 or negative error |
564 | * | 637 | * |
565 | * int bpf_skb_adjust_room(skb, len_diff, mode, flags) | 638 | * int bpf_skb_adjust_room(skb, len_diff, mode, flags) |
@@ -583,6 +656,27 @@ union bpf_attr { | |||
583 | * @map: pointer to sockmap to update | 656 | * @map: pointer to sockmap to update |
584 | * @key: key to insert/update sock in map | 657 | * @key: key to insert/update sock in map |
585 | * @flags: same flags as map update elem | 658 | * @flags: same flags as map update elem |
659 | * | ||
660 | * int bpf_xdp_adjust_meta(xdp_md, delta) | ||
661 | * Adjust the xdp_md.data_meta by delta | ||
662 | * @xdp_md: pointer to xdp_md | ||
663 | * @delta: An positive/negative integer to be added to xdp_md.data_meta | ||
664 | * Return: 0 on success or negative on error | ||
665 | * | ||
666 | * int bpf_perf_event_read_value(map, flags, buf, buf_size) | ||
667 | * read perf event counter value and perf event enabled/running time | ||
668 | * @map: pointer to perf_event_array map | ||
669 | * @flags: index of event in the map or bitmask flags | ||
670 | * @buf: buf to fill | ||
671 | * @buf_size: size of the buf | ||
672 | * Return: 0 on success or negative error code | ||
673 | * | ||
674 | * int bpf_perf_prog_read_value(ctx, buf, buf_size) | ||
675 | * read perf prog attached perf event counter and enabled/running time | ||
676 | * @ctx: pointer to ctx | ||
677 | * @buf: buf to fill | ||
678 | * @buf_size: size of the buf | ||
679 | * Return : 0 on success or negative error code | ||
586 | */ | 680 | */ |
587 | #define __BPF_FUNC_MAPPER(FN) \ | 681 | #define __BPF_FUNC_MAPPER(FN) \ |
588 | FN(unspec), \ | 682 | FN(unspec), \ |
@@ -639,6 +733,10 @@ union bpf_attr { | |||
639 | FN(redirect_map), \ | 733 | FN(redirect_map), \ |
640 | FN(sk_redirect_map), \ | 734 | FN(sk_redirect_map), \ |
641 | FN(sock_map_update), \ | 735 | FN(sock_map_update), \ |
736 | FN(xdp_adjust_meta), \ | ||
737 | FN(perf_event_read_value), \ | ||
738 | FN(perf_prog_read_value), \ | ||
739 | FN(getsockopt), | ||
642 | 740 | ||
643 | /* integer value in 'imm' field of BPF_CALL instruction selects which helper | 741 | /* integer value in 'imm' field of BPF_CALL instruction selects which helper |
644 | * function eBPF program intends to call | 742 | * function eBPF program intends to call |
@@ -682,7 +780,9 @@ enum bpf_func_id { | |||
682 | #define BPF_F_ZERO_CSUM_TX (1ULL << 1) | 780 | #define BPF_F_ZERO_CSUM_TX (1ULL << 1) |
683 | #define BPF_F_DONT_FRAGMENT (1ULL << 2) | 781 | #define BPF_F_DONT_FRAGMENT (1ULL << 2) |
684 | 782 | ||
685 | /* BPF_FUNC_perf_event_output and BPF_FUNC_perf_event_read flags. */ | 783 | /* BPF_FUNC_perf_event_output, BPF_FUNC_perf_event_read and |
784 | * BPF_FUNC_perf_event_read_value flags. | ||
785 | */ | ||
686 | #define BPF_F_INDEX_MASK 0xffffffffULL | 786 | #define BPF_F_INDEX_MASK 0xffffffffULL |
687 | #define BPF_F_CURRENT_CPU BPF_F_INDEX_MASK | 787 | #define BPF_F_CURRENT_CPU BPF_F_INDEX_MASK |
688 | /* BPF_FUNC_perf_event_output for sk_buff input context. */ | 788 | /* BPF_FUNC_perf_event_output for sk_buff input context. */ |
@@ -716,7 +816,7 @@ struct __sk_buff { | |||
716 | __u32 data_end; | 816 | __u32 data_end; |
717 | __u32 napi_id; | 817 | __u32 napi_id; |
718 | 818 | ||
719 | /* accessed by BPF_PROG_TYPE_sk_skb types */ | 819 | /* Accessed by BPF_PROG_TYPE_sk_skb types from here to ... */ |
720 | __u32 family; | 820 | __u32 family; |
721 | __u32 remote_ip4; /* Stored in network byte order */ | 821 | __u32 remote_ip4; /* Stored in network byte order */ |
722 | __u32 local_ip4; /* Stored in network byte order */ | 822 | __u32 local_ip4; /* Stored in network byte order */ |
@@ -724,6 +824,9 @@ struct __sk_buff { | |||
724 | __u32 local_ip6[4]; /* Stored in network byte order */ | 824 | __u32 local_ip6[4]; /* Stored in network byte order */ |
725 | __u32 remote_port; /* Stored in network byte order */ | 825 | __u32 remote_port; /* Stored in network byte order */ |
726 | __u32 local_port; /* stored in host byte order */ | 826 | __u32 local_port; /* stored in host byte order */ |
827 | /* ... here. */ | ||
828 | |||
829 | __u32 data_meta; | ||
727 | }; | 830 | }; |
728 | 831 | ||
729 | struct bpf_tunnel_key { | 832 | struct bpf_tunnel_key { |
@@ -784,6 +887,7 @@ enum xdp_action { | |||
784 | struct xdp_md { | 887 | struct xdp_md { |
785 | __u32 data; | 888 | __u32 data; |
786 | __u32 data_end; | 889 | __u32 data_end; |
890 | __u32 data_meta; | ||
787 | }; | 891 | }; |
788 | 892 | ||
789 | enum sk_action { | 893 | enum sk_action { |
@@ -801,6 +905,11 @@ struct bpf_prog_info { | |||
801 | __u32 xlated_prog_len; | 905 | __u32 xlated_prog_len; |
802 | __aligned_u64 jited_prog_insns; | 906 | __aligned_u64 jited_prog_insns; |
803 | __aligned_u64 xlated_prog_insns; | 907 | __aligned_u64 xlated_prog_insns; |
908 | __u64 load_time; /* ns since boottime */ | ||
909 | __u32 created_by_uid; | ||
910 | __u32 nr_map_ids; | ||
911 | __aligned_u64 map_ids; | ||
912 | char name[BPF_OBJ_NAME_LEN]; | ||
804 | } __attribute__((aligned(8))); | 913 | } __attribute__((aligned(8))); |
805 | 914 | ||
806 | struct bpf_map_info { | 915 | struct bpf_map_info { |
@@ -810,6 +919,7 @@ struct bpf_map_info { | |||
810 | __u32 value_size; | 919 | __u32 value_size; |
811 | __u32 max_entries; | 920 | __u32 max_entries; |
812 | __u32 map_flags; | 921 | __u32 map_flags; |
922 | char name[BPF_OBJ_NAME_LEN]; | ||
813 | } __attribute__((aligned(8))); | 923 | } __attribute__((aligned(8))); |
814 | 924 | ||
815 | /* User bpf_sock_ops struct to access socket values and specify request ops | 925 | /* User bpf_sock_ops struct to access socket values and specify request ops |
@@ -859,9 +969,35 @@ enum { | |||
859 | BPF_SOCK_OPS_NEEDS_ECN, /* If connection's congestion control | 969 | BPF_SOCK_OPS_NEEDS_ECN, /* If connection's congestion control |
860 | * needs ECN | 970 | * needs ECN |
861 | */ | 971 | */ |
972 | BPF_SOCK_OPS_BASE_RTT, /* Get base RTT. The correct value is | ||
973 | * based on the path and may be | ||
974 | * dependent on the congestion control | ||
975 | * algorithm. In general it indicates | ||
976 | * a congestion threshold. RTTs above | ||
977 | * this indicate congestion | ||
978 | */ | ||
862 | }; | 979 | }; |
863 | 980 | ||
864 | #define TCP_BPF_IW 1001 /* Set TCP initial congestion window */ | 981 | #define TCP_BPF_IW 1001 /* Set TCP initial congestion window */ |
865 | #define TCP_BPF_SNDCWND_CLAMP 1002 /* Set sndcwnd_clamp */ | 982 | #define TCP_BPF_SNDCWND_CLAMP 1002 /* Set sndcwnd_clamp */ |
866 | 983 | ||
984 | struct bpf_perf_event_value { | ||
985 | __u64 counter; | ||
986 | __u64 enabled; | ||
987 | __u64 running; | ||
988 | }; | ||
989 | |||
990 | #define BPF_DEVCG_ACC_MKNOD (1ULL << 0) | ||
991 | #define BPF_DEVCG_ACC_READ (1ULL << 1) | ||
992 | #define BPF_DEVCG_ACC_WRITE (1ULL << 2) | ||
993 | |||
994 | #define BPF_DEVCG_DEV_BLOCK (1ULL << 0) | ||
995 | #define BPF_DEVCG_DEV_CHAR (1ULL << 1) | ||
996 | |||
997 | struct bpf_cgroup_dev_ctx { | ||
998 | __u32 access_type; /* (access << 16) | type */ | ||
999 | __u32 major; | ||
1000 | __u32 minor; | ||
1001 | }; | ||
1002 | |||
867 | #endif /* _UAPI__LINUX_BPF_H__ */ | 1003 | #endif /* _UAPI__LINUX_BPF_H__ */ |
diff --git a/tools/kvm/kvm_stat/kvm_stat b/tools/kvm/kvm_stat/kvm_stat index 32283d88701a..217cf6f95c36 100755 --- a/tools/kvm/kvm_stat/kvm_stat +++ b/tools/kvm/kvm_stat/kvm_stat | |||
@@ -19,9 +19,11 @@ Three different ways of output formatting are available: | |||
19 | 19 | ||
20 | The data is sampled from the KVM's debugfs entries and its perf events. | 20 | The data is sampled from the KVM's debugfs entries and its perf events. |
21 | """ | 21 | """ |
22 | from __future__ import print_function | ||
22 | 23 | ||
23 | import curses | 24 | import curses |
24 | import sys | 25 | import sys |
26 | import locale | ||
25 | import os | 27 | import os |
26 | import time | 28 | import time |
27 | import optparse | 29 | import optparse |
@@ -225,6 +227,8 @@ IOCTL_NUMBERS = { | |||
225 | 'RESET': 0x00002403, | 227 | 'RESET': 0x00002403, |
226 | } | 228 | } |
227 | 229 | ||
230 | ENCODING = locale.getpreferredencoding(False) | ||
231 | |||
228 | 232 | ||
229 | class Arch(object): | 233 | class Arch(object): |
230 | """Encapsulates global architecture specific data. | 234 | """Encapsulates global architecture specific data. |
@@ -666,7 +670,7 @@ class TracepointProvider(Provider): | |||
666 | """Returns 'event name: current value' for all enabled events.""" | 670 | """Returns 'event name: current value' for all enabled events.""" |
667 | ret = defaultdict(int) | 671 | ret = defaultdict(int) |
668 | for group in self.group_leaders: | 672 | for group in self.group_leaders: |
669 | for name, val in group.read().iteritems(): | 673 | for name, val in group.read().items(): |
670 | if name in self._fields: | 674 | if name in self._fields: |
671 | ret[name] += val | 675 | ret[name] += val |
672 | return ret | 676 | return ret |
@@ -955,7 +959,7 @@ class Tui(object): | |||
955 | except: | 959 | except: |
956 | raise Exception | 960 | raise Exception |
957 | for line in child.stdout: | 961 | for line in child.stdout: |
958 | line = line.lstrip().split(' ', 1) | 962 | line = line.decode(ENCODING).lstrip().split(' ', 1) |
959 | # perform a sanity check before calling the more expensive | 963 | # perform a sanity check before calling the more expensive |
960 | # function to possibly extract the guest name | 964 | # function to possibly extract the guest name |
961 | if ' -name ' in line[1]: | 965 | if ' -name ' in line[1]: |
@@ -1005,7 +1009,7 @@ class Tui(object): | |||
1005 | name = '' | 1009 | name = '' |
1006 | try: | 1010 | try: |
1007 | line = open('/proc/{}/cmdline' | 1011 | line = open('/proc/{}/cmdline' |
1008 | .format(pid), 'rb').read().split('\0') | 1012 | .format(pid), 'r').read().split('\0') |
1009 | parms = line[line.index('-name') + 1].split(',') | 1013 | parms = line[line.index('-name') + 1].split(',') |
1010 | while '' in parms: | 1014 | while '' in parms: |
1011 | # commas are escaped (i.e. ',,'), hence e.g. 'foo,bar' results | 1015 | # commas are escaped (i.e. ',,'), hence e.g. 'foo,bar' results |
@@ -1170,7 +1174,7 @@ class Tui(object): | |||
1170 | .format(self.stats.fields_filter)) | 1174 | .format(self.stats.fields_filter)) |
1171 | self.screen.addstr(3, 0, "New regex: ") | 1175 | self.screen.addstr(3, 0, "New regex: ") |
1172 | curses.echo() | 1176 | curses.echo() |
1173 | regex = self.screen.getstr() | 1177 | regex = self.screen.getstr().decode(ENCODING) |
1174 | curses.noecho() | 1178 | curses.noecho() |
1175 | if len(regex) == 0: | 1179 | if len(regex) == 0: |
1176 | self.stats.fields_filter = DEFAULT_REGEX | 1180 | self.stats.fields_filter = DEFAULT_REGEX |
@@ -1204,7 +1208,7 @@ class Tui(object): | |||
1204 | 1208 | ||
1205 | curses.echo() | 1209 | curses.echo() |
1206 | self.screen.addstr(3, 0, "Pid [0 or pid]: ") | 1210 | self.screen.addstr(3, 0, "Pid [0 or pid]: ") |
1207 | pid = self.screen.getstr() | 1211 | pid = self.screen.getstr().decode(ENCODING) |
1208 | curses.noecho() | 1212 | curses.noecho() |
1209 | 1213 | ||
1210 | try: | 1214 | try: |
@@ -1233,7 +1237,7 @@ class Tui(object): | |||
1233 | self.screen.addstr(2, 0, 'Change delay from %.1fs to ' % | 1237 | self.screen.addstr(2, 0, 'Change delay from %.1fs to ' % |
1234 | self._delay_regular) | 1238 | self._delay_regular) |
1235 | curses.echo() | 1239 | curses.echo() |
1236 | val = self.screen.getstr() | 1240 | val = self.screen.getstr().decode(ENCODING) |
1237 | curses.noecho() | 1241 | curses.noecho() |
1238 | 1242 | ||
1239 | try: | 1243 | try: |
@@ -1273,7 +1277,7 @@ class Tui(object): | |||
1273 | self.print_all_gnames(7) | 1277 | self.print_all_gnames(7) |
1274 | curses.echo() | 1278 | curses.echo() |
1275 | self.screen.addstr(3, 0, "Guest [ENTER or guest]: ") | 1279 | self.screen.addstr(3, 0, "Guest [ENTER or guest]: ") |
1276 | gname = self.screen.getstr() | 1280 | gname = self.screen.getstr().decode(ENCODING) |
1277 | curses.noecho() | 1281 | curses.noecho() |
1278 | 1282 | ||
1279 | if not gname: | 1283 | if not gname: |
@@ -1369,25 +1373,25 @@ def batch(stats): | |||
1369 | s = stats.get() | 1373 | s = stats.get() |
1370 | for key in sorted(s.keys()): | 1374 | for key in sorted(s.keys()): |
1371 | values = s[key] | 1375 | values = s[key] |
1372 | print '%-42s%10d%10d' % (key, values[0], values[1]) | 1376 | print('%-42s%10d%10d' % (key, values[0], values[1])) |
1373 | except KeyboardInterrupt: | 1377 | except KeyboardInterrupt: |
1374 | pass | 1378 | pass |
1375 | 1379 | ||
1376 | 1380 | ||
1377 | def log(stats): | 1381 | def log(stats): |
1378 | """Prints statistics as reiterating key block, multiple value blocks.""" | 1382 | """Prints statistics as reiterating key block, multiple value blocks.""" |
1379 | keys = sorted(stats.get().iterkeys()) | 1383 | keys = sorted(stats.get().keys()) |
1380 | 1384 | ||
1381 | def banner(): | 1385 | def banner(): |
1382 | for k in keys: | 1386 | for k in keys: |
1383 | print '%s' % k, | 1387 | print(k, end=' ') |
1384 | 1388 | print() | |
1385 | 1389 | ||
1386 | def statline(): | 1390 | def statline(): |
1387 | s = stats.get() | 1391 | s = stats.get() |
1388 | for k in keys: | 1392 | for k in keys: |
1389 | print ' %9d' % s[k][1], | 1393 | print(' %9d' % s[k][1], end=' ') |
1390 | 1394 | print() | |
1391 | line = 0 | 1395 | line = 0 |
1392 | banner_repeat = 20 | 1396 | banner_repeat = 20 |
1393 | while True: | 1397 | while True: |
diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 1d6907d379c9..5128677e4117 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c | |||
@@ -46,6 +46,8 @@ | |||
46 | # endif | 46 | # endif |
47 | #endif | 47 | #endif |
48 | 48 | ||
49 | #define min(x, y) ((x) < (y) ? (x) : (y)) | ||
50 | |||
49 | static inline __u64 ptr_to_u64(const void *ptr) | 51 | static inline __u64 ptr_to_u64(const void *ptr) |
50 | { | 52 | { |
51 | return (__u64) (unsigned long) ptr; | 53 | return (__u64) (unsigned long) ptr; |
@@ -57,10 +59,11 @@ static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr, | |||
57 | return syscall(__NR_bpf, cmd, attr, size); | 59 | return syscall(__NR_bpf, cmd, attr, size); |
58 | } | 60 | } |
59 | 61 | ||
60 | int bpf_create_map_node(enum bpf_map_type map_type, int key_size, | 62 | int bpf_create_map_node(enum bpf_map_type map_type, const char *name, |
61 | int value_size, int max_entries, __u32 map_flags, | 63 | int key_size, int value_size, int max_entries, |
62 | int node) | 64 | __u32 map_flags, int node) |
63 | { | 65 | { |
66 | __u32 name_len = name ? strlen(name) : 0; | ||
64 | union bpf_attr attr; | 67 | union bpf_attr attr; |
65 | 68 | ||
66 | memset(&attr, '\0', sizeof(attr)); | 69 | memset(&attr, '\0', sizeof(attr)); |
@@ -70,6 +73,8 @@ int bpf_create_map_node(enum bpf_map_type map_type, int key_size, | |||
70 | attr.value_size = value_size; | 73 | attr.value_size = value_size; |
71 | attr.max_entries = max_entries; | 74 | attr.max_entries = max_entries; |
72 | attr.map_flags = map_flags; | 75 | attr.map_flags = map_flags; |
76 | memcpy(attr.map_name, name, min(name_len, BPF_OBJ_NAME_LEN - 1)); | ||
77 | |||
73 | if (node >= 0) { | 78 | if (node >= 0) { |
74 | attr.map_flags |= BPF_F_NUMA_NODE; | 79 | attr.map_flags |= BPF_F_NUMA_NODE; |
75 | attr.numa_node = node; | 80 | attr.numa_node = node; |
@@ -81,14 +86,23 @@ int bpf_create_map_node(enum bpf_map_type map_type, int key_size, | |||
81 | int bpf_create_map(enum bpf_map_type map_type, int key_size, | 86 | int bpf_create_map(enum bpf_map_type map_type, int key_size, |
82 | int value_size, int max_entries, __u32 map_flags) | 87 | int value_size, int max_entries, __u32 map_flags) |
83 | { | 88 | { |
84 | return bpf_create_map_node(map_type, key_size, value_size, | 89 | return bpf_create_map_node(map_type, NULL, key_size, value_size, |
85 | max_entries, map_flags, -1); | 90 | max_entries, map_flags, -1); |
86 | } | 91 | } |
87 | 92 | ||
88 | int bpf_create_map_in_map_node(enum bpf_map_type map_type, int key_size, | 93 | int bpf_create_map_name(enum bpf_map_type map_type, const char *name, |
89 | int inner_map_fd, int max_entries, | 94 | int key_size, int value_size, int max_entries, |
95 | __u32 map_flags) | ||
96 | { | ||
97 | return bpf_create_map_node(map_type, name, key_size, value_size, | ||
98 | max_entries, map_flags, -1); | ||
99 | } | ||
100 | |||
101 | int bpf_create_map_in_map_node(enum bpf_map_type map_type, const char *name, | ||
102 | int key_size, int inner_map_fd, int max_entries, | ||
90 | __u32 map_flags, int node) | 103 | __u32 map_flags, int node) |
91 | { | 104 | { |
105 | __u32 name_len = name ? strlen(name) : 0; | ||
92 | union bpf_attr attr; | 106 | union bpf_attr attr; |
93 | 107 | ||
94 | memset(&attr, '\0', sizeof(attr)); | 108 | memset(&attr, '\0', sizeof(attr)); |
@@ -99,6 +113,8 @@ int bpf_create_map_in_map_node(enum bpf_map_type map_type, int key_size, | |||
99 | attr.inner_map_fd = inner_map_fd; | 113 | attr.inner_map_fd = inner_map_fd; |
100 | attr.max_entries = max_entries; | 114 | attr.max_entries = max_entries; |
101 | attr.map_flags = map_flags; | 115 | attr.map_flags = map_flags; |
116 | memcpy(attr.map_name, name, min(name_len, BPF_OBJ_NAME_LEN - 1)); | ||
117 | |||
102 | if (node >= 0) { | 118 | if (node >= 0) { |
103 | attr.map_flags |= BPF_F_NUMA_NODE; | 119 | attr.map_flags |= BPF_F_NUMA_NODE; |
104 | attr.numa_node = node; | 120 | attr.numa_node = node; |
@@ -107,19 +123,24 @@ int bpf_create_map_in_map_node(enum bpf_map_type map_type, int key_size, | |||
107 | return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); | 123 | return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); |
108 | } | 124 | } |
109 | 125 | ||
110 | int bpf_create_map_in_map(enum bpf_map_type map_type, int key_size, | 126 | int bpf_create_map_in_map(enum bpf_map_type map_type, const char *name, |
111 | int inner_map_fd, int max_entries, __u32 map_flags) | 127 | int key_size, int inner_map_fd, int max_entries, |
128 | __u32 map_flags) | ||
112 | { | 129 | { |
113 | return bpf_create_map_in_map_node(map_type, key_size, inner_map_fd, | 130 | return bpf_create_map_in_map_node(map_type, name, key_size, |
114 | max_entries, map_flags, -1); | 131 | inner_map_fd, max_entries, map_flags, |
132 | -1); | ||
115 | } | 133 | } |
116 | 134 | ||
117 | int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns, | 135 | int bpf_load_program_name(enum bpf_prog_type type, const char *name, |
118 | size_t insns_cnt, const char *license, | 136 | const struct bpf_insn *insns, |
119 | __u32 kern_version, char *log_buf, size_t log_buf_sz) | 137 | size_t insns_cnt, const char *license, |
138 | __u32 kern_version, char *log_buf, | ||
139 | size_t log_buf_sz) | ||
120 | { | 140 | { |
121 | int fd; | 141 | int fd; |
122 | union bpf_attr attr; | 142 | union bpf_attr attr; |
143 | __u32 name_len = name ? strlen(name) : 0; | ||
123 | 144 | ||
124 | bzero(&attr, sizeof(attr)); | 145 | bzero(&attr, sizeof(attr)); |
125 | attr.prog_type = type; | 146 | attr.prog_type = type; |
@@ -130,6 +151,7 @@ int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns, | |||
130 | attr.log_size = 0; | 151 | attr.log_size = 0; |
131 | attr.log_level = 0; | 152 | attr.log_level = 0; |
132 | attr.kern_version = kern_version; | 153 | attr.kern_version = kern_version; |
154 | memcpy(attr.prog_name, name, min(name_len, BPF_OBJ_NAME_LEN - 1)); | ||
133 | 155 | ||
134 | fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); | 156 | fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); |
135 | if (fd >= 0 || !log_buf || !log_buf_sz) | 157 | if (fd >= 0 || !log_buf || !log_buf_sz) |
@@ -143,6 +165,15 @@ int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns, | |||
143 | return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); | 165 | return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); |
144 | } | 166 | } |
145 | 167 | ||
168 | int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns, | ||
169 | size_t insns_cnt, const char *license, | ||
170 | __u32 kern_version, char *log_buf, | ||
171 | size_t log_buf_sz) | ||
172 | { | ||
173 | return bpf_load_program_name(type, NULL, insns, insns_cnt, license, | ||
174 | kern_version, log_buf, log_buf_sz); | ||
175 | } | ||
176 | |||
146 | int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns, | 177 | int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns, |
147 | size_t insns_cnt, int strict_alignment, | 178 | size_t insns_cnt, int strict_alignment, |
148 | const char *license, __u32 kern_version, | 179 | const char *license, __u32 kern_version, |
@@ -260,6 +291,38 @@ int bpf_prog_detach(int target_fd, enum bpf_attach_type type) | |||
260 | return sys_bpf(BPF_PROG_DETACH, &attr, sizeof(attr)); | 291 | return sys_bpf(BPF_PROG_DETACH, &attr, sizeof(attr)); |
261 | } | 292 | } |
262 | 293 | ||
294 | int bpf_prog_detach2(int prog_fd, int target_fd, enum bpf_attach_type type) | ||
295 | { | ||
296 | union bpf_attr attr; | ||
297 | |||
298 | bzero(&attr, sizeof(attr)); | ||
299 | attr.target_fd = target_fd; | ||
300 | attr.attach_bpf_fd = prog_fd; | ||
301 | attr.attach_type = type; | ||
302 | |||
303 | return sys_bpf(BPF_PROG_DETACH, &attr, sizeof(attr)); | ||
304 | } | ||
305 | |||
306 | int bpf_prog_query(int target_fd, enum bpf_attach_type type, __u32 query_flags, | ||
307 | __u32 *attach_flags, __u32 *prog_ids, __u32 *prog_cnt) | ||
308 | { | ||
309 | union bpf_attr attr; | ||
310 | int ret; | ||
311 | |||
312 | bzero(&attr, sizeof(attr)); | ||
313 | attr.query.target_fd = target_fd; | ||
314 | attr.query.attach_type = type; | ||
315 | attr.query.query_flags = query_flags; | ||
316 | attr.query.prog_cnt = *prog_cnt; | ||
317 | attr.query.prog_ids = ptr_to_u64(prog_ids); | ||
318 | |||
319 | ret = sys_bpf(BPF_PROG_QUERY, &attr, sizeof(attr)); | ||
320 | if (attach_flags) | ||
321 | *attach_flags = attr.query.attach_flags; | ||
322 | *prog_cnt = attr.query.prog_cnt; | ||
323 | return ret; | ||
324 | } | ||
325 | |||
263 | int bpf_prog_test_run(int prog_fd, int repeat, void *data, __u32 size, | 326 | int bpf_prog_test_run(int prog_fd, int repeat, void *data, __u32 size, |
264 | void *data_out, __u32 *size_out, __u32 *retval, | 327 | void *data_out, __u32 *size_out, __u32 *retval, |
265 | __u32 *duration) | 328 | __u32 *duration) |
diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index b8ea5843c39e..6534889e2b2f 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h | |||
@@ -24,19 +24,28 @@ | |||
24 | #include <linux/bpf.h> | 24 | #include <linux/bpf.h> |
25 | #include <stddef.h> | 25 | #include <stddef.h> |
26 | 26 | ||
27 | int bpf_create_map_node(enum bpf_map_type map_type, int key_size, | 27 | int bpf_create_map_node(enum bpf_map_type map_type, const char *name, |
28 | int value_size, int max_entries, __u32 map_flags, | 28 | int key_size, int value_size, int max_entries, |
29 | int node); | 29 | __u32 map_flags, int node); |
30 | int bpf_create_map_name(enum bpf_map_type map_type, const char *name, | ||
31 | int key_size, int value_size, int max_entries, | ||
32 | __u32 map_flags); | ||
30 | int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size, | 33 | int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size, |
31 | int max_entries, __u32 map_flags); | 34 | int max_entries, __u32 map_flags); |
32 | int bpf_create_map_in_map_node(enum bpf_map_type map_type, int key_size, | 35 | int bpf_create_map_in_map_node(enum bpf_map_type map_type, const char *name, |
33 | int inner_map_fd, int max_entries, | 36 | int key_size, int inner_map_fd, int max_entries, |
34 | __u32 map_flags, int node); | 37 | __u32 map_flags, int node); |
35 | int bpf_create_map_in_map(enum bpf_map_type map_type, int key_size, | 38 | int bpf_create_map_in_map(enum bpf_map_type map_type, const char *name, |
36 | int inner_map_fd, int max_entries, __u32 map_flags); | 39 | int key_size, int inner_map_fd, int max_entries, |
40 | __u32 map_flags); | ||
37 | 41 | ||
38 | /* Recommend log buffer size */ | 42 | /* Recommend log buffer size */ |
39 | #define BPF_LOG_BUF_SIZE 65536 | 43 | #define BPF_LOG_BUF_SIZE 65536 |
44 | int bpf_load_program_name(enum bpf_prog_type type, const char *name, | ||
45 | const struct bpf_insn *insns, | ||
46 | size_t insns_cnt, const char *license, | ||
47 | __u32 kern_version, char *log_buf, | ||
48 | size_t log_buf_sz); | ||
40 | int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns, | 49 | int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns, |
41 | size_t insns_cnt, const char *license, | 50 | size_t insns_cnt, const char *license, |
42 | __u32 kern_version, char *log_buf, | 51 | __u32 kern_version, char *log_buf, |
@@ -57,6 +66,7 @@ int bpf_obj_get(const char *pathname); | |||
57 | int bpf_prog_attach(int prog_fd, int attachable_fd, enum bpf_attach_type type, | 66 | int bpf_prog_attach(int prog_fd, int attachable_fd, enum bpf_attach_type type, |
58 | unsigned int flags); | 67 | unsigned int flags); |
59 | int bpf_prog_detach(int attachable_fd, enum bpf_attach_type type); | 68 | int bpf_prog_detach(int attachable_fd, enum bpf_attach_type type); |
69 | int bpf_prog_detach2(int prog_fd, int attachable_fd, enum bpf_attach_type type); | ||
60 | int bpf_prog_test_run(int prog_fd, int repeat, void *data, __u32 size, | 70 | int bpf_prog_test_run(int prog_fd, int repeat, void *data, __u32 size, |
61 | void *data_out, __u32 *size_out, __u32 *retval, | 71 | void *data_out, __u32 *size_out, __u32 *retval, |
62 | __u32 *duration); | 72 | __u32 *duration); |
@@ -65,5 +75,6 @@ int bpf_map_get_next_id(__u32 start_id, __u32 *next_id); | |||
65 | int bpf_prog_get_fd_by_id(__u32 id); | 75 | int bpf_prog_get_fd_by_id(__u32 id); |
66 | int bpf_map_get_fd_by_id(__u32 id); | 76 | int bpf_map_get_fd_by_id(__u32 id); |
67 | int bpf_obj_get_info_by_fd(int prog_fd, void *info, __u32 *info_len); | 77 | int bpf_obj_get_info_by_fd(int prog_fd, void *info, __u32 *info_len); |
68 | 78 | int bpf_prog_query(int target_fd, enum bpf_attach_type type, __u32 query_flags, | |
79 | __u32 *attach_flags, __u32 *prog_ids, __u32 *prog_cnt); | ||
69 | #endif | 80 | #endif |
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 35f6dfcdc565..5aa45f89da93 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c | |||
@@ -171,6 +171,7 @@ int libbpf_strerror(int err, char *buf, size_t size) | |||
171 | struct bpf_program { | 171 | struct bpf_program { |
172 | /* Index in elf obj file, for relocation use. */ | 172 | /* Index in elf obj file, for relocation use. */ |
173 | int idx; | 173 | int idx; |
174 | char *name; | ||
174 | char *section_name; | 175 | char *section_name; |
175 | struct bpf_insn *insns; | 176 | struct bpf_insn *insns; |
176 | size_t insns_cnt; | 177 | size_t insns_cnt; |
@@ -283,6 +284,7 @@ static void bpf_program__exit(struct bpf_program *prog) | |||
283 | prog->clear_priv = NULL; | 284 | prog->clear_priv = NULL; |
284 | 285 | ||
285 | bpf_program__unload(prog); | 286 | bpf_program__unload(prog); |
287 | zfree(&prog->name); | ||
286 | zfree(&prog->section_name); | 288 | zfree(&prog->section_name); |
287 | zfree(&prog->insns); | 289 | zfree(&prog->insns); |
288 | zfree(&prog->reloc_desc); | 290 | zfree(&prog->reloc_desc); |
@@ -293,26 +295,27 @@ static void bpf_program__exit(struct bpf_program *prog) | |||
293 | } | 295 | } |
294 | 296 | ||
295 | static int | 297 | static int |
296 | bpf_program__init(void *data, size_t size, char *name, int idx, | 298 | bpf_program__init(void *data, size_t size, char *section_name, int idx, |
297 | struct bpf_program *prog) | 299 | struct bpf_program *prog) |
298 | { | 300 | { |
299 | if (size < sizeof(struct bpf_insn)) { | 301 | if (size < sizeof(struct bpf_insn)) { |
300 | pr_warning("corrupted section '%s'\n", name); | 302 | pr_warning("corrupted section '%s'\n", section_name); |
301 | return -EINVAL; | 303 | return -EINVAL; |
302 | } | 304 | } |
303 | 305 | ||
304 | bzero(prog, sizeof(*prog)); | 306 | bzero(prog, sizeof(*prog)); |
305 | 307 | ||
306 | prog->section_name = strdup(name); | 308 | prog->section_name = strdup(section_name); |
307 | if (!prog->section_name) { | 309 | if (!prog->section_name) { |
308 | pr_warning("failed to alloc name for prog %s\n", | 310 | pr_warning("failed to alloc name for prog under section %s\n", |
309 | name); | 311 | section_name); |
310 | goto errout; | 312 | goto errout; |
311 | } | 313 | } |
312 | 314 | ||
313 | prog->insns = malloc(size); | 315 | prog->insns = malloc(size); |
314 | if (!prog->insns) { | 316 | if (!prog->insns) { |
315 | pr_warning("failed to alloc insns for %s\n", name); | 317 | pr_warning("failed to alloc insns for prog under section %s\n", |
318 | section_name); | ||
316 | goto errout; | 319 | goto errout; |
317 | } | 320 | } |
318 | prog->insns_cnt = size / sizeof(struct bpf_insn); | 321 | prog->insns_cnt = size / sizeof(struct bpf_insn); |
@@ -331,12 +334,12 @@ errout: | |||
331 | 334 | ||
332 | static int | 335 | static int |
333 | bpf_object__add_program(struct bpf_object *obj, void *data, size_t size, | 336 | bpf_object__add_program(struct bpf_object *obj, void *data, size_t size, |
334 | char *name, int idx) | 337 | char *section_name, int idx) |
335 | { | 338 | { |
336 | struct bpf_program prog, *progs; | 339 | struct bpf_program prog, *progs; |
337 | int nr_progs, err; | 340 | int nr_progs, err; |
338 | 341 | ||
339 | err = bpf_program__init(data, size, name, idx, &prog); | 342 | err = bpf_program__init(data, size, section_name, idx, &prog); |
340 | if (err) | 343 | if (err) |
341 | return err; | 344 | return err; |
342 | 345 | ||
@@ -350,8 +353,8 @@ bpf_object__add_program(struct bpf_object *obj, void *data, size_t size, | |||
350 | * is still valid, so don't need special treat for | 353 | * is still valid, so don't need special treat for |
351 | * bpf_close_object(). | 354 | * bpf_close_object(). |
352 | */ | 355 | */ |
353 | pr_warning("failed to alloc a new program '%s'\n", | 356 | pr_warning("failed to alloc a new program under section '%s'\n", |
354 | name); | 357 | section_name); |
355 | bpf_program__exit(&prog); | 358 | bpf_program__exit(&prog); |
356 | return -ENOMEM; | 359 | return -ENOMEM; |
357 | } | 360 | } |
@@ -364,6 +367,54 @@ bpf_object__add_program(struct bpf_object *obj, void *data, size_t size, | |||
364 | return 0; | 367 | return 0; |
365 | } | 368 | } |
366 | 369 | ||
370 | static int | ||
371 | bpf_object__init_prog_names(struct bpf_object *obj) | ||
372 | { | ||
373 | Elf_Data *symbols = obj->efile.symbols; | ||
374 | struct bpf_program *prog; | ||
375 | size_t pi, si; | ||
376 | |||
377 | for (pi = 0; pi < obj->nr_programs; pi++) { | ||
378 | char *name = NULL; | ||
379 | |||
380 | prog = &obj->programs[pi]; | ||
381 | |||
382 | for (si = 0; si < symbols->d_size / sizeof(GElf_Sym) && !name; | ||
383 | si++) { | ||
384 | GElf_Sym sym; | ||
385 | |||
386 | if (!gelf_getsym(symbols, si, &sym)) | ||
387 | continue; | ||
388 | if (sym.st_shndx != prog->idx) | ||
389 | continue; | ||
390 | |||
391 | name = elf_strptr(obj->efile.elf, | ||
392 | obj->efile.strtabidx, | ||
393 | sym.st_name); | ||
394 | if (!name) { | ||
395 | pr_warning("failed to get sym name string for prog %s\n", | ||
396 | prog->section_name); | ||
397 | return -LIBBPF_ERRNO__LIBELF; | ||
398 | } | ||
399 | } | ||
400 | |||
401 | if (!name) { | ||
402 | pr_warning("failed to find sym for prog %s\n", | ||
403 | prog->section_name); | ||
404 | return -EINVAL; | ||
405 | } | ||
406 | |||
407 | prog->name = strdup(name); | ||
408 | if (!prog->name) { | ||
409 | pr_warning("failed to allocate memory for prog sym %s\n", | ||
410 | name); | ||
411 | return -ENOMEM; | ||
412 | } | ||
413 | } | ||
414 | |||
415 | return 0; | ||
416 | } | ||
417 | |||
367 | static struct bpf_object *bpf_object__new(const char *path, | 418 | static struct bpf_object *bpf_object__new(const char *path, |
368 | void *obj_buf, | 419 | void *obj_buf, |
369 | size_t obj_buf_sz) | 420 | size_t obj_buf_sz) |
@@ -528,31 +579,6 @@ bpf_object__init_kversion(struct bpf_object *obj, | |||
528 | return 0; | 579 | return 0; |
529 | } | 580 | } |
530 | 581 | ||
531 | static int | ||
532 | bpf_object__validate_maps(struct bpf_object *obj) | ||
533 | { | ||
534 | int i; | ||
535 | |||
536 | /* | ||
537 | * If there's only 1 map, the only error case should have been | ||
538 | * catched in bpf_object__init_maps(). | ||
539 | */ | ||
540 | if (!obj->maps || !obj->nr_maps || (obj->nr_maps == 1)) | ||
541 | return 0; | ||
542 | |||
543 | for (i = 1; i < obj->nr_maps; i++) { | ||
544 | const struct bpf_map *a = &obj->maps[i - 1]; | ||
545 | const struct bpf_map *b = &obj->maps[i]; | ||
546 | |||
547 | if (b->offset - a->offset < sizeof(struct bpf_map_def)) { | ||
548 | pr_warning("corrupted map section in %s: map \"%s\" too small\n", | ||
549 | obj->path, a->name); | ||
550 | return -EINVAL; | ||
551 | } | ||
552 | } | ||
553 | return 0; | ||
554 | } | ||
555 | |||
556 | static int compare_bpf_map(const void *_a, const void *_b) | 582 | static int compare_bpf_map(const void *_a, const void *_b) |
557 | { | 583 | { |
558 | const struct bpf_map *a = _a; | 584 | const struct bpf_map *a = _a; |
@@ -564,7 +590,7 @@ static int compare_bpf_map(const void *_a, const void *_b) | |||
564 | static int | 590 | static int |
565 | bpf_object__init_maps(struct bpf_object *obj) | 591 | bpf_object__init_maps(struct bpf_object *obj) |
566 | { | 592 | { |
567 | int i, map_idx, nr_maps = 0; | 593 | int i, map_idx, map_def_sz, nr_maps = 0; |
568 | Elf_Scn *scn; | 594 | Elf_Scn *scn; |
569 | Elf_Data *data; | 595 | Elf_Data *data; |
570 | Elf_Data *symbols = obj->efile.symbols; | 596 | Elf_Data *symbols = obj->efile.symbols; |
@@ -607,6 +633,15 @@ bpf_object__init_maps(struct bpf_object *obj) | |||
607 | if (!nr_maps) | 633 | if (!nr_maps) |
608 | return 0; | 634 | return 0; |
609 | 635 | ||
636 | /* Assume equally sized map definitions */ | ||
637 | map_def_sz = data->d_size / nr_maps; | ||
638 | if (!data->d_size || (data->d_size % nr_maps) != 0) { | ||
639 | pr_warning("unable to determine map definition size " | ||
640 | "section %s, %d maps in %zd bytes\n", | ||
641 | obj->path, nr_maps, data->d_size); | ||
642 | return -EINVAL; | ||
643 | } | ||
644 | |||
610 | obj->maps = calloc(nr_maps, sizeof(obj->maps[0])); | 645 | obj->maps = calloc(nr_maps, sizeof(obj->maps[0])); |
611 | if (!obj->maps) { | 646 | if (!obj->maps) { |
612 | pr_warning("alloc maps for object failed\n"); | 647 | pr_warning("alloc maps for object failed\n"); |
@@ -639,7 +674,7 @@ bpf_object__init_maps(struct bpf_object *obj) | |||
639 | obj->efile.strtabidx, | 674 | obj->efile.strtabidx, |
640 | sym.st_name); | 675 | sym.st_name); |
641 | obj->maps[map_idx].offset = sym.st_value; | 676 | obj->maps[map_idx].offset = sym.st_value; |
642 | if (sym.st_value + sizeof(struct bpf_map_def) > data->d_size) { | 677 | if (sym.st_value + map_def_sz > data->d_size) { |
643 | pr_warning("corrupted maps section in %s: last map \"%s\" too small\n", | 678 | pr_warning("corrupted maps section in %s: last map \"%s\" too small\n", |
644 | obj->path, map_name); | 679 | obj->path, map_name); |
645 | return -EINVAL; | 680 | return -EINVAL; |
@@ -653,12 +688,40 @@ bpf_object__init_maps(struct bpf_object *obj) | |||
653 | pr_debug("map %d is \"%s\"\n", map_idx, | 688 | pr_debug("map %d is \"%s\"\n", map_idx, |
654 | obj->maps[map_idx].name); | 689 | obj->maps[map_idx].name); |
655 | def = (struct bpf_map_def *)(data->d_buf + sym.st_value); | 690 | def = (struct bpf_map_def *)(data->d_buf + sym.st_value); |
656 | obj->maps[map_idx].def = *def; | 691 | /* |
692 | * If the definition of the map in the object file fits in | ||
693 | * bpf_map_def, copy it. Any extra fields in our version | ||
694 | * of bpf_map_def will default to zero as a result of the | ||
695 | * calloc above. | ||
696 | */ | ||
697 | if (map_def_sz <= sizeof(struct bpf_map_def)) { | ||
698 | memcpy(&obj->maps[map_idx].def, def, map_def_sz); | ||
699 | } else { | ||
700 | /* | ||
701 | * Here the map structure being read is bigger than what | ||
702 | * we expect, truncate if the excess bits are all zero. | ||
703 | * If they are not zero, reject this map as | ||
704 | * incompatible. | ||
705 | */ | ||
706 | char *b; | ||
707 | for (b = ((char *)def) + sizeof(struct bpf_map_def); | ||
708 | b < ((char *)def) + map_def_sz; b++) { | ||
709 | if (*b != 0) { | ||
710 | pr_warning("maps section in %s: \"%s\" " | ||
711 | "has unrecognized, non-zero " | ||
712 | "options\n", | ||
713 | obj->path, map_name); | ||
714 | return -EINVAL; | ||
715 | } | ||
716 | } | ||
717 | memcpy(&obj->maps[map_idx].def, def, | ||
718 | sizeof(struct bpf_map_def)); | ||
719 | } | ||
657 | map_idx++; | 720 | map_idx++; |
658 | } | 721 | } |
659 | 722 | ||
660 | qsort(obj->maps, obj->nr_maps, sizeof(obj->maps[0]), compare_bpf_map); | 723 | qsort(obj->maps, obj->nr_maps, sizeof(obj->maps[0]), compare_bpf_map); |
661 | return bpf_object__validate_maps(obj); | 724 | return 0; |
662 | } | 725 | } |
663 | 726 | ||
664 | static int bpf_object__elf_collect(struct bpf_object *obj) | 727 | static int bpf_object__elf_collect(struct bpf_object *obj) |
@@ -766,8 +829,12 @@ static int bpf_object__elf_collect(struct bpf_object *obj) | |||
766 | pr_warning("Corrupted ELF file: index of strtab invalid\n"); | 829 | pr_warning("Corrupted ELF file: index of strtab invalid\n"); |
767 | return LIBBPF_ERRNO__FORMAT; | 830 | return LIBBPF_ERRNO__FORMAT; |
768 | } | 831 | } |
769 | if (obj->efile.maps_shndx >= 0) | 832 | if (obj->efile.maps_shndx >= 0) { |
770 | err = bpf_object__init_maps(obj); | 833 | err = bpf_object__init_maps(obj); |
834 | if (err) | ||
835 | goto out; | ||
836 | } | ||
837 | err = bpf_object__init_prog_names(obj); | ||
771 | out: | 838 | out: |
772 | return err; | 839 | return err; |
773 | } | 840 | } |
@@ -870,11 +937,12 @@ bpf_object__create_maps(struct bpf_object *obj) | |||
870 | struct bpf_map_def *def = &obj->maps[i].def; | 937 | struct bpf_map_def *def = &obj->maps[i].def; |
871 | int *pfd = &obj->maps[i].fd; | 938 | int *pfd = &obj->maps[i].fd; |
872 | 939 | ||
873 | *pfd = bpf_create_map(def->type, | 940 | *pfd = bpf_create_map_name(def->type, |
874 | def->key_size, | 941 | obj->maps[i].name, |
875 | def->value_size, | 942 | def->key_size, |
876 | def->max_entries, | 943 | def->value_size, |
877 | 0); | 944 | def->max_entries, |
945 | def->map_flags); | ||
878 | if (*pfd < 0) { | 946 | if (*pfd < 0) { |
879 | size_t j; | 947 | size_t j; |
880 | int err = *pfd; | 948 | int err = *pfd; |
@@ -982,7 +1050,7 @@ static int bpf_object__collect_reloc(struct bpf_object *obj) | |||
982 | } | 1050 | } |
983 | 1051 | ||
984 | static int | 1052 | static int |
985 | load_program(enum bpf_prog_type type, struct bpf_insn *insns, | 1053 | load_program(enum bpf_prog_type type, const char *name, struct bpf_insn *insns, |
986 | int insns_cnt, char *license, u32 kern_version, int *pfd) | 1054 | int insns_cnt, char *license, u32 kern_version, int *pfd) |
987 | { | 1055 | { |
988 | int ret; | 1056 | int ret; |
@@ -995,8 +1063,8 @@ load_program(enum bpf_prog_type type, struct bpf_insn *insns, | |||
995 | if (!log_buf) | 1063 | if (!log_buf) |
996 | pr_warning("Alloc log buffer for bpf loader error, continue without log\n"); | 1064 | pr_warning("Alloc log buffer for bpf loader error, continue without log\n"); |
997 | 1065 | ||
998 | ret = bpf_load_program(type, insns, insns_cnt, license, | 1066 | ret = bpf_load_program_name(type, name, insns, insns_cnt, license, |
999 | kern_version, log_buf, BPF_LOG_BUF_SIZE); | 1067 | kern_version, log_buf, BPF_LOG_BUF_SIZE); |
1000 | 1068 | ||
1001 | if (ret >= 0) { | 1069 | if (ret >= 0) { |
1002 | *pfd = ret; | 1070 | *pfd = ret; |
@@ -1021,9 +1089,9 @@ load_program(enum bpf_prog_type type, struct bpf_insn *insns, | |||
1021 | if (type != BPF_PROG_TYPE_KPROBE) { | 1089 | if (type != BPF_PROG_TYPE_KPROBE) { |
1022 | int fd; | 1090 | int fd; |
1023 | 1091 | ||
1024 | fd = bpf_load_program(BPF_PROG_TYPE_KPROBE, insns, | 1092 | fd = bpf_load_program_name(BPF_PROG_TYPE_KPROBE, name, |
1025 | insns_cnt, license, kern_version, | 1093 | insns, insns_cnt, license, |
1026 | NULL, 0); | 1094 | kern_version, NULL, 0); |
1027 | if (fd >= 0) { | 1095 | if (fd >= 0) { |
1028 | close(fd); | 1096 | close(fd); |
1029 | ret = -LIBBPF_ERRNO__PROGTYPE; | 1097 | ret = -LIBBPF_ERRNO__PROGTYPE; |
@@ -1067,8 +1135,8 @@ bpf_program__load(struct bpf_program *prog, | |||
1067 | pr_warning("Program '%s' is inconsistent: nr(%d) != 1\n", | 1135 | pr_warning("Program '%s' is inconsistent: nr(%d) != 1\n", |
1068 | prog->section_name, prog->instances.nr); | 1136 | prog->section_name, prog->instances.nr); |
1069 | } | 1137 | } |
1070 | err = load_program(prog->type, prog->insns, prog->insns_cnt, | 1138 | err = load_program(prog->type, prog->name, prog->insns, |
1071 | license, kern_version, &fd); | 1139 | prog->insns_cnt, license, kern_version, &fd); |
1072 | if (!err) | 1140 | if (!err) |
1073 | prog->instances.fds[0] = fd; | 1141 | prog->instances.fds[0] = fd; |
1074 | goto out; | 1142 | goto out; |
@@ -1096,7 +1164,8 @@ bpf_program__load(struct bpf_program *prog, | |||
1096 | continue; | 1164 | continue; |
1097 | } | 1165 | } |
1098 | 1166 | ||
1099 | err = load_program(prog->type, result.new_insn_ptr, | 1167 | err = load_program(prog->type, prog->name, |
1168 | result.new_insn_ptr, | ||
1100 | result.new_insn_cnt, | 1169 | result.new_insn_cnt, |
1101 | license, kern_version, &fd); | 1170 | license, kern_version, &fd); |
1102 | 1171 | ||
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 7959086eb9c9..6e20003109e0 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h | |||
@@ -207,6 +207,7 @@ struct bpf_map_def { | |||
207 | unsigned int key_size; | 207 | unsigned int key_size; |
208 | unsigned int value_size; | 208 | unsigned int value_size; |
209 | unsigned int max_entries; | 209 | unsigned int max_entries; |
210 | unsigned int map_flags; | ||
210 | }; | 211 | }; |
211 | 212 | ||
212 | /* | 213 | /* |
diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c index 7c214ceb9386..315df0a70265 100644 --- a/tools/lib/traceevent/parse-filter.c +++ b/tools/lib/traceevent/parse-filter.c | |||
@@ -436,13 +436,13 @@ create_arg_exp(enum filter_exp_type etype) | |||
436 | return NULL; | 436 | return NULL; |
437 | 437 | ||
438 | arg->type = FILTER_ARG_EXP; | 438 | arg->type = FILTER_ARG_EXP; |
439 | arg->op.type = etype; | 439 | arg->exp.type = etype; |
440 | 440 | ||
441 | return arg; | 441 | return arg; |
442 | } | 442 | } |
443 | 443 | ||
444 | static struct filter_arg * | 444 | static struct filter_arg * |
445 | create_arg_cmp(enum filter_exp_type etype) | 445 | create_arg_cmp(enum filter_cmp_type ctype) |
446 | { | 446 | { |
447 | struct filter_arg *arg; | 447 | struct filter_arg *arg; |
448 | 448 | ||
@@ -452,7 +452,7 @@ create_arg_cmp(enum filter_exp_type etype) | |||
452 | 452 | ||
453 | /* Use NUM and change if necessary */ | 453 | /* Use NUM and change if necessary */ |
454 | arg->type = FILTER_ARG_NUM; | 454 | arg->type = FILTER_ARG_NUM; |
455 | arg->op.type = etype; | 455 | arg->num.type = ctype; |
456 | 456 | ||
457 | return arg; | 457 | return arg; |
458 | } | 458 | } |
diff --git a/tools/objtool/.gitignore b/tools/objtool/.gitignore index d3102c865a95..914cff12899b 100644 --- a/tools/objtool/.gitignore +++ b/tools/objtool/.gitignore | |||
@@ -1,3 +1,3 @@ | |||
1 | arch/x86/insn/inat-tables.c | 1 | arch/x86/lib/inat-tables.c |
2 | objtool | 2 | objtool |
3 | fixdep | 3 | fixdep |
diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile index 424b1965d06f..0f94af3ccaaa 100644 --- a/tools/objtool/Makefile +++ b/tools/objtool/Makefile | |||
@@ -25,7 +25,9 @@ OBJTOOL_IN := $(OBJTOOL)-in.o | |||
25 | 25 | ||
26 | all: $(OBJTOOL) | 26 | all: $(OBJTOOL) |
27 | 27 | ||
28 | INCLUDES := -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(HOSTARCH)/include/uapi | 28 | INCLUDES := -I$(srctree)/tools/include \ |
29 | -I$(srctree)/tools/arch/$(HOSTARCH)/include/uapi \ | ||
30 | -I$(srctree)/tools/objtool/arch/$(ARCH)/include | ||
29 | WARNINGS := $(EXTRA_WARNINGS) -Wno-switch-default -Wno-switch-enum -Wno-packed | 31 | WARNINGS := $(EXTRA_WARNINGS) -Wno-switch-default -Wno-switch-enum -Wno-packed |
30 | CFLAGS += -Wall -Werror $(WARNINGS) -fomit-frame-pointer -O2 -g $(INCLUDES) | 32 | CFLAGS += -Wall -Werror $(WARNINGS) -fomit-frame-pointer -O2 -g $(INCLUDES) |
31 | LDFLAGS += -lelf $(LIBSUBCMD) | 33 | LDFLAGS += -lelf $(LIBSUBCMD) |
@@ -41,22 +43,8 @@ include $(srctree)/tools/build/Makefile.include | |||
41 | $(OBJTOOL_IN): fixdep FORCE | 43 | $(OBJTOOL_IN): fixdep FORCE |
42 | @$(MAKE) $(build)=objtool | 44 | @$(MAKE) $(build)=objtool |
43 | 45 | ||
44 | # Busybox's diff doesn't have -I, avoid warning in that case | ||
45 | # | ||
46 | $(OBJTOOL): $(LIBSUBCMD) $(OBJTOOL_IN) | 46 | $(OBJTOOL): $(LIBSUBCMD) $(OBJTOOL_IN) |
47 | @(diff -I 2>&1 | grep -q 'option requires an argument' && \ | 47 | @./sync-check.sh |
48 | test -d ../../kernel -a -d ../../tools -a -d ../objtool && (( \ | ||
49 | diff -I'^#include' arch/x86/insn/insn.c ../../arch/x86/lib/insn.c >/dev/null && \ | ||
50 | diff -I'^#include' arch/x86/insn/inat.c ../../arch/x86/lib/inat.c >/dev/null && \ | ||
51 | diff arch/x86/insn/x86-opcode-map.txt ../../arch/x86/lib/x86-opcode-map.txt >/dev/null && \ | ||
52 | diff arch/x86/insn/gen-insn-attr-x86.awk ../../arch/x86/tools/gen-insn-attr-x86.awk >/dev/null && \ | ||
53 | diff -I'^#include' arch/x86/insn/insn.h ../../arch/x86/include/asm/insn.h >/dev/null && \ | ||
54 | diff -I'^#include' arch/x86/insn/inat.h ../../arch/x86/include/asm/inat.h >/dev/null && \ | ||
55 | diff -I'^#include' arch/x86/insn/inat_types.h ../../arch/x86/include/asm/inat_types.h >/dev/null) \ | ||
56 | || echo "warning: objtool: x86 instruction decoder differs from kernel" >&2 )) || true | ||
57 | @(test -d ../../kernel -a -d ../../tools -a -d ../objtool && (( \ | ||
58 | diff ../../arch/x86/include/asm/orc_types.h orc_types.h >/dev/null) \ | ||
59 | || echo "warning: objtool: orc_types.h differs from kernel" >&2 )) || true | ||
60 | $(QUIET_LINK)$(CC) $(OBJTOOL_IN) $(LDFLAGS) -o $@ | 48 | $(QUIET_LINK)$(CC) $(OBJTOOL_IN) $(LDFLAGS) -o $@ |
61 | 49 | ||
62 | 50 | ||
@@ -66,7 +54,7 @@ $(LIBSUBCMD): fixdep FORCE | |||
66 | clean: | 54 | clean: |
67 | $(call QUIET_CLEAN, objtool) $(RM) $(OBJTOOL) | 55 | $(call QUIET_CLEAN, objtool) $(RM) $(OBJTOOL) |
68 | $(Q)find $(OUTPUT) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete | 56 | $(Q)find $(OUTPUT) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete |
69 | $(Q)$(RM) $(OUTPUT)arch/x86/insn/inat-tables.c $(OUTPUT)fixdep | 57 | $(Q)$(RM) $(OUTPUT)arch/x86/lib/inat-tables.c $(OUTPUT)fixdep |
70 | 58 | ||
71 | FORCE: | 59 | FORCE: |
72 | 60 | ||
diff --git a/tools/objtool/arch/x86/Build b/tools/objtool/arch/x86/Build index debbdb0b5c43..b998412c017d 100644 --- a/tools/objtool/arch/x86/Build +++ b/tools/objtool/arch/x86/Build | |||
@@ -1,12 +1,12 @@ | |||
1 | objtool-y += decode.o | 1 | objtool-y += decode.o |
2 | 2 | ||
3 | inat_tables_script = arch/x86/insn/gen-insn-attr-x86.awk | 3 | inat_tables_script = arch/x86/tools/gen-insn-attr-x86.awk |
4 | inat_tables_maps = arch/x86/insn/x86-opcode-map.txt | 4 | inat_tables_maps = arch/x86/lib/x86-opcode-map.txt |
5 | 5 | ||
6 | $(OUTPUT)arch/x86/insn/inat-tables.c: $(inat_tables_script) $(inat_tables_maps) | 6 | $(OUTPUT)arch/x86/lib/inat-tables.c: $(inat_tables_script) $(inat_tables_maps) |
7 | $(call rule_mkdir) | 7 | $(call rule_mkdir) |
8 | $(Q)$(call echo-cmd,gen)$(AWK) -f $(inat_tables_script) $(inat_tables_maps) > $@ | 8 | $(Q)$(call echo-cmd,gen)$(AWK) -f $(inat_tables_script) $(inat_tables_maps) > $@ |
9 | 9 | ||
10 | $(OUTPUT)arch/x86/decode.o: $(OUTPUT)arch/x86/insn/inat-tables.c | 10 | $(OUTPUT)arch/x86/decode.o: $(OUTPUT)arch/x86/lib/inat-tables.c |
11 | 11 | ||
12 | CFLAGS_decode.o += -I$(OUTPUT)arch/x86/insn | 12 | CFLAGS_decode.o += -I$(OUTPUT)arch/x86/lib |
diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c index 34a579f806e3..8acfc47af70e 100644 --- a/tools/objtool/arch/x86/decode.c +++ b/tools/objtool/arch/x86/decode.c | |||
@@ -19,9 +19,9 @@ | |||
19 | #include <stdlib.h> | 19 | #include <stdlib.h> |
20 | 20 | ||
21 | #define unlikely(cond) (cond) | 21 | #define unlikely(cond) (cond) |
22 | #include "insn/insn.h" | 22 | #include <asm/insn.h> |
23 | #include "insn/inat.c" | 23 | #include "lib/inat.c" |
24 | #include "insn/insn.c" | 24 | #include "lib/insn.c" |
25 | 25 | ||
26 | #include "../../elf.h" | 26 | #include "../../elf.h" |
27 | #include "../../arch.h" | 27 | #include "../../arch.h" |
diff --git a/tools/objtool/arch/x86/insn/inat.h b/tools/objtool/arch/x86/include/asm/inat.h index 125ecd2a300d..1c78580e58be 100644 --- a/tools/objtool/arch/x86/insn/inat.h +++ b/tools/objtool/arch/x86/include/asm/inat.h | |||
@@ -20,7 +20,7 @@ | |||
20 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | 20 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | #include "inat_types.h" | 23 | #include <asm/inat_types.h> |
24 | 24 | ||
25 | /* | 25 | /* |
26 | * Internal bits. Don't use bitmasks directly, because these bits are | 26 | * Internal bits. Don't use bitmasks directly, because these bits are |
@@ -97,6 +97,16 @@ | |||
97 | #define INAT_MAKE_GROUP(grp) ((grp << INAT_GRP_OFFS) | INAT_MODRM) | 97 | #define INAT_MAKE_GROUP(grp) ((grp << INAT_GRP_OFFS) | INAT_MODRM) |
98 | #define INAT_MAKE_IMM(imm) (imm << INAT_IMM_OFFS) | 98 | #define INAT_MAKE_IMM(imm) (imm << INAT_IMM_OFFS) |
99 | 99 | ||
100 | /* Identifiers for segment registers */ | ||
101 | #define INAT_SEG_REG_IGNORE 0 | ||
102 | #define INAT_SEG_REG_DEFAULT 1 | ||
103 | #define INAT_SEG_REG_CS 2 | ||
104 | #define INAT_SEG_REG_SS 3 | ||
105 | #define INAT_SEG_REG_DS 4 | ||
106 | #define INAT_SEG_REG_ES 5 | ||
107 | #define INAT_SEG_REG_FS 6 | ||
108 | #define INAT_SEG_REG_GS 7 | ||
109 | |||
100 | /* Attribute search APIs */ | 110 | /* Attribute search APIs */ |
101 | extern insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode); | 111 | extern insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode); |
102 | extern int inat_get_last_prefix_id(insn_byte_t last_pfx); | 112 | extern int inat_get_last_prefix_id(insn_byte_t last_pfx); |
diff --git a/tools/objtool/arch/x86/insn/inat_types.h b/tools/objtool/arch/x86/include/asm/inat_types.h index cb3c20ce39cf..cb3c20ce39cf 100644 --- a/tools/objtool/arch/x86/insn/inat_types.h +++ b/tools/objtool/arch/x86/include/asm/inat_types.h | |||
diff --git a/tools/objtool/arch/x86/insn/insn.h b/tools/objtool/arch/x86/include/asm/insn.h index e23578c7b1be..b3e32b010ab1 100644 --- a/tools/objtool/arch/x86/insn/insn.h +++ b/tools/objtool/arch/x86/include/asm/insn.h | |||
@@ -21,7 +21,7 @@ | |||
21 | */ | 21 | */ |
22 | 22 | ||
23 | /* insn_attr_t is defined in inat.h */ | 23 | /* insn_attr_t is defined in inat.h */ |
24 | #include "inat.h" | 24 | #include <asm/inat.h> |
25 | 25 | ||
26 | struct insn_field { | 26 | struct insn_field { |
27 | union { | 27 | union { |
diff --git a/tools/objtool/orc_types.h b/tools/objtool/arch/x86/include/asm/orc_types.h index 9c9dc579bd7d..9c9dc579bd7d 100644 --- a/tools/objtool/orc_types.h +++ b/tools/objtool/arch/x86/include/asm/orc_types.h | |||
diff --git a/tools/objtool/arch/x86/insn/inat.c b/tools/objtool/arch/x86/lib/inat.c index e4bf28e6f4c7..c1f01a8e9f65 100644 --- a/tools/objtool/arch/x86/insn/inat.c +++ b/tools/objtool/arch/x86/lib/inat.c | |||
@@ -18,7 +18,7 @@ | |||
18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | #include "insn.h" | 21 | #include <asm/insn.h> |
22 | 22 | ||
23 | /* Attribute tables are generated from opcode map */ | 23 | /* Attribute tables are generated from opcode map */ |
24 | #include "inat-tables.c" | 24 | #include "inat-tables.c" |
diff --git a/tools/objtool/arch/x86/insn/insn.c b/tools/objtool/arch/x86/lib/insn.c index ca983e2bea8b..1088eb8f3a5f 100644 --- a/tools/objtool/arch/x86/insn/insn.c +++ b/tools/objtool/arch/x86/lib/insn.c | |||
@@ -23,8 +23,8 @@ | |||
23 | #else | 23 | #else |
24 | #include <string.h> | 24 | #include <string.h> |
25 | #endif | 25 | #endif |
26 | #include "inat.h" | 26 | #include <asm/inat.h> |
27 | #include "insn.h" | 27 | #include <asm/insn.h> |
28 | 28 | ||
29 | /* Verify next sizeof(t) bytes can be on the same instruction */ | 29 | /* Verify next sizeof(t) bytes can be on the same instruction */ |
30 | #define validate_next(t, insn, n) \ | 30 | #define validate_next(t, insn, n) \ |
diff --git a/tools/objtool/arch/x86/insn/x86-opcode-map.txt b/tools/objtool/arch/x86/lib/x86-opcode-map.txt index 12e377184ee4..12e377184ee4 100644 --- a/tools/objtool/arch/x86/insn/x86-opcode-map.txt +++ b/tools/objtool/arch/x86/lib/x86-opcode-map.txt | |||
diff --git a/tools/objtool/arch/x86/insn/gen-insn-attr-x86.awk b/tools/objtool/arch/x86/tools/gen-insn-attr-x86.awk index b02a36b2c14f..b02a36b2c14f 100644 --- a/tools/objtool/arch/x86/insn/gen-insn-attr-x86.awk +++ b/tools/objtool/arch/x86/tools/gen-insn-attr-x86.awk | |||
diff --git a/tools/objtool/orc.h b/tools/objtool/orc.h index a4139e386ef3..b0e92a6d0903 100644 --- a/tools/objtool/orc.h +++ b/tools/objtool/orc.h | |||
@@ -18,7 +18,7 @@ | |||
18 | #ifndef _ORC_H | 18 | #ifndef _ORC_H |
19 | #define _ORC_H | 19 | #define _ORC_H |
20 | 20 | ||
21 | #include "orc_types.h" | 21 | #include <asm/orc_types.h> |
22 | 22 | ||
23 | struct objtool_file; | 23 | struct objtool_file; |
24 | 24 | ||
diff --git a/tools/objtool/sync-check.sh b/tools/objtool/sync-check.sh new file mode 100755 index 000000000000..1470e74e9d66 --- /dev/null +++ b/tools/objtool/sync-check.sh | |||
@@ -0,0 +1,29 @@ | |||
1 | #!/bin/sh | ||
2 | # SPDX-License-Identifier: GPL-2.0 | ||
3 | |||
4 | FILES=' | ||
5 | arch/x86/lib/insn.c | ||
6 | arch/x86/lib/inat.c | ||
7 | arch/x86/lib/x86-opcode-map.txt | ||
8 | arch/x86/tools/gen-insn-attr-x86.awk | ||
9 | arch/x86/include/asm/insn.h | ||
10 | arch/x86/include/asm/inat.h | ||
11 | arch/x86/include/asm/inat_types.h | ||
12 | arch/x86/include/asm/orc_types.h | ||
13 | ' | ||
14 | |||
15 | check() | ||
16 | { | ||
17 | local file=$1 | ||
18 | |||
19 | diff $file ../../$file > /dev/null || | ||
20 | echo "Warning: synced file at 'tools/objtool/$file' differs from latest kernel version at '$file'" | ||
21 | } | ||
22 | |||
23 | if [ ! -d ../../kernel ] || [ ! -d ../../tools ] || [ ! -d ../objtool ]; then | ||
24 | exit 0 | ||
25 | fi | ||
26 | |||
27 | for i in $FILES; do | ||
28 | check $i | ||
29 | done | ||
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index 63f534a0902f..ed65e82f034e 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config | |||
@@ -53,6 +53,10 @@ ifeq ($(SRCARCH),arm64) | |||
53 | LIBUNWIND_LIBS = -lunwind -lunwind-aarch64 | 53 | LIBUNWIND_LIBS = -lunwind -lunwind-aarch64 |
54 | endif | 54 | endif |
55 | 55 | ||
56 | ifeq ($(ARCH),s390) | ||
57 | NO_PERF_REGS := 0 | ||
58 | endif | ||
59 | |||
56 | ifeq ($(NO_PERF_REGS),0) | 60 | ifeq ($(NO_PERF_REGS),0) |
57 | $(call detected,CONFIG_PERF_REGS) | 61 | $(call detected,CONFIG_PERF_REGS) |
58 | endif | 62 | endif |
@@ -61,7 +65,7 @@ endif | |||
61 | # Disable it on all other architectures in case libdw unwind | 65 | # Disable it on all other architectures in case libdw unwind |
62 | # support is detected in system. Add supported architectures | 66 | # support is detected in system. Add supported architectures |
63 | # to the check. | 67 | # to the check. |
64 | ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm powerpc)) | 68 | ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm powerpc s390)) |
65 | NO_LIBDW_DWARF_UNWIND := 1 | 69 | NO_LIBDW_DWARF_UNWIND := 1 |
66 | endif | 70 | endif |
67 | 71 | ||
diff --git a/tools/perf/arch/s390/include/dwarf-regs-table.h b/tools/perf/arch/s390/include/dwarf-regs-table.h index 792d4c277225..671553525f41 100644 --- a/tools/perf/arch/s390/include/dwarf-regs-table.h +++ b/tools/perf/arch/s390/include/dwarf-regs-table.h | |||
@@ -1,9 +1,72 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | #ifdef DEFINE_DWARF_REGSTR_TABLE | 2 | #ifndef S390_DWARF_REGS_TABLE_H |
3 | /* This is included in perf/util/dwarf-regs.c */ | 3 | #define S390_DWARF_REGS_TABLE_H |
4 | 4 | ||
5 | static const char * const s390_regstr_tbl[] = { | 5 | #define REG_DWARFNUM_NAME(reg, idx) [idx] = "%" #reg |
6 | |||
7 | /* | ||
8 | * For reference, see DWARF register mapping: | ||
9 | * http://refspecs.linuxfoundation.org/ELF/zSeries/lzsabi0_s390/x1542.html | ||
10 | */ | ||
11 | static const char * const s390_dwarf_regs[] = { | ||
6 | "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7", | 12 | "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7", |
7 | "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", | 13 | "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", |
14 | REG_DWARFNUM_NAME(f0, 16), | ||
15 | REG_DWARFNUM_NAME(f1, 20), | ||
16 | REG_DWARFNUM_NAME(f2, 17), | ||
17 | REG_DWARFNUM_NAME(f3, 21), | ||
18 | REG_DWARFNUM_NAME(f4, 18), | ||
19 | REG_DWARFNUM_NAME(f5, 22), | ||
20 | REG_DWARFNUM_NAME(f6, 19), | ||
21 | REG_DWARFNUM_NAME(f7, 23), | ||
22 | REG_DWARFNUM_NAME(f8, 24), | ||
23 | REG_DWARFNUM_NAME(f9, 28), | ||
24 | REG_DWARFNUM_NAME(f10, 25), | ||
25 | REG_DWARFNUM_NAME(f11, 29), | ||
26 | REG_DWARFNUM_NAME(f12, 26), | ||
27 | REG_DWARFNUM_NAME(f13, 30), | ||
28 | REG_DWARFNUM_NAME(f14, 27), | ||
29 | REG_DWARFNUM_NAME(f15, 31), | ||
30 | REG_DWARFNUM_NAME(c0, 32), | ||
31 | REG_DWARFNUM_NAME(c1, 33), | ||
32 | REG_DWARFNUM_NAME(c2, 34), | ||
33 | REG_DWARFNUM_NAME(c3, 35), | ||
34 | REG_DWARFNUM_NAME(c4, 36), | ||
35 | REG_DWARFNUM_NAME(c5, 37), | ||
36 | REG_DWARFNUM_NAME(c6, 38), | ||
37 | REG_DWARFNUM_NAME(c7, 39), | ||
38 | REG_DWARFNUM_NAME(c8, 40), | ||
39 | REG_DWARFNUM_NAME(c9, 41), | ||
40 | REG_DWARFNUM_NAME(c10, 42), | ||
41 | REG_DWARFNUM_NAME(c11, 43), | ||
42 | REG_DWARFNUM_NAME(c12, 44), | ||
43 | REG_DWARFNUM_NAME(c13, 45), | ||
44 | REG_DWARFNUM_NAME(c14, 46), | ||
45 | REG_DWARFNUM_NAME(c15, 47), | ||
46 | REG_DWARFNUM_NAME(a0, 48), | ||
47 | REG_DWARFNUM_NAME(a1, 49), | ||
48 | REG_DWARFNUM_NAME(a2, 50), | ||
49 | REG_DWARFNUM_NAME(a3, 51), | ||
50 | REG_DWARFNUM_NAME(a4, 52), | ||
51 | REG_DWARFNUM_NAME(a5, 53), | ||
52 | REG_DWARFNUM_NAME(a6, 54), | ||
53 | REG_DWARFNUM_NAME(a7, 55), | ||
54 | REG_DWARFNUM_NAME(a8, 56), | ||
55 | REG_DWARFNUM_NAME(a9, 57), | ||
56 | REG_DWARFNUM_NAME(a10, 58), | ||
57 | REG_DWARFNUM_NAME(a11, 59), | ||
58 | REG_DWARFNUM_NAME(a12, 60), | ||
59 | REG_DWARFNUM_NAME(a13, 61), | ||
60 | REG_DWARFNUM_NAME(a14, 62), | ||
61 | REG_DWARFNUM_NAME(a15, 63), | ||
62 | REG_DWARFNUM_NAME(pswm, 64), | ||
63 | REG_DWARFNUM_NAME(pswa, 65), | ||
8 | }; | 64 | }; |
9 | #endif | 65 | |
66 | #ifdef DEFINE_DWARF_REGSTR_TABLE | ||
67 | /* This is included in perf/util/dwarf-regs.c */ | ||
68 | |||
69 | #define s390_regstr_tbl s390_dwarf_regs | ||
70 | |||
71 | #endif /* DEFINE_DWARF_REGSTR_TABLE */ | ||
72 | #endif /* S390_DWARF_REGS_TABLE_H */ | ||
diff --git a/tools/perf/arch/s390/include/perf_regs.h b/tools/perf/arch/s390/include/perf_regs.h new file mode 100644 index 000000000000..d2df54a6bc5a --- /dev/null +++ b/tools/perf/arch/s390/include/perf_regs.h | |||
@@ -0,0 +1,95 @@ | |||
1 | #ifndef ARCH_PERF_REGS_H | ||
2 | #define ARCH_PERF_REGS_H | ||
3 | |||
4 | #include <stdlib.h> | ||
5 | #include <linux/types.h> | ||
6 | #include <../../../../arch/s390/include/uapi/asm/perf_regs.h> | ||
7 | |||
8 | void perf_regs_load(u64 *regs); | ||
9 | |||
10 | #define PERF_REGS_MASK ((1ULL << PERF_REG_S390_MAX) - 1) | ||
11 | #define PERF_REGS_MAX PERF_REG_S390_MAX | ||
12 | #define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_64 | ||
13 | |||
14 | #define PERF_REG_IP PERF_REG_S390_PC | ||
15 | #define PERF_REG_SP PERF_REG_S390_R15 | ||
16 | |||
17 | static inline const char *perf_reg_name(int id) | ||
18 | { | ||
19 | switch (id) { | ||
20 | case PERF_REG_S390_R0: | ||
21 | return "R0"; | ||
22 | case PERF_REG_S390_R1: | ||
23 | return "R1"; | ||
24 | case PERF_REG_S390_R2: | ||
25 | return "R2"; | ||
26 | case PERF_REG_S390_R3: | ||
27 | return "R3"; | ||
28 | case PERF_REG_S390_R4: | ||
29 | return "R4"; | ||
30 | case PERF_REG_S390_R5: | ||
31 | return "R5"; | ||
32 | case PERF_REG_S390_R6: | ||
33 | return "R6"; | ||
34 | case PERF_REG_S390_R7: | ||
35 | return "R7"; | ||
36 | case PERF_REG_S390_R8: | ||
37 | return "R8"; | ||
38 | case PERF_REG_S390_R9: | ||
39 | return "R9"; | ||
40 | case PERF_REG_S390_R10: | ||
41 | return "R10"; | ||
42 | case PERF_REG_S390_R11: | ||
43 | return "R11"; | ||
44 | case PERF_REG_S390_R12: | ||
45 | return "R12"; | ||
46 | case PERF_REG_S390_R13: | ||
47 | return "R13"; | ||
48 | case PERF_REG_S390_R14: | ||
49 | return "R14"; | ||
50 | case PERF_REG_S390_R15: | ||
51 | return "R15"; | ||
52 | case PERF_REG_S390_FP0: | ||
53 | return "FP0"; | ||
54 | case PERF_REG_S390_FP1: | ||
55 | return "FP1"; | ||
56 | case PERF_REG_S390_FP2: | ||
57 | return "FP2"; | ||
58 | case PERF_REG_S390_FP3: | ||
59 | return "FP3"; | ||
60 | case PERF_REG_S390_FP4: | ||
61 | return "FP4"; | ||
62 | case PERF_REG_S390_FP5: | ||
63 | return "FP5"; | ||
64 | case PERF_REG_S390_FP6: | ||
65 | return "FP6"; | ||
66 | case PERF_REG_S390_FP7: | ||
67 | return "FP7"; | ||
68 | case PERF_REG_S390_FP8: | ||
69 | return "FP8"; | ||
70 | case PERF_REG_S390_FP9: | ||
71 | return "FP9"; | ||
72 | case PERF_REG_S390_FP10: | ||
73 | return "FP10"; | ||
74 | case PERF_REG_S390_FP11: | ||
75 | return "FP11"; | ||
76 | case PERF_REG_S390_FP12: | ||
77 | return "FP12"; | ||
78 | case PERF_REG_S390_FP13: | ||
79 | return "FP13"; | ||
80 | case PERF_REG_S390_FP14: | ||
81 | return "FP14"; | ||
82 | case PERF_REG_S390_FP15: | ||
83 | return "FP15"; | ||
84 | case PERF_REG_S390_MASK: | ||
85 | return "MASK"; | ||
86 | case PERF_REG_S390_PC: | ||
87 | return "PC"; | ||
88 | default: | ||
89 | return NULL; | ||
90 | } | ||
91 | |||
92 | return NULL; | ||
93 | } | ||
94 | |||
95 | #endif /* ARCH_PERF_REGS_H */ | ||
diff --git a/tools/perf/arch/s390/util/Build b/tools/perf/arch/s390/util/Build index 5bd7b9260cc0..4a233683c684 100644 --- a/tools/perf/arch/s390/util/Build +++ b/tools/perf/arch/s390/util/Build | |||
@@ -2,5 +2,8 @@ libperf-y += header.o | |||
2 | libperf-y += kvm-stat.o | 2 | libperf-y += kvm-stat.o |
3 | 3 | ||
4 | libperf-$(CONFIG_DWARF) += dwarf-regs.o | 4 | libperf-$(CONFIG_DWARF) += dwarf-regs.o |
5 | libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o | ||
5 | 6 | ||
6 | libperf-y += machine.o | 7 | libperf-y += machine.o |
8 | |||
9 | libperf-$(CONFIG_AUXTRACE) += auxtrace.o | ||
diff --git a/tools/perf/arch/s390/util/auxtrace.c b/tools/perf/arch/s390/util/auxtrace.c new file mode 100644 index 000000000000..6cb48e4cffd9 --- /dev/null +++ b/tools/perf/arch/s390/util/auxtrace.c | |||
@@ -0,0 +1,118 @@ | |||
1 | #include <stdbool.h> | ||
2 | #include <linux/kernel.h> | ||
3 | #include <linux/types.h> | ||
4 | #include <linux/bitops.h> | ||
5 | #include <linux/log2.h> | ||
6 | |||
7 | #include "../../util/evlist.h" | ||
8 | #include "../../util/auxtrace.h" | ||
9 | #include "../../util/evsel.h" | ||
10 | |||
11 | #define PERF_EVENT_CPUM_SF 0xB0000 /* Event: Basic-sampling */ | ||
12 | #define PERF_EVENT_CPUM_SF_DIAG 0xBD000 /* Event: Combined-sampling */ | ||
13 | #define DEFAULT_AUX_PAGES 128 | ||
14 | #define DEFAULT_FREQ 4000 | ||
15 | |||
16 | static void cpumsf_free(struct auxtrace_record *itr) | ||
17 | { | ||
18 | free(itr); | ||
19 | } | ||
20 | |||
21 | static size_t cpumsf_info_priv_size(struct auxtrace_record *itr __maybe_unused, | ||
22 | struct perf_evlist *evlist __maybe_unused) | ||
23 | { | ||
24 | return 0; | ||
25 | } | ||
26 | |||
27 | static int | ||
28 | cpumsf_info_fill(struct auxtrace_record *itr __maybe_unused, | ||
29 | struct perf_session *session __maybe_unused, | ||
30 | struct auxtrace_info_event *auxtrace_info __maybe_unused, | ||
31 | size_t priv_size __maybe_unused) | ||
32 | { | ||
33 | return 0; | ||
34 | } | ||
35 | |||
36 | static unsigned long | ||
37 | cpumsf_reference(struct auxtrace_record *itr __maybe_unused) | ||
38 | { | ||
39 | return 0; | ||
40 | } | ||
41 | |||
42 | static int | ||
43 | cpumsf_recording_options(struct auxtrace_record *ar __maybe_unused, | ||
44 | struct perf_evlist *evlist __maybe_unused, | ||
45 | struct record_opts *opts) | ||
46 | { | ||
47 | unsigned int factor = 1; | ||
48 | unsigned int pages; | ||
49 | |||
50 | opts->full_auxtrace = true; | ||
51 | |||
52 | /* | ||
53 | * The AUX buffer size should be set properly to avoid | ||
54 | * overflow of samples if it is not set explicitly. | ||
55 | * DEFAULT_AUX_PAGES is an proper size when sampling frequency | ||
56 | * is DEFAULT_FREQ. It is expected to hold about 1/2 second | ||
57 | * of sampling data. The size used for AUX buffer will scale | ||
58 | * according to the specified frequency and DEFAULT_FREQ. | ||
59 | */ | ||
60 | if (!opts->auxtrace_mmap_pages) { | ||
61 | if (opts->user_freq != UINT_MAX) | ||
62 | factor = (opts->user_freq + DEFAULT_FREQ | ||
63 | - 1) / DEFAULT_FREQ; | ||
64 | pages = DEFAULT_AUX_PAGES * factor; | ||
65 | opts->auxtrace_mmap_pages = roundup_pow_of_two(pages); | ||
66 | } | ||
67 | |||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | static int | ||
72 | cpumsf_parse_snapshot_options(struct auxtrace_record *itr __maybe_unused, | ||
73 | struct record_opts *opts __maybe_unused, | ||
74 | const char *str __maybe_unused) | ||
75 | { | ||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | /* | ||
80 | * auxtrace_record__init is called when perf record | ||
81 | * check if the event really need auxtrace | ||
82 | */ | ||
83 | struct auxtrace_record *auxtrace_record__init(struct perf_evlist *evlist, | ||
84 | int *err) | ||
85 | { | ||
86 | struct auxtrace_record *aux; | ||
87 | struct perf_evsel *pos; | ||
88 | int diagnose = 0; | ||
89 | |||
90 | if (evlist->nr_entries == 0) | ||
91 | return NULL; | ||
92 | |||
93 | evlist__for_each_entry(evlist, pos) { | ||
94 | if (pos->attr.config == PERF_EVENT_CPUM_SF_DIAG) { | ||
95 | diagnose = 1; | ||
96 | break; | ||
97 | } | ||
98 | } | ||
99 | |||
100 | if (!diagnose) | ||
101 | return NULL; | ||
102 | |||
103 | /* sampling in diagnose mode. alloc aux buffer */ | ||
104 | aux = zalloc(sizeof(*aux)); | ||
105 | if (aux == NULL) { | ||
106 | *err = -ENOMEM; | ||
107 | return NULL; | ||
108 | } | ||
109 | |||
110 | aux->parse_snapshot_options = cpumsf_parse_snapshot_options; | ||
111 | aux->recording_options = cpumsf_recording_options; | ||
112 | aux->info_priv_size = cpumsf_info_priv_size; | ||
113 | aux->info_fill = cpumsf_info_fill; | ||
114 | aux->free = cpumsf_free; | ||
115 | aux->reference = cpumsf_reference; | ||
116 | |||
117 | return aux; | ||
118 | } | ||
diff --git a/tools/perf/arch/s390/util/dwarf-regs.c b/tools/perf/arch/s390/util/dwarf-regs.c index 0dff5b2ed1e5..f47576ce13ea 100644 --- a/tools/perf/arch/s390/util/dwarf-regs.c +++ b/tools/perf/arch/s390/util/dwarf-regs.c | |||
@@ -9,15 +9,10 @@ | |||
9 | 9 | ||
10 | #include <stddef.h> | 10 | #include <stddef.h> |
11 | #include <dwarf-regs.h> | 11 | #include <dwarf-regs.h> |
12 | 12 | #include <linux/kernel.h> | |
13 | #define NUM_GPRS 16 | 13 | #include "dwarf-regs-table.h" |
14 | |||
15 | static const char *gpr_names[NUM_GPRS] = { | ||
16 | "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7", | ||
17 | "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", | ||
18 | }; | ||
19 | 14 | ||
20 | const char *get_arch_regstr(unsigned int n) | 15 | const char *get_arch_regstr(unsigned int n) |
21 | { | 16 | { |
22 | return (n >= NUM_GPRS) ? NULL : gpr_names[n]; | 17 | return (n >= ARRAY_SIZE(s390_dwarf_regs)) ? NULL : s390_dwarf_regs[n]; |
23 | } | 18 | } |
diff --git a/tools/perf/arch/s390/util/unwind-libdw.c b/tools/perf/arch/s390/util/unwind-libdw.c new file mode 100644 index 000000000000..387c698cdd1b --- /dev/null +++ b/tools/perf/arch/s390/util/unwind-libdw.c | |||
@@ -0,0 +1,63 @@ | |||
1 | #include <linux/kernel.h> | ||
2 | #include <elfutils/libdwfl.h> | ||
3 | #include "../../util/unwind-libdw.h" | ||
4 | #include "../../util/perf_regs.h" | ||
5 | #include "../../util/event.h" | ||
6 | #include "dwarf-regs-table.h" | ||
7 | |||
8 | |||
9 | bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg) | ||
10 | { | ||
11 | struct unwind_info *ui = arg; | ||
12 | struct regs_dump *user_regs = &ui->sample->user_regs; | ||
13 | Dwarf_Word dwarf_regs[ARRAY_SIZE(s390_dwarf_regs)]; | ||
14 | |||
15 | #define REG(r) ({ \ | ||
16 | Dwarf_Word val = 0; \ | ||
17 | perf_reg_value(&val, user_regs, PERF_REG_S390_##r); \ | ||
18 | val; \ | ||
19 | }) | ||
20 | /* | ||
21 | * For DWARF register mapping details, | ||
22 | * see also perf/arch/s390/include/dwarf-regs-table.h | ||
23 | */ | ||
24 | dwarf_regs[0] = REG(R0); | ||
25 | dwarf_regs[1] = REG(R1); | ||
26 | dwarf_regs[2] = REG(R2); | ||
27 | dwarf_regs[3] = REG(R3); | ||
28 | dwarf_regs[4] = REG(R4); | ||
29 | dwarf_regs[5] = REG(R5); | ||
30 | dwarf_regs[6] = REG(R6); | ||
31 | dwarf_regs[7] = REG(R7); | ||
32 | dwarf_regs[8] = REG(R8); | ||
33 | dwarf_regs[9] = REG(R9); | ||
34 | dwarf_regs[10] = REG(R10); | ||
35 | dwarf_regs[11] = REG(R11); | ||
36 | dwarf_regs[12] = REG(R12); | ||
37 | dwarf_regs[13] = REG(R13); | ||
38 | dwarf_regs[14] = REG(R14); | ||
39 | dwarf_regs[15] = REG(R15); | ||
40 | |||
41 | dwarf_regs[16] = REG(FP0); | ||
42 | dwarf_regs[17] = REG(FP2); | ||
43 | dwarf_regs[18] = REG(FP4); | ||
44 | dwarf_regs[19] = REG(FP6); | ||
45 | dwarf_regs[20] = REG(FP1); | ||
46 | dwarf_regs[21] = REG(FP3); | ||
47 | dwarf_regs[22] = REG(FP5); | ||
48 | dwarf_regs[23] = REG(FP7); | ||
49 | dwarf_regs[24] = REG(FP8); | ||
50 | dwarf_regs[25] = REG(FP10); | ||
51 | dwarf_regs[26] = REG(FP12); | ||
52 | dwarf_regs[27] = REG(FP14); | ||
53 | dwarf_regs[28] = REG(FP9); | ||
54 | dwarf_regs[29] = REG(FP11); | ||
55 | dwarf_regs[30] = REG(FP13); | ||
56 | dwarf_regs[31] = REG(FP15); | ||
57 | |||
58 | dwarf_regs[64] = REG(MASK); | ||
59 | dwarf_regs[65] = REG(PC); | ||
60 | |||
61 | dwfl_thread_state_register_pc(thread, dwarf_regs[65]); | ||
62 | return dwfl_thread_state_registers(thread, 0, 32, dwarf_regs); | ||
63 | } | ||
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 557d391f564a..ae11e4c3516a 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c | |||
@@ -641,7 +641,6 @@ static const struct { | |||
641 | { "__GFP_ATOMIC", "_A" }, | 641 | { "__GFP_ATOMIC", "_A" }, |
642 | { "__GFP_IO", "I" }, | 642 | { "__GFP_IO", "I" }, |
643 | { "__GFP_FS", "F" }, | 643 | { "__GFP_FS", "F" }, |
644 | { "__GFP_COLD", "CO" }, | ||
645 | { "__GFP_NOWARN", "NWR" }, | 644 | { "__GFP_NOWARN", "NWR" }, |
646 | { "__GFP_RETRY_MAYFAIL", "R" }, | 645 | { "__GFP_RETRY_MAYFAIL", "R" }, |
647 | { "__GFP_NOFAIL", "NF" }, | 646 | { "__GFP_NOFAIL", "NF" }, |
@@ -655,7 +654,6 @@ static const struct { | |||
655 | { "__GFP_RECLAIMABLE", "RC" }, | 654 | { "__GFP_RECLAIMABLE", "RC" }, |
656 | { "__GFP_MOVABLE", "M" }, | 655 | { "__GFP_MOVABLE", "M" }, |
657 | { "__GFP_ACCOUNT", "AC" }, | 656 | { "__GFP_ACCOUNT", "AC" }, |
658 | { "__GFP_NOTRACK", "NT" }, | ||
659 | { "__GFP_WRITE", "WR" }, | 657 | { "__GFP_WRITE", "WR" }, |
660 | { "__GFP_RECLAIM", "R" }, | 658 | { "__GFP_RECLAIM", "R" }, |
661 | { "__GFP_DIRECT_RECLAIM", "DR" }, | 659 | { "__GFP_DIRECT_RECLAIM", "DR" }, |
diff --git a/tools/power/acpi/tools/acpidump/Makefile b/tools/power/acpi/tools/acpidump/Makefile index f7c7af1f9258..b436f8675f6a 100644 --- a/tools/power/acpi/tools/acpidump/Makefile +++ b/tools/power/acpi/tools/acpidump/Makefile | |||
@@ -39,6 +39,7 @@ TOOL_OBJS = \ | |||
39 | utnonansi.o\ | 39 | utnonansi.o\ |
40 | utprint.o\ | 40 | utprint.o\ |
41 | utstring.o\ | 41 | utstring.o\ |
42 | utstrsuppt.o\ | ||
42 | utstrtoul64.o\ | 43 | utstrtoul64.o\ |
43 | utxferror.o\ | 44 | utxferror.o\ |
44 | oslinuxtbl.o\ | 45 | oslinuxtbl.o\ |
diff --git a/tools/power/acpi/tools/acpidump/apdump.c b/tools/power/acpi/tools/acpidump/apdump.c index 60df1fbd4a77..0634449156d8 100644 --- a/tools/power/acpi/tools/acpidump/apdump.c +++ b/tools/power/acpi/tools/acpidump/apdump.c | |||
@@ -287,8 +287,7 @@ int ap_dump_table_by_address(char *ascii_address) | |||
287 | 287 | ||
288 | /* Convert argument to an integer physical address */ | 288 | /* Convert argument to an integer physical address */ |
289 | 289 | ||
290 | status = acpi_ut_strtoul64(ascii_address, ACPI_STRTOUL_64BIT, | 290 | status = acpi_ut_strtoul64(ascii_address, &long_address); |
291 | &long_address); | ||
292 | if (ACPI_FAILURE(status)) { | 291 | if (ACPI_FAILURE(status)) { |
293 | fprintf(stderr, "%s: Could not convert to a physical address\n", | 292 | fprintf(stderr, "%s: Could not convert to a physical address\n", |
294 | ascii_address); | 293 | ascii_address); |
diff --git a/tools/power/acpi/tools/acpidump/apmain.c b/tools/power/acpi/tools/acpidump/apmain.c index 943b6b614683..22c3b4ee1617 100644 --- a/tools/power/acpi/tools/acpidump/apmain.c +++ b/tools/power/acpi/tools/acpidump/apmain.c | |||
@@ -208,9 +208,7 @@ static int ap_do_options(int argc, char **argv) | |||
208 | case 'r': /* Dump tables from specified RSDP */ | 208 | case 'r': /* Dump tables from specified RSDP */ |
209 | 209 | ||
210 | status = | 210 | status = |
211 | acpi_ut_strtoul64(acpi_gbl_optarg, | 211 | acpi_ut_strtoul64(acpi_gbl_optarg, &gbl_rsdp_base); |
212 | ACPI_STRTOUL_64BIT, | ||
213 | &gbl_rsdp_base); | ||
214 | if (ACPI_FAILURE(status)) { | 212 | if (ACPI_FAILURE(status)) { |
215 | fprintf(stderr, | 213 | fprintf(stderr, |
216 | "%s: Could not convert to a physical address\n", | 214 | "%s: Could not convert to a physical address\n", |
diff --git a/tools/power/cpupower/.gitignore b/tools/power/cpupower/.gitignore index d42073f12609..1f9977cc609c 100644 --- a/tools/power/cpupower/.gitignore +++ b/tools/power/cpupower/.gitignore | |||
@@ -1,7 +1,6 @@ | |||
1 | .libs | 1 | .libs |
2 | libcpupower.so | 2 | libcpupower.so |
3 | libcpupower.so.0 | 3 | libcpupower.so.* |
4 | libcpupower.so.0.0.0 | ||
5 | build/ccdv | 4 | build/ccdv |
6 | cpufreq-info | 5 | cpufreq-info |
7 | cpufreq-set | 6 | cpufreq-set |
diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile index d6e1c02ddcfe..1dd5f4fcffd5 100644 --- a/tools/power/cpupower/Makefile +++ b/tools/power/cpupower/Makefile | |||
@@ -26,10 +26,12 @@ endif | |||
26 | 26 | ||
27 | ifneq ($(OUTPUT),) | 27 | ifneq ($(OUTPUT),) |
28 | # check that the output directory actually exists | 28 | # check that the output directory actually exists |
29 | OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd) | 29 | OUTDIR := $(shell cd $(OUTPUT) && pwd) |
30 | $(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist)) | 30 | $(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist)) |
31 | endif | 31 | endif |
32 | 32 | ||
33 | include ../../scripts/Makefile.arch | ||
34 | |||
33 | # --- CONFIGURATION BEGIN --- | 35 | # --- CONFIGURATION BEGIN --- |
34 | 36 | ||
35 | # Set the following to `true' to make a unstripped, unoptimized | 37 | # Set the following to `true' to make a unstripped, unoptimized |
@@ -79,7 +81,11 @@ bindir ?= /usr/bin | |||
79 | sbindir ?= /usr/sbin | 81 | sbindir ?= /usr/sbin |
80 | mandir ?= /usr/man | 82 | mandir ?= /usr/man |
81 | includedir ?= /usr/include | 83 | includedir ?= /usr/include |
84 | ifeq ($(IS_64_BIT), 1) | ||
85 | libdir ?= /usr/lib64 | ||
86 | else | ||
82 | libdir ?= /usr/lib | 87 | libdir ?= /usr/lib |
88 | endif | ||
83 | localedir ?= /usr/share/locale | 89 | localedir ?= /usr/share/locale |
84 | docdir ?= /usr/share/doc/packages/cpupower | 90 | docdir ?= /usr/share/doc/packages/cpupower |
85 | confdir ?= /etc/ | 91 | confdir ?= /etc/ |
diff --git a/tools/power/cpupower/bench/system.c b/tools/power/cpupower/bench/system.c index c25a74ae51ba..2bb3eef7d5c1 100644 --- a/tools/power/cpupower/bench/system.c +++ b/tools/power/cpupower/bench/system.c | |||
@@ -61,7 +61,7 @@ int set_cpufreq_governor(char *governor, unsigned int cpu) | |||
61 | 61 | ||
62 | dprintf("set %s as cpufreq governor\n", governor); | 62 | dprintf("set %s as cpufreq governor\n", governor); |
63 | 63 | ||
64 | if (cpupower_is_cpu_online(cpu) != 0) { | 64 | if (cpupower_is_cpu_online(cpu) != 1) { |
65 | perror("cpufreq_cpu_exists"); | 65 | perror("cpufreq_cpu_exists"); |
66 | fprintf(stderr, "error: cpu %u does not exist\n", cpu); | 66 | fprintf(stderr, "error: cpu %u does not exist\n", cpu); |
67 | return -1; | 67 | return -1; |
diff --git a/tools/power/cpupower/utils/cpufreq-info.c b/tools/power/cpupower/utils/cpufreq-info.c index 3e701f0e9c14..df43cd45d810 100644 --- a/tools/power/cpupower/utils/cpufreq-info.c +++ b/tools/power/cpupower/utils/cpufreq-info.c | |||
@@ -93,8 +93,6 @@ static void print_speed(unsigned long speed) | |||
93 | if (speed > 1000000) | 93 | if (speed > 1000000) |
94 | printf("%u.%06u GHz", ((unsigned int) speed/1000000), | 94 | printf("%u.%06u GHz", ((unsigned int) speed/1000000), |
95 | ((unsigned int) speed%1000000)); | 95 | ((unsigned int) speed%1000000)); |
96 | else if (speed > 100000) | ||
97 | printf("%u MHz", (unsigned int) speed); | ||
98 | else if (speed > 1000) | 96 | else if (speed > 1000) |
99 | printf("%u.%03u MHz", ((unsigned int) speed/1000), | 97 | printf("%u.%03u MHz", ((unsigned int) speed/1000), |
100 | (unsigned int) (speed%1000)); | 98 | (unsigned int) (speed%1000)); |
diff --git a/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c index 1b5da0066ebf..5b3205f16217 100644 --- a/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c +++ b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c | |||
@@ -130,15 +130,18 @@ static struct cpuidle_monitor *cpuidle_register(void) | |||
130 | { | 130 | { |
131 | int num; | 131 | int num; |
132 | char *tmp; | 132 | char *tmp; |
133 | int this_cpu; | ||
134 | |||
135 | this_cpu = sched_getcpu(); | ||
133 | 136 | ||
134 | /* Assume idle state count is the same for all CPUs */ | 137 | /* Assume idle state count is the same for all CPUs */ |
135 | cpuidle_sysfs_monitor.hw_states_num = cpuidle_state_count(0); | 138 | cpuidle_sysfs_monitor.hw_states_num = cpuidle_state_count(this_cpu); |
136 | 139 | ||
137 | if (cpuidle_sysfs_monitor.hw_states_num <= 0) | 140 | if (cpuidle_sysfs_monitor.hw_states_num <= 0) |
138 | return NULL; | 141 | return NULL; |
139 | 142 | ||
140 | for (num = 0; num < cpuidle_sysfs_monitor.hw_states_num; num++) { | 143 | for (num = 0; num < cpuidle_sysfs_monitor.hw_states_num; num++) { |
141 | tmp = cpuidle_state_name(0, num); | 144 | tmp = cpuidle_state_name(this_cpu, num); |
142 | if (tmp == NULL) | 145 | if (tmp == NULL) |
143 | continue; | 146 | continue; |
144 | 147 | ||
@@ -146,7 +149,7 @@ static struct cpuidle_monitor *cpuidle_register(void) | |||
146 | strncpy(cpuidle_cstates[num].name, tmp, CSTATE_NAME_LEN - 1); | 149 | strncpy(cpuidle_cstates[num].name, tmp, CSTATE_NAME_LEN - 1); |
147 | free(tmp); | 150 | free(tmp); |
148 | 151 | ||
149 | tmp = cpuidle_state_desc(0, num); | 152 | tmp = cpuidle_state_desc(this_cpu, num); |
150 | if (tmp == NULL) | 153 | if (tmp == NULL) |
151 | continue; | 154 | continue; |
152 | strncpy(cpuidle_cstates[num].desc, tmp, CSTATE_DESC_LEN - 1); | 155 | strncpy(cpuidle_cstates[num].desc, tmp, CSTATE_DESC_LEN - 1); |
diff --git a/tools/scripts/Makefile.include b/tools/scripts/Makefile.include index 654efd9768fd..3fab179b1aba 100644 --- a/tools/scripts/Makefile.include +++ b/tools/scripts/Makefile.include | |||
@@ -13,7 +13,7 @@ endif | |||
13 | 13 | ||
14 | # check that the output directory actually exists | 14 | # check that the output directory actually exists |
15 | ifneq ($(OUTPUT),) | 15 | ifneq ($(OUTPUT),) |
16 | OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd) | 16 | OUTDIR := $(shell cd $(OUTPUT) && pwd) |
17 | $(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist)) | 17 | $(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist)) |
18 | endif | 18 | endif |
19 | 19 | ||
diff --git a/tools/testing/nvdimm/Kbuild b/tools/testing/nvdimm/Kbuild index 65368d9027f5..db33b28c5ef3 100644 --- a/tools/testing/nvdimm/Kbuild +++ b/tools/testing/nvdimm/Kbuild | |||
@@ -70,6 +70,7 @@ libnvdimm-y += $(NVDIMM_SRC)/region_devs.o | |||
70 | libnvdimm-y += $(NVDIMM_SRC)/region.o | 70 | libnvdimm-y += $(NVDIMM_SRC)/region.o |
71 | libnvdimm-y += $(NVDIMM_SRC)/namespace_devs.o | 71 | libnvdimm-y += $(NVDIMM_SRC)/namespace_devs.o |
72 | libnvdimm-y += $(NVDIMM_SRC)/label.o | 72 | libnvdimm-y += $(NVDIMM_SRC)/label.o |
73 | libnvdimm-y += $(NVDIMM_SRC)/badrange.o | ||
73 | libnvdimm-$(CONFIG_ND_CLAIM) += $(NVDIMM_SRC)/claim.o | 74 | libnvdimm-$(CONFIG_ND_CLAIM) += $(NVDIMM_SRC)/claim.o |
74 | libnvdimm-$(CONFIG_BTT) += $(NVDIMM_SRC)/btt_devs.o | 75 | libnvdimm-$(CONFIG_BTT) += $(NVDIMM_SRC)/btt_devs.o |
75 | libnvdimm-$(CONFIG_NVDIMM_PFN) += $(NVDIMM_SRC)/pfn_devs.o | 76 | libnvdimm-$(CONFIG_NVDIMM_PFN) += $(NVDIMM_SRC)/pfn_devs.o |
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index bef419d4266d..7217b2b953b5 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c | |||
@@ -168,8 +168,12 @@ struct nfit_test { | |||
168 | spinlock_t lock; | 168 | spinlock_t lock; |
169 | } ars_state; | 169 | } ars_state; |
170 | struct device *dimm_dev[NUM_DCR]; | 170 | struct device *dimm_dev[NUM_DCR]; |
171 | struct badrange badrange; | ||
172 | struct work_struct work; | ||
171 | }; | 173 | }; |
172 | 174 | ||
175 | static struct workqueue_struct *nfit_wq; | ||
176 | |||
173 | static struct nfit_test *to_nfit_test(struct device *dev) | 177 | static struct nfit_test *to_nfit_test(struct device *dev) |
174 | { | 178 | { |
175 | struct platform_device *pdev = to_platform_device(dev); | 179 | struct platform_device *pdev = to_platform_device(dev); |
@@ -234,48 +238,68 @@ static int nfit_test_cmd_set_config_data(struct nd_cmd_set_config_hdr *nd_cmd, | |||
234 | return rc; | 238 | return rc; |
235 | } | 239 | } |
236 | 240 | ||
237 | #define NFIT_TEST_ARS_RECORDS 4 | ||
238 | #define NFIT_TEST_CLEAR_ERR_UNIT 256 | 241 | #define NFIT_TEST_CLEAR_ERR_UNIT 256 |
239 | 242 | ||
240 | static int nfit_test_cmd_ars_cap(struct nd_cmd_ars_cap *nd_cmd, | 243 | static int nfit_test_cmd_ars_cap(struct nd_cmd_ars_cap *nd_cmd, |
241 | unsigned int buf_len) | 244 | unsigned int buf_len) |
242 | { | 245 | { |
246 | int ars_recs; | ||
247 | |||
243 | if (buf_len < sizeof(*nd_cmd)) | 248 | if (buf_len < sizeof(*nd_cmd)) |
244 | return -EINVAL; | 249 | return -EINVAL; |
245 | 250 | ||
251 | /* for testing, only store up to n records that fit within 4k */ | ||
252 | ars_recs = SZ_4K / sizeof(struct nd_ars_record); | ||
253 | |||
246 | nd_cmd->max_ars_out = sizeof(struct nd_cmd_ars_status) | 254 | nd_cmd->max_ars_out = sizeof(struct nd_cmd_ars_status) |
247 | + NFIT_TEST_ARS_RECORDS * sizeof(struct nd_ars_record); | 255 | + ars_recs * sizeof(struct nd_ars_record); |
248 | nd_cmd->status = (ND_ARS_PERSISTENT | ND_ARS_VOLATILE) << 16; | 256 | nd_cmd->status = (ND_ARS_PERSISTENT | ND_ARS_VOLATILE) << 16; |
249 | nd_cmd->clear_err_unit = NFIT_TEST_CLEAR_ERR_UNIT; | 257 | nd_cmd->clear_err_unit = NFIT_TEST_CLEAR_ERR_UNIT; |
250 | 258 | ||
251 | return 0; | 259 | return 0; |
252 | } | 260 | } |
253 | 261 | ||
254 | /* | 262 | static void post_ars_status(struct ars_state *ars_state, |
255 | * Initialize the ars_state to return an ars_result 1 second in the future with | 263 | struct badrange *badrange, u64 addr, u64 len) |
256 | * a 4K error range in the middle of the requested address range. | ||
257 | */ | ||
258 | static void post_ars_status(struct ars_state *ars_state, u64 addr, u64 len) | ||
259 | { | 264 | { |
260 | struct nd_cmd_ars_status *ars_status; | 265 | struct nd_cmd_ars_status *ars_status; |
261 | struct nd_ars_record *ars_record; | 266 | struct nd_ars_record *ars_record; |
267 | struct badrange_entry *be; | ||
268 | u64 end = addr + len - 1; | ||
269 | int i = 0; | ||
262 | 270 | ||
263 | ars_state->deadline = jiffies + 1*HZ; | 271 | ars_state->deadline = jiffies + 1*HZ; |
264 | ars_status = ars_state->ars_status; | 272 | ars_status = ars_state->ars_status; |
265 | ars_status->status = 0; | 273 | ars_status->status = 0; |
266 | ars_status->out_length = sizeof(struct nd_cmd_ars_status) | ||
267 | + sizeof(struct nd_ars_record); | ||
268 | ars_status->address = addr; | 274 | ars_status->address = addr; |
269 | ars_status->length = len; | 275 | ars_status->length = len; |
270 | ars_status->type = ND_ARS_PERSISTENT; | 276 | ars_status->type = ND_ARS_PERSISTENT; |
271 | ars_status->num_records = 1; | 277 | |
272 | ars_record = &ars_status->records[0]; | 278 | spin_lock(&badrange->lock); |
273 | ars_record->handle = 0; | 279 | list_for_each_entry(be, &badrange->list, list) { |
274 | ars_record->err_address = addr + len / 2; | 280 | u64 be_end = be->start + be->length - 1; |
275 | ars_record->length = SZ_4K; | 281 | u64 rstart, rend; |
282 | |||
283 | /* skip entries outside the range */ | ||
284 | if (be_end < addr || be->start > end) | ||
285 | continue; | ||
286 | |||
287 | rstart = (be->start < addr) ? addr : be->start; | ||
288 | rend = (be_end < end) ? be_end : end; | ||
289 | ars_record = &ars_status->records[i]; | ||
290 | ars_record->handle = 0; | ||
291 | ars_record->err_address = rstart; | ||
292 | ars_record->length = rend - rstart + 1; | ||
293 | i++; | ||
294 | } | ||
295 | spin_unlock(&badrange->lock); | ||
296 | ars_status->num_records = i; | ||
297 | ars_status->out_length = sizeof(struct nd_cmd_ars_status) | ||
298 | + i * sizeof(struct nd_ars_record); | ||
276 | } | 299 | } |
277 | 300 | ||
278 | static int nfit_test_cmd_ars_start(struct ars_state *ars_state, | 301 | static int nfit_test_cmd_ars_start(struct nfit_test *t, |
302 | struct ars_state *ars_state, | ||
279 | struct nd_cmd_ars_start *ars_start, unsigned int buf_len, | 303 | struct nd_cmd_ars_start *ars_start, unsigned int buf_len, |
280 | int *cmd_rc) | 304 | int *cmd_rc) |
281 | { | 305 | { |
@@ -289,7 +313,7 @@ static int nfit_test_cmd_ars_start(struct ars_state *ars_state, | |||
289 | } else { | 313 | } else { |
290 | ars_start->status = 0; | 314 | ars_start->status = 0; |
291 | ars_start->scrub_time = 1; | 315 | ars_start->scrub_time = 1; |
292 | post_ars_status(ars_state, ars_start->address, | 316 | post_ars_status(ars_state, &t->badrange, ars_start->address, |
293 | ars_start->length); | 317 | ars_start->length); |
294 | *cmd_rc = 0; | 318 | *cmd_rc = 0; |
295 | } | 319 | } |
@@ -320,7 +344,8 @@ static int nfit_test_cmd_ars_status(struct ars_state *ars_state, | |||
320 | return 0; | 344 | return 0; |
321 | } | 345 | } |
322 | 346 | ||
323 | static int nfit_test_cmd_clear_error(struct nd_cmd_clear_error *clear_err, | 347 | static int nfit_test_cmd_clear_error(struct nfit_test *t, |
348 | struct nd_cmd_clear_error *clear_err, | ||
324 | unsigned int buf_len, int *cmd_rc) | 349 | unsigned int buf_len, int *cmd_rc) |
325 | { | 350 | { |
326 | const u64 mask = NFIT_TEST_CLEAR_ERR_UNIT - 1; | 351 | const u64 mask = NFIT_TEST_CLEAR_ERR_UNIT - 1; |
@@ -330,18 +355,91 @@ static int nfit_test_cmd_clear_error(struct nd_cmd_clear_error *clear_err, | |||
330 | if ((clear_err->address & mask) || (clear_err->length & mask)) | 355 | if ((clear_err->address & mask) || (clear_err->length & mask)) |
331 | return -EINVAL; | 356 | return -EINVAL; |
332 | 357 | ||
333 | /* | 358 | badrange_forget(&t->badrange, clear_err->address, clear_err->length); |
334 | * Report 'all clear' success for all commands even though a new | ||
335 | * scrub will find errors again. This is enough to have the | ||
336 | * error removed from the 'badblocks' tracking in the pmem | ||
337 | * driver. | ||
338 | */ | ||
339 | clear_err->status = 0; | 359 | clear_err->status = 0; |
340 | clear_err->cleared = clear_err->length; | 360 | clear_err->cleared = clear_err->length; |
341 | *cmd_rc = 0; | 361 | *cmd_rc = 0; |
342 | return 0; | 362 | return 0; |
343 | } | 363 | } |
344 | 364 | ||
365 | struct region_search_spa { | ||
366 | u64 addr; | ||
367 | struct nd_region *region; | ||
368 | }; | ||
369 | |||
370 | static int is_region_device(struct device *dev) | ||
371 | { | ||
372 | return !strncmp(dev->kobj.name, "region", 6); | ||
373 | } | ||
374 | |||
375 | static int nfit_test_search_region_spa(struct device *dev, void *data) | ||
376 | { | ||
377 | struct region_search_spa *ctx = data; | ||
378 | struct nd_region *nd_region; | ||
379 | resource_size_t ndr_end; | ||
380 | |||
381 | if (!is_region_device(dev)) | ||
382 | return 0; | ||
383 | |||
384 | nd_region = to_nd_region(dev); | ||
385 | ndr_end = nd_region->ndr_start + nd_region->ndr_size; | ||
386 | |||
387 | if (ctx->addr >= nd_region->ndr_start && ctx->addr < ndr_end) { | ||
388 | ctx->region = nd_region; | ||
389 | return 1; | ||
390 | } | ||
391 | |||
392 | return 0; | ||
393 | } | ||
394 | |||
395 | static int nfit_test_search_spa(struct nvdimm_bus *bus, | ||
396 | struct nd_cmd_translate_spa *spa) | ||
397 | { | ||
398 | int ret; | ||
399 | struct nd_region *nd_region = NULL; | ||
400 | struct nvdimm *nvdimm = NULL; | ||
401 | struct nd_mapping *nd_mapping = NULL; | ||
402 | struct region_search_spa ctx = { | ||
403 | .addr = spa->spa, | ||
404 | .region = NULL, | ||
405 | }; | ||
406 | u64 dpa; | ||
407 | |||
408 | ret = device_for_each_child(&bus->dev, &ctx, | ||
409 | nfit_test_search_region_spa); | ||
410 | |||
411 | if (!ret) | ||
412 | return -ENODEV; | ||
413 | |||
414 | nd_region = ctx.region; | ||
415 | |||
416 | dpa = ctx.addr - nd_region->ndr_start; | ||
417 | |||
418 | /* | ||
419 | * last dimm is selected for test | ||
420 | */ | ||
421 | nd_mapping = &nd_region->mapping[nd_region->ndr_mappings - 1]; | ||
422 | nvdimm = nd_mapping->nvdimm; | ||
423 | |||
424 | spa->devices[0].nfit_device_handle = handle[nvdimm->id]; | ||
425 | spa->num_nvdimms = 1; | ||
426 | spa->devices[0].dpa = dpa; | ||
427 | |||
428 | return 0; | ||
429 | } | ||
430 | |||
431 | static int nfit_test_cmd_translate_spa(struct nvdimm_bus *bus, | ||
432 | struct nd_cmd_translate_spa *spa, unsigned int buf_len) | ||
433 | { | ||
434 | if (buf_len < spa->translate_length) | ||
435 | return -EINVAL; | ||
436 | |||
437 | if (nfit_test_search_spa(bus, spa) < 0 || !spa->num_nvdimms) | ||
438 | spa->status = 2; | ||
439 | |||
440 | return 0; | ||
441 | } | ||
442 | |||
345 | static int nfit_test_cmd_smart(struct nd_cmd_smart *smart, unsigned int buf_len) | 443 | static int nfit_test_cmd_smart(struct nd_cmd_smart *smart, unsigned int buf_len) |
346 | { | 444 | { |
347 | static const struct nd_smart_payload smart_data = { | 445 | static const struct nd_smart_payload smart_data = { |
@@ -378,6 +476,93 @@ static int nfit_test_cmd_smart_threshold(struct nd_cmd_smart_threshold *smart_t, | |||
378 | return 0; | 476 | return 0; |
379 | } | 477 | } |
380 | 478 | ||
479 | static void uc_error_notify(struct work_struct *work) | ||
480 | { | ||
481 | struct nfit_test *t = container_of(work, typeof(*t), work); | ||
482 | |||
483 | __acpi_nfit_notify(&t->pdev.dev, t, NFIT_NOTIFY_UC_MEMORY_ERROR); | ||
484 | } | ||
485 | |||
486 | static int nfit_test_cmd_ars_error_inject(struct nfit_test *t, | ||
487 | struct nd_cmd_ars_err_inj *err_inj, unsigned int buf_len) | ||
488 | { | ||
489 | int rc; | ||
490 | |||
491 | if (buf_len != sizeof(*err_inj)) { | ||
492 | rc = -EINVAL; | ||
493 | goto err; | ||
494 | } | ||
495 | |||
496 | if (err_inj->err_inj_spa_range_length <= 0) { | ||
497 | rc = -EINVAL; | ||
498 | goto err; | ||
499 | } | ||
500 | |||
501 | rc = badrange_add(&t->badrange, err_inj->err_inj_spa_range_base, | ||
502 | err_inj->err_inj_spa_range_length); | ||
503 | if (rc < 0) | ||
504 | goto err; | ||
505 | |||
506 | if (err_inj->err_inj_options & (1 << ND_ARS_ERR_INJ_OPT_NOTIFY)) | ||
507 | queue_work(nfit_wq, &t->work); | ||
508 | |||
509 | err_inj->status = 0; | ||
510 | return 0; | ||
511 | |||
512 | err: | ||
513 | err_inj->status = NFIT_ARS_INJECT_INVALID; | ||
514 | return rc; | ||
515 | } | ||
516 | |||
517 | static int nfit_test_cmd_ars_inject_clear(struct nfit_test *t, | ||
518 | struct nd_cmd_ars_err_inj_clr *err_clr, unsigned int buf_len) | ||
519 | { | ||
520 | int rc; | ||
521 | |||
522 | if (buf_len != sizeof(*err_clr)) { | ||
523 | rc = -EINVAL; | ||
524 | goto err; | ||
525 | } | ||
526 | |||
527 | if (err_clr->err_inj_clr_spa_range_length <= 0) { | ||
528 | rc = -EINVAL; | ||
529 | goto err; | ||
530 | } | ||
531 | |||
532 | badrange_forget(&t->badrange, err_clr->err_inj_clr_spa_range_base, | ||
533 | err_clr->err_inj_clr_spa_range_length); | ||
534 | |||
535 | err_clr->status = 0; | ||
536 | return 0; | ||
537 | |||
538 | err: | ||
539 | err_clr->status = NFIT_ARS_INJECT_INVALID; | ||
540 | return rc; | ||
541 | } | ||
542 | |||
543 | static int nfit_test_cmd_ars_inject_status(struct nfit_test *t, | ||
544 | struct nd_cmd_ars_err_inj_stat *err_stat, | ||
545 | unsigned int buf_len) | ||
546 | { | ||
547 | struct badrange_entry *be; | ||
548 | int max = SZ_4K / sizeof(struct nd_error_stat_query_record); | ||
549 | int i = 0; | ||
550 | |||
551 | err_stat->status = 0; | ||
552 | spin_lock(&t->badrange.lock); | ||
553 | list_for_each_entry(be, &t->badrange.list, list) { | ||
554 | err_stat->record[i].err_inj_stat_spa_range_base = be->start; | ||
555 | err_stat->record[i].err_inj_stat_spa_range_length = be->length; | ||
556 | i++; | ||
557 | if (i > max) | ||
558 | break; | ||
559 | } | ||
560 | spin_unlock(&t->badrange.lock); | ||
561 | err_stat->inj_err_rec_count = i; | ||
562 | |||
563 | return 0; | ||
564 | } | ||
565 | |||
381 | static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, | 566 | static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, |
382 | struct nvdimm *nvdimm, unsigned int cmd, void *buf, | 567 | struct nvdimm *nvdimm, unsigned int cmd, void *buf, |
383 | unsigned int buf_len, int *cmd_rc) | 568 | unsigned int buf_len, int *cmd_rc) |
@@ -449,6 +634,38 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, | |||
449 | } | 634 | } |
450 | } else { | 635 | } else { |
451 | struct ars_state *ars_state = &t->ars_state; | 636 | struct ars_state *ars_state = &t->ars_state; |
637 | struct nd_cmd_pkg *call_pkg = buf; | ||
638 | |||
639 | if (!nd_desc) | ||
640 | return -ENOTTY; | ||
641 | |||
642 | if (cmd == ND_CMD_CALL) { | ||
643 | func = call_pkg->nd_command; | ||
644 | |||
645 | buf_len = call_pkg->nd_size_in + call_pkg->nd_size_out; | ||
646 | buf = (void *) call_pkg->nd_payload; | ||
647 | |||
648 | switch (func) { | ||
649 | case NFIT_CMD_TRANSLATE_SPA: | ||
650 | rc = nfit_test_cmd_translate_spa( | ||
651 | acpi_desc->nvdimm_bus, buf, buf_len); | ||
652 | return rc; | ||
653 | case NFIT_CMD_ARS_INJECT_SET: | ||
654 | rc = nfit_test_cmd_ars_error_inject(t, buf, | ||
655 | buf_len); | ||
656 | return rc; | ||
657 | case NFIT_CMD_ARS_INJECT_CLEAR: | ||
658 | rc = nfit_test_cmd_ars_inject_clear(t, buf, | ||
659 | buf_len); | ||
660 | return rc; | ||
661 | case NFIT_CMD_ARS_INJECT_GET: | ||
662 | rc = nfit_test_cmd_ars_inject_status(t, buf, | ||
663 | buf_len); | ||
664 | return rc; | ||
665 | default: | ||
666 | return -ENOTTY; | ||
667 | } | ||
668 | } | ||
452 | 669 | ||
453 | if (!nd_desc || !test_bit(cmd, &nd_desc->cmd_mask)) | 670 | if (!nd_desc || !test_bit(cmd, &nd_desc->cmd_mask)) |
454 | return -ENOTTY; | 671 | return -ENOTTY; |
@@ -458,15 +675,15 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, | |||
458 | rc = nfit_test_cmd_ars_cap(buf, buf_len); | 675 | rc = nfit_test_cmd_ars_cap(buf, buf_len); |
459 | break; | 676 | break; |
460 | case ND_CMD_ARS_START: | 677 | case ND_CMD_ARS_START: |
461 | rc = nfit_test_cmd_ars_start(ars_state, buf, buf_len, | 678 | rc = nfit_test_cmd_ars_start(t, ars_state, buf, |
462 | cmd_rc); | 679 | buf_len, cmd_rc); |
463 | break; | 680 | break; |
464 | case ND_CMD_ARS_STATUS: | 681 | case ND_CMD_ARS_STATUS: |
465 | rc = nfit_test_cmd_ars_status(ars_state, buf, buf_len, | 682 | rc = nfit_test_cmd_ars_status(ars_state, buf, buf_len, |
466 | cmd_rc); | 683 | cmd_rc); |
467 | break; | 684 | break; |
468 | case ND_CMD_CLEAR_ERROR: | 685 | case ND_CMD_CLEAR_ERROR: |
469 | rc = nfit_test_cmd_clear_error(buf, buf_len, cmd_rc); | 686 | rc = nfit_test_cmd_clear_error(t, buf, buf_len, cmd_rc); |
470 | break; | 687 | break; |
471 | default: | 688 | default: |
472 | return -ENOTTY; | 689 | return -ENOTTY; |
@@ -566,10 +783,9 @@ static struct nfit_test_resource *nfit_test_lookup(resource_size_t addr) | |||
566 | 783 | ||
567 | static int ars_state_init(struct device *dev, struct ars_state *ars_state) | 784 | static int ars_state_init(struct device *dev, struct ars_state *ars_state) |
568 | { | 785 | { |
786 | /* for testing, only store up to n records that fit within 4k */ | ||
569 | ars_state->ars_status = devm_kzalloc(dev, | 787 | ars_state->ars_status = devm_kzalloc(dev, |
570 | sizeof(struct nd_cmd_ars_status) | 788 | sizeof(struct nd_cmd_ars_status) + SZ_4K, GFP_KERNEL); |
571 | + sizeof(struct nd_ars_record) * NFIT_TEST_ARS_RECORDS, | ||
572 | GFP_KERNEL); | ||
573 | if (!ars_state->ars_status) | 789 | if (!ars_state->ars_status) |
574 | return -ENOMEM; | 790 | return -ENOMEM; |
575 | spin_lock_init(&ars_state->lock); | 791 | spin_lock_init(&ars_state->lock); |
@@ -1419,7 +1635,8 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1419 | + i * sizeof(u64); | 1635 | + i * sizeof(u64); |
1420 | } | 1636 | } |
1421 | 1637 | ||
1422 | post_ars_status(&t->ars_state, t->spa_set_dma[0], SPA0_SIZE); | 1638 | post_ars_status(&t->ars_state, &t->badrange, t->spa_set_dma[0], |
1639 | SPA0_SIZE); | ||
1423 | 1640 | ||
1424 | acpi_desc = &t->acpi_desc; | 1641 | acpi_desc = &t->acpi_desc; |
1425 | set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_cmd_force_en); | 1642 | set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_cmd_force_en); |
@@ -1430,7 +1647,12 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1430 | set_bit(ND_CMD_ARS_START, &acpi_desc->bus_cmd_force_en); | 1647 | set_bit(ND_CMD_ARS_START, &acpi_desc->bus_cmd_force_en); |
1431 | set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_cmd_force_en); | 1648 | set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_cmd_force_en); |
1432 | set_bit(ND_CMD_CLEAR_ERROR, &acpi_desc->bus_cmd_force_en); | 1649 | set_bit(ND_CMD_CLEAR_ERROR, &acpi_desc->bus_cmd_force_en); |
1650 | set_bit(ND_CMD_CALL, &acpi_desc->bus_cmd_force_en); | ||
1433 | set_bit(ND_CMD_SMART_THRESHOLD, &acpi_desc->dimm_cmd_force_en); | 1651 | set_bit(ND_CMD_SMART_THRESHOLD, &acpi_desc->dimm_cmd_force_en); |
1652 | set_bit(NFIT_CMD_TRANSLATE_SPA, &acpi_desc->bus_nfit_cmd_force_en); | ||
1653 | set_bit(NFIT_CMD_ARS_INJECT_SET, &acpi_desc->bus_nfit_cmd_force_en); | ||
1654 | set_bit(NFIT_CMD_ARS_INJECT_CLEAR, &acpi_desc->bus_nfit_cmd_force_en); | ||
1655 | set_bit(NFIT_CMD_ARS_INJECT_GET, &acpi_desc->bus_nfit_cmd_force_en); | ||
1434 | } | 1656 | } |
1435 | 1657 | ||
1436 | static void nfit_test1_setup(struct nfit_test *t) | 1658 | static void nfit_test1_setup(struct nfit_test *t) |
@@ -1520,7 +1742,8 @@ static void nfit_test1_setup(struct nfit_test *t) | |||
1520 | dcr->code = NFIT_FIC_BYTE; | 1742 | dcr->code = NFIT_FIC_BYTE; |
1521 | dcr->windows = 0; | 1743 | dcr->windows = 0; |
1522 | 1744 | ||
1523 | post_ars_status(&t->ars_state, t->spa_set_dma[0], SPA2_SIZE); | 1745 | post_ars_status(&t->ars_state, &t->badrange, t->spa_set_dma[0], |
1746 | SPA2_SIZE); | ||
1524 | 1747 | ||
1525 | acpi_desc = &t->acpi_desc; | 1748 | acpi_desc = &t->acpi_desc; |
1526 | set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_cmd_force_en); | 1749 | set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_cmd_force_en); |
@@ -1589,6 +1812,7 @@ static int nfit_ctl_test(struct device *dev) | |||
1589 | unsigned long mask, cmd_size, offset; | 1812 | unsigned long mask, cmd_size, offset; |
1590 | union { | 1813 | union { |
1591 | struct nd_cmd_get_config_size cfg_size; | 1814 | struct nd_cmd_get_config_size cfg_size; |
1815 | struct nd_cmd_clear_error clear_err; | ||
1592 | struct nd_cmd_ars_status ars_stat; | 1816 | struct nd_cmd_ars_status ars_stat; |
1593 | struct nd_cmd_ars_cap ars_cap; | 1817 | struct nd_cmd_ars_cap ars_cap; |
1594 | char buf[sizeof(struct nd_cmd_ars_status) | 1818 | char buf[sizeof(struct nd_cmd_ars_status) |
@@ -1613,10 +1837,15 @@ static int nfit_ctl_test(struct device *dev) | |||
1613 | .cmd_mask = 1UL << ND_CMD_ARS_CAP | 1837 | .cmd_mask = 1UL << ND_CMD_ARS_CAP |
1614 | | 1UL << ND_CMD_ARS_START | 1838 | | 1UL << ND_CMD_ARS_START |
1615 | | 1UL << ND_CMD_ARS_STATUS | 1839 | | 1UL << ND_CMD_ARS_STATUS |
1616 | | 1UL << ND_CMD_CLEAR_ERROR, | 1840 | | 1UL << ND_CMD_CLEAR_ERROR |
1841 | | 1UL << ND_CMD_CALL, | ||
1617 | .module = THIS_MODULE, | 1842 | .module = THIS_MODULE, |
1618 | .provider_name = "ACPI.NFIT", | 1843 | .provider_name = "ACPI.NFIT", |
1619 | .ndctl = acpi_nfit_ctl, | 1844 | .ndctl = acpi_nfit_ctl, |
1845 | .bus_dsm_mask = 1UL << NFIT_CMD_TRANSLATE_SPA | ||
1846 | | 1UL << NFIT_CMD_ARS_INJECT_SET | ||
1847 | | 1UL << NFIT_CMD_ARS_INJECT_CLEAR | ||
1848 | | 1UL << NFIT_CMD_ARS_INJECT_GET, | ||
1620 | }, | 1849 | }, |
1621 | .dev = &adev->dev, | 1850 | .dev = &adev->dev, |
1622 | }; | 1851 | }; |
@@ -1767,6 +1996,23 @@ static int nfit_ctl_test(struct device *dev) | |||
1767 | return -EIO; | 1996 | return -EIO; |
1768 | } | 1997 | } |
1769 | 1998 | ||
1999 | /* test clear error */ | ||
2000 | cmd_size = sizeof(cmds.clear_err); | ||
2001 | cmds.clear_err = (struct nd_cmd_clear_error) { | ||
2002 | .length = 512, | ||
2003 | .cleared = 512, | ||
2004 | }; | ||
2005 | rc = setup_result(cmds.buf, cmd_size); | ||
2006 | if (rc) | ||
2007 | return rc; | ||
2008 | rc = acpi_nfit_ctl(&acpi_desc->nd_desc, NULL, ND_CMD_CLEAR_ERROR, | ||
2009 | cmds.buf, cmd_size, &cmd_rc); | ||
2010 | if (rc < 0 || cmd_rc) { | ||
2011 | dev_dbg(dev, "%s: failed at: %d rc: %d cmd_rc: %d\n", | ||
2012 | __func__, __LINE__, rc, cmd_rc); | ||
2013 | return -EIO; | ||
2014 | } | ||
2015 | |||
1770 | return 0; | 2016 | return 0; |
1771 | } | 2017 | } |
1772 | 2018 | ||
@@ -1915,6 +2161,10 @@ static __init int nfit_test_init(void) | |||
1915 | 2161 | ||
1916 | nfit_test_setup(nfit_test_lookup, nfit_test_evaluate_dsm); | 2162 | nfit_test_setup(nfit_test_lookup, nfit_test_evaluate_dsm); |
1917 | 2163 | ||
2164 | nfit_wq = create_singlethread_workqueue("nfit"); | ||
2165 | if (!nfit_wq) | ||
2166 | return -ENOMEM; | ||
2167 | |||
1918 | nfit_test_dimm = class_create(THIS_MODULE, "nfit_test_dimm"); | 2168 | nfit_test_dimm = class_create(THIS_MODULE, "nfit_test_dimm"); |
1919 | if (IS_ERR(nfit_test_dimm)) { | 2169 | if (IS_ERR(nfit_test_dimm)) { |
1920 | rc = PTR_ERR(nfit_test_dimm); | 2170 | rc = PTR_ERR(nfit_test_dimm); |
@@ -1931,6 +2181,7 @@ static __init int nfit_test_init(void) | |||
1931 | goto err_register; | 2181 | goto err_register; |
1932 | } | 2182 | } |
1933 | INIT_LIST_HEAD(&nfit_test->resources); | 2183 | INIT_LIST_HEAD(&nfit_test->resources); |
2184 | badrange_init(&nfit_test->badrange); | ||
1934 | switch (i) { | 2185 | switch (i) { |
1935 | case 0: | 2186 | case 0: |
1936 | nfit_test->num_pm = NUM_PM; | 2187 | nfit_test->num_pm = NUM_PM; |
@@ -1966,6 +2217,7 @@ static __init int nfit_test_init(void) | |||
1966 | goto err_register; | 2217 | goto err_register; |
1967 | 2218 | ||
1968 | instances[i] = nfit_test; | 2219 | instances[i] = nfit_test; |
2220 | INIT_WORK(&nfit_test->work, uc_error_notify); | ||
1969 | } | 2221 | } |
1970 | 2222 | ||
1971 | rc = platform_driver_register(&nfit_test_driver); | 2223 | rc = platform_driver_register(&nfit_test_driver); |
@@ -1974,6 +2226,7 @@ static __init int nfit_test_init(void) | |||
1974 | return 0; | 2226 | return 0; |
1975 | 2227 | ||
1976 | err_register: | 2228 | err_register: |
2229 | destroy_workqueue(nfit_wq); | ||
1977 | for (i = 0; i < NUM_NFITS; i++) | 2230 | for (i = 0; i < NUM_NFITS; i++) |
1978 | if (instances[i]) | 2231 | if (instances[i]) |
1979 | platform_device_unregister(&instances[i]->pdev); | 2232 | platform_device_unregister(&instances[i]->pdev); |
@@ -1989,6 +2242,8 @@ static __exit void nfit_test_exit(void) | |||
1989 | { | 2242 | { |
1990 | int i; | 2243 | int i; |
1991 | 2244 | ||
2245 | flush_workqueue(nfit_wq); | ||
2246 | destroy_workqueue(nfit_wq); | ||
1992 | for (i = 0; i < NUM_NFITS; i++) | 2247 | for (i = 0; i < NUM_NFITS; i++) |
1993 | platform_device_unregister(&instances[i]->pdev); | 2248 | platform_device_unregister(&instances[i]->pdev); |
1994 | platform_driver_unregister(&nfit_test_driver); | 2249 | platform_driver_unregister(&nfit_test_driver); |
diff --git a/tools/testing/nvdimm/test/nfit_test.h b/tools/testing/nvdimm/test/nfit_test.h index d3d63dd5ed38..113b44675a71 100644 --- a/tools/testing/nvdimm/test/nfit_test.h +++ b/tools/testing/nvdimm/test/nfit_test.h | |||
@@ -32,6 +32,58 @@ struct nfit_test_resource { | |||
32 | void *buf; | 32 | void *buf; |
33 | }; | 33 | }; |
34 | 34 | ||
35 | #define ND_TRANSLATE_SPA_STATUS_INVALID_SPA 2 | ||
36 | #define NFIT_ARS_INJECT_INVALID 2 | ||
37 | |||
38 | enum err_inj_options { | ||
39 | ND_ARS_ERR_INJ_OPT_NOTIFY = 0, | ||
40 | }; | ||
41 | |||
42 | /* nfit commands */ | ||
43 | enum nfit_cmd_num { | ||
44 | NFIT_CMD_TRANSLATE_SPA = 5, | ||
45 | NFIT_CMD_ARS_INJECT_SET = 7, | ||
46 | NFIT_CMD_ARS_INJECT_CLEAR = 8, | ||
47 | NFIT_CMD_ARS_INJECT_GET = 9, | ||
48 | }; | ||
49 | |||
50 | struct nd_cmd_translate_spa { | ||
51 | __u64 spa; | ||
52 | __u32 status; | ||
53 | __u8 flags; | ||
54 | __u8 _reserved[3]; | ||
55 | __u64 translate_length; | ||
56 | __u32 num_nvdimms; | ||
57 | struct nd_nvdimm_device { | ||
58 | __u32 nfit_device_handle; | ||
59 | __u32 _reserved; | ||
60 | __u64 dpa; | ||
61 | } __packed devices[0]; | ||
62 | |||
63 | } __packed; | ||
64 | |||
65 | struct nd_cmd_ars_err_inj { | ||
66 | __u64 err_inj_spa_range_base; | ||
67 | __u64 err_inj_spa_range_length; | ||
68 | __u8 err_inj_options; | ||
69 | __u32 status; | ||
70 | } __packed; | ||
71 | |||
72 | struct nd_cmd_ars_err_inj_clr { | ||
73 | __u64 err_inj_clr_spa_range_base; | ||
74 | __u64 err_inj_clr_spa_range_length; | ||
75 | __u32 status; | ||
76 | } __packed; | ||
77 | |||
78 | struct nd_cmd_ars_err_inj_stat { | ||
79 | __u32 status; | ||
80 | __u32 inj_err_rec_count; | ||
81 | struct nd_error_stat_query_record { | ||
82 | __u64 err_inj_stat_spa_range_base; | ||
83 | __u64 err_inj_stat_spa_range_length; | ||
84 | } __packed record[0]; | ||
85 | } __packed; | ||
86 | |||
35 | union acpi_object; | 87 | union acpi_object; |
36 | typedef void *acpi_handle; | 88 | typedef void *acpi_handle; |
37 | 89 | ||
diff --git a/tools/testing/radix-tree/multiorder.c b/tools/testing/radix-tree/multiorder.c index 06c71178d07d..59245b3d587c 100644 --- a/tools/testing/radix-tree/multiorder.c +++ b/tools/testing/radix-tree/multiorder.c | |||
@@ -618,7 +618,7 @@ static void multiorder_account(void) | |||
618 | __radix_tree_insert(&tree, 1 << 5, 5, (void *)0x12); | 618 | __radix_tree_insert(&tree, 1 << 5, 5, (void *)0x12); |
619 | __radix_tree_lookup(&tree, 1 << 5, &node, &slot); | 619 | __radix_tree_lookup(&tree, 1 << 5, &node, &slot); |
620 | assert(node->count == node->exceptional * 2); | 620 | assert(node->count == node->exceptional * 2); |
621 | __radix_tree_replace(&tree, node, slot, NULL, NULL, NULL); | 621 | __radix_tree_replace(&tree, node, slot, NULL, NULL); |
622 | assert(node->exceptional == 0); | 622 | assert(node->exceptional == 0); |
623 | 623 | ||
624 | item_kill_tree(&tree); | 624 | item_kill_tree(&tree); |
diff --git a/tools/testing/scatterlist/Makefile b/tools/testing/scatterlist/Makefile new file mode 100644 index 000000000000..933c3a6e4d77 --- /dev/null +++ b/tools/testing/scatterlist/Makefile | |||
@@ -0,0 +1,30 @@ | |||
1 | CFLAGS += -I. -I../../include -g -O2 -Wall -fsanitize=address | ||
2 | LDFLAGS += -fsanitize=address -fsanitize=undefined | ||
3 | TARGETS = main | ||
4 | OFILES = main.o scatterlist.o | ||
5 | |||
6 | ifeq ($(BUILD), 32) | ||
7 | CFLAGS += -m32 | ||
8 | LDFLAGS += -m32 | ||
9 | endif | ||
10 | |||
11 | targets: include $(TARGETS) | ||
12 | |||
13 | main: $(OFILES) | ||
14 | |||
15 | clean: | ||
16 | $(RM) $(TARGETS) $(OFILES) scatterlist.c linux/scatterlist.h linux/highmem.h linux/kmemleak.h asm/io.h | ||
17 | @rmdir asm | ||
18 | |||
19 | scatterlist.c: ../../../lib/scatterlist.c | ||
20 | @sed -e 's/^static //' -e 's/__always_inline //' -e 's/inline //' < $< > $@ | ||
21 | |||
22 | .PHONY: include | ||
23 | |||
24 | include: ../../../include/linux/scatterlist.h | ||
25 | @mkdir -p linux | ||
26 | @mkdir -p asm | ||
27 | @touch asm/io.h | ||
28 | @touch linux/highmem.h | ||
29 | @touch linux/kmemleak.h | ||
30 | @cp $< linux/scatterlist.h | ||
diff --git a/tools/testing/scatterlist/linux/mm.h b/tools/testing/scatterlist/linux/mm.h new file mode 100644 index 000000000000..6f9ac14aa800 --- /dev/null +++ b/tools/testing/scatterlist/linux/mm.h | |||
@@ -0,0 +1,125 @@ | |||
1 | #ifndef _LINUX_MM_H | ||
2 | #define _LINUX_MM_H | ||
3 | |||
4 | #include <assert.h> | ||
5 | #include <string.h> | ||
6 | #include <stdlib.h> | ||
7 | #include <errno.h> | ||
8 | #include <limits.h> | ||
9 | #include <stdio.h> | ||
10 | |||
11 | typedef unsigned long dma_addr_t; | ||
12 | |||
13 | #define unlikely | ||
14 | |||
15 | #define BUG_ON(x) assert(!(x)) | ||
16 | |||
17 | #define WARN_ON(condition) ({ \ | ||
18 | int __ret_warn_on = !!(condition); \ | ||
19 | unlikely(__ret_warn_on); \ | ||
20 | }) | ||
21 | |||
22 | #define WARN_ON_ONCE(condition) ({ \ | ||
23 | int __ret_warn_on = !!(condition); \ | ||
24 | if (unlikely(__ret_warn_on)) \ | ||
25 | assert(0); \ | ||
26 | unlikely(__ret_warn_on); \ | ||
27 | }) | ||
28 | |||
29 | #define PAGE_SIZE (4096) | ||
30 | #define PAGE_SHIFT (12) | ||
31 | #define PAGE_MASK (~(PAGE_SIZE-1)) | ||
32 | |||
33 | #define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1) | ||
34 | #define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask)) | ||
35 | #define ALIGN(x, a) __ALIGN_KERNEL((x), (a)) | ||
36 | |||
37 | #define PAGE_ALIGN(addr) ALIGN(addr, PAGE_SIZE) | ||
38 | |||
39 | #define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK) | ||
40 | |||
41 | #define virt_to_page(x) ((void *)x) | ||
42 | #define page_address(x) ((void *)x) | ||
43 | |||
44 | static inline unsigned long page_to_phys(struct page *page) | ||
45 | { | ||
46 | assert(0); | ||
47 | |||
48 | return 0; | ||
49 | } | ||
50 | |||
51 | #define page_to_pfn(page) ((unsigned long)(page) / PAGE_SIZE) | ||
52 | #define pfn_to_page(pfn) (void *)((pfn) * PAGE_SIZE) | ||
53 | #define nth_page(page,n) pfn_to_page(page_to_pfn((page)) + (n)) | ||
54 | |||
55 | #define __min(t1, t2, min1, min2, x, y) ({ \ | ||
56 | t1 min1 = (x); \ | ||
57 | t2 min2 = (y); \ | ||
58 | (void) (&min1 == &min2); \ | ||
59 | min1 < min2 ? min1 : min2; }) | ||
60 | |||
61 | #define ___PASTE(a,b) a##b | ||
62 | #define __PASTE(a,b) ___PASTE(a,b) | ||
63 | |||
64 | #define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__) | ||
65 | |||
66 | #define min(x, y) \ | ||
67 | __min(typeof(x), typeof(y), \ | ||
68 | __UNIQUE_ID(min1_), __UNIQUE_ID(min2_), \ | ||
69 | x, y) | ||
70 | |||
71 | #define min_t(type, x, y) \ | ||
72 | __min(type, type, \ | ||
73 | __UNIQUE_ID(min1_), __UNIQUE_ID(min2_), \ | ||
74 | x, y) | ||
75 | |||
76 | #define preemptible() (1) | ||
77 | |||
78 | static inline void *kmap(struct page *page) | ||
79 | { | ||
80 | assert(0); | ||
81 | |||
82 | return NULL; | ||
83 | } | ||
84 | |||
85 | static inline void *kmap_atomic(struct page *page) | ||
86 | { | ||
87 | assert(0); | ||
88 | |||
89 | return NULL; | ||
90 | } | ||
91 | |||
92 | static inline void kunmap(void *addr) | ||
93 | { | ||
94 | assert(0); | ||
95 | } | ||
96 | |||
97 | static inline void kunmap_atomic(void *addr) | ||
98 | { | ||
99 | assert(0); | ||
100 | } | ||
101 | |||
102 | static inline unsigned long __get_free_page(unsigned int flags) | ||
103 | { | ||
104 | return (unsigned long)malloc(PAGE_SIZE); | ||
105 | } | ||
106 | |||
107 | static inline void free_page(unsigned long page) | ||
108 | { | ||
109 | free((void *)page); | ||
110 | } | ||
111 | |||
112 | static inline void *kmalloc(unsigned int size, unsigned int flags) | ||
113 | { | ||
114 | return malloc(size); | ||
115 | } | ||
116 | |||
117 | #define kfree(x) free(x) | ||
118 | |||
119 | #define kmemleak_alloc(a, b, c, d) | ||
120 | #define kmemleak_free(a) | ||
121 | |||
122 | #define PageSlab(p) (0) | ||
123 | #define flush_kernel_dcache_page(p) | ||
124 | |||
125 | #endif | ||
diff --git a/tools/testing/scatterlist/main.c b/tools/testing/scatterlist/main.c new file mode 100644 index 000000000000..0a1464181226 --- /dev/null +++ b/tools/testing/scatterlist/main.c | |||
@@ -0,0 +1,79 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <assert.h> | ||
3 | |||
4 | #include <linux/scatterlist.h> | ||
5 | |||
6 | #define MAX_PAGES (64) | ||
7 | |||
8 | static void set_pages(struct page **pages, const unsigned *array, unsigned num) | ||
9 | { | ||
10 | unsigned int i; | ||
11 | |||
12 | assert(num < MAX_PAGES); | ||
13 | for (i = 0; i < num; i++) | ||
14 | pages[i] = (struct page *)(unsigned long) | ||
15 | ((1 + array[i]) * PAGE_SIZE); | ||
16 | } | ||
17 | |||
18 | #define pfn(...) (unsigned []){ __VA_ARGS__ } | ||
19 | |||
20 | int main(void) | ||
21 | { | ||
22 | const unsigned int sgmax = SCATTERLIST_MAX_SEGMENT; | ||
23 | struct test { | ||
24 | int alloc_ret; | ||
25 | unsigned num_pages; | ||
26 | unsigned *pfn; | ||
27 | unsigned size; | ||
28 | unsigned int max_seg; | ||
29 | unsigned int expected_segments; | ||
30 | } *test, tests[] = { | ||
31 | { -EINVAL, 1, pfn(0), PAGE_SIZE, PAGE_SIZE + 1, 1 }, | ||
32 | { -EINVAL, 1, pfn(0), PAGE_SIZE, 0, 1 }, | ||
33 | { -EINVAL, 1, pfn(0), PAGE_SIZE, sgmax + 1, 1 }, | ||
34 | { 0, 1, pfn(0), PAGE_SIZE, sgmax, 1 }, | ||
35 | { 0, 1, pfn(0), 1, sgmax, 1 }, | ||
36 | { 0, 2, pfn(0, 1), 2 * PAGE_SIZE, sgmax, 1 }, | ||
37 | { 0, 2, pfn(1, 0), 2 * PAGE_SIZE, sgmax, 2 }, | ||
38 | { 0, 3, pfn(0, 1, 2), 3 * PAGE_SIZE, sgmax, 1 }, | ||
39 | { 0, 3, pfn(0, 2, 1), 3 * PAGE_SIZE, sgmax, 3 }, | ||
40 | { 0, 3, pfn(0, 1, 3), 3 * PAGE_SIZE, sgmax, 2 }, | ||
41 | { 0, 3, pfn(1, 2, 4), 3 * PAGE_SIZE, sgmax, 2 }, | ||
42 | { 0, 3, pfn(1, 3, 4), 3 * PAGE_SIZE, sgmax, 2 }, | ||
43 | { 0, 4, pfn(0, 1, 3, 4), 4 * PAGE_SIZE, sgmax, 2 }, | ||
44 | { 0, 5, pfn(0, 1, 3, 4, 5), 5 * PAGE_SIZE, sgmax, 2 }, | ||
45 | { 0, 5, pfn(0, 1, 3, 4, 6), 5 * PAGE_SIZE, sgmax, 3 }, | ||
46 | { 0, 5, pfn(0, 1, 2, 3, 4), 5 * PAGE_SIZE, sgmax, 1 }, | ||
47 | { 0, 5, pfn(0, 1, 2, 3, 4), 5 * PAGE_SIZE, 2 * PAGE_SIZE, 3 }, | ||
48 | { 0, 6, pfn(0, 1, 2, 3, 4, 5), 6 * PAGE_SIZE, 2 * PAGE_SIZE, 3 }, | ||
49 | { 0, 6, pfn(0, 2, 3, 4, 5, 6), 6 * PAGE_SIZE, 2 * PAGE_SIZE, 4 }, | ||
50 | { 0, 6, pfn(0, 1, 3, 4, 5, 6), 6 * PAGE_SIZE, 2 * PAGE_SIZE, 3 }, | ||
51 | { 0, 0, NULL, 0, 0, 0 }, | ||
52 | }; | ||
53 | unsigned int i; | ||
54 | |||
55 | for (i = 0, test = tests; test->expected_segments; test++, i++) { | ||
56 | struct page *pages[MAX_PAGES]; | ||
57 | struct sg_table st; | ||
58 | int ret; | ||
59 | |||
60 | set_pages(pages, test->pfn, test->num_pages); | ||
61 | |||
62 | ret = __sg_alloc_table_from_pages(&st, pages, test->num_pages, | ||
63 | 0, test->size, test->max_seg, | ||
64 | GFP_KERNEL); | ||
65 | assert(ret == test->alloc_ret); | ||
66 | |||
67 | if (test->alloc_ret) | ||
68 | continue; | ||
69 | |||
70 | assert(st.nents == test->expected_segments); | ||
71 | assert(st.orig_nents == test->expected_segments); | ||
72 | |||
73 | sg_free_table(&st); | ||
74 | } | ||
75 | |||
76 | assert(i == (sizeof(tests) / sizeof(tests[0])) - 1); | ||
77 | |||
78 | return 0; | ||
79 | } | ||
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 3c9c0bbe7dbb..eaf599dc2137 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile | |||
@@ -1,5 +1,6 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 | 1 | # SPDX-License-Identifier: GPL-2.0 |
2 | TARGETS = bpf | 2 | TARGETS = android |
3 | TARGETS += bpf | ||
3 | TARGETS += breakpoints | 4 | TARGETS += breakpoints |
4 | TARGETS += capabilities | 5 | TARGETS += capabilities |
5 | TARGETS += cpufreq | 6 | TARGETS += cpufreq |
diff --git a/tools/testing/selftests/android/Makefile b/tools/testing/selftests/android/Makefile new file mode 100644 index 000000000000..1a7492268993 --- /dev/null +++ b/tools/testing/selftests/android/Makefile | |||
@@ -0,0 +1,46 @@ | |||
1 | SUBDIRS := ion | ||
2 | |||
3 | TEST_PROGS := run.sh | ||
4 | |||
5 | .PHONY: all clean | ||
6 | |||
7 | include ../lib.mk | ||
8 | |||
9 | all: | ||
10 | @for DIR in $(SUBDIRS); do \ | ||
11 | BUILD_TARGET=$(OUTPUT)/$$DIR; \ | ||
12 | mkdir $$BUILD_TARGET -p; \ | ||
13 | make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\ | ||
14 | #SUBDIR test prog name should be in the form: SUBDIR_test.sh | ||
15 | TEST=$$DIR"_test.sh"; \ | ||
16 | if [ -e $$DIR/$$TEST ]; then | ||
17 | rsync -a $$DIR/$$TEST $$BUILD_TARGET/; | ||
18 | fi | ||
19 | done | ||
20 | |||
21 | override define RUN_TESTS | ||
22 | @cd $(OUTPUT); ./run.sh | ||
23 | endef | ||
24 | |||
25 | override define INSTALL_RULE | ||
26 | mkdir -p $(INSTALL_PATH) | ||
27 | install -t $(INSTALL_PATH) $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES) | ||
28 | |||
29 | @for SUBDIR in $(SUBDIRS); do \ | ||
30 | BUILD_TARGET=$(OUTPUT)/$$SUBDIR; \ | ||
31 | mkdir $$BUILD_TARGET -p; \ | ||
32 | $(MAKE) OUTPUT=$$BUILD_TARGET -C $$SUBDIR INSTALL_PATH=$(INSTALL_PATH)/$$SUBDIR install; \ | ||
33 | done; | ||
34 | endef | ||
35 | |||
36 | override define EMIT_TESTS | ||
37 | echo "./run.sh" | ||
38 | endef | ||
39 | |||
40 | override define CLEAN | ||
41 | @for DIR in $(SUBDIRS); do \ | ||
42 | BUILD_TARGET=$(OUTPUT)/$$DIR; \ | ||
43 | mkdir $$BUILD_TARGET -p; \ | ||
44 | make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\ | ||
45 | done | ||
46 | endef | ||
diff --git a/tools/testing/selftests/android/ion/.gitignore b/tools/testing/selftests/android/ion/.gitignore new file mode 100644 index 000000000000..67e6f391b2a9 --- /dev/null +++ b/tools/testing/selftests/android/ion/.gitignore | |||
@@ -0,0 +1,2 @@ | |||
1 | ionapp_export | ||
2 | ionapp_import | ||
diff --git a/tools/testing/selftests/android/ion/Makefile b/tools/testing/selftests/android/ion/Makefile new file mode 100644 index 000000000000..96e0c448b39d --- /dev/null +++ b/tools/testing/selftests/android/ion/Makefile | |||
@@ -0,0 +1,16 @@ | |||
1 | |||
2 | INCLUDEDIR := -I. -I../../../../../drivers/staging/android/uapi/ | ||
3 | CFLAGS := $(CFLAGS) $(INCLUDEDIR) -Wall -O2 -g | ||
4 | |||
5 | TEST_GEN_FILES := ionapp_export ionapp_import | ||
6 | |||
7 | all: $(TEST_GEN_FILES) | ||
8 | |||
9 | $(TEST_GEN_FILES): ipcsocket.c ionutils.c | ||
10 | |||
11 | TEST_PROGS := ion_test.sh | ||
12 | |||
13 | include ../../lib.mk | ||
14 | |||
15 | $(OUTPUT)/ionapp_export: ionapp_export.c ipcsocket.c ionutils.c | ||
16 | $(OUTPUT)/ionapp_import: ionapp_import.c ipcsocket.c ionutils.c | ||
diff --git a/tools/testing/selftests/android/ion/README b/tools/testing/selftests/android/ion/README new file mode 100644 index 000000000000..21783e9c451e --- /dev/null +++ b/tools/testing/selftests/android/ion/README | |||
@@ -0,0 +1,101 @@ | |||
1 | ION BUFFER SHARING UTILITY | ||
2 | ========================== | ||
3 | File: ion_test.sh : Utility to test ION driver buffer sharing mechanism. | ||
4 | Author: Pintu Kumar <pintu.ping@gmail.com> | ||
5 | |||
6 | Introduction: | ||
7 | ------------- | ||
8 | This is a test utility to verify ION buffer sharing in user space | ||
9 | between 2 independent processes. | ||
10 | It uses unix domain socket (with SCM_RIGHTS) as IPC to transfer an FD to | ||
11 | another process to share the same buffer. | ||
12 | This utility demonstrates how ION buffer sharing can be implemented between | ||
13 | two user space processes, using various heap types. | ||
14 | The following heap types are supported by ION driver. | ||
15 | ION_HEAP_TYPE_SYSTEM (0) | ||
16 | ION_HEAP_TYPE_SYSTEM_CONTIG (1) | ||
17 | ION_HEAP_TYPE_CARVEOUT (2) | ||
18 | ION_HEAP_TYPE_CHUNK (3) | ||
19 | ION_HEAP_TYPE_DMA (4) | ||
20 | |||
21 | By default only the SYSTEM and SYSTEM_CONTIG heaps are supported. | ||
22 | Each heap is associated with the respective heap id. | ||
23 | This utility is designed in the form of client/server program. | ||
24 | The server part (ionapp_export) is the exporter of the buffer. | ||
25 | It is responsible for creating an ION client, allocating the buffer based on | ||
26 | the heap id, writing some data to this buffer and then exporting the FD | ||
27 | (associated with this buffer) to another process using socket IPC. | ||
28 | This FD is called as buffer FD (which is different than the ION client FD). | ||
29 | |||
30 | The client part (ionapp_import) is the importer of the buffer. | ||
31 | It retrives the FD from the socket data and installs into its address space. | ||
32 | This new FD internally points to the same kernel buffer. | ||
33 | So first it reads the data that is stored in this buffer and prints it. | ||
34 | Then it writes the different size of data (it could be different data) to the | ||
35 | same buffer. | ||
36 | Finally the buffer FD must be closed by both the exporter and importer. | ||
37 | Thus the same kernel buffer is shared among two user space processes using | ||
38 | ION driver and only one time allocation. | ||
39 | |||
40 | Prerequisite: | ||
41 | ------------- | ||
42 | This utility works only if /dev/ion interface is present. | ||
43 | The following configs needs to be enabled in kernel to include ion driver. | ||
44 | CONFIG_ANDROID=y | ||
45 | CONFIG_STAGING=y | ||
46 | CONFIG_ION=y | ||
47 | CONFIG_ION_SYSTEM_HEAP=y | ||
48 | |||
49 | This utility requires to be run as root user. | ||
50 | |||
51 | |||
52 | Compile and test: | ||
53 | ----------------- | ||
54 | This utility is made to be run as part of kselftest framework in kernel. | ||
55 | To compile and run using kselftest you can simply do the following from the | ||
56 | kernel top directory. | ||
57 | linux$ make TARGETS=android kselftest | ||
58 | Or you can also use: | ||
59 | linux$ make -C tools/testing/selftests TARGETS=android run_tests | ||
60 | Using the selftest it can directly execute the ion_test.sh script to test the | ||
61 | buffer sharing using ion system heap. | ||
62 | Currently the heap size is hard coded as just 10 bytes inside this script. | ||
63 | You need to be a root user to run under selftest. | ||
64 | |||
65 | You can also compile and test manually using the following steps: | ||
66 | ion$ make | ||
67 | These will generate 2 executable: ionapp_export, ionapp_import | ||
68 | Now you can run the export and import manually by specifying the heap type | ||
69 | and the heap size. | ||
70 | You can also directly execute the shell script to run the test automatically. | ||
71 | Simply use the following command to run the test. | ||
72 | ion$ sudo ./ion_test.sh | ||
73 | |||
74 | Test Results: | ||
75 | ------------- | ||
76 | The utility is verified on Ubuntu-32 bit system with Linux Kernel 4.14. | ||
77 | Here is the snapshot of the test result using kselftest. | ||
78 | |||
79 | linux# make TARGETS=android kselftest | ||
80 | heap_type: 0, heap_size: 10 | ||
81 | -------------------------------------- | ||
82 | heap type: 0 | ||
83 | heap id: 1 | ||
84 | heap name: ion_system_heap | ||
85 | -------------------------------------- | ||
86 | Fill buffer content: | ||
87 | 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd | ||
88 | Sharing fd: 6, Client fd: 5 | ||
89 | <ion_close_buffer_fd>: buffer release successfully.... | ||
90 | Received buffer fd: 4 | ||
91 | Read buffer content: | ||
92 | 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0x0 0x0 0x0 0x0 0x0 0x0 | ||
93 | 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 | ||
94 | Fill buffer content: | ||
95 | 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd | ||
96 | 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd | ||
97 | 0xfd 0xfd | ||
98 | <ion_close_buffer_fd>: buffer release successfully.... | ||
99 | ion_test.sh: heap_type: 0 - [PASS] | ||
100 | |||
101 | ion_test.sh: done | ||
diff --git a/tools/testing/selftests/android/ion/config b/tools/testing/selftests/android/ion/config new file mode 100644 index 000000000000..19db6ca9aa2b --- /dev/null +++ b/tools/testing/selftests/android/ion/config | |||
@@ -0,0 +1,4 @@ | |||
1 | CONFIG_ANDROID=y | ||
2 | CONFIG_STAGING=y | ||
3 | CONFIG_ION=y | ||
4 | CONFIG_ION_SYSTEM_HEAP=y | ||
diff --git a/tools/testing/selftests/android/ion/ion.h b/tools/testing/selftests/android/ion/ion.h new file mode 100644 index 000000000000..f7021ac51335 --- /dev/null +++ b/tools/testing/selftests/android/ion/ion.h | |||
@@ -0,0 +1,143 @@ | |||
1 | /* | ||
2 | * ion.h | ||
3 | * | ||
4 | * Copyright (C) 2011 Google, Inc. | ||
5 | * | ||
6 | * This software is licensed under the terms of the GNU General Public | ||
7 | * License version 2, as published by the Free Software Foundation, and | ||
8 | * may be copied, distributed, and modified under those terms. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | /* This file is copied from drivers/staging/android/uapi/ion.h | ||
18 | * This local copy is required for the selftest to pass, when build | ||
19 | * outside the kernel source tree. | ||
20 | * Please keep this file in sync with its original file until the | ||
21 | * ion driver is moved outside the staging tree. | ||
22 | */ | ||
23 | |||
24 | #ifndef _UAPI_LINUX_ION_H | ||
25 | #define _UAPI_LINUX_ION_H | ||
26 | |||
27 | #include <linux/ioctl.h> | ||
28 | #include <linux/types.h> | ||
29 | |||
30 | /** | ||
31 | * enum ion_heap_types - list of all possible types of heaps | ||
32 | * @ION_HEAP_TYPE_SYSTEM: memory allocated via vmalloc | ||
33 | * @ION_HEAP_TYPE_SYSTEM_CONTIG: memory allocated via kmalloc | ||
34 | * @ION_HEAP_TYPE_CARVEOUT: memory allocated from a prereserved | ||
35 | * carveout heap, allocations are physically | ||
36 | * contiguous | ||
37 | * @ION_HEAP_TYPE_DMA: memory allocated via DMA API | ||
38 | * @ION_NUM_HEAPS: helper for iterating over heaps, a bit mask | ||
39 | * is used to identify the heaps, so only 32 | ||
40 | * total heap types are supported | ||
41 | */ | ||
42 | enum ion_heap_type { | ||
43 | ION_HEAP_TYPE_SYSTEM, | ||
44 | ION_HEAP_TYPE_SYSTEM_CONTIG, | ||
45 | ION_HEAP_TYPE_CARVEOUT, | ||
46 | ION_HEAP_TYPE_CHUNK, | ||
47 | ION_HEAP_TYPE_DMA, | ||
48 | ION_HEAP_TYPE_CUSTOM, /* | ||
49 | * must be last so device specific heaps always | ||
50 | * are at the end of this enum | ||
51 | */ | ||
52 | }; | ||
53 | |||
54 | #define ION_NUM_HEAP_IDS (sizeof(unsigned int) * 8) | ||
55 | |||
56 | /** | ||
57 | * allocation flags - the lower 16 bits are used by core ion, the upper 16 | ||
58 | * bits are reserved for use by the heaps themselves. | ||
59 | */ | ||
60 | |||
61 | /* | ||
62 | * mappings of this buffer should be cached, ion will do cache maintenance | ||
63 | * when the buffer is mapped for dma | ||
64 | */ | ||
65 | #define ION_FLAG_CACHED 1 | ||
66 | |||
67 | /** | ||
68 | * DOC: Ion Userspace API | ||
69 | * | ||
70 | * create a client by opening /dev/ion | ||
71 | * most operations handled via following ioctls | ||
72 | * | ||
73 | */ | ||
74 | |||
75 | /** | ||
76 | * struct ion_allocation_data - metadata passed from userspace for allocations | ||
77 | * @len: size of the allocation | ||
78 | * @heap_id_mask: mask of heap ids to allocate from | ||
79 | * @flags: flags passed to heap | ||
80 | * @handle: pointer that will be populated with a cookie to use to | ||
81 | * refer to this allocation | ||
82 | * | ||
83 | * Provided by userspace as an argument to the ioctl | ||
84 | */ | ||
85 | struct ion_allocation_data { | ||
86 | __u64 len; | ||
87 | __u32 heap_id_mask; | ||
88 | __u32 flags; | ||
89 | __u32 fd; | ||
90 | __u32 unused; | ||
91 | }; | ||
92 | |||
93 | #define MAX_HEAP_NAME 32 | ||
94 | |||
95 | /** | ||
96 | * struct ion_heap_data - data about a heap | ||
97 | * @name - first 32 characters of the heap name | ||
98 | * @type - heap type | ||
99 | * @heap_id - heap id for the heap | ||
100 | */ | ||
101 | struct ion_heap_data { | ||
102 | char name[MAX_HEAP_NAME]; | ||
103 | __u32 type; | ||
104 | __u32 heap_id; | ||
105 | __u32 reserved0; | ||
106 | __u32 reserved1; | ||
107 | __u32 reserved2; | ||
108 | }; | ||
109 | |||
110 | /** | ||
111 | * struct ion_heap_query - collection of data about all heaps | ||
112 | * @cnt - total number of heaps to be copied | ||
113 | * @heaps - buffer to copy heap data | ||
114 | */ | ||
115 | struct ion_heap_query { | ||
116 | __u32 cnt; /* Total number of heaps to be copied */ | ||
117 | __u32 reserved0; /* align to 64bits */ | ||
118 | __u64 heaps; /* buffer to be populated */ | ||
119 | __u32 reserved1; | ||
120 | __u32 reserved2; | ||
121 | }; | ||
122 | |||
123 | #define ION_IOC_MAGIC 'I' | ||
124 | |||
125 | /** | ||
126 | * DOC: ION_IOC_ALLOC - allocate memory | ||
127 | * | ||
128 | * Takes an ion_allocation_data struct and returns it with the handle field | ||
129 | * populated with the opaque handle for the allocation. | ||
130 | */ | ||
131 | #define ION_IOC_ALLOC _IOWR(ION_IOC_MAGIC, 0, \ | ||
132 | struct ion_allocation_data) | ||
133 | |||
134 | /** | ||
135 | * DOC: ION_IOC_HEAP_QUERY - information about available heaps | ||
136 | * | ||
137 | * Takes an ion_heap_query structure and populates information about | ||
138 | * available Ion heaps. | ||
139 | */ | ||
140 | #define ION_IOC_HEAP_QUERY _IOWR(ION_IOC_MAGIC, 8, \ | ||
141 | struct ion_heap_query) | ||
142 | |||
143 | #endif /* _UAPI_LINUX_ION_H */ | ||
diff --git a/tools/testing/selftests/android/ion/ion_test.sh b/tools/testing/selftests/android/ion/ion_test.sh new file mode 100755 index 000000000000..a1aff506f5e6 --- /dev/null +++ b/tools/testing/selftests/android/ion/ion_test.sh | |||
@@ -0,0 +1,55 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | heapsize=4096 | ||
4 | TCID="ion_test.sh" | ||
5 | errcode=0 | ||
6 | |||
7 | run_test() | ||
8 | { | ||
9 | heaptype=$1 | ||
10 | ./ionapp_export -i $heaptype -s $heapsize & | ||
11 | sleep 1 | ||
12 | ./ionapp_import | ||
13 | if [ $? -ne 0 ]; then | ||
14 | echo "$TCID: heap_type: $heaptype - [FAIL]" | ||
15 | errcode=1 | ||
16 | else | ||
17 | echo "$TCID: heap_type: $heaptype - [PASS]" | ||
18 | fi | ||
19 | sleep 1 | ||
20 | echo "" | ||
21 | } | ||
22 | |||
23 | check_root() | ||
24 | { | ||
25 | uid=$(id -u) | ||
26 | if [ $uid -ne 0 ]; then | ||
27 | echo $TCID: must be run as root >&2 | ||
28 | exit 0 | ||
29 | fi | ||
30 | } | ||
31 | |||
32 | check_device() | ||
33 | { | ||
34 | DEVICE=/dev/ion | ||
35 | if [ ! -e $DEVICE ]; then | ||
36 | echo $TCID: No $DEVICE device found >&2 | ||
37 | echo $TCID: May be CONFIG_ION is not set >&2 | ||
38 | exit 0 | ||
39 | fi | ||
40 | } | ||
41 | |||
42 | main_function() | ||
43 | { | ||
44 | check_device | ||
45 | check_root | ||
46 | |||
47 | # ION_SYSTEM_HEAP TEST | ||
48 | run_test 0 | ||
49 | # ION_SYSTEM_CONTIG_HEAP TEST | ||
50 | run_test 1 | ||
51 | } | ||
52 | |||
53 | main_function | ||
54 | echo "$TCID: done" | ||
55 | exit $errcode | ||
diff --git a/tools/testing/selftests/android/ion/ionapp_export.c b/tools/testing/selftests/android/ion/ionapp_export.c new file mode 100644 index 000000000000..a944e72621a9 --- /dev/null +++ b/tools/testing/selftests/android/ion/ionapp_export.c | |||
@@ -0,0 +1,135 @@ | |||
1 | /* | ||
2 | * ionapp_export.c | ||
3 | * | ||
4 | * It is a user space utility to create and export android | ||
5 | * ion memory buffer fd to another process using unix domain socket as IPC. | ||
6 | * This acts like a server for ionapp_import(client). | ||
7 | * So, this server has to be started first before the client. | ||
8 | * | ||
9 | * Copyright (C) 2017 Pintu Kumar <pintu.ping@gmail.com> | ||
10 | * | ||
11 | * This software is licensed under the terms of the GNU General Public | ||
12 | * License version 2, as published by the Free Software Foundation, and | ||
13 | * may be copied, distributed, and modified under those terms. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <stdio.h> | ||
23 | #include <stdlib.h> | ||
24 | #include <string.h> | ||
25 | #include <unistd.h> | ||
26 | #include <errno.h> | ||
27 | #include <sys/time.h> | ||
28 | #include "ionutils.h" | ||
29 | #include "ipcsocket.h" | ||
30 | |||
31 | |||
32 | void print_usage(int argc, char *argv[]) | ||
33 | { | ||
34 | printf("Usage: %s [-h <help>] [-i <heap id>] [-s <size in bytes>]\n", | ||
35 | argv[0]); | ||
36 | } | ||
37 | |||
38 | int main(int argc, char *argv[]) | ||
39 | { | ||
40 | int opt, ret, status, heapid; | ||
41 | int sockfd, client_fd, shared_fd; | ||
42 | unsigned char *map_buf; | ||
43 | unsigned long map_len, heap_type, heap_size, flags; | ||
44 | struct ion_buffer_info info; | ||
45 | struct socket_info skinfo; | ||
46 | |||
47 | if (argc < 2) { | ||
48 | print_usage(argc, argv); | ||
49 | return -1; | ||
50 | } | ||
51 | |||
52 | heap_size = 0; | ||
53 | flags = 0; | ||
54 | |||
55 | while ((opt = getopt(argc, argv, "hi:s:")) != -1) { | ||
56 | switch (opt) { | ||
57 | case 'h': | ||
58 | print_usage(argc, argv); | ||
59 | exit(0); | ||
60 | break; | ||
61 | case 'i': | ||
62 | heapid = atoi(optarg); | ||
63 | switch (heapid) { | ||
64 | case 0: | ||
65 | heap_type = ION_HEAP_TYPE_SYSTEM; | ||
66 | break; | ||
67 | case 1: | ||
68 | heap_type = ION_HEAP_TYPE_SYSTEM_CONTIG; | ||
69 | break; | ||
70 | default: | ||
71 | printf("ERROR: heap type not supported\n"); | ||
72 | exit(1); | ||
73 | } | ||
74 | break; | ||
75 | case 's': | ||
76 | heap_size = atoi(optarg); | ||
77 | break; | ||
78 | default: | ||
79 | print_usage(argc, argv); | ||
80 | exit(1); | ||
81 | break; | ||
82 | } | ||
83 | } | ||
84 | |||
85 | if (heap_size <= 0) { | ||
86 | printf("heap_size cannot be 0\n"); | ||
87 | print_usage(argc, argv); | ||
88 | exit(1); | ||
89 | } | ||
90 | |||
91 | printf("heap_type: %ld, heap_size: %ld\n", heap_type, heap_size); | ||
92 | info.heap_type = heap_type; | ||
93 | info.heap_size = heap_size; | ||
94 | info.flag_type = flags; | ||
95 | |||
96 | /* This is server: open the socket connection first */ | ||
97 | /* Here; 1 indicates server or exporter */ | ||
98 | status = opensocket(&sockfd, SOCKET_NAME, 1); | ||
99 | if (status < 0) { | ||
100 | fprintf(stderr, "<%s>: Failed opensocket.\n", __func__); | ||
101 | goto err_socket; | ||
102 | } | ||
103 | skinfo.sockfd = sockfd; | ||
104 | |||
105 | ret = ion_export_buffer_fd(&info); | ||
106 | if (ret < 0) { | ||
107 | fprintf(stderr, "FAILED: ion_get_buffer_fd\n"); | ||
108 | goto err_export; | ||
109 | } | ||
110 | client_fd = info.ionfd; | ||
111 | shared_fd = info.buffd; | ||
112 | map_buf = info.buffer; | ||
113 | map_len = info.buflen; | ||
114 | write_buffer(map_buf, map_len); | ||
115 | |||
116 | /* share ion buf fd with other user process */ | ||
117 | printf("Sharing fd: %d, Client fd: %d\n", shared_fd, client_fd); | ||
118 | skinfo.datafd = shared_fd; | ||
119 | skinfo.buflen = map_len; | ||
120 | |||
121 | ret = socket_send_fd(&skinfo); | ||
122 | if (ret < 0) { | ||
123 | fprintf(stderr, "FAILED: socket_send_fd\n"); | ||
124 | goto err_send; | ||
125 | } | ||
126 | |||
127 | err_send: | ||
128 | err_export: | ||
129 | ion_close_buffer_fd(&info); | ||
130 | |||
131 | err_socket: | ||
132 | closesocket(sockfd, SOCKET_NAME); | ||
133 | |||
134 | return 0; | ||
135 | } | ||
diff --git a/tools/testing/selftests/android/ion/ionapp_import.c b/tools/testing/selftests/android/ion/ionapp_import.c new file mode 100644 index 000000000000..ae2d704cfa46 --- /dev/null +++ b/tools/testing/selftests/android/ion/ionapp_import.c | |||
@@ -0,0 +1,88 @@ | |||
1 | /* | ||
2 | * ionapp_import.c | ||
3 | * | ||
4 | * It is a user space utility to receive android ion memory buffer fd | ||
5 | * over unix domain socket IPC that can be exported by ionapp_export. | ||
6 | * This acts like a client for ionapp_export. | ||
7 | * | ||
8 | * Copyright (C) 2017 Pintu Kumar <pintu.ping@gmail.com> | ||
9 | * | ||
10 | * This software is licensed under the terms of the GNU General Public | ||
11 | * License version 2, as published by the Free Software Foundation, and | ||
12 | * may be copied, distributed, and modified under those terms. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | #include <stdio.h> | ||
22 | #include <stdlib.h> | ||
23 | #include <unistd.h> | ||
24 | #include <string.h> | ||
25 | #include "ionutils.h" | ||
26 | #include "ipcsocket.h" | ||
27 | |||
28 | |||
29 | int main(void) | ||
30 | { | ||
31 | int ret, status; | ||
32 | int sockfd, shared_fd; | ||
33 | unsigned char *map_buf; | ||
34 | unsigned long map_len; | ||
35 | struct ion_buffer_info info; | ||
36 | struct socket_info skinfo; | ||
37 | |||
38 | /* This is the client part. Here 0 means client or importer */ | ||
39 | status = opensocket(&sockfd, SOCKET_NAME, 0); | ||
40 | if (status < 0) { | ||
41 | fprintf(stderr, "No exporter exists...\n"); | ||
42 | ret = status; | ||
43 | goto err_socket; | ||
44 | } | ||
45 | |||
46 | skinfo.sockfd = sockfd; | ||
47 | |||
48 | ret = socket_receive_fd(&skinfo); | ||
49 | if (ret < 0) { | ||
50 | fprintf(stderr, "Failed: socket_receive_fd\n"); | ||
51 | goto err_recv; | ||
52 | } | ||
53 | |||
54 | shared_fd = skinfo.datafd; | ||
55 | printf("Received buffer fd: %d\n", shared_fd); | ||
56 | if (shared_fd <= 0) { | ||
57 | fprintf(stderr, "ERROR: improper buf fd\n"); | ||
58 | ret = -1; | ||
59 | goto err_fd; | ||
60 | } | ||
61 | |||
62 | memset(&info, 0, sizeof(info)); | ||
63 | info.buffd = shared_fd; | ||
64 | info.buflen = ION_BUFFER_LEN; | ||
65 | |||
66 | ret = ion_import_buffer_fd(&info); | ||
67 | if (ret < 0) { | ||
68 | fprintf(stderr, "Failed: ion_use_buffer_fd\n"); | ||
69 | goto err_import; | ||
70 | } | ||
71 | |||
72 | map_buf = info.buffer; | ||
73 | map_len = info.buflen; | ||
74 | read_buffer(map_buf, map_len); | ||
75 | |||
76 | /* Write probably new data to the same buffer again */ | ||
77 | map_len = ION_BUFFER_LEN; | ||
78 | write_buffer(map_buf, map_len); | ||
79 | |||
80 | err_import: | ||
81 | ion_close_buffer_fd(&info); | ||
82 | err_fd: | ||
83 | err_recv: | ||
84 | err_socket: | ||
85 | closesocket(sockfd, SOCKET_NAME); | ||
86 | |||
87 | return ret; | ||
88 | } | ||
diff --git a/tools/testing/selftests/android/ion/ionutils.c b/tools/testing/selftests/android/ion/ionutils.c new file mode 100644 index 000000000000..ce69c14f51fa --- /dev/null +++ b/tools/testing/selftests/android/ion/ionutils.c | |||
@@ -0,0 +1,259 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <string.h> | ||
3 | #include <unistd.h> | ||
4 | #include <fcntl.h> | ||
5 | #include <errno.h> | ||
6 | //#include <stdint.h> | ||
7 | #include <sys/ioctl.h> | ||
8 | #include <sys/mman.h> | ||
9 | #include "ionutils.h" | ||
10 | #include "ipcsocket.h" | ||
11 | |||
12 | |||
13 | void write_buffer(void *buffer, unsigned long len) | ||
14 | { | ||
15 | int i; | ||
16 | unsigned char *ptr = (unsigned char *)buffer; | ||
17 | |||
18 | if (!ptr) { | ||
19 | fprintf(stderr, "<%s>: Invalid buffer...\n", __func__); | ||
20 | return; | ||
21 | } | ||
22 | |||
23 | printf("Fill buffer content:\n"); | ||
24 | memset(ptr, 0xfd, len); | ||
25 | for (i = 0; i < len; i++) | ||
26 | printf("0x%x ", ptr[i]); | ||
27 | printf("\n"); | ||
28 | } | ||
29 | |||
30 | void read_buffer(void *buffer, unsigned long len) | ||
31 | { | ||
32 | int i; | ||
33 | unsigned char *ptr = (unsigned char *)buffer; | ||
34 | |||
35 | if (!ptr) { | ||
36 | fprintf(stderr, "<%s>: Invalid buffer...\n", __func__); | ||
37 | return; | ||
38 | } | ||
39 | |||
40 | printf("Read buffer content:\n"); | ||
41 | for (i = 0; i < len; i++) | ||
42 | printf("0x%x ", ptr[i]); | ||
43 | printf("\n"); | ||
44 | } | ||
45 | |||
46 | int ion_export_buffer_fd(struct ion_buffer_info *ion_info) | ||
47 | { | ||
48 | int i, ret, ionfd, buffer_fd; | ||
49 | unsigned int heap_id; | ||
50 | unsigned long maplen; | ||
51 | unsigned char *map_buffer; | ||
52 | struct ion_allocation_data alloc_data; | ||
53 | struct ion_heap_query query; | ||
54 | struct ion_heap_data heap_data[MAX_HEAP_COUNT]; | ||
55 | |||
56 | if (!ion_info) { | ||
57 | fprintf(stderr, "<%s>: Invalid ion info\n", __func__); | ||
58 | return -1; | ||
59 | } | ||
60 | |||
61 | /* Create an ION client */ | ||
62 | ionfd = open(ION_DEVICE, O_RDWR); | ||
63 | if (ionfd < 0) { | ||
64 | fprintf(stderr, "<%s>: Failed to open ion client: %s\n", | ||
65 | __func__, strerror(errno)); | ||
66 | return -1; | ||
67 | } | ||
68 | |||
69 | memset(&query, 0, sizeof(query)); | ||
70 | query.cnt = MAX_HEAP_COUNT; | ||
71 | query.heaps = (unsigned long int)&heap_data[0]; | ||
72 | /* Query ION heap_id_mask from ION heap */ | ||
73 | ret = ioctl(ionfd, ION_IOC_HEAP_QUERY, &query); | ||
74 | if (ret < 0) { | ||
75 | fprintf(stderr, "<%s>: Failed: ION_IOC_HEAP_QUERY: %s\n", | ||
76 | __func__, strerror(errno)); | ||
77 | goto err_query; | ||
78 | } | ||
79 | |||
80 | heap_id = MAX_HEAP_COUNT + 1; | ||
81 | for (i = 0; i < query.cnt; i++) { | ||
82 | if (heap_data[i].type == ion_info->heap_type) { | ||
83 | printf("--------------------------------------\n"); | ||
84 | printf("heap type: %d\n", heap_data[i].type); | ||
85 | printf(" heap id: %d\n", heap_data[i].heap_id); | ||
86 | printf("heap name: %s\n", heap_data[i].name); | ||
87 | printf("--------------------------------------\n"); | ||
88 | heap_id = heap_data[i].heap_id; | ||
89 | break; | ||
90 | } | ||
91 | } | ||
92 | |||
93 | if (heap_id > MAX_HEAP_COUNT) { | ||
94 | fprintf(stderr, "<%s>: ERROR: heap type does not exists\n", | ||
95 | __func__); | ||
96 | goto err_heap; | ||
97 | } | ||
98 | |||
99 | alloc_data.len = ion_info->heap_size; | ||
100 | alloc_data.heap_id_mask = 1 << heap_id; | ||
101 | alloc_data.flags = ion_info->flag_type; | ||
102 | |||
103 | /* Allocate memory for this ION client as per heap_type */ | ||
104 | ret = ioctl(ionfd, ION_IOC_ALLOC, &alloc_data); | ||
105 | if (ret < 0) { | ||
106 | fprintf(stderr, "<%s>: Failed: ION_IOC_ALLOC: %s\n", | ||
107 | __func__, strerror(errno)); | ||
108 | goto err_alloc; | ||
109 | } | ||
110 | |||
111 | /* This will return a valid buffer fd */ | ||
112 | buffer_fd = alloc_data.fd; | ||
113 | maplen = alloc_data.len; | ||
114 | |||
115 | if (buffer_fd < 0 || maplen <= 0) { | ||
116 | fprintf(stderr, "<%s>: Invalid map data, fd: %d, len: %ld\n", | ||
117 | __func__, buffer_fd, maplen); | ||
118 | goto err_fd_data; | ||
119 | } | ||
120 | |||
121 | /* Create memory mapped buffer for the buffer fd */ | ||
122 | map_buffer = (unsigned char *)mmap(NULL, maplen, PROT_READ|PROT_WRITE, | ||
123 | MAP_SHARED, buffer_fd, 0); | ||
124 | if (map_buffer == MAP_FAILED) { | ||
125 | fprintf(stderr, "<%s>: Failed: mmap: %s\n", | ||
126 | __func__, strerror(errno)); | ||
127 | goto err_mmap; | ||
128 | } | ||
129 | |||
130 | ion_info->ionfd = ionfd; | ||
131 | ion_info->buffd = buffer_fd; | ||
132 | ion_info->buffer = map_buffer; | ||
133 | ion_info->buflen = maplen; | ||
134 | |||
135 | return 0; | ||
136 | |||
137 | munmap(map_buffer, maplen); | ||
138 | |||
139 | err_fd_data: | ||
140 | err_mmap: | ||
141 | /* in case of error: close the buffer fd */ | ||
142 | if (buffer_fd) | ||
143 | close(buffer_fd); | ||
144 | |||
145 | err_query: | ||
146 | err_heap: | ||
147 | err_alloc: | ||
148 | /* In case of error: close the ion client fd */ | ||
149 | if (ionfd) | ||
150 | close(ionfd); | ||
151 | |||
152 | return -1; | ||
153 | } | ||
154 | |||
155 | int ion_import_buffer_fd(struct ion_buffer_info *ion_info) | ||
156 | { | ||
157 | int buffd; | ||
158 | unsigned char *map_buf; | ||
159 | unsigned long map_len; | ||
160 | |||
161 | if (!ion_info) { | ||
162 | fprintf(stderr, "<%s>: Invalid ion info\n", __func__); | ||
163 | return -1; | ||
164 | } | ||
165 | |||
166 | map_len = ion_info->buflen; | ||
167 | buffd = ion_info->buffd; | ||
168 | |||
169 | if (buffd < 0 || map_len <= 0) { | ||
170 | fprintf(stderr, "<%s>: Invalid map data, fd: %d, len: %ld\n", | ||
171 | __func__, buffd, map_len); | ||
172 | goto err_buffd; | ||
173 | } | ||
174 | |||
175 | map_buf = (unsigned char *)mmap(NULL, map_len, PROT_READ|PROT_WRITE, | ||
176 | MAP_SHARED, buffd, 0); | ||
177 | if (map_buf == MAP_FAILED) { | ||
178 | printf("<%s>: Failed - mmap: %s\n", | ||
179 | __func__, strerror(errno)); | ||
180 | goto err_mmap; | ||
181 | } | ||
182 | |||
183 | ion_info->buffer = map_buf; | ||
184 | ion_info->buflen = map_len; | ||
185 | |||
186 | return 0; | ||
187 | |||
188 | err_mmap: | ||
189 | if (buffd) | ||
190 | close(buffd); | ||
191 | |||
192 | err_buffd: | ||
193 | return -1; | ||
194 | } | ||
195 | |||
196 | void ion_close_buffer_fd(struct ion_buffer_info *ion_info) | ||
197 | { | ||
198 | if (ion_info) { | ||
199 | /* unmap the buffer properly in the end */ | ||
200 | munmap(ion_info->buffer, ion_info->buflen); | ||
201 | /* close the buffer fd */ | ||
202 | if (ion_info->buffd > 0) | ||
203 | close(ion_info->buffd); | ||
204 | /* Finally, close the client fd */ | ||
205 | if (ion_info->ionfd > 0) | ||
206 | close(ion_info->ionfd); | ||
207 | printf("<%s>: buffer release successfully....\n", __func__); | ||
208 | } | ||
209 | } | ||
210 | |||
211 | int socket_send_fd(struct socket_info *info) | ||
212 | { | ||
213 | int status; | ||
214 | int fd, sockfd; | ||
215 | struct socketdata skdata; | ||
216 | |||
217 | if (!info) { | ||
218 | fprintf(stderr, "<%s>: Invalid socket info\n", __func__); | ||
219 | return -1; | ||
220 | } | ||
221 | |||
222 | sockfd = info->sockfd; | ||
223 | fd = info->datafd; | ||
224 | memset(&skdata, 0, sizeof(skdata)); | ||
225 | skdata.data = fd; | ||
226 | skdata.len = sizeof(skdata.data); | ||
227 | status = sendtosocket(sockfd, &skdata); | ||
228 | if (status < 0) { | ||
229 | fprintf(stderr, "<%s>: Failed: sendtosocket\n", __func__); | ||
230 | return -1; | ||
231 | } | ||
232 | |||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | int socket_receive_fd(struct socket_info *info) | ||
237 | { | ||
238 | int status; | ||
239 | int fd, sockfd; | ||
240 | struct socketdata skdata; | ||
241 | |||
242 | if (!info) { | ||
243 | fprintf(stderr, "<%s>: Invalid socket info\n", __func__); | ||
244 | return -1; | ||
245 | } | ||
246 | |||
247 | sockfd = info->sockfd; | ||
248 | memset(&skdata, 0, sizeof(skdata)); | ||
249 | status = receivefromsocket(sockfd, &skdata); | ||
250 | if (status < 0) { | ||
251 | fprintf(stderr, "<%s>: Failed: receivefromsocket\n", __func__); | ||
252 | return -1; | ||
253 | } | ||
254 | |||
255 | fd = (int)skdata.data; | ||
256 | info->datafd = fd; | ||
257 | |||
258 | return status; | ||
259 | } | ||
diff --git a/tools/testing/selftests/android/ion/ionutils.h b/tools/testing/selftests/android/ion/ionutils.h new file mode 100644 index 000000000000..9941eb858576 --- /dev/null +++ b/tools/testing/selftests/android/ion/ionutils.h | |||
@@ -0,0 +1,55 @@ | |||
1 | #ifndef __ION_UTILS_H | ||
2 | #define __ION_UTILS_H | ||
3 | |||
4 | #include "ion.h" | ||
5 | |||
6 | #define SOCKET_NAME "ion_socket" | ||
7 | #define ION_DEVICE "/dev/ion" | ||
8 | |||
9 | #define ION_BUFFER_LEN 4096 | ||
10 | #define MAX_HEAP_COUNT ION_HEAP_TYPE_CUSTOM | ||
11 | |||
12 | struct socket_info { | ||
13 | int sockfd; | ||
14 | int datafd; | ||
15 | unsigned long buflen; | ||
16 | }; | ||
17 | |||
18 | struct ion_buffer_info { | ||
19 | int ionfd; | ||
20 | int buffd; | ||
21 | unsigned int heap_type; | ||
22 | unsigned int flag_type; | ||
23 | unsigned long heap_size; | ||
24 | unsigned long buflen; | ||
25 | unsigned char *buffer; | ||
26 | }; | ||
27 | |||
28 | |||
29 | /* This is used to fill the data into the mapped buffer */ | ||
30 | void write_buffer(void *buffer, unsigned long len); | ||
31 | |||
32 | /* This is used to read the data from the exported buffer */ | ||
33 | void read_buffer(void *buffer, unsigned long len); | ||
34 | |||
35 | /* This is used to create an ION buffer FD for the kernel buffer | ||
36 | * So you can export this same buffer to others in the form of FD | ||
37 | */ | ||
38 | int ion_export_buffer_fd(struct ion_buffer_info *ion_info); | ||
39 | |||
40 | /* This is used to import or map an exported FD. | ||
41 | * So we point to same buffer without making a copy. Hence zero-copy. | ||
42 | */ | ||
43 | int ion_import_buffer_fd(struct ion_buffer_info *ion_info); | ||
44 | |||
45 | /* This is used to close all references for the ION client */ | ||
46 | void ion_close_buffer_fd(struct ion_buffer_info *ion_info); | ||
47 | |||
48 | /* This is used to send FD to another process using socket IPC */ | ||
49 | int socket_send_fd(struct socket_info *skinfo); | ||
50 | |||
51 | /* This is used to receive FD from another process using socket IPC */ | ||
52 | int socket_receive_fd(struct socket_info *skinfo); | ||
53 | |||
54 | |||
55 | #endif | ||
diff --git a/tools/testing/selftests/android/ion/ipcsocket.c b/tools/testing/selftests/android/ion/ipcsocket.c new file mode 100644 index 000000000000..7dc521002095 --- /dev/null +++ b/tools/testing/selftests/android/ion/ipcsocket.c | |||
@@ -0,0 +1,227 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <stdlib.h> | ||
3 | #include <string.h> | ||
4 | #include <unistd.h> | ||
5 | #include <sys/types.h> | ||
6 | #include <sys/socket.h> | ||
7 | #include <sys/time.h> | ||
8 | #include <sys/un.h> | ||
9 | #include <errno.h> | ||
10 | |||
11 | #include "ipcsocket.h" | ||
12 | |||
13 | |||
14 | int opensocket(int *sockfd, const char *name, int connecttype) | ||
15 | { | ||
16 | int ret, temp = 1; | ||
17 | |||
18 | if (!name || strlen(name) > MAX_SOCK_NAME_LEN) { | ||
19 | fprintf(stderr, "<%s>: Invalid socket name.\n", __func__); | ||
20 | return -1; | ||
21 | } | ||
22 | |||
23 | ret = socket(PF_LOCAL, SOCK_STREAM, 0); | ||
24 | if (ret < 0) { | ||
25 | fprintf(stderr, "<%s>: Failed socket: <%s>\n", | ||
26 | __func__, strerror(errno)); | ||
27 | return ret; | ||
28 | } | ||
29 | |||
30 | *sockfd = ret; | ||
31 | if (setsockopt(*sockfd, SOL_SOCKET, SO_REUSEADDR, | ||
32 | (char *)&temp, sizeof(int)) < 0) { | ||
33 | fprintf(stderr, "<%s>: Failed setsockopt: <%s>\n", | ||
34 | __func__, strerror(errno)); | ||
35 | goto err; | ||
36 | } | ||
37 | |||
38 | sprintf(sock_name, "/tmp/%s", name); | ||
39 | |||
40 | if (connecttype == 1) { | ||
41 | /* This is for Server connection */ | ||
42 | struct sockaddr_un skaddr; | ||
43 | int clientfd; | ||
44 | socklen_t sklen; | ||
45 | |||
46 | unlink(sock_name); | ||
47 | memset(&skaddr, 0, sizeof(skaddr)); | ||
48 | skaddr.sun_family = AF_LOCAL; | ||
49 | strcpy(skaddr.sun_path, sock_name); | ||
50 | |||
51 | ret = bind(*sockfd, (struct sockaddr *)&skaddr, | ||
52 | SUN_LEN(&skaddr)); | ||
53 | if (ret < 0) { | ||
54 | fprintf(stderr, "<%s>: Failed bind: <%s>\n", | ||
55 | __func__, strerror(errno)); | ||
56 | goto err; | ||
57 | } | ||
58 | |||
59 | ret = listen(*sockfd, 5); | ||
60 | if (ret < 0) { | ||
61 | fprintf(stderr, "<%s>: Failed listen: <%s>\n", | ||
62 | __func__, strerror(errno)); | ||
63 | goto err; | ||
64 | } | ||
65 | |||
66 | memset(&skaddr, 0, sizeof(skaddr)); | ||
67 | sklen = sizeof(skaddr); | ||
68 | |||
69 | ret = accept(*sockfd, (struct sockaddr *)&skaddr, | ||
70 | (socklen_t *)&sklen); | ||
71 | if (ret < 0) { | ||
72 | fprintf(stderr, "<%s>: Failed accept: <%s>\n", | ||
73 | __func__, strerror(errno)); | ||
74 | goto err; | ||
75 | } | ||
76 | |||
77 | clientfd = ret; | ||
78 | *sockfd = clientfd; | ||
79 | } else { | ||
80 | /* This is for client connection */ | ||
81 | struct sockaddr_un skaddr; | ||
82 | |||
83 | memset(&skaddr, 0, sizeof(skaddr)); | ||
84 | skaddr.sun_family = AF_LOCAL; | ||
85 | strcpy(skaddr.sun_path, sock_name); | ||
86 | |||
87 | ret = connect(*sockfd, (struct sockaddr *)&skaddr, | ||
88 | SUN_LEN(&skaddr)); | ||
89 | if (ret < 0) { | ||
90 | fprintf(stderr, "<%s>: Failed connect: <%s>\n", | ||
91 | __func__, strerror(errno)); | ||
92 | goto err; | ||
93 | } | ||
94 | } | ||
95 | |||
96 | return 0; | ||
97 | |||
98 | err: | ||
99 | if (*sockfd) | ||
100 | close(*sockfd); | ||
101 | |||
102 | return ret; | ||
103 | } | ||
104 | |||
105 | int sendtosocket(int sockfd, struct socketdata *skdata) | ||
106 | { | ||
107 | int ret, buffd; | ||
108 | unsigned int len; | ||
109 | char cmsg_b[CMSG_SPACE(sizeof(int))]; | ||
110 | struct cmsghdr *cmsg; | ||
111 | struct msghdr msgh; | ||
112 | struct iovec iov; | ||
113 | struct timeval timeout; | ||
114 | fd_set selFDs; | ||
115 | |||
116 | if (!skdata) { | ||
117 | fprintf(stderr, "<%s>: socketdata is NULL\n", __func__); | ||
118 | return -1; | ||
119 | } | ||
120 | |||
121 | FD_ZERO(&selFDs); | ||
122 | FD_SET(0, &selFDs); | ||
123 | FD_SET(sockfd, &selFDs); | ||
124 | timeout.tv_sec = 20; | ||
125 | timeout.tv_usec = 0; | ||
126 | |||
127 | ret = select(sockfd+1, NULL, &selFDs, NULL, &timeout); | ||
128 | if (ret < 0) { | ||
129 | fprintf(stderr, "<%s>: Failed select: <%s>\n", | ||
130 | __func__, strerror(errno)); | ||
131 | return -1; | ||
132 | } | ||
133 | |||
134 | if (FD_ISSET(sockfd, &selFDs)) { | ||
135 | buffd = skdata->data; | ||
136 | len = skdata->len; | ||
137 | memset(&msgh, 0, sizeof(msgh)); | ||
138 | msgh.msg_control = &cmsg_b; | ||
139 | msgh.msg_controllen = CMSG_LEN(len); | ||
140 | iov.iov_base = "OK"; | ||
141 | iov.iov_len = 2; | ||
142 | msgh.msg_iov = &iov; | ||
143 | msgh.msg_iovlen = 1; | ||
144 | cmsg = CMSG_FIRSTHDR(&msgh); | ||
145 | cmsg->cmsg_level = SOL_SOCKET; | ||
146 | cmsg->cmsg_type = SCM_RIGHTS; | ||
147 | cmsg->cmsg_len = CMSG_LEN(len); | ||
148 | memcpy(CMSG_DATA(cmsg), &buffd, len); | ||
149 | |||
150 | ret = sendmsg(sockfd, &msgh, MSG_DONTWAIT); | ||
151 | if (ret < 0) { | ||
152 | fprintf(stderr, "<%s>: Failed sendmsg: <%s>\n", | ||
153 | __func__, strerror(errno)); | ||
154 | return -1; | ||
155 | } | ||
156 | } | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | int receivefromsocket(int sockfd, struct socketdata *skdata) | ||
162 | { | ||
163 | int ret, buffd; | ||
164 | unsigned int len = 0; | ||
165 | char cmsg_b[CMSG_SPACE(sizeof(int))]; | ||
166 | struct cmsghdr *cmsg; | ||
167 | struct msghdr msgh; | ||
168 | struct iovec iov; | ||
169 | fd_set recvFDs; | ||
170 | char data[32]; | ||
171 | |||
172 | if (!skdata) { | ||
173 | fprintf(stderr, "<%s>: socketdata is NULL\n", __func__); | ||
174 | return -1; | ||
175 | } | ||
176 | |||
177 | FD_ZERO(&recvFDs); | ||
178 | FD_SET(0, &recvFDs); | ||
179 | FD_SET(sockfd, &recvFDs); | ||
180 | |||
181 | ret = select(sockfd+1, &recvFDs, NULL, NULL, NULL); | ||
182 | if (ret < 0) { | ||
183 | fprintf(stderr, "<%s>: Failed select: <%s>\n", | ||
184 | __func__, strerror(errno)); | ||
185 | return -1; | ||
186 | } | ||
187 | |||
188 | if (FD_ISSET(sockfd, &recvFDs)) { | ||
189 | len = sizeof(buffd); | ||
190 | memset(&msgh, 0, sizeof(msgh)); | ||
191 | msgh.msg_control = &cmsg_b; | ||
192 | msgh.msg_controllen = CMSG_LEN(len); | ||
193 | iov.iov_base = data; | ||
194 | iov.iov_len = sizeof(data)-1; | ||
195 | msgh.msg_iov = &iov; | ||
196 | msgh.msg_iovlen = 1; | ||
197 | cmsg = CMSG_FIRSTHDR(&msgh); | ||
198 | cmsg->cmsg_level = SOL_SOCKET; | ||
199 | cmsg->cmsg_type = SCM_RIGHTS; | ||
200 | cmsg->cmsg_len = CMSG_LEN(len); | ||
201 | |||
202 | ret = recvmsg(sockfd, &msgh, MSG_DONTWAIT); | ||
203 | if (ret < 0) { | ||
204 | fprintf(stderr, "<%s>: Failed recvmsg: <%s>\n", | ||
205 | __func__, strerror(errno)); | ||
206 | return -1; | ||
207 | } | ||
208 | |||
209 | memcpy(&buffd, CMSG_DATA(cmsg), len); | ||
210 | skdata->data = buffd; | ||
211 | skdata->len = len; | ||
212 | } | ||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | int closesocket(int sockfd, char *name) | ||
217 | { | ||
218 | char sockname[MAX_SOCK_NAME_LEN]; | ||
219 | |||
220 | if (sockfd) | ||
221 | close(sockfd); | ||
222 | sprintf(sockname, "/tmp/%s", name); | ||
223 | unlink(sockname); | ||
224 | shutdown(sockfd, 2); | ||
225 | |||
226 | return 0; | ||
227 | } | ||
diff --git a/tools/testing/selftests/android/ion/ipcsocket.h b/tools/testing/selftests/android/ion/ipcsocket.h new file mode 100644 index 000000000000..b3e84498a8a1 --- /dev/null +++ b/tools/testing/selftests/android/ion/ipcsocket.h | |||
@@ -0,0 +1,35 @@ | |||
1 | |||
2 | #ifndef _IPCSOCKET_H | ||
3 | #define _IPCSOCKET_H | ||
4 | |||
5 | |||
6 | #define MAX_SOCK_NAME_LEN 64 | ||
7 | |||
8 | char sock_name[MAX_SOCK_NAME_LEN]; | ||
9 | |||
10 | /* This structure is responsible for holding the IPC data | ||
11 | * data: hold the buffer fd | ||
12 | * len: just the length of 32-bit integer fd | ||
13 | */ | ||
14 | struct socketdata { | ||
15 | int data; | ||
16 | unsigned int len; | ||
17 | }; | ||
18 | |||
19 | /* This API is used to open the IPC socket connection | ||
20 | * name: implies a unique socket name in the system | ||
21 | * connecttype: implies server(0) or client(1) | ||
22 | */ | ||
23 | int opensocket(int *sockfd, const char *name, int connecttype); | ||
24 | |||
25 | /* This is the API to send socket data over IPC socket */ | ||
26 | int sendtosocket(int sockfd, struct socketdata *data); | ||
27 | |||
28 | /* This is the API to receive socket data over IPC socket */ | ||
29 | int receivefromsocket(int sockfd, struct socketdata *data); | ||
30 | |||
31 | /* This is the API to close the socket connection */ | ||
32 | int closesocket(int sockfd, char *name); | ||
33 | |||
34 | |||
35 | #endif | ||
diff --git a/tools/testing/selftests/android/run.sh b/tools/testing/selftests/android/run.sh new file mode 100755 index 000000000000..dd8edf291454 --- /dev/null +++ b/tools/testing/selftests/android/run.sh | |||
@@ -0,0 +1,3 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | (cd ion; ./ion_test.sh) | ||
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index eab7644a07b4..333a48655ee0 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile | |||
@@ -13,16 +13,17 @@ CFLAGS += -Wall -O2 -I$(APIDIR) -I$(LIBDIR) -I$(GENDIR) $(GENFLAGS) -I../../../i | |||
13 | LDLIBS += -lcap -lelf | 13 | LDLIBS += -lcap -lelf |
14 | 14 | ||
15 | TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \ | 15 | TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \ |
16 | test_align | 16 | test_align test_verifier_log test_dev_cgroup |
17 | 17 | ||
18 | TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o \ | 18 | TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o \ |
19 | test_pkt_md_access.o test_xdp_redirect.o sockmap_parse_prog.o sockmap_verdict_prog.o | 19 | test_pkt_md_access.o test_xdp_redirect.o test_xdp_meta.o sockmap_parse_prog.o \ |
20 | sockmap_verdict_prog.o dev_cgroup.o | ||
20 | 21 | ||
21 | TEST_PROGS := test_kmod.sh test_xdp_redirect.sh | 22 | TEST_PROGS := test_kmod.sh test_xdp_redirect.sh test_xdp_meta.sh |
22 | 23 | ||
23 | include ../lib.mk | 24 | include ../lib.mk |
24 | 25 | ||
25 | BPFOBJ := $(OUTPUT)/libbpf.a | 26 | BPFOBJ := $(OUTPUT)/libbpf.a $(OUTPUT)/cgroup_helpers.c |
26 | 27 | ||
27 | $(TEST_GEN_PROGS): $(BPFOBJ) | 28 | $(TEST_GEN_PROGS): $(BPFOBJ) |
28 | 29 | ||
@@ -35,8 +36,20 @@ $(BPFOBJ): force | |||
35 | $(MAKE) -C $(BPFDIR) OUTPUT=$(OUTPUT)/ | 36 | $(MAKE) -C $(BPFDIR) OUTPUT=$(OUTPUT)/ |
36 | 37 | ||
37 | CLANG ?= clang | 38 | CLANG ?= clang |
39 | LLC ?= llc | ||
40 | |||
41 | PROBE := $(shell llc -march=bpf -mcpu=probe -filetype=null /dev/null 2>&1) | ||
42 | |||
43 | # Let newer LLVM versions transparently probe the kernel for availability | ||
44 | # of full BPF instruction set. | ||
45 | ifeq ($(PROBE),) | ||
46 | CPU ?= probe | ||
47 | else | ||
48 | CPU ?= generic | ||
49 | endif | ||
38 | 50 | ||
39 | %.o: %.c | 51 | %.o: %.c |
40 | $(CLANG) -I. -I./include/uapi -I../../../include/uapi \ | 52 | $(CLANG) -I. -I./include/uapi -I../../../include/uapi \ |
41 | -Wno-compare-distinct-pointer-types \ | 53 | -Wno-compare-distinct-pointer-types \ |
42 | -O2 -target bpf -c $< -o $@ | 54 | -O2 -target bpf -emit-llvm -c $< -o - | \ |
55 | $(LLC) -march=bpf -mcpu=$(CPU) -filetype=obj -o $@ | ||
diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h index 50353c10573c..fd9a17fa8a8b 100644 --- a/tools/testing/selftests/bpf/bpf_helpers.h +++ b/tools/testing/selftests/bpf/bpf_helpers.h | |||
@@ -63,14 +63,25 @@ static unsigned long long (*bpf_get_prandom_u32)(void) = | |||
63 | (void *) BPF_FUNC_get_prandom_u32; | 63 | (void *) BPF_FUNC_get_prandom_u32; |
64 | static int (*bpf_xdp_adjust_head)(void *ctx, int offset) = | 64 | static int (*bpf_xdp_adjust_head)(void *ctx, int offset) = |
65 | (void *) BPF_FUNC_xdp_adjust_head; | 65 | (void *) BPF_FUNC_xdp_adjust_head; |
66 | static int (*bpf_xdp_adjust_meta)(void *ctx, int offset) = | ||
67 | (void *) BPF_FUNC_xdp_adjust_meta; | ||
66 | static int (*bpf_setsockopt)(void *ctx, int level, int optname, void *optval, | 68 | static int (*bpf_setsockopt)(void *ctx, int level, int optname, void *optval, |
67 | int optlen) = | 69 | int optlen) = |
68 | (void *) BPF_FUNC_setsockopt; | 70 | (void *) BPF_FUNC_setsockopt; |
71 | static int (*bpf_getsockopt)(void *ctx, int level, int optname, void *optval, | ||
72 | int optlen) = | ||
73 | (void *) BPF_FUNC_getsockopt; | ||
69 | static int (*bpf_sk_redirect_map)(void *ctx, void *map, int key, int flags) = | 74 | static int (*bpf_sk_redirect_map)(void *ctx, void *map, int key, int flags) = |
70 | (void *) BPF_FUNC_sk_redirect_map; | 75 | (void *) BPF_FUNC_sk_redirect_map; |
71 | static int (*bpf_sock_map_update)(void *map, void *key, void *value, | 76 | static int (*bpf_sock_map_update)(void *map, void *key, void *value, |
72 | unsigned long long flags) = | 77 | unsigned long long flags) = |
73 | (void *) BPF_FUNC_sock_map_update; | 78 | (void *) BPF_FUNC_sock_map_update; |
79 | static int (*bpf_perf_event_read_value)(void *map, unsigned long long flags, | ||
80 | void *buf, unsigned int buf_size) = | ||
81 | (void *) BPF_FUNC_perf_event_read_value; | ||
82 | static int (*bpf_perf_prog_read_value)(void *ctx, void *buf, | ||
83 | unsigned int buf_size) = | ||
84 | (void *) BPF_FUNC_perf_prog_read_value; | ||
74 | 85 | ||
75 | 86 | ||
76 | /* llvm builtin functions that eBPF C program may use to | 87 | /* llvm builtin functions that eBPF C program may use to |
@@ -110,7 +121,47 @@ static int (*bpf_skb_under_cgroup)(void *ctx, void *map, int index) = | |||
110 | static int (*bpf_skb_change_head)(void *, int len, int flags) = | 121 | static int (*bpf_skb_change_head)(void *, int len, int flags) = |
111 | (void *) BPF_FUNC_skb_change_head; | 122 | (void *) BPF_FUNC_skb_change_head; |
112 | 123 | ||
124 | /* Scan the ARCH passed in from ARCH env variable (see Makefile) */ | ||
125 | #if defined(__TARGET_ARCH_x86) | ||
126 | #define bpf_target_x86 | ||
127 | #define bpf_target_defined | ||
128 | #elif defined(__TARGET_ARCH_s930x) | ||
129 | #define bpf_target_s930x | ||
130 | #define bpf_target_defined | ||
131 | #elif defined(__TARGET_ARCH_arm64) | ||
132 | #define bpf_target_arm64 | ||
133 | #define bpf_target_defined | ||
134 | #elif defined(__TARGET_ARCH_mips) | ||
135 | #define bpf_target_mips | ||
136 | #define bpf_target_defined | ||
137 | #elif defined(__TARGET_ARCH_powerpc) | ||
138 | #define bpf_target_powerpc | ||
139 | #define bpf_target_defined | ||
140 | #elif defined(__TARGET_ARCH_sparc) | ||
141 | #define bpf_target_sparc | ||
142 | #define bpf_target_defined | ||
143 | #else | ||
144 | #undef bpf_target_defined | ||
145 | #endif | ||
146 | |||
147 | /* Fall back to what the compiler says */ | ||
148 | #ifndef bpf_target_defined | ||
113 | #if defined(__x86_64__) | 149 | #if defined(__x86_64__) |
150 | #define bpf_target_x86 | ||
151 | #elif defined(__s390x__) | ||
152 | #define bpf_target_s930x | ||
153 | #elif defined(__aarch64__) | ||
154 | #define bpf_target_arm64 | ||
155 | #elif defined(__mips__) | ||
156 | #define bpf_target_mips | ||
157 | #elif defined(__powerpc__) | ||
158 | #define bpf_target_powerpc | ||
159 | #elif defined(__sparc__) | ||
160 | #define bpf_target_sparc | ||
161 | #endif | ||
162 | #endif | ||
163 | |||
164 | #if defined(bpf_target_x86) | ||
114 | 165 | ||
115 | #define PT_REGS_PARM1(x) ((x)->di) | 166 | #define PT_REGS_PARM1(x) ((x)->di) |
116 | #define PT_REGS_PARM2(x) ((x)->si) | 167 | #define PT_REGS_PARM2(x) ((x)->si) |
@@ -123,7 +174,7 @@ static int (*bpf_skb_change_head)(void *, int len, int flags) = | |||
123 | #define PT_REGS_SP(x) ((x)->sp) | 174 | #define PT_REGS_SP(x) ((x)->sp) |
124 | #define PT_REGS_IP(x) ((x)->ip) | 175 | #define PT_REGS_IP(x) ((x)->ip) |
125 | 176 | ||
126 | #elif defined(__s390x__) | 177 | #elif defined(bpf_target_s390x) |
127 | 178 | ||
128 | #define PT_REGS_PARM1(x) ((x)->gprs[2]) | 179 | #define PT_REGS_PARM1(x) ((x)->gprs[2]) |
129 | #define PT_REGS_PARM2(x) ((x)->gprs[3]) | 180 | #define PT_REGS_PARM2(x) ((x)->gprs[3]) |
@@ -136,7 +187,7 @@ static int (*bpf_skb_change_head)(void *, int len, int flags) = | |||
136 | #define PT_REGS_SP(x) ((x)->gprs[15]) | 187 | #define PT_REGS_SP(x) ((x)->gprs[15]) |
137 | #define PT_REGS_IP(x) ((x)->psw.addr) | 188 | #define PT_REGS_IP(x) ((x)->psw.addr) |
138 | 189 | ||
139 | #elif defined(__aarch64__) | 190 | #elif defined(bpf_target_arm64) |
140 | 191 | ||
141 | #define PT_REGS_PARM1(x) ((x)->regs[0]) | 192 | #define PT_REGS_PARM1(x) ((x)->regs[0]) |
142 | #define PT_REGS_PARM2(x) ((x)->regs[1]) | 193 | #define PT_REGS_PARM2(x) ((x)->regs[1]) |
@@ -149,7 +200,7 @@ static int (*bpf_skb_change_head)(void *, int len, int flags) = | |||
149 | #define PT_REGS_SP(x) ((x)->sp) | 200 | #define PT_REGS_SP(x) ((x)->sp) |
150 | #define PT_REGS_IP(x) ((x)->pc) | 201 | #define PT_REGS_IP(x) ((x)->pc) |
151 | 202 | ||
152 | #elif defined(__mips__) | 203 | #elif defined(bpf_target_mips) |
153 | 204 | ||
154 | #define PT_REGS_PARM1(x) ((x)->regs[4]) | 205 | #define PT_REGS_PARM1(x) ((x)->regs[4]) |
155 | #define PT_REGS_PARM2(x) ((x)->regs[5]) | 206 | #define PT_REGS_PARM2(x) ((x)->regs[5]) |
@@ -162,7 +213,7 @@ static int (*bpf_skb_change_head)(void *, int len, int flags) = | |||
162 | #define PT_REGS_SP(x) ((x)->regs[29]) | 213 | #define PT_REGS_SP(x) ((x)->regs[29]) |
163 | #define PT_REGS_IP(x) ((x)->cp0_epc) | 214 | #define PT_REGS_IP(x) ((x)->cp0_epc) |
164 | 215 | ||
165 | #elif defined(__powerpc__) | 216 | #elif defined(bpf_target_powerpc) |
166 | 217 | ||
167 | #define PT_REGS_PARM1(x) ((x)->gpr[3]) | 218 | #define PT_REGS_PARM1(x) ((x)->gpr[3]) |
168 | #define PT_REGS_PARM2(x) ((x)->gpr[4]) | 219 | #define PT_REGS_PARM2(x) ((x)->gpr[4]) |
@@ -173,7 +224,7 @@ static int (*bpf_skb_change_head)(void *, int len, int flags) = | |||
173 | #define PT_REGS_SP(x) ((x)->sp) | 224 | #define PT_REGS_SP(x) ((x)->sp) |
174 | #define PT_REGS_IP(x) ((x)->nip) | 225 | #define PT_REGS_IP(x) ((x)->nip) |
175 | 226 | ||
176 | #elif defined(__sparc__) | 227 | #elif defined(bpf_target_sparc) |
177 | 228 | ||
178 | #define PT_REGS_PARM1(x) ((x)->u_regs[UREG_I0]) | 229 | #define PT_REGS_PARM1(x) ((x)->u_regs[UREG_I0]) |
179 | #define PT_REGS_PARM2(x) ((x)->u_regs[UREG_I1]) | 230 | #define PT_REGS_PARM2(x) ((x)->u_regs[UREG_I1]) |
@@ -183,6 +234,8 @@ static int (*bpf_skb_change_head)(void *, int len, int flags) = | |||
183 | #define PT_REGS_RET(x) ((x)->u_regs[UREG_I7]) | 234 | #define PT_REGS_RET(x) ((x)->u_regs[UREG_I7]) |
184 | #define PT_REGS_RC(x) ((x)->u_regs[UREG_I0]) | 235 | #define PT_REGS_RC(x) ((x)->u_regs[UREG_I0]) |
185 | #define PT_REGS_SP(x) ((x)->u_regs[UREG_FP]) | 236 | #define PT_REGS_SP(x) ((x)->u_regs[UREG_FP]) |
237 | |||
238 | /* Should this also be a bpf_target check for the sparc case? */ | ||
186 | #if defined(__arch64__) | 239 | #if defined(__arch64__) |
187 | #define PT_REGS_IP(x) ((x)->tpc) | 240 | #define PT_REGS_IP(x) ((x)->tpc) |
188 | #else | 241 | #else |
@@ -191,10 +244,10 @@ static int (*bpf_skb_change_head)(void *, int len, int flags) = | |||
191 | 244 | ||
192 | #endif | 245 | #endif |
193 | 246 | ||
194 | #ifdef __powerpc__ | 247 | #ifdef bpf_target_powerpc |
195 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = (ctx)->link; }) | 248 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = (ctx)->link; }) |
196 | #define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP | 249 | #define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP |
197 | #elif defined(__sparc__) | 250 | #elif bpf_target_sparc |
198 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = PT_REGS_RET(ctx); }) | 251 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = PT_REGS_RET(ctx); }) |
199 | #define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP | 252 | #define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP |
200 | #else | 253 | #else |
diff --git a/tools/testing/selftests/bpf/cgroup_helpers.c b/tools/testing/selftests/bpf/cgroup_helpers.c new file mode 100644 index 000000000000..f3bca3ade0f3 --- /dev/null +++ b/tools/testing/selftests/bpf/cgroup_helpers.c | |||
@@ -0,0 +1,178 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | #define _GNU_SOURCE | ||
3 | #include <sched.h> | ||
4 | #include <sys/mount.h> | ||
5 | #include <sys/stat.h> | ||
6 | #include <sys/types.h> | ||
7 | #include <linux/limits.h> | ||
8 | #include <stdio.h> | ||
9 | #include <linux/sched.h> | ||
10 | #include <fcntl.h> | ||
11 | #include <unistd.h> | ||
12 | #include <ftw.h> | ||
13 | |||
14 | |||
15 | #include "cgroup_helpers.h" | ||
16 | |||
17 | /* | ||
18 | * To avoid relying on the system setup, when setup_cgroup_env is called | ||
19 | * we create a new mount namespace, and cgroup namespace. The cgroup2 | ||
20 | * root is mounted at CGROUP_MOUNT_PATH | ||
21 | * | ||
22 | * Unfortunately, most people don't have cgroupv2 enabled at this point in time. | ||
23 | * It's easier to create our own mount namespace and manage it ourselves. | ||
24 | * | ||
25 | * We assume /mnt exists. | ||
26 | */ | ||
27 | |||
28 | #define WALK_FD_LIMIT 16 | ||
29 | #define CGROUP_MOUNT_PATH "/mnt" | ||
30 | #define CGROUP_WORK_DIR "/cgroup-test-work-dir" | ||
31 | #define format_cgroup_path(buf, path) \ | ||
32 | snprintf(buf, sizeof(buf), "%s%s%s", CGROUP_MOUNT_PATH, \ | ||
33 | CGROUP_WORK_DIR, path) | ||
34 | |||
35 | /** | ||
36 | * setup_cgroup_environment() - Setup the cgroup environment | ||
37 | * | ||
38 | * After calling this function, cleanup_cgroup_environment should be called | ||
39 | * once testing is complete. | ||
40 | * | ||
41 | * This function will print an error to stderr and return 1 if it is unable | ||
42 | * to setup the cgroup environment. If setup is successful, 0 is returned. | ||
43 | */ | ||
44 | int setup_cgroup_environment(void) | ||
45 | { | ||
46 | char cgroup_workdir[PATH_MAX + 1]; | ||
47 | |||
48 | format_cgroup_path(cgroup_workdir, ""); | ||
49 | |||
50 | if (unshare(CLONE_NEWNS)) { | ||
51 | log_err("unshare"); | ||
52 | return 1; | ||
53 | } | ||
54 | |||
55 | if (mount("none", "/", NULL, MS_REC | MS_PRIVATE, NULL)) { | ||
56 | log_err("mount fakeroot"); | ||
57 | return 1; | ||
58 | } | ||
59 | |||
60 | if (mount("none", CGROUP_MOUNT_PATH, "cgroup2", 0, NULL) && errno != EBUSY) { | ||
61 | log_err("mount cgroup2"); | ||
62 | return 1; | ||
63 | } | ||
64 | |||
65 | /* Cleanup existing failed runs, now that the environment is setup */ | ||
66 | cleanup_cgroup_environment(); | ||
67 | |||
68 | if (mkdir(cgroup_workdir, 0777) && errno != EEXIST) { | ||
69 | log_err("mkdir cgroup work dir"); | ||
70 | return 1; | ||
71 | } | ||
72 | |||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | static int nftwfunc(const char *filename, const struct stat *statptr, | ||
77 | int fileflags, struct FTW *pfwt) | ||
78 | { | ||
79 | if ((fileflags & FTW_D) && rmdir(filename)) | ||
80 | log_err("Removing cgroup: %s", filename); | ||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | |||
85 | static int join_cgroup_from_top(char *cgroup_path) | ||
86 | { | ||
87 | char cgroup_procs_path[PATH_MAX + 1]; | ||
88 | pid_t pid = getpid(); | ||
89 | int fd, rc = 0; | ||
90 | |||
91 | snprintf(cgroup_procs_path, sizeof(cgroup_procs_path), | ||
92 | "%s/cgroup.procs", cgroup_path); | ||
93 | |||
94 | fd = open(cgroup_procs_path, O_WRONLY); | ||
95 | if (fd < 0) { | ||
96 | log_err("Opening Cgroup Procs: %s", cgroup_procs_path); | ||
97 | return 1; | ||
98 | } | ||
99 | |||
100 | if (dprintf(fd, "%d\n", pid) < 0) { | ||
101 | log_err("Joining Cgroup"); | ||
102 | rc = 1; | ||
103 | } | ||
104 | |||
105 | close(fd); | ||
106 | return rc; | ||
107 | } | ||
108 | |||
109 | /** | ||
110 | * join_cgroup() - Join a cgroup | ||
111 | * @path: The cgroup path, relative to the workdir, to join | ||
112 | * | ||
113 | * This function expects a cgroup to already be created, relative to the cgroup | ||
114 | * work dir, and it joins it. For example, passing "/my-cgroup" as the path | ||
115 | * would actually put the calling process into the cgroup | ||
116 | * "/cgroup-test-work-dir/my-cgroup" | ||
117 | * | ||
118 | * On success, it returns 0, otherwise on failure it returns 1. | ||
119 | */ | ||
120 | int join_cgroup(char *path) | ||
121 | { | ||
122 | char cgroup_path[PATH_MAX + 1]; | ||
123 | |||
124 | format_cgroup_path(cgroup_path, path); | ||
125 | return join_cgroup_from_top(cgroup_path); | ||
126 | } | ||
127 | |||
128 | /** | ||
129 | * cleanup_cgroup_environment() - Cleanup Cgroup Testing Environment | ||
130 | * | ||
131 | * This is an idempotent function to delete all temporary cgroups that | ||
132 | * have been created during the test, including the cgroup testing work | ||
133 | * directory. | ||
134 | * | ||
135 | * At call time, it moves the calling process to the root cgroup, and then | ||
136 | * runs the deletion process. It is idempotent, and should not fail, unless | ||
137 | * a process is lingering. | ||
138 | * | ||
139 | * On failure, it will print an error to stderr, and try to continue. | ||
140 | */ | ||
141 | void cleanup_cgroup_environment(void) | ||
142 | { | ||
143 | char cgroup_workdir[PATH_MAX + 1]; | ||
144 | |||
145 | format_cgroup_path(cgroup_workdir, ""); | ||
146 | join_cgroup_from_top(CGROUP_MOUNT_PATH); | ||
147 | nftw(cgroup_workdir, nftwfunc, WALK_FD_LIMIT, FTW_DEPTH | FTW_MOUNT); | ||
148 | } | ||
149 | |||
150 | /** | ||
151 | * create_and_get_cgroup() - Create a cgroup, relative to workdir, and get the FD | ||
152 | * @path: The cgroup path, relative to the workdir, to join | ||
153 | * | ||
154 | * This function creates a cgroup under the top level workdir and returns the | ||
155 | * file descriptor. It is idempotent. | ||
156 | * | ||
157 | * On success, it returns the file descriptor. On failure it returns 0. | ||
158 | * If there is a failure, it prints the error to stderr. | ||
159 | */ | ||
160 | int create_and_get_cgroup(char *path) | ||
161 | { | ||
162 | char cgroup_path[PATH_MAX + 1]; | ||
163 | int fd; | ||
164 | |||
165 | format_cgroup_path(cgroup_path, path); | ||
166 | if (mkdir(cgroup_path, 0777) && errno != EEXIST) { | ||
167 | log_err("mkdiring cgroup %s .. %s", path, cgroup_path); | ||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | fd = open(cgroup_path, O_RDONLY); | ||
172 | if (fd < 0) { | ||
173 | log_err("Opening Cgroup"); | ||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | return fd; | ||
178 | } | ||
diff --git a/tools/testing/selftests/bpf/cgroup_helpers.h b/tools/testing/selftests/bpf/cgroup_helpers.h new file mode 100644 index 000000000000..06485e0002b3 --- /dev/null +++ b/tools/testing/selftests/bpf/cgroup_helpers.h | |||
@@ -0,0 +1,17 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | #ifndef __CGROUP_HELPERS_H | ||
3 | #define __CGROUP_HELPERS_H | ||
4 | #include <errno.h> | ||
5 | #include <string.h> | ||
6 | |||
7 | #define clean_errno() (errno == 0 ? "None" : strerror(errno)) | ||
8 | #define log_err(MSG, ...) fprintf(stderr, "(%s:%d: errno: %s) " MSG "\n", \ | ||
9 | __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__) | ||
10 | |||
11 | |||
12 | int create_and_get_cgroup(char *path); | ||
13 | int join_cgroup(char *path); | ||
14 | int setup_cgroup_environment(void); | ||
15 | void cleanup_cgroup_environment(void); | ||
16 | |||
17 | #endif | ||
diff --git a/tools/testing/selftests/bpf/dev_cgroup.c b/tools/testing/selftests/bpf/dev_cgroup.c new file mode 100644 index 000000000000..ce41a3475f27 --- /dev/null +++ b/tools/testing/selftests/bpf/dev_cgroup.c | |||
@@ -0,0 +1,60 @@ | |||
1 | /* Copyright (c) 2017 Facebook | ||
2 | * | ||
3 | * This program is free software; you can redistribute it and/or | ||
4 | * modify it under the terms of version 2 of the GNU General Public | ||
5 | * License as published by the Free Software Foundation. | ||
6 | */ | ||
7 | |||
8 | #include <linux/bpf.h> | ||
9 | #include <linux/version.h> | ||
10 | #include "bpf_helpers.h" | ||
11 | |||
12 | SEC("cgroup/dev") | ||
13 | int bpf_prog1(struct bpf_cgroup_dev_ctx *ctx) | ||
14 | { | ||
15 | short type = ctx->access_type & 0xFFFF; | ||
16 | #ifdef DEBUG | ||
17 | short access = ctx->access_type >> 16; | ||
18 | char fmt[] = " %d:%d \n"; | ||
19 | |||
20 | switch (type) { | ||
21 | case BPF_DEVCG_DEV_BLOCK: | ||
22 | fmt[0] = 'b'; | ||
23 | break; | ||
24 | case BPF_DEVCG_DEV_CHAR: | ||
25 | fmt[0] = 'c'; | ||
26 | break; | ||
27 | default: | ||
28 | fmt[0] = '?'; | ||
29 | break; | ||
30 | } | ||
31 | |||
32 | if (access & BPF_DEVCG_ACC_READ) | ||
33 | fmt[8] = 'r'; | ||
34 | |||
35 | if (access & BPF_DEVCG_ACC_WRITE) | ||
36 | fmt[9] = 'w'; | ||
37 | |||
38 | if (access & BPF_DEVCG_ACC_MKNOD) | ||
39 | fmt[10] = 'm'; | ||
40 | |||
41 | bpf_trace_printk(fmt, sizeof(fmt), ctx->major, ctx->minor); | ||
42 | #endif | ||
43 | |||
44 | /* Allow access to /dev/zero and /dev/random. | ||
45 | * Forbid everything else. | ||
46 | */ | ||
47 | if (ctx->major != 1 || type != BPF_DEVCG_DEV_CHAR) | ||
48 | return 0; | ||
49 | |||
50 | switch (ctx->minor) { | ||
51 | case 5: /* 1:5 /dev/zero */ | ||
52 | case 9: /* 1:9 /dev/urandom */ | ||
53 | return 1; | ||
54 | } | ||
55 | |||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | char _license[] SEC("license") = "GPL"; | ||
60 | __u32 _version SEC("version") = LINUX_VERSION_CODE; | ||
diff --git a/tools/testing/selftests/bpf/sockmap_parse_prog.c b/tools/testing/selftests/bpf/sockmap_parse_prog.c index fae3b96c3aa4..a1dec2b6d9c5 100644 --- a/tools/testing/selftests/bpf/sockmap_parse_prog.c +++ b/tools/testing/selftests/bpf/sockmap_parse_prog.c | |||
@@ -29,9 +29,6 @@ int bpf_prog1(struct __sk_buff *skb) | |||
29 | * fields. | 29 | * fields. |
30 | */ | 30 | */ |
31 | d[7] = 1; | 31 | d[7] = 1; |
32 | |||
33 | bpf_printk("parse: data[0] = (%u): local_port %i remote %i\n", | ||
34 | d[0], lport, bpf_ntohl(rport)); | ||
35 | return skb->len; | 32 | return skb->len; |
36 | } | 33 | } |
37 | 34 | ||
diff --git a/tools/testing/selftests/bpf/sockmap_verdict_prog.c b/tools/testing/selftests/bpf/sockmap_verdict_prog.c index 2cd2d552938b..d7bea972cb21 100644 --- a/tools/testing/selftests/bpf/sockmap_verdict_prog.c +++ b/tools/testing/selftests/bpf/sockmap_verdict_prog.c | |||
@@ -58,8 +58,6 @@ int bpf_prog2(struct __sk_buff *skb) | |||
58 | d[6] = 0xe; | 58 | d[6] = 0xe; |
59 | d[7] = 0xf; | 59 | d[7] = 0xf; |
60 | 60 | ||
61 | bpf_printk("verdict: data[0] = redir(%u:%u)\n", map, sk); | ||
62 | |||
63 | if (!map) | 61 | if (!map) |
64 | return bpf_sk_redirect_map(skb, &sock_map_rx, sk, 0); | 62 | return bpf_sk_redirect_map(skb, &sock_map_rx, sk, 0); |
65 | return bpf_sk_redirect_map(skb, &sock_map_tx, sk, 0); | 63 | return bpf_sk_redirect_map(skb, &sock_map_tx, sk, 0); |
diff --git a/tools/testing/selftests/bpf/test_dev_cgroup.c b/tools/testing/selftests/bpf/test_dev_cgroup.c new file mode 100644 index 000000000000..02c85d6c89b0 --- /dev/null +++ b/tools/testing/selftests/bpf/test_dev_cgroup.c | |||
@@ -0,0 +1,93 @@ | |||
1 | /* Copyright (c) 2017 Facebook | ||
2 | * | ||
3 | * This program is free software; you can redistribute it and/or | ||
4 | * modify it under the terms of version 2 of the GNU General Public | ||
5 | * License as published by the Free Software Foundation. | ||
6 | */ | ||
7 | |||
8 | #include <stdio.h> | ||
9 | #include <stdlib.h> | ||
10 | #include <string.h> | ||
11 | #include <errno.h> | ||
12 | #include <assert.h> | ||
13 | |||
14 | #include <linux/bpf.h> | ||
15 | #include <bpf/bpf.h> | ||
16 | #include <bpf/libbpf.h> | ||
17 | |||
18 | #include "cgroup_helpers.h" | ||
19 | |||
20 | #define DEV_CGROUP_PROG "./dev_cgroup.o" | ||
21 | |||
22 | #define TEST_CGROUP "test-bpf-based-device-cgroup/" | ||
23 | |||
24 | int main(int argc, char **argv) | ||
25 | { | ||
26 | struct bpf_object *obj; | ||
27 | int error = EXIT_FAILURE; | ||
28 | int prog_fd, cgroup_fd; | ||
29 | __u32 prog_cnt; | ||
30 | |||
31 | if (bpf_prog_load(DEV_CGROUP_PROG, BPF_PROG_TYPE_CGROUP_DEVICE, | ||
32 | &obj, &prog_fd)) { | ||
33 | printf("Failed to load DEV_CGROUP program\n"); | ||
34 | goto err; | ||
35 | } | ||
36 | |||
37 | if (setup_cgroup_environment()) { | ||
38 | printf("Failed to load DEV_CGROUP program\n"); | ||
39 | goto err; | ||
40 | } | ||
41 | |||
42 | /* Create a cgroup, get fd, and join it */ | ||
43 | cgroup_fd = create_and_get_cgroup(TEST_CGROUP); | ||
44 | if (!cgroup_fd) { | ||
45 | printf("Failed to create test cgroup\n"); | ||
46 | goto err; | ||
47 | } | ||
48 | |||
49 | if (join_cgroup(TEST_CGROUP)) { | ||
50 | printf("Failed to join cgroup\n"); | ||
51 | goto err; | ||
52 | } | ||
53 | |||
54 | /* Attach bpf program */ | ||
55 | if (bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_DEVICE, 0)) { | ||
56 | printf("Failed to attach DEV_CGROUP program"); | ||
57 | goto err; | ||
58 | } | ||
59 | |||
60 | if (bpf_prog_query(cgroup_fd, BPF_CGROUP_DEVICE, 0, NULL, NULL, | ||
61 | &prog_cnt)) { | ||
62 | printf("Failed to query attached programs"); | ||
63 | goto err; | ||
64 | } | ||
65 | |||
66 | /* All operations with /dev/zero and and /dev/urandom are allowed, | ||
67 | * everything else is forbidden. | ||
68 | */ | ||
69 | assert(system("rm -f /tmp/test_dev_cgroup_null") == 0); | ||
70 | assert(system("mknod /tmp/test_dev_cgroup_null c 1 3")); | ||
71 | assert(system("rm -f /tmp/test_dev_cgroup_null") == 0); | ||
72 | |||
73 | /* /dev/zero is whitelisted */ | ||
74 | assert(system("rm -f /tmp/test_dev_cgroup_zero") == 0); | ||
75 | assert(system("mknod /tmp/test_dev_cgroup_zero c 1 5") == 0); | ||
76 | assert(system("rm -f /tmp/test_dev_cgroup_zero") == 0); | ||
77 | |||
78 | assert(system("dd if=/dev/urandom of=/dev/zero count=64") == 0); | ||
79 | |||
80 | /* src is allowed, target is forbidden */ | ||
81 | assert(system("dd if=/dev/urandom of=/dev/full count=64")); | ||
82 | |||
83 | /* src is forbidden, target is allowed */ | ||
84 | assert(system("dd if=/dev/random of=/dev/zero count=64")); | ||
85 | |||
86 | error = 0; | ||
87 | printf("test_dev_cgroup:PASS\n"); | ||
88 | |||
89 | err: | ||
90 | cleanup_cgroup_environment(); | ||
91 | |||
92 | return error; | ||
93 | } | ||
diff --git a/tools/testing/selftests/bpf/test_lpm_map.c b/tools/testing/selftests/bpf/test_lpm_map.c index f93a333cbf2c..f61480641b6e 100644 --- a/tools/testing/selftests/bpf/test_lpm_map.c +++ b/tools/testing/selftests/bpf/test_lpm_map.c | |||
@@ -32,6 +32,10 @@ struct tlpm_node { | |||
32 | uint8_t key[]; | 32 | uint8_t key[]; |
33 | }; | 33 | }; |
34 | 34 | ||
35 | static struct tlpm_node *tlpm_match(struct tlpm_node *list, | ||
36 | const uint8_t *key, | ||
37 | size_t n_bits); | ||
38 | |||
35 | static struct tlpm_node *tlpm_add(struct tlpm_node *list, | 39 | static struct tlpm_node *tlpm_add(struct tlpm_node *list, |
36 | const uint8_t *key, | 40 | const uint8_t *key, |
37 | size_t n_bits) | 41 | size_t n_bits) |
@@ -39,9 +43,17 @@ static struct tlpm_node *tlpm_add(struct tlpm_node *list, | |||
39 | struct tlpm_node *node; | 43 | struct tlpm_node *node; |
40 | size_t n; | 44 | size_t n; |
41 | 45 | ||
46 | n = (n_bits + 7) / 8; | ||
47 | |||
48 | /* 'overwrite' an equivalent entry if one already exists */ | ||
49 | node = tlpm_match(list, key, n_bits); | ||
50 | if (node && node->n_bits == n_bits) { | ||
51 | memcpy(node->key, key, n); | ||
52 | return list; | ||
53 | } | ||
54 | |||
42 | /* add new entry with @key/@n_bits to @list and return new head */ | 55 | /* add new entry with @key/@n_bits to @list and return new head */ |
43 | 56 | ||
44 | n = (n_bits + 7) / 8; | ||
45 | node = malloc(sizeof(*node) + n); | 57 | node = malloc(sizeof(*node) + n); |
46 | assert(node); | 58 | assert(node); |
47 | 59 | ||
@@ -93,6 +105,34 @@ static struct tlpm_node *tlpm_match(struct tlpm_node *list, | |||
93 | return best; | 105 | return best; |
94 | } | 106 | } |
95 | 107 | ||
108 | static struct tlpm_node *tlpm_delete(struct tlpm_node *list, | ||
109 | const uint8_t *key, | ||
110 | size_t n_bits) | ||
111 | { | ||
112 | struct tlpm_node *best = tlpm_match(list, key, n_bits); | ||
113 | struct tlpm_node *node; | ||
114 | |||
115 | if (!best || best->n_bits != n_bits) | ||
116 | return list; | ||
117 | |||
118 | if (best == list) { | ||
119 | node = best->next; | ||
120 | free(best); | ||
121 | return node; | ||
122 | } | ||
123 | |||
124 | for (node = list; node; node = node->next) { | ||
125 | if (node->next == best) { | ||
126 | node->next = best->next; | ||
127 | free(best); | ||
128 | return list; | ||
129 | } | ||
130 | } | ||
131 | /* should never get here */ | ||
132 | assert(0); | ||
133 | return list; | ||
134 | } | ||
135 | |||
96 | static void test_lpm_basic(void) | 136 | static void test_lpm_basic(void) |
97 | { | 137 | { |
98 | struct tlpm_node *list = NULL, *t1, *t2; | 138 | struct tlpm_node *list = NULL, *t1, *t2; |
@@ -115,6 +155,13 @@ static void test_lpm_basic(void) | |||
115 | assert(t1 == tlpm_match(list, (uint8_t[]){ 0xff, 0xff }, 15)); | 155 | assert(t1 == tlpm_match(list, (uint8_t[]){ 0xff, 0xff }, 15)); |
116 | assert(!tlpm_match(list, (uint8_t[]){ 0x7f, 0xff }, 16)); | 156 | assert(!tlpm_match(list, (uint8_t[]){ 0x7f, 0xff }, 16)); |
117 | 157 | ||
158 | list = tlpm_delete(list, (uint8_t[]){ 0xff, 0xff }, 16); | ||
159 | assert(t1 == tlpm_match(list, (uint8_t[]){ 0xff }, 8)); | ||
160 | assert(t1 == tlpm_match(list, (uint8_t[]){ 0xff, 0xff }, 16)); | ||
161 | |||
162 | list = tlpm_delete(list, (uint8_t[]){ 0xff }, 8); | ||
163 | assert(!tlpm_match(list, (uint8_t[]){ 0xff }, 8)); | ||
164 | |||
118 | tlpm_clear(list); | 165 | tlpm_clear(list); |
119 | } | 166 | } |
120 | 167 | ||
@@ -159,7 +206,7 @@ static void test_lpm_order(void) | |||
159 | 206 | ||
160 | static void test_lpm_map(int keysize) | 207 | static void test_lpm_map(int keysize) |
161 | { | 208 | { |
162 | size_t i, j, n_matches, n_nodes, n_lookups; | 209 | size_t i, j, n_matches, n_matches_after_delete, n_nodes, n_lookups; |
163 | struct tlpm_node *t, *list = NULL; | 210 | struct tlpm_node *t, *list = NULL; |
164 | struct bpf_lpm_trie_key *key; | 211 | struct bpf_lpm_trie_key *key; |
165 | uint8_t *data, *value; | 212 | uint8_t *data, *value; |
@@ -171,6 +218,7 @@ static void test_lpm_map(int keysize) | |||
171 | */ | 218 | */ |
172 | 219 | ||
173 | n_matches = 0; | 220 | n_matches = 0; |
221 | n_matches_after_delete = 0; | ||
174 | n_nodes = 1 << 8; | 222 | n_nodes = 1 << 8; |
175 | n_lookups = 1 << 16; | 223 | n_lookups = 1 << 16; |
176 | 224 | ||
@@ -224,15 +272,54 @@ static void test_lpm_map(int keysize) | |||
224 | } | 272 | } |
225 | } | 273 | } |
226 | 274 | ||
275 | /* Remove the first half of the elements in the tlpm and the | ||
276 | * corresponding nodes from the bpf-lpm. Then run the same | ||
277 | * large number of random lookups in both and make sure they match. | ||
278 | * Note: we need to count the number of nodes actually inserted | ||
279 | * since there may have been duplicates. | ||
280 | */ | ||
281 | for (i = 0, t = list; t; i++, t = t->next) | ||
282 | ; | ||
283 | for (j = 0; j < i / 2; ++j) { | ||
284 | key->prefixlen = list->n_bits; | ||
285 | memcpy(key->data, list->key, keysize); | ||
286 | r = bpf_map_delete_elem(map, key); | ||
287 | assert(!r); | ||
288 | list = tlpm_delete(list, list->key, list->n_bits); | ||
289 | assert(list); | ||
290 | } | ||
291 | for (i = 0; i < n_lookups; ++i) { | ||
292 | for (j = 0; j < keysize; ++j) | ||
293 | data[j] = rand() & 0xff; | ||
294 | |||
295 | t = tlpm_match(list, data, 8 * keysize); | ||
296 | |||
297 | key->prefixlen = 8 * keysize; | ||
298 | memcpy(key->data, data, keysize); | ||
299 | r = bpf_map_lookup_elem(map, key, value); | ||
300 | assert(!r || errno == ENOENT); | ||
301 | assert(!t == !!r); | ||
302 | |||
303 | if (t) { | ||
304 | ++n_matches_after_delete; | ||
305 | assert(t->n_bits == value[keysize]); | ||
306 | for (j = 0; j < t->n_bits; ++j) | ||
307 | assert((t->key[j / 8] & (1 << (7 - j % 8))) == | ||
308 | (value[j / 8] & (1 << (7 - j % 8)))); | ||
309 | } | ||
310 | } | ||
311 | |||
227 | close(map); | 312 | close(map); |
228 | tlpm_clear(list); | 313 | tlpm_clear(list); |
229 | 314 | ||
230 | /* With 255 random nodes in the map, we are pretty likely to match | 315 | /* With 255 random nodes in the map, we are pretty likely to match |
231 | * something on every lookup. For statistics, use this: | 316 | * something on every lookup. For statistics, use this: |
232 | * | 317 | * |
233 | * printf(" nodes: %zu\n" | 318 | * printf(" nodes: %zu\n" |
234 | * "lookups: %zu\n" | 319 | * " lookups: %zu\n" |
235 | * "matches: %zu\n", n_nodes, n_lookups, n_matches); | 320 | * " matches: %zu\n" |
321 | * "matches(delete): %zu\n", | ||
322 | * n_nodes, n_lookups, n_matches, n_matches_after_delete); | ||
236 | */ | 323 | */ |
237 | } | 324 | } |
238 | 325 | ||
@@ -332,6 +419,108 @@ static void test_lpm_ipaddr(void) | |||
332 | close(map_fd_ipv6); | 419 | close(map_fd_ipv6); |
333 | } | 420 | } |
334 | 421 | ||
422 | static void test_lpm_delete(void) | ||
423 | { | ||
424 | struct bpf_lpm_trie_key *key; | ||
425 | size_t key_size; | ||
426 | int map_fd; | ||
427 | __u64 value; | ||
428 | |||
429 | key_size = sizeof(*key) + sizeof(__u32); | ||
430 | key = alloca(key_size); | ||
431 | |||
432 | map_fd = bpf_create_map(BPF_MAP_TYPE_LPM_TRIE, | ||
433 | key_size, sizeof(value), | ||
434 | 100, BPF_F_NO_PREALLOC); | ||
435 | assert(map_fd >= 0); | ||
436 | |||
437 | /* Add nodes: | ||
438 | * 192.168.0.0/16 (1) | ||
439 | * 192.168.0.0/24 (2) | ||
440 | * 192.168.128.0/24 (3) | ||
441 | * 192.168.1.0/24 (4) | ||
442 | * | ||
443 | * (1) | ||
444 | * / \ | ||
445 | * (IM) (3) | ||
446 | * / \ | ||
447 | * (2) (4) | ||
448 | */ | ||
449 | value = 1; | ||
450 | key->prefixlen = 16; | ||
451 | inet_pton(AF_INET, "192.168.0.0", key->data); | ||
452 | assert(bpf_map_update_elem(map_fd, key, &value, 0) == 0); | ||
453 | |||
454 | value = 2; | ||
455 | key->prefixlen = 24; | ||
456 | inet_pton(AF_INET, "192.168.0.0", key->data); | ||
457 | assert(bpf_map_update_elem(map_fd, key, &value, 0) == 0); | ||
458 | |||
459 | value = 3; | ||
460 | key->prefixlen = 24; | ||
461 | inet_pton(AF_INET, "192.168.128.0", key->data); | ||
462 | assert(bpf_map_update_elem(map_fd, key, &value, 0) == 0); | ||
463 | |||
464 | value = 4; | ||
465 | key->prefixlen = 24; | ||
466 | inet_pton(AF_INET, "192.168.1.0", key->data); | ||
467 | assert(bpf_map_update_elem(map_fd, key, &value, 0) == 0); | ||
468 | |||
469 | /* remove non-existent node */ | ||
470 | key->prefixlen = 32; | ||
471 | inet_pton(AF_INET, "10.0.0.1", key->data); | ||
472 | assert(bpf_map_lookup_elem(map_fd, key, &value) == -1 && | ||
473 | errno == ENOENT); | ||
474 | |||
475 | /* assert initial lookup */ | ||
476 | key->prefixlen = 32; | ||
477 | inet_pton(AF_INET, "192.168.0.1", key->data); | ||
478 | assert(bpf_map_lookup_elem(map_fd, key, &value) == 0); | ||
479 | assert(value == 2); | ||
480 | |||
481 | /* remove leaf node */ | ||
482 | key->prefixlen = 24; | ||
483 | inet_pton(AF_INET, "192.168.0.0", key->data); | ||
484 | assert(bpf_map_delete_elem(map_fd, key) == 0); | ||
485 | |||
486 | key->prefixlen = 32; | ||
487 | inet_pton(AF_INET, "192.168.0.1", key->data); | ||
488 | assert(bpf_map_lookup_elem(map_fd, key, &value) == 0); | ||
489 | assert(value == 1); | ||
490 | |||
491 | /* remove leaf (and intermediary) node */ | ||
492 | key->prefixlen = 24; | ||
493 | inet_pton(AF_INET, "192.168.1.0", key->data); | ||
494 | assert(bpf_map_delete_elem(map_fd, key) == 0); | ||
495 | |||
496 | key->prefixlen = 32; | ||
497 | inet_pton(AF_INET, "192.168.1.1", key->data); | ||
498 | assert(bpf_map_lookup_elem(map_fd, key, &value) == 0); | ||
499 | assert(value == 1); | ||
500 | |||
501 | /* remove root node */ | ||
502 | key->prefixlen = 16; | ||
503 | inet_pton(AF_INET, "192.168.0.0", key->data); | ||
504 | assert(bpf_map_delete_elem(map_fd, key) == 0); | ||
505 | |||
506 | key->prefixlen = 32; | ||
507 | inet_pton(AF_INET, "192.168.128.1", key->data); | ||
508 | assert(bpf_map_lookup_elem(map_fd, key, &value) == 0); | ||
509 | assert(value == 3); | ||
510 | |||
511 | /* remove last node */ | ||
512 | key->prefixlen = 24; | ||
513 | inet_pton(AF_INET, "192.168.128.0", key->data); | ||
514 | assert(bpf_map_delete_elem(map_fd, key) == 0); | ||
515 | |||
516 | key->prefixlen = 32; | ||
517 | inet_pton(AF_INET, "192.168.128.1", key->data); | ||
518 | assert(bpf_map_lookup_elem(map_fd, key, &value) == -1 && | ||
519 | errno == ENOENT); | ||
520 | |||
521 | close(map_fd); | ||
522 | } | ||
523 | |||
335 | int main(void) | 524 | int main(void) |
336 | { | 525 | { |
337 | struct rlimit limit = { RLIM_INFINITY, RLIM_INFINITY }; | 526 | struct rlimit limit = { RLIM_INFINITY, RLIM_INFINITY }; |
@@ -354,6 +543,8 @@ int main(void) | |||
354 | 543 | ||
355 | test_lpm_ipaddr(); | 544 | test_lpm_ipaddr(); |
356 | 545 | ||
546 | test_lpm_delete(); | ||
547 | |||
357 | printf("test_lpm: OK\n"); | 548 | printf("test_lpm: OK\n"); |
358 | return 0; | 549 | return 0; |
359 | } | 550 | } |
diff --git a/tools/testing/selftests/bpf/test_maps.c b/tools/testing/selftests/bpf/test_maps.c index 50ce52d2013d..040356ecc862 100644 --- a/tools/testing/selftests/bpf/test_maps.c +++ b/tools/testing/selftests/bpf/test_maps.c | |||
@@ -1043,6 +1043,51 @@ static void test_map_parallel(void) | |||
1043 | assert(bpf_map_get_next_key(fd, &key, &key) == -1 && errno == ENOENT); | 1043 | assert(bpf_map_get_next_key(fd, &key, &key) == -1 && errno == ENOENT); |
1044 | } | 1044 | } |
1045 | 1045 | ||
1046 | static void test_map_rdonly(void) | ||
1047 | { | ||
1048 | int fd, key = 0, value = 0; | ||
1049 | |||
1050 | fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value), | ||
1051 | MAP_SIZE, map_flags | BPF_F_RDONLY); | ||
1052 | if (fd < 0) { | ||
1053 | printf("Failed to create map for read only test '%s'!\n", | ||
1054 | strerror(errno)); | ||
1055 | exit(1); | ||
1056 | } | ||
1057 | |||
1058 | key = 1; | ||
1059 | value = 1234; | ||
1060 | /* Insert key=1 element. */ | ||
1061 | assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) == -1 && | ||
1062 | errno == EPERM); | ||
1063 | |||
1064 | /* Check that key=2 is not found. */ | ||
1065 | assert(bpf_map_lookup_elem(fd, &key, &value) == -1 && errno == ENOENT); | ||
1066 | assert(bpf_map_get_next_key(fd, &key, &value) == -1 && errno == ENOENT); | ||
1067 | } | ||
1068 | |||
1069 | static void test_map_wronly(void) | ||
1070 | { | ||
1071 | int fd, key = 0, value = 0; | ||
1072 | |||
1073 | fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value), | ||
1074 | MAP_SIZE, map_flags | BPF_F_WRONLY); | ||
1075 | if (fd < 0) { | ||
1076 | printf("Failed to create map for read only test '%s'!\n", | ||
1077 | strerror(errno)); | ||
1078 | exit(1); | ||
1079 | } | ||
1080 | |||
1081 | key = 1; | ||
1082 | value = 1234; | ||
1083 | /* Insert key=1 element. */ | ||
1084 | assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) == 0); | ||
1085 | |||
1086 | /* Check that key=2 is not found. */ | ||
1087 | assert(bpf_map_lookup_elem(fd, &key, &value) == -1 && errno == EPERM); | ||
1088 | assert(bpf_map_get_next_key(fd, &key, &value) == -1 && errno == EPERM); | ||
1089 | } | ||
1090 | |||
1046 | static void run_all_tests(void) | 1091 | static void run_all_tests(void) |
1047 | { | 1092 | { |
1048 | test_hashmap(0, NULL); | 1093 | test_hashmap(0, NULL); |
@@ -1060,6 +1105,9 @@ static void run_all_tests(void) | |||
1060 | test_map_large(); | 1105 | test_map_large(); |
1061 | test_map_parallel(); | 1106 | test_map_parallel(); |
1062 | test_map_stress(); | 1107 | test_map_stress(); |
1108 | |||
1109 | test_map_rdonly(); | ||
1110 | test_map_wronly(); | ||
1063 | } | 1111 | } |
1064 | 1112 | ||
1065 | int main(void) | 1113 | int main(void) |
diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c index 11ee25cea227..69427531408d 100644 --- a/tools/testing/selftests/bpf/test_progs.c +++ b/tools/testing/selftests/bpf/test_progs.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <string.h> | 10 | #include <string.h> |
11 | #include <assert.h> | 11 | #include <assert.h> |
12 | #include <stdlib.h> | 12 | #include <stdlib.h> |
13 | #include <time.h> | ||
13 | 14 | ||
14 | #include <linux/types.h> | 15 | #include <linux/types.h> |
15 | typedef __u16 __sum16; | 16 | typedef __u16 __sum16; |
@@ -19,6 +20,8 @@ typedef __u16 __sum16; | |||
19 | #include <linux/ip.h> | 20 | #include <linux/ip.h> |
20 | #include <linux/ipv6.h> | 21 | #include <linux/ipv6.h> |
21 | #include <linux/tcp.h> | 22 | #include <linux/tcp.h> |
23 | #include <linux/filter.h> | ||
24 | #include <linux/unistd.h> | ||
22 | 25 | ||
23 | #include <sys/wait.h> | 26 | #include <sys/wait.h> |
24 | #include <sys/resource.h> | 27 | #include <sys/resource.h> |
@@ -273,16 +276,26 @@ static void test_bpf_obj_id(void) | |||
273 | const int nr_iters = 2; | 276 | const int nr_iters = 2; |
274 | const char *file = "./test_obj_id.o"; | 277 | const char *file = "./test_obj_id.o"; |
275 | const char *jit_sysctl = "/proc/sys/net/core/bpf_jit_enable"; | 278 | const char *jit_sysctl = "/proc/sys/net/core/bpf_jit_enable"; |
279 | const char *expected_prog_name = "test_obj_id"; | ||
280 | const char *expected_map_name = "test_map_id"; | ||
281 | const __u64 nsec_per_sec = 1000000000; | ||
276 | 282 | ||
277 | struct bpf_object *objs[nr_iters]; | 283 | struct bpf_object *objs[nr_iters]; |
278 | int prog_fds[nr_iters], map_fds[nr_iters]; | 284 | int prog_fds[nr_iters], map_fds[nr_iters]; |
279 | /* +1 to test for the info_len returned by kernel */ | 285 | /* +1 to test for the info_len returned by kernel */ |
280 | struct bpf_prog_info prog_infos[nr_iters + 1]; | 286 | struct bpf_prog_info prog_infos[nr_iters + 1]; |
281 | struct bpf_map_info map_infos[nr_iters + 1]; | 287 | struct bpf_map_info map_infos[nr_iters + 1]; |
288 | /* Each prog only uses one map. +1 to test nr_map_ids | ||
289 | * returned by kernel. | ||
290 | */ | ||
291 | __u32 map_ids[nr_iters + 1]; | ||
282 | char jited_insns[128], xlated_insns[128], zeros[128]; | 292 | char jited_insns[128], xlated_insns[128], zeros[128]; |
283 | __u32 i, next_id, info_len, nr_id_found, duration = 0; | 293 | __u32 i, next_id, info_len, nr_id_found, duration = 0; |
294 | struct timespec real_time_ts, boot_time_ts; | ||
284 | int sysctl_fd, jit_enabled = 0, err = 0; | 295 | int sysctl_fd, jit_enabled = 0, err = 0; |
285 | __u64 array_value; | 296 | __u64 array_value; |
297 | uid_t my_uid = getuid(); | ||
298 | time_t now, load_time; | ||
286 | 299 | ||
287 | sysctl_fd = open(jit_sysctl, 0, O_RDONLY); | 300 | sysctl_fd = open(jit_sysctl, 0, O_RDONLY); |
288 | if (sysctl_fd != -1) { | 301 | if (sysctl_fd != -1) { |
@@ -307,6 +320,7 @@ static void test_bpf_obj_id(void) | |||
307 | /* Check bpf_obj_get_info_by_fd() */ | 320 | /* Check bpf_obj_get_info_by_fd() */ |
308 | bzero(zeros, sizeof(zeros)); | 321 | bzero(zeros, sizeof(zeros)); |
309 | for (i = 0; i < nr_iters; i++) { | 322 | for (i = 0; i < nr_iters; i++) { |
323 | now = time(NULL); | ||
310 | err = bpf_prog_load(file, BPF_PROG_TYPE_SOCKET_FILTER, | 324 | err = bpf_prog_load(file, BPF_PROG_TYPE_SOCKET_FILTER, |
311 | &objs[i], &prog_fds[i]); | 325 | &objs[i], &prog_fds[i]); |
312 | /* test_obj_id.o is a dumb prog. It should never fail | 326 | /* test_obj_id.o is a dumb prog. It should never fail |
@@ -316,6 +330,38 @@ static void test_bpf_obj_id(void) | |||
316 | error_cnt++; | 330 | error_cnt++; |
317 | assert(!err); | 331 | assert(!err); |
318 | 332 | ||
333 | /* Insert a magic value to the map */ | ||
334 | map_fds[i] = bpf_find_map(__func__, objs[i], "test_map_id"); | ||
335 | assert(map_fds[i] >= 0); | ||
336 | err = bpf_map_update_elem(map_fds[i], &array_key, | ||
337 | &array_magic_value, 0); | ||
338 | assert(!err); | ||
339 | |||
340 | /* Check getting map info */ | ||
341 | info_len = sizeof(struct bpf_map_info) * 2; | ||
342 | bzero(&map_infos[i], info_len); | ||
343 | err = bpf_obj_get_info_by_fd(map_fds[i], &map_infos[i], | ||
344 | &info_len); | ||
345 | if (CHECK(err || | ||
346 | map_infos[i].type != BPF_MAP_TYPE_ARRAY || | ||
347 | map_infos[i].key_size != sizeof(__u32) || | ||
348 | map_infos[i].value_size != sizeof(__u64) || | ||
349 | map_infos[i].max_entries != 1 || | ||
350 | map_infos[i].map_flags != 0 || | ||
351 | info_len != sizeof(struct bpf_map_info) || | ||
352 | strcmp((char *)map_infos[i].name, expected_map_name), | ||
353 | "get-map-info(fd)", | ||
354 | "err %d errno %d type %d(%d) info_len %u(%lu) key_size %u value_size %u max_entries %u map_flags %X name %s(%s)\n", | ||
355 | err, errno, | ||
356 | map_infos[i].type, BPF_MAP_TYPE_ARRAY, | ||
357 | info_len, sizeof(struct bpf_map_info), | ||
358 | map_infos[i].key_size, | ||
359 | map_infos[i].value_size, | ||
360 | map_infos[i].max_entries, | ||
361 | map_infos[i].map_flags, | ||
362 | map_infos[i].name, expected_map_name)) | ||
363 | goto done; | ||
364 | |||
319 | /* Check getting prog info */ | 365 | /* Check getting prog info */ |
320 | info_len = sizeof(struct bpf_prog_info) * 2; | 366 | info_len = sizeof(struct bpf_prog_info) * 2; |
321 | bzero(&prog_infos[i], info_len); | 367 | bzero(&prog_infos[i], info_len); |
@@ -325,8 +371,16 @@ static void test_bpf_obj_id(void) | |||
325 | prog_infos[i].jited_prog_len = sizeof(jited_insns); | 371 | prog_infos[i].jited_prog_len = sizeof(jited_insns); |
326 | prog_infos[i].xlated_prog_insns = ptr_to_u64(xlated_insns); | 372 | prog_infos[i].xlated_prog_insns = ptr_to_u64(xlated_insns); |
327 | prog_infos[i].xlated_prog_len = sizeof(xlated_insns); | 373 | prog_infos[i].xlated_prog_len = sizeof(xlated_insns); |
374 | prog_infos[i].map_ids = ptr_to_u64(map_ids + i); | ||
375 | prog_infos[i].nr_map_ids = 2; | ||
376 | err = clock_gettime(CLOCK_REALTIME, &real_time_ts); | ||
377 | assert(!err); | ||
378 | err = clock_gettime(CLOCK_BOOTTIME, &boot_time_ts); | ||
379 | assert(!err); | ||
328 | err = bpf_obj_get_info_by_fd(prog_fds[i], &prog_infos[i], | 380 | err = bpf_obj_get_info_by_fd(prog_fds[i], &prog_infos[i], |
329 | &info_len); | 381 | &info_len); |
382 | load_time = (real_time_ts.tv_sec - boot_time_ts.tv_sec) | ||
383 | + (prog_infos[i].load_time / nsec_per_sec); | ||
330 | if (CHECK(err || | 384 | if (CHECK(err || |
331 | prog_infos[i].type != BPF_PROG_TYPE_SOCKET_FILTER || | 385 | prog_infos[i].type != BPF_PROG_TYPE_SOCKET_FILTER || |
332 | info_len != sizeof(struct bpf_prog_info) || | 386 | info_len != sizeof(struct bpf_prog_info) || |
@@ -334,9 +388,14 @@ static void test_bpf_obj_id(void) | |||
334 | (jit_enabled && | 388 | (jit_enabled && |
335 | !memcmp(jited_insns, zeros, sizeof(zeros))) || | 389 | !memcmp(jited_insns, zeros, sizeof(zeros))) || |
336 | !prog_infos[i].xlated_prog_len || | 390 | !prog_infos[i].xlated_prog_len || |
337 | !memcmp(xlated_insns, zeros, sizeof(zeros)), | 391 | !memcmp(xlated_insns, zeros, sizeof(zeros)) || |
392 | load_time < now - 60 || load_time > now + 60 || | ||
393 | prog_infos[i].created_by_uid != my_uid || | ||
394 | prog_infos[i].nr_map_ids != 1 || | ||
395 | *(int *)prog_infos[i].map_ids != map_infos[i].id || | ||
396 | strcmp((char *)prog_infos[i].name, expected_prog_name), | ||
338 | "get-prog-info(fd)", | 397 | "get-prog-info(fd)", |
339 | "err %d errno %d i %d type %d(%d) info_len %u(%lu) jit_enabled %d jited_prog_len %u xlated_prog_len %u jited_prog %d xlated_prog %d\n", | 398 | "err %d errno %d i %d type %d(%d) info_len %u(%lu) jit_enabled %d jited_prog_len %u xlated_prog_len %u jited_prog %d xlated_prog %d load_time %lu(%lu) uid %u(%u) nr_map_ids %u(%u) map_id %u(%u) name %s(%s)\n", |
340 | err, errno, i, | 399 | err, errno, i, |
341 | prog_infos[i].type, BPF_PROG_TYPE_SOCKET_FILTER, | 400 | prog_infos[i].type, BPF_PROG_TYPE_SOCKET_FILTER, |
342 | info_len, sizeof(struct bpf_prog_info), | 401 | info_len, sizeof(struct bpf_prog_info), |
@@ -344,36 +403,12 @@ static void test_bpf_obj_id(void) | |||
344 | prog_infos[i].jited_prog_len, | 403 | prog_infos[i].jited_prog_len, |
345 | prog_infos[i].xlated_prog_len, | 404 | prog_infos[i].xlated_prog_len, |
346 | !!memcmp(jited_insns, zeros, sizeof(zeros)), | 405 | !!memcmp(jited_insns, zeros, sizeof(zeros)), |
347 | !!memcmp(xlated_insns, zeros, sizeof(zeros)))) | 406 | !!memcmp(xlated_insns, zeros, sizeof(zeros)), |
348 | goto done; | 407 | load_time, now, |
349 | 408 | prog_infos[i].created_by_uid, my_uid, | |
350 | map_fds[i] = bpf_find_map(__func__, objs[i], "test_map_id"); | 409 | prog_infos[i].nr_map_ids, 1, |
351 | assert(map_fds[i] >= 0); | 410 | *(int *)prog_infos[i].map_ids, map_infos[i].id, |
352 | err = bpf_map_update_elem(map_fds[i], &array_key, | 411 | prog_infos[i].name, expected_prog_name)) |
353 | &array_magic_value, 0); | ||
354 | assert(!err); | ||
355 | |||
356 | /* Check getting map info */ | ||
357 | info_len = sizeof(struct bpf_map_info) * 2; | ||
358 | bzero(&map_infos[i], info_len); | ||
359 | err = bpf_obj_get_info_by_fd(map_fds[i], &map_infos[i], | ||
360 | &info_len); | ||
361 | if (CHECK(err || | ||
362 | map_infos[i].type != BPF_MAP_TYPE_ARRAY || | ||
363 | map_infos[i].key_size != sizeof(__u32) || | ||
364 | map_infos[i].value_size != sizeof(__u64) || | ||
365 | map_infos[i].max_entries != 1 || | ||
366 | map_infos[i].map_flags != 0 || | ||
367 | info_len != sizeof(struct bpf_map_info), | ||
368 | "get-map-info(fd)", | ||
369 | "err %d errno %d type %d(%d) info_len %u(%lu) key_size %u value_size %u max_entries %u map_flags %X\n", | ||
370 | err, errno, | ||
371 | map_infos[i].type, BPF_MAP_TYPE_ARRAY, | ||
372 | info_len, sizeof(struct bpf_map_info), | ||
373 | map_infos[i].key_size, | ||
374 | map_infos[i].value_size, | ||
375 | map_infos[i].max_entries, | ||
376 | map_infos[i].map_flags)) | ||
377 | goto done; | 412 | goto done; |
378 | } | 413 | } |
379 | 414 | ||
@@ -382,6 +417,7 @@ static void test_bpf_obj_id(void) | |||
382 | next_id = 0; | 417 | next_id = 0; |
383 | while (!bpf_prog_get_next_id(next_id, &next_id)) { | 418 | while (!bpf_prog_get_next_id(next_id, &next_id)) { |
384 | struct bpf_prog_info prog_info = {}; | 419 | struct bpf_prog_info prog_info = {}; |
420 | __u32 saved_map_id; | ||
385 | int prog_fd; | 421 | int prog_fd; |
386 | 422 | ||
387 | info_len = sizeof(prog_info); | 423 | info_len = sizeof(prog_info); |
@@ -404,16 +440,33 @@ static void test_bpf_obj_id(void) | |||
404 | 440 | ||
405 | nr_id_found++; | 441 | nr_id_found++; |
406 | 442 | ||
443 | /* Negative test: | ||
444 | * prog_info.nr_map_ids = 1 | ||
445 | * prog_info.map_ids = NULL | ||
446 | */ | ||
447 | prog_info.nr_map_ids = 1; | ||
448 | err = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &info_len); | ||
449 | if (CHECK(!err || errno != EFAULT, | ||
450 | "get-prog-fd-bad-nr-map-ids", "err %d errno %d(%d)", | ||
451 | err, errno, EFAULT)) | ||
452 | break; | ||
453 | bzero(&prog_info, sizeof(prog_info)); | ||
454 | info_len = sizeof(prog_info); | ||
455 | |||
456 | saved_map_id = *(int *)(prog_infos[i].map_ids); | ||
457 | prog_info.map_ids = prog_infos[i].map_ids; | ||
458 | prog_info.nr_map_ids = 2; | ||
407 | err = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &info_len); | 459 | err = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &info_len); |
408 | prog_infos[i].jited_prog_insns = 0; | 460 | prog_infos[i].jited_prog_insns = 0; |
409 | prog_infos[i].xlated_prog_insns = 0; | 461 | prog_infos[i].xlated_prog_insns = 0; |
410 | CHECK(err || info_len != sizeof(struct bpf_prog_info) || | 462 | CHECK(err || info_len != sizeof(struct bpf_prog_info) || |
411 | memcmp(&prog_info, &prog_infos[i], info_len), | 463 | memcmp(&prog_info, &prog_infos[i], info_len) || |
464 | *(int *)prog_info.map_ids != saved_map_id, | ||
412 | "get-prog-info(next_id->fd)", | 465 | "get-prog-info(next_id->fd)", |
413 | "err %d errno %d info_len %u(%lu) memcmp %d\n", | 466 | "err %d errno %d info_len %u(%lu) memcmp %d map_id %u(%u)\n", |
414 | err, errno, info_len, sizeof(struct bpf_prog_info), | 467 | err, errno, info_len, sizeof(struct bpf_prog_info), |
415 | memcmp(&prog_info, &prog_infos[i], info_len)); | 468 | memcmp(&prog_info, &prog_infos[i], info_len), |
416 | 469 | *(int *)prog_info.map_ids, saved_map_id); | |
417 | close(prog_fd); | 470 | close(prog_fd); |
418 | } | 471 | } |
419 | CHECK(nr_id_found != nr_iters, | 472 | CHECK(nr_id_found != nr_iters, |
@@ -495,6 +548,75 @@ static void test_pkt_md_access(void) | |||
495 | bpf_object__close(obj); | 548 | bpf_object__close(obj); |
496 | } | 549 | } |
497 | 550 | ||
551 | static void test_obj_name(void) | ||
552 | { | ||
553 | struct { | ||
554 | const char *name; | ||
555 | int success; | ||
556 | int expected_errno; | ||
557 | } tests[] = { | ||
558 | { "", 1, 0 }, | ||
559 | { "_123456789ABCDE", 1, 0 }, | ||
560 | { "_123456789ABCDEF", 0, EINVAL }, | ||
561 | { "_123456789ABCD\n", 0, EINVAL }, | ||
562 | }; | ||
563 | struct bpf_insn prog[] = { | ||
564 | BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 0), | ||
565 | BPF_EXIT_INSN(), | ||
566 | }; | ||
567 | __u32 duration = 0; | ||
568 | int i; | ||
569 | |||
570 | for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { | ||
571 | size_t name_len = strlen(tests[i].name) + 1; | ||
572 | union bpf_attr attr; | ||
573 | size_t ncopy; | ||
574 | int fd; | ||
575 | |||
576 | /* test different attr.prog_name during BPF_PROG_LOAD */ | ||
577 | ncopy = name_len < sizeof(attr.prog_name) ? | ||
578 | name_len : sizeof(attr.prog_name); | ||
579 | bzero(&attr, sizeof(attr)); | ||
580 | attr.prog_type = BPF_PROG_TYPE_SCHED_CLS; | ||
581 | attr.insn_cnt = 2; | ||
582 | attr.insns = ptr_to_u64(prog); | ||
583 | attr.license = ptr_to_u64(""); | ||
584 | memcpy(attr.prog_name, tests[i].name, ncopy); | ||
585 | |||
586 | fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr)); | ||
587 | CHECK((tests[i].success && fd < 0) || | ||
588 | (!tests[i].success && fd != -1) || | ||
589 | (!tests[i].success && errno != tests[i].expected_errno), | ||
590 | "check-bpf-prog-name", | ||
591 | "fd %d(%d) errno %d(%d)\n", | ||
592 | fd, tests[i].success, errno, tests[i].expected_errno); | ||
593 | |||
594 | if (fd != -1) | ||
595 | close(fd); | ||
596 | |||
597 | /* test different attr.map_name during BPF_MAP_CREATE */ | ||
598 | ncopy = name_len < sizeof(attr.map_name) ? | ||
599 | name_len : sizeof(attr.map_name); | ||
600 | bzero(&attr, sizeof(attr)); | ||
601 | attr.map_type = BPF_MAP_TYPE_ARRAY; | ||
602 | attr.key_size = 4; | ||
603 | attr.value_size = 4; | ||
604 | attr.max_entries = 1; | ||
605 | attr.map_flags = 0; | ||
606 | memcpy(attr.map_name, tests[i].name, ncopy); | ||
607 | fd = syscall(__NR_bpf, BPF_MAP_CREATE, &attr, sizeof(attr)); | ||
608 | CHECK((tests[i].success && fd < 0) || | ||
609 | (!tests[i].success && fd != -1) || | ||
610 | (!tests[i].success && errno != tests[i].expected_errno), | ||
611 | "check-bpf-map-name", | ||
612 | "fd %d(%d) errno %d(%d)\n", | ||
613 | fd, tests[i].success, errno, tests[i].expected_errno); | ||
614 | |||
615 | if (fd != -1) | ||
616 | close(fd); | ||
617 | } | ||
618 | } | ||
619 | |||
498 | int main(void) | 620 | int main(void) |
499 | { | 621 | { |
500 | struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY }; | 622 | struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY }; |
@@ -507,6 +629,7 @@ int main(void) | |||
507 | test_tcp_estats(); | 629 | test_tcp_estats(); |
508 | test_bpf_obj_id(); | 630 | test_bpf_obj_id(); |
509 | test_pkt_md_access(); | 631 | test_pkt_md_access(); |
632 | test_obj_name(); | ||
510 | 633 | ||
511 | printf("Summary: %d PASSED, %d FAILED\n", pass_cnt, error_cnt); | 634 | printf("Summary: %d PASSED, %d FAILED\n", pass_cnt, error_cnt); |
512 | return error_cnt ? EXIT_FAILURE : EXIT_SUCCESS; | 635 | return error_cnt ? EXIT_FAILURE : EXIT_SUCCESS; |
diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 64ae21f64489..3c64f30cf63c 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c | |||
@@ -3579,7 +3579,7 @@ static struct bpf_test tests[] = { | |||
3579 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 3579 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
3580 | }, | 3580 | }, |
3581 | { | 3581 | { |
3582 | "helper access to packet: test19, cls helper fail range zero", | 3582 | "helper access to packet: test19, cls helper range zero", |
3583 | .insns = { | 3583 | .insns = { |
3584 | BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, | 3584 | BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, |
3585 | offsetof(struct __sk_buff, data)), | 3585 | offsetof(struct __sk_buff, data)), |
@@ -3599,8 +3599,7 @@ static struct bpf_test tests[] = { | |||
3599 | BPF_MOV64_IMM(BPF_REG_0, 0), | 3599 | BPF_MOV64_IMM(BPF_REG_0, 0), |
3600 | BPF_EXIT_INSN(), | 3600 | BPF_EXIT_INSN(), |
3601 | }, | 3601 | }, |
3602 | .result = REJECT, | 3602 | .result = ACCEPT, |
3603 | .errstr = "invalid access to packet", | ||
3604 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 3603 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
3605 | }, | 3604 | }, |
3606 | { | 3605 | { |
@@ -4378,11 +4377,10 @@ static struct bpf_test tests[] = { | |||
4378 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | 4377 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), |
4379 | BPF_LD_MAP_FD(BPF_REG_1, 0), | 4378 | BPF_LD_MAP_FD(BPF_REG_1, 0), |
4380 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | 4379 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), |
4381 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4), | 4380 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3), |
4382 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | 4381 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), |
4383 | BPF_MOV64_IMM(BPF_REG_2, 0), | 4382 | BPF_MOV64_IMM(BPF_REG_2, 0), |
4384 | BPF_MOV64_IMM(BPF_REG_3, 0), | 4383 | BPF_EMIT_CALL(BPF_FUNC_trace_printk), |
4385 | BPF_EMIT_CALL(BPF_FUNC_probe_read), | ||
4386 | BPF_EXIT_INSN(), | 4384 | BPF_EXIT_INSN(), |
4387 | }, | 4385 | }, |
4388 | .fixup_map2 = { 3 }, | 4386 | .fixup_map2 = { 3 }, |
@@ -4482,13 +4480,12 @@ static struct bpf_test tests[] = { | |||
4482 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | 4480 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), |
4483 | BPF_LD_MAP_FD(BPF_REG_1, 0), | 4481 | BPF_LD_MAP_FD(BPF_REG_1, 0), |
4484 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | 4482 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), |
4485 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5), | 4483 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4), |
4486 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | 4484 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), |
4487 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, | 4485 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, |
4488 | offsetof(struct test_val, foo)), | 4486 | offsetof(struct test_val, foo)), |
4489 | BPF_MOV64_IMM(BPF_REG_2, 0), | 4487 | BPF_MOV64_IMM(BPF_REG_2, 0), |
4490 | BPF_MOV64_IMM(BPF_REG_3, 0), | 4488 | BPF_EMIT_CALL(BPF_FUNC_trace_printk), |
4491 | BPF_EMIT_CALL(BPF_FUNC_probe_read), | ||
4492 | BPF_EXIT_INSN(), | 4489 | BPF_EXIT_INSN(), |
4493 | }, | 4490 | }, |
4494 | .fixup_map2 = { 3 }, | 4491 | .fixup_map2 = { 3 }, |
@@ -4618,13 +4615,12 @@ static struct bpf_test tests[] = { | |||
4618 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | 4615 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), |
4619 | BPF_LD_MAP_FD(BPF_REG_1, 0), | 4616 | BPF_LD_MAP_FD(BPF_REG_1, 0), |
4620 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | 4617 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), |
4621 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6), | 4618 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5), |
4622 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | 4619 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), |
4623 | BPF_MOV64_IMM(BPF_REG_3, 0), | 4620 | BPF_MOV64_IMM(BPF_REG_3, 0), |
4624 | BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_3), | 4621 | BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_3), |
4625 | BPF_MOV64_IMM(BPF_REG_2, 0), | 4622 | BPF_MOV64_IMM(BPF_REG_2, 0), |
4626 | BPF_MOV64_IMM(BPF_REG_3, 0), | 4623 | BPF_EMIT_CALL(BPF_FUNC_trace_printk), |
4627 | BPF_EMIT_CALL(BPF_FUNC_probe_read), | ||
4628 | BPF_EXIT_INSN(), | 4624 | BPF_EXIT_INSN(), |
4629 | }, | 4625 | }, |
4630 | .fixup_map2 = { 3 }, | 4626 | .fixup_map2 = { 3 }, |
@@ -4759,15 +4755,14 @@ static struct bpf_test tests[] = { | |||
4759 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), | 4755 | BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), |
4760 | BPF_LD_MAP_FD(BPF_REG_1, 0), | 4756 | BPF_LD_MAP_FD(BPF_REG_1, 0), |
4761 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | 4757 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), |
4762 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 7), | 4758 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6), |
4763 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | 4759 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), |
4764 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_0, 0), | 4760 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_0, 0), |
4765 | BPF_JMP_IMM(BPF_JGT, BPF_REG_3, | 4761 | BPF_JMP_IMM(BPF_JGT, BPF_REG_3, |
4766 | offsetof(struct test_val, foo), 4), | 4762 | offsetof(struct test_val, foo), 3), |
4767 | BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_3), | 4763 | BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_3), |
4768 | BPF_MOV64_IMM(BPF_REG_2, 0), | 4764 | BPF_MOV64_IMM(BPF_REG_2, 0), |
4769 | BPF_MOV64_IMM(BPF_REG_3, 0), | 4765 | BPF_EMIT_CALL(BPF_FUNC_trace_printk), |
4770 | BPF_EMIT_CALL(BPF_FUNC_probe_read), | ||
4771 | BPF_EXIT_INSN(), | 4766 | BPF_EXIT_INSN(), |
4772 | }, | 4767 | }, |
4773 | .fixup_map2 = { 3 }, | 4768 | .fixup_map2 = { 3 }, |
@@ -5350,7 +5345,7 @@ static struct bpf_test tests[] = { | |||
5350 | BPF_EMIT_CALL(BPF_FUNC_probe_read), | 5345 | BPF_EMIT_CALL(BPF_FUNC_probe_read), |
5351 | BPF_EXIT_INSN(), | 5346 | BPF_EXIT_INSN(), |
5352 | }, | 5347 | }, |
5353 | .errstr = "invalid stack type R1 off=-64 access_size=0", | 5348 | .errstr = "invalid indirect read from stack off -64+0 size 64", |
5354 | .result = REJECT, | 5349 | .result = REJECT, |
5355 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 5350 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
5356 | }, | 5351 | }, |
@@ -5505,7 +5500,7 @@ static struct bpf_test tests[] = { | |||
5505 | BPF_MOV64_IMM(BPF_REG_0, 0), | 5500 | BPF_MOV64_IMM(BPF_REG_0, 0), |
5506 | BPF_EXIT_INSN(), | 5501 | BPF_EXIT_INSN(), |
5507 | }, | 5502 | }, |
5508 | .errstr = "invalid stack type R1 off=-64 access_size=0", | 5503 | .errstr = "invalid indirect read from stack off -64+0 size 64", |
5509 | .result = REJECT, | 5504 | .result = REJECT, |
5510 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 5505 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
5511 | }, | 5506 | }, |
@@ -5636,7 +5631,7 @@ static struct bpf_test tests[] = { | |||
5636 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 5631 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
5637 | }, | 5632 | }, |
5638 | { | 5633 | { |
5639 | "helper access to variable memory: size = 0 allowed on NULL", | 5634 | "helper access to variable memory: size = 0 allowed on NULL (ARG_PTR_TO_MEM_OR_NULL)", |
5640 | .insns = { | 5635 | .insns = { |
5641 | BPF_MOV64_IMM(BPF_REG_1, 0), | 5636 | BPF_MOV64_IMM(BPF_REG_1, 0), |
5642 | BPF_MOV64_IMM(BPF_REG_2, 0), | 5637 | BPF_MOV64_IMM(BPF_REG_2, 0), |
@@ -5650,7 +5645,7 @@ static struct bpf_test tests[] = { | |||
5650 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 5645 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
5651 | }, | 5646 | }, |
5652 | { | 5647 | { |
5653 | "helper access to variable memory: size > 0 not allowed on NULL", | 5648 | "helper access to variable memory: size > 0 not allowed on NULL (ARG_PTR_TO_MEM_OR_NULL)", |
5654 | .insns = { | 5649 | .insns = { |
5655 | BPF_MOV64_IMM(BPF_REG_1, 0), | 5650 | BPF_MOV64_IMM(BPF_REG_1, 0), |
5656 | BPF_MOV64_IMM(BPF_REG_2, 0), | 5651 | BPF_MOV64_IMM(BPF_REG_2, 0), |
@@ -5668,7 +5663,7 @@ static struct bpf_test tests[] = { | |||
5668 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 5663 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
5669 | }, | 5664 | }, |
5670 | { | 5665 | { |
5671 | "helper access to variable memory: size = 0 not allowed on != NULL", | 5666 | "helper access to variable memory: size = 0 allowed on != NULL stack pointer (ARG_PTR_TO_MEM_OR_NULL)", |
5672 | .insns = { | 5667 | .insns = { |
5673 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), | 5668 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), |
5674 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8), | 5669 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8), |
@@ -5681,11 +5676,201 @@ static struct bpf_test tests[] = { | |||
5681 | BPF_EMIT_CALL(BPF_FUNC_csum_diff), | 5676 | BPF_EMIT_CALL(BPF_FUNC_csum_diff), |
5682 | BPF_EXIT_INSN(), | 5677 | BPF_EXIT_INSN(), |
5683 | }, | 5678 | }, |
5684 | .errstr = "invalid stack type R1 off=-8 access_size=0", | 5679 | .result = ACCEPT, |
5685 | .result = REJECT, | 5680 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
5681 | }, | ||
5682 | { | ||
5683 | "helper access to variable memory: size = 0 allowed on != NULL map pointer (ARG_PTR_TO_MEM_OR_NULL)", | ||
5684 | .insns = { | ||
5685 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
5686 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
5687 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
5688 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
5689 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
5690 | BPF_FUNC_map_lookup_elem), | ||
5691 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6), | ||
5692 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
5693 | BPF_MOV64_IMM(BPF_REG_2, 0), | ||
5694 | BPF_MOV64_IMM(BPF_REG_3, 0), | ||
5695 | BPF_MOV64_IMM(BPF_REG_4, 0), | ||
5696 | BPF_MOV64_IMM(BPF_REG_5, 0), | ||
5697 | BPF_EMIT_CALL(BPF_FUNC_csum_diff), | ||
5698 | BPF_EXIT_INSN(), | ||
5699 | }, | ||
5700 | .fixup_map1 = { 3 }, | ||
5701 | .result = ACCEPT, | ||
5702 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
5703 | }, | ||
5704 | { | ||
5705 | "helper access to variable memory: size possible = 0 allowed on != NULL stack pointer (ARG_PTR_TO_MEM_OR_NULL)", | ||
5706 | .insns = { | ||
5707 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
5708 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
5709 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
5710 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
5711 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
5712 | BPF_FUNC_map_lookup_elem), | ||
5713 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 9), | ||
5714 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_0, 0), | ||
5715 | BPF_JMP_IMM(BPF_JGT, BPF_REG_2, 8, 7), | ||
5716 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), | ||
5717 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8), | ||
5718 | BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_2, 0), | ||
5719 | BPF_MOV64_IMM(BPF_REG_3, 0), | ||
5720 | BPF_MOV64_IMM(BPF_REG_4, 0), | ||
5721 | BPF_MOV64_IMM(BPF_REG_5, 0), | ||
5722 | BPF_EMIT_CALL(BPF_FUNC_csum_diff), | ||
5723 | BPF_EXIT_INSN(), | ||
5724 | }, | ||
5725 | .fixup_map1 = { 3 }, | ||
5726 | .result = ACCEPT, | ||
5727 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
5728 | }, | ||
5729 | { | ||
5730 | "helper access to variable memory: size possible = 0 allowed on != NULL map pointer (ARG_PTR_TO_MEM_OR_NULL)", | ||
5731 | .insns = { | ||
5732 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
5733 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
5734 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
5735 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
5736 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
5737 | BPF_FUNC_map_lookup_elem), | ||
5738 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 7), | ||
5739 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
5740 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_0, 0), | ||
5741 | BPF_JMP_IMM(BPF_JGT, BPF_REG_2, 8, 4), | ||
5742 | BPF_MOV64_IMM(BPF_REG_3, 0), | ||
5743 | BPF_MOV64_IMM(BPF_REG_4, 0), | ||
5744 | BPF_MOV64_IMM(BPF_REG_5, 0), | ||
5745 | BPF_EMIT_CALL(BPF_FUNC_csum_diff), | ||
5746 | BPF_EXIT_INSN(), | ||
5747 | }, | ||
5748 | .fixup_map1 = { 3 }, | ||
5749 | .result = ACCEPT, | ||
5750 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
5751 | }, | ||
5752 | { | ||
5753 | "helper access to variable memory: size possible = 0 allowed on != NULL packet pointer (ARG_PTR_TO_MEM_OR_NULL)", | ||
5754 | .insns = { | ||
5755 | BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, | ||
5756 | offsetof(struct __sk_buff, data)), | ||
5757 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
5758 | offsetof(struct __sk_buff, data_end)), | ||
5759 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_6), | ||
5760 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), | ||
5761 | BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 7), | ||
5762 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), | ||
5763 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_6, 0), | ||
5764 | BPF_JMP_IMM(BPF_JGT, BPF_REG_2, 8, 4), | ||
5765 | BPF_MOV64_IMM(BPF_REG_3, 0), | ||
5766 | BPF_MOV64_IMM(BPF_REG_4, 0), | ||
5767 | BPF_MOV64_IMM(BPF_REG_5, 0), | ||
5768 | BPF_EMIT_CALL(BPF_FUNC_csum_diff), | ||
5769 | BPF_EXIT_INSN(), | ||
5770 | }, | ||
5771 | .result = ACCEPT, | ||
5686 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 5772 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
5687 | }, | 5773 | }, |
5688 | { | 5774 | { |
5775 | "helper access to variable memory: size = 0 not allowed on NULL (!ARG_PTR_TO_MEM_OR_NULL)", | ||
5776 | .insns = { | ||
5777 | BPF_MOV64_IMM(BPF_REG_1, 0), | ||
5778 | BPF_MOV64_IMM(BPF_REG_2, 0), | ||
5779 | BPF_MOV64_IMM(BPF_REG_3, 0), | ||
5780 | BPF_EMIT_CALL(BPF_FUNC_probe_read), | ||
5781 | BPF_EXIT_INSN(), | ||
5782 | }, | ||
5783 | .errstr = "R1 type=inv expected=fp", | ||
5784 | .result = REJECT, | ||
5785 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
5786 | }, | ||
5787 | { | ||
5788 | "helper access to variable memory: size > 0 not allowed on NULL (!ARG_PTR_TO_MEM_OR_NULL)", | ||
5789 | .insns = { | ||
5790 | BPF_MOV64_IMM(BPF_REG_1, 0), | ||
5791 | BPF_MOV64_IMM(BPF_REG_2, 1), | ||
5792 | BPF_MOV64_IMM(BPF_REG_3, 0), | ||
5793 | BPF_EMIT_CALL(BPF_FUNC_probe_read), | ||
5794 | BPF_EXIT_INSN(), | ||
5795 | }, | ||
5796 | .errstr = "R1 type=inv expected=fp", | ||
5797 | .result = REJECT, | ||
5798 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
5799 | }, | ||
5800 | { | ||
5801 | "helper access to variable memory: size = 0 allowed on != NULL stack pointer (!ARG_PTR_TO_MEM_OR_NULL)", | ||
5802 | .insns = { | ||
5803 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), | ||
5804 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8), | ||
5805 | BPF_MOV64_IMM(BPF_REG_2, 0), | ||
5806 | BPF_MOV64_IMM(BPF_REG_3, 0), | ||
5807 | BPF_EMIT_CALL(BPF_FUNC_probe_read), | ||
5808 | BPF_EXIT_INSN(), | ||
5809 | }, | ||
5810 | .result = ACCEPT, | ||
5811 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
5812 | }, | ||
5813 | { | ||
5814 | "helper access to variable memory: size = 0 allowed on != NULL map pointer (!ARG_PTR_TO_MEM_OR_NULL)", | ||
5815 | .insns = { | ||
5816 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
5817 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
5818 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
5819 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
5820 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | ||
5821 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4), | ||
5822 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
5823 | BPF_MOV64_IMM(BPF_REG_2, 0), | ||
5824 | BPF_MOV64_IMM(BPF_REG_3, 0), | ||
5825 | BPF_EMIT_CALL(BPF_FUNC_probe_read), | ||
5826 | BPF_EXIT_INSN(), | ||
5827 | }, | ||
5828 | .fixup_map1 = { 3 }, | ||
5829 | .result = ACCEPT, | ||
5830 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
5831 | }, | ||
5832 | { | ||
5833 | "helper access to variable memory: size possible = 0 allowed on != NULL stack pointer (!ARG_PTR_TO_MEM_OR_NULL)", | ||
5834 | .insns = { | ||
5835 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
5836 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
5837 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
5838 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
5839 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | ||
5840 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6), | ||
5841 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_0, 0), | ||
5842 | BPF_JMP_IMM(BPF_JGT, BPF_REG_2, 8, 4), | ||
5843 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), | ||
5844 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8), | ||
5845 | BPF_MOV64_IMM(BPF_REG_3, 0), | ||
5846 | BPF_EMIT_CALL(BPF_FUNC_probe_read), | ||
5847 | BPF_EXIT_INSN(), | ||
5848 | }, | ||
5849 | .fixup_map1 = { 3 }, | ||
5850 | .result = ACCEPT, | ||
5851 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
5852 | }, | ||
5853 | { | ||
5854 | "helper access to variable memory: size possible = 0 allowed on != NULL map pointer (!ARG_PTR_TO_MEM_OR_NULL)", | ||
5855 | .insns = { | ||
5856 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
5857 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
5858 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
5859 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
5860 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | ||
5861 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5), | ||
5862 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
5863 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_0, 0), | ||
5864 | BPF_JMP_IMM(BPF_JGT, BPF_REG_2, 8, 2), | ||
5865 | BPF_MOV64_IMM(BPF_REG_3, 0), | ||
5866 | BPF_EMIT_CALL(BPF_FUNC_probe_read), | ||
5867 | BPF_EXIT_INSN(), | ||
5868 | }, | ||
5869 | .fixup_map1 = { 3 }, | ||
5870 | .result = ACCEPT, | ||
5871 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
5872 | }, | ||
5873 | { | ||
5689 | "helper access to variable memory: 8 bytes leak", | 5874 | "helper access to variable memory: 8 bytes leak", |
5690 | .insns = { | 5875 | .insns = { |
5691 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), | 5876 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), |
@@ -6658,6 +6843,253 @@ static struct bpf_test tests[] = { | |||
6658 | .result = REJECT, | 6843 | .result = REJECT, |
6659 | }, | 6844 | }, |
6660 | { | 6845 | { |
6846 | "meta access, test1", | ||
6847 | .insns = { | ||
6848 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
6849 | offsetof(struct xdp_md, data_meta)), | ||
6850 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
6851 | offsetof(struct xdp_md, data)), | ||
6852 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), | ||
6853 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), | ||
6854 | BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 1), | ||
6855 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_2, 0), | ||
6856 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
6857 | BPF_EXIT_INSN(), | ||
6858 | }, | ||
6859 | .result = ACCEPT, | ||
6860 | .prog_type = BPF_PROG_TYPE_XDP, | ||
6861 | }, | ||
6862 | { | ||
6863 | "meta access, test2", | ||
6864 | .insns = { | ||
6865 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
6866 | offsetof(struct xdp_md, data_meta)), | ||
6867 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
6868 | offsetof(struct xdp_md, data)), | ||
6869 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), | ||
6870 | BPF_ALU64_IMM(BPF_SUB, BPF_REG_0, 8), | ||
6871 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_2), | ||
6872 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 8), | ||
6873 | BPF_JMP_REG(BPF_JGT, BPF_REG_4, BPF_REG_3, 1), | ||
6874 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0), | ||
6875 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
6876 | BPF_EXIT_INSN(), | ||
6877 | }, | ||
6878 | .result = REJECT, | ||
6879 | .errstr = "invalid access to packet, off=-8", | ||
6880 | .prog_type = BPF_PROG_TYPE_XDP, | ||
6881 | }, | ||
6882 | { | ||
6883 | "meta access, test3", | ||
6884 | .insns = { | ||
6885 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
6886 | offsetof(struct xdp_md, data_meta)), | ||
6887 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
6888 | offsetof(struct xdp_md, data_end)), | ||
6889 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), | ||
6890 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), | ||
6891 | BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 1), | ||
6892 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_2, 0), | ||
6893 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
6894 | BPF_EXIT_INSN(), | ||
6895 | }, | ||
6896 | .result = REJECT, | ||
6897 | .errstr = "invalid access to packet", | ||
6898 | .prog_type = BPF_PROG_TYPE_XDP, | ||
6899 | }, | ||
6900 | { | ||
6901 | "meta access, test4", | ||
6902 | .insns = { | ||
6903 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
6904 | offsetof(struct xdp_md, data_meta)), | ||
6905 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
6906 | offsetof(struct xdp_md, data_end)), | ||
6907 | BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_1, | ||
6908 | offsetof(struct xdp_md, data)), | ||
6909 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_4), | ||
6910 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), | ||
6911 | BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 1), | ||
6912 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_2, 0), | ||
6913 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
6914 | BPF_EXIT_INSN(), | ||
6915 | }, | ||
6916 | .result = REJECT, | ||
6917 | .errstr = "invalid access to packet", | ||
6918 | .prog_type = BPF_PROG_TYPE_XDP, | ||
6919 | }, | ||
6920 | { | ||
6921 | "meta access, test5", | ||
6922 | .insns = { | ||
6923 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
6924 | offsetof(struct xdp_md, data_meta)), | ||
6925 | BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_1, | ||
6926 | offsetof(struct xdp_md, data)), | ||
6927 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_3), | ||
6928 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), | ||
6929 | BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_4, 3), | ||
6930 | BPF_MOV64_IMM(BPF_REG_2, -8), | ||
6931 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
6932 | BPF_FUNC_xdp_adjust_meta), | ||
6933 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_3, 0), | ||
6934 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
6935 | BPF_EXIT_INSN(), | ||
6936 | }, | ||
6937 | .result = REJECT, | ||
6938 | .errstr = "R3 !read_ok", | ||
6939 | .prog_type = BPF_PROG_TYPE_XDP, | ||
6940 | }, | ||
6941 | { | ||
6942 | "meta access, test6", | ||
6943 | .insns = { | ||
6944 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
6945 | offsetof(struct xdp_md, data_meta)), | ||
6946 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
6947 | offsetof(struct xdp_md, data)), | ||
6948 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_3), | ||
6949 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), | ||
6950 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_2), | ||
6951 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 8), | ||
6952 | BPF_JMP_REG(BPF_JGT, BPF_REG_4, BPF_REG_0, 1), | ||
6953 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_2, 0), | ||
6954 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
6955 | BPF_EXIT_INSN(), | ||
6956 | }, | ||
6957 | .result = REJECT, | ||
6958 | .errstr = "invalid access to packet", | ||
6959 | .prog_type = BPF_PROG_TYPE_XDP, | ||
6960 | }, | ||
6961 | { | ||
6962 | "meta access, test7", | ||
6963 | .insns = { | ||
6964 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
6965 | offsetof(struct xdp_md, data_meta)), | ||
6966 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
6967 | offsetof(struct xdp_md, data)), | ||
6968 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_3), | ||
6969 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), | ||
6970 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_2), | ||
6971 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 8), | ||
6972 | BPF_JMP_REG(BPF_JGT, BPF_REG_4, BPF_REG_3, 1), | ||
6973 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_2, 0), | ||
6974 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
6975 | BPF_EXIT_INSN(), | ||
6976 | }, | ||
6977 | .result = ACCEPT, | ||
6978 | .prog_type = BPF_PROG_TYPE_XDP, | ||
6979 | }, | ||
6980 | { | ||
6981 | "meta access, test8", | ||
6982 | .insns = { | ||
6983 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
6984 | offsetof(struct xdp_md, data_meta)), | ||
6985 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
6986 | offsetof(struct xdp_md, data)), | ||
6987 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_2), | ||
6988 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 0xFFFF), | ||
6989 | BPF_JMP_REG(BPF_JGT, BPF_REG_4, BPF_REG_3, 1), | ||
6990 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_2, 0), | ||
6991 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
6992 | BPF_EXIT_INSN(), | ||
6993 | }, | ||
6994 | .result = ACCEPT, | ||
6995 | .prog_type = BPF_PROG_TYPE_XDP, | ||
6996 | }, | ||
6997 | { | ||
6998 | "meta access, test9", | ||
6999 | .insns = { | ||
7000 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
7001 | offsetof(struct xdp_md, data_meta)), | ||
7002 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
7003 | offsetof(struct xdp_md, data)), | ||
7004 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_2), | ||
7005 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 0xFFFF), | ||
7006 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 1), | ||
7007 | BPF_JMP_REG(BPF_JGT, BPF_REG_4, BPF_REG_3, 1), | ||
7008 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_2, 0), | ||
7009 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
7010 | BPF_EXIT_INSN(), | ||
7011 | }, | ||
7012 | .result = REJECT, | ||
7013 | .errstr = "invalid access to packet", | ||
7014 | .prog_type = BPF_PROG_TYPE_XDP, | ||
7015 | }, | ||
7016 | { | ||
7017 | "meta access, test10", | ||
7018 | .insns = { | ||
7019 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
7020 | offsetof(struct xdp_md, data_meta)), | ||
7021 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
7022 | offsetof(struct xdp_md, data)), | ||
7023 | BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_1, | ||
7024 | offsetof(struct xdp_md, data_end)), | ||
7025 | BPF_MOV64_IMM(BPF_REG_5, 42), | ||
7026 | BPF_MOV64_IMM(BPF_REG_6, 24), | ||
7027 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_5, -8), | ||
7028 | BPF_STX_XADD(BPF_DW, BPF_REG_10, BPF_REG_6, -8), | ||
7029 | BPF_LDX_MEM(BPF_DW, BPF_REG_5, BPF_REG_10, -8), | ||
7030 | BPF_JMP_IMM(BPF_JGT, BPF_REG_5, 100, 6), | ||
7031 | BPF_ALU64_REG(BPF_ADD, BPF_REG_3, BPF_REG_5), | ||
7032 | BPF_MOV64_REG(BPF_REG_5, BPF_REG_3), | ||
7033 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_2), | ||
7034 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 8), | ||
7035 | BPF_JMP_REG(BPF_JGT, BPF_REG_6, BPF_REG_5, 1), | ||
7036 | BPF_LDX_MEM(BPF_B, BPF_REG_2, BPF_REG_2, 0), | ||
7037 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
7038 | BPF_EXIT_INSN(), | ||
7039 | }, | ||
7040 | .result = REJECT, | ||
7041 | .errstr = "invalid access to packet", | ||
7042 | .prog_type = BPF_PROG_TYPE_XDP, | ||
7043 | }, | ||
7044 | { | ||
7045 | "meta access, test11", | ||
7046 | .insns = { | ||
7047 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
7048 | offsetof(struct xdp_md, data_meta)), | ||
7049 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
7050 | offsetof(struct xdp_md, data)), | ||
7051 | BPF_MOV64_IMM(BPF_REG_5, 42), | ||
7052 | BPF_MOV64_IMM(BPF_REG_6, 24), | ||
7053 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_5, -8), | ||
7054 | BPF_STX_XADD(BPF_DW, BPF_REG_10, BPF_REG_6, -8), | ||
7055 | BPF_LDX_MEM(BPF_DW, BPF_REG_5, BPF_REG_10, -8), | ||
7056 | BPF_JMP_IMM(BPF_JGT, BPF_REG_5, 100, 6), | ||
7057 | BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_5), | ||
7058 | BPF_MOV64_REG(BPF_REG_5, BPF_REG_2), | ||
7059 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_2), | ||
7060 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 8), | ||
7061 | BPF_JMP_REG(BPF_JGT, BPF_REG_6, BPF_REG_3, 1), | ||
7062 | BPF_LDX_MEM(BPF_B, BPF_REG_5, BPF_REG_5, 0), | ||
7063 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
7064 | BPF_EXIT_INSN(), | ||
7065 | }, | ||
7066 | .result = ACCEPT, | ||
7067 | .prog_type = BPF_PROG_TYPE_XDP, | ||
7068 | }, | ||
7069 | { | ||
7070 | "meta access, test12", | ||
7071 | .insns = { | ||
7072 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
7073 | offsetof(struct xdp_md, data_meta)), | ||
7074 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
7075 | offsetof(struct xdp_md, data)), | ||
7076 | BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_1, | ||
7077 | offsetof(struct xdp_md, data_end)), | ||
7078 | BPF_MOV64_REG(BPF_REG_5, BPF_REG_3), | ||
7079 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 16), | ||
7080 | BPF_JMP_REG(BPF_JGT, BPF_REG_5, BPF_REG_4, 5), | ||
7081 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_3, 0), | ||
7082 | BPF_MOV64_REG(BPF_REG_5, BPF_REG_2), | ||
7083 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 16), | ||
7084 | BPF_JMP_REG(BPF_JGT, BPF_REG_5, BPF_REG_3, 1), | ||
7085 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_2, 0), | ||
7086 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
7087 | BPF_EXIT_INSN(), | ||
7088 | }, | ||
7089 | .result = ACCEPT, | ||
7090 | .prog_type = BPF_PROG_TYPE_XDP, | ||
7091 | }, | ||
7092 | { | ||
6661 | "arithmetic ops make PTR_TO_CTX unusable", | 7093 | "arithmetic ops make PTR_TO_CTX unusable", |
6662 | .insns = { | 7094 | .insns = { |
6663 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, | 7095 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, |
@@ -7151,6 +7583,520 @@ static struct bpf_test tests[] = { | |||
7151 | .prog_type = BPF_PROG_TYPE_XDP, | 7583 | .prog_type = BPF_PROG_TYPE_XDP, |
7152 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | 7584 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |
7153 | }, | 7585 | }, |
7586 | { | ||
7587 | "XDP pkt read, pkt_meta' > pkt_data, good access", | ||
7588 | .insns = { | ||
7589 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
7590 | offsetof(struct xdp_md, data_meta)), | ||
7591 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
7592 | offsetof(struct xdp_md, data)), | ||
7593 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), | ||
7594 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8), | ||
7595 | BPF_JMP_REG(BPF_JGT, BPF_REG_1, BPF_REG_3, 1), | ||
7596 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8), | ||
7597 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
7598 | BPF_EXIT_INSN(), | ||
7599 | }, | ||
7600 | .result = ACCEPT, | ||
7601 | .prog_type = BPF_PROG_TYPE_XDP, | ||
7602 | }, | ||
7603 | { | ||
7604 | "XDP pkt read, pkt_meta' > pkt_data, bad access 1", | ||
7605 | .insns = { | ||
7606 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
7607 | offsetof(struct xdp_md, data_meta)), | ||
7608 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
7609 | offsetof(struct xdp_md, data)), | ||
7610 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), | ||
7611 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8), | ||
7612 | BPF_JMP_REG(BPF_JGT, BPF_REG_1, BPF_REG_3, 1), | ||
7613 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -4), | ||
7614 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
7615 | BPF_EXIT_INSN(), | ||
7616 | }, | ||
7617 | .errstr = "R1 offset is outside of the packet", | ||
7618 | .result = REJECT, | ||
7619 | .prog_type = BPF_PROG_TYPE_XDP, | ||
7620 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
7621 | }, | ||
7622 | { | ||
7623 | "XDP pkt read, pkt_meta' > pkt_data, bad access 2", | ||
7624 | .insns = { | ||
7625 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
7626 | offsetof(struct xdp_md, data_meta)), | ||
7627 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
7628 | offsetof(struct xdp_md, data)), | ||
7629 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), | ||
7630 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8), | ||
7631 | BPF_JMP_REG(BPF_JGT, BPF_REG_1, BPF_REG_3, 0), | ||
7632 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8), | ||
7633 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
7634 | BPF_EXIT_INSN(), | ||
7635 | }, | ||
7636 | .errstr = "R1 offset is outside of the packet", | ||
7637 | .result = REJECT, | ||
7638 | .prog_type = BPF_PROG_TYPE_XDP, | ||
7639 | }, | ||
7640 | { | ||
7641 | "XDP pkt read, pkt_data > pkt_meta', good access", | ||
7642 | .insns = { | ||
7643 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
7644 | offsetof(struct xdp_md, data_meta)), | ||
7645 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
7646 | offsetof(struct xdp_md, data)), | ||
7647 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), | ||
7648 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8), | ||
7649 | BPF_JMP_REG(BPF_JGT, BPF_REG_3, BPF_REG_1, 1), | ||
7650 | BPF_JMP_IMM(BPF_JA, 0, 0, 1), | ||
7651 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, -5), | ||
7652 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
7653 | BPF_EXIT_INSN(), | ||
7654 | }, | ||
7655 | .result = ACCEPT, | ||
7656 | .prog_type = BPF_PROG_TYPE_XDP, | ||
7657 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
7658 | }, | ||
7659 | { | ||
7660 | "XDP pkt read, pkt_data > pkt_meta', bad access 1", | ||
7661 | .insns = { | ||
7662 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
7663 | offsetof(struct xdp_md, data_meta)), | ||
7664 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
7665 | offsetof(struct xdp_md, data)), | ||
7666 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), | ||
7667 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8), | ||
7668 | BPF_JMP_REG(BPF_JGT, BPF_REG_3, BPF_REG_1, 1), | ||
7669 | BPF_JMP_IMM(BPF_JA, 0, 0, 1), | ||
7670 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8), | ||
7671 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
7672 | BPF_EXIT_INSN(), | ||
7673 | }, | ||
7674 | .errstr = "R1 offset is outside of the packet", | ||
7675 | .result = REJECT, | ||
7676 | .prog_type = BPF_PROG_TYPE_XDP, | ||
7677 | }, | ||
7678 | { | ||
7679 | "XDP pkt read, pkt_data > pkt_meta', bad access 2", | ||
7680 | .insns = { | ||
7681 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
7682 | offsetof(struct xdp_md, data_meta)), | ||
7683 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
7684 | offsetof(struct xdp_md, data)), | ||
7685 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), | ||
7686 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8), | ||
7687 | BPF_JMP_REG(BPF_JGT, BPF_REG_3, BPF_REG_1, 1), | ||
7688 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8), | ||
7689 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
7690 | BPF_EXIT_INSN(), | ||
7691 | }, | ||
7692 | .errstr = "R1 offset is outside of the packet", | ||
7693 | .result = REJECT, | ||
7694 | .prog_type = BPF_PROG_TYPE_XDP, | ||
7695 | }, | ||
7696 | { | ||
7697 | "XDP pkt read, pkt_meta' < pkt_data, good access", | ||
7698 | .insns = { | ||
7699 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
7700 | offsetof(struct xdp_md, data_meta)), | ||
7701 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
7702 | offsetof(struct xdp_md, data)), | ||
7703 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), | ||
7704 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8), | ||
7705 | BPF_JMP_REG(BPF_JLT, BPF_REG_1, BPF_REG_3, 1), | ||
7706 | BPF_JMP_IMM(BPF_JA, 0, 0, 1), | ||
7707 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, -5), | ||
7708 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
7709 | BPF_EXIT_INSN(), | ||
7710 | }, | ||
7711 | .result = ACCEPT, | ||
7712 | .prog_type = BPF_PROG_TYPE_XDP, | ||
7713 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
7714 | }, | ||
7715 | { | ||
7716 | "XDP pkt read, pkt_meta' < pkt_data, bad access 1", | ||
7717 | .insns = { | ||
7718 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
7719 | offsetof(struct xdp_md, data_meta)), | ||
7720 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
7721 | offsetof(struct xdp_md, data)), | ||
7722 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), | ||
7723 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8), | ||
7724 | BPF_JMP_REG(BPF_JLT, BPF_REG_1, BPF_REG_3, 1), | ||
7725 | BPF_JMP_IMM(BPF_JA, 0, 0, 1), | ||
7726 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8), | ||
7727 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
7728 | BPF_EXIT_INSN(), | ||
7729 | }, | ||
7730 | .errstr = "R1 offset is outside of the packet", | ||
7731 | .result = REJECT, | ||
7732 | .prog_type = BPF_PROG_TYPE_XDP, | ||
7733 | }, | ||
7734 | { | ||
7735 | "XDP pkt read, pkt_meta' < pkt_data, bad access 2", | ||
7736 | .insns = { | ||
7737 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
7738 | offsetof(struct xdp_md, data_meta)), | ||
7739 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
7740 | offsetof(struct xdp_md, data)), | ||
7741 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), | ||
7742 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8), | ||
7743 | BPF_JMP_REG(BPF_JLT, BPF_REG_1, BPF_REG_3, 1), | ||
7744 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8), | ||
7745 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
7746 | BPF_EXIT_INSN(), | ||
7747 | }, | ||
7748 | .errstr = "R1 offset is outside of the packet", | ||
7749 | .result = REJECT, | ||
7750 | .prog_type = BPF_PROG_TYPE_XDP, | ||
7751 | }, | ||
7752 | { | ||
7753 | "XDP pkt read, pkt_data < pkt_meta', good access", | ||
7754 | .insns = { | ||
7755 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
7756 | offsetof(struct xdp_md, data_meta)), | ||
7757 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
7758 | offsetof(struct xdp_md, data)), | ||
7759 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), | ||
7760 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8), | ||
7761 | BPF_JMP_REG(BPF_JLT, BPF_REG_3, BPF_REG_1, 1), | ||
7762 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8), | ||
7763 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
7764 | BPF_EXIT_INSN(), | ||
7765 | }, | ||
7766 | .result = ACCEPT, | ||
7767 | .prog_type = BPF_PROG_TYPE_XDP, | ||
7768 | }, | ||
7769 | { | ||
7770 | "XDP pkt read, pkt_data < pkt_meta', bad access 1", | ||
7771 | .insns = { | ||
7772 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
7773 | offsetof(struct xdp_md, data_meta)), | ||
7774 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
7775 | offsetof(struct xdp_md, data)), | ||
7776 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), | ||
7777 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8), | ||
7778 | BPF_JMP_REG(BPF_JLT, BPF_REG_3, BPF_REG_1, 1), | ||
7779 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -4), | ||
7780 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
7781 | BPF_EXIT_INSN(), | ||
7782 | }, | ||
7783 | .errstr = "R1 offset is outside of the packet", | ||
7784 | .result = REJECT, | ||
7785 | .prog_type = BPF_PROG_TYPE_XDP, | ||
7786 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
7787 | }, | ||
7788 | { | ||
7789 | "XDP pkt read, pkt_data < pkt_meta', bad access 2", | ||
7790 | .insns = { | ||
7791 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
7792 | offsetof(struct xdp_md, data_meta)), | ||
7793 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
7794 | offsetof(struct xdp_md, data)), | ||
7795 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), | ||
7796 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8), | ||
7797 | BPF_JMP_REG(BPF_JLT, BPF_REG_3, BPF_REG_1, 0), | ||
7798 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8), | ||
7799 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
7800 | BPF_EXIT_INSN(), | ||
7801 | }, | ||
7802 | .errstr = "R1 offset is outside of the packet", | ||
7803 | .result = REJECT, | ||
7804 | .prog_type = BPF_PROG_TYPE_XDP, | ||
7805 | }, | ||
7806 | { | ||
7807 | "XDP pkt read, pkt_meta' >= pkt_data, good access", | ||
7808 | .insns = { | ||
7809 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
7810 | offsetof(struct xdp_md, data_meta)), | ||
7811 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
7812 | offsetof(struct xdp_md, data)), | ||
7813 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), | ||
7814 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8), | ||
7815 | BPF_JMP_REG(BPF_JGE, BPF_REG_1, BPF_REG_3, 1), | ||
7816 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, -5), | ||
7817 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
7818 | BPF_EXIT_INSN(), | ||
7819 | }, | ||
7820 | .result = ACCEPT, | ||
7821 | .prog_type = BPF_PROG_TYPE_XDP, | ||
7822 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
7823 | }, | ||
7824 | { | ||
7825 | "XDP pkt read, pkt_meta' >= pkt_data, bad access 1", | ||
7826 | .insns = { | ||
7827 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
7828 | offsetof(struct xdp_md, data_meta)), | ||
7829 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
7830 | offsetof(struct xdp_md, data)), | ||
7831 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), | ||
7832 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8), | ||
7833 | BPF_JMP_REG(BPF_JGE, BPF_REG_1, BPF_REG_3, 1), | ||
7834 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8), | ||
7835 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
7836 | BPF_EXIT_INSN(), | ||
7837 | }, | ||
7838 | .errstr = "R1 offset is outside of the packet", | ||
7839 | .result = REJECT, | ||
7840 | .prog_type = BPF_PROG_TYPE_XDP, | ||
7841 | }, | ||
7842 | { | ||
7843 | "XDP pkt read, pkt_meta' >= pkt_data, bad access 2", | ||
7844 | .insns = { | ||
7845 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
7846 | offsetof(struct xdp_md, data_meta)), | ||
7847 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
7848 | offsetof(struct xdp_md, data)), | ||
7849 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), | ||
7850 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8), | ||
7851 | BPF_JMP_REG(BPF_JGE, BPF_REG_1, BPF_REG_3, 0), | ||
7852 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, -5), | ||
7853 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
7854 | BPF_EXIT_INSN(), | ||
7855 | }, | ||
7856 | .errstr = "R1 offset is outside of the packet", | ||
7857 | .result = REJECT, | ||
7858 | .prog_type = BPF_PROG_TYPE_XDP, | ||
7859 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
7860 | }, | ||
7861 | { | ||
7862 | "XDP pkt read, pkt_data >= pkt_meta', good access", | ||
7863 | .insns = { | ||
7864 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
7865 | offsetof(struct xdp_md, data_meta)), | ||
7866 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
7867 | offsetof(struct xdp_md, data)), | ||
7868 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), | ||
7869 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8), | ||
7870 | BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_1, 1), | ||
7871 | BPF_JMP_IMM(BPF_JA, 0, 0, 1), | ||
7872 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8), | ||
7873 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
7874 | BPF_EXIT_INSN(), | ||
7875 | }, | ||
7876 | .result = ACCEPT, | ||
7877 | .prog_type = BPF_PROG_TYPE_XDP, | ||
7878 | }, | ||
7879 | { | ||
7880 | "XDP pkt read, pkt_data >= pkt_meta', bad access 1", | ||
7881 | .insns = { | ||
7882 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
7883 | offsetof(struct xdp_md, data_meta)), | ||
7884 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
7885 | offsetof(struct xdp_md, data)), | ||
7886 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), | ||
7887 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8), | ||
7888 | BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_1, 1), | ||
7889 | BPF_JMP_IMM(BPF_JA, 0, 0, 1), | ||
7890 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -4), | ||
7891 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
7892 | BPF_EXIT_INSN(), | ||
7893 | }, | ||
7894 | .errstr = "R1 offset is outside of the packet", | ||
7895 | .result = REJECT, | ||
7896 | .prog_type = BPF_PROG_TYPE_XDP, | ||
7897 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
7898 | }, | ||
7899 | { | ||
7900 | "XDP pkt read, pkt_data >= pkt_meta', bad access 2", | ||
7901 | .insns = { | ||
7902 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
7903 | offsetof(struct xdp_md, data_meta)), | ||
7904 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
7905 | offsetof(struct xdp_md, data)), | ||
7906 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), | ||
7907 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8), | ||
7908 | BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_1, 1), | ||
7909 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8), | ||
7910 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
7911 | BPF_EXIT_INSN(), | ||
7912 | }, | ||
7913 | .errstr = "R1 offset is outside of the packet", | ||
7914 | .result = REJECT, | ||
7915 | .prog_type = BPF_PROG_TYPE_XDP, | ||
7916 | }, | ||
7917 | { | ||
7918 | "XDP pkt read, pkt_meta' <= pkt_data, good access", | ||
7919 | .insns = { | ||
7920 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
7921 | offsetof(struct xdp_md, data_meta)), | ||
7922 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
7923 | offsetof(struct xdp_md, data)), | ||
7924 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), | ||
7925 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8), | ||
7926 | BPF_JMP_REG(BPF_JLE, BPF_REG_1, BPF_REG_3, 1), | ||
7927 | BPF_JMP_IMM(BPF_JA, 0, 0, 1), | ||
7928 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8), | ||
7929 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
7930 | BPF_EXIT_INSN(), | ||
7931 | }, | ||
7932 | .result = ACCEPT, | ||
7933 | .prog_type = BPF_PROG_TYPE_XDP, | ||
7934 | }, | ||
7935 | { | ||
7936 | "XDP pkt read, pkt_meta' <= pkt_data, bad access 1", | ||
7937 | .insns = { | ||
7938 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
7939 | offsetof(struct xdp_md, data_meta)), | ||
7940 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
7941 | offsetof(struct xdp_md, data)), | ||
7942 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), | ||
7943 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8), | ||
7944 | BPF_JMP_REG(BPF_JLE, BPF_REG_1, BPF_REG_3, 1), | ||
7945 | BPF_JMP_IMM(BPF_JA, 0, 0, 1), | ||
7946 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -4), | ||
7947 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
7948 | BPF_EXIT_INSN(), | ||
7949 | }, | ||
7950 | .errstr = "R1 offset is outside of the packet", | ||
7951 | .result = REJECT, | ||
7952 | .prog_type = BPF_PROG_TYPE_XDP, | ||
7953 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
7954 | }, | ||
7955 | { | ||
7956 | "XDP pkt read, pkt_meta' <= pkt_data, bad access 2", | ||
7957 | .insns = { | ||
7958 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
7959 | offsetof(struct xdp_md, data_meta)), | ||
7960 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
7961 | offsetof(struct xdp_md, data)), | ||
7962 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), | ||
7963 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8), | ||
7964 | BPF_JMP_REG(BPF_JLE, BPF_REG_1, BPF_REG_3, 1), | ||
7965 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8), | ||
7966 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
7967 | BPF_EXIT_INSN(), | ||
7968 | }, | ||
7969 | .errstr = "R1 offset is outside of the packet", | ||
7970 | .result = REJECT, | ||
7971 | .prog_type = BPF_PROG_TYPE_XDP, | ||
7972 | }, | ||
7973 | { | ||
7974 | "XDP pkt read, pkt_data <= pkt_meta', good access", | ||
7975 | .insns = { | ||
7976 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
7977 | offsetof(struct xdp_md, data_meta)), | ||
7978 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
7979 | offsetof(struct xdp_md, data)), | ||
7980 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), | ||
7981 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8), | ||
7982 | BPF_JMP_REG(BPF_JLE, BPF_REG_3, BPF_REG_1, 1), | ||
7983 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, -5), | ||
7984 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
7985 | BPF_EXIT_INSN(), | ||
7986 | }, | ||
7987 | .result = ACCEPT, | ||
7988 | .prog_type = BPF_PROG_TYPE_XDP, | ||
7989 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
7990 | }, | ||
7991 | { | ||
7992 | "XDP pkt read, pkt_data <= pkt_meta', bad access 1", | ||
7993 | .insns = { | ||
7994 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
7995 | offsetof(struct xdp_md, data_meta)), | ||
7996 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
7997 | offsetof(struct xdp_md, data)), | ||
7998 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), | ||
7999 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8), | ||
8000 | BPF_JMP_REG(BPF_JLE, BPF_REG_3, BPF_REG_1, 1), | ||
8001 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8), | ||
8002 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
8003 | BPF_EXIT_INSN(), | ||
8004 | }, | ||
8005 | .errstr = "R1 offset is outside of the packet", | ||
8006 | .result = REJECT, | ||
8007 | .prog_type = BPF_PROG_TYPE_XDP, | ||
8008 | }, | ||
8009 | { | ||
8010 | "XDP pkt read, pkt_data <= pkt_meta', bad access 2", | ||
8011 | .insns = { | ||
8012 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
8013 | offsetof(struct xdp_md, data_meta)), | ||
8014 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
8015 | offsetof(struct xdp_md, data)), | ||
8016 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), | ||
8017 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8), | ||
8018 | BPF_JMP_REG(BPF_JLE, BPF_REG_3, BPF_REG_1, 0), | ||
8019 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, -5), | ||
8020 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
8021 | BPF_EXIT_INSN(), | ||
8022 | }, | ||
8023 | .errstr = "R1 offset is outside of the packet", | ||
8024 | .result = REJECT, | ||
8025 | .prog_type = BPF_PROG_TYPE_XDP, | ||
8026 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | ||
8027 | }, | ||
8028 | { | ||
8029 | "bpf_exit with invalid return code. test1", | ||
8030 | .insns = { | ||
8031 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 0), | ||
8032 | BPF_EXIT_INSN(), | ||
8033 | }, | ||
8034 | .errstr = "R0 has value (0x0; 0xffffffff)", | ||
8035 | .result = REJECT, | ||
8036 | .prog_type = BPF_PROG_TYPE_CGROUP_SOCK, | ||
8037 | }, | ||
8038 | { | ||
8039 | "bpf_exit with invalid return code. test2", | ||
8040 | .insns = { | ||
8041 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 0), | ||
8042 | BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1), | ||
8043 | BPF_EXIT_INSN(), | ||
8044 | }, | ||
8045 | .result = ACCEPT, | ||
8046 | .prog_type = BPF_PROG_TYPE_CGROUP_SOCK, | ||
8047 | }, | ||
8048 | { | ||
8049 | "bpf_exit with invalid return code. test3", | ||
8050 | .insns = { | ||
8051 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 0), | ||
8052 | BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 3), | ||
8053 | BPF_EXIT_INSN(), | ||
8054 | }, | ||
8055 | .errstr = "R0 has value (0x0; 0x3)", | ||
8056 | .result = REJECT, | ||
8057 | .prog_type = BPF_PROG_TYPE_CGROUP_SOCK, | ||
8058 | }, | ||
8059 | { | ||
8060 | "bpf_exit with invalid return code. test4", | ||
8061 | .insns = { | ||
8062 | BPF_MOV64_IMM(BPF_REG_0, 1), | ||
8063 | BPF_EXIT_INSN(), | ||
8064 | }, | ||
8065 | .result = ACCEPT, | ||
8066 | .prog_type = BPF_PROG_TYPE_CGROUP_SOCK, | ||
8067 | }, | ||
8068 | { | ||
8069 | "bpf_exit with invalid return code. test5", | ||
8070 | .insns = { | ||
8071 | BPF_MOV64_IMM(BPF_REG_0, 2), | ||
8072 | BPF_EXIT_INSN(), | ||
8073 | }, | ||
8074 | .errstr = "R0 has value (0x2; 0x0)", | ||
8075 | .result = REJECT, | ||
8076 | .prog_type = BPF_PROG_TYPE_CGROUP_SOCK, | ||
8077 | }, | ||
8078 | { | ||
8079 | "bpf_exit with invalid return code. test6", | ||
8080 | .insns = { | ||
8081 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_1), | ||
8082 | BPF_EXIT_INSN(), | ||
8083 | }, | ||
8084 | .errstr = "R0 is not a known value (ctx)", | ||
8085 | .result = REJECT, | ||
8086 | .prog_type = BPF_PROG_TYPE_CGROUP_SOCK, | ||
8087 | }, | ||
8088 | { | ||
8089 | "bpf_exit with invalid return code. test7", | ||
8090 | .insns = { | ||
8091 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 0), | ||
8092 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 4), | ||
8093 | BPF_ALU64_REG(BPF_MUL, BPF_REG_0, BPF_REG_2), | ||
8094 | BPF_EXIT_INSN(), | ||
8095 | }, | ||
8096 | .errstr = "R0 has unknown scalar value", | ||
8097 | .result = REJECT, | ||
8098 | .prog_type = BPF_PROG_TYPE_CGROUP_SOCK, | ||
8099 | }, | ||
7154 | }; | 8100 | }; |
7155 | 8101 | ||
7156 | static int probe_filter_length(const struct bpf_insn *fp) | 8102 | static int probe_filter_length(const struct bpf_insn *fp) |
@@ -7198,7 +8144,7 @@ static int create_map_in_map(void) | |||
7198 | return inner_map_fd; | 8144 | return inner_map_fd; |
7199 | } | 8145 | } |
7200 | 8146 | ||
7201 | outer_map_fd = bpf_create_map_in_map(BPF_MAP_TYPE_ARRAY_OF_MAPS, | 8147 | outer_map_fd = bpf_create_map_in_map(BPF_MAP_TYPE_ARRAY_OF_MAPS, NULL, |
7202 | sizeof(int), inner_map_fd, 1, 0); | 8148 | sizeof(int), inner_map_fd, 1, 0); |
7203 | if (outer_map_fd < 0) | 8149 | if (outer_map_fd < 0) |
7204 | printf("Failed to create array of maps '%s'!\n", | 8150 | printf("Failed to create array of maps '%s'!\n", |
diff --git a/tools/testing/selftests/bpf/test_verifier_log.c b/tools/testing/selftests/bpf/test_verifier_log.c new file mode 100644 index 000000000000..e9626cf5607a --- /dev/null +++ b/tools/testing/selftests/bpf/test_verifier_log.c | |||
@@ -0,0 +1,178 @@ | |||
1 | #include <errno.h> | ||
2 | #include <stdlib.h> | ||
3 | #include <stdio.h> | ||
4 | #include <string.h> | ||
5 | #include <unistd.h> | ||
6 | #include <sys/time.h> | ||
7 | #include <sys/resource.h> | ||
8 | |||
9 | #include <linux/bpf.h> | ||
10 | #include <linux/filter.h> | ||
11 | #include <linux/unistd.h> | ||
12 | |||
13 | #include <bpf/bpf.h> | ||
14 | |||
15 | #define LOG_SIZE (1 << 20) | ||
16 | |||
17 | #define err(str...) printf("ERROR: " str) | ||
18 | |||
19 | static const struct bpf_insn code_sample[] = { | ||
20 | /* We need a few instructions to pass the min log length */ | ||
21 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
22 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
23 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
24 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
25 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
26 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
27 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
28 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
29 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
30 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
31 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
32 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
33 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
34 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
35 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
36 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
37 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
38 | BPF_FUNC_map_lookup_elem), | ||
39 | BPF_EXIT_INSN(), | ||
40 | }; | ||
41 | |||
42 | static inline __u64 ptr_to_u64(const void *ptr) | ||
43 | { | ||
44 | return (__u64) (unsigned long) ptr; | ||
45 | } | ||
46 | |||
47 | static int load(char *log, size_t log_len, int log_level) | ||
48 | { | ||
49 | union bpf_attr attr; | ||
50 | |||
51 | bzero(&attr, sizeof(attr)); | ||
52 | attr.prog_type = BPF_PROG_TYPE_SOCKET_FILTER; | ||
53 | attr.insn_cnt = (__u32)(sizeof(code_sample) / sizeof(struct bpf_insn)); | ||
54 | attr.insns = ptr_to_u64(code_sample); | ||
55 | attr.license = ptr_to_u64("GPL"); | ||
56 | attr.log_buf = ptr_to_u64(log); | ||
57 | attr.log_size = log_len; | ||
58 | attr.log_level = log_level; | ||
59 | |||
60 | return syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr)); | ||
61 | } | ||
62 | |||
63 | static void check_ret(int ret, int exp_errno) | ||
64 | { | ||
65 | if (ret > 0) { | ||
66 | close(ret); | ||
67 | err("broken sample loaded successfully!?\n"); | ||
68 | exit(1); | ||
69 | } | ||
70 | |||
71 | if (!ret || errno != exp_errno) { | ||
72 | err("Program load returned: ret:%d/errno:%d, expected ret:%d/errno:%d\n", | ||
73 | ret, errno, -1, exp_errno); | ||
74 | exit(1); | ||
75 | } | ||
76 | } | ||
77 | |||
78 | static void check_ones(const char *buf, size_t len, const char *msg) | ||
79 | { | ||
80 | while (len--) | ||
81 | if (buf[len] != 1) { | ||
82 | err("%s", msg); | ||
83 | exit(1); | ||
84 | } | ||
85 | } | ||
86 | |||
87 | static void test_log_good(char *log, size_t buf_len, size_t log_len, | ||
88 | size_t exp_len, int exp_errno, const char *full_log) | ||
89 | { | ||
90 | size_t len; | ||
91 | int ret; | ||
92 | |||
93 | memset(log, 1, buf_len); | ||
94 | |||
95 | ret = load(log, log_len, 1); | ||
96 | check_ret(ret, exp_errno); | ||
97 | |||
98 | len = strnlen(log, buf_len); | ||
99 | if (len == buf_len) { | ||
100 | err("verifier did not NULL terminate the log\n"); | ||
101 | exit(1); | ||
102 | } | ||
103 | if (exp_len && len != exp_len) { | ||
104 | err("incorrect log length expected:%zd have:%zd\n", | ||
105 | exp_len, len); | ||
106 | exit(1); | ||
107 | } | ||
108 | |||
109 | if (strchr(log, 1)) { | ||
110 | err("verifier leaked a byte through\n"); | ||
111 | exit(1); | ||
112 | } | ||
113 | |||
114 | check_ones(log + len + 1, buf_len - len - 1, | ||
115 | "verifier wrote bytes past NULL termination\n"); | ||
116 | |||
117 | if (memcmp(full_log, log, LOG_SIZE)) { | ||
118 | err("log did not match expected output\n"); | ||
119 | exit(1); | ||
120 | } | ||
121 | } | ||
122 | |||
123 | static void test_log_bad(char *log, size_t log_len, int log_level) | ||
124 | { | ||
125 | int ret; | ||
126 | |||
127 | ret = load(log, log_len, log_level); | ||
128 | check_ret(ret, EINVAL); | ||
129 | if (log) | ||
130 | check_ones(log, LOG_SIZE, | ||
131 | "verifier touched log with bad parameters\n"); | ||
132 | } | ||
133 | |||
134 | int main(int argc, char **argv) | ||
135 | { | ||
136 | struct rlimit limit = { RLIM_INFINITY, RLIM_INFINITY }; | ||
137 | char full_log[LOG_SIZE]; | ||
138 | char log[LOG_SIZE]; | ||
139 | size_t want_len; | ||
140 | int i; | ||
141 | |||
142 | /* allow unlimited locked memory to have more consistent error code */ | ||
143 | if (setrlimit(RLIMIT_MEMLOCK, &limit) < 0) | ||
144 | perror("Unable to lift memlock rlimit"); | ||
145 | |||
146 | memset(log, 1, LOG_SIZE); | ||
147 | |||
148 | /* Test incorrect attr */ | ||
149 | printf("Test log_level 0...\n"); | ||
150 | test_log_bad(log, LOG_SIZE, 0); | ||
151 | |||
152 | printf("Test log_size < 128...\n"); | ||
153 | test_log_bad(log, 15, 1); | ||
154 | |||
155 | printf("Test log_buff = NULL...\n"); | ||
156 | test_log_bad(NULL, LOG_SIZE, 1); | ||
157 | |||
158 | /* Test with log big enough */ | ||
159 | printf("Test oversized buffer...\n"); | ||
160 | test_log_good(full_log, LOG_SIZE, LOG_SIZE, 0, EACCES, full_log); | ||
161 | |||
162 | want_len = strlen(full_log); | ||
163 | |||
164 | printf("Test exact buffer...\n"); | ||
165 | test_log_good(log, LOG_SIZE, want_len + 2, want_len, EACCES, full_log); | ||
166 | |||
167 | printf("Test undersized buffers...\n"); | ||
168 | for (i = 0; i < 64; i++) { | ||
169 | full_log[want_len - i + 1] = 1; | ||
170 | full_log[want_len - i] = 0; | ||
171 | |||
172 | test_log_good(log, LOG_SIZE, want_len + 1 - i, want_len - i, | ||
173 | ENOSPC, full_log); | ||
174 | } | ||
175 | |||
176 | printf("test_verifier_log: OK\n"); | ||
177 | return 0; | ||
178 | } | ||
diff --git a/tools/testing/selftests/bpf/test_xdp_meta.c b/tools/testing/selftests/bpf/test_xdp_meta.c new file mode 100644 index 000000000000..8d0182650653 --- /dev/null +++ b/tools/testing/selftests/bpf/test_xdp_meta.c | |||
@@ -0,0 +1,53 @@ | |||
1 | #include <linux/bpf.h> | ||
2 | #include <linux/if_ether.h> | ||
3 | #include <linux/pkt_cls.h> | ||
4 | |||
5 | #include "bpf_helpers.h" | ||
6 | |||
7 | #define __round_mask(x, y) ((__typeof__(x))((y) - 1)) | ||
8 | #define round_up(x, y) ((((x) - 1) | __round_mask(x, y)) + 1) | ||
9 | #define ctx_ptr(ctx, mem) (void *)(unsigned long)ctx->mem | ||
10 | |||
11 | SEC("t") | ||
12 | int ing_cls(struct __sk_buff *ctx) | ||
13 | { | ||
14 | __u8 *data, *data_meta, *data_end; | ||
15 | __u32 diff = 0; | ||
16 | |||
17 | data_meta = ctx_ptr(ctx, data_meta); | ||
18 | data_end = ctx_ptr(ctx, data_end); | ||
19 | data = ctx_ptr(ctx, data); | ||
20 | |||
21 | if (data + ETH_ALEN > data_end || | ||
22 | data_meta + round_up(ETH_ALEN, 4) > data) | ||
23 | return TC_ACT_SHOT; | ||
24 | |||
25 | diff |= ((__u32 *)data_meta)[0] ^ ((__u32 *)data)[0]; | ||
26 | diff |= ((__u16 *)data_meta)[2] ^ ((__u16 *)data)[2]; | ||
27 | |||
28 | return diff ? TC_ACT_SHOT : TC_ACT_OK; | ||
29 | } | ||
30 | |||
31 | SEC("x") | ||
32 | int ing_xdp(struct xdp_md *ctx) | ||
33 | { | ||
34 | __u8 *data, *data_meta, *data_end; | ||
35 | int ret; | ||
36 | |||
37 | ret = bpf_xdp_adjust_meta(ctx, -round_up(ETH_ALEN, 4)); | ||
38 | if (ret < 0) | ||
39 | return XDP_DROP; | ||
40 | |||
41 | data_meta = ctx_ptr(ctx, data_meta); | ||
42 | data_end = ctx_ptr(ctx, data_end); | ||
43 | data = ctx_ptr(ctx, data); | ||
44 | |||
45 | if (data + ETH_ALEN > data_end || | ||
46 | data_meta + round_up(ETH_ALEN, 4) > data) | ||
47 | return XDP_DROP; | ||
48 | |||
49 | __builtin_memcpy(data_meta, data, ETH_ALEN); | ||
50 | return XDP_PASS; | ||
51 | } | ||
52 | |||
53 | char _license[] SEC("license") = "GPL"; | ||
diff --git a/tools/testing/selftests/bpf/test_xdp_meta.sh b/tools/testing/selftests/bpf/test_xdp_meta.sh new file mode 100755 index 000000000000..307aa856cee3 --- /dev/null +++ b/tools/testing/selftests/bpf/test_xdp_meta.sh | |||
@@ -0,0 +1,51 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | cleanup() | ||
4 | { | ||
5 | if [ "$?" = "0" ]; then | ||
6 | echo "selftests: test_xdp_meta [PASS]"; | ||
7 | else | ||
8 | echo "selftests: test_xdp_meta [FAILED]"; | ||
9 | fi | ||
10 | |||
11 | set +e | ||
12 | ip netns del ns1 2> /dev/null | ||
13 | ip netns del ns2 2> /dev/null | ||
14 | } | ||
15 | |||
16 | ip link set dev lo xdp off 2>/dev/null > /dev/null | ||
17 | if [ $? -ne 0 ];then | ||
18 | echo "selftests: [SKIP] Could not run test without the ip xdp support" | ||
19 | exit 0 | ||
20 | fi | ||
21 | set -e | ||
22 | |||
23 | ip netns add ns1 | ||
24 | ip netns add ns2 | ||
25 | |||
26 | trap cleanup 0 2 3 6 9 | ||
27 | |||
28 | ip link add veth1 type veth peer name veth2 | ||
29 | |||
30 | ip link set veth1 netns ns1 | ||
31 | ip link set veth2 netns ns2 | ||
32 | |||
33 | ip netns exec ns1 ip addr add 10.1.1.11/24 dev veth1 | ||
34 | ip netns exec ns2 ip addr add 10.1.1.22/24 dev veth2 | ||
35 | |||
36 | ip netns exec ns1 tc qdisc add dev veth1 clsact | ||
37 | ip netns exec ns2 tc qdisc add dev veth2 clsact | ||
38 | |||
39 | ip netns exec ns1 tc filter add dev veth1 ingress bpf da obj test_xdp_meta.o sec t | ||
40 | ip netns exec ns2 tc filter add dev veth2 ingress bpf da obj test_xdp_meta.o sec t | ||
41 | |||
42 | ip netns exec ns1 ip link set dev veth1 xdp obj test_xdp_meta.o sec x | ||
43 | ip netns exec ns2 ip link set dev veth2 xdp obj test_xdp_meta.o sec x | ||
44 | |||
45 | ip netns exec ns1 ip link set dev veth1 up | ||
46 | ip netns exec ns2 ip link set dev veth2 up | ||
47 | |||
48 | ip netns exec ns1 ping -c 1 10.1.1.22 | ||
49 | ip netns exec ns2 ping -c 1 10.1.1.11 | ||
50 | |||
51 | exit 0 | ||
diff --git a/tools/testing/selftests/breakpoints/breakpoint_test_arm64.c b/tools/testing/selftests/breakpoints/breakpoint_test_arm64.c index 960d02100c26..2d95e5adde72 100644 --- a/tools/testing/selftests/breakpoints/breakpoint_test_arm64.c +++ b/tools/testing/selftests/breakpoints/breakpoint_test_arm64.c | |||
@@ -19,6 +19,7 @@ | |||
19 | 19 | ||
20 | #define _GNU_SOURCE | 20 | #define _GNU_SOURCE |
21 | 21 | ||
22 | #include <asm/ptrace.h> | ||
22 | #include <sys/types.h> | 23 | #include <sys/types.h> |
23 | #include <sys/wait.h> | 24 | #include <sys/wait.h> |
24 | #include <sys/ptrace.h> | 25 | #include <sys/ptrace.h> |
diff --git a/tools/testing/selftests/cpu-hotplug/config b/tools/testing/selftests/cpu-hotplug/config index e6ab090cfbf3..d4aca2ad5069 100644 --- a/tools/testing/selftests/cpu-hotplug/config +++ b/tools/testing/selftests/cpu-hotplug/config | |||
@@ -1,2 +1 @@ | |||
1 | CONFIG_NOTIFIER_ERROR_INJECTION=y | CONFIG_NOTIFIER_ERROR_INJECTION=y | |
2 | CONFIG_CPU_NOTIFIER_ERROR_INJECT=m | ||
diff --git a/tools/testing/selftests/exec/execveat.c b/tools/testing/selftests/exec/execveat.c index 8d5d1d2ee7c1..67cd4597db2b 100644 --- a/tools/testing/selftests/exec/execveat.c +++ b/tools/testing/selftests/exec/execveat.c | |||
@@ -147,7 +147,7 @@ static void exe_cp(const char *src, const char *dest) | |||
147 | } | 147 | } |
148 | 148 | ||
149 | #define XX_DIR_LEN 200 | 149 | #define XX_DIR_LEN 200 |
150 | static int check_execveat_pathmax(int dot_dfd, const char *src, int is_script) | 150 | static int check_execveat_pathmax(int root_dfd, const char *src, int is_script) |
151 | { | 151 | { |
152 | int fail = 0; | 152 | int fail = 0; |
153 | int ii, count, len; | 153 | int ii, count, len; |
@@ -156,20 +156,30 @@ static int check_execveat_pathmax(int dot_dfd, const char *src, int is_script) | |||
156 | 156 | ||
157 | if (*longpath == '\0') { | 157 | if (*longpath == '\0') { |
158 | /* Create a filename close to PATH_MAX in length */ | 158 | /* Create a filename close to PATH_MAX in length */ |
159 | char *cwd = getcwd(NULL, 0); | ||
160 | |||
161 | if (!cwd) { | ||
162 | printf("Failed to getcwd(), errno=%d (%s)\n", | ||
163 | errno, strerror(errno)); | ||
164 | return 2; | ||
165 | } | ||
166 | strcpy(longpath, cwd); | ||
167 | strcat(longpath, "/"); | ||
159 | memset(longname, 'x', XX_DIR_LEN - 1); | 168 | memset(longname, 'x', XX_DIR_LEN - 1); |
160 | longname[XX_DIR_LEN - 1] = '/'; | 169 | longname[XX_DIR_LEN - 1] = '/'; |
161 | longname[XX_DIR_LEN] = '\0'; | 170 | longname[XX_DIR_LEN] = '\0'; |
162 | count = (PATH_MAX - 3) / XX_DIR_LEN; | 171 | count = (PATH_MAX - 3 - strlen(cwd)) / XX_DIR_LEN; |
163 | for (ii = 0; ii < count; ii++) { | 172 | for (ii = 0; ii < count; ii++) { |
164 | strcat(longpath, longname); | 173 | strcat(longpath, longname); |
165 | mkdir(longpath, 0755); | 174 | mkdir(longpath, 0755); |
166 | } | 175 | } |
167 | len = (PATH_MAX - 3) - (count * XX_DIR_LEN); | 176 | len = (PATH_MAX - 3 - strlen(cwd)) - (count * XX_DIR_LEN); |
168 | if (len <= 0) | 177 | if (len <= 0) |
169 | len = 1; | 178 | len = 1; |
170 | memset(longname, 'y', len); | 179 | memset(longname, 'y', len); |
171 | longname[len] = '\0'; | 180 | longname[len] = '\0'; |
172 | strcat(longpath, longname); | 181 | strcat(longpath, longname); |
182 | free(cwd); | ||
173 | } | 183 | } |
174 | exe_cp(src, longpath); | 184 | exe_cp(src, longpath); |
175 | 185 | ||
@@ -190,7 +200,7 @@ static int check_execveat_pathmax(int dot_dfd, const char *src, int is_script) | |||
190 | } | 200 | } |
191 | 201 | ||
192 | /* | 202 | /* |
193 | * Execute as a long pathname relative to ".". If this is a script, | 203 | * Execute as a long pathname relative to "/". If this is a script, |
194 | * the interpreter will launch but fail to open the script because its | 204 | * the interpreter will launch but fail to open the script because its |
195 | * name ("/dev/fd/5/xxx....") is bigger than PATH_MAX. | 205 | * name ("/dev/fd/5/xxx....") is bigger than PATH_MAX. |
196 | * | 206 | * |
@@ -200,10 +210,10 @@ static int check_execveat_pathmax(int dot_dfd, const char *src, int is_script) | |||
200 | * the exit status shall be 126."), so allow either. | 210 | * the exit status shall be 126."), so allow either. |
201 | */ | 211 | */ |
202 | if (is_script) | 212 | if (is_script) |
203 | fail += check_execveat_invoked_rc(dot_dfd, longpath, 0, | 213 | fail += check_execveat_invoked_rc(root_dfd, longpath + 1, 0, |
204 | 127, 126); | 214 | 127, 126); |
205 | else | 215 | else |
206 | fail += check_execveat(dot_dfd, longpath, 0); | 216 | fail += check_execveat(root_dfd, longpath + 1, 0); |
207 | 217 | ||
208 | return fail; | 218 | return fail; |
209 | } | 219 | } |
@@ -218,6 +228,7 @@ static int run_tests(void) | |||
218 | int subdir_dfd_ephemeral = open_or_die("subdir.ephemeral", | 228 | int subdir_dfd_ephemeral = open_or_die("subdir.ephemeral", |
219 | O_DIRECTORY|O_RDONLY); | 229 | O_DIRECTORY|O_RDONLY); |
220 | int dot_dfd = open_or_die(".", O_DIRECTORY|O_RDONLY); | 230 | int dot_dfd = open_or_die(".", O_DIRECTORY|O_RDONLY); |
231 | int root_dfd = open_or_die("/", O_DIRECTORY|O_RDONLY); | ||
221 | int dot_dfd_path = open_or_die(".", O_DIRECTORY|O_RDONLY|O_PATH); | 232 | int dot_dfd_path = open_or_die(".", O_DIRECTORY|O_RDONLY|O_PATH); |
222 | int dot_dfd_cloexec = open_or_die(".", O_DIRECTORY|O_RDONLY|O_CLOEXEC); | 233 | int dot_dfd_cloexec = open_or_die(".", O_DIRECTORY|O_RDONLY|O_CLOEXEC); |
223 | int fd = open_or_die("execveat", O_RDONLY); | 234 | int fd = open_or_die("execveat", O_RDONLY); |
@@ -353,8 +364,8 @@ static int run_tests(void) | |||
353 | /* Attempt to execute relative to non-directory => ENOTDIR */ | 364 | /* Attempt to execute relative to non-directory => ENOTDIR */ |
354 | fail += check_execveat_fail(fd, "execveat", 0, ENOTDIR); | 365 | fail += check_execveat_fail(fd, "execveat", 0, ENOTDIR); |
355 | 366 | ||
356 | fail += check_execveat_pathmax(dot_dfd, "execveat", 0); | 367 | fail += check_execveat_pathmax(root_dfd, "execveat", 0); |
357 | fail += check_execveat_pathmax(dot_dfd, "script", 1); | 368 | fail += check_execveat_pathmax(root_dfd, "script", 1); |
358 | return fail; | 369 | return fail; |
359 | } | 370 | } |
360 | 371 | ||
diff --git a/tools/testing/selftests/firmware/fw_fallback.sh b/tools/testing/selftests/firmware/fw_fallback.sh index a52a3bab532b..34a42c68ebfb 100755 --- a/tools/testing/selftests/firmware/fw_fallback.sh +++ b/tools/testing/selftests/firmware/fw_fallback.sh | |||
@@ -86,6 +86,11 @@ load_fw_cancel() | |||
86 | 86 | ||
87 | load_fw_custom() | 87 | load_fw_custom() |
88 | { | 88 | { |
89 | if [ ! -e "$DIR"/trigger_custom_fallback ]; then | ||
90 | echo "$0: custom fallback trigger not present, ignoring test" >&2 | ||
91 | return 1 | ||
92 | fi | ||
93 | |||
89 | local name="$1" | 94 | local name="$1" |
90 | local file="$2" | 95 | local file="$2" |
91 | 96 | ||
@@ -108,11 +113,17 @@ load_fw_custom() | |||
108 | 113 | ||
109 | # Wait for request to finish. | 114 | # Wait for request to finish. |
110 | wait | 115 | wait |
116 | return 0 | ||
111 | } | 117 | } |
112 | 118 | ||
113 | 119 | ||
114 | load_fw_custom_cancel() | 120 | load_fw_custom_cancel() |
115 | { | 121 | { |
122 | if [ ! -e "$DIR"/trigger_custom_fallback ]; then | ||
123 | echo "$0: canceling custom fallback trigger not present, ignoring test" >&2 | ||
124 | return 1 | ||
125 | fi | ||
126 | |||
116 | local name="$1" | 127 | local name="$1" |
117 | local file="$2" | 128 | local file="$2" |
118 | 129 | ||
@@ -133,6 +144,7 @@ load_fw_custom_cancel() | |||
133 | 144 | ||
134 | # Wait for request to finish. | 145 | # Wait for request to finish. |
135 | wait | 146 | wait |
147 | return 0 | ||
136 | } | 148 | } |
137 | 149 | ||
138 | load_fw_fallback_with_child() | 150 | load_fw_fallback_with_child() |
@@ -227,20 +239,22 @@ else | |||
227 | echo "$0: cancelling fallback mechanism works" | 239 | echo "$0: cancelling fallback mechanism works" |
228 | fi | 240 | fi |
229 | 241 | ||
230 | load_fw_custom "$NAME" "$FW" | 242 | if load_fw_custom "$NAME" "$FW" ; then |
231 | if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then | 243 | if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then |
232 | echo "$0: firmware was not loaded" >&2 | 244 | echo "$0: firmware was not loaded" >&2 |
233 | exit 1 | 245 | exit 1 |
234 | else | 246 | else |
235 | echo "$0: custom fallback loading mechanism works" | 247 | echo "$0: custom fallback loading mechanism works" |
248 | fi | ||
236 | fi | 249 | fi |
237 | 250 | ||
238 | load_fw_custom_cancel "nope-$NAME" "$FW" | 251 | if load_fw_custom_cancel "nope-$NAME" "$FW" ; then |
239 | if diff -q "$FW" /dev/test_firmware >/dev/null ; then | 252 | if diff -q "$FW" /dev/test_firmware >/dev/null ; then |
240 | echo "$0: firmware was expected to be cancelled" >&2 | 253 | echo "$0: firmware was expected to be cancelled" >&2 |
241 | exit 1 | 254 | exit 1 |
242 | else | 255 | else |
243 | echo "$0: cancelling custom fallback mechanism works" | 256 | echo "$0: cancelling custom fallback mechanism works" |
257 | fi | ||
244 | fi | 258 | fi |
245 | 259 | ||
246 | set +e | 260 | set +e |
diff --git a/tools/testing/selftests/firmware/fw_filesystem.sh b/tools/testing/selftests/firmware/fw_filesystem.sh index 62f2d6f54929..b1f20fef36c7 100755 --- a/tools/testing/selftests/firmware/fw_filesystem.sh +++ b/tools/testing/selftests/firmware/fw_filesystem.sh | |||
@@ -70,9 +70,13 @@ if printf '\000' >"$DIR"/trigger_request 2> /dev/null; then | |||
70 | exit 1 | 70 | exit 1 |
71 | fi | 71 | fi |
72 | 72 | ||
73 | if printf '\000' >"$DIR"/trigger_async_request 2> /dev/null; then | 73 | if [ ! -e "$DIR"/trigger_async_request ]; then |
74 | echo "$0: empty filename should not succeed (async)" >&2 | 74 | echo "$0: empty filename: async trigger not present, ignoring test" >&2 |
75 | exit 1 | 75 | else |
76 | if printf '\000' >"$DIR"/trigger_async_request 2> /dev/null; then | ||
77 | echo "$0: empty filename should not succeed (async)" >&2 | ||
78 | exit 1 | ||
79 | fi | ||
76 | fi | 80 | fi |
77 | 81 | ||
78 | # Request a firmware that doesn't exist, it should fail. | 82 | # Request a firmware that doesn't exist, it should fail. |
@@ -105,17 +109,21 @@ else | |||
105 | fi | 109 | fi |
106 | 110 | ||
107 | # Try the asynchronous version too | 111 | # Try the asynchronous version too |
108 | if ! echo -n "$NAME" >"$DIR"/trigger_async_request ; then | 112 | if [ ! -e "$DIR"/trigger_async_request ]; then |
109 | echo "$0: could not trigger async request" >&2 | 113 | echo "$0: firmware loading: async trigger not present, ignoring test" >&2 |
110 | exit 1 | ||
111 | fi | ||
112 | |||
113 | # Verify the contents are what we expect. | ||
114 | if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then | ||
115 | echo "$0: firmware was not loaded (async)" >&2 | ||
116 | exit 1 | ||
117 | else | 114 | else |
118 | echo "$0: async filesystem loading works" | 115 | if ! echo -n "$NAME" >"$DIR"/trigger_async_request ; then |
116 | echo "$0: could not trigger async request" >&2 | ||
117 | exit 1 | ||
118 | fi | ||
119 | |||
120 | # Verify the contents are what we expect. | ||
121 | if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then | ||
122 | echo "$0: firmware was not loaded (async)" >&2 | ||
123 | exit 1 | ||
124 | else | ||
125 | echo "$0: async filesystem loading works" | ||
126 | fi | ||
119 | fi | 127 | fi |
120 | 128 | ||
121 | ### Batched requests tests | 129 | ### Batched requests tests |
diff --git a/tools/testing/selftests/ftrace/config b/tools/testing/selftests/ftrace/config index 8a1c9f949fe0..b01924c71c09 100644 --- a/tools/testing/selftests/ftrace/config +++ b/tools/testing/selftests/ftrace/config | |||
@@ -1,2 +1,6 @@ | |||
1 | CONFIG_KPROBES=y | 1 | CONFIG_KPROBES=y |
2 | CONFIG_FTRACE=y | 2 | CONFIG_FTRACE=y |
3 | CONFIG_FUNCTION_PROFILER=y | ||
4 | CONFIG_TRACER_SNAPSHOT=y | ||
5 | CONFIG_STACK_TRACER=y | ||
6 | CONFIG_HIST_TRIGGERS=y | ||
diff --git a/tools/testing/selftests/ftrace/ftracetest b/tools/testing/selftests/ftrace/ftracetest index abc706cf7702..f9a9d424c980 100755 --- a/tools/testing/selftests/ftrace/ftracetest +++ b/tools/testing/selftests/ftrace/ftracetest | |||
@@ -222,7 +222,14 @@ SIG_RESULT= | |||
222 | SIG_BASE=36 # Use realtime signals | 222 | SIG_BASE=36 # Use realtime signals |
223 | SIG_PID=$$ | 223 | SIG_PID=$$ |
224 | 224 | ||
225 | exit_pass () { | ||
226 | exit 0 | ||
227 | } | ||
228 | |||
225 | SIG_FAIL=$((SIG_BASE + FAIL)) | 229 | SIG_FAIL=$((SIG_BASE + FAIL)) |
230 | exit_fail () { | ||
231 | exit 1 | ||
232 | } | ||
226 | trap 'SIG_RESULT=$FAIL' $SIG_FAIL | 233 | trap 'SIG_RESULT=$FAIL' $SIG_FAIL |
227 | 234 | ||
228 | SIG_UNRESOLVED=$((SIG_BASE + UNRESOLVED)) | 235 | SIG_UNRESOLVED=$((SIG_BASE + UNRESOLVED)) |
diff --git a/tools/testing/selftests/ftrace/test.d/00basic/basic4.tc b/tools/testing/selftests/ftrace/test.d/00basic/basic4.tc index aa51f6c17359..0696098d6408 100644 --- a/tools/testing/selftests/ftrace/test.d/00basic/basic4.tc +++ b/tools/testing/selftests/ftrace/test.d/00basic/basic4.tc | |||
@@ -2,4 +2,4 @@ | |||
2 | # description: Basic event tracing check | 2 | # description: Basic event tracing check |
3 | test -f available_events -a -f set_event -a -d events | 3 | test -f available_events -a -f set_event -a -d events |
4 | # check scheduler events are available | 4 | # check scheduler events are available |
5 | grep -q sched available_events && exit 0 || exit $FAIL | 5 | grep -q sched available_events && exit_pass || exit_fail |
diff --git a/tools/testing/selftests/ftrace/test.d/event/event-enable.tc b/tools/testing/selftests/ftrace/test.d/event/event-enable.tc index 6ff851a75884..9daf034186f5 100644 --- a/tools/testing/selftests/ftrace/test.d/event/event-enable.tc +++ b/tools/testing/selftests/ftrace/test.d/event/event-enable.tc | |||
@@ -11,7 +11,7 @@ do_reset() { | |||
11 | fail() { #msg | 11 | fail() { #msg |
12 | do_reset | 12 | do_reset |
13 | echo $1 | 13 | echo $1 |
14 | exit $FAIL | 14 | exit_fail |
15 | } | 15 | } |
16 | 16 | ||
17 | yield() { | 17 | yield() { |
diff --git a/tools/testing/selftests/ftrace/test.d/event/event-pid.tc b/tools/testing/selftests/ftrace/test.d/event/event-pid.tc index cc14feec6e1f..132478b305c2 100644 --- a/tools/testing/selftests/ftrace/test.d/event/event-pid.tc +++ b/tools/testing/selftests/ftrace/test.d/event/event-pid.tc | |||
@@ -13,7 +13,7 @@ do_reset() { | |||
13 | fail() { #msg | 13 | fail() { #msg |
14 | do_reset | 14 | do_reset |
15 | echo $1 | 15 | echo $1 |
16 | exit $FAIL | 16 | exit_fail |
17 | } | 17 | } |
18 | 18 | ||
19 | yield() { | 19 | yield() { |
diff --git a/tools/testing/selftests/ftrace/test.d/event/subsystem-enable.tc b/tools/testing/selftests/ftrace/test.d/event/subsystem-enable.tc index 85094904aa79..6a37a8642ee6 100644 --- a/tools/testing/selftests/ftrace/test.d/event/subsystem-enable.tc +++ b/tools/testing/selftests/ftrace/test.d/event/subsystem-enable.tc | |||
@@ -11,7 +11,7 @@ do_reset() { | |||
11 | fail() { #msg | 11 | fail() { #msg |
12 | do_reset | 12 | do_reset |
13 | echo $1 | 13 | echo $1 |
14 | exit $FAIL | 14 | exit_fail |
15 | } | 15 | } |
16 | 16 | ||
17 | yield() { | 17 | yield() { |
diff --git a/tools/testing/selftests/ftrace/test.d/event/toplevel-enable.tc b/tools/testing/selftests/ftrace/test.d/event/toplevel-enable.tc index cc1cf4d30ef5..4e9b6e2c0219 100644 --- a/tools/testing/selftests/ftrace/test.d/event/toplevel-enable.tc +++ b/tools/testing/selftests/ftrace/test.d/event/toplevel-enable.tc | |||
@@ -10,7 +10,7 @@ do_reset() { | |||
10 | fail() { #msg | 10 | fail() { #msg |
11 | do_reset | 11 | do_reset |
12 | echo $1 | 12 | echo $1 |
13 | exit $FAIL | 13 | exit_fail |
14 | } | 14 | } |
15 | 15 | ||
16 | yield() { | 16 | yield() { |
diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/fgraph-filter-stack.tc b/tools/testing/selftests/ftrace/test.d/ftrace/fgraph-filter-stack.tc index 45df747887e0..1aec99d108eb 100644 --- a/tools/testing/selftests/ftrace/test.d/ftrace/fgraph-filter-stack.tc +++ b/tools/testing/selftests/ftrace/test.d/ftrace/fgraph-filter-stack.tc | |||
@@ -28,7 +28,7 @@ do_reset() { | |||
28 | fail() { # msg | 28 | fail() { # msg |
29 | do_reset | 29 | do_reset |
30 | echo $1 | 30 | echo $1 |
31 | exit $FAIL | 31 | exit_fail |
32 | } | 32 | } |
33 | 33 | ||
34 | disable_tracing | 34 | disable_tracing |
diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/fgraph-filter.tc b/tools/testing/selftests/ftrace/test.d/ftrace/fgraph-filter.tc index 0387e22e7577..9f8d27ca39cf 100644 --- a/tools/testing/selftests/ftrace/test.d/ftrace/fgraph-filter.tc +++ b/tools/testing/selftests/ftrace/test.d/ftrace/fgraph-filter.tc | |||
@@ -18,7 +18,7 @@ do_reset() { | |||
18 | fail() { # msg | 18 | fail() { # msg |
19 | do_reset | 19 | do_reset |
20 | echo $1 | 20 | echo $1 |
21 | exit $FAIL | 21 | exit_fail |
22 | } | 22 | } |
23 | 23 | ||
24 | disable_tracing | 24 | disable_tracing |
diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/func-filter-pid.tc b/tools/testing/selftests/ftrace/test.d/ftrace/func-filter-pid.tc index 78524fcc25ae..524ce24b3c22 100644 --- a/tools/testing/selftests/ftrace/test.d/ftrace/func-filter-pid.tc +++ b/tools/testing/selftests/ftrace/test.d/ftrace/func-filter-pid.tc | |||
@@ -51,7 +51,7 @@ do_reset() { | |||
51 | fail() { # msg | 51 | fail() { # msg |
52 | do_reset | 52 | do_reset |
53 | echo $1 | 53 | echo $1 |
54 | exit $FAIL | 54 | exit_fail |
55 | } | 55 | } |
56 | 56 | ||
57 | yield() { | 57 | yield() { |
diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/func_event_triggers.tc b/tools/testing/selftests/ftrace/test.d/ftrace/func_event_triggers.tc index 9d4afcca1e36..6fed4cf2db81 100644 --- a/tools/testing/selftests/ftrace/test.d/ftrace/func_event_triggers.tc +++ b/tools/testing/selftests/ftrace/test.d/ftrace/func_event_triggers.tc | |||
@@ -27,7 +27,7 @@ do_reset() { | |||
27 | fail() { # mesg | 27 | fail() { # mesg |
28 | do_reset | 28 | do_reset |
29 | echo $1 | 29 | echo $1 |
30 | exit $FAIL | 30 | exit_fail |
31 | } | 31 | } |
32 | 32 | ||
33 | SLEEP_TIME=".1" | 33 | SLEEP_TIME=".1" |
@@ -48,8 +48,7 @@ test_event_enabled() { | |||
48 | 48 | ||
49 | e=`cat $EVENT_ENABLE` | 49 | e=`cat $EVENT_ENABLE` |
50 | if [ "$e" != $val ]; then | 50 | if [ "$e" != $val ]; then |
51 | echo "Expected $val but found $e" | 51 | fail "Expected $val but found $e" |
52 | exit 1 | ||
53 | fi | 52 | fi |
54 | } | 53 | } |
55 | 54 | ||
diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/func_profiler.tc b/tools/testing/selftests/ftrace/test.d/ftrace/func_profiler.tc index fe0dc5a7ea26..b2d5a8febfe8 100644 --- a/tools/testing/selftests/ftrace/test.d/ftrace/func_profiler.tc +++ b/tools/testing/selftests/ftrace/test.d/ftrace/func_profiler.tc | |||
@@ -32,7 +32,7 @@ fail() { # mesg | |||
32 | reset_tracer | 32 | reset_tracer |
33 | echo > set_ftrace_filter | 33 | echo > set_ftrace_filter |
34 | echo $1 | 34 | echo $1 |
35 | exit $FAIL | 35 | exit_fail |
36 | } | 36 | } |
37 | 37 | ||
38 | echo "Testing function tracer with profiler:" | 38 | echo "Testing function tracer with profiler:" |
diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/func_set_ftrace_file.tc b/tools/testing/selftests/ftrace/test.d/ftrace/func_set_ftrace_file.tc index 5ad723724adb..0f3f92622e33 100644 --- a/tools/testing/selftests/ftrace/test.d/ftrace/func_set_ftrace_file.tc +++ b/tools/testing/selftests/ftrace/test.d/ftrace/func_set_ftrace_file.tc | |||
@@ -26,14 +26,14 @@ do_reset() { | |||
26 | fail() { # mesg | 26 | fail() { # mesg |
27 | do_reset | 27 | do_reset |
28 | echo $1 | 28 | echo $1 |
29 | exit $FAIL | 29 | exit_fail |
30 | } | 30 | } |
31 | 31 | ||
32 | do_reset | 32 | do_reset |
33 | 33 | ||
34 | FILTER=set_ftrace_filter | 34 | FILTER=set_ftrace_filter |
35 | FUNC1="schedule" | 35 | FUNC1="schedule" |
36 | FUNC2="do_IRQ" | 36 | FUNC2="do_softirq" |
37 | 37 | ||
38 | ALL_FUNCS="#### all functions enabled ####" | 38 | ALL_FUNCS="#### all functions enabled ####" |
39 | 39 | ||
diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/func_traceonoff_triggers.tc b/tools/testing/selftests/ftrace/test.d/ftrace/func_traceonoff_triggers.tc index cdc92a371cd7..f6d9ac73268a 100644 --- a/tools/testing/selftests/ftrace/test.d/ftrace/func_traceonoff_triggers.tc +++ b/tools/testing/selftests/ftrace/test.d/ftrace/func_traceonoff_triggers.tc | |||
@@ -27,7 +27,7 @@ do_reset() { | |||
27 | fail() { # mesg | 27 | fail() { # mesg |
28 | do_reset | 28 | do_reset |
29 | echo $1 | 29 | echo $1 |
30 | exit $FAIL | 30 | exit_fail |
31 | } | 31 | } |
32 | 32 | ||
33 | SLEEP_TIME=".1" | 33 | SLEEP_TIME=".1" |
diff --git a/tools/testing/selftests/ftrace/test.d/instances/instance-event.tc b/tools/testing/selftests/ftrace/test.d/instances/instance-event.tc index d7f48b55df51..4fa0f79144f4 100644 --- a/tools/testing/selftests/ftrace/test.d/instances/instance-event.tc +++ b/tools/testing/selftests/ftrace/test.d/instances/instance-event.tc | |||
@@ -11,7 +11,7 @@ fail() { # mesg | |||
11 | rmdir foo 2>/dev/null | 11 | rmdir foo 2>/dev/null |
12 | echo $1 | 12 | echo $1 |
13 | set -e | 13 | set -e |
14 | exit $FAIL | 14 | exit_fail |
15 | } | 15 | } |
16 | 16 | ||
17 | cd instances | 17 | cd instances |
diff --git a/tools/testing/selftests/ftrace/test.d/instances/instance.tc b/tools/testing/selftests/ftrace/test.d/instances/instance.tc index ddda62203366..b84651283bf3 100644 --- a/tools/testing/selftests/ftrace/test.d/instances/instance.tc +++ b/tools/testing/selftests/ftrace/test.d/instances/instance.tc | |||
@@ -11,7 +11,7 @@ fail() { # mesg | |||
11 | rmdir x y z 2>/dev/null | 11 | rmdir x y z 2>/dev/null |
12 | echo $1 | 12 | echo $1 |
13 | set -e | 13 | set -e |
14 | exit $FAIL | 14 | exit_fail |
15 | } | 15 | } |
16 | 16 | ||
17 | cd instances | 17 | cd instances |
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc b/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc index 0e6f415c6152..bbc443a9190c 100644 --- a/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc +++ b/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc | |||
@@ -9,7 +9,7 @@ echo > kprobe_events | |||
9 | echo p:myevent _do_fork > kprobe_events | 9 | echo p:myevent _do_fork > kprobe_events |
10 | test -d events/kprobes/myevent | 10 | test -d events/kprobes/myevent |
11 | echo 1 > events/kprobes/myevent/enable | 11 | echo 1 > events/kprobes/myevent/enable |
12 | echo > kprobe_events && exit 1 # this must fail | 12 | echo > kprobe_events && exit_fail # this must fail |
13 | echo 0 > events/kprobes/myevent/enable | 13 | echo 0 > events/kprobes/myevent/enable |
14 | echo > kprobe_events # this must succeed | 14 | echo > kprobe_events # this must succeed |
15 | clear_trace | 15 | clear_trace |
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc index 679bbd23bcc3..8b43c6804fc3 100644 --- a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc +++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc | |||
@@ -14,5 +14,5 @@ echo 1 > events/kprobes/testprobe/enable | |||
14 | echo 0 > events/kprobes/testprobe/enable | 14 | echo 0 > events/kprobes/testprobe/enable |
15 | echo "-:testprobe" >> kprobe_events | 15 | echo "-:testprobe" >> kprobe_events |
16 | clear_trace | 16 | clear_trace |
17 | test -d events/kprobes/testprobe && exit 1 || exit 0 | 17 | test -d events/kprobes/testprobe && exit_fail || exit_pass |
18 | 18 | ||
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_type.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_type.tc index 17d33ba192f6..2a1755bfc290 100644 --- a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_type.tc +++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_type.tc | |||
@@ -35,4 +35,4 @@ check_types $ARGS | |||
35 | 35 | ||
36 | echo "-:testprobe" >> kprobe_events | 36 | echo "-:testprobe" >> kprobe_events |
37 | clear_trace | 37 | clear_trace |
38 | test -d events/kprobes/testprobe && exit 1 || exit 0 | 38 | test -d events/kprobes/testprobe && exit_fail || exit_pass |
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc index f1825bdbe3f3..321954683aaa 100644 --- a/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc +++ b/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc | |||
@@ -14,4 +14,4 @@ echo 1 > events/kprobes/testprobe2/enable | |||
14 | echo 0 > events/kprobes/testprobe2/enable | 14 | echo 0 > events/kprobes/testprobe2/enable |
15 | echo '-:testprobe2' >> kprobe_events | 15 | echo '-:testprobe2' >> kprobe_events |
16 | clear_trace | 16 | clear_trace |
17 | test -d events/kprobes/testprobe2 && exit 1 || exit 0 | 17 | test -d events/kprobes/testprobe2 && exit_fail || exit_pass |
diff --git a/tools/testing/selftests/ftrace/test.d/template b/tools/testing/selftests/ftrace/test.d/template index 5448f7abad5f..5c39ceb18a0d 100644 --- a/tools/testing/selftests/ftrace/test.d/template +++ b/tools/testing/selftests/ftrace/test.d/template | |||
@@ -4,6 +4,7 @@ | |||
4 | # Note that all tests are run with "errexit" option. | 4 | # Note that all tests are run with "errexit" option. |
5 | 5 | ||
6 | exit 0 # Return 0 if the test is passed, otherwise return !0 | 6 | exit 0 # Return 0 if the test is passed, otherwise return !0 |
7 | # Or you can call exit_pass for passed test, and exit_fail for failed test. | ||
7 | # If the test could not run because of lack of feature, call exit_unsupported | 8 | # If the test could not run because of lack of feature, call exit_unsupported |
8 | # If the test returned unclear results, call exit_unresolved | 9 | # If the test returned unclear results, call exit_unresolved |
9 | # If the test is a dummy, or a placeholder, call exit_untested | 10 | # If the test is a dummy, or a placeholder, call exit_untested |
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-eventonoff.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-eventonoff.tc index 839ac4320b24..28cc355a3a7b 100644 --- a/tools/testing/selftests/ftrace/test.d/trigger/trigger-eventonoff.tc +++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-eventonoff.tc | |||
@@ -12,7 +12,7 @@ do_reset() { | |||
12 | fail() { #msg | 12 | fail() { #msg |
13 | do_reset | 13 | do_reset |
14 | echo $1 | 14 | echo $1 |
15 | exit $FAIL | 15 | exit_fail |
16 | } | 16 | } |
17 | 17 | ||
18 | if [ ! -f set_event -o ! -d events/sched ]; then | 18 | if [ ! -f set_event -o ! -d events/sched ]; then |
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-filter.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-filter.tc index 66873c4b12c9..a48e23eb8a8b 100644 --- a/tools/testing/selftests/ftrace/test.d/trigger/trigger-filter.tc +++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-filter.tc | |||
@@ -12,7 +12,7 @@ do_reset() { | |||
12 | fail() { #msg | 12 | fail() { #msg |
13 | do_reset | 13 | do_reset |
14 | echo $1 | 14 | echo $1 |
15 | exit $FAIL | 15 | exit_fail |
16 | } | 16 | } |
17 | 17 | ||
18 | if [ ! -f set_event -o ! -d events/sched ]; then | 18 | if [ ! -f set_event -o ! -d events/sched ]; then |
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist-mod.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist-mod.tc index 4237b32769f1..8da80efc44d8 100644 --- a/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist-mod.tc +++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist-mod.tc | |||
@@ -12,7 +12,7 @@ do_reset() { | |||
12 | fail() { #msg | 12 | fail() { #msg |
13 | do_reset | 13 | do_reset |
14 | echo $1 | 14 | echo $1 |
15 | exit $FAIL | 15 | exit_fail |
16 | } | 16 | } |
17 | 17 | ||
18 | if [ ! -f set_event -o ! -d events/sched ]; then | 18 | if [ ! -f set_event -o ! -d events/sched ]; then |
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist.tc index d24e2b8bd863..449fe9ff91a2 100644 --- a/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist.tc +++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist.tc | |||
@@ -12,7 +12,7 @@ do_reset() { | |||
12 | fail() { #msg | 12 | fail() { #msg |
13 | do_reset | 13 | do_reset |
14 | echo $1 | 14 | echo $1 |
15 | exit $FAIL | 15 | exit_fail |
16 | } | 16 | } |
17 | 17 | ||
18 | if [ ! -f set_event -o ! -d events/sched ]; then | 18 | if [ ! -f set_event -o ! -d events/sched ]; then |
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-multihist.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-multihist.tc index 4c0774fff378..c5ef8b9d02b3 100644 --- a/tools/testing/selftests/ftrace/test.d/trigger/trigger-multihist.tc +++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-multihist.tc | |||
@@ -12,7 +12,7 @@ do_reset() { | |||
12 | fail() { #msg | 12 | fail() { #msg |
13 | do_reset | 13 | do_reset |
14 | echo $1 | 14 | echo $1 |
15 | exit $FAIL | 15 | exit_fail |
16 | } | 16 | } |
17 | 17 | ||
18 | if [ ! -f set_event -o ! -d events/sched ]; then | 18 | if [ ! -f set_event -o ! -d events/sched ]; then |
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-snapshot.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-snapshot.tc index 3fc6321e081f..ed38f0050d77 100644 --- a/tools/testing/selftests/ftrace/test.d/trigger/trigger-snapshot.tc +++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-snapshot.tc | |||
@@ -11,7 +11,7 @@ do_reset() { | |||
11 | fail() { #msg | 11 | fail() { #msg |
12 | do_reset | 12 | do_reset |
13 | echo $1 | 13 | echo $1 |
14 | exit $FAIL | 14 | exit_fail |
15 | } | 15 | } |
16 | 16 | ||
17 | if [ ! -f set_event -o ! -d events/sched ]; then | 17 | if [ ! -f set_event -o ! -d events/sched ]; then |
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-stacktrace.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-stacktrace.tc index 3652824f81ed..3121d795a868 100644 --- a/tools/testing/selftests/ftrace/test.d/trigger/trigger-stacktrace.tc +++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-stacktrace.tc | |||
@@ -11,7 +11,7 @@ do_reset() { | |||
11 | fail() { #msg | 11 | fail() { #msg |
12 | do_reset | 12 | do_reset |
13 | echo $1 | 13 | echo $1 |
14 | exit $FAIL | 14 | exit_fail |
15 | } | 15 | } |
16 | 16 | ||
17 | if [ ! -f set_event -o ! -d events/sched ]; then | 17 | if [ ! -f set_event -o ! -d events/sched ]; then |
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-traceonoff.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-traceonoff.tc index 6d9051cdf408..c59d9eb546da 100644 --- a/tools/testing/selftests/ftrace/test.d/trigger/trigger-traceonoff.tc +++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-traceonoff.tc | |||
@@ -11,7 +11,7 @@ do_reset() { | |||
11 | fail() { #msg | 11 | fail() { #msg |
12 | do_reset | 12 | do_reset |
13 | echo $1 | 13 | echo $1 |
14 | exit $FAIL | 14 | exit_fail |
15 | } | 15 | } |
16 | 16 | ||
17 | if [ ! -f set_event -o ! -d events/sched ]; then | 17 | if [ ! -f set_event -o ! -d events/sched ]; then |
diff --git a/tools/testing/selftests/memfd/memfd_test.c b/tools/testing/selftests/memfd/memfd_test.c index 845e5f67b6f0..132a54f74e88 100644 --- a/tools/testing/selftests/memfd/memfd_test.c +++ b/tools/testing/selftests/memfd/memfd_test.c | |||
@@ -515,7 +515,7 @@ static void mfd_assert_grow_write(int fd) | |||
515 | 515 | ||
516 | buf = malloc(mfd_def_size * 8); | 516 | buf = malloc(mfd_def_size * 8); |
517 | if (!buf) { | 517 | if (!buf) { |
518 | printf("malloc(%d) failed: %m\n", mfd_def_size * 8); | 518 | printf("malloc(%zu) failed: %m\n", mfd_def_size * 8); |
519 | abort(); | 519 | abort(); |
520 | } | 520 | } |
521 | 521 | ||
@@ -535,7 +535,7 @@ static void mfd_fail_grow_write(int fd) | |||
535 | 535 | ||
536 | buf = malloc(mfd_def_size * 8); | 536 | buf = malloc(mfd_def_size * 8); |
537 | if (!buf) { | 537 | if (!buf) { |
538 | printf("malloc(%d) failed: %m\n", mfd_def_size * 8); | 538 | printf("malloc(%zu) failed: %m\n", mfd_def_size * 8); |
539 | abort(); | 539 | abort(); |
540 | } | 540 | } |
541 | 541 | ||
diff --git a/tools/testing/selftests/memory-hotplug/Makefile b/tools/testing/selftests/memory-hotplug/Makefile index 23db11c94b59..86636d207adf 100644 --- a/tools/testing/selftests/memory-hotplug/Makefile +++ b/tools/testing/selftests/memory-hotplug/Makefile | |||
@@ -4,10 +4,10 @@ all: | |||
4 | include ../lib.mk | 4 | include ../lib.mk |
5 | 5 | ||
6 | TEST_PROGS := mem-on-off-test.sh | 6 | TEST_PROGS := mem-on-off-test.sh |
7 | override RUN_TESTS := ./mem-on-off-test.sh -r 2 || echo "selftests: memory-hotplug [FAIL]" | 7 | override RUN_TESTS := ./mem-on-off-test.sh -r 2 && echo "selftests: memory-hotplug [PASS]" || echo "selftests: memory-hotplug [FAIL]" |
8 | override EMIT_TESTS := echo "$(RUN_TESTS)" | 8 | override EMIT_TESTS := echo "$(RUN_TESTS)" |
9 | 9 | ||
10 | run_full_test: | 10 | run_full_test: |
11 | @/bin/bash ./mem-on-off-test.sh || echo "memory-hotplug selftests: [FAIL]" | 11 | @/bin/bash ./mem-on-off-test.sh && echo "memory-hotplug selftests: [PASS]" || echo "memory-hotplug selftests: [FAIL]" |
12 | 12 | ||
13 | clean: | 13 | clean: |
diff --git a/tools/testing/selftests/net/rtnetlink.sh b/tools/testing/selftests/net/rtnetlink.sh index 57b5ff576240..5215493166c9 100755 --- a/tools/testing/selftests/net/rtnetlink.sh +++ b/tools/testing/selftests/net/rtnetlink.sh | |||
@@ -15,6 +15,14 @@ check_err() | |||
15 | fi | 15 | fi |
16 | } | 16 | } |
17 | 17 | ||
18 | # same but inverted -- used when command must fail for test to pass | ||
19 | check_fail() | ||
20 | { | ||
21 | if [ $1 -eq 0 ]; then | ||
22 | ret=1 | ||
23 | fi | ||
24 | } | ||
25 | |||
18 | kci_add_dummy() | 26 | kci_add_dummy() |
19 | { | 27 | { |
20 | ip link add name "$devdummy" type dummy | 28 | ip link add name "$devdummy" type dummy |
@@ -29,6 +37,26 @@ kci_del_dummy() | |||
29 | check_err $? | 37 | check_err $? |
30 | } | 38 | } |
31 | 39 | ||
40 | kci_test_netconf() | ||
41 | { | ||
42 | dev="$1" | ||
43 | r=$ret | ||
44 | |||
45 | ip netconf show dev "$dev" > /dev/null | ||
46 | check_err $? | ||
47 | |||
48 | for f in 4 6; do | ||
49 | ip -$f netconf show dev "$dev" > /dev/null | ||
50 | check_err $? | ||
51 | done | ||
52 | |||
53 | if [ $ret -ne 0 ] ;then | ||
54 | echo "FAIL: ip netconf show $dev" | ||
55 | test $r -eq 0 && ret=0 | ||
56 | return 1 | ||
57 | fi | ||
58 | } | ||
59 | |||
32 | # add a bridge with vlans on top | 60 | # add a bridge with vlans on top |
33 | kci_test_bridge() | 61 | kci_test_bridge() |
34 | { | 62 | { |
@@ -55,6 +83,11 @@ kci_test_bridge() | |||
55 | check_err $? | 83 | check_err $? |
56 | ip r s t all > /dev/null | 84 | ip r s t all > /dev/null |
57 | check_err $? | 85 | check_err $? |
86 | |||
87 | for name in "$devbr" "$vlandev" "$devdummy" ; do | ||
88 | kci_test_netconf "$name" | ||
89 | done | ||
90 | |||
58 | ip -6 addr del dev "$vlandev" dead:42::1234/64 | 91 | ip -6 addr del dev "$vlandev" dead:42::1234/64 |
59 | check_err $? | 92 | check_err $? |
60 | 93 | ||
@@ -92,6 +125,9 @@ kci_test_gre() | |||
92 | check_err $? | 125 | check_err $? |
93 | ip addr > /dev/null | 126 | ip addr > /dev/null |
94 | check_err $? | 127 | check_err $? |
128 | |||
129 | kci_test_netconf "$gredev" | ||
130 | |||
95 | ip addr del dev "$devdummy" 10.23.7.11/24 | 131 | ip addr del dev "$devdummy" 10.23.7.11/24 |
96 | check_err $? | 132 | check_err $? |
97 | 133 | ||
@@ -235,6 +271,237 @@ kci_test_addrlabel() | |||
235 | echo "PASS: ipv6 addrlabel" | 271 | echo "PASS: ipv6 addrlabel" |
236 | } | 272 | } |
237 | 273 | ||
274 | kci_test_ifalias() | ||
275 | { | ||
276 | ret=0 | ||
277 | namewant=$(uuidgen) | ||
278 | syspathname="/sys/class/net/$devdummy/ifalias" | ||
279 | |||
280 | ip link set dev "$devdummy" alias "$namewant" | ||
281 | check_err $? | ||
282 | |||
283 | if [ $ret -ne 0 ]; then | ||
284 | echo "FAIL: cannot set interface alias of $devdummy to $namewant" | ||
285 | return 1 | ||
286 | fi | ||
287 | |||
288 | ip link show "$devdummy" | grep -q "alias $namewant" | ||
289 | check_err $? | ||
290 | |||
291 | if [ -r "$syspathname" ] ; then | ||
292 | read namehave < "$syspathname" | ||
293 | if [ "$namewant" != "$namehave" ]; then | ||
294 | echo "FAIL: did set ifalias $namewant but got $namehave" | ||
295 | return 1 | ||
296 | fi | ||
297 | |||
298 | namewant=$(uuidgen) | ||
299 | echo "$namewant" > "$syspathname" | ||
300 | ip link show "$devdummy" | grep -q "alias $namewant" | ||
301 | check_err $? | ||
302 | |||
303 | # sysfs interface allows to delete alias again | ||
304 | echo "" > "$syspathname" | ||
305 | |||
306 | ip link show "$devdummy" | grep -q "alias $namewant" | ||
307 | check_fail $? | ||
308 | |||
309 | for i in $(seq 1 100); do | ||
310 | uuidgen > "$syspathname" & | ||
311 | done | ||
312 | |||
313 | wait | ||
314 | |||
315 | # re-add the alias -- kernel should free mem when dummy dev is removed | ||
316 | ip link set dev "$devdummy" alias "$namewant" | ||
317 | check_err $? | ||
318 | fi | ||
319 | |||
320 | if [ $ret -ne 0 ]; then | ||
321 | echo "FAIL: set interface alias $devdummy to $namewant" | ||
322 | return 1 | ||
323 | fi | ||
324 | |||
325 | echo "PASS: set ifalias $namewant for $devdummy" | ||
326 | } | ||
327 | |||
328 | kci_test_vrf() | ||
329 | { | ||
330 | vrfname="test-vrf" | ||
331 | ret=0 | ||
332 | |||
333 | ip link show type vrf 2>/dev/null | ||
334 | if [ $? -ne 0 ]; then | ||
335 | echo "SKIP: vrf: iproute2 too old" | ||
336 | return 0 | ||
337 | fi | ||
338 | |||
339 | ip link add "$vrfname" type vrf table 10 | ||
340 | check_err $? | ||
341 | if [ $ret -ne 0 ];then | ||
342 | echo "FAIL: can't add vrf interface, skipping test" | ||
343 | return 0 | ||
344 | fi | ||
345 | |||
346 | ip -br link show type vrf | grep -q "$vrfname" | ||
347 | check_err $? | ||
348 | if [ $ret -ne 0 ];then | ||
349 | echo "FAIL: created vrf device not found" | ||
350 | return 1 | ||
351 | fi | ||
352 | |||
353 | ip link set dev "$vrfname" up | ||
354 | check_err $? | ||
355 | |||
356 | ip link set dev "$devdummy" master "$vrfname" | ||
357 | check_err $? | ||
358 | ip link del dev "$vrfname" | ||
359 | check_err $? | ||
360 | |||
361 | if [ $ret -ne 0 ];then | ||
362 | echo "FAIL: vrf" | ||
363 | return 1 | ||
364 | fi | ||
365 | |||
366 | echo "PASS: vrf" | ||
367 | } | ||
368 | |||
369 | kci_test_encap_vxlan() | ||
370 | { | ||
371 | ret=0 | ||
372 | vxlan="test-vxlan0" | ||
373 | vlan="test-vlan0" | ||
374 | testns="$1" | ||
375 | |||
376 | ip netns exec "$testns" ip link add "$vxlan" type vxlan id 42 group 239.1.1.1 \ | ||
377 | dev "$devdummy" dstport 4789 2>/dev/null | ||
378 | if [ $? -ne 0 ]; then | ||
379 | echo "FAIL: can't add vxlan interface, skipping test" | ||
380 | return 0 | ||
381 | fi | ||
382 | check_err $? | ||
383 | |||
384 | ip netns exec "$testns" ip addr add 10.2.11.49/24 dev "$vxlan" | ||
385 | check_err $? | ||
386 | |||
387 | ip netns exec "$testns" ip link set up dev "$vxlan" | ||
388 | check_err $? | ||
389 | |||
390 | ip netns exec "$testns" ip link add link "$vxlan" name "$vlan" type vlan id 1 | ||
391 | check_err $? | ||
392 | |||
393 | ip netns exec "$testns" ip link del "$vxlan" | ||
394 | check_err $? | ||
395 | |||
396 | if [ $ret -ne 0 ]; then | ||
397 | echo "FAIL: vxlan" | ||
398 | return 1 | ||
399 | fi | ||
400 | echo "PASS: vxlan" | ||
401 | } | ||
402 | |||
403 | kci_test_encap_fou() | ||
404 | { | ||
405 | ret=0 | ||
406 | name="test-fou" | ||
407 | testns="$1" | ||
408 | |||
409 | ip fou help 2>&1 |grep -q 'Usage: ip fou' | ||
410 | if [ $? -ne 0 ];then | ||
411 | echo "SKIP: fou: iproute2 too old" | ||
412 | return 1 | ||
413 | fi | ||
414 | |||
415 | ip netns exec "$testns" ip fou add port 7777 ipproto 47 2>/dev/null | ||
416 | if [ $? -ne 0 ];then | ||
417 | echo "FAIL: can't add fou port 7777, skipping test" | ||
418 | return 1 | ||
419 | fi | ||
420 | |||
421 | ip netns exec "$testns" ip fou add port 8888 ipproto 4 | ||
422 | check_err $? | ||
423 | |||
424 | ip netns exec "$testns" ip fou del port 9999 2>/dev/null | ||
425 | check_fail $? | ||
426 | |||
427 | ip netns exec "$testns" ip fou del port 7777 | ||
428 | check_err $? | ||
429 | |||
430 | if [ $ret -ne 0 ]; then | ||
431 | echo "FAIL: fou" | ||
432 | return 1 | ||
433 | fi | ||
434 | |||
435 | echo "PASS: fou" | ||
436 | } | ||
437 | |||
438 | # test various encap methods, use netns to avoid unwanted interference | ||
439 | kci_test_encap() | ||
440 | { | ||
441 | testns="testns" | ||
442 | ret=0 | ||
443 | |||
444 | ip netns add "$testns" | ||
445 | if [ $? -ne 0 ]; then | ||
446 | echo "SKIP encap tests: cannot add net namespace $testns" | ||
447 | return 1 | ||
448 | fi | ||
449 | |||
450 | ip netns exec "$testns" ip link set lo up | ||
451 | check_err $? | ||
452 | |||
453 | ip netns exec "$testns" ip link add name "$devdummy" type dummy | ||
454 | check_err $? | ||
455 | ip netns exec "$testns" ip link set "$devdummy" up | ||
456 | check_err $? | ||
457 | |||
458 | kci_test_encap_vxlan "$testns" | ||
459 | kci_test_encap_fou "$testns" | ||
460 | |||
461 | ip netns del "$testns" | ||
462 | } | ||
463 | |||
464 | kci_test_macsec() | ||
465 | { | ||
466 | msname="test_macsec0" | ||
467 | ret=0 | ||
468 | |||
469 | ip macsec help 2>&1 | grep -q "^Usage: ip macsec" | ||
470 | if [ $? -ne 0 ]; then | ||
471 | echo "SKIP: macsec: iproute2 too old" | ||
472 | return 0 | ||
473 | fi | ||
474 | |||
475 | ip link add link "$devdummy" "$msname" type macsec port 42 encrypt on | ||
476 | check_err $? | ||
477 | if [ $ret -ne 0 ];then | ||
478 | echo "FAIL: can't add macsec interface, skipping test" | ||
479 | return 1 | ||
480 | fi | ||
481 | |||
482 | ip macsec add "$msname" tx sa 0 pn 1024 on key 01 12345678901234567890123456789012 | ||
483 | check_err $? | ||
484 | |||
485 | ip macsec add "$msname" rx port 1234 address "1c:ed:de:ad:be:ef" | ||
486 | check_err $? | ||
487 | |||
488 | ip macsec add "$msname" rx port 1234 address "1c:ed:de:ad:be:ef" sa 0 pn 1 on key 00 0123456789abcdef0123456789abcdef | ||
489 | check_err $? | ||
490 | |||
491 | ip macsec show > /dev/null | ||
492 | check_err $? | ||
493 | |||
494 | ip link del dev "$msname" | ||
495 | check_err $? | ||
496 | |||
497 | if [ $ret -ne 0 ];then | ||
498 | echo "FAIL: macsec" | ||
499 | return 1 | ||
500 | fi | ||
501 | |||
502 | echo "PASS: macsec" | ||
503 | } | ||
504 | |||
238 | kci_test_rtnl() | 505 | kci_test_rtnl() |
239 | { | 506 | { |
240 | kci_add_dummy | 507 | kci_add_dummy |
@@ -249,6 +516,10 @@ kci_test_rtnl() | |||
249 | kci_test_gre | 516 | kci_test_gre |
250 | kci_test_bridge | 517 | kci_test_bridge |
251 | kci_test_addrlabel | 518 | kci_test_addrlabel |
519 | kci_test_ifalias | ||
520 | kci_test_vrf | ||
521 | kci_test_encap | ||
522 | kci_test_macsec | ||
252 | 523 | ||
253 | kci_del_dummy | 524 | kci_del_dummy |
254 | } | 525 | } |
diff --git a/tools/testing/selftests/powerpc/benchmarks/context_switch.c b/tools/testing/selftests/powerpc/benchmarks/context_switch.c index f4241339edd2..87f1f0252299 100644 --- a/tools/testing/selftests/powerpc/benchmarks/context_switch.c +++ b/tools/testing/selftests/powerpc/benchmarks/context_switch.c | |||
@@ -10,6 +10,7 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | #define _GNU_SOURCE | 12 | #define _GNU_SOURCE |
13 | #include <errno.h> | ||
13 | #include <sched.h> | 14 | #include <sched.h> |
14 | #include <string.h> | 15 | #include <string.h> |
15 | #include <stdio.h> | 16 | #include <stdio.h> |
@@ -75,6 +76,7 @@ static void touch(void) | |||
75 | 76 | ||
76 | static void start_thread_on(void *(*fn)(void *), void *arg, unsigned long cpu) | 77 | static void start_thread_on(void *(*fn)(void *), void *arg, unsigned long cpu) |
77 | { | 78 | { |
79 | int rc; | ||
78 | pthread_t tid; | 80 | pthread_t tid; |
79 | cpu_set_t cpuset; | 81 | cpu_set_t cpuset; |
80 | pthread_attr_t attr; | 82 | pthread_attr_t attr; |
@@ -82,14 +84,23 @@ static void start_thread_on(void *(*fn)(void *), void *arg, unsigned long cpu) | |||
82 | CPU_ZERO(&cpuset); | 84 | CPU_ZERO(&cpuset); |
83 | CPU_SET(cpu, &cpuset); | 85 | CPU_SET(cpu, &cpuset); |
84 | 86 | ||
85 | pthread_attr_init(&attr); | 87 | rc = pthread_attr_init(&attr); |
88 | if (rc) { | ||
89 | errno = rc; | ||
90 | perror("pthread_attr_init"); | ||
91 | exit(1); | ||
92 | } | ||
86 | 93 | ||
87 | if (pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset)) { | 94 | rc = pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset); |
95 | if (rc) { | ||
96 | errno = rc; | ||
88 | perror("pthread_attr_setaffinity_np"); | 97 | perror("pthread_attr_setaffinity_np"); |
89 | exit(1); | 98 | exit(1); |
90 | } | 99 | } |
91 | 100 | ||
92 | if (pthread_create(&tid, &attr, fn, arg)) { | 101 | rc = pthread_create(&tid, &attr, fn, arg); |
102 | if (rc) { | ||
103 | errno = rc; | ||
93 | perror("pthread_create"); | 104 | perror("pthread_create"); |
94 | exit(1); | 105 | exit(1); |
95 | } | 106 | } |
diff --git a/tools/testing/selftests/powerpc/dscr/dscr_sysfs_test.c b/tools/testing/selftests/powerpc/dscr/dscr_sysfs_test.c index 17fb1b43c320..1899bd85121f 100644 --- a/tools/testing/selftests/powerpc/dscr/dscr_sysfs_test.c +++ b/tools/testing/selftests/powerpc/dscr/dscr_sysfs_test.c | |||
@@ -53,6 +53,8 @@ static int check_all_cpu_dscr_defaults(unsigned long val) | |||
53 | } | 53 | } |
54 | 54 | ||
55 | while ((dp = readdir(sysfs))) { | 55 | while ((dp = readdir(sysfs))) { |
56 | int len; | ||
57 | |||
56 | if (!(dp->d_type & DT_DIR)) | 58 | if (!(dp->d_type & DT_DIR)) |
57 | continue; | 59 | continue; |
58 | if (!strcmp(dp->d_name, "cpuidle")) | 60 | if (!strcmp(dp->d_name, "cpuidle")) |
@@ -60,7 +62,9 @@ static int check_all_cpu_dscr_defaults(unsigned long val) | |||
60 | if (!strstr(dp->d_name, "cpu")) | 62 | if (!strstr(dp->d_name, "cpu")) |
61 | continue; | 63 | continue; |
62 | 64 | ||
63 | sprintf(file, "%s%s/dscr", CPU_PATH, dp->d_name); | 65 | len = snprintf(file, LEN_MAX, "%s%s/dscr", CPU_PATH, dp->d_name); |
66 | if (len >= LEN_MAX) | ||
67 | continue; | ||
64 | if (access(file, F_OK)) | 68 | if (access(file, F_OK)) |
65 | continue; | 69 | continue; |
66 | 70 | ||
diff --git a/tools/testing/selftests/powerpc/tm/.gitignore b/tools/testing/selftests/powerpc/tm/.gitignore index 2f1f7b013293..241a4a4ee0e4 100644 --- a/tools/testing/selftests/powerpc/tm/.gitignore +++ b/tools/testing/selftests/powerpc/tm/.gitignore | |||
@@ -12,3 +12,4 @@ tm-signal-context-chk-gpr | |||
12 | tm-signal-context-chk-vmx | 12 | tm-signal-context-chk-vmx |
13 | tm-signal-context-chk-vsx | 13 | tm-signal-context-chk-vsx |
14 | tm-vmx-unavail | 14 | tm-vmx-unavail |
15 | tm-unavailable | ||
diff --git a/tools/testing/selftests/powerpc/tm/Makefile b/tools/testing/selftests/powerpc/tm/Makefile index fca7c7f5e640..8ed6f8c57230 100644 --- a/tools/testing/selftests/powerpc/tm/Makefile +++ b/tools/testing/selftests/powerpc/tm/Makefile | |||
@@ -3,7 +3,7 @@ SIGNAL_CONTEXT_CHK_TESTS := tm-signal-context-chk-gpr tm-signal-context-chk-fpu | |||
3 | tm-signal-context-chk-vmx tm-signal-context-chk-vsx | 3 | tm-signal-context-chk-vmx tm-signal-context-chk-vsx |
4 | 4 | ||
5 | TEST_GEN_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack \ | 5 | TEST_GEN_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack \ |
6 | tm-vmxcopy tm-fork tm-tar tm-tmspr tm-vmx-unavail \ | 6 | tm-vmxcopy tm-fork tm-tar tm-tmspr tm-vmx-unavail tm-unavailable \ |
7 | $(SIGNAL_CONTEXT_CHK_TESTS) | 7 | $(SIGNAL_CONTEXT_CHK_TESTS) |
8 | 8 | ||
9 | include ../../lib.mk | 9 | include ../../lib.mk |
@@ -17,6 +17,7 @@ $(OUTPUT)/tm-syscall: CFLAGS += -I../../../../../usr/include | |||
17 | $(OUTPUT)/tm-tmspr: CFLAGS += -pthread | 17 | $(OUTPUT)/tm-tmspr: CFLAGS += -pthread |
18 | $(OUTPUT)/tm-vmx-unavail: CFLAGS += -pthread -m64 | 18 | $(OUTPUT)/tm-vmx-unavail: CFLAGS += -pthread -m64 |
19 | $(OUTPUT)/tm-resched-dscr: ../pmu/lib.o | 19 | $(OUTPUT)/tm-resched-dscr: ../pmu/lib.o |
20 | $(OUTPUT)/tm-unavailable: CFLAGS += -O0 -pthread -m64 -Wno-error=uninitialized -mvsx | ||
20 | 21 | ||
21 | SIGNAL_CONTEXT_CHK_TESTS := $(patsubst %,$(OUTPUT)/%,$(SIGNAL_CONTEXT_CHK_TESTS)) | 22 | SIGNAL_CONTEXT_CHK_TESTS := $(patsubst %,$(OUTPUT)/%,$(SIGNAL_CONTEXT_CHK_TESTS)) |
22 | $(SIGNAL_CONTEXT_CHK_TESTS): tm-signal.S | 23 | $(SIGNAL_CONTEXT_CHK_TESTS): tm-signal.S |
diff --git a/tools/testing/selftests/powerpc/tm/tm-unavailable.c b/tools/testing/selftests/powerpc/tm/tm-unavailable.c new file mode 100644 index 000000000000..96c37f84ce54 --- /dev/null +++ b/tools/testing/selftests/powerpc/tm/tm-unavailable.c | |||
@@ -0,0 +1,371 @@ | |||
1 | /* | ||
2 | * Copyright 2017, Gustavo Romero, Breno Leitao, Cyril Bur, IBM Corp. | ||
3 | * Licensed under GPLv2. | ||
4 | * | ||
5 | * Force FP, VEC and VSX unavailable exception during transaction in all | ||
6 | * possible scenarios regarding the MSR.FP and MSR.VEC state, e.g. when FP | ||
7 | * is enable and VEC is disable, when FP is disable and VEC is enable, and | ||
8 | * so on. Then we check if the restored state is correctly set for the | ||
9 | * FP and VEC registers to the previous state we set just before we entered | ||
10 | * in TM, i.e. we check if it corrupts somehow the recheckpointed FP and | ||
11 | * VEC/Altivec registers on abortion due to an unavailable exception in TM. | ||
12 | * N.B. In this test we do not test all the FP/Altivec/VSX registers for | ||
13 | * corruption, but only for registers vs0 and vs32, which are respectively | ||
14 | * representatives of FP and VEC/Altivec reg sets. | ||
15 | */ | ||
16 | |||
17 | #define _GNU_SOURCE | ||
18 | #include <stdio.h> | ||
19 | #include <stdlib.h> | ||
20 | #include <unistd.h> | ||
21 | #include <inttypes.h> | ||
22 | #include <stdbool.h> | ||
23 | #include <pthread.h> | ||
24 | #include <sched.h> | ||
25 | |||
26 | #include "tm.h" | ||
27 | |||
28 | #define DEBUG 0 | ||
29 | |||
30 | /* Unavailable exceptions to test in HTM */ | ||
31 | #define FP_UNA_EXCEPTION 0 | ||
32 | #define VEC_UNA_EXCEPTION 1 | ||
33 | #define VSX_UNA_EXCEPTION 2 | ||
34 | |||
35 | #define NUM_EXCEPTIONS 3 | ||
36 | |||
37 | struct Flags { | ||
38 | int touch_fp; | ||
39 | int touch_vec; | ||
40 | int result; | ||
41 | int exception; | ||
42 | } flags; | ||
43 | |||
44 | bool expecting_failure(void) | ||
45 | { | ||
46 | if (flags.touch_fp && flags.exception == FP_UNA_EXCEPTION) | ||
47 | return false; | ||
48 | |||
49 | if (flags.touch_vec && flags.exception == VEC_UNA_EXCEPTION) | ||
50 | return false; | ||
51 | |||
52 | /* | ||
53 | * If both FP and VEC are touched it does not mean that touching VSX | ||
54 | * won't raise an exception. However since FP and VEC state are already | ||
55 | * correctly loaded, the transaction is not aborted (i.e. | ||
56 | * treclaimed/trecheckpointed) and MSR.VSX is just set as 1, so a TM | ||
57 | * failure is not expected also in this case. | ||
58 | */ | ||
59 | if ((flags.touch_fp && flags.touch_vec) && | ||
60 | flags.exception == VSX_UNA_EXCEPTION) | ||
61 | return false; | ||
62 | |||
63 | return true; | ||
64 | } | ||
65 | |||
66 | /* Check if failure occurred whilst in transaction. */ | ||
67 | bool is_failure(uint64_t condition_reg) | ||
68 | { | ||
69 | /* | ||
70 | * When failure handling occurs, CR0 is set to 0b1010 (0xa). Otherwise | ||
71 | * transaction completes without failure and hence reaches out 'tend.' | ||
72 | * that sets CR0 to 0b0100 (0x4). | ||
73 | */ | ||
74 | return ((condition_reg >> 28) & 0xa) == 0xa; | ||
75 | } | ||
76 | |||
77 | void *ping(void *input) | ||
78 | { | ||
79 | |||
80 | /* | ||
81 | * Expected values for vs0 and vs32 after a TM failure. They must never | ||
82 | * change, otherwise they got corrupted. | ||
83 | */ | ||
84 | uint64_t high_vs0 = 0x5555555555555555; | ||
85 | uint64_t low_vs0 = 0xffffffffffffffff; | ||
86 | uint64_t high_vs32 = 0x5555555555555555; | ||
87 | uint64_t low_vs32 = 0xffffffffffffffff; | ||
88 | |||
89 | /* Counter for busy wait */ | ||
90 | uint64_t counter = 0x1ff000000; | ||
91 | |||
92 | /* | ||
93 | * Variable to keep a copy of CR register content taken just after we | ||
94 | * leave the transactional state. | ||
95 | */ | ||
96 | uint64_t cr_ = 0; | ||
97 | |||
98 | /* | ||
99 | * Wait a bit so thread can get its name "ping". This is not important | ||
100 | * to reproduce the issue but it's nice to have for systemtap debugging. | ||
101 | */ | ||
102 | if (DEBUG) | ||
103 | sleep(1); | ||
104 | |||
105 | printf("If MSR.FP=%d MSR.VEC=%d: ", flags.touch_fp, flags.touch_vec); | ||
106 | |||
107 | if (flags.exception != FP_UNA_EXCEPTION && | ||
108 | flags.exception != VEC_UNA_EXCEPTION && | ||
109 | flags.exception != VSX_UNA_EXCEPTION) { | ||
110 | printf("No valid exception specified to test.\n"); | ||
111 | return NULL; | ||
112 | } | ||
113 | |||
114 | asm ( | ||
115 | /* Prepare to merge low and high. */ | ||
116 | " mtvsrd 33, %[high_vs0] ;" | ||
117 | " mtvsrd 34, %[low_vs0] ;" | ||
118 | |||
119 | /* | ||
120 | * Adjust VS0 expected value after an TM failure, | ||
121 | * i.e. vs0 = 0x5555555555555555555FFFFFFFFFFFFFFFF | ||
122 | */ | ||
123 | " xxmrghd 0, 33, 34 ;" | ||
124 | |||
125 | /* | ||
126 | * Adjust VS32 expected value after an TM failure, | ||
127 | * i.e. vs32 = 0x5555555555555555555FFFFFFFFFFFFFFFF | ||
128 | */ | ||
129 | " xxmrghd 32, 33, 34 ;" | ||
130 | |||
131 | /* | ||
132 | * Wait an amount of context switches so load_fp and load_vec | ||
133 | * overflow and MSR.FP, MSR.VEC, and MSR.VSX become zero (off). | ||
134 | */ | ||
135 | " mtctr %[counter] ;" | ||
136 | |||
137 | /* Decrement CTR branch if CTR non zero. */ | ||
138 | "1: bdnz 1b ;" | ||
139 | |||
140 | /* | ||
141 | * Check if we want to touch FP prior to the test in order | ||
142 | * to set MSR.FP = 1 before provoking an unavailable | ||
143 | * exception in TM. | ||
144 | */ | ||
145 | " cmpldi %[touch_fp], 0 ;" | ||
146 | " beq no_fp ;" | ||
147 | " fadd 10, 10, 10 ;" | ||
148 | "no_fp: ;" | ||
149 | |||
150 | /* | ||
151 | * Check if we want to touch VEC prior to the test in order | ||
152 | * to set MSR.VEC = 1 before provoking an unavailable | ||
153 | * exception in TM. | ||
154 | */ | ||
155 | " cmpldi %[touch_vec], 0 ;" | ||
156 | " beq no_vec ;" | ||
157 | " vaddcuw 10, 10, 10 ;" | ||
158 | "no_vec: ;" | ||
159 | |||
160 | /* | ||
161 | * Perhaps it would be a better idea to do the | ||
162 | * compares outside transactional context and simply | ||
163 | * duplicate code. | ||
164 | */ | ||
165 | " tbegin. ;" | ||
166 | " beq trans_fail ;" | ||
167 | |||
168 | /* Do we do FP Unavailable? */ | ||
169 | " cmpldi %[exception], %[ex_fp] ;" | ||
170 | " bne 1f ;" | ||
171 | " fadd 10, 10, 10 ;" | ||
172 | " b done ;" | ||
173 | |||
174 | /* Do we do VEC Unavailable? */ | ||
175 | "1: cmpldi %[exception], %[ex_vec] ;" | ||
176 | " bne 2f ;" | ||
177 | " vaddcuw 10, 10, 10 ;" | ||
178 | " b done ;" | ||
179 | |||
180 | /* | ||
181 | * Not FP or VEC, therefore VSX. Ensure this | ||
182 | * instruction always generates a VSX Unavailable. | ||
183 | * ISA 3.0 is tricky here. | ||
184 | * (xxmrghd will on ISA 2.07 and ISA 3.0) | ||
185 | */ | ||
186 | "2: xxmrghd 10, 10, 10 ;" | ||
187 | |||
188 | "done: tend. ;" | ||
189 | |||
190 | "trans_fail: ;" | ||
191 | |||
192 | /* Give values back to C. */ | ||
193 | " mfvsrd %[high_vs0], 0 ;" | ||
194 | " xxsldwi 3, 0, 0, 2 ;" | ||
195 | " mfvsrd %[low_vs0], 3 ;" | ||
196 | " mfvsrd %[high_vs32], 32 ;" | ||
197 | " xxsldwi 3, 32, 32, 2 ;" | ||
198 | " mfvsrd %[low_vs32], 3 ;" | ||
199 | |||
200 | /* Give CR back to C so that it can check what happened. */ | ||
201 | " mfcr %[cr_] ;" | ||
202 | |||
203 | : [high_vs0] "+r" (high_vs0), | ||
204 | [low_vs0] "+r" (low_vs0), | ||
205 | [high_vs32] "=r" (high_vs32), | ||
206 | [low_vs32] "=r" (low_vs32), | ||
207 | [cr_] "+r" (cr_) | ||
208 | : [touch_fp] "r" (flags.touch_fp), | ||
209 | [touch_vec] "r" (flags.touch_vec), | ||
210 | [exception] "r" (flags.exception), | ||
211 | [ex_fp] "i" (FP_UNA_EXCEPTION), | ||
212 | [ex_vec] "i" (VEC_UNA_EXCEPTION), | ||
213 | [ex_vsx] "i" (VSX_UNA_EXCEPTION), | ||
214 | [counter] "r" (counter) | ||
215 | |||
216 | : "cr0", "ctr", "v10", "vs0", "vs10", "vs3", "vs32", "vs33", | ||
217 | "vs34", "fr10" | ||
218 | |||
219 | ); | ||
220 | |||
221 | /* | ||
222 | * Check if we were expecting a failure and it did not occur by checking | ||
223 | * CR0 state just after we leave the transaction. Either way we check if | ||
224 | * vs0 or vs32 got corrupted. | ||
225 | */ | ||
226 | if (expecting_failure() && !is_failure(cr_)) { | ||
227 | printf("\n\tExpecting the transaction to fail, %s", | ||
228 | "but it didn't\n\t"); | ||
229 | flags.result++; | ||
230 | } | ||
231 | |||
232 | /* Check if we were not expecting a failure and a it occurred. */ | ||
233 | if (!expecting_failure() && is_failure(cr_)) { | ||
234 | printf("\n\tUnexpected transaction failure 0x%02lx\n\t", | ||
235 | failure_code()); | ||
236 | return (void *) -1; | ||
237 | } | ||
238 | |||
239 | /* | ||
240 | * Check if TM failed due to the cause we were expecting. 0xda is a | ||
241 | * TM_CAUSE_FAC_UNAV cause, otherwise it's an unexpected cause. | ||
242 | */ | ||
243 | if (is_failure(cr_) && !failure_is_unavailable()) { | ||
244 | printf("\n\tUnexpected failure cause 0x%02lx\n\t", | ||
245 | failure_code()); | ||
246 | return (void *) -1; | ||
247 | } | ||
248 | |||
249 | /* 0x4 is a success and 0xa is a fail. See comment in is_failure(). */ | ||
250 | if (DEBUG) | ||
251 | printf("CR0: 0x%1lx ", cr_ >> 28); | ||
252 | |||
253 | /* Check FP (vs0) for the expected value. */ | ||
254 | if (high_vs0 != 0x5555555555555555 || low_vs0 != 0xFFFFFFFFFFFFFFFF) { | ||
255 | printf("FP corrupted!"); | ||
256 | printf(" high = %#16" PRIx64 " low = %#16" PRIx64 " ", | ||
257 | high_vs0, low_vs0); | ||
258 | flags.result++; | ||
259 | } else | ||
260 | printf("FP ok "); | ||
261 | |||
262 | /* Check VEC (vs32) for the expected value. */ | ||
263 | if (high_vs32 != 0x5555555555555555 || low_vs32 != 0xFFFFFFFFFFFFFFFF) { | ||
264 | printf("VEC corrupted!"); | ||
265 | printf(" high = %#16" PRIx64 " low = %#16" PRIx64, | ||
266 | high_vs32, low_vs32); | ||
267 | flags.result++; | ||
268 | } else | ||
269 | printf("VEC ok"); | ||
270 | |||
271 | putchar('\n'); | ||
272 | |||
273 | return NULL; | ||
274 | } | ||
275 | |||
276 | /* Thread to force context switch */ | ||
277 | void *pong(void *not_used) | ||
278 | { | ||
279 | /* Wait thread get its name "pong". */ | ||
280 | if (DEBUG) | ||
281 | sleep(1); | ||
282 | |||
283 | /* Classed as an interactive-like thread. */ | ||
284 | while (1) | ||
285 | sched_yield(); | ||
286 | } | ||
287 | |||
288 | /* Function that creates a thread and launches the "ping" task. */ | ||
289 | void test_fp_vec(int fp, int vec, pthread_attr_t *attr) | ||
290 | { | ||
291 | int retries = 2; | ||
292 | void *ret_value; | ||
293 | pthread_t t0; | ||
294 | |||
295 | flags.touch_fp = fp; | ||
296 | flags.touch_vec = vec; | ||
297 | |||
298 | /* | ||
299 | * Without luck it's possible that the transaction is aborted not due to | ||
300 | * the unavailable exception caught in the middle as we expect but also, | ||
301 | * for instance, due to a context switch or due to a KVM reschedule (if | ||
302 | * it's running on a VM). Thus we try a few times before giving up, | ||
303 | * checking if the failure cause is the one we expect. | ||
304 | */ | ||
305 | do { | ||
306 | /* Bind 'ping' to CPU 0, as specified in 'attr'. */ | ||
307 | pthread_create(&t0, attr, ping, (void *) &flags); | ||
308 | pthread_setname_np(t0, "ping"); | ||
309 | pthread_join(t0, &ret_value); | ||
310 | retries--; | ||
311 | } while (ret_value != NULL && retries); | ||
312 | |||
313 | if (!retries) { | ||
314 | flags.result = 1; | ||
315 | if (DEBUG) | ||
316 | printf("All transactions failed unexpectedly\n"); | ||
317 | |||
318 | } | ||
319 | } | ||
320 | |||
321 | int main(int argc, char **argv) | ||
322 | { | ||
323 | int exception; /* FP = 0, VEC = 1, VSX = 2 */ | ||
324 | pthread_t t1; | ||
325 | pthread_attr_t attr; | ||
326 | cpu_set_t cpuset; | ||
327 | |||
328 | /* Set only CPU 0 in the mask. Both threads will be bound to CPU 0. */ | ||
329 | CPU_ZERO(&cpuset); | ||
330 | CPU_SET(0, &cpuset); | ||
331 | |||
332 | /* Init pthread attribute. */ | ||
333 | pthread_attr_init(&attr); | ||
334 | |||
335 | /* Set CPU 0 mask into the pthread attribute. */ | ||
336 | pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset); | ||
337 | |||
338 | pthread_create(&t1, &attr /* Bind 'pong' to CPU 0 */, pong, NULL); | ||
339 | pthread_setname_np(t1, "pong"); /* Name it for systemtap convenience */ | ||
340 | |||
341 | flags.result = 0; | ||
342 | |||
343 | for (exception = 0; exception < NUM_EXCEPTIONS; exception++) { | ||
344 | printf("Checking if FP/VEC registers are sane after"); | ||
345 | |||
346 | if (exception == FP_UNA_EXCEPTION) | ||
347 | printf(" a FP unavailable exception...\n"); | ||
348 | |||
349 | else if (exception == VEC_UNA_EXCEPTION) | ||
350 | printf(" a VEC unavailable exception...\n"); | ||
351 | |||
352 | else | ||
353 | printf(" a VSX unavailable exception...\n"); | ||
354 | |||
355 | flags.exception = exception; | ||
356 | |||
357 | test_fp_vec(0, 0, &attr); | ||
358 | test_fp_vec(1, 0, &attr); | ||
359 | test_fp_vec(0, 1, &attr); | ||
360 | test_fp_vec(1, 1, &attr); | ||
361 | |||
362 | } | ||
363 | |||
364 | if (flags.result > 0) { | ||
365 | printf("result: failed!\n"); | ||
366 | exit(1); | ||
367 | } else { | ||
368 | printf("result: success\n"); | ||
369 | exit(0); | ||
370 | } | ||
371 | } | ||
diff --git a/tools/testing/selftests/powerpc/tm/tm.h b/tools/testing/selftests/powerpc/tm/tm.h index 0ffff04433c5..df4204247d45 100644 --- a/tools/testing/selftests/powerpc/tm/tm.h +++ b/tools/testing/selftests/powerpc/tm/tm.h | |||
@@ -47,6 +47,11 @@ static inline bool failure_is_syscall(void) | |||
47 | return (failure_code() & TM_CAUSE_SYSCALL) == TM_CAUSE_SYSCALL; | 47 | return (failure_code() & TM_CAUSE_SYSCALL) == TM_CAUSE_SYSCALL; |
48 | } | 48 | } |
49 | 49 | ||
50 | static inline bool failure_is_unavailable(void) | ||
51 | { | ||
52 | return (failure_code() & TM_CAUSE_FAC_UNAV) == TM_CAUSE_FAC_UNAV; | ||
53 | } | ||
54 | |||
50 | static inline bool failure_is_nesting(void) | 55 | static inline bool failure_is_nesting(void) |
51 | { | 56 | { |
52 | return (__builtin_get_texasru() & 0x400000); | 57 | return (__builtin_get_texasru() & 0x400000); |
diff --git a/tools/testing/selftests/seccomp/.gitignore b/tools/testing/selftests/seccomp/.gitignore index 346d83ca8069..5af29d3a1b0a 100644 --- a/tools/testing/selftests/seccomp/.gitignore +++ b/tools/testing/selftests/seccomp/.gitignore | |||
@@ -1 +1,2 @@ | |||
1 | seccomp_bpf | 1 | seccomp_bpf |
2 | seccomp_benchmark | ||
diff --git a/tools/testing/selftests/tc-testing/.gitignore b/tools/testing/selftests/tc-testing/.gitignore index c18dd8d83cee..7a60b85e148f 100644 --- a/tools/testing/selftests/tc-testing/.gitignore +++ b/tools/testing/selftests/tc-testing/.gitignore | |||
@@ -1 +1,2 @@ | |||
1 | __pycache__/ | 1 | __pycache__/ |
2 | *.pyc | ||
diff --git a/tools/testing/selftests/tc-testing/creating-testcases/AddingTestCases.txt b/tools/testing/selftests/tc-testing/creating-testcases/AddingTestCases.txt index 4e09257bc443..00438331ba47 100644 --- a/tools/testing/selftests/tc-testing/creating-testcases/AddingTestCases.txt +++ b/tools/testing/selftests/tc-testing/creating-testcases/AddingTestCases.txt | |||
@@ -34,6 +34,12 @@ category: A list of single-word descriptions covering what the command | |||
34 | setup: The list of commands required to ensure the command under test | 34 | setup: The list of commands required to ensure the command under test |
35 | succeeds. For example: if testing a filter, the command to create | 35 | succeeds. For example: if testing a filter, the command to create |
36 | the qdisc would appear here. | 36 | the qdisc would appear here. |
37 | This list can be empty. | ||
38 | Each command can be a string to be executed, or a list consisting | ||
39 | of a string which is a command to be executed, followed by 1 or | ||
40 | more acceptable exit codes for this command. | ||
41 | If only a string is given for the command, then an exit code of 0 | ||
42 | will be expected. | ||
37 | cmdUnderTest: The tc command being tested itself. | 43 | cmdUnderTest: The tc command being tested itself. |
38 | expExitCode: The code returned by the command under test upon its termination. | 44 | expExitCode: The code returned by the command under test upon its termination. |
39 | tdc will compare this value against the actual returned value. | 45 | tdc will compare this value against the actual returned value. |
@@ -49,6 +55,12 @@ matchCount: How many times the regex in matchPattern should match. A value | |||
49 | teardown: The list of commands to clean up after the test is completed. | 55 | teardown: The list of commands to clean up after the test is completed. |
50 | The environment should be returned to the same state as when | 56 | The environment should be returned to the same state as when |
51 | this test was started: qdiscs deleted, actions flushed, etc. | 57 | this test was started: qdiscs deleted, actions flushed, etc. |
58 | This list can be empty. | ||
59 | Each command can be a string to be executed, or a list consisting | ||
60 | of a string which is a command to be executed, followed by 1 or | ||
61 | more acceptable exit codes for this command. | ||
62 | If only a string is given for the command, then an exit code of 0 | ||
63 | will be expected. | ||
52 | 64 | ||
53 | 65 | ||
54 | SETUP/TEARDOWN ERRORS | 66 | SETUP/TEARDOWN ERRORS |
diff --git a/tools/testing/selftests/tc-testing/creating-testcases/example.json b/tools/testing/selftests/tc-testing/creating-testcases/example.json new file mode 100644 index 000000000000..5ec501200970 --- /dev/null +++ b/tools/testing/selftests/tc-testing/creating-testcases/example.json | |||
@@ -0,0 +1,55 @@ | |||
1 | [ | ||
2 | { | ||
3 | "id": "1f", | ||
4 | "name": "simple test to test framework", | ||
5 | "category": [ | ||
6 | "example" | ||
7 | ], | ||
8 | "setup": [ | ||
9 | "mkdir mytest" | ||
10 | ], | ||
11 | "cmdUnderTest": "touch mytest/blorfl", | ||
12 | "expExitCode": "0", | ||
13 | "verifyCmd": "ls mytest/* | grep '[b]lorfl'", | ||
14 | "matchPattern": "orfl", | ||
15 | "matchCount": "1", | ||
16 | "teardown": [ | ||
17 | "rm -rf mytest" | ||
18 | ] | ||
19 | }, | ||
20 | { | ||
21 | "id": "2f", | ||
22 | "name": "simple test, no need for verify", | ||
23 | "category": [ | ||
24 | "example" | ||
25 | ], | ||
26 | "setup": [ | ||
27 | "mkdir mytest", | ||
28 | "touch mytest/blorfl" | ||
29 | ], | ||
30 | "cmdUnderTest": "ls mytest/blorfl", | ||
31 | "expExitCode": "0", | ||
32 | "verifyCmd": "/bin/true", | ||
33 | "matchPattern": " ", | ||
34 | "matchCount": "0", | ||
35 | "teardown": [ | ||
36 | "rm -rf mytest" | ||
37 | ] | ||
38 | }, | ||
39 | { | ||
40 | "id": "3f", | ||
41 | "name": "simple test, no need for setup or teardown (or verify)", | ||
42 | "category": [ | ||
43 | "example" | ||
44 | ], | ||
45 | "setup": [ | ||
46 | ], | ||
47 | "cmdUnderTest": "ip l l lo", | ||
48 | "expExitCode": "0", | ||
49 | "verifyCmd": "/bin/true", | ||
50 | "matchPattern": " ", | ||
51 | "matchCount": "0", | ||
52 | "teardown": [ | ||
53 | ] | ||
54 | } | ||
55 | ] | ||
diff --git a/tools/testing/selftests/tc-testing/creating-testcases/template.json b/tools/testing/selftests/tc-testing/creating-testcases/template.json index 87971744bdd4..8b99b86d65bd 100644 --- a/tools/testing/selftests/tc-testing/creating-testcases/template.json +++ b/tools/testing/selftests/tc-testing/creating-testcases/template.json | |||
@@ -26,7 +26,13 @@ | |||
26 | "" | 26 | "" |
27 | ], | 27 | ], |
28 | "setup": [ | 28 | "setup": [ |
29 | "" | 29 | "", |
30 | [ | ||
31 | "", | ||
32 | 0, | ||
33 | 1, | ||
34 | 255 | ||
35 | ] | ||
30 | ], | 36 | ], |
31 | "cmdUnderTest": "", | 37 | "cmdUnderTest": "", |
32 | "expExitCode": "", | 38 | "expExitCode": "", |
@@ -34,7 +40,12 @@ | |||
34 | "matchPattern": "", | 40 | "matchPattern": "", |
35 | "matchCount": "", | 41 | "matchCount": "", |
36 | "teardown": [ | 42 | "teardown": [ |
37 | "" | 43 | "", |
44 | [ | ||
45 | "", | ||
46 | 0, | ||
47 | 255 | ||
48 | ] | ||
38 | ] | 49 | ] |
39 | } | 50 | } |
40 | ] | 51 | ] |
diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/gact.json b/tools/testing/selftests/tc-testing/tc-tests/actions/gact.json new file mode 100644 index 000000000000..e2187b6e0b7a --- /dev/null +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/gact.json | |||
@@ -0,0 +1,469 @@ | |||
1 | [ | ||
2 | { | ||
3 | "id": "e89a", | ||
4 | "name": "Add valid pass action", | ||
5 | "category": [ | ||
6 | "actions", | ||
7 | "gact" | ||
8 | ], | ||
9 | "setup": [ | ||
10 | [ | ||
11 | "$TC actions flush action gact", | ||
12 | 0, | ||
13 | 1, | ||
14 | 255 | ||
15 | ] | ||
16 | ], | ||
17 | "cmdUnderTest": "$TC actions add action pass index 8", | ||
18 | "expExitCode": "0", | ||
19 | "verifyCmd": "$TC actions list action gact", | ||
20 | "matchPattern": "action order [0-9]*: gact action pass.*index 8 ref", | ||
21 | "matchCount": "1", | ||
22 | "teardown": [ | ||
23 | "$TC actions flush action gact" | ||
24 | ] | ||
25 | }, | ||
26 | { | ||
27 | "id": "a02c", | ||
28 | "name": "Add valid pipe action", | ||
29 | "category": [ | ||
30 | "actions", | ||
31 | "gact" | ||
32 | ], | ||
33 | "setup": [ | ||
34 | [ | ||
35 | "$TC actions flush action gact", | ||
36 | 0, | ||
37 | 1, | ||
38 | 255 | ||
39 | ] | ||
40 | ], | ||
41 | "cmdUnderTest": "$TC actions add action pipe index 6", | ||
42 | "expExitCode": "0", | ||
43 | "verifyCmd": "$TC actions list action gact", | ||
44 | "matchPattern": "action order [0-9]*: gact action pipe.*index 6 ref", | ||
45 | "matchCount": "1", | ||
46 | "teardown": [ | ||
47 | "$TC actions flush action gact" | ||
48 | ] | ||
49 | }, | ||
50 | { | ||
51 | "id": "feef", | ||
52 | "name": "Add valid reclassify action", | ||
53 | "category": [ | ||
54 | "actions", | ||
55 | "gact" | ||
56 | ], | ||
57 | "setup": [ | ||
58 | [ | ||
59 | "$TC actions flush action gact", | ||
60 | 0, | ||
61 | 1, | ||
62 | 255 | ||
63 | ] | ||
64 | ], | ||
65 | "cmdUnderTest": "$TC actions add action reclassify index 5", | ||
66 | "expExitCode": "0", | ||
67 | "verifyCmd": "$TC actions list action gact", | ||
68 | "matchPattern": "action order [0-9]*: gact action reclassify.*index 5 ref", | ||
69 | "matchCount": "1", | ||
70 | "teardown": [ | ||
71 | "$TC actions flush action gact" | ||
72 | ] | ||
73 | }, | ||
74 | { | ||
75 | "id": "8a7a", | ||
76 | "name": "Add valid drop action", | ||
77 | "category": [ | ||
78 | "actions", | ||
79 | "gact" | ||
80 | ], | ||
81 | "setup": [ | ||
82 | [ | ||
83 | "$TC actions flush action gact", | ||
84 | 0, | ||
85 | 1, | ||
86 | 255 | ||
87 | ] | ||
88 | ], | ||
89 | "cmdUnderTest": "$TC actions add action drop index 30", | ||
90 | "expExitCode": "0", | ||
91 | "verifyCmd": "$TC actions list action gact", | ||
92 | "matchPattern": "action order [0-9]*: gact action drop.*index 30 ref", | ||
93 | "matchCount": "1", | ||
94 | "teardown": [ | ||
95 | "$TC actions flush action gact" | ||
96 | ] | ||
97 | }, | ||
98 | { | ||
99 | "id": "9a52", | ||
100 | "name": "Add valid continue action", | ||
101 | "category": [ | ||
102 | "actions", | ||
103 | "gact" | ||
104 | ], | ||
105 | "setup": [ | ||
106 | [ | ||
107 | "$TC actions flush action gact", | ||
108 | 0, | ||
109 | 1, | ||
110 | 255 | ||
111 | ] | ||
112 | ], | ||
113 | "cmdUnderTest": "$TC actions add action continue index 432", | ||
114 | "expExitCode": "0", | ||
115 | "verifyCmd": "$TC actions list action gact", | ||
116 | "matchPattern": "action order [0-9]*: gact action continue.*index 432 ref", | ||
117 | "matchCount": "1", | ||
118 | "teardown": [ | ||
119 | "$TC actions flush action gact" | ||
120 | ] | ||
121 | }, | ||
122 | { | ||
123 | "id": "d700", | ||
124 | "name": "Add invalid action", | ||
125 | "category": [ | ||
126 | "actions", | ||
127 | "gact" | ||
128 | ], | ||
129 | "setup": [ | ||
130 | [ | ||
131 | "$TC actions flush action gact", | ||
132 | 0, | ||
133 | 1, | ||
134 | 255 | ||
135 | ] | ||
136 | ], | ||
137 | "cmdUnderTest": "$TC actions add action pump index 386", | ||
138 | "expExitCode": "255", | ||
139 | "verifyCmd": "$TC actions list action gact", | ||
140 | "matchPattern": "action order [0-9]*: gact action.*index 386 ref", | ||
141 | "matchCount": "0", | ||
142 | "teardown": [ | ||
143 | "$TC actions flush action gact" | ||
144 | ] | ||
145 | }, | ||
146 | { | ||
147 | "id": "9215", | ||
148 | "name": "Add action with duplicate index", | ||
149 | "category": [ | ||
150 | "actions", | ||
151 | "gact" | ||
152 | ], | ||
153 | "setup": [ | ||
154 | [ | ||
155 | "$TC actions flush action gact", | ||
156 | 0, | ||
157 | 1, | ||
158 | 255 | ||
159 | ], | ||
160 | "$TC actions add action pipe index 15" | ||
161 | ], | ||
162 | "cmdUnderTest": "$TC actions add action drop index 15", | ||
163 | "expExitCode": "255", | ||
164 | "verifyCmd": "$TC actions list action gact", | ||
165 | "matchPattern": "action order [0-9]*: gact action drop.*index 15 ref", | ||
166 | "matchCount": "0", | ||
167 | "teardown": [ | ||
168 | "$TC actions flush action gact" | ||
169 | ] | ||
170 | }, | ||
171 | { | ||
172 | "id": "798e", | ||
173 | "name": "Add action with index exceeding 32-bit maximum", | ||
174 | "category": [ | ||
175 | "actions", | ||
176 | "gact" | ||
177 | ], | ||
178 | "setup": [ | ||
179 | [ | ||
180 | "$TC actions flush action gact", | ||
181 | 0, | ||
182 | 1, | ||
183 | 255 | ||
184 | ] | ||
185 | ], | ||
186 | "cmdUnderTest": "$TC actions add action drop index 4294967296", | ||
187 | "expExitCode": "255", | ||
188 | "verifyCmd": "actions list action gact", | ||
189 | "matchPattern": "action order [0-9]*: gact action drop.*index 4294967296 ref", | ||
190 | "matchCount": "0", | ||
191 | "teardown": [ | ||
192 | "$TC actions flush action gact" | ||
193 | ] | ||
194 | }, | ||
195 | { | ||
196 | "id": "22be", | ||
197 | "name": "Add action with index at 32-bit maximum", | ||
198 | "category": [ | ||
199 | "actions", | ||
200 | "gact" | ||
201 | ], | ||
202 | "setup": [ | ||
203 | [ | ||
204 | "$TC actions flush action gact", | ||
205 | 0, | ||
206 | 1, | ||
207 | 255 | ||
208 | ] | ||
209 | ], | ||
210 | "cmdUnderTest": "$TC actions add action drop index 4294967295", | ||
211 | "expExitCode": "0", | ||
212 | "verifyCmd": "$TC actions list action gact", | ||
213 | "matchPattern": "action order [0-9]*: gact action drop.*index 4294967295 ref", | ||
214 | "matchCount": "1", | ||
215 | "teardown": [ | ||
216 | "$TC actions flush action gact" | ||
217 | ] | ||
218 | }, | ||
219 | { | ||
220 | "id": "ac2a", | ||
221 | "name": "List actions", | ||
222 | "category": [ | ||
223 | "actions", | ||
224 | "gact" | ||
225 | ], | ||
226 | "setup": [ | ||
227 | [ | ||
228 | "$TC actions flush action gact", | ||
229 | 0, | ||
230 | 1, | ||
231 | 255 | ||
232 | ], | ||
233 | "$TC actions add action reclassify index 101", | ||
234 | "$TC actions add action reclassify index 102", | ||
235 | "$TC actions add action reclassify index 103", | ||
236 | "$TC actions add action reclassify index 104", | ||
237 | "$TC actions add action reclassify index 105" | ||
238 | ], | ||
239 | "cmdUnderTest": "$TC actions list action gact", | ||
240 | "expExitCode": "0", | ||
241 | "verifyCmd": "$TC actions list action gact", | ||
242 | "matchPattern": "action order [0-9]*: gact action reclassify", | ||
243 | "matchCount": "5", | ||
244 | "teardown": [ | ||
245 | "$TC actions flush action gact" | ||
246 | ] | ||
247 | }, | ||
248 | { | ||
249 | "id": "3edf", | ||
250 | "name": "Flush gact actions", | ||
251 | "category": [ | ||
252 | "actions", | ||
253 | "gact" | ||
254 | ], | ||
255 | "setup": [ | ||
256 | "$TC actions add action reclassify index 101", | ||
257 | "$TC actions add action reclassify index 102", | ||
258 | "$TC actions add action reclassify index 103", | ||
259 | "$TC actions add action reclassify index 104", | ||
260 | "$TC actions add action reclassify index 105" | ||
261 | ], | ||
262 | "cmdUnderTest": "$TC actions flush action gact", | ||
263 | "expExitCode": "0", | ||
264 | "verifyCmd": "$TC actions list action gact", | ||
265 | "matchPattern": "action order [0-9]*: gact action reclassify", | ||
266 | "matchCount": "0", | ||
267 | "teardown": [] | ||
268 | }, | ||
269 | { | ||
270 | "id": "63ec", | ||
271 | "name": "Delete pass action", | ||
272 | "category": [ | ||
273 | "actions", | ||
274 | "gact" | ||
275 | ], | ||
276 | "setup": [ | ||
277 | [ | ||
278 | "$TC actions flush action gact", | ||
279 | 0, | ||
280 | 1, | ||
281 | 255 | ||
282 | ], | ||
283 | "$TC actions add action pass index 1" | ||
284 | ], | ||
285 | "cmdUnderTest": "$TC actions del action gact index 1", | ||
286 | "expExitCode": "0", | ||
287 | "verifyCmd": "$TC actions list action gact", | ||
288 | "matchPattern": "action order [0-9]*: gact action pass.*index 1 ref", | ||
289 | "matchCount": "0", | ||
290 | "teardown": [ | ||
291 | "$TC actions flush action gact" | ||
292 | ] | ||
293 | }, | ||
294 | { | ||
295 | "id": "46be", | ||
296 | "name": "Delete pipe action", | ||
297 | "category": [ | ||
298 | "actions", | ||
299 | "gact" | ||
300 | ], | ||
301 | "setup": [ | ||
302 | [ | ||
303 | "$TC actions flush action gact", | ||
304 | 0, | ||
305 | 1, | ||
306 | 255 | ||
307 | ], | ||
308 | "$TC actions add action pipe index 9" | ||
309 | ], | ||
310 | "cmdUnderTest": "$TC actions del action gact index 9", | ||
311 | "expExitCode": "0", | ||
312 | "verifyCmd": "$TC actions list action gact", | ||
313 | "matchPattern": "action order [0-9]*: gact action pipe.*index 9 ref", | ||
314 | "matchCount": "0", | ||
315 | "teardown": [ | ||
316 | "$TC actions flush action gact" | ||
317 | ] | ||
318 | }, | ||
319 | { | ||
320 | "id": "2e08", | ||
321 | "name": "Delete reclassify action", | ||
322 | "category": [ | ||
323 | "actions", | ||
324 | "gact" | ||
325 | ], | ||
326 | "setup": [ | ||
327 | [ | ||
328 | "$TC actions flush action gact", | ||
329 | 0, | ||
330 | 1, | ||
331 | 255 | ||
332 | ], | ||
333 | "$TC actions add action reclassify index 65536" | ||
334 | ], | ||
335 | "cmdUnderTest": "$TC actions del action gact index 65536", | ||
336 | "expExitCode": "0", | ||
337 | "verifyCmd": "$TC actions list action gact", | ||
338 | "matchPattern": "action order [0-9]*: gact action reclassify.*index 65536 ref", | ||
339 | "matchCount": "0", | ||
340 | "teardown": [ | ||
341 | "$TC actions flush action gact" | ||
342 | ] | ||
343 | }, | ||
344 | { | ||
345 | "id": "99c4", | ||
346 | "name": "Delete drop action", | ||
347 | "category": [ | ||
348 | "actions", | ||
349 | "gact" | ||
350 | ], | ||
351 | "setup": [ | ||
352 | [ | ||
353 | "$TC actions flush action gact", | ||
354 | 0, | ||
355 | 1, | ||
356 | 255 | ||
357 | ], | ||
358 | "$TC actions add action drop index 16" | ||
359 | ], | ||
360 | "cmdUnderTest": "$TC actions del action gact index 16", | ||
361 | "expExitCode": "0", | ||
362 | "verifyCmd": "$TC actions list action gact", | ||
363 | "matchPattern": "action order [0-9]*: gact action drop.*index 16 ref", | ||
364 | "matchCount": "0", | ||
365 | "teardown": [ | ||
366 | "$TC actions flush action gact" | ||
367 | ] | ||
368 | }, | ||
369 | { | ||
370 | "id": "fb6b", | ||
371 | "name": "Delete continue action", | ||
372 | "category": [ | ||
373 | "actions", | ||
374 | "gact" | ||
375 | ], | ||
376 | "setup": [ | ||
377 | [ | ||
378 | "$TC actions flush action gact", | ||
379 | 0, | ||
380 | 1, | ||
381 | 255 | ||
382 | ], | ||
383 | "$TC actions add action continue index 32" | ||
384 | ], | ||
385 | "cmdUnderTest": "$TC actions del action gact index 32", | ||
386 | "expExitCode": "0", | ||
387 | "verifyCmd": "actions list action gact", | ||
388 | "matchPattern": "action order [0-9]*: gact action continue.*index 32 ref", | ||
389 | "matchCount": "0", | ||
390 | "teardown": [ | ||
391 | "$TC actions flush action gact" | ||
392 | ] | ||
393 | }, | ||
394 | { | ||
395 | "id": "0eb3", | ||
396 | "name": "Delete non-existent action", | ||
397 | "category": [ | ||
398 | "actions", | ||
399 | "gact" | ||
400 | ], | ||
401 | "setup": [ | ||
402 | [ | ||
403 | "$TC actions flush action gact", | ||
404 | 0, | ||
405 | 1, | ||
406 | 255 | ||
407 | ] | ||
408 | ], | ||
409 | "cmdUnderTest": "$TC actions del action gact index 2", | ||
410 | "expExitCode": "255", | ||
411 | "verifyCmd": "$TC actions list action gact", | ||
412 | "matchPattern": "action order [0-9]*: gact action", | ||
413 | "matchCount": "0", | ||
414 | "teardown": [ | ||
415 | "$TC actions flush action gact" | ||
416 | ] | ||
417 | }, | ||
418 | { | ||
419 | "id": "f02c", | ||
420 | "name": "Replace gact action", | ||
421 | "category": [ | ||
422 | "actions", | ||
423 | "gact" | ||
424 | ], | ||
425 | "setup": [ | ||
426 | [ | ||
427 | "$TC actions flush action gact", | ||
428 | 0, | ||
429 | 1, | ||
430 | 255 | ||
431 | ], | ||
432 | "$TC actions add action drop index 10", | ||
433 | "$TC actions add action drop index 12" | ||
434 | ], | ||
435 | "cmdUnderTest": "$TC actions replace action ok index 12", | ||
436 | "expExitCode": "0", | ||
437 | "verifyCmd": "$TC actions ls action gact", | ||
438 | "matchPattern": "action order [0-9]*: gact action pass", | ||
439 | "matchCount": "1", | ||
440 | "teardown": [ | ||
441 | "$TC actions flush action gact" | ||
442 | ] | ||
443 | }, | ||
444 | { | ||
445 | "id": "525f", | ||
446 | "name": "Get gact action by index", | ||
447 | "category": [ | ||
448 | "actions", | ||
449 | "gact" | ||
450 | ], | ||
451 | "setup": [ | ||
452 | [ | ||
453 | "$TC actions flush action gact", | ||
454 | 0, | ||
455 | 1, | ||
456 | 255 | ||
457 | ], | ||
458 | "$TC actions add action drop index 3900800700" | ||
459 | ], | ||
460 | "cmdUnderTest": "$TC actions get action gact index 3900800700", | ||
461 | "expExitCode": "0", | ||
462 | "verifyCmd": "$TC actions get action gact index 3900800700", | ||
463 | "matchPattern": "index 3900800700", | ||
464 | "matchCount": "1", | ||
465 | "teardown": [ | ||
466 | "$TC actions flush action gact" | ||
467 | ] | ||
468 | } | ||
469 | ] | ||
diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/ife.json b/tools/testing/selftests/tc-testing/tc-tests/actions/ife.json new file mode 100644 index 000000000000..9f34f0753969 --- /dev/null +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/ife.json | |||
@@ -0,0 +1,52 @@ | |||
1 | [ | ||
2 | { | ||
3 | "id": "a568", | ||
4 | "name": "Add action with ife type", | ||
5 | "category": [ | ||
6 | "actions", | ||
7 | "ife" | ||
8 | ], | ||
9 | "setup": [ | ||
10 | [ | ||
11 | "$TC actions flush action ife", | ||
12 | 0, | ||
13 | 1, | ||
14 | 255 | ||
15 | ], | ||
16 | "$TC actions add action ife encode type 0xDEAD index 1" | ||
17 | ], | ||
18 | "cmdUnderTest": "$TC actions get action ife index 1", | ||
19 | "expExitCode": "0", | ||
20 | "verifyCmd": "$TC actions get action ife index 1", | ||
21 | "matchPattern": "type 0xDEAD", | ||
22 | "matchCount": "1", | ||
23 | "teardown": [ | ||
24 | "$TC actions flush action ife" | ||
25 | ] | ||
26 | }, | ||
27 | { | ||
28 | "id": "b983", | ||
29 | "name": "Add action without ife type", | ||
30 | "category": [ | ||
31 | "actions", | ||
32 | "ife" | ||
33 | ], | ||
34 | "setup": [ | ||
35 | [ | ||
36 | "$TC actions flush action ife", | ||
37 | 0, | ||
38 | 1, | ||
39 | 255 | ||
40 | ], | ||
41 | "$TC actions add action ife encode index 1" | ||
42 | ], | ||
43 | "cmdUnderTest": "$TC actions get action ife index 1", | ||
44 | "expExitCode": "0", | ||
45 | "verifyCmd": "$TC actions get action ife index 1", | ||
46 | "matchPattern": "type 0xED3E", | ||
47 | "matchCount": "1", | ||
48 | "teardown": [ | ||
49 | "$TC actions flush action ife" | ||
50 | ] | ||
51 | } | ||
52 | ] | ||
diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/mirred.json b/tools/testing/selftests/tc-testing/tc-tests/actions/mirred.json new file mode 100644 index 000000000000..0fcccf18399b --- /dev/null +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/mirred.json | |||
@@ -0,0 +1,223 @@ | |||
1 | [ | ||
2 | { | ||
3 | "id": "5124", | ||
4 | "name": "Add mirred mirror to egress action", | ||
5 | "category": [ | ||
6 | "actions", | ||
7 | "mirred" | ||
8 | ], | ||
9 | "setup": [ | ||
10 | [ | ||
11 | "$TC actions flush action mirred", | ||
12 | 0, | ||
13 | 1, | ||
14 | 255 | ||
15 | ] | ||
16 | ], | ||
17 | "cmdUnderTest": "$TC actions add action mirred egress mirror index 1 dev lo", | ||
18 | "expExitCode": "0", | ||
19 | "verifyCmd": "$TC actions list action mirred", | ||
20 | "matchPattern": "action order [0-9]*: mirred \\(Egress Mirror to device lo\\).*index 1 ref", | ||
21 | "matchCount": "1", | ||
22 | "teardown": [ | ||
23 | "$TC actions flush action mirred" | ||
24 | ] | ||
25 | }, | ||
26 | { | ||
27 | "id": "6fb4", | ||
28 | "name": "Add mirred redirect to egress action", | ||
29 | "category": [ | ||
30 | "actions", | ||
31 | "mirred" | ||
32 | ], | ||
33 | "setup": [ | ||
34 | [ | ||
35 | "$TC actions flush action mirred", | ||
36 | 0, | ||
37 | 1, | ||
38 | 255 | ||
39 | ] | ||
40 | ], | ||
41 | "cmdUnderTest": "$TC actions add action mirred egress redirect index 2 dev lo action pipe", | ||
42 | "expExitCode": "0", | ||
43 | "verifyCmd": "$TC actions list action mirred", | ||
44 | "matchPattern": "action order [0-9]*: mirred \\(Egress Redirect to device lo\\).*index 2 ref", | ||
45 | "matchCount": "1", | ||
46 | "teardown": [ | ||
47 | "$TC actions flush action mirred" | ||
48 | ] | ||
49 | }, | ||
50 | { | ||
51 | "id": "ba38", | ||
52 | "name": "Get mirred actions", | ||
53 | "category": [ | ||
54 | "actions", | ||
55 | "mirred" | ||
56 | ], | ||
57 | "setup": [ | ||
58 | [ | ||
59 | "$TC actions flush action mirred", | ||
60 | 0, | ||
61 | 1, | ||
62 | 255 | ||
63 | ], | ||
64 | "$TC actions add action mirred egress mirror index 1 dev lo", | ||
65 | "$TC actions add action mirred egress redirect index 2 dev lo" | ||
66 | ], | ||
67 | "cmdUnderTest": "$TC actions show action mirred", | ||
68 | "expExitCode": "0", | ||
69 | "verifyCmd": "$TC actions list action mirred", | ||
70 | "matchPattern": "[Mirror|Redirect] to device lo", | ||
71 | "matchCount": "2", | ||
72 | "teardown": [ | ||
73 | "$TC actions flush action mirred" | ||
74 | ] | ||
75 | }, | ||
76 | { | ||
77 | "id": "d7c0", | ||
78 | "name": "Add invalid mirred direction", | ||
79 | "category": [ | ||
80 | "actions", | ||
81 | "mirred" | ||
82 | ], | ||
83 | "setup": [ | ||
84 | [ | ||
85 | "$TC actions flush action mirred", | ||
86 | 0, | ||
87 | 1, | ||
88 | 255 | ||
89 | ] | ||
90 | ], | ||
91 | "cmdUnderTest": "$TC actions add action mirred inbound mirror index 20 dev lo", | ||
92 | "expExitCode": "255", | ||
93 | "verifyCmd": "$TC actions list action mirred", | ||
94 | "matchPattern": "action order [0-9]*: mirred \\(.*to device lo\\).*index 20 ref", | ||
95 | "matchCount": "0", | ||
96 | "teardown": [ | ||
97 | "$TC actions flush action mirred" | ||
98 | ] | ||
99 | }, | ||
100 | { | ||
101 | "id": "e213", | ||
102 | "name": "Add invalid mirred action", | ||
103 | "category": [ | ||
104 | "actions", | ||
105 | "mirred" | ||
106 | ], | ||
107 | "setup": [ | ||
108 | [ | ||
109 | "$TC actions flush action mirred", | ||
110 | 0, | ||
111 | 1, | ||
112 | 255 | ||
113 | ] | ||
114 | ], | ||
115 | "cmdUnderTest": "$TC actions add action mirred egress remirror index 20 dev lo", | ||
116 | "expExitCode": "255", | ||
117 | "verifyCmd": "$TC actions list action mirred", | ||
118 | "matchPattern": "action order [0-9]*: mirred \\(Egress.*to device lo\\).*index 20 ref", | ||
119 | "matchCount": "0", | ||
120 | "teardown": [ | ||
121 | "$TC actions flush action mirred" | ||
122 | ] | ||
123 | }, | ||
124 | { | ||
125 | "id": "2d89", | ||
126 | "name": "Add mirred action with invalid device", | ||
127 | "category": [ | ||
128 | "actions", | ||
129 | "mirred" | ||
130 | ], | ||
131 | "setup": [ | ||
132 | [ | ||
133 | "$TC actions flush action mirred", | ||
134 | 0, | ||
135 | 1, | ||
136 | 255 | ||
137 | ] | ||
138 | ], | ||
139 | "cmdUnderTest": "$TC actions add action mirred egress mirror index 20 dev eltoh", | ||
140 | "expExitCode": "255", | ||
141 | "verifyCmd": "$TC actions list action mirred", | ||
142 | "matchPattern": "action order [0-9]*: mirred \\(.*to device eltoh\\).*index 20 ref", | ||
143 | "matchCount": "0", | ||
144 | "teardown": [ | ||
145 | "$TC actions flush action mirred" | ||
146 | ] | ||
147 | }, | ||
148 | { | ||
149 | "id": "300b", | ||
150 | "name": "Add mirred action with duplicate index", | ||
151 | "category": [ | ||
152 | "actions", | ||
153 | "mirred" | ||
154 | ], | ||
155 | "setup": [ | ||
156 | [ | ||
157 | "$TC actions flush action mirred", | ||
158 | 0, | ||
159 | 1, | ||
160 | 255 | ||
161 | ], | ||
162 | "$TC actions add action mirred egress redirect index 15 dev lo" | ||
163 | ], | ||
164 | "cmdUnderTest": "$TC actions add action mirred egress mirror index 15 dev lo", | ||
165 | "expExitCode": "255", | ||
166 | "verifyCmd": "$TC actions list action mirred", | ||
167 | "matchPattern": "action order [0-9]*: mirred \\(.*to device lo\\).*index 15 ref", | ||
168 | "matchCount": "1", | ||
169 | "teardown": [ | ||
170 | "$TC actions flush action mirred" | ||
171 | ] | ||
172 | }, | ||
173 | { | ||
174 | "id": "a70e", | ||
175 | "name": "Delete mirred mirror action", | ||
176 | "category": [ | ||
177 | "actions", | ||
178 | "mirred" | ||
179 | ], | ||
180 | "setup": [ | ||
181 | [ | ||
182 | "$TC actions flush action mirred", | ||
183 | 0, | ||
184 | 1, | ||
185 | 255 | ||
186 | ], | ||
187 | "$TC actions add action mirred egress mirror index 5 dev lo" | ||
188 | ], | ||
189 | "cmdUnderTest": "$TC actions del action mirred index 5", | ||
190 | "expExitCode": "0", | ||
191 | "verifyCmd": "$TC actions list action mirred", | ||
192 | "matchPattern": "action order [0-9]*: mirred \\(Egress Mirror to device lo\\).*index 5 ref", | ||
193 | "matchCount": "0", | ||
194 | "teardown": [ | ||
195 | "$TC actions flush action mirred" | ||
196 | ] | ||
197 | }, | ||
198 | { | ||
199 | "id": "3fb3", | ||
200 | "name": "Delete mirred redirect action", | ||
201 | "category": [ | ||
202 | "actions", | ||
203 | "mirred" | ||
204 | ], | ||
205 | "setup": [ | ||
206 | [ | ||
207 | "$TC actions flush action mirred", | ||
208 | 0, | ||
209 | 1, | ||
210 | 255 | ||
211 | ], | ||
212 | "$TC actions add action mirred egress redirect index 5 dev lo" | ||
213 | ], | ||
214 | "cmdUnderTest": "$TC actions del action mirred index 5", | ||
215 | "expExitCode": "0", | ||
216 | "verifyCmd": "$TC actions list action mirred", | ||
217 | "matchPattern": "action order [0-9]*: mirred \\(Egress Redirect to device lo\\).*index 5 ref", | ||
218 | "matchCount": "0", | ||
219 | "teardown": [ | ||
220 | "$TC actions flush action mirred" | ||
221 | ] | ||
222 | } | ||
223 | ] | ||
diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/police.json b/tools/testing/selftests/tc-testing/tc-tests/actions/police.json new file mode 100644 index 000000000000..0e602a3f9393 --- /dev/null +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/police.json | |||
@@ -0,0 +1,527 @@ | |||
1 | [ | ||
2 | { | ||
3 | "id": "49aa", | ||
4 | "name": "Add valid basic police action", | ||
5 | "category": [ | ||
6 | "actions", | ||
7 | "police" | ||
8 | ], | ||
9 | "setup": [ | ||
10 | [ | ||
11 | "$TC actions flush action police", | ||
12 | 0, | ||
13 | 1, | ||
14 | 255 | ||
15 | ] | ||
16 | ], | ||
17 | "cmdUnderTest": "$TC actions add action police rate 1kbit burst 10k index 1", | ||
18 | "expExitCode": "0", | ||
19 | "verifyCmd": "$TC actions ls action police", | ||
20 | "matchPattern": "action order [0-9]*: police 0x1 rate 1Kbit burst 10Kb", | ||
21 | "matchCount": "1", | ||
22 | "teardown": [ | ||
23 | "$TC actions flush action police" | ||
24 | ] | ||
25 | }, | ||
26 | { | ||
27 | "id": "3abe", | ||
28 | "name": "Add police action with duplicate index", | ||
29 | "category": [ | ||
30 | "actions", | ||
31 | "police" | ||
32 | ], | ||
33 | "setup": [ | ||
34 | [ | ||
35 | "$TC actions flush action police", | ||
36 | 0, | ||
37 | 1, | ||
38 | 255 | ||
39 | ], | ||
40 | "$TC actions add action police rate 4Mbit burst 120k index 9" | ||
41 | ], | ||
42 | "cmdUnderTest": "$TC actions add action police rate 8kbit burst 24k index 9", | ||
43 | "expExitCode": "255", | ||
44 | "verifyCmd": "$TC actions ls action police", | ||
45 | "matchPattern": "action order [0-9]*: police 0x9", | ||
46 | "matchCount": "1", | ||
47 | "teardown": [ | ||
48 | "$TC actions flush action police" | ||
49 | ] | ||
50 | }, | ||
51 | { | ||
52 | "id": "49fa", | ||
53 | "name": "Add valid police action with mtu", | ||
54 | "category": [ | ||
55 | "actions", | ||
56 | "police" | ||
57 | ], | ||
58 | "setup": [ | ||
59 | [ | ||
60 | "$TC actions flush action police", | ||
61 | 0, | ||
62 | 1, | ||
63 | 255 | ||
64 | ] | ||
65 | ], | ||
66 | "cmdUnderTest": "$TC actions add action police rate 90kbit burst 10k mtu 1k index 98", | ||
67 | "expExitCode": "0", | ||
68 | "verifyCmd": "$TC actions get action police index 98", | ||
69 | "matchPattern": "action order [0-9]*: police 0x62 rate 90Kbit burst 10Kb mtu 1Kb", | ||
70 | "matchCount": "1", | ||
71 | "teardown": [ | ||
72 | "$TC actions flush action police" | ||
73 | ] | ||
74 | }, | ||
75 | { | ||
76 | "id": "7943", | ||
77 | "name": "Add valid police action with peakrate", | ||
78 | "category": [ | ||
79 | "actions", | ||
80 | "police" | ||
81 | ], | ||
82 | "setup": [ | ||
83 | [ | ||
84 | "$TC actions flush action police", | ||
85 | 0, | ||
86 | 1, | ||
87 | 255 | ||
88 | ] | ||
89 | ], | ||
90 | "cmdUnderTest": "$TC actions add action police rate 90kbit burst 10k mtu 2kb peakrate 100kbit index 3", | ||
91 | "expExitCode": "0", | ||
92 | "verifyCmd": "$TC actions ls action police", | ||
93 | "matchPattern": "action order [0-9]*: police 0x3 rate 90Kbit burst 10Kb mtu 2Kb peakrate 100Kbit", | ||
94 | "matchCount": "1", | ||
95 | "teardown": [ | ||
96 | "$TC actions flush action police" | ||
97 | ] | ||
98 | }, | ||
99 | { | ||
100 | "id": "055e", | ||
101 | "name": "Add police action with peakrate and no mtu", | ||
102 | "category": [ | ||
103 | "actions", | ||
104 | "police" | ||
105 | ], | ||
106 | "setup": [ | ||
107 | [ | ||
108 | "$TC actions flush action police", | ||
109 | 0, | ||
110 | 1, | ||
111 | 255 | ||
112 | ] | ||
113 | ], | ||
114 | "cmdUnderTest": "$TC actions add action police rate 5kbit burst 6kb peakrate 10kbit index 9", | ||
115 | "expExitCode": "255", | ||
116 | "verifyCmd": "$TC actions ls action police", | ||
117 | "matchPattern": "action order [0-9]*: police 0x9 rate 5Kb burst 10Kb", | ||
118 | "matchCount": "0", | ||
119 | "teardown": [ | ||
120 | "$TC actions flush action police" | ||
121 | ] | ||
122 | }, | ||
123 | { | ||
124 | "id": "f057", | ||
125 | "name": "Add police action with valid overhead", | ||
126 | "category": [ | ||
127 | "actions", | ||
128 | "police" | ||
129 | ], | ||
130 | "setup": [ | ||
131 | [ | ||
132 | "$TC actions flush action police", | ||
133 | 0, | ||
134 | 1, | ||
135 | 255 | ||
136 | ] | ||
137 | ], | ||
138 | "cmdUnderTest": "$TC actions add action police rate 1mbit burst 100k overhead 64 index 64", | ||
139 | "expExitCode": "0", | ||
140 | "verifyCmd": "$TC actions get action police index 64", | ||
141 | "matchPattern": "action order [0-9]*: police 0x40 rate 1Mbit burst 100Kb mtu 2Kb action reclassify overhead 64b", | ||
142 | "matchCount": "1", | ||
143 | "teardown": [ | ||
144 | "$TC actions flush action police" | ||
145 | ] | ||
146 | }, | ||
147 | { | ||
148 | "id": "7ffb", | ||
149 | "name": "Add police action with ethernet linklayer type", | ||
150 | "category": [ | ||
151 | "actions", | ||
152 | "police" | ||
153 | ], | ||
154 | "setup": [ | ||
155 | [ | ||
156 | "$TC actions flush action police", | ||
157 | 0, | ||
158 | 1, | ||
159 | 255 | ||
160 | ] | ||
161 | ], | ||
162 | "cmdUnderTest": "$TC actions add action police rate 2mbit burst 200k linklayer ethernet index 8", | ||
163 | "expExitCode": "0", | ||
164 | "verifyCmd": "$TC actions show action police", | ||
165 | "matchPattern": "action order [0-9]*: police 0x8 rate 2Mbit burst 200Kb mtu 2Kb action reclassify overhead 0b", | ||
166 | "matchCount": "1", | ||
167 | "teardown": [ | ||
168 | "$TC actions flush action police" | ||
169 | ] | ||
170 | }, | ||
171 | { | ||
172 | "id": "3dda", | ||
173 | "name": "Add police action with atm linklayer type", | ||
174 | "category": [ | ||
175 | "actions", | ||
176 | "police" | ||
177 | ], | ||
178 | "setup": [ | ||
179 | [ | ||
180 | "$TC actions flush action police", | ||
181 | 0, | ||
182 | 1, | ||
183 | 255 | ||
184 | ] | ||
185 | ], | ||
186 | "cmdUnderTest": "$TC actions add action police rate 2mbit burst 200k linklayer atm index 8", | ||
187 | "expExitCode": "0", | ||
188 | "verifyCmd": "$TC actions show action police", | ||
189 | "matchPattern": "action order [0-9]*: police 0x8 rate 2Mbit burst 200Kb mtu 2Kb action reclassify overhead 0b linklayer atm", | ||
190 | "matchCount": "1", | ||
191 | "teardown": [ | ||
192 | "$TC actions flush action police" | ||
193 | ] | ||
194 | }, | ||
195 | { | ||
196 | "id": "551b", | ||
197 | "name": "Add police actions with conform-exceed control continue/drop", | ||
198 | "category": [ | ||
199 | "actions", | ||
200 | "police" | ||
201 | ], | ||
202 | "setup": [ | ||
203 | [ | ||
204 | "$TC actions flush action police", | ||
205 | 0, | ||
206 | 1, | ||
207 | 255 | ||
208 | ] | ||
209 | ], | ||
210 | "cmdUnderTest": "$TC actions add action police rate 3mbit burst 250k conform-exceed continue/drop index 1", | ||
211 | "expExitCode": "0", | ||
212 | "verifyCmd": "$TC actions get action police index 1", | ||
213 | "matchPattern": "action order [0-9]*: police 0x1 rate 3Mbit burst 250Kb mtu 2Kb action continue/drop", | ||
214 | "matchCount": "1", | ||
215 | "teardown": [ | ||
216 | "$TC actions flush action police" | ||
217 | ] | ||
218 | }, | ||
219 | { | ||
220 | "id": "0c70", | ||
221 | "name": "Add police actions with conform-exceed control pass/reclassify", | ||
222 | "category": [ | ||
223 | "actions", | ||
224 | "police" | ||
225 | ], | ||
226 | "setup": [ | ||
227 | [ | ||
228 | "$TC actions flush action police", | ||
229 | 0, | ||
230 | 1, | ||
231 | 255 | ||
232 | ] | ||
233 | ], | ||
234 | "cmdUnderTest": "$TC actions add action police rate 3mbit burst 250k conform-exceed pass/reclassify index 4", | ||
235 | "expExitCode": "0", | ||
236 | "verifyCmd": "$TC actions ls action police", | ||
237 | "matchPattern": "action order [0-9]*: police 0x4 rate 3Mbit burst 250Kb mtu 2Kb action pass/reclassify", | ||
238 | "matchCount": "1", | ||
239 | "teardown": [ | ||
240 | "$TC actions flush action police" | ||
241 | ] | ||
242 | }, | ||
243 | { | ||
244 | "id": "d946", | ||
245 | "name": "Add police actions with conform-exceed control pass/pipe", | ||
246 | "category": [ | ||
247 | "actions", | ||
248 | "police" | ||
249 | ], | ||
250 | "setup": [ | ||
251 | [ | ||
252 | "$TC actions flush action police", | ||
253 | 0, | ||
254 | 1, | ||
255 | 255 | ||
256 | ] | ||
257 | ], | ||
258 | "cmdUnderTest": "$TC actions add action police rate 3mbit burst 250k conform-exceed pass/pipe index 5", | ||
259 | "expExitCode": "0", | ||
260 | "verifyCmd": "$TC actions ls action police", | ||
261 | "matchPattern": "action order [0-9]*: police 0x5 rate 3Mbit burst 250Kb mtu 2Kb action pass/pipe", | ||
262 | "matchCount": "1", | ||
263 | "teardown": [ | ||
264 | "$TC actions flush action police" | ||
265 | ] | ||
266 | }, | ||
267 | { | ||
268 | "id": "336e", | ||
269 | "name": "Delete police action", | ||
270 | "category": [ | ||
271 | "actions", | ||
272 | "police" | ||
273 | ], | ||
274 | "setup": [ | ||
275 | [ | ||
276 | "$TC actions flush action police", | ||
277 | 0, | ||
278 | 1, | ||
279 | 255 | ||
280 | ], | ||
281 | "$TC actions add action police rate 5mbit burst 2m index 12" | ||
282 | ], | ||
283 | "cmdUnderTest": "$TC actions delete action police index 12", | ||
284 | "expExitCode": "0", | ||
285 | "verifyCmd": "$TC actions ls action police", | ||
286 | "matchPattern": "action order [0-9]*: police 0xc rate 5Mb burst 2Mb", | ||
287 | "matchCount": "0", | ||
288 | "teardown": [ | ||
289 | "$TC actions flush action police" | ||
290 | ] | ||
291 | }, | ||
292 | { | ||
293 | "id": "77fa", | ||
294 | "name": "Get single police action from many actions", | ||
295 | "category": [ | ||
296 | "actions", | ||
297 | "police" | ||
298 | ], | ||
299 | "setup": [ | ||
300 | [ | ||
301 | "$TC actions flush action police", | ||
302 | 0, | ||
303 | 1, | ||
304 | 255 | ||
305 | ], | ||
306 | "$TC actions add action police rate 1mbit burst 100k index 1", | ||
307 | "$TC actions add action police rate 2mbit burst 200k index 2", | ||
308 | "$TC actions add action police rate 3mbit burst 300k index 3", | ||
309 | "$TC actions add action police rate 4mbit burst 400k index 4", | ||
310 | "$TC actions add action police rate 5mbit burst 500k index 5", | ||
311 | "$TC actions add action police rate 6mbit burst 600k index 6", | ||
312 | "$TC actions add action police rate 7mbit burst 700k index 7", | ||
313 | "$TC actions add action police rate 8mbit burst 800k index 8" | ||
314 | ], | ||
315 | "cmdUnderTest": "$TC actions get action police index 4", | ||
316 | "expExitCode": "0", | ||
317 | "verifyCmd": "$TC actions get action police index 4", | ||
318 | "matchPattern": "action order [0-9]*: police 0x4 rate 4Mbit burst 400Kb", | ||
319 | "matchCount": "1", | ||
320 | "teardown": [ | ||
321 | "$TC actions flush action police" | ||
322 | ] | ||
323 | }, | ||
324 | { | ||
325 | "id": "aa43", | ||
326 | "name": "Get single police action without specifying index", | ||
327 | "category": [ | ||
328 | "actions", | ||
329 | "police" | ||
330 | ], | ||
331 | "setup": [ | ||
332 | [ | ||
333 | "$TC actions flush action police", | ||
334 | 0, | ||
335 | 1, | ||
336 | 255 | ||
337 | ], | ||
338 | "$TC actions add action police rate 1mbit burst 100k index 1" | ||
339 | ], | ||
340 | "cmdUnderTest": "$TC actions get action police", | ||
341 | "expExitCode": "255", | ||
342 | "verifyCmd": "$TC actions get action police", | ||
343 | "matchPattern": "action order [0-9]*: police", | ||
344 | "matchCount": "0", | ||
345 | "teardown": [ | ||
346 | "$TC actions flush action police" | ||
347 | ] | ||
348 | }, | ||
349 | { | ||
350 | "id": "858b", | ||
351 | "name": "List police actions", | ||
352 | "category": [ | ||
353 | "actions", | ||
354 | "police" | ||
355 | ], | ||
356 | "setup": [ | ||
357 | [ | ||
358 | "$TC actions flush action police", | ||
359 | 0, | ||
360 | 1, | ||
361 | 255 | ||
362 | ], | ||
363 | "$TC actions add action police rate 1mbit burst 100k index 1", | ||
364 | "$TC actions add action police rate 2mbit burst 200k index 2", | ||
365 | "$TC actions add action police rate 3mbit burst 300k index 3", | ||
366 | "$TC actions add action police rate 4mbit burst 400k index 4", | ||
367 | "$TC actions add action police rate 5mbit burst 500k index 5", | ||
368 | "$TC actions add action police rate 6mbit burst 600k index 6", | ||
369 | "$TC actions add action police rate 7mbit burst 700k index 7", | ||
370 | "$TC actions add action police rate 8mbit burst 800k index 8" | ||
371 | ], | ||
372 | "cmdUnderTest": "$TC actions list action police", | ||
373 | "expExitCode": "0", | ||
374 | "verifyCmd": "$TC actions ls action police", | ||
375 | "matchPattern": "action order [0-9]*: police 0x[1-8] rate [1-8]Mbit burst [1-8]00Kb", | ||
376 | "matchCount": "8", | ||
377 | "teardown": [ | ||
378 | "$TC actions flush action police" | ||
379 | ] | ||
380 | }, | ||
381 | { | ||
382 | "id": "1c3a", | ||
383 | "name": "Flush police actions", | ||
384 | "category": [ | ||
385 | "actions", | ||
386 | "police" | ||
387 | ], | ||
388 | "setup": [ | ||
389 | "$TC actions add action police rate 1mbit burst 100k index 1", | ||
390 | "$TC actions add action police rate 2mbit burst 200k index 2", | ||
391 | "$TC actions add action police rate 3mbit burst 300k index 3", | ||
392 | "$TC actions add action police rate 4mbit burst 400k index 4", | ||
393 | "$TC actions add action police rate 5mbit burst 500k index 5", | ||
394 | "$TC actions add action police rate 6mbit burst 600k index 6", | ||
395 | "$TC actions add action police rate 7mbit burst 700k index 7", | ||
396 | "$TC actions add action police rate 8mbit burst 800k index 8" | ||
397 | ], | ||
398 | "cmdUnderTest": "$TC actions flush action police", | ||
399 | "expExitCode": "0", | ||
400 | "verifyCmd": "$TC actions ls action police", | ||
401 | "matchPattern": "action order [0-9]*: police", | ||
402 | "matchCount": "0", | ||
403 | "teardown": [ | ||
404 | "" | ||
405 | ] | ||
406 | }, | ||
407 | { | ||
408 | "id": "7326", | ||
409 | "name": "Add police action with control continue", | ||
410 | "category": [ | ||
411 | "actions", | ||
412 | "police" | ||
413 | ], | ||
414 | "setup": [ | ||
415 | [ | ||
416 | "$TC actions flush action police", | ||
417 | 0, | ||
418 | 1, | ||
419 | 255 | ||
420 | ] | ||
421 | ], | ||
422 | "cmdUnderTest": "$TC actions add action police rate 7mbit burst 1m continue index 1", | ||
423 | "expExitCode": "0", | ||
424 | "verifyCmd": "$TC actions get action police index 1", | ||
425 | "matchPattern": "action order [0-9]*: police 0x1 rate 7Mbit burst 1024Kb mtu 2Kb action continue", | ||
426 | "matchCount": "1", | ||
427 | "teardown": [ | ||
428 | "$TC actions flush action police" | ||
429 | ] | ||
430 | }, | ||
431 | { | ||
432 | "id": "34fa", | ||
433 | "name": "Add police action with control drop", | ||
434 | "category": [ | ||
435 | "actions", | ||
436 | "police" | ||
437 | ], | ||
438 | "setup": [ | ||
439 | [ | ||
440 | "$TC actions flush action police", | ||
441 | 0, | ||
442 | 1, | ||
443 | 255 | ||
444 | ] | ||
445 | ], | ||
446 | "cmdUnderTest": "$TC actions add action police rate 7mbit burst 1m drop index 1", | ||
447 | "expExitCode": "0", | ||
448 | "verifyCmd": "$TC actions ls action police", | ||
449 | "matchPattern": "action order [0-9]*: police 0x1 rate 7Mbit burst 1024Kb mtu 2Kb action drop", | ||
450 | "matchCount": "1", | ||
451 | "teardown": [ | ||
452 | "$TC actions flush action police" | ||
453 | ] | ||
454 | }, | ||
455 | { | ||
456 | "id": "8dd5", | ||
457 | "name": "Add police action with control ok", | ||
458 | "category": [ | ||
459 | "actions", | ||
460 | "police" | ||
461 | ], | ||
462 | "setup": [ | ||
463 | [ | ||
464 | "$TC actions flush action police", | ||
465 | 0, | ||
466 | 1, | ||
467 | 255 | ||
468 | ] | ||
469 | ], | ||
470 | "cmdUnderTest": "$TC actions add action police rate 7mbit burst 1m ok index 1", | ||
471 | "expExitCode": "0", | ||
472 | "verifyCmd": "$TC actions ls action police", | ||
473 | "matchPattern": "action order [0-9]*: police 0x1 rate 7Mbit burst 1024Kb mtu 2Kb action pass", | ||
474 | "matchCount": "1", | ||
475 | "teardown": [ | ||
476 | "$TC actions flush action police" | ||
477 | ] | ||
478 | }, | ||
479 | { | ||
480 | "id": "b9d1", | ||
481 | "name": "Add police action with control reclassify", | ||
482 | "category": [ | ||
483 | "actions", | ||
484 | "police" | ||
485 | ], | ||
486 | "setup": [ | ||
487 | [ | ||
488 | "$TC actions flush action police", | ||
489 | 0, | ||
490 | 1, | ||
491 | 255 | ||
492 | ] | ||
493 | ], | ||
494 | "cmdUnderTest": "$TC actions add action police rate 7mbit burst 1m reclassify index 1", | ||
495 | "expExitCode": "0", | ||
496 | "verifyCmd": "$TC actions get action police index 1", | ||
497 | "matchPattern": "action order [0-9]*: police 0x1 rate 7Mbit burst 1024Kb mtu 2Kb action reclassify", | ||
498 | "matchCount": "1", | ||
499 | "teardown": [ | ||
500 | "$TC actions flush action police" | ||
501 | ] | ||
502 | }, | ||
503 | { | ||
504 | "id": "c534", | ||
505 | "name": "Add police action with control pipe", | ||
506 | "category": [ | ||
507 | "actions", | ||
508 | "police" | ||
509 | ], | ||
510 | "setup": [ | ||
511 | [ | ||
512 | "$TC actions flush action police", | ||
513 | 0, | ||
514 | 1, | ||
515 | 255 | ||
516 | ] | ||
517 | ], | ||
518 | "cmdUnderTest": "$TC actions add action police rate 7mbit burst 1m pipe index 1", | ||
519 | "expExitCode": "0", | ||
520 | "verifyCmd": "$TC actions ls action police", | ||
521 | "matchPattern": "action order [0-9]*: police 0x1 rate 7Mbit burst 1024Kb mtu 2Kb action pipe", | ||
522 | "matchCount": "1", | ||
523 | "teardown": [ | ||
524 | "$TC actions flush action police" | ||
525 | ] | ||
526 | } | ||
527 | ] | ||
diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/simple.json b/tools/testing/selftests/tc-testing/tc-tests/actions/simple.json new file mode 100644 index 000000000000..e89a7aa4012d --- /dev/null +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/simple.json | |||
@@ -0,0 +1,130 @@ | |||
1 | [ | ||
2 | { | ||
3 | "id": "b078", | ||
4 | "name": "Add simple action", | ||
5 | "category": [ | ||
6 | "actions", | ||
7 | "simple" | ||
8 | ], | ||
9 | "setup": [ | ||
10 | [ | ||
11 | "$TC actions flush action simple", | ||
12 | 0, | ||
13 | 1, | ||
14 | 255 | ||
15 | ] | ||
16 | ], | ||
17 | "cmdUnderTest": "$TC actions add action simple sdata \"A triumph\" index 60", | ||
18 | "expExitCode": "0", | ||
19 | "verifyCmd": "$TC actions list action simple", | ||
20 | "matchPattern": "action order [0-9]*: Simple <A triumph>.*index 60 ref", | ||
21 | "matchCount": "1", | ||
22 | "teardown": [ | ||
23 | "$TC actions flush action simple" | ||
24 | ] | ||
25 | }, | ||
26 | { | ||
27 | "id": "6d4c", | ||
28 | "name": "Add simple action with duplicate index", | ||
29 | "category": [ | ||
30 | "actions", | ||
31 | "simple" | ||
32 | ], | ||
33 | "setup": [ | ||
34 | [ | ||
35 | "$TC actions flush action simple", | ||
36 | 0, | ||
37 | 1, | ||
38 | 255 | ||
39 | ], | ||
40 | "$TC actions add action simple sdata \"Aruba\" index 4" | ||
41 | ], | ||
42 | "cmdUnderTest": "$TC actions add action simple sdata \"Jamaica\" index 4", | ||
43 | "expExitCode": "255", | ||
44 | "verifyCmd": "$TC actions list action simple", | ||
45 | "matchPattern": "action order [0-9]*: Simple <Jamaica>.*ref", | ||
46 | "matchCount": "0", | ||
47 | "teardown": [ | ||
48 | "$TC actions flush action simple" | ||
49 | ] | ||
50 | }, | ||
51 | { | ||
52 | "id": "2542", | ||
53 | "name": "List simple actions", | ||
54 | "category": [ | ||
55 | "actions", | ||
56 | "simple" | ||
57 | ], | ||
58 | "setup": [ | ||
59 | [ | ||
60 | "$TC actions flush action simple", | ||
61 | 0, | ||
62 | 1, | ||
63 | 255 | ||
64 | ], | ||
65 | "$TC actions add action simple sdata \"Rock\"", | ||
66 | "$TC actions add action simple sdata \"Paper\"", | ||
67 | "$TC actions add action simple sdata \"Scissors\" index 98" | ||
68 | ], | ||
69 | "cmdUnderTest": "$TC actions list action simple", | ||
70 | "expExitCode": "0", | ||
71 | "verifyCmd": "$TC actions list action simple", | ||
72 | "matchPattern": "action order [0-9]*: Simple <[A-Z][a-z]*>", | ||
73 | "matchCount": "3", | ||
74 | "teardown": [ | ||
75 | "$TC actions flush action simple" | ||
76 | ] | ||
77 | }, | ||
78 | { | ||
79 | "id": "ea67", | ||
80 | "name": "Delete simple action", | ||
81 | "category": [ | ||
82 | "actions", | ||
83 | "simple" | ||
84 | ], | ||
85 | "setup": [ | ||
86 | [ | ||
87 | "$TC actions flush action simple", | ||
88 | 0, | ||
89 | 1, | ||
90 | 255 | ||
91 | ], | ||
92 | "$TC actions add action simple sdata \"Blinkenlights\" index 1" | ||
93 | ], | ||
94 | "cmdUnderTest": "$TC actions delete action simple index 1", | ||
95 | "expExitCode": "0", | ||
96 | "verifyCmd": "$TC actions list action simple", | ||
97 | "matchPattern": "action order [0-9]*: Simple <Blinkenlights>.*index 1 ref", | ||
98 | "matchCount": "0", | ||
99 | "teardown": [ | ||
100 | "$TC actions flush action simple" | ||
101 | ] | ||
102 | }, | ||
103 | { | ||
104 | "id": "8ff1", | ||
105 | "name": "Flush simple actions", | ||
106 | "category": [ | ||
107 | "actions", | ||
108 | "simple" | ||
109 | ], | ||
110 | "setup": [ | ||
111 | [ | ||
112 | "$TC actions flush action simple", | ||
113 | 0, | ||
114 | 1, | ||
115 | 255 | ||
116 | ], | ||
117 | "$TC actions add action simple sdata \"Kirk\"", | ||
118 | "$TC actions add action simple sdata \"Spock\" index 50", | ||
119 | "$TC actions add action simple sdata \"McCoy\" index 9" | ||
120 | ], | ||
121 | "cmdUnderTest": "$TC actions flush action simple", | ||
122 | "expExitCode": "0", | ||
123 | "verifyCmd": "$TC actions list action simple", | ||
124 | "matchPattern": "action order [0-9]*: Simple <[A-Z][a-z]*>", | ||
125 | "matchCount": "0", | ||
126 | "teardown": [ | ||
127 | "" | ||
128 | ] | ||
129 | } | ||
130 | ] | ||
diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/skbedit.json b/tools/testing/selftests/tc-testing/tc-tests/actions/skbedit.json new file mode 100644 index 000000000000..99635ea4722e --- /dev/null +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/skbedit.json | |||
@@ -0,0 +1,320 @@ | |||
1 | [ | ||
2 | { | ||
3 | "id": "6236", | ||
4 | "name": "Add skbedit action with valid mark", | ||
5 | "category": [ | ||
6 | "actions", | ||
7 | "skbedit" | ||
8 | ], | ||
9 | "setup": [ | ||
10 | [ | ||
11 | "$TC actions flush action skbedit", | ||
12 | 0, | ||
13 | 1, | ||
14 | 255 | ||
15 | ] | ||
16 | ], | ||
17 | "cmdUnderTest": "$TC actions add action skbedit mark 1", | ||
18 | "expExitCode": "0", | ||
19 | "verifyCmd": "$TC actions list action skbedit", | ||
20 | "matchPattern": "action order [0-9]*: skbedit mark 1", | ||
21 | "matchCount": "1", | ||
22 | "teardown": [ | ||
23 | "$TC actions flush action skbedit" | ||
24 | ] | ||
25 | }, | ||
26 | { | ||
27 | "id": "407b", | ||
28 | "name": "Add skbedit action with invalid mark", | ||
29 | "category": [ | ||
30 | "actions", | ||
31 | "skbedit" | ||
32 | ], | ||
33 | "setup": [ | ||
34 | [ | ||
35 | "$TC actions flush action skbedit", | ||
36 | 0, | ||
37 | 1, | ||
38 | 255 | ||
39 | ] | ||
40 | ], | ||
41 | "cmdUnderTest": "$TC actions add action skbedit mark 666777888999", | ||
42 | "expExitCode": "255", | ||
43 | "verifyCmd": "$TC actions list action skbedit", | ||
44 | "matchPattern": "action order [0-9]*: skbedit mark", | ||
45 | "matchCount": "0", | ||
46 | "teardown": [ | ||
47 | "$TC actions flush action skbedit" | ||
48 | ] | ||
49 | }, | ||
50 | { | ||
51 | "id": "081d", | ||
52 | "name": "Add skbedit action with priority", | ||
53 | "category": [ | ||
54 | "actions", | ||
55 | "skbedit" | ||
56 | ], | ||
57 | "setup": [ | ||
58 | [ | ||
59 | "$TC actions flush action skbedit", | ||
60 | 0, | ||
61 | 1, | ||
62 | 255 | ||
63 | ] | ||
64 | ], | ||
65 | "cmdUnderTest": "$TC actions add action skbedit prio 99", | ||
66 | "expExitCode": "0", | ||
67 | "verifyCmd": "$TC actions list action skbedit", | ||
68 | "matchPattern": "action order [0-9]*: skbedit priority :99", | ||
69 | "matchCount": "1", | ||
70 | "teardown": [ | ||
71 | "$TC actions flush action skbedit" | ||
72 | ] | ||
73 | }, | ||
74 | { | ||
75 | "id": "cc37", | ||
76 | "name": "Add skbedit action with invalid priority", | ||
77 | "category": [ | ||
78 | "actions", | ||
79 | "skbedit" | ||
80 | ], | ||
81 | "setup": [ | ||
82 | [ | ||
83 | "$TC actions flush action skbedit", | ||
84 | 0, | ||
85 | 1, | ||
86 | 255 | ||
87 | ] | ||
88 | ], | ||
89 | "cmdUnderTest": "$TC actions add action skbedit prio foo", | ||
90 | "expExitCode": "255", | ||
91 | "verifyCmd": "$TC actions list action skbedit", | ||
92 | "matchPattern": "action order [0-9]*: skbedit priority", | ||
93 | "matchCount": "0", | ||
94 | "teardown": [ | ||
95 | "$TC actions flush action skbedit" | ||
96 | ] | ||
97 | }, | ||
98 | { | ||
99 | "id": "3c95", | ||
100 | "name": "Add skbedit action with queue_mapping", | ||
101 | "category": [ | ||
102 | "actions", | ||
103 | "skbedit" | ||
104 | ], | ||
105 | "setup": [ | ||
106 | [ | ||
107 | "$TC actions flush action skbedit", | ||
108 | 0, | ||
109 | 1, | ||
110 | 255 | ||
111 | ] | ||
112 | ], | ||
113 | "cmdUnderTest": "$TC actions add action skbedit queue_mapping 909", | ||
114 | "expExitCode": "0", | ||
115 | "verifyCmd": "$TC actions list action skbedit", | ||
116 | "matchPattern": "action order [0-9]*: skbedit queue_mapping 909", | ||
117 | "matchCount": "1", | ||
118 | "teardown": [ | ||
119 | "$TC actions flush action skbedit" | ||
120 | ] | ||
121 | }, | ||
122 | { | ||
123 | "id": "985c", | ||
124 | "name": "Add skbedit action with invalid queue_mapping", | ||
125 | "category": [ | ||
126 | "actions", | ||
127 | "skbedit" | ||
128 | ], | ||
129 | "setup": [ | ||
130 | [ | ||
131 | "$TC actions flush action skbedit", | ||
132 | 0, | ||
133 | 1, | ||
134 | 255 | ||
135 | ] | ||
136 | ], | ||
137 | "cmdUnderTest": "$TC actions add action skbedit queue_mapping 67000", | ||
138 | "expExitCode": "255", | ||
139 | "verifyCmd": "$TC actions list action skbedit", | ||
140 | "matchPattern": "action order [0-9]*: skbedit queue_mapping", | ||
141 | "matchCount": "0", | ||
142 | "teardown": [ | ||
143 | "$TC actions flush action skbedit" | ||
144 | ] | ||
145 | }, | ||
146 | { | ||
147 | "id": "224f", | ||
148 | "name": "Add skbedit action with ptype host", | ||
149 | "category": [ | ||
150 | "actions", | ||
151 | "skbedit" | ||
152 | ], | ||
153 | "setup": [ | ||
154 | [ | ||
155 | "$TC actions flush action skbedit", | ||
156 | 0, | ||
157 | 1, | ||
158 | 255 | ||
159 | ] | ||
160 | ], | ||
161 | "cmdUnderTest": "$TC actions add action skbedit ptype host", | ||
162 | "expExitCode": "0", | ||
163 | "verifyCmd": "$TC actions list action skbedit", | ||
164 | "matchPattern": "action order [0-9]*: skbedit ptype host", | ||
165 | "matchCount": "1", | ||
166 | "teardown": [ | ||
167 | "$TC actions flush action skbedit" | ||
168 | ] | ||
169 | }, | ||
170 | { | ||
171 | "id": "d1a3", | ||
172 | "name": "Add skbedit action with ptype otherhost", | ||
173 | "category": [ | ||
174 | "actions", | ||
175 | "skbedit" | ||
176 | ], | ||
177 | "setup": [ | ||
178 | [ | ||
179 | "$TC actions flush action skbedit", | ||
180 | 0, | ||
181 | 1, | ||
182 | 255 | ||
183 | ] | ||
184 | ], | ||
185 | "cmdUnderTest": "$TC actions add action skbedit ptype otherhost", | ||
186 | "expExitCode": "0", | ||
187 | "verifyCmd": "$TC actions list action skbedit", | ||
188 | "matchPattern": "action order [0-9]*: skbedit ptype otherhost", | ||
189 | "matchCount": "1", | ||
190 | "teardown": [ | ||
191 | "$TC actions flush action skbedit" | ||
192 | ] | ||
193 | }, | ||
194 | { | ||
195 | "id": "b9c6", | ||
196 | "name": "Add skbedit action with invalid ptype", | ||
197 | "category": [ | ||
198 | "actions", | ||
199 | "skbedit" | ||
200 | ], | ||
201 | "setup": [ | ||
202 | [ | ||
203 | "$TC actions flush action skbedit", | ||
204 | 0, | ||
205 | 1, | ||
206 | 255 | ||
207 | ] | ||
208 | ], | ||
209 | "cmdUnderTest": "$TC actions add action skbedit ptype openair", | ||
210 | "expExitCode": "255", | ||
211 | "verifyCmd": "$TC actions list action skbedit", | ||
212 | "matchPattern": "action order [0-9]*: skbedit ptype openair", | ||
213 | "matchCount": "0", | ||
214 | "teardown": [ | ||
215 | "$TC actions flush action skbedit" | ||
216 | ] | ||
217 | }, | ||
218 | { | ||
219 | "id": "5172", | ||
220 | "name": "List skbedit actions", | ||
221 | "category": [ | ||
222 | "actions", | ||
223 | "skbedit" | ||
224 | ], | ||
225 | "setup": [ | ||
226 | [ | ||
227 | "$TC actions flush action skbedit", | ||
228 | 0, | ||
229 | 1, | ||
230 | 255 | ||
231 | ], | ||
232 | "$TC actions add action skbedit ptype otherhost", | ||
233 | "$TC actions add action skbedit ptype broadcast", | ||
234 | "$TC actions add action skbedit mark 59", | ||
235 | "$TC actions add action skbedit mark 409" | ||
236 | ], | ||
237 | "cmdUnderTest": "$TC actions list action skbedit", | ||
238 | "expExitCode": "0", | ||
239 | "verifyCmd": "$TC actions list action skbedit", | ||
240 | "matchPattern": "action order [0-9]*: skbedit", | ||
241 | "matchCount": "4", | ||
242 | "teardown": [ | ||
243 | "$TC actions flush action skbedit" | ||
244 | ] | ||
245 | }, | ||
246 | { | ||
247 | "id": "a6d6", | ||
248 | "name": "Add skbedit action with index", | ||
249 | "category": [ | ||
250 | "actions", | ||
251 | "skbedit" | ||
252 | ], | ||
253 | "setup": [ | ||
254 | [ | ||
255 | "$TC actions flush action skbedit", | ||
256 | 0, | ||
257 | 1, | ||
258 | 255 | ||
259 | ] | ||
260 | ], | ||
261 | "cmdUnderTest": "$TC actions add action skbedit mark 808 index 4040404040", | ||
262 | "expExitCode": "0", | ||
263 | "verifyCmd": "$TC actions list action skbedit", | ||
264 | "matchPattern": "index 4040404040", | ||
265 | "matchCount": "1", | ||
266 | "teardown": [ | ||
267 | "$TC actions flush action skbedit" | ||
268 | ] | ||
269 | }, | ||
270 | { | ||
271 | "id": "38f3", | ||
272 | "name": "Delete skbedit action", | ||
273 | "category": [ | ||
274 | "actions", | ||
275 | "skbedit" | ||
276 | ], | ||
277 | "setup": [ | ||
278 | [ | ||
279 | "$TC actions flush action skbedit", | ||
280 | 0, | ||
281 | 1, | ||
282 | 255 | ||
283 | ], | ||
284 | "$TC actions add action skbedit mark 42 index 9009" | ||
285 | ], | ||
286 | "cmdUnderTest": "$TC actions del action skbedit index 9009", | ||
287 | "expExitCode": "0", | ||
288 | "verifyCmd": "$TC actions list action skbedit", | ||
289 | "matchPattern": "action order [0-9]*: skbedit mark 42", | ||
290 | "matchCount": "0", | ||
291 | "teardown": [ | ||
292 | "$TC actions flush action skbedit" | ||
293 | ] | ||
294 | }, | ||
295 | { | ||
296 | "id": "ce97", | ||
297 | "name": "Flush skbedit actions", | ||
298 | "category": [ | ||
299 | "actions", | ||
300 | "skbedit" | ||
301 | ], | ||
302 | "setup": [ | ||
303 | "$TC actions add action skbedit mark 500", | ||
304 | "$TC actions add action skbedit mark 501", | ||
305 | "$TC actions add action skbedit mark 502", | ||
306 | "$TC actions add action skbedit mark 503", | ||
307 | "$TC actions add action skbedit mark 504", | ||
308 | "$TC actions add action skbedit mark 505", | ||
309 | "$TC actions add action skbedit mark 506" | ||
310 | ], | ||
311 | "cmdUnderTest": "$TC actions flush action skbedit", | ||
312 | "expExitCode": "0", | ||
313 | "verifyCmd": "$TC actions list action skbedit", | ||
314 | "matchPattern": "action order [0-9]*: skbedit", | ||
315 | "matchCount": "0", | ||
316 | "teardown": [ | ||
317 | "$TC actions flush action skbedit" | ||
318 | ] | ||
319 | } | ||
320 | ] | ||
diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/skbmod.json b/tools/testing/selftests/tc-testing/tc-tests/actions/skbmod.json new file mode 100644 index 000000000000..e34075059c26 --- /dev/null +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/skbmod.json | |||
@@ -0,0 +1,372 @@ | |||
1 | [ | ||
2 | { | ||
3 | "id": "7d50", | ||
4 | "name": "Add skbmod action to set destination mac", | ||
5 | "category": [ | ||
6 | "actions", | ||
7 | "skbmod" | ||
8 | ], | ||
9 | "setup": [ | ||
10 | [ | ||
11 | "$TC actions flush action skbmod", | ||
12 | 0, | ||
13 | 1, | ||
14 | 255 | ||
15 | ] | ||
16 | ], | ||
17 | "cmdUnderTest": "$TC actions add action skbmod set dmac 11:22:33:44:55:66 index 5", | ||
18 | "expExitCode": "0", | ||
19 | "verifyCmd": "$TC actions ls action skbmod", | ||
20 | "matchPattern": "action order [0-9]*: skbmod pipe set dmac 11:22:33:44:55:66\\s+index 5", | ||
21 | "matchCount": "1", | ||
22 | "teardown": [ | ||
23 | "$TC actions flush action skbmod" | ||
24 | ] | ||
25 | }, | ||
26 | { | ||
27 | "id": "9b29", | ||
28 | "name": "Add skbmod action to set source mac", | ||
29 | "category": [ | ||
30 | "actions", | ||
31 | "skbmod" | ||
32 | ], | ||
33 | "setup": [ | ||
34 | [ | ||
35 | "$TC actions flush action skbmod", | ||
36 | 0, | ||
37 | 1, | ||
38 | 255 | ||
39 | ] | ||
40 | ], | ||
41 | "cmdUnderTest": "$TC actions add action skbmod set smac 77:88:99:AA:BB:CC index 7", | ||
42 | "expExitCode": "0", | ||
43 | "verifyCmd": "$TC actions get action skbmod index 7", | ||
44 | "matchPattern": "action order [0-9]*: skbmod pipe set smac 77:88:99:aa:bb:cc\\s+index 7", | ||
45 | "matchCount": "1", | ||
46 | "teardown": [ | ||
47 | "$TC actions flush action skbmod" | ||
48 | ] | ||
49 | }, | ||
50 | { | ||
51 | "id": "1724", | ||
52 | "name": "Add skbmod action with invalid mac", | ||
53 | "category": [ | ||
54 | "actions", | ||
55 | "skbmod" | ||
56 | ], | ||
57 | "setup": [ | ||
58 | [ | ||
59 | "$TC actions flush action skbmod", | ||
60 | 0, | ||
61 | 1, | ||
62 | 255 | ||
63 | ] | ||
64 | ], | ||
65 | "cmdUnderTest": "$TC actions add action skbmod set smac 00:44:55:44:55", | ||
66 | "expExitCode": "255", | ||
67 | "verifyCmd": "$TC actions ls action skbmod", | ||
68 | "matchPattern": "action order [0-9]*: skbmod pipe set smac 00:44:55:44:55", | ||
69 | "matchCount": "0", | ||
70 | "teardown": [ | ||
71 | "$TC actions flush action skbmod" | ||
72 | ] | ||
73 | }, | ||
74 | { | ||
75 | "id": "3cf1", | ||
76 | "name": "Add skbmod action with valid etype", | ||
77 | "category": [ | ||
78 | "actions", | ||
79 | "skbmod" | ||
80 | ], | ||
81 | "setup": [ | ||
82 | [ | ||
83 | "$TC actions flush action skbmod", | ||
84 | 0, | ||
85 | 1, | ||
86 | 255 | ||
87 | ] | ||
88 | ], | ||
89 | "cmdUnderTest": "$TC actions add action skbmod set etype 0xfefe", | ||
90 | "expExitCode": "0", | ||
91 | "verifyCmd": "$TC actions ls action skbmod", | ||
92 | "matchPattern": "action order [0-9]*: skbmod pipe set etype 0xFEFE", | ||
93 | "matchCount": "1", | ||
94 | "teardown": [ | ||
95 | "$TC actions flush action skbmod" | ||
96 | ] | ||
97 | }, | ||
98 | { | ||
99 | "id": "a749", | ||
100 | "name": "Add skbmod action with invalid etype", | ||
101 | "category": [ | ||
102 | "actions", | ||
103 | "skbmod" | ||
104 | ], | ||
105 | "setup": [ | ||
106 | [ | ||
107 | "$TC actions flush action skbmod", | ||
108 | 0, | ||
109 | 1, | ||
110 | 255 | ||
111 | ] | ||
112 | ], | ||
113 | "cmdUnderTest": "$TC actions add action skbmod set etype 0xfefef", | ||
114 | "expExitCode": "255", | ||
115 | "verifyCmd": "$TC actions ls action skbmod", | ||
116 | "matchPattern": "action order [0-9]*: skbmod pipe set etype 0xFEFEF", | ||
117 | "matchCount": "0", | ||
118 | "teardown": [ | ||
119 | "$TC actions flush action skbmod" | ||
120 | ] | ||
121 | }, | ||
122 | { | ||
123 | "id": "bfe6", | ||
124 | "name": "Add skbmod action to swap mac", | ||
125 | "category": [ | ||
126 | "actions", | ||
127 | "skbmod" | ||
128 | ], | ||
129 | "setup": [ | ||
130 | [ | ||
131 | "$TC actions flush action skbmod", | ||
132 | 0, | ||
133 | 1, | ||
134 | 255 | ||
135 | ] | ||
136 | ], | ||
137 | "cmdUnderTest": "$TC actions add action skbmod swap mac", | ||
138 | "expExitCode": "0", | ||
139 | "verifyCmd": "$TC actions get action skbmod index 1", | ||
140 | "matchPattern": "action order [0-9]*: skbmod pipe swap mac", | ||
141 | "matchCount": "1", | ||
142 | "teardown": [ | ||
143 | "$TC actions flush action skbmod" | ||
144 | ] | ||
145 | }, | ||
146 | { | ||
147 | "id": "839b", | ||
148 | "name": "Add skbmod action with control pipe", | ||
149 | "category": [ | ||
150 | "actions", | ||
151 | "skbmod" | ||
152 | ], | ||
153 | "setup": [ | ||
154 | [ | ||
155 | "$TC actions flush action skbmod", | ||
156 | 0, | ||
157 | 1, | ||
158 | 255 | ||
159 | ] | ||
160 | ], | ||
161 | "cmdUnderTest": "$TC actions add action skbmod swap mac pipe", | ||
162 | "expExitCode": "0", | ||
163 | "verifyCmd": "$TC actions ls action skbmod", | ||
164 | "matchPattern": "action order [0-9]*: skbmod pipe swap mac", | ||
165 | "matchCount": "1", | ||
166 | "teardown": [ | ||
167 | "$TC actions flush action skbmod" | ||
168 | ] | ||
169 | }, | ||
170 | { | ||
171 | "id": "c167", | ||
172 | "name": "Add skbmod action with control reclassify", | ||
173 | "category": [ | ||
174 | "actions", | ||
175 | "skbmod" | ||
176 | ], | ||
177 | "setup": [ | ||
178 | [ | ||
179 | "$TC actions flush action skbmod", | ||
180 | 0, | ||
181 | 1, | ||
182 | 255 | ||
183 | ] | ||
184 | ], | ||
185 | "cmdUnderTest": "$TC actions add action skbmod set etype 0xbeef reclassify", | ||
186 | "expExitCode": "0", | ||
187 | "verifyCmd": "$TC actions ls action skbmod", | ||
188 | "matchPattern": "action order [0-9]*: skbmod reclassify set etype 0xBEEF", | ||
189 | "matchCount": "1", | ||
190 | "teardown": [ | ||
191 | "$TC actions flush action skbmod" | ||
192 | ] | ||
193 | }, | ||
194 | { | ||
195 | "id": "0c2f", | ||
196 | "name": "Add skbmod action with control drop", | ||
197 | "category": [ | ||
198 | "actions", | ||
199 | "skbmod" | ||
200 | ], | ||
201 | "setup": [ | ||
202 | [ | ||
203 | "$TC actions flush action skbmod", | ||
204 | 0, | ||
205 | 1, | ||
206 | 255 | ||
207 | ] | ||
208 | ], | ||
209 | "cmdUnderTest": "$TC actions add action skbmod set etype 0x0001 drop", | ||
210 | "expExitCode": "0", | ||
211 | "verifyCmd": "$TC actions get action skbmod index 1", | ||
212 | "matchPattern": "action order [0-9]*: skbmod drop set etype 0x1", | ||
213 | "matchCount": "1", | ||
214 | "teardown": [ | ||
215 | "$TC actions flush action skbmod" | ||
216 | ] | ||
217 | }, | ||
218 | { | ||
219 | "id": "d113", | ||
220 | "name": "Add skbmod action with control continue", | ||
221 | "category": [ | ||
222 | "actions", | ||
223 | "skbmod" | ||
224 | ], | ||
225 | "setup": [ | ||
226 | [ | ||
227 | "$TC actions flush action skbmod", | ||
228 | 0, | ||
229 | 1, | ||
230 | 255 | ||
231 | ] | ||
232 | ], | ||
233 | "cmdUnderTest": "$TC actions add action skbmod set etype 0x1 continue", | ||
234 | "expExitCode": "0", | ||
235 | "verifyCmd": "$TC actions ls action skbmod", | ||
236 | "matchPattern": "action order [0-9]*: skbmod continue set etype 0x1", | ||
237 | "matchCount": "1", | ||
238 | "teardown": [ | ||
239 | "$TC actions flush action skbmod" | ||
240 | ] | ||
241 | }, | ||
242 | { | ||
243 | "id": "7242", | ||
244 | "name": "Add skbmod action with control pass", | ||
245 | "category": [ | ||
246 | "actions", | ||
247 | "skbmod" | ||
248 | ], | ||
249 | "setup": [ | ||
250 | [ | ||
251 | "$TC actions flush action skbmod", | ||
252 | 0, | ||
253 | 1, | ||
254 | 255 | ||
255 | ] | ||
256 | ], | ||
257 | "cmdUnderTest": "$TC actions add action skbmod set smac 00:00:00:00:00:01 pass", | ||
258 | "expExitCode": "0", | ||
259 | "verifyCmd": "$TC actions ls action skbmod", | ||
260 | "matchPattern": "action order [0-9]*: skbmod pass set smac 00:00:00:00:00:01", | ||
261 | "matchCount": "1", | ||
262 | "teardown": [ | ||
263 | "$TC actions flush action skbmod" | ||
264 | ] | ||
265 | }, | ||
266 | { | ||
267 | "id": "58cb", | ||
268 | "name": "List skbmod actions", | ||
269 | "category": [ | ||
270 | "actions", | ||
271 | "skbmod" | ||
272 | ], | ||
273 | "setup": [ | ||
274 | [ | ||
275 | "$TC actions flush action skbmod", | ||
276 | 0, | ||
277 | 1, | ||
278 | 255 | ||
279 | ], | ||
280 | "$TC actions add action skbmod set etype 0x0001", | ||
281 | "$TC actions add action skbmod set etype 0x0011", | ||
282 | "$TC actions add action skbmod set etype 0x0021", | ||
283 | "$TC actions add action skbmod set etype 0x0031", | ||
284 | "$TC actions add action skbmod set etype 0x0041" | ||
285 | ], | ||
286 | "cmdUnderTest": "$TC actions ls action skbmod", | ||
287 | "expExitCode": "0", | ||
288 | "verifyCmd": "$TC actions ls action skbmod", | ||
289 | "matchPattern": "action order [0-9]*: skbmod", | ||
290 | "matchCount": "5", | ||
291 | "teardown": [ | ||
292 | "$TC actions flush action skbmod" | ||
293 | ] | ||
294 | }, | ||
295 | { | ||
296 | "id": "9aa8", | ||
297 | "name": "Get a single skbmod action from a list", | ||
298 | "category": [ | ||
299 | "actions", | ||
300 | "skbmod" | ||
301 | ], | ||
302 | "setup": [ | ||
303 | [ | ||
304 | "$TC actions flush action skbmod", | ||
305 | 0, | ||
306 | 1, | ||
307 | 255 | ||
308 | ], | ||
309 | "$TC actions add action skbmod set etype 0x0001", | ||
310 | "$TC actions add action skbmod set etype 0x0011", | ||
311 | "$TC actions add action skbmod set etype 0x0021", | ||
312 | "$TC actions add action skbmod set etype 0x0031", | ||
313 | "$TC actions add action skbmod set etype 0x0041" | ||
314 | ], | ||
315 | "cmdUnderTest": "$TC actions ls action skbmod", | ||
316 | "expExitCode": "0", | ||
317 | "verifyCmd": "$TC actions get action skbmod index 4", | ||
318 | "matchPattern": "action order [0-9]*: skbmod pipe set etype 0x0031", | ||
319 | "matchCount": "1", | ||
320 | "teardown": [ | ||
321 | "$TC actions flush action skbmod" | ||
322 | ] | ||
323 | }, | ||
324 | { | ||
325 | "id": "e93a", | ||
326 | "name": "Delete an skbmod action", | ||
327 | "category": [ | ||
328 | "actions", | ||
329 | "skbmod" | ||
330 | ], | ||
331 | "setup": [ | ||
332 | [ | ||
333 | "$TC actions flush action skbmod", | ||
334 | 0, | ||
335 | 1, | ||
336 | 255 | ||
337 | ], | ||
338 | "$TC actions add action skbmod set etype 0x1111 index 909" | ||
339 | ], | ||
340 | "cmdUnderTest": "$TC actions del action skbmod index 909", | ||
341 | "expExitCode": "0", | ||
342 | "verifyCmd": "$TC actions ls action skbmod", | ||
343 | "matchPattern": "action order [0-9]*: skbmod pipe set etype 0x1111\\s+index 909", | ||
344 | "matchCount": "0", | ||
345 | "teardown": [ | ||
346 | "$TC actions flush action skbmod" | ||
347 | ] | ||
348 | }, | ||
349 | { | ||
350 | "id": "40c2", | ||
351 | "name": "Flush skbmod actions", | ||
352 | "category": [ | ||
353 | "actions", | ||
354 | "skbmod" | ||
355 | ], | ||
356 | "setup": [ | ||
357 | "$TC actions add action skbmod set etype 0x0001", | ||
358 | "$TC actions add action skbmod set etype 0x0011", | ||
359 | "$TC actions add action skbmod set etype 0x0021", | ||
360 | "$TC actions add action skbmod set etype 0x0031", | ||
361 | "$TC actions add action skbmod set etype 0x0041" | ||
362 | ], | ||
363 | "cmdUnderTest": "$TC actions flush action skbmod", | ||
364 | "expExitCode": "0", | ||
365 | "verifyCmd": "$TC actions ls action skbmod", | ||
366 | "matchPattern": "action order [0-9]*: skbmod", | ||
367 | "matchCount": "0", | ||
368 | "teardown": [ | ||
369 | "$TC actions flush action skbmod" | ||
370 | ] | ||
371 | } | ||
372 | ] | ||
diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/tests.json b/tools/testing/selftests/tc-testing/tc-tests/actions/tests.json deleted file mode 100644 index 6973bdc5b5bf..000000000000 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/tests.json +++ /dev/null | |||
@@ -1,1165 +0,0 @@ | |||
1 | [ | ||
2 | { | ||
3 | "id": "e89a", | ||
4 | "name": "Add valid pass action", | ||
5 | "category": [ | ||
6 | "actions", | ||
7 | "gact" | ||
8 | ], | ||
9 | "setup": [ | ||
10 | [ | ||
11 | "$TC actions flush action gact", | ||
12 | 0, | ||
13 | 1, | ||
14 | 255 | ||
15 | ] | ||
16 | ], | ||
17 | "cmdUnderTest": "$TC actions add action pass index 8", | ||
18 | "expExitCode": "0", | ||
19 | "verifyCmd": "$TC actions list action gact", | ||
20 | "matchPattern": "action order [0-9]*: gact action pass.*index 8 ref", | ||
21 | "matchCount": "1", | ||
22 | "teardown": [ | ||
23 | "$TC actions flush action gact" | ||
24 | ] | ||
25 | }, | ||
26 | { | ||
27 | "id": "a02c", | ||
28 | "name": "Add valid pipe action", | ||
29 | "category": [ | ||
30 | "actions", | ||
31 | "gact" | ||
32 | ], | ||
33 | "setup": [ | ||
34 | [ | ||
35 | "$TC actions flush action gact", | ||
36 | 0, | ||
37 | 1, | ||
38 | 255 | ||
39 | ] | ||
40 | ], | ||
41 | "cmdUnderTest": "$TC actions add action pipe index 6", | ||
42 | "expExitCode": "0", | ||
43 | "verifyCmd": "$TC actions list action gact", | ||
44 | "matchPattern": "action order [0-9]*: gact action pipe.*index 6 ref", | ||
45 | "matchCount": "1", | ||
46 | "teardown": [ | ||
47 | "$TC actions flush action gact" | ||
48 | ] | ||
49 | }, | ||
50 | { | ||
51 | "id": "feef", | ||
52 | "name": "Add valid reclassify action", | ||
53 | "category": [ | ||
54 | "actions", | ||
55 | "gact" | ||
56 | ], | ||
57 | "setup": [ | ||
58 | [ | ||
59 | "$TC actions flush action gact", | ||
60 | 0, | ||
61 | 1, | ||
62 | 255 | ||
63 | ] | ||
64 | ], | ||
65 | "cmdUnderTest": "$TC actions add action reclassify index 5", | ||
66 | "expExitCode": "0", | ||
67 | "verifyCmd": "$TC actions list action gact", | ||
68 | "matchPattern": "action order [0-9]*: gact action reclassify.*index 5 ref", | ||
69 | "matchCount": "1", | ||
70 | "teardown": [ | ||
71 | "$TC actions flush action gact" | ||
72 | ] | ||
73 | }, | ||
74 | { | ||
75 | "id": "8a7a", | ||
76 | "name": "Add valid drop action", | ||
77 | "category": [ | ||
78 | "actions", | ||
79 | "gact" | ||
80 | ], | ||
81 | "setup": [ | ||
82 | [ | ||
83 | "$TC actions flush action gact", | ||
84 | 0, | ||
85 | 1, | ||
86 | 255 | ||
87 | ] | ||
88 | ], | ||
89 | "cmdUnderTest": "$TC actions add action drop index 30", | ||
90 | "expExitCode": "0", | ||
91 | "verifyCmd": "$TC actions list action gact", | ||
92 | "matchPattern": "action order [0-9]*: gact action drop.*index 30 ref", | ||
93 | "matchCount": "1", | ||
94 | "teardown": [ | ||
95 | "$TC actions flush action gact" | ||
96 | ] | ||
97 | }, | ||
98 | { | ||
99 | "id": "9a52", | ||
100 | "name": "Add valid continue action", | ||
101 | "category": [ | ||
102 | "actions", | ||
103 | "gact" | ||
104 | ], | ||
105 | "setup": [ | ||
106 | [ | ||
107 | "$TC actions flush action gact", | ||
108 | 0, | ||
109 | 1, | ||
110 | 255 | ||
111 | ] | ||
112 | ], | ||
113 | "cmdUnderTest": "$TC actions add action continue index 432", | ||
114 | "expExitCode": "0", | ||
115 | "verifyCmd": "$TC actions list action gact", | ||
116 | "matchPattern": "action order [0-9]*: gact action continue.*index 432 ref", | ||
117 | "matchCount": "1", | ||
118 | "teardown": [ | ||
119 | "$TC actions flush action gact" | ||
120 | ] | ||
121 | }, | ||
122 | { | ||
123 | "id": "d700", | ||
124 | "name": "Add invalid action", | ||
125 | "category": [ | ||
126 | "actions", | ||
127 | "gact" | ||
128 | ], | ||
129 | "setup": [ | ||
130 | [ | ||
131 | "$TC actions flush action gact", | ||
132 | 0, | ||
133 | 1, | ||
134 | 255 | ||
135 | ] | ||
136 | ], | ||
137 | "cmdUnderTest": "$TC actions add action pump index 386", | ||
138 | "expExitCode": "255", | ||
139 | "verifyCmd": "$TC actions list action gact", | ||
140 | "matchPattern": "action order [0-9]*: gact action.*index 386 ref", | ||
141 | "matchCount": "0", | ||
142 | "teardown": [ | ||
143 | "$TC actions flush action gact" | ||
144 | ] | ||
145 | }, | ||
146 | { | ||
147 | "id": "9215", | ||
148 | "name": "Add action with duplicate index", | ||
149 | "category": [ | ||
150 | "actions", | ||
151 | "gact" | ||
152 | ], | ||
153 | "setup": [ | ||
154 | [ | ||
155 | "$TC actions flush action gact", | ||
156 | 0, | ||
157 | 1, | ||
158 | 255 | ||
159 | ], | ||
160 | "$TC actions add action pipe index 15" | ||
161 | ], | ||
162 | "cmdUnderTest": "$TC actions add action drop index 15", | ||
163 | "expExitCode": "255", | ||
164 | "verifyCmd": "$TC actions list action gact", | ||
165 | "matchPattern": "action order [0-9]*: gact action drop.*index 15 ref", | ||
166 | "matchCount": "0", | ||
167 | "teardown": [ | ||
168 | "$TC actions flush action gact" | ||
169 | ] | ||
170 | }, | ||
171 | { | ||
172 | "id": "798e", | ||
173 | "name": "Add action with index exceeding 32-bit maximum", | ||
174 | "category": [ | ||
175 | "actions", | ||
176 | "gact" | ||
177 | ], | ||
178 | "setup": [ | ||
179 | [ | ||
180 | "$TC actions flush action gact", | ||
181 | 0, | ||
182 | 1, | ||
183 | 255 | ||
184 | ] | ||
185 | ], | ||
186 | "cmdUnderTest": "$TC actions add action drop index 4294967296", | ||
187 | "expExitCode": "255", | ||
188 | "verifyCmd": "actions list action gact", | ||
189 | "matchPattern": "action order [0-9]*: gact action drop.*index 4294967296 ref", | ||
190 | "matchCount": "0", | ||
191 | "teardown": [ | ||
192 | "$TC actions flush action gact" | ||
193 | ] | ||
194 | }, | ||
195 | { | ||
196 | "id": "22be", | ||
197 | "name": "Add action with index at 32-bit maximum", | ||
198 | "category": [ | ||
199 | "actions", | ||
200 | "gact" | ||
201 | ], | ||
202 | "setup": [ | ||
203 | [ | ||
204 | "$TC actions flush action gact", | ||
205 | 0, | ||
206 | 1, | ||
207 | 255 | ||
208 | ] | ||
209 | ], | ||
210 | "cmdUnderTest": "$TC actions add action drop index 4294967295", | ||
211 | "expExitCode": "0", | ||
212 | "verifyCmd": "$TC actions list action gact", | ||
213 | "matchPattern": "action order [0-9]*: gact action drop.*index 4294967295 ref", | ||
214 | "matchCount": "1", | ||
215 | "teardown": [ | ||
216 | "$TC actions flush action gact" | ||
217 | ] | ||
218 | }, | ||
219 | { | ||
220 | "id": "ac2a", | ||
221 | "name": "List actions", | ||
222 | "category": [ | ||
223 | "actions", | ||
224 | "gact" | ||
225 | ], | ||
226 | "setup": [ | ||
227 | [ | ||
228 | "$TC actions flush action gact", | ||
229 | 0, | ||
230 | 1, | ||
231 | 255 | ||
232 | ], | ||
233 | "$TC actions add action reclassify index 101", | ||
234 | "$TC actions add action reclassify index 102", | ||
235 | "$TC actions add action reclassify index 103", | ||
236 | "$TC actions add action reclassify index 104", | ||
237 | "$TC actions add action reclassify index 105" | ||
238 | ], | ||
239 | "cmdUnderTest": "$TC actions list action gact", | ||
240 | "expExitCode": "0", | ||
241 | "verifyCmd": "$TC actions list action gact", | ||
242 | "matchPattern": "action order [0-9]*: gact action reclassify", | ||
243 | "matchCount": "5", | ||
244 | "teardown": [ | ||
245 | "$TC actions flush action gact" | ||
246 | ] | ||
247 | }, | ||
248 | { | ||
249 | "id": "63ec", | ||
250 | "name": "Delete pass action", | ||
251 | "category": [ | ||
252 | "actions", | ||
253 | "gact" | ||
254 | ], | ||
255 | "setup": [ | ||
256 | [ | ||
257 | "$TC actions flush action gact", | ||
258 | 0, | ||
259 | 1, | ||
260 | 255 | ||
261 | ], | ||
262 | "$TC actions add action pass index 1" | ||
263 | ], | ||
264 | "cmdUnderTest": "$TC actions del action gact index 1", | ||
265 | "expExitCode": "0", | ||
266 | "verifyCmd": "$TC actions list action gact", | ||
267 | "matchPattern": "action order [0-9]*: gact action pass.*index 1 ref", | ||
268 | "matchCount": "0", | ||
269 | "teardown": [ | ||
270 | "$TC actions flush action gact" | ||
271 | ] | ||
272 | }, | ||
273 | { | ||
274 | "id": "46be", | ||
275 | "name": "Delete pipe action", | ||
276 | "category": [ | ||
277 | "actions", | ||
278 | "gact" | ||
279 | ], | ||
280 | "setup": [ | ||
281 | [ | ||
282 | "$TC actions flush action gact", | ||
283 | 0, | ||
284 | 1, | ||
285 | 255 | ||
286 | ], | ||
287 | "$TC actions add action pipe index 9" | ||
288 | ], | ||
289 | "cmdUnderTest": "$TC actions del action gact index 9", | ||
290 | "expExitCode": "0", | ||
291 | "verifyCmd": "$TC actions list action gact", | ||
292 | "matchPattern": "action order [0-9]*: gact action pipe.*index 9 ref", | ||
293 | "matchCount": "0", | ||
294 | "teardown": [ | ||
295 | "$TC actions flush action gact" | ||
296 | ] | ||
297 | }, | ||
298 | { | ||
299 | "id": "2e08", | ||
300 | "name": "Delete reclassify action", | ||
301 | "category": [ | ||
302 | "actions", | ||
303 | "gact" | ||
304 | ], | ||
305 | "setup": [ | ||
306 | [ | ||
307 | "$TC actions flush action gact", | ||
308 | 0, | ||
309 | 1, | ||
310 | 255 | ||
311 | ], | ||
312 | "$TC actions add action reclassify index 65536" | ||
313 | ], | ||
314 | "cmdUnderTest": "$TC actions del action gact index 65536", | ||
315 | "expExitCode": "0", | ||
316 | "verifyCmd": "$TC actions list action gact", | ||
317 | "matchPattern": "action order [0-9]*: gact action reclassify.*index 65536 ref", | ||
318 | "matchCount": "0", | ||
319 | "teardown": [ | ||
320 | "$TC actions flush action gact" | ||
321 | ] | ||
322 | }, | ||
323 | { | ||
324 | "id": "99c4", | ||
325 | "name": "Delete drop action", | ||
326 | "category": [ | ||
327 | "actions", | ||
328 | "gact" | ||
329 | ], | ||
330 | "setup": [ | ||
331 | [ | ||
332 | "$TC actions flush action gact", | ||
333 | 0, | ||
334 | 1, | ||
335 | 255 | ||
336 | ], | ||
337 | "$TC actions add action drop index 16" | ||
338 | ], | ||
339 | "cmdUnderTest": "$TC actions del action gact index 16", | ||
340 | "expExitCode": "0", | ||
341 | "verifyCmd": "$TC actions list action gact", | ||
342 | "matchPattern": "action order [0-9]*: gact action drop.*index 16 ref", | ||
343 | "matchCount": "0", | ||
344 | "teardown": [ | ||
345 | "$TC actions flush action gact" | ||
346 | ] | ||
347 | }, | ||
348 | { | ||
349 | "id": "fb6b", | ||
350 | "name": "Delete continue action", | ||
351 | "category": [ | ||
352 | "actions", | ||
353 | "gact" | ||
354 | ], | ||
355 | "setup": [ | ||
356 | [ | ||
357 | "$TC actions flush action gact", | ||
358 | 0, | ||
359 | 1, | ||
360 | 255 | ||
361 | ], | ||
362 | "$TC actions add action continue index 32" | ||
363 | ], | ||
364 | "cmdUnderTest": "$TC actions del action gact index 32", | ||
365 | "expExitCode": "0", | ||
366 | "verifyCmd": "actions list action gact", | ||
367 | "matchPattern": "action order [0-9]*: gact action continue.*index 32 ref", | ||
368 | "matchCount": "0", | ||
369 | "teardown": [ | ||
370 | "$TC actions flush action gact" | ||
371 | ] | ||
372 | }, | ||
373 | { | ||
374 | "id": "0eb3", | ||
375 | "name": "Delete non-existent action", | ||
376 | "category": [ | ||
377 | "actions", | ||
378 | "gact" | ||
379 | ], | ||
380 | "setup": [ | ||
381 | [ | ||
382 | "$TC actions flush action gact", | ||
383 | 0, | ||
384 | 1, | ||
385 | 255 | ||
386 | ] | ||
387 | ], | ||
388 | "cmdUnderTest": "$TC actions del action gact index 2", | ||
389 | "expExitCode": "255", | ||
390 | "verifyCmd": "$TC actions list action gact", | ||
391 | "matchPattern": "action order [0-9]*: gact action", | ||
392 | "matchCount": "0", | ||
393 | "teardown": [ | ||
394 | "$TC actions flush action gact" | ||
395 | ] | ||
396 | }, | ||
397 | { | ||
398 | "id": "5124", | ||
399 | "name": "Add mirred mirror to egress action", | ||
400 | "category": [ | ||
401 | "actions", | ||
402 | "mirred" | ||
403 | ], | ||
404 | "setup": [ | ||
405 | [ | ||
406 | "$TC actions flush action mirred", | ||
407 | 0, | ||
408 | 1, | ||
409 | 255 | ||
410 | ] | ||
411 | ], | ||
412 | "cmdUnderTest": "$TC actions add action mirred egress mirror index 1 dev lo", | ||
413 | "expExitCode": "0", | ||
414 | "verifyCmd": "$TC actions list action mirred", | ||
415 | "matchPattern": "action order [0-9]*: mirred \\(Egress Mirror to device lo\\).*index 1 ref", | ||
416 | "matchCount": "1", | ||
417 | "teardown": [ | ||
418 | "$TC actions flush action mirred" | ||
419 | ] | ||
420 | }, | ||
421 | { | ||
422 | "id": "6fb4", | ||
423 | "name": "Add mirred redirect to egress action", | ||
424 | "category": [ | ||
425 | "actions", | ||
426 | "mirred" | ||
427 | ], | ||
428 | "setup": [ | ||
429 | [ | ||
430 | "$TC actions flush action mirred", | ||
431 | 0, | ||
432 | 1, | ||
433 | 255 | ||
434 | ] | ||
435 | ], | ||
436 | "cmdUnderTest": "$TC actions add action mirred egress redirect index 2 dev lo action pipe", | ||
437 | "expExitCode": "0", | ||
438 | "verifyCmd": "$TC actions list action mirred", | ||
439 | "matchPattern": "action order [0-9]*: mirred \\(Egress Redirect to device lo\\).*index 2 ref", | ||
440 | "matchCount": "1", | ||
441 | "teardown": [ | ||
442 | "$TC actions flush action mirred" | ||
443 | ] | ||
444 | }, | ||
445 | { | ||
446 | "id": "ba38", | ||
447 | "name": "Get mirred actions", | ||
448 | "category": [ | ||
449 | "actions", | ||
450 | "mirred" | ||
451 | ], | ||
452 | "setup": [ | ||
453 | [ | ||
454 | "$TC actions flush action mirred", | ||
455 | 0, | ||
456 | 1, | ||
457 | 255 | ||
458 | ], | ||
459 | "$TC actions add action mirred egress mirror index 1 dev lo", | ||
460 | "$TC actions add action mirred egress redirect index 2 dev lo" | ||
461 | ], | ||
462 | "cmdUnderTest": "$TC actions show action mirred", | ||
463 | "expExitCode": "0", | ||
464 | "verifyCmd": "$TC actions list action mirred", | ||
465 | "matchPattern": "[Mirror|Redirect] to device lo", | ||
466 | "matchCount": "2", | ||
467 | "teardown": [ | ||
468 | "$TC actions flush action mirred" | ||
469 | ] | ||
470 | }, | ||
471 | { | ||
472 | "id": "d7c0", | ||
473 | "name": "Add invalid mirred direction", | ||
474 | "category": [ | ||
475 | "actions", | ||
476 | "mirred" | ||
477 | ], | ||
478 | "setup": [ | ||
479 | [ | ||
480 | "$TC actions flush action mirred", | ||
481 | 0, | ||
482 | 1, | ||
483 | 255 | ||
484 | ] | ||
485 | ], | ||
486 | "cmdUnderTest": "$TC actions add action mirred inbound mirror index 20 dev lo", | ||
487 | "expExitCode": "255", | ||
488 | "verifyCmd": "$TC actions list action mirred", | ||
489 | "matchPattern": "action order [0-9]*: mirred \\(.*to device lo\\).*index 20 ref", | ||
490 | "matchCount": "0", | ||
491 | "teardown": [ | ||
492 | "$TC actions flush action mirred" | ||
493 | ] | ||
494 | }, | ||
495 | { | ||
496 | "id": "e213", | ||
497 | "name": "Add invalid mirred action", | ||
498 | "category": [ | ||
499 | "actions", | ||
500 | "mirred" | ||
501 | ], | ||
502 | "setup": [ | ||
503 | [ | ||
504 | "$TC actions flush action mirred", | ||
505 | 0, | ||
506 | 1, | ||
507 | 255 | ||
508 | ] | ||
509 | ], | ||
510 | "cmdUnderTest": "$TC actions add action mirred egress remirror index 20 dev lo", | ||
511 | "expExitCode": "255", | ||
512 | "verifyCmd": "$TC actions list action mirred", | ||
513 | "matchPattern": "action order [0-9]*: mirred \\(Egress.*to device lo\\).*index 20 ref", | ||
514 | "matchCount": "0", | ||
515 | "teardown": [ | ||
516 | "$TC actions flush action mirred" | ||
517 | ] | ||
518 | }, | ||
519 | { | ||
520 | "id": "2d89", | ||
521 | "name": "Add mirred action with invalid device", | ||
522 | "category": [ | ||
523 | "actions", | ||
524 | "mirred" | ||
525 | ], | ||
526 | "setup": [ | ||
527 | [ | ||
528 | "$TC actions flush action mirred", | ||
529 | 0, | ||
530 | 1, | ||
531 | 255 | ||
532 | ] | ||
533 | ], | ||
534 | "cmdUnderTest": "$TC actions add action mirred egress mirror index 20 dev eltoh", | ||
535 | "expExitCode": "255", | ||
536 | "verifyCmd": "$TC actions list action mirred", | ||
537 | "matchPattern": "action order [0-9]*: mirred \\(.*to device eltoh\\).*index 20 ref", | ||
538 | "matchCount": "0", | ||
539 | "teardown": [ | ||
540 | "$TC actions flush action mirred" | ||
541 | ] | ||
542 | }, | ||
543 | { | ||
544 | "id": "300b", | ||
545 | "name": "Add mirred action with duplicate index", | ||
546 | "category": [ | ||
547 | "actions", | ||
548 | "mirred" | ||
549 | ], | ||
550 | "setup": [ | ||
551 | [ | ||
552 | "$TC actions flush action mirred", | ||
553 | 0, | ||
554 | 1, | ||
555 | 255 | ||
556 | ], | ||
557 | "$TC actions add action mirred egress redirect index 15 dev lo" | ||
558 | ], | ||
559 | "cmdUnderTest": "$TC actions add action mirred egress mirror index 15 dev lo", | ||
560 | "expExitCode": "255", | ||
561 | "verifyCmd": "$TC actions list action mirred", | ||
562 | "matchPattern": "action order [0-9]*: mirred \\(.*to device lo\\).*index 15 ref", | ||
563 | "matchCount": "1", | ||
564 | "teardown": [ | ||
565 | "$TC actions flush action mirred" | ||
566 | ] | ||
567 | }, | ||
568 | { | ||
569 | "id": "a70e", | ||
570 | "name": "Delete mirred mirror action", | ||
571 | "category": [ | ||
572 | "actions", | ||
573 | "mirred" | ||
574 | ], | ||
575 | "setup": [ | ||
576 | [ | ||
577 | "$TC actions flush action mirred", | ||
578 | 0, | ||
579 | 1, | ||
580 | 255 | ||
581 | ], | ||
582 | "$TC actions add action mirred egress mirror index 5 dev lo" | ||
583 | ], | ||
584 | "cmdUnderTest": "$TC actions del action mirred index 5", | ||
585 | "expExitCode": "0", | ||
586 | "verifyCmd": "$TC actions list action mirred", | ||
587 | "matchPattern": "action order [0-9]*: mirred \\(Egress Mirror to device lo\\).*index 5 ref", | ||
588 | "matchCount": "0", | ||
589 | "teardown": [ | ||
590 | "$TC actions flush action mirred" | ||
591 | ] | ||
592 | }, | ||
593 | { | ||
594 | "id": "3fb3", | ||
595 | "name": "Delete mirred redirect action", | ||
596 | "category": [ | ||
597 | "actions", | ||
598 | "mirred" | ||
599 | ], | ||
600 | "setup": [ | ||
601 | [ | ||
602 | "$TC actions flush action mirred", | ||
603 | 0, | ||
604 | 1, | ||
605 | 255 | ||
606 | ], | ||
607 | "$TC actions add action mirred egress redirect index 5 dev lo" | ||
608 | ], | ||
609 | "cmdUnderTest": "$TC actions del action mirred index 5", | ||
610 | "expExitCode": "0", | ||
611 | "verifyCmd": "$TC actions list action mirred", | ||
612 | "matchPattern": "action order [0-9]*: mirred \\(Egress Redirect to device lo\\).*index 5 ref", | ||
613 | "matchCount": "0", | ||
614 | "teardown": [ | ||
615 | "$TC actions flush action mirred" | ||
616 | ] | ||
617 | }, | ||
618 | { | ||
619 | "id": "b078", | ||
620 | "name": "Add simple action", | ||
621 | "category": [ | ||
622 | "actions", | ||
623 | "simple" | ||
624 | ], | ||
625 | "setup": [ | ||
626 | [ | ||
627 | "$TC actions flush action simple", | ||
628 | 0, | ||
629 | 1, | ||
630 | 255 | ||
631 | ] | ||
632 | ], | ||
633 | "cmdUnderTest": "$TC actions add action simple sdata \"A triumph\" index 60", | ||
634 | "expExitCode": "0", | ||
635 | "verifyCmd": "$TC actions list action simple", | ||
636 | "matchPattern": "action order [0-9]*: Simple <A triumph>.*index 60 ref", | ||
637 | "matchCount": "1", | ||
638 | "teardown": [ | ||
639 | "$TC actions flush action simple" | ||
640 | ] | ||
641 | }, | ||
642 | { | ||
643 | "id": "6d4c", | ||
644 | "name": "Add simple action with duplicate index", | ||
645 | "category": [ | ||
646 | "actions", | ||
647 | "simple" | ||
648 | ], | ||
649 | "setup": [ | ||
650 | [ | ||
651 | "$TC actions flush action simple", | ||
652 | 0, | ||
653 | 1, | ||
654 | 255 | ||
655 | ], | ||
656 | "$TC actions add action simple sdata \"Aruba\" index 4" | ||
657 | ], | ||
658 | "cmdUnderTest": "$TC actions add action simple sdata \"Jamaica\" index 4", | ||
659 | "expExitCode": "255", | ||
660 | "verifyCmd": "$TC actions list action simple", | ||
661 | "matchPattern": "action order [0-9]*: Simple <Jamaica>.*ref", | ||
662 | "matchCount": "0", | ||
663 | "teardown": [ | ||
664 | "$TC actions flush action simple" | ||
665 | ] | ||
666 | }, | ||
667 | { | ||
668 | "id": "2542", | ||
669 | "name": "List simple actions", | ||
670 | "category": [ | ||
671 | "actions", | ||
672 | "simple" | ||
673 | ], | ||
674 | "setup": [ | ||
675 | [ | ||
676 | "$TC actions flush action simple", | ||
677 | 0, | ||
678 | 1, | ||
679 | 255 | ||
680 | ], | ||
681 | "$TC actions add action simple sdata \"Rock\"", | ||
682 | "$TC actions add action simple sdata \"Paper\"", | ||
683 | "$TC actions add action simple sdata \"Scissors\" index 98" | ||
684 | ], | ||
685 | "cmdUnderTest": "$TC actions list action simple", | ||
686 | "expExitCode": "0", | ||
687 | "verifyCmd": "$TC actions list action simple", | ||
688 | "matchPattern": "action order [0-9]*: Simple <[A-Z][a-z]*>", | ||
689 | "matchCount": "3", | ||
690 | "teardown": [ | ||
691 | "$TC actions flush action simple" | ||
692 | ] | ||
693 | }, | ||
694 | { | ||
695 | "id": "ea67", | ||
696 | "name": "Delete simple action", | ||
697 | "category": [ | ||
698 | "actions", | ||
699 | "simple" | ||
700 | ], | ||
701 | "setup": [ | ||
702 | [ | ||
703 | "$TC actions flush action simple", | ||
704 | 0, | ||
705 | 1, | ||
706 | 255 | ||
707 | ], | ||
708 | "$TC actions add action simple sdata \"Blinkenlights\" index 1" | ||
709 | ], | ||
710 | "cmdUnderTest": "$TC actions delete action simple index 1", | ||
711 | "expExitCode": "0", | ||
712 | "verifyCmd": "$TC actions list action simple", | ||
713 | "matchPattern": "action order [0-9]*: Simple <Blinkenlights>.*index 1 ref", | ||
714 | "matchCount": "0", | ||
715 | "teardown": [ | ||
716 | "$TC actions flush action simple" | ||
717 | ] | ||
718 | }, | ||
719 | { | ||
720 | "id": "8ff1", | ||
721 | "name": "Flush simple actions", | ||
722 | "category": [ | ||
723 | "actions", | ||
724 | "simple" | ||
725 | ], | ||
726 | "setup": [ | ||
727 | [ | ||
728 | "$TC actions flush action simple", | ||
729 | 0, | ||
730 | 1, | ||
731 | 255 | ||
732 | ], | ||
733 | "$TC actions add action simple sdata \"Kirk\"", | ||
734 | "$TC actions add action simple sdata \"Spock\" index 50", | ||
735 | "$TC actions add action simple sdata \"McCoy\" index 9" | ||
736 | ], | ||
737 | "cmdUnderTest": "$TC actions flush action simple", | ||
738 | "expExitCode": "0", | ||
739 | "verifyCmd": "$TC actions list action simple", | ||
740 | "matchPattern": "action order [0-9]*: Simple <[A-Z][a-z]*>", | ||
741 | "matchCount": "0", | ||
742 | "teardown": [ | ||
743 | "" | ||
744 | ] | ||
745 | }, | ||
746 | { | ||
747 | "id": "6236", | ||
748 | "name": "Add skbedit action with valid mark", | ||
749 | "category": [ | ||
750 | "actions", | ||
751 | "skbedit" | ||
752 | ], | ||
753 | "setup": [ | ||
754 | [ | ||
755 | "$TC actions flush action skbedit", | ||
756 | 0, | ||
757 | 1, | ||
758 | 255 | ||
759 | ] | ||
760 | ], | ||
761 | "cmdUnderTest": "$TC actions add action skbedit mark 1", | ||
762 | "expExitCode": "0", | ||
763 | "verifyCmd": "$TC actions list action skbedit", | ||
764 | "matchPattern": "action order [0-9]*: skbedit mark 1", | ||
765 | "matchCount": "1", | ||
766 | "teardown": [ | ||
767 | "$TC actions flush action skbedit" | ||
768 | ] | ||
769 | }, | ||
770 | { | ||
771 | "id": "407b", | ||
772 | "name": "Add skbedit action with invalid mark", | ||
773 | "category": [ | ||
774 | "actions", | ||
775 | "skbedit" | ||
776 | ], | ||
777 | "setup": [ | ||
778 | [ | ||
779 | "$TC actions flush action skbedit", | ||
780 | 0, | ||
781 | 1, | ||
782 | 255 | ||
783 | ] | ||
784 | ], | ||
785 | "cmdUnderTest": "$TC actions add action skbedit mark 666777888999", | ||
786 | "expExitCode": "255", | ||
787 | "verifyCmd": "$TC actions list action skbedit", | ||
788 | "matchPattern": "action order [0-9]*: skbedit mark", | ||
789 | "matchCount": "0", | ||
790 | "teardown": [ | ||
791 | "$TC actions flush action skbedit" | ||
792 | ] | ||
793 | }, | ||
794 | { | ||
795 | "id": "081d", | ||
796 | "name": "Add skbedit action with priority", | ||
797 | "category": [ | ||
798 | "actions", | ||
799 | "skbedit" | ||
800 | ], | ||
801 | "setup": [ | ||
802 | [ | ||
803 | "$TC actions flush action skbedit", | ||
804 | 0, | ||
805 | 1, | ||
806 | 255 | ||
807 | ] | ||
808 | ], | ||
809 | "cmdUnderTest": "$TC actions add action skbedit prio 99", | ||
810 | "expExitCode": "0", | ||
811 | "verifyCmd": "$TC actions list action skbedit", | ||
812 | "matchPattern": "action order [0-9]*: skbedit priority :99", | ||
813 | "matchCount": "1", | ||
814 | "teardown": [ | ||
815 | "$TC actions flush action skbedit" | ||
816 | ] | ||
817 | }, | ||
818 | { | ||
819 | "id": "cc37", | ||
820 | "name": "Add skbedit action with invalid priority", | ||
821 | "category": [ | ||
822 | "actions", | ||
823 | "skbedit" | ||
824 | ], | ||
825 | "setup": [ | ||
826 | [ | ||
827 | "$TC actions flush action skbedit", | ||
828 | 0, | ||
829 | 1, | ||
830 | 255 | ||
831 | ] | ||
832 | ], | ||
833 | "cmdUnderTest": "$TC actions add action skbedit prio foo", | ||
834 | "expExitCode": "255", | ||
835 | "verifyCmd": "$TC actions list action skbedit", | ||
836 | "matchPattern": "action order [0-9]*: skbedit priority", | ||
837 | "matchCount": "0", | ||
838 | "teardown": [ | ||
839 | "$TC actions flush action skbedit" | ||
840 | ] | ||
841 | }, | ||
842 | { | ||
843 | "id": "3c95", | ||
844 | "name": "Add skbedit action with queue_mapping", | ||
845 | "category": [ | ||
846 | "actions", | ||
847 | "skbedit" | ||
848 | ], | ||
849 | "setup": [ | ||
850 | [ | ||
851 | "$TC actions flush action skbedit", | ||
852 | 0, | ||
853 | 1, | ||
854 | 255 | ||
855 | ] | ||
856 | ], | ||
857 | "cmdUnderTest": "$TC actions add action skbedit queue_mapping 909", | ||
858 | "expExitCode": "0", | ||
859 | "verifyCmd": "$TC actions list action skbedit", | ||
860 | "matchPattern": "action order [0-9]*: skbedit queue_mapping 909", | ||
861 | "matchCount": "1", | ||
862 | "teardown": [ | ||
863 | "$TC actions flush action skbedit" | ||
864 | ] | ||
865 | }, | ||
866 | { | ||
867 | "id": "985c", | ||
868 | "name": "Add skbedit action with invalid queue_mapping", | ||
869 | "category": [ | ||
870 | "actions", | ||
871 | "skbedit" | ||
872 | ], | ||
873 | "setup": [ | ||
874 | [ | ||
875 | "$TC actions flush action skbedit", | ||
876 | 0, | ||
877 | 1, | ||
878 | 255 | ||
879 | ] | ||
880 | ], | ||
881 | "cmdUnderTest": "$TC actions add action skbedit queue_mapping 67000", | ||
882 | "expExitCode": "255", | ||
883 | "verifyCmd": "$TC actions list action skbedit", | ||
884 | "matchPattern": "action order [0-9]*: skbedit queue_mapping", | ||
885 | "matchCount": "0", | ||
886 | "teardown": [ | ||
887 | "$TC actions flush action skbedit" | ||
888 | ] | ||
889 | }, | ||
890 | { | ||
891 | "id": "224f", | ||
892 | "name": "Add skbedit action with ptype host", | ||
893 | "category": [ | ||
894 | "actions", | ||
895 | "skbedit" | ||
896 | ], | ||
897 | "setup": [ | ||
898 | [ | ||
899 | "$TC actions flush action skbedit", | ||
900 | 0, | ||
901 | 1, | ||
902 | 255 | ||
903 | ] | ||
904 | ], | ||
905 | "cmdUnderTest": "$TC actions add action skbedit ptype host", | ||
906 | "expExitCode": "0", | ||
907 | "verifyCmd": "$TC actions list action skbedit", | ||
908 | "matchPattern": "action order [0-9]*: skbedit ptype host", | ||
909 | "matchCount": "1", | ||
910 | "teardown": [ | ||
911 | "$TC actions flush action skbedit" | ||
912 | ] | ||
913 | }, | ||
914 | { | ||
915 | "id": "d1a3", | ||
916 | "name": "Add skbedit action with ptype otherhost", | ||
917 | "category": [ | ||
918 | "actions", | ||
919 | "skbedit" | ||
920 | ], | ||
921 | "setup": [ | ||
922 | [ | ||
923 | "$TC actions flush action skbedit", | ||
924 | 0, | ||
925 | 1, | ||
926 | 255 | ||
927 | ] | ||
928 | ], | ||
929 | "cmdUnderTest": "$TC actions add action skbedit ptype otherhost", | ||
930 | "expExitCode": "0", | ||
931 | "verifyCmd": "$TC actions list action skbedit", | ||
932 | "matchPattern": "action order [0-9]*: skbedit ptype otherhost", | ||
933 | "matchCount": "1", | ||
934 | "teardown": [ | ||
935 | "$TC actions flush action skbedit" | ||
936 | ] | ||
937 | }, | ||
938 | { | ||
939 | "id": "b9c6", | ||
940 | "name": "Add skbedit action with invalid ptype", | ||
941 | "category": [ | ||
942 | "actions", | ||
943 | "skbedit" | ||
944 | ], | ||
945 | "setup": [ | ||
946 | [ | ||
947 | "$TC actions flush action skbedit", | ||
948 | 0, | ||
949 | 1, | ||
950 | 255 | ||
951 | ] | ||
952 | ], | ||
953 | "cmdUnderTest": "$TC actions add action skbedit ptype openair", | ||
954 | "expExitCode": "255", | ||
955 | "verifyCmd": "$TC actions list action skbedit", | ||
956 | "matchPattern": "action order [0-9]*: skbedit ptype openair", | ||
957 | "matchCount": "0", | ||
958 | "teardown": [ | ||
959 | "$TC actions flush action skbedit" | ||
960 | ] | ||
961 | }, | ||
962 | { | ||
963 | "id": "5172", | ||
964 | "name": "List skbedit actions", | ||
965 | "category": [ | ||
966 | "actions", | ||
967 | "skbedit" | ||
968 | ], | ||
969 | "setup": [ | ||
970 | [ | ||
971 | "$TC actions flush action skbedit", | ||
972 | 0, | ||
973 | 1, | ||
974 | 255 | ||
975 | ], | ||
976 | "$TC actions add action skbedit ptype otherhost", | ||
977 | "$TC actions add action skbedit ptype broadcast", | ||
978 | "$TC actions add action skbedit mark 59", | ||
979 | "$TC actions add action skbedit mark 409" | ||
980 | ], | ||
981 | "cmdUnderTest": "$TC actions list action skbedit", | ||
982 | "expExitCode": "0", | ||
983 | "verifyCmd": "$TC actions list action skbedit", | ||
984 | "matchPattern": "action order [0-9]*: skbedit", | ||
985 | "matchCount": "4", | ||
986 | "teardown": [ | ||
987 | "$TC actions flush action skbedit" | ||
988 | ] | ||
989 | }, | ||
990 | { | ||
991 | "id": "a6d6", | ||
992 | "name": "Add skbedit action with index", | ||
993 | "category": [ | ||
994 | "actions", | ||
995 | "skbedit" | ||
996 | ], | ||
997 | "setup": [ | ||
998 | [ | ||
999 | "$TC actions flush action skbedit", | ||
1000 | 0, | ||
1001 | 1, | ||
1002 | 255 | ||
1003 | ] | ||
1004 | ], | ||
1005 | "cmdUnderTest": "$TC actions add action skbedit mark 808 index 4040404040", | ||
1006 | "expExitCode": "0", | ||
1007 | "verifyCmd": "$TC actions list action skbedit", | ||
1008 | "matchPattern": "index 4040404040", | ||
1009 | "matchCount": "1", | ||
1010 | "teardown": [ | ||
1011 | "$TC actions flush action skbedit" | ||
1012 | ] | ||
1013 | }, | ||
1014 | { | ||
1015 | "id": "38f3", | ||
1016 | "name": "Delete skbedit action", | ||
1017 | "category": [ | ||
1018 | "actions", | ||
1019 | "skbedit" | ||
1020 | ], | ||
1021 | "setup": [ | ||
1022 | [ | ||
1023 | "$TC actions flush action skbedit", | ||
1024 | 0, | ||
1025 | 1, | ||
1026 | 255 | ||
1027 | ], | ||
1028 | "$TC actions add action skbedit mark 42 index 9009" | ||
1029 | ], | ||
1030 | "cmdUnderTest": "$TC actions del action skbedit index 9009", | ||
1031 | "expExitCode": "0", | ||
1032 | "verifyCmd": "$TC actions list action skbedit", | ||
1033 | "matchPattern": "action order [0-9]*: skbedit mark 42", | ||
1034 | "matchCount": "0", | ||
1035 | "teardown": [ | ||
1036 | "$TC actions flush action skbedit" | ||
1037 | ] | ||
1038 | }, | ||
1039 | { | ||
1040 | "id": "ce97", | ||
1041 | "name": "Flush skbedit actions", | ||
1042 | "category": [ | ||
1043 | "actions", | ||
1044 | "skbedit" | ||
1045 | ], | ||
1046 | "setup": [ | ||
1047 | "$TC actions add action skbedit mark 500", | ||
1048 | "$TC actions add action skbedit mark 501", | ||
1049 | "$TC actions add action skbedit mark 502", | ||
1050 | "$TC actions add action skbedit mark 503", | ||
1051 | "$TC actions add action skbedit mark 504", | ||
1052 | "$TC actions add action skbedit mark 505", | ||
1053 | "$TC actions add action skbedit mark 506" | ||
1054 | ], | ||
1055 | "cmdUnderTest": "$TC actions flush action skbedit", | ||
1056 | "expExitCode": "0", | ||
1057 | "verifyCmd": "$TC actions list action skbedit", | ||
1058 | "matchPattern": "action order [0-9]*: skbedit", | ||
1059 | "matchCount": "0", | ||
1060 | "teardown": [ | ||
1061 | "$TC actions flush action skbedit" | ||
1062 | ] | ||
1063 | }, | ||
1064 | { | ||
1065 | "id": "f02c", | ||
1066 | "name": "Replace gact action", | ||
1067 | "category": [ | ||
1068 | "actions", | ||
1069 | "gact" | ||
1070 | ], | ||
1071 | "setup": [ | ||
1072 | [ | ||
1073 | "$TC actions flush action gact", | ||
1074 | 0, | ||
1075 | 1, | ||
1076 | 255 | ||
1077 | ], | ||
1078 | "$TC actions add action drop index 10", | ||
1079 | "$TC actions add action drop index 12" | ||
1080 | ], | ||
1081 | "cmdUnderTest": "$TC actions replace action ok index 12", | ||
1082 | "expExitCode": "0", | ||
1083 | "verifyCmd": "$TC actions ls action gact", | ||
1084 | "matchPattern": "action order [0-9]*: gact action pass", | ||
1085 | "matchCount": "1", | ||
1086 | "teardown": [ | ||
1087 | "$TC actions flush action gact" | ||
1088 | ] | ||
1089 | }, | ||
1090 | { | ||
1091 | "id": "525f", | ||
1092 | "name": "Get gact action by index", | ||
1093 | "category": [ | ||
1094 | "actions", | ||
1095 | "gact" | ||
1096 | ], | ||
1097 | "setup": [ | ||
1098 | [ | ||
1099 | "$TC actions flush action gact", | ||
1100 | 0, | ||
1101 | 1, | ||
1102 | 255 | ||
1103 | ], | ||
1104 | "$TC actions add action drop index 3900800700" | ||
1105 | ], | ||
1106 | "cmdUnderTest": "$TC actions get action gact index 3900800700", | ||
1107 | "expExitCode": "0", | ||
1108 | "verifyCmd": "$TC actions get action gact index 3900800700", | ||
1109 | "matchPattern": "index 3900800700", | ||
1110 | "matchCount": "1", | ||
1111 | "teardown": [ | ||
1112 | "$TC actions flush action gact" | ||
1113 | ] | ||
1114 | }, | ||
1115 | { | ||
1116 | "id": "a568", | ||
1117 | "name": "Add action with ife type", | ||
1118 | "category": [ | ||
1119 | "actions", | ||
1120 | "ife" | ||
1121 | ], | ||
1122 | "setup": [ | ||
1123 | [ | ||
1124 | "$TC actions flush action ife", | ||
1125 | 0, | ||
1126 | 1, | ||
1127 | 255 | ||
1128 | ], | ||
1129 | "$TC actions add action ife encode type 0xDEAD index 1" | ||
1130 | ], | ||
1131 | "cmdUnderTest": "$TC actions get action ife index 1", | ||
1132 | "expExitCode": "0", | ||
1133 | "verifyCmd": "$TC actions get action ife index 1", | ||
1134 | "matchPattern": "type 0xDEAD", | ||
1135 | "matchCount": "1", | ||
1136 | "teardown": [ | ||
1137 | "$TC actions flush action ife" | ||
1138 | ] | ||
1139 | }, | ||
1140 | { | ||
1141 | "id": "b983", | ||
1142 | "name": "Add action without ife type", | ||
1143 | "category": [ | ||
1144 | "actions", | ||
1145 | "ife" | ||
1146 | ], | ||
1147 | "setup": [ | ||
1148 | [ | ||
1149 | "$TC actions flush action ife", | ||
1150 | 0, | ||
1151 | 1, | ||
1152 | 255 | ||
1153 | ], | ||
1154 | "$TC actions add action ife encode index 1" | ||
1155 | ], | ||
1156 | "cmdUnderTest": "$TC actions get action ife index 1", | ||
1157 | "expExitCode": "0", | ||
1158 | "verifyCmd": "$TC actions get action ife index 1", | ||
1159 | "matchPattern": "type 0xED3E", | ||
1160 | "matchCount": "1", | ||
1161 | "teardown": [ | ||
1162 | "$TC actions flush action ife" | ||
1163 | ] | ||
1164 | } | ||
1165 | ] \ No newline at end of file | ||
diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index b8462e1b74f9..fc373fdf2bdc 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py | |||
@@ -50,7 +50,7 @@ def exec_cmd(command, nsonly=True): | |||
50 | stderr=subprocess.PIPE) | 50 | stderr=subprocess.PIPE) |
51 | (rawout, serr) = proc.communicate() | 51 | (rawout, serr) = proc.communicate() |
52 | 52 | ||
53 | if proc.returncode != 0: | 53 | if proc.returncode != 0 and len(serr) > 0: |
54 | foutput = serr.decode("utf-8") | 54 | foutput = serr.decode("utf-8") |
55 | else: | 55 | else: |
56 | foutput = rawout.decode("utf-8") | 56 | foutput = rawout.decode("utf-8") |
@@ -180,15 +180,20 @@ def has_blank_ids(idlist): | |||
180 | 180 | ||
181 | def load_from_file(filename): | 181 | def load_from_file(filename): |
182 | """ | 182 | """ |
183 | Open the JSON file containing the test cases and return them as an | 183 | Open the JSON file containing the test cases and return them |
184 | ordered dictionary object. | 184 | as list of ordered dictionary objects. |
185 | """ | 185 | """ |
186 | with open(filename) as test_data: | 186 | try: |
187 | testlist = json.load(test_data, object_pairs_hook=OrderedDict) | 187 | with open(filename) as test_data: |
188 | idlist = get_id_list(testlist) | 188 | testlist = json.load(test_data, object_pairs_hook=OrderedDict) |
189 | if (has_blank_ids(idlist)): | 189 | except json.JSONDecodeError as jde: |
190 | for k in testlist: | 190 | print('IGNORING test case file {}\n\tBECAUSE: {}'.format(filename, jde)) |
191 | k['filename'] = filename | 191 | testlist = list() |
192 | else: | ||
193 | idlist = get_id_list(testlist) | ||
194 | if (has_blank_ids(idlist)): | ||
195 | for k in testlist: | ||
196 | k['filename'] = filename | ||
192 | return testlist | 197 | return testlist |
193 | 198 | ||
194 | 199 | ||
@@ -210,7 +215,7 @@ def set_args(parser): | |||
210 | help='Run tests only from the specified category, or if no category is specified, list known categories.') | 215 | help='Run tests only from the specified category, or if no category is specified, list known categories.') |
211 | parser.add_argument('-f', '--file', type=str, | 216 | parser.add_argument('-f', '--file', type=str, |
212 | help='Run tests from the specified file') | 217 | help='Run tests from the specified file') |
213 | parser.add_argument('-l', '--list', type=str, nargs='?', const="", metavar='CATEGORY', | 218 | parser.add_argument('-l', '--list', type=str, nargs='?', const="++", metavar='CATEGORY', |
214 | help='List all test cases, or those only within the specified category') | 219 | help='List all test cases, or those only within the specified category') |
215 | parser.add_argument('-s', '--show', type=str, nargs=1, metavar='ID', dest='showID', | 220 | parser.add_argument('-s', '--show', type=str, nargs=1, metavar='ID', dest='showID', |
216 | help='Display the test case with specified id') | 221 | help='Display the test case with specified id') |
@@ -367,10 +372,10 @@ def set_operation_mode(args): | |||
367 | testcases = get_categorized_testlist(alltests, ucat) | 372 | testcases = get_categorized_testlist(alltests, ucat) |
368 | 373 | ||
369 | if args.list: | 374 | if args.list: |
370 | if (len(args.list) == 0): | 375 | if (args.list == "++"): |
371 | list_test_cases(alltests) | 376 | list_test_cases(alltests) |
372 | exit(0) | 377 | exit(0) |
373 | elif(len(args.list > 0)): | 378 | elif(len(args.list) > 0): |
374 | if (args.list not in ucat): | 379 | if (args.list not in ucat): |
375 | print("Unknown category " + args.list) | 380 | print("Unknown category " + args.list) |
376 | print("Available categories:") | 381 | print("Available categories:") |
diff --git a/tools/testing/selftests/tc-testing/tdc_config.py b/tools/testing/selftests/tc-testing/tdc_config.py index eb188c729dd6..a023d0d62b25 100644 --- a/tools/testing/selftests/tc-testing/tdc_config.py +++ b/tools/testing/selftests/tc-testing/tdc_config.py | |||
@@ -18,3 +18,17 @@ NAMES = { | |||
18 | # Name of the namespace to use | 18 | # Name of the namespace to use |
19 | 'NS': 'tcut' | 19 | 'NS': 'tcut' |
20 | } | 20 | } |
21 | |||
22 | |||
23 | ENVIR = { } | ||
24 | |||
25 | # put customizations in tdc_config_local.py | ||
26 | try: | ||
27 | from tdc_config_local import * | ||
28 | except ImportError as ie: | ||
29 | pass | ||
30 | |||
31 | try: | ||
32 | NAMES.update(EXTRA_NAMES) | ||
33 | except NameError as ne: | ||
34 | pass | ||
diff --git a/tools/testing/selftests/tc-testing/tdc_config_local_template.py b/tools/testing/selftests/tc-testing/tdc_config_local_template.py new file mode 100644 index 000000000000..d48fc732a399 --- /dev/null +++ b/tools/testing/selftests/tc-testing/tdc_config_local_template.py | |||
@@ -0,0 +1,23 @@ | |||
1 | """ | ||
2 | tdc_config_local.py - tdc plugin-writer-specified values | ||
3 | |||
4 | Copyright (C) 2017 bjb@mojatatu.com | ||
5 | """ | ||
6 | |||
7 | import os | ||
8 | |||
9 | ENVIR = os.environ.copy() | ||
10 | |||
11 | ENV_LD_LIBRARY_PATH = os.getenv('LD_LIBRARY_PATH', '') | ||
12 | ENV_OTHER_LIB = os.getenv('OTHER_LIB', '') | ||
13 | |||
14 | |||
15 | # example adding value to NAMES, without editing tdc_config.py | ||
16 | EXTRA_NAMES = dict() | ||
17 | EXTRA_NAMES['SOME_BIN'] = os.path.join(os.getenv('OTHER_BIN', ''), 'some_bin') | ||
18 | |||
19 | |||
20 | # example adding values to ENVIR, without editing tdc_config.py | ||
21 | ENVIR['VALGRIND_LIB'] = '/usr/lib/valgrind' | ||
22 | ENVIR['VALGRIND_BIN'] = '/usr/bin/valgrind' | ||
23 | ENVIR['VGDB_BIN'] = '/usr/bin/vgdb' | ||
diff --git a/tools/testing/selftests/tc-testing/tdc_helper.py b/tools/testing/selftests/tc-testing/tdc_helper.py index ccf2d2458703..db381120a566 100644 --- a/tools/testing/selftests/tc-testing/tdc_helper.py +++ b/tools/testing/selftests/tc-testing/tdc_helper.py | |||
@@ -16,7 +16,7 @@ def get_categorized_testlist(alltests, ucat): | |||
16 | 16 | ||
17 | 17 | ||
18 | def get_unique_item(lst): | 18 | def get_unique_item(lst): |
19 | """ For a list, return a set of the unique items in the list. """ | 19 | """ For a list, return a list of the unique items in the list. """ |
20 | return list(set(lst)) | 20 | return list(set(lst)) |
21 | 21 | ||
22 | 22 | ||
@@ -58,7 +58,7 @@ def print_sll(items): | |||
58 | def print_test_case(tcase): | 58 | def print_test_case(tcase): |
59 | """ Pretty-printing of a given test case. """ | 59 | """ Pretty-printing of a given test case. """ |
60 | for k in tcase.keys(): | 60 | for k in tcase.keys(): |
61 | if (type(tcase[k]) == list): | 61 | if (isinstance(tcase[k], list)): |
62 | print(k + ":") | 62 | print(k + ":") |
63 | print_list(tcase[k]) | 63 | print_list(tcase[k]) |
64 | else: | 64 | else: |
diff --git a/tools/testing/selftests/timers/.gitignore b/tools/testing/selftests/timers/.gitignore index cc986621f512..2c8ac8416299 100644 --- a/tools/testing/selftests/timers/.gitignore +++ b/tools/testing/selftests/timers/.gitignore | |||
@@ -18,3 +18,5 @@ threadtest | |||
18 | valid-adjtimex | 18 | valid-adjtimex |
19 | adjtick | 19 | adjtick |
20 | set-tz | 20 | set-tz |
21 | freq-step | ||
22 | rtctest_setdate | ||
diff --git a/tools/testing/selftests/vDSO/vdso_test.c b/tools/testing/selftests/vDSO/vdso_test.c index 8daeb7d7032c..2df26bd0099c 100644 --- a/tools/testing/selftests/vDSO/vdso_test.c +++ b/tools/testing/selftests/vDSO/vdso_test.c | |||
@@ -19,6 +19,19 @@ extern void *vdso_sym(const char *version, const char *name); | |||
19 | extern void vdso_init_from_sysinfo_ehdr(uintptr_t base); | 19 | extern void vdso_init_from_sysinfo_ehdr(uintptr_t base); |
20 | extern void vdso_init_from_auxv(void *auxv); | 20 | extern void vdso_init_from_auxv(void *auxv); |
21 | 21 | ||
22 | /* | ||
23 | * ARM64's vDSO exports its gettimeofday() implementation with a different | ||
24 | * name and version from other architectures, so we need to handle it as | ||
25 | * a special case. | ||
26 | */ | ||
27 | #if defined(__aarch64__) | ||
28 | const char *version = "LINUX_2.6.39"; | ||
29 | const char *name = "__kernel_gettimeofday"; | ||
30 | #else | ||
31 | const char *version = "LINUX_2.6"; | ||
32 | const char *name = "__vdso_gettimeofday"; | ||
33 | #endif | ||
34 | |||
22 | int main(int argc, char **argv) | 35 | int main(int argc, char **argv) |
23 | { | 36 | { |
24 | unsigned long sysinfo_ehdr = getauxval(AT_SYSINFO_EHDR); | 37 | unsigned long sysinfo_ehdr = getauxval(AT_SYSINFO_EHDR); |
@@ -31,10 +44,10 @@ int main(int argc, char **argv) | |||
31 | 44 | ||
32 | /* Find gettimeofday. */ | 45 | /* Find gettimeofday. */ |
33 | typedef long (*gtod_t)(struct timeval *tv, struct timezone *tz); | 46 | typedef long (*gtod_t)(struct timeval *tv, struct timezone *tz); |
34 | gtod_t gtod = (gtod_t)vdso_sym("LINUX_2.6", "__vdso_gettimeofday"); | 47 | gtod_t gtod = (gtod_t)vdso_sym(version, name); |
35 | 48 | ||
36 | if (!gtod) { | 49 | if (!gtod) { |
37 | printf("Could not find __vdso_gettimeofday\n"); | 50 | printf("Could not find %s\n", name); |
38 | return 1; | 51 | return 1; |
39 | } | 52 | } |
40 | 53 | ||
@@ -45,7 +58,7 @@ int main(int argc, char **argv) | |||
45 | printf("The time is %lld.%06lld\n", | 58 | printf("The time is %lld.%06lld\n", |
46 | (long long)tv.tv_sec, (long long)tv.tv_usec); | 59 | (long long)tv.tv_sec, (long long)tv.tv_usec); |
47 | } else { | 60 | } else { |
48 | printf("__vdso_gettimeofday failed\n"); | 61 | printf("%s failed\n", name); |
49 | } | 62 | } |
50 | 63 | ||
51 | return 0; | 64 | return 0; |
diff --git a/tools/testing/selftests/vm/.gitignore b/tools/testing/selftests/vm/.gitignore index 142c565bb351..1ca2ee4d15b9 100644 --- a/tools/testing/selftests/vm/.gitignore +++ b/tools/testing/selftests/vm/.gitignore | |||
@@ -8,3 +8,5 @@ on-fault-limit | |||
8 | transhuge-stress | 8 | transhuge-stress |
9 | userfaultfd | 9 | userfaultfd |
10 | mlock-intersect-test | 10 | mlock-intersect-test |
11 | mlock-random-test | ||
12 | virtual_address_range | ||
diff --git a/tools/testing/selftests/vm/Makefile b/tools/testing/selftests/vm/Makefile index e49eca1915f8..7f45806bd863 100644 --- a/tools/testing/selftests/vm/Makefile +++ b/tools/testing/selftests/vm/Makefile | |||
@@ -18,6 +18,7 @@ TEST_GEN_FILES += transhuge-stress | |||
18 | TEST_GEN_FILES += userfaultfd | 18 | TEST_GEN_FILES += userfaultfd |
19 | TEST_GEN_FILES += mlock-random-test | 19 | TEST_GEN_FILES += mlock-random-test |
20 | TEST_GEN_FILES += virtual_address_range | 20 | TEST_GEN_FILES += virtual_address_range |
21 | TEST_GEN_FILES += gup_benchmark | ||
21 | 22 | ||
22 | TEST_PROGS := run_vmtests | 23 | TEST_PROGS := run_vmtests |
23 | 24 | ||
diff --git a/tools/testing/selftests/vm/gup_benchmark.c b/tools/testing/selftests/vm/gup_benchmark.c new file mode 100644 index 000000000000..36df55132036 --- /dev/null +++ b/tools/testing/selftests/vm/gup_benchmark.c | |||
@@ -0,0 +1,91 @@ | |||
1 | #include <fcntl.h> | ||
2 | #include <stdio.h> | ||
3 | #include <stdlib.h> | ||
4 | #include <unistd.h> | ||
5 | |||
6 | #include <sys/ioctl.h> | ||
7 | #include <sys/mman.h> | ||
8 | #include <sys/prctl.h> | ||
9 | #include <sys/stat.h> | ||
10 | #include <sys/types.h> | ||
11 | |||
12 | #include <linux/types.h> | ||
13 | |||
14 | #define MB (1UL << 20) | ||
15 | #define PAGE_SIZE sysconf(_SC_PAGESIZE) | ||
16 | |||
17 | #define GUP_FAST_BENCHMARK _IOWR('g', 1, struct gup_benchmark) | ||
18 | |||
19 | struct gup_benchmark { | ||
20 | __u64 delta_usec; | ||
21 | __u64 addr; | ||
22 | __u64 size; | ||
23 | __u32 nr_pages_per_call; | ||
24 | __u32 flags; | ||
25 | }; | ||
26 | |||
27 | int main(int argc, char **argv) | ||
28 | { | ||
29 | struct gup_benchmark gup; | ||
30 | unsigned long size = 128 * MB; | ||
31 | int i, fd, opt, nr_pages = 1, thp = -1, repeats = 1, write = 0; | ||
32 | char *p; | ||
33 | |||
34 | while ((opt = getopt(argc, argv, "m:r:n:tT")) != -1) { | ||
35 | switch (opt) { | ||
36 | case 'm': | ||
37 | size = atoi(optarg) * MB; | ||
38 | break; | ||
39 | case 'r': | ||
40 | repeats = atoi(optarg); | ||
41 | break; | ||
42 | case 'n': | ||
43 | nr_pages = atoi(optarg); | ||
44 | break; | ||
45 | case 't': | ||
46 | thp = 1; | ||
47 | break; | ||
48 | case 'T': | ||
49 | thp = 0; | ||
50 | break; | ||
51 | case 'w': | ||
52 | write = 1; | ||
53 | default: | ||
54 | return -1; | ||
55 | } | ||
56 | } | ||
57 | |||
58 | gup.nr_pages_per_call = nr_pages; | ||
59 | gup.flags = write; | ||
60 | |||
61 | fd = open("/sys/kernel/debug/gup_benchmark", O_RDWR); | ||
62 | if (fd == -1) | ||
63 | perror("open"), exit(1); | ||
64 | |||
65 | p = mmap(NULL, size, PROT_READ | PROT_WRITE, | ||
66 | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); | ||
67 | if (p == MAP_FAILED) | ||
68 | perror("mmap"), exit(1); | ||
69 | gup.addr = (unsigned long)p; | ||
70 | |||
71 | if (thp == 1) | ||
72 | madvise(p, size, MADV_HUGEPAGE); | ||
73 | else if (thp == 0) | ||
74 | madvise(p, size, MADV_NOHUGEPAGE); | ||
75 | |||
76 | for (; (unsigned long)p < gup.addr + size; p += PAGE_SIZE) | ||
77 | p[0] = 0; | ||
78 | |||
79 | for (i = 0; i < repeats; i++) { | ||
80 | gup.size = size; | ||
81 | if (ioctl(fd, GUP_FAST_BENCHMARK, &gup)) | ||
82 | perror("ioctl"), exit(1); | ||
83 | |||
84 | printf("Time: %lld us", gup.delta_usec); | ||
85 | if (gup.size != size) | ||
86 | printf(", truncated (size: %lld)", gup.size); | ||
87 | printf("\n"); | ||
88 | } | ||
89 | |||
90 | return 0; | ||
91 | } | ||
diff --git a/tools/testing/selftests/x86/5lvl.c b/tools/testing/selftests/x86/5lvl.c new file mode 100644 index 000000000000..2eafdcd4c2b3 --- /dev/null +++ b/tools/testing/selftests/x86/5lvl.c | |||
@@ -0,0 +1,177 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <sys/mman.h> | ||
3 | |||
4 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) | ||
5 | |||
6 | #define PAGE_SIZE 4096 | ||
7 | #define LOW_ADDR ((void *) (1UL << 30)) | ||
8 | #define HIGH_ADDR ((void *) (1UL << 50)) | ||
9 | |||
10 | struct testcase { | ||
11 | void *addr; | ||
12 | unsigned long size; | ||
13 | unsigned long flags; | ||
14 | const char *msg; | ||
15 | unsigned int low_addr_required:1; | ||
16 | unsigned int keep_mapped:1; | ||
17 | }; | ||
18 | |||
19 | static struct testcase testcases[] = { | ||
20 | { | ||
21 | .addr = NULL, | ||
22 | .size = 2 * PAGE_SIZE, | ||
23 | .flags = MAP_PRIVATE | MAP_ANONYMOUS, | ||
24 | .msg = "mmap(NULL)", | ||
25 | .low_addr_required = 1, | ||
26 | }, | ||
27 | { | ||
28 | .addr = LOW_ADDR, | ||
29 | .size = 2 * PAGE_SIZE, | ||
30 | .flags = MAP_PRIVATE | MAP_ANONYMOUS, | ||
31 | .msg = "mmap(LOW_ADDR)", | ||
32 | .low_addr_required = 1, | ||
33 | }, | ||
34 | { | ||
35 | .addr = HIGH_ADDR, | ||
36 | .size = 2 * PAGE_SIZE, | ||
37 | .flags = MAP_PRIVATE | MAP_ANONYMOUS, | ||
38 | .msg = "mmap(HIGH_ADDR)", | ||
39 | .keep_mapped = 1, | ||
40 | }, | ||
41 | { | ||
42 | .addr = HIGH_ADDR, | ||
43 | .size = 2 * PAGE_SIZE, | ||
44 | .flags = MAP_PRIVATE | MAP_ANONYMOUS, | ||
45 | .msg = "mmap(HIGH_ADDR) again", | ||
46 | .keep_mapped = 1, | ||
47 | }, | ||
48 | { | ||
49 | .addr = HIGH_ADDR, | ||
50 | .size = 2 * PAGE_SIZE, | ||
51 | .flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, | ||
52 | .msg = "mmap(HIGH_ADDR, MAP_FIXED)", | ||
53 | }, | ||
54 | { | ||
55 | .addr = (void*) -1, | ||
56 | .size = 2 * PAGE_SIZE, | ||
57 | .flags = MAP_PRIVATE | MAP_ANONYMOUS, | ||
58 | .msg = "mmap(-1)", | ||
59 | .keep_mapped = 1, | ||
60 | }, | ||
61 | { | ||
62 | .addr = (void*) -1, | ||
63 | .size = 2 * PAGE_SIZE, | ||
64 | .flags = MAP_PRIVATE | MAP_ANONYMOUS, | ||
65 | .msg = "mmap(-1) again", | ||
66 | }, | ||
67 | { | ||
68 | .addr = (void *)((1UL << 47) - PAGE_SIZE), | ||
69 | .size = 2 * PAGE_SIZE, | ||
70 | .flags = MAP_PRIVATE | MAP_ANONYMOUS, | ||
71 | .msg = "mmap((1UL << 47), 2 * PAGE_SIZE)", | ||
72 | .low_addr_required = 1, | ||
73 | .keep_mapped = 1, | ||
74 | }, | ||
75 | { | ||
76 | .addr = (void *)((1UL << 47) - PAGE_SIZE / 2), | ||
77 | .size = 2 * PAGE_SIZE, | ||
78 | .flags = MAP_PRIVATE | MAP_ANONYMOUS, | ||
79 | .msg = "mmap((1UL << 47), 2 * PAGE_SIZE / 2)", | ||
80 | .low_addr_required = 1, | ||
81 | .keep_mapped = 1, | ||
82 | }, | ||
83 | { | ||
84 | .addr = (void *)((1UL << 47) - PAGE_SIZE), | ||
85 | .size = 2 * PAGE_SIZE, | ||
86 | .flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, | ||
87 | .msg = "mmap((1UL << 47) - PAGE_SIZE, 2 * PAGE_SIZE, MAP_FIXED)", | ||
88 | }, | ||
89 | { | ||
90 | .addr = NULL, | ||
91 | .size = 2UL << 20, | ||
92 | .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS, | ||
93 | .msg = "mmap(NULL, MAP_HUGETLB)", | ||
94 | .low_addr_required = 1, | ||
95 | }, | ||
96 | { | ||
97 | .addr = LOW_ADDR, | ||
98 | .size = 2UL << 20, | ||
99 | .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS, | ||
100 | .msg = "mmap(LOW_ADDR, MAP_HUGETLB)", | ||
101 | .low_addr_required = 1, | ||
102 | }, | ||
103 | { | ||
104 | .addr = HIGH_ADDR, | ||
105 | .size = 2UL << 20, | ||
106 | .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS, | ||
107 | .msg = "mmap(HIGH_ADDR, MAP_HUGETLB)", | ||
108 | .keep_mapped = 1, | ||
109 | }, | ||
110 | { | ||
111 | .addr = HIGH_ADDR, | ||
112 | .size = 2UL << 20, | ||
113 | .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS, | ||
114 | .msg = "mmap(HIGH_ADDR, MAP_HUGETLB) again", | ||
115 | .keep_mapped = 1, | ||
116 | }, | ||
117 | { | ||
118 | .addr = HIGH_ADDR, | ||
119 | .size = 2UL << 20, | ||
120 | .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, | ||
121 | .msg = "mmap(HIGH_ADDR, MAP_FIXED | MAP_HUGETLB)", | ||
122 | }, | ||
123 | { | ||
124 | .addr = (void*) -1, | ||
125 | .size = 2UL << 20, | ||
126 | .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS, | ||
127 | .msg = "mmap(-1, MAP_HUGETLB)", | ||
128 | .keep_mapped = 1, | ||
129 | }, | ||
130 | { | ||
131 | .addr = (void*) -1, | ||
132 | .size = 2UL << 20, | ||
133 | .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS, | ||
134 | .msg = "mmap(-1, MAP_HUGETLB) again", | ||
135 | }, | ||
136 | { | ||
137 | .addr = (void *)((1UL << 47) - PAGE_SIZE), | ||
138 | .size = 4UL << 20, | ||
139 | .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS, | ||
140 | .msg = "mmap((1UL << 47), 4UL << 20, MAP_HUGETLB)", | ||
141 | .low_addr_required = 1, | ||
142 | .keep_mapped = 1, | ||
143 | }, | ||
144 | { | ||
145 | .addr = (void *)((1UL << 47) - (2UL << 20)), | ||
146 | .size = 4UL << 20, | ||
147 | .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, | ||
148 | .msg = "mmap((1UL << 47) - (2UL << 20), 4UL << 20, MAP_FIXED | MAP_HUGETLB)", | ||
149 | }, | ||
150 | }; | ||
151 | |||
152 | int main(int argc, char **argv) | ||
153 | { | ||
154 | int i; | ||
155 | void *p; | ||
156 | |||
157 | for (i = 0; i < ARRAY_SIZE(testcases); i++) { | ||
158 | struct testcase *t = testcases + i; | ||
159 | |||
160 | p = mmap(t->addr, t->size, PROT_NONE, t->flags, -1, 0); | ||
161 | |||
162 | printf("%s: %p - ", t->msg, p); | ||
163 | |||
164 | if (p == MAP_FAILED) { | ||
165 | printf("FAILED\n"); | ||
166 | continue; | ||
167 | } | ||
168 | |||
169 | if (t->low_addr_required && p >= (void *)(1UL << 47)) | ||
170 | printf("FAILED\n"); | ||
171 | else | ||
172 | printf("OK\n"); | ||
173 | if (!t->keep_mapped) | ||
174 | munmap(p, t->size); | ||
175 | } | ||
176 | return 0; | ||
177 | } | ||
diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile index 7b1adeee4b0f..939a337128db 100644 --- a/tools/testing/selftests/x86/Makefile +++ b/tools/testing/selftests/x86/Makefile | |||
@@ -11,7 +11,7 @@ TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_sysc | |||
11 | TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \ | 11 | TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \ |
12 | test_FCMOV test_FCOMI test_FISTTP \ | 12 | test_FCMOV test_FCOMI test_FISTTP \ |
13 | vdso_restorer | 13 | vdso_restorer |
14 | TARGETS_C_64BIT_ONLY := fsgsbase sysret_rip | 14 | TARGETS_C_64BIT_ONLY := fsgsbase sysret_rip 5lvl |
15 | 15 | ||
16 | TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY) | 16 | TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY) |
17 | TARGETS_C_64BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_64BIT_ONLY) | 17 | TARGETS_C_64BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_64BIT_ONLY) |
diff --git a/tools/testing/selftests/x86/mpx-hw.h b/tools/testing/selftests/x86/mpx-hw.h index 3f0093911f03..d1b61ab870f8 100644 --- a/tools/testing/selftests/x86/mpx-hw.h +++ b/tools/testing/selftests/x86/mpx-hw.h | |||
@@ -52,14 +52,14 @@ | |||
52 | struct mpx_bd_entry { | 52 | struct mpx_bd_entry { |
53 | union { | 53 | union { |
54 | char x[MPX_BOUNDS_DIR_ENTRY_SIZE_BYTES]; | 54 | char x[MPX_BOUNDS_DIR_ENTRY_SIZE_BYTES]; |
55 | void *contents[1]; | 55 | void *contents[0]; |
56 | }; | 56 | }; |
57 | } __attribute__((packed)); | 57 | } __attribute__((packed)); |
58 | 58 | ||
59 | struct mpx_bt_entry { | 59 | struct mpx_bt_entry { |
60 | union { | 60 | union { |
61 | char x[MPX_BOUNDS_TABLE_ENTRY_SIZE_BYTES]; | 61 | char x[MPX_BOUNDS_TABLE_ENTRY_SIZE_BYTES]; |
62 | unsigned long contents[1]; | 62 | unsigned long contents[0]; |
63 | }; | 63 | }; |
64 | } __attribute__((packed)); | 64 | } __attribute__((packed)); |
65 | 65 | ||
diff --git a/tools/testing/selftests/x86/pkey-helpers.h b/tools/testing/selftests/x86/pkey-helpers.h index 3818f25391c2..b3cb7670e026 100644 --- a/tools/testing/selftests/x86/pkey-helpers.h +++ b/tools/testing/selftests/x86/pkey-helpers.h | |||
@@ -30,6 +30,7 @@ static inline void sigsafe_printf(const char *format, ...) | |||
30 | if (!dprint_in_signal) { | 30 | if (!dprint_in_signal) { |
31 | vprintf(format, ap); | 31 | vprintf(format, ap); |
32 | } else { | 32 | } else { |
33 | int ret; | ||
33 | int len = vsnprintf(dprint_in_signal_buffer, | 34 | int len = vsnprintf(dprint_in_signal_buffer, |
34 | DPRINT_IN_SIGNAL_BUF_SIZE, | 35 | DPRINT_IN_SIGNAL_BUF_SIZE, |
35 | format, ap); | 36 | format, ap); |
@@ -39,7 +40,9 @@ static inline void sigsafe_printf(const char *format, ...) | |||
39 | */ | 40 | */ |
40 | if (len > DPRINT_IN_SIGNAL_BUF_SIZE) | 41 | if (len > DPRINT_IN_SIGNAL_BUF_SIZE) |
41 | len = DPRINT_IN_SIGNAL_BUF_SIZE; | 42 | len = DPRINT_IN_SIGNAL_BUF_SIZE; |
42 | write(1, dprint_in_signal_buffer, len); | 43 | ret = write(1, dprint_in_signal_buffer, len); |
44 | if (ret < 0) | ||
45 | abort(); | ||
43 | } | 46 | } |
44 | va_end(ap); | 47 | va_end(ap); |
45 | } | 48 | } |
diff --git a/tools/testing/selftests/x86/protection_keys.c b/tools/testing/selftests/x86/protection_keys.c index 7a1cc0e56d2d..bc1b0735bb50 100644 --- a/tools/testing/selftests/x86/protection_keys.c +++ b/tools/testing/selftests/x86/protection_keys.c | |||
@@ -250,7 +250,7 @@ void signal_handler(int signum, siginfo_t *si, void *vucontext) | |||
250 | unsigned long ip; | 250 | unsigned long ip; |
251 | char *fpregs; | 251 | char *fpregs; |
252 | u32 *pkru_ptr; | 252 | u32 *pkru_ptr; |
253 | u64 si_pkey; | 253 | u64 siginfo_pkey; |
254 | u32 *si_pkey_ptr; | 254 | u32 *si_pkey_ptr; |
255 | int pkru_offset; | 255 | int pkru_offset; |
256 | fpregset_t fpregset; | 256 | fpregset_t fpregset; |
@@ -292,9 +292,9 @@ void signal_handler(int signum, siginfo_t *si, void *vucontext) | |||
292 | si_pkey_ptr = (u32 *)(((u8 *)si) + si_pkey_offset); | 292 | si_pkey_ptr = (u32 *)(((u8 *)si) + si_pkey_offset); |
293 | dprintf1("si_pkey_ptr: %p\n", si_pkey_ptr); | 293 | dprintf1("si_pkey_ptr: %p\n", si_pkey_ptr); |
294 | dump_mem(si_pkey_ptr - 8, 24); | 294 | dump_mem(si_pkey_ptr - 8, 24); |
295 | si_pkey = *si_pkey_ptr; | 295 | siginfo_pkey = *si_pkey_ptr; |
296 | pkey_assert(si_pkey < NR_PKEYS); | 296 | pkey_assert(siginfo_pkey < NR_PKEYS); |
297 | last_si_pkey = si_pkey; | 297 | last_si_pkey = siginfo_pkey; |
298 | 298 | ||
299 | if ((si->si_code == SEGV_MAPERR) || | 299 | if ((si->si_code == SEGV_MAPERR) || |
300 | (si->si_code == SEGV_ACCERR) || | 300 | (si->si_code == SEGV_ACCERR) || |
@@ -306,7 +306,7 @@ void signal_handler(int signum, siginfo_t *si, void *vucontext) | |||
306 | dprintf1("signal pkru from xsave: %08x\n", *pkru_ptr); | 306 | dprintf1("signal pkru from xsave: %08x\n", *pkru_ptr); |
307 | /* need __rdpkru() version so we do not do shadow_pkru checking */ | 307 | /* need __rdpkru() version so we do not do shadow_pkru checking */ |
308 | dprintf1("signal pkru from pkru: %08x\n", __rdpkru()); | 308 | dprintf1("signal pkru from pkru: %08x\n", __rdpkru()); |
309 | dprintf1("si_pkey from siginfo: %jx\n", si_pkey); | 309 | dprintf1("pkey from siginfo: %jx\n", siginfo_pkey); |
310 | *(u64 *)pkru_ptr = 0x00000000; | 310 | *(u64 *)pkru_ptr = 0x00000000; |
311 | dprintf1("WARNING: set PRKU=0 to allow faulting instruction to continue\n"); | 311 | dprintf1("WARNING: set PRKU=0 to allow faulting instruction to continue\n"); |
312 | pkru_faults++; | 312 | pkru_faults++; |
diff --git a/tools/testing/vsock/.gitignore b/tools/testing/vsock/.gitignore new file mode 100644 index 000000000000..dc5f11faf530 --- /dev/null +++ b/tools/testing/vsock/.gitignore | |||
@@ -0,0 +1,2 @@ | |||
1 | *.d | ||
2 | vsock_diag_test | ||
diff --git a/tools/testing/vsock/Makefile b/tools/testing/vsock/Makefile new file mode 100644 index 000000000000..66ba0924194d --- /dev/null +++ b/tools/testing/vsock/Makefile | |||
@@ -0,0 +1,9 @@ | |||
1 | all: test | ||
2 | test: vsock_diag_test | ||
3 | vsock_diag_test: vsock_diag_test.o timeout.o control.o | ||
4 | |||
5 | CFLAGS += -g -O2 -Werror -Wall -I. -I../../include/uapi -I../../include -Wno-pointer-sign -fno-strict-overflow -fno-strict-aliasing -fno-common -MMD -U_FORTIFY_SOURCE -D_GNU_SOURCE | ||
6 | .PHONY: all test clean | ||
7 | clean: | ||
8 | ${RM} *.o *.d vsock_diag_test | ||
9 | -include *.d | ||
diff --git a/tools/testing/vsock/README b/tools/testing/vsock/README new file mode 100644 index 000000000000..2cc6d7302db6 --- /dev/null +++ b/tools/testing/vsock/README | |||
@@ -0,0 +1,36 @@ | |||
1 | AF_VSOCK test suite | ||
2 | ------------------- | ||
3 | These tests exercise net/vmw_vsock/ host<->guest sockets for VMware, KVM, and | ||
4 | Hyper-V. | ||
5 | |||
6 | The following tests are available: | ||
7 | |||
8 | * vsock_diag_test - vsock_diag.ko module for listing open sockets | ||
9 | |||
10 | The following prerequisite steps are not automated and must be performed prior | ||
11 | to running tests: | ||
12 | |||
13 | 1. Build the kernel and these tests. | ||
14 | 2. Install the kernel and tests on the host. | ||
15 | 3. Install the kernel and tests inside the guest. | ||
16 | 4. Boot the guest and ensure that the AF_VSOCK transport is enabled. | ||
17 | |||
18 | Invoke test binaries in both directions as follows: | ||
19 | |||
20 | # host=server, guest=client | ||
21 | (host)# $TEST_BINARY --mode=server \ | ||
22 | --control-port=1234 \ | ||
23 | --peer-cid=3 | ||
24 | (guest)# $TEST_BINARY --mode=client \ | ||
25 | --control-host=$HOST_IP \ | ||
26 | --control-port=1234 \ | ||
27 | --peer-cid=2 | ||
28 | |||
29 | # host=client, guest=server | ||
30 | (guest)# $TEST_BINARY --mode=server \ | ||
31 | --control-port=1234 \ | ||
32 | --peer-cid=2 | ||
33 | (host)# $TEST_BINARY --mode=client \ | ||
34 | --control-port=$GUEST_IP \ | ||
35 | --control-port=1234 \ | ||
36 | --peer-cid=3 | ||
diff --git a/tools/testing/vsock/control.c b/tools/testing/vsock/control.c new file mode 100644 index 000000000000..90fd47f0e422 --- /dev/null +++ b/tools/testing/vsock/control.c | |||
@@ -0,0 +1,219 @@ | |||
1 | /* Control socket for client/server test execution | ||
2 | * | ||
3 | * Copyright (C) 2017 Red Hat, Inc. | ||
4 | * | ||
5 | * Author: Stefan Hajnoczi <stefanha@redhat.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; version 2 | ||
10 | * of the License. | ||
11 | */ | ||
12 | |||
13 | /* The client and server may need to coordinate to avoid race conditions like | ||
14 | * the client attempting to connect to a socket that the server is not | ||
15 | * listening on yet. The control socket offers a communications channel for | ||
16 | * such coordination tasks. | ||
17 | * | ||
18 | * If the client calls control_expectln("LISTENING"), then it will block until | ||
19 | * the server calls control_writeln("LISTENING"). This provides a simple | ||
20 | * mechanism for coordinating between the client and the server. | ||
21 | */ | ||
22 | |||
23 | #include <errno.h> | ||
24 | #include <netdb.h> | ||
25 | #include <stdio.h> | ||
26 | #include <stdlib.h> | ||
27 | #include <string.h> | ||
28 | #include <unistd.h> | ||
29 | #include <sys/types.h> | ||
30 | #include <sys/socket.h> | ||
31 | |||
32 | #include "timeout.h" | ||
33 | #include "control.h" | ||
34 | |||
35 | static int control_fd = -1; | ||
36 | |||
37 | /* Open the control socket, either in server or client mode */ | ||
38 | void control_init(const char *control_host, | ||
39 | const char *control_port, | ||
40 | bool server) | ||
41 | { | ||
42 | struct addrinfo hints = { | ||
43 | .ai_socktype = SOCK_STREAM, | ||
44 | }; | ||
45 | struct addrinfo *result = NULL; | ||
46 | struct addrinfo *ai; | ||
47 | int ret; | ||
48 | |||
49 | ret = getaddrinfo(control_host, control_port, &hints, &result); | ||
50 | if (ret != 0) { | ||
51 | fprintf(stderr, "%s\n", gai_strerror(ret)); | ||
52 | exit(EXIT_FAILURE); | ||
53 | } | ||
54 | |||
55 | for (ai = result; ai; ai = ai->ai_next) { | ||
56 | int fd; | ||
57 | int val = 1; | ||
58 | |||
59 | fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); | ||
60 | if (fd < 0) | ||
61 | continue; | ||
62 | |||
63 | if (!server) { | ||
64 | if (connect(fd, ai->ai_addr, ai->ai_addrlen) < 0) | ||
65 | goto next; | ||
66 | control_fd = fd; | ||
67 | printf("Control socket connected to %s:%s.\n", | ||
68 | control_host, control_port); | ||
69 | break; | ||
70 | } | ||
71 | |||
72 | if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, | ||
73 | &val, sizeof(val)) < 0) { | ||
74 | perror("setsockopt"); | ||
75 | exit(EXIT_FAILURE); | ||
76 | } | ||
77 | |||
78 | if (bind(fd, ai->ai_addr, ai->ai_addrlen) < 0) | ||
79 | goto next; | ||
80 | if (listen(fd, 1) < 0) | ||
81 | goto next; | ||
82 | |||
83 | printf("Control socket listening on %s:%s\n", | ||
84 | control_host, control_port); | ||
85 | fflush(stdout); | ||
86 | |||
87 | control_fd = accept(fd, NULL, 0); | ||
88 | close(fd); | ||
89 | |||
90 | if (control_fd < 0) { | ||
91 | perror("accept"); | ||
92 | exit(EXIT_FAILURE); | ||
93 | } | ||
94 | printf("Control socket connection accepted...\n"); | ||
95 | break; | ||
96 | |||
97 | next: | ||
98 | close(fd); | ||
99 | } | ||
100 | |||
101 | if (control_fd < 0) { | ||
102 | fprintf(stderr, "Control socket initialization failed. Invalid address %s:%s?\n", | ||
103 | control_host, control_port); | ||
104 | exit(EXIT_FAILURE); | ||
105 | } | ||
106 | |||
107 | freeaddrinfo(result); | ||
108 | } | ||
109 | |||
110 | /* Free resources */ | ||
111 | void control_cleanup(void) | ||
112 | { | ||
113 | close(control_fd); | ||
114 | control_fd = -1; | ||
115 | } | ||
116 | |||
117 | /* Write a line to the control socket */ | ||
118 | void control_writeln(const char *str) | ||
119 | { | ||
120 | ssize_t len = strlen(str); | ||
121 | ssize_t ret; | ||
122 | |||
123 | timeout_begin(TIMEOUT); | ||
124 | |||
125 | do { | ||
126 | ret = send(control_fd, str, len, MSG_MORE); | ||
127 | timeout_check("send"); | ||
128 | } while (ret < 0 && errno == EINTR); | ||
129 | |||
130 | if (ret != len) { | ||
131 | perror("send"); | ||
132 | exit(EXIT_FAILURE); | ||
133 | } | ||
134 | |||
135 | do { | ||
136 | ret = send(control_fd, "\n", 1, 0); | ||
137 | timeout_check("send"); | ||
138 | } while (ret < 0 && errno == EINTR); | ||
139 | |||
140 | if (ret != 1) { | ||
141 | perror("send"); | ||
142 | exit(EXIT_FAILURE); | ||
143 | } | ||
144 | |||
145 | timeout_end(); | ||
146 | } | ||
147 | |||
148 | /* Return the next line from the control socket (without the trailing newline). | ||
149 | * | ||
150 | * The program terminates if a timeout occurs. | ||
151 | * | ||
152 | * The caller must free() the returned string. | ||
153 | */ | ||
154 | char *control_readln(void) | ||
155 | { | ||
156 | char *buf = NULL; | ||
157 | size_t idx = 0; | ||
158 | size_t buflen = 0; | ||
159 | |||
160 | timeout_begin(TIMEOUT); | ||
161 | |||
162 | for (;;) { | ||
163 | ssize_t ret; | ||
164 | |||
165 | if (idx >= buflen) { | ||
166 | char *new_buf; | ||
167 | |||
168 | new_buf = realloc(buf, buflen + 80); | ||
169 | if (!new_buf) { | ||
170 | perror("realloc"); | ||
171 | exit(EXIT_FAILURE); | ||
172 | } | ||
173 | |||
174 | buf = new_buf; | ||
175 | buflen += 80; | ||
176 | } | ||
177 | |||
178 | do { | ||
179 | ret = recv(control_fd, &buf[idx], 1, 0); | ||
180 | timeout_check("recv"); | ||
181 | } while (ret < 0 && errno == EINTR); | ||
182 | |||
183 | if (ret == 0) { | ||
184 | fprintf(stderr, "unexpected EOF on control socket\n"); | ||
185 | exit(EXIT_FAILURE); | ||
186 | } | ||
187 | |||
188 | if (ret != 1) { | ||
189 | perror("recv"); | ||
190 | exit(EXIT_FAILURE); | ||
191 | } | ||
192 | |||
193 | if (buf[idx] == '\n') { | ||
194 | buf[idx] = '\0'; | ||
195 | break; | ||
196 | } | ||
197 | |||
198 | idx++; | ||
199 | } | ||
200 | |||
201 | timeout_end(); | ||
202 | |||
203 | return buf; | ||
204 | } | ||
205 | |||
206 | /* Wait until a given line is received or a timeout occurs */ | ||
207 | void control_expectln(const char *str) | ||
208 | { | ||
209 | char *line; | ||
210 | |||
211 | line = control_readln(); | ||
212 | if (strcmp(str, line) != 0) { | ||
213 | fprintf(stderr, "expected \"%s\" on control socket, got \"%s\"\n", | ||
214 | str, line); | ||
215 | exit(EXIT_FAILURE); | ||
216 | } | ||
217 | |||
218 | free(line); | ||
219 | } | ||
diff --git a/tools/testing/vsock/control.h b/tools/testing/vsock/control.h new file mode 100644 index 000000000000..54a07efd267c --- /dev/null +++ b/tools/testing/vsock/control.h | |||
@@ -0,0 +1,13 @@ | |||
1 | #ifndef CONTROL_H | ||
2 | #define CONTROL_H | ||
3 | |||
4 | #include <stdbool.h> | ||
5 | |||
6 | void control_init(const char *control_host, const char *control_port, | ||
7 | bool server); | ||
8 | void control_cleanup(void); | ||
9 | void control_writeln(const char *str); | ||
10 | char *control_readln(void); | ||
11 | void control_expectln(const char *str); | ||
12 | |||
13 | #endif /* CONTROL_H */ | ||
diff --git a/tools/testing/vsock/timeout.c b/tools/testing/vsock/timeout.c new file mode 100644 index 000000000000..c49b3003b2db --- /dev/null +++ b/tools/testing/vsock/timeout.c | |||
@@ -0,0 +1,64 @@ | |||
1 | /* Timeout API for single-threaded programs that use blocking | ||
2 | * syscalls (read/write/send/recv/connect/accept). | ||
3 | * | ||
4 | * Copyright (C) 2017 Red Hat, Inc. | ||
5 | * | ||
6 | * Author: Stefan Hajnoczi <stefanha@redhat.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; version 2 | ||
11 | * of the License. | ||
12 | */ | ||
13 | |||
14 | /* Use the following pattern: | ||
15 | * | ||
16 | * timeout_begin(TIMEOUT); | ||
17 | * do { | ||
18 | * ret = accept(...); | ||
19 | * timeout_check("accept"); | ||
20 | * } while (ret < 0 && ret == EINTR); | ||
21 | * timeout_end(); | ||
22 | */ | ||
23 | |||
24 | #include <stdlib.h> | ||
25 | #include <stdbool.h> | ||
26 | #include <unistd.h> | ||
27 | #include <stdio.h> | ||
28 | #include "timeout.h" | ||
29 | |||
30 | static volatile bool timeout; | ||
31 | |||
32 | /* SIGALRM handler function. Do not use sleep(2), alarm(2), or | ||
33 | * setitimer(2) while using this API - they may interfere with each | ||
34 | * other. | ||
35 | */ | ||
36 | void sigalrm(int signo) | ||
37 | { | ||
38 | timeout = true; | ||
39 | } | ||
40 | |||
41 | /* Start a timeout. Call timeout_check() to verify that the timeout hasn't | ||
42 | * expired. timeout_end() must be called to stop the timeout. Timeouts cannot | ||
43 | * be nested. | ||
44 | */ | ||
45 | void timeout_begin(unsigned int seconds) | ||
46 | { | ||
47 | alarm(seconds); | ||
48 | } | ||
49 | |||
50 | /* Exit with an error message if the timeout has expired */ | ||
51 | void timeout_check(const char *operation) | ||
52 | { | ||
53 | if (timeout) { | ||
54 | fprintf(stderr, "%s timed out\n", operation); | ||
55 | exit(EXIT_FAILURE); | ||
56 | } | ||
57 | } | ||
58 | |||
59 | /* Stop a timeout */ | ||
60 | void timeout_end(void) | ||
61 | { | ||
62 | alarm(0); | ||
63 | timeout = false; | ||
64 | } | ||
diff --git a/tools/testing/vsock/timeout.h b/tools/testing/vsock/timeout.h new file mode 100644 index 000000000000..77db9ce9860a --- /dev/null +++ b/tools/testing/vsock/timeout.h | |||
@@ -0,0 +1,14 @@ | |||
1 | #ifndef TIMEOUT_H | ||
2 | #define TIMEOUT_H | ||
3 | |||
4 | enum { | ||
5 | /* Default timeout */ | ||
6 | TIMEOUT = 10 /* seconds */ | ||
7 | }; | ||
8 | |||
9 | void sigalrm(int signo); | ||
10 | void timeout_begin(unsigned int seconds); | ||
11 | void timeout_check(const char *operation); | ||
12 | void timeout_end(void); | ||
13 | |||
14 | #endif /* TIMEOUT_H */ | ||
diff --git a/tools/testing/vsock/vsock_diag_test.c b/tools/testing/vsock/vsock_diag_test.c new file mode 100644 index 000000000000..e896a4af52f4 --- /dev/null +++ b/tools/testing/vsock/vsock_diag_test.c | |||
@@ -0,0 +1,681 @@ | |||
1 | /* | ||
2 | * vsock_diag_test - vsock_diag.ko test suite | ||
3 | * | ||
4 | * Copyright (C) 2017 Red Hat, Inc. | ||
5 | * | ||
6 | * Author: Stefan Hajnoczi <stefanha@redhat.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; version 2 | ||
11 | * of the License. | ||
12 | */ | ||
13 | |||
14 | #include <getopt.h> | ||
15 | #include <stdio.h> | ||
16 | #include <stdbool.h> | ||
17 | #include <stdlib.h> | ||
18 | #include <string.h> | ||
19 | #include <errno.h> | ||
20 | #include <unistd.h> | ||
21 | #include <signal.h> | ||
22 | #include <sys/socket.h> | ||
23 | #include <sys/stat.h> | ||
24 | #include <sys/types.h> | ||
25 | #include <linux/list.h> | ||
26 | #include <linux/net.h> | ||
27 | #include <linux/netlink.h> | ||
28 | #include <linux/sock_diag.h> | ||
29 | #include <netinet/tcp.h> | ||
30 | |||
31 | #include "../../../include/uapi/linux/vm_sockets.h" | ||
32 | #include "../../../include/uapi/linux/vm_sockets_diag.h" | ||
33 | |||
34 | #include "timeout.h" | ||
35 | #include "control.h" | ||
36 | |||
37 | enum test_mode { | ||
38 | TEST_MODE_UNSET, | ||
39 | TEST_MODE_CLIENT, | ||
40 | TEST_MODE_SERVER | ||
41 | }; | ||
42 | |||
43 | /* Per-socket status */ | ||
44 | struct vsock_stat { | ||
45 | struct list_head list; | ||
46 | struct vsock_diag_msg msg; | ||
47 | }; | ||
48 | |||
49 | static const char *sock_type_str(int type) | ||
50 | { | ||
51 | switch (type) { | ||
52 | case SOCK_DGRAM: | ||
53 | return "DGRAM"; | ||
54 | case SOCK_STREAM: | ||
55 | return "STREAM"; | ||
56 | default: | ||
57 | return "INVALID TYPE"; | ||
58 | } | ||
59 | } | ||
60 | |||
61 | static const char *sock_state_str(int state) | ||
62 | { | ||
63 | switch (state) { | ||
64 | case TCP_CLOSE: | ||
65 | return "UNCONNECTED"; | ||
66 | case TCP_SYN_SENT: | ||
67 | return "CONNECTING"; | ||
68 | case TCP_ESTABLISHED: | ||
69 | return "CONNECTED"; | ||
70 | case TCP_CLOSING: | ||
71 | return "DISCONNECTING"; | ||
72 | case TCP_LISTEN: | ||
73 | return "LISTEN"; | ||
74 | default: | ||
75 | return "INVALID STATE"; | ||
76 | } | ||
77 | } | ||
78 | |||
79 | static const char *sock_shutdown_str(int shutdown) | ||
80 | { | ||
81 | switch (shutdown) { | ||
82 | case 1: | ||
83 | return "RCV_SHUTDOWN"; | ||
84 | case 2: | ||
85 | return "SEND_SHUTDOWN"; | ||
86 | case 3: | ||
87 | return "RCV_SHUTDOWN | SEND_SHUTDOWN"; | ||
88 | default: | ||
89 | return "0"; | ||
90 | } | ||
91 | } | ||
92 | |||
93 | static void print_vsock_addr(FILE *fp, unsigned int cid, unsigned int port) | ||
94 | { | ||
95 | if (cid == VMADDR_CID_ANY) | ||
96 | fprintf(fp, "*:"); | ||
97 | else | ||
98 | fprintf(fp, "%u:", cid); | ||
99 | |||
100 | if (port == VMADDR_PORT_ANY) | ||
101 | fprintf(fp, "*"); | ||
102 | else | ||
103 | fprintf(fp, "%u", port); | ||
104 | } | ||
105 | |||
106 | static void print_vsock_stat(FILE *fp, struct vsock_stat *st) | ||
107 | { | ||
108 | print_vsock_addr(fp, st->msg.vdiag_src_cid, st->msg.vdiag_src_port); | ||
109 | fprintf(fp, " "); | ||
110 | print_vsock_addr(fp, st->msg.vdiag_dst_cid, st->msg.vdiag_dst_port); | ||
111 | fprintf(fp, " %s %s %s %u\n", | ||
112 | sock_type_str(st->msg.vdiag_type), | ||
113 | sock_state_str(st->msg.vdiag_state), | ||
114 | sock_shutdown_str(st->msg.vdiag_shutdown), | ||
115 | st->msg.vdiag_ino); | ||
116 | } | ||
117 | |||
118 | static void print_vsock_stats(FILE *fp, struct list_head *head) | ||
119 | { | ||
120 | struct vsock_stat *st; | ||
121 | |||
122 | list_for_each_entry(st, head, list) | ||
123 | print_vsock_stat(fp, st); | ||
124 | } | ||
125 | |||
126 | static struct vsock_stat *find_vsock_stat(struct list_head *head, int fd) | ||
127 | { | ||
128 | struct vsock_stat *st; | ||
129 | struct stat stat; | ||
130 | |||
131 | if (fstat(fd, &stat) < 0) { | ||
132 | perror("fstat"); | ||
133 | exit(EXIT_FAILURE); | ||
134 | } | ||
135 | |||
136 | list_for_each_entry(st, head, list) | ||
137 | if (st->msg.vdiag_ino == stat.st_ino) | ||
138 | return st; | ||
139 | |||
140 | fprintf(stderr, "cannot find fd %d\n", fd); | ||
141 | exit(EXIT_FAILURE); | ||
142 | } | ||
143 | |||
144 | static void check_no_sockets(struct list_head *head) | ||
145 | { | ||
146 | if (!list_empty(head)) { | ||
147 | fprintf(stderr, "expected no sockets\n"); | ||
148 | print_vsock_stats(stderr, head); | ||
149 | exit(1); | ||
150 | } | ||
151 | } | ||
152 | |||
153 | static void check_num_sockets(struct list_head *head, int expected) | ||
154 | { | ||
155 | struct list_head *node; | ||
156 | int n = 0; | ||
157 | |||
158 | list_for_each(node, head) | ||
159 | n++; | ||
160 | |||
161 | if (n != expected) { | ||
162 | fprintf(stderr, "expected %d sockets, found %d\n", | ||
163 | expected, n); | ||
164 | print_vsock_stats(stderr, head); | ||
165 | exit(EXIT_FAILURE); | ||
166 | } | ||
167 | } | ||
168 | |||
169 | static void check_socket_state(struct vsock_stat *st, __u8 state) | ||
170 | { | ||
171 | if (st->msg.vdiag_state != state) { | ||
172 | fprintf(stderr, "expected socket state %#x, got %#x\n", | ||
173 | state, st->msg.vdiag_state); | ||
174 | exit(EXIT_FAILURE); | ||
175 | } | ||
176 | } | ||
177 | |||
178 | static void send_req(int fd) | ||
179 | { | ||
180 | struct sockaddr_nl nladdr = { | ||
181 | .nl_family = AF_NETLINK, | ||
182 | }; | ||
183 | struct { | ||
184 | struct nlmsghdr nlh; | ||
185 | struct vsock_diag_req vreq; | ||
186 | } req = { | ||
187 | .nlh = { | ||
188 | .nlmsg_len = sizeof(req), | ||
189 | .nlmsg_type = SOCK_DIAG_BY_FAMILY, | ||
190 | .nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP, | ||
191 | }, | ||
192 | .vreq = { | ||
193 | .sdiag_family = AF_VSOCK, | ||
194 | .vdiag_states = ~(__u32)0, | ||
195 | }, | ||
196 | }; | ||
197 | struct iovec iov = { | ||
198 | .iov_base = &req, | ||
199 | .iov_len = sizeof(req), | ||
200 | }; | ||
201 | struct msghdr msg = { | ||
202 | .msg_name = &nladdr, | ||
203 | .msg_namelen = sizeof(nladdr), | ||
204 | .msg_iov = &iov, | ||
205 | .msg_iovlen = 1, | ||
206 | }; | ||
207 | |||
208 | for (;;) { | ||
209 | if (sendmsg(fd, &msg, 0) < 0) { | ||
210 | if (errno == EINTR) | ||
211 | continue; | ||
212 | |||
213 | perror("sendmsg"); | ||
214 | exit(EXIT_FAILURE); | ||
215 | } | ||
216 | |||
217 | return; | ||
218 | } | ||
219 | } | ||
220 | |||
221 | static ssize_t recv_resp(int fd, void *buf, size_t len) | ||
222 | { | ||
223 | struct sockaddr_nl nladdr = { | ||
224 | .nl_family = AF_NETLINK, | ||
225 | }; | ||
226 | struct iovec iov = { | ||
227 | .iov_base = buf, | ||
228 | .iov_len = len, | ||
229 | }; | ||
230 | struct msghdr msg = { | ||
231 | .msg_name = &nladdr, | ||
232 | .msg_namelen = sizeof(nladdr), | ||
233 | .msg_iov = &iov, | ||
234 | .msg_iovlen = 1, | ||
235 | }; | ||
236 | ssize_t ret; | ||
237 | |||
238 | do { | ||
239 | ret = recvmsg(fd, &msg, 0); | ||
240 | } while (ret < 0 && errno == EINTR); | ||
241 | |||
242 | if (ret < 0) { | ||
243 | perror("recvmsg"); | ||
244 | exit(EXIT_FAILURE); | ||
245 | } | ||
246 | |||
247 | return ret; | ||
248 | } | ||
249 | |||
250 | static void add_vsock_stat(struct list_head *sockets, | ||
251 | const struct vsock_diag_msg *resp) | ||
252 | { | ||
253 | struct vsock_stat *st; | ||
254 | |||
255 | st = malloc(sizeof(*st)); | ||
256 | if (!st) { | ||
257 | perror("malloc"); | ||
258 | exit(EXIT_FAILURE); | ||
259 | } | ||
260 | |||
261 | st->msg = *resp; | ||
262 | list_add_tail(&st->list, sockets); | ||
263 | } | ||
264 | |||
265 | /* | ||
266 | * Read vsock stats into a list. | ||
267 | */ | ||
268 | static void read_vsock_stat(struct list_head *sockets) | ||
269 | { | ||
270 | long buf[8192 / sizeof(long)]; | ||
271 | int fd; | ||
272 | |||
273 | fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG); | ||
274 | if (fd < 0) { | ||
275 | perror("socket"); | ||
276 | exit(EXIT_FAILURE); | ||
277 | } | ||
278 | |||
279 | send_req(fd); | ||
280 | |||
281 | for (;;) { | ||
282 | const struct nlmsghdr *h; | ||
283 | ssize_t ret; | ||
284 | |||
285 | ret = recv_resp(fd, buf, sizeof(buf)); | ||
286 | if (ret == 0) | ||
287 | goto done; | ||
288 | if (ret < sizeof(*h)) { | ||
289 | fprintf(stderr, "short read of %zd bytes\n", ret); | ||
290 | exit(EXIT_FAILURE); | ||
291 | } | ||
292 | |||
293 | h = (struct nlmsghdr *)buf; | ||
294 | |||
295 | while (NLMSG_OK(h, ret)) { | ||
296 | if (h->nlmsg_type == NLMSG_DONE) | ||
297 | goto done; | ||
298 | |||
299 | if (h->nlmsg_type == NLMSG_ERROR) { | ||
300 | const struct nlmsgerr *err = NLMSG_DATA(h); | ||
301 | |||
302 | if (h->nlmsg_len < NLMSG_LENGTH(sizeof(*err))) | ||
303 | fprintf(stderr, "NLMSG_ERROR\n"); | ||
304 | else { | ||
305 | errno = -err->error; | ||
306 | perror("NLMSG_ERROR"); | ||
307 | } | ||
308 | |||
309 | exit(EXIT_FAILURE); | ||
310 | } | ||
311 | |||
312 | if (h->nlmsg_type != SOCK_DIAG_BY_FAMILY) { | ||
313 | fprintf(stderr, "unexpected nlmsg_type %#x\n", | ||
314 | h->nlmsg_type); | ||
315 | exit(EXIT_FAILURE); | ||
316 | } | ||
317 | if (h->nlmsg_len < | ||
318 | NLMSG_LENGTH(sizeof(struct vsock_diag_msg))) { | ||
319 | fprintf(stderr, "short vsock_diag_msg\n"); | ||
320 | exit(EXIT_FAILURE); | ||
321 | } | ||
322 | |||
323 | add_vsock_stat(sockets, NLMSG_DATA(h)); | ||
324 | |||
325 | h = NLMSG_NEXT(h, ret); | ||
326 | } | ||
327 | } | ||
328 | |||
329 | done: | ||
330 | close(fd); | ||
331 | } | ||
332 | |||
333 | static void free_sock_stat(struct list_head *sockets) | ||
334 | { | ||
335 | struct vsock_stat *st; | ||
336 | struct vsock_stat *next; | ||
337 | |||
338 | list_for_each_entry_safe(st, next, sockets, list) | ||
339 | free(st); | ||
340 | } | ||
341 | |||
342 | static void test_no_sockets(unsigned int peer_cid) | ||
343 | { | ||
344 | LIST_HEAD(sockets); | ||
345 | |||
346 | read_vsock_stat(&sockets); | ||
347 | |||
348 | check_no_sockets(&sockets); | ||
349 | |||
350 | free_sock_stat(&sockets); | ||
351 | } | ||
352 | |||
353 | static void test_listen_socket_server(unsigned int peer_cid) | ||
354 | { | ||
355 | union { | ||
356 | struct sockaddr sa; | ||
357 | struct sockaddr_vm svm; | ||
358 | } addr = { | ||
359 | .svm = { | ||
360 | .svm_family = AF_VSOCK, | ||
361 | .svm_port = 1234, | ||
362 | .svm_cid = VMADDR_CID_ANY, | ||
363 | }, | ||
364 | }; | ||
365 | LIST_HEAD(sockets); | ||
366 | struct vsock_stat *st; | ||
367 | int fd; | ||
368 | |||
369 | fd = socket(AF_VSOCK, SOCK_STREAM, 0); | ||
370 | |||
371 | if (bind(fd, &addr.sa, sizeof(addr.svm)) < 0) { | ||
372 | perror("bind"); | ||
373 | exit(EXIT_FAILURE); | ||
374 | } | ||
375 | |||
376 | if (listen(fd, 1) < 0) { | ||
377 | perror("listen"); | ||
378 | exit(EXIT_FAILURE); | ||
379 | } | ||
380 | |||
381 | read_vsock_stat(&sockets); | ||
382 | |||
383 | check_num_sockets(&sockets, 1); | ||
384 | st = find_vsock_stat(&sockets, fd); | ||
385 | check_socket_state(st, TCP_LISTEN); | ||
386 | |||
387 | close(fd); | ||
388 | free_sock_stat(&sockets); | ||
389 | } | ||
390 | |||
391 | static void test_connect_client(unsigned int peer_cid) | ||
392 | { | ||
393 | union { | ||
394 | struct sockaddr sa; | ||
395 | struct sockaddr_vm svm; | ||
396 | } addr = { | ||
397 | .svm = { | ||
398 | .svm_family = AF_VSOCK, | ||
399 | .svm_port = 1234, | ||
400 | .svm_cid = peer_cid, | ||
401 | }, | ||
402 | }; | ||
403 | int fd; | ||
404 | int ret; | ||
405 | LIST_HEAD(sockets); | ||
406 | struct vsock_stat *st; | ||
407 | |||
408 | control_expectln("LISTENING"); | ||
409 | |||
410 | fd = socket(AF_VSOCK, SOCK_STREAM, 0); | ||
411 | |||
412 | timeout_begin(TIMEOUT); | ||
413 | do { | ||
414 | ret = connect(fd, &addr.sa, sizeof(addr.svm)); | ||
415 | timeout_check("connect"); | ||
416 | } while (ret < 0 && errno == EINTR); | ||
417 | timeout_end(); | ||
418 | |||
419 | if (ret < 0) { | ||
420 | perror("connect"); | ||
421 | exit(EXIT_FAILURE); | ||
422 | } | ||
423 | |||
424 | read_vsock_stat(&sockets); | ||
425 | |||
426 | check_num_sockets(&sockets, 1); | ||
427 | st = find_vsock_stat(&sockets, fd); | ||
428 | check_socket_state(st, TCP_ESTABLISHED); | ||
429 | |||
430 | control_expectln("DONE"); | ||
431 | control_writeln("DONE"); | ||
432 | |||
433 | close(fd); | ||
434 | free_sock_stat(&sockets); | ||
435 | } | ||
436 | |||
437 | static void test_connect_server(unsigned int peer_cid) | ||
438 | { | ||
439 | union { | ||
440 | struct sockaddr sa; | ||
441 | struct sockaddr_vm svm; | ||
442 | } addr = { | ||
443 | .svm = { | ||
444 | .svm_family = AF_VSOCK, | ||
445 | .svm_port = 1234, | ||
446 | .svm_cid = VMADDR_CID_ANY, | ||
447 | }, | ||
448 | }; | ||
449 | union { | ||
450 | struct sockaddr sa; | ||
451 | struct sockaddr_vm svm; | ||
452 | } clientaddr; | ||
453 | socklen_t clientaddr_len = sizeof(clientaddr.svm); | ||
454 | LIST_HEAD(sockets); | ||
455 | struct vsock_stat *st; | ||
456 | int fd; | ||
457 | int client_fd; | ||
458 | |||
459 | fd = socket(AF_VSOCK, SOCK_STREAM, 0); | ||
460 | |||
461 | if (bind(fd, &addr.sa, sizeof(addr.svm)) < 0) { | ||
462 | perror("bind"); | ||
463 | exit(EXIT_FAILURE); | ||
464 | } | ||
465 | |||
466 | if (listen(fd, 1) < 0) { | ||
467 | perror("listen"); | ||
468 | exit(EXIT_FAILURE); | ||
469 | } | ||
470 | |||
471 | control_writeln("LISTENING"); | ||
472 | |||
473 | timeout_begin(TIMEOUT); | ||
474 | do { | ||
475 | client_fd = accept(fd, &clientaddr.sa, &clientaddr_len); | ||
476 | timeout_check("accept"); | ||
477 | } while (client_fd < 0 && errno == EINTR); | ||
478 | timeout_end(); | ||
479 | |||
480 | if (client_fd < 0) { | ||
481 | perror("accept"); | ||
482 | exit(EXIT_FAILURE); | ||
483 | } | ||
484 | if (clientaddr.sa.sa_family != AF_VSOCK) { | ||
485 | fprintf(stderr, "expected AF_VSOCK from accept(2), got %d\n", | ||
486 | clientaddr.sa.sa_family); | ||
487 | exit(EXIT_FAILURE); | ||
488 | } | ||
489 | if (clientaddr.svm.svm_cid != peer_cid) { | ||
490 | fprintf(stderr, "expected peer CID %u from accept(2), got %u\n", | ||
491 | peer_cid, clientaddr.svm.svm_cid); | ||
492 | exit(EXIT_FAILURE); | ||
493 | } | ||
494 | |||
495 | read_vsock_stat(&sockets); | ||
496 | |||
497 | check_num_sockets(&sockets, 2); | ||
498 | find_vsock_stat(&sockets, fd); | ||
499 | st = find_vsock_stat(&sockets, client_fd); | ||
500 | check_socket_state(st, TCP_ESTABLISHED); | ||
501 | |||
502 | control_writeln("DONE"); | ||
503 | control_expectln("DONE"); | ||
504 | |||
505 | close(client_fd); | ||
506 | close(fd); | ||
507 | free_sock_stat(&sockets); | ||
508 | } | ||
509 | |||
510 | static struct { | ||
511 | const char *name; | ||
512 | void (*run_client)(unsigned int peer_cid); | ||
513 | void (*run_server)(unsigned int peer_cid); | ||
514 | } test_cases[] = { | ||
515 | { | ||
516 | .name = "No sockets", | ||
517 | .run_server = test_no_sockets, | ||
518 | }, | ||
519 | { | ||
520 | .name = "Listen socket", | ||
521 | .run_server = test_listen_socket_server, | ||
522 | }, | ||
523 | { | ||
524 | .name = "Connect", | ||
525 | .run_client = test_connect_client, | ||
526 | .run_server = test_connect_server, | ||
527 | }, | ||
528 | {}, | ||
529 | }; | ||
530 | |||
531 | static void init_signals(void) | ||
532 | { | ||
533 | struct sigaction act = { | ||
534 | .sa_handler = sigalrm, | ||
535 | }; | ||
536 | |||
537 | sigaction(SIGALRM, &act, NULL); | ||
538 | signal(SIGPIPE, SIG_IGN); | ||
539 | } | ||
540 | |||
541 | static unsigned int parse_cid(const char *str) | ||
542 | { | ||
543 | char *endptr = NULL; | ||
544 | unsigned long int n; | ||
545 | |||
546 | errno = 0; | ||
547 | n = strtoul(str, &endptr, 10); | ||
548 | if (errno || *endptr != '\0') { | ||
549 | fprintf(stderr, "malformed CID \"%s\"\n", str); | ||
550 | exit(EXIT_FAILURE); | ||
551 | } | ||
552 | return n; | ||
553 | } | ||
554 | |||
555 | static const char optstring[] = ""; | ||
556 | static const struct option longopts[] = { | ||
557 | { | ||
558 | .name = "control-host", | ||
559 | .has_arg = required_argument, | ||
560 | .val = 'H', | ||
561 | }, | ||
562 | { | ||
563 | .name = "control-port", | ||
564 | .has_arg = required_argument, | ||
565 | .val = 'P', | ||
566 | }, | ||
567 | { | ||
568 | .name = "mode", | ||
569 | .has_arg = required_argument, | ||
570 | .val = 'm', | ||
571 | }, | ||
572 | { | ||
573 | .name = "peer-cid", | ||
574 | .has_arg = required_argument, | ||
575 | .val = 'p', | ||
576 | }, | ||
577 | { | ||
578 | .name = "help", | ||
579 | .has_arg = no_argument, | ||
580 | .val = '?', | ||
581 | }, | ||
582 | {}, | ||
583 | }; | ||
584 | |||
585 | static void usage(void) | ||
586 | { | ||
587 | fprintf(stderr, "Usage: vsock_diag_test [--help] [--control-host=<host>] --control-port=<port> --mode=client|server --peer-cid=<cid>\n" | ||
588 | "\n" | ||
589 | " Server: vsock_diag_test --control-port=1234 --mode=server --peer-cid=3\n" | ||
590 | " Client: vsock_diag_test --control-host=192.168.0.1 --control-port=1234 --mode=client --peer-cid=2\n" | ||
591 | "\n" | ||
592 | "Run vsock_diag.ko tests. Must be launched in both\n" | ||
593 | "guest and host. One side must use --mode=client and\n" | ||
594 | "the other side must use --mode=server.\n" | ||
595 | "\n" | ||
596 | "A TCP control socket connection is used to coordinate tests\n" | ||
597 | "between the client and the server. The server requires a\n" | ||
598 | "listen address and the client requires an address to\n" | ||
599 | "connect to.\n" | ||
600 | "\n" | ||
601 | "The CID of the other side must be given with --peer-cid=<cid>.\n"); | ||
602 | exit(EXIT_FAILURE); | ||
603 | } | ||
604 | |||
605 | int main(int argc, char **argv) | ||
606 | { | ||
607 | const char *control_host = NULL; | ||
608 | const char *control_port = NULL; | ||
609 | int mode = TEST_MODE_UNSET; | ||
610 | unsigned int peer_cid = VMADDR_CID_ANY; | ||
611 | int i; | ||
612 | |||
613 | init_signals(); | ||
614 | |||
615 | for (;;) { | ||
616 | int opt = getopt_long(argc, argv, optstring, longopts, NULL); | ||
617 | |||
618 | if (opt == -1) | ||
619 | break; | ||
620 | |||
621 | switch (opt) { | ||
622 | case 'H': | ||
623 | control_host = optarg; | ||
624 | break; | ||
625 | case 'm': | ||
626 | if (strcmp(optarg, "client") == 0) | ||
627 | mode = TEST_MODE_CLIENT; | ||
628 | else if (strcmp(optarg, "server") == 0) | ||
629 | mode = TEST_MODE_SERVER; | ||
630 | else { | ||
631 | fprintf(stderr, "--mode must be \"client\" or \"server\"\n"); | ||
632 | return EXIT_FAILURE; | ||
633 | } | ||
634 | break; | ||
635 | case 'p': | ||
636 | peer_cid = parse_cid(optarg); | ||
637 | break; | ||
638 | case 'P': | ||
639 | control_port = optarg; | ||
640 | break; | ||
641 | case '?': | ||
642 | default: | ||
643 | usage(); | ||
644 | } | ||
645 | } | ||
646 | |||
647 | if (!control_port) | ||
648 | usage(); | ||
649 | if (mode == TEST_MODE_UNSET) | ||
650 | usage(); | ||
651 | if (peer_cid == VMADDR_CID_ANY) | ||
652 | usage(); | ||
653 | |||
654 | if (!control_host) { | ||
655 | if (mode != TEST_MODE_SERVER) | ||
656 | usage(); | ||
657 | control_host = "0.0.0.0"; | ||
658 | } | ||
659 | |||
660 | control_init(control_host, control_port, mode == TEST_MODE_SERVER); | ||
661 | |||
662 | for (i = 0; test_cases[i].name; i++) { | ||
663 | void (*run)(unsigned int peer_cid); | ||
664 | |||
665 | printf("%s...", test_cases[i].name); | ||
666 | fflush(stdout); | ||
667 | |||
668 | if (mode == TEST_MODE_CLIENT) | ||
669 | run = test_cases[i].run_client; | ||
670 | else | ||
671 | run = test_cases[i].run_server; | ||
672 | |||
673 | if (run) | ||
674 | run(peer_cid); | ||
675 | |||
676 | printf("ok\n"); | ||
677 | } | ||
678 | |||
679 | control_cleanup(); | ||
680 | return EXIT_SUCCESS; | ||
681 | } | ||
diff --git a/tools/thermal/tmon/Makefile b/tools/thermal/tmon/Makefile index 21169322baea..735a510230c3 100644 --- a/tools/thermal/tmon/Makefile +++ b/tools/thermal/tmon/Makefile | |||
@@ -1,10 +1,16 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 | 1 | # SPDX-License-Identifier: GPL-2.0 |
2 | # We need this for the "cc-option" macro. | ||
3 | include ../../../scripts/Kbuild.include | ||
4 | |||
2 | VERSION = 1.0 | 5 | VERSION = 1.0 |
3 | 6 | ||
4 | BINDIR=usr/bin | 7 | BINDIR=usr/bin |
5 | WARNFLAGS=-Wall -Wshadow -W -Wformat -Wimplicit-function-declaration -Wimplicit-int | 8 | WARNFLAGS=-Wall -Wshadow -W -Wformat -Wimplicit-function-declaration -Wimplicit-int |
6 | CFLAGS+= -O1 ${WARNFLAGS} -fstack-protector | 9 | CFLAGS+= -O1 ${WARNFLAGS} |
7 | CC=$(CROSS_COMPILE)gcc | 10 | # Add "-fstack-protector" only if toolchain supports it. |
11 | CFLAGS+= $(call cc-option,-fstack-protector) | ||
12 | CC?= $(CROSS_COMPILE)gcc | ||
13 | PKG_CONFIG?= pkg-config | ||
8 | 14 | ||
9 | CFLAGS+=-D VERSION=\"$(VERSION)\" | 15 | CFLAGS+=-D VERSION=\"$(VERSION)\" |
10 | LDFLAGS+= | 16 | LDFLAGS+= |
@@ -19,12 +25,12 @@ STATIC := --static | |||
19 | endif | 25 | endif |
20 | 26 | ||
21 | TMON_LIBS=-lm -lpthread | 27 | TMON_LIBS=-lm -lpthread |
22 | TMON_LIBS += $(shell pkg-config --libs $(STATIC) panelw ncursesw 2> /dev/null || \ | 28 | TMON_LIBS += $(shell $(PKG_CONFIG) --libs $(STATIC) panelw ncursesw 2> /dev/null || \ |
23 | pkg-config --libs $(STATIC) panel ncurses 2> /dev/null || \ | 29 | $(PKG_CONFIG) --libs $(STATIC) panel ncurses 2> /dev/null || \ |
24 | echo -lpanel -lncurses) | 30 | echo -lpanel -lncurses) |
25 | 31 | ||
26 | CFLAGS += $(shell pkg-config --cflags $(STATIC) panelw ncursesw 2> /dev/null || \ | 32 | CFLAGS += $(shell $(PKG_CONFIG) --cflags $(STATIC) panelw ncursesw 2> /dev/null || \ |
27 | pkg-config --cflags $(STATIC) panel ncurses 2> /dev/null) | 33 | $(PKG_CONFIG) --cflags $(STATIC) panel ncurses 2> /dev/null) |
28 | 34 | ||
29 | OBJS = tmon.o tui.o sysfs.o pid.o | 35 | OBJS = tmon.o tui.o sysfs.o pid.o |
30 | OBJS += | 36 | OBJS += |
diff --git a/tools/usb/usbip/Makefile.am b/tools/usb/usbip/Makefile.am index da3a430849a8..5961e9c18812 100644 --- a/tools/usb/usbip/Makefile.am +++ b/tools/usb/usbip/Makefile.am | |||
@@ -2,6 +2,7 @@ | |||
2 | SUBDIRS := libsrc src | 2 | SUBDIRS := libsrc src |
3 | includedir = @includedir@/usbip | 3 | includedir = @includedir@/usbip |
4 | include_HEADERS := $(addprefix libsrc/, \ | 4 | include_HEADERS := $(addprefix libsrc/, \ |
5 | usbip_common.h vhci_driver.h usbip_host_driver.h) | 5 | usbip_common.h vhci_driver.h usbip_host_driver.h \ |
6 | list.h sysfs_utils.h usbip_host_common.h) | ||
6 | 7 | ||
7 | dist_man_MANS := $(addprefix doc/, usbip.8 usbipd.8) | 8 | dist_man_MANS := $(addprefix doc/, usbip.8 usbipd.8) |
diff --git a/tools/usb/usbip/libsrc/vhci_driver.c b/tools/usb/usbip/libsrc/vhci_driver.c index 5727dfb15a83..8a1cd1616de4 100644 --- a/tools/usb/usbip/libsrc/vhci_driver.c +++ b/tools/usb/usbip/libsrc/vhci_driver.c | |||
@@ -329,9 +329,17 @@ err: | |||
329 | int usbip_vhci_get_free_port(uint32_t speed) | 329 | int usbip_vhci_get_free_port(uint32_t speed) |
330 | { | 330 | { |
331 | for (int i = 0; i < vhci_driver->nports; i++) { | 331 | for (int i = 0; i < vhci_driver->nports; i++) { |
332 | if (speed == USB_SPEED_SUPER && | 332 | |
333 | vhci_driver->idev[i].hub != HUB_SPEED_SUPER) | 333 | switch (speed) { |
334 | continue; | 334 | case USB_SPEED_SUPER: |
335 | if (vhci_driver->idev[i].hub != HUB_SPEED_SUPER) | ||
336 | continue; | ||
337 | break; | ||
338 | default: | ||
339 | if (vhci_driver->idev[i].hub != HUB_SPEED_HIGH) | ||
340 | continue; | ||
341 | break; | ||
342 | } | ||
335 | 343 | ||
336 | if (vhci_driver->idev[i].status == VDEV_ST_NULL) | 344 | if (vhci_driver->idev[i].status == VDEV_ST_NULL) |
337 | return vhci_driver->idev[i].port; | 345 | return vhci_driver->idev[i].port; |
diff --git a/tools/vm/slabinfo.c b/tools/vm/slabinfo.c index b0b7ef6d0de1..f82c2eaa859d 100644 --- a/tools/vm/slabinfo.c +++ b/tools/vm/slabinfo.c | |||
@@ -84,6 +84,7 @@ int output_lines = -1; | |||
84 | int sort_loss; | 84 | int sort_loss; |
85 | int extended_totals; | 85 | int extended_totals; |
86 | int show_bytes; | 86 | int show_bytes; |
87 | int unreclaim_only; | ||
87 | 88 | ||
88 | /* Debug options */ | 89 | /* Debug options */ |
89 | int sanity; | 90 | int sanity; |
@@ -133,6 +134,7 @@ static void usage(void) | |||
133 | "-L|--Loss Sort by loss\n" | 134 | "-L|--Loss Sort by loss\n" |
134 | "-X|--Xtotals Show extended summary information\n" | 135 | "-X|--Xtotals Show extended summary information\n" |
135 | "-B|--Bytes Show size in bytes\n" | 136 | "-B|--Bytes Show size in bytes\n" |
137 | "-U|--Unreclaim Show unreclaimable slabs only\n" | ||
136 | "\nValid debug options (FZPUT may be combined)\n" | 138 | "\nValid debug options (FZPUT may be combined)\n" |
137 | "a / A Switch on all debug options (=FZUP)\n" | 139 | "a / A Switch on all debug options (=FZUP)\n" |
138 | "- Switch off all debug options\n" | 140 | "- Switch off all debug options\n" |
@@ -569,6 +571,9 @@ static void slabcache(struct slabinfo *s) | |||
569 | if (strcmp(s->name, "*") == 0) | 571 | if (strcmp(s->name, "*") == 0) |
570 | return; | 572 | return; |
571 | 573 | ||
574 | if (unreclaim_only && s->reclaim_account) | ||
575 | return; | ||
576 | |||
572 | if (actual_slabs == 1) { | 577 | if (actual_slabs == 1) { |
573 | report(s); | 578 | report(s); |
574 | return; | 579 | return; |
@@ -1347,6 +1352,7 @@ struct option opts[] = { | |||
1347 | { "Loss", no_argument, NULL, 'L'}, | 1352 | { "Loss", no_argument, NULL, 'L'}, |
1348 | { "Xtotals", no_argument, NULL, 'X'}, | 1353 | { "Xtotals", no_argument, NULL, 'X'}, |
1349 | { "Bytes", no_argument, NULL, 'B'}, | 1354 | { "Bytes", no_argument, NULL, 'B'}, |
1355 | { "Unreclaim", no_argument, NULL, 'U'}, | ||
1350 | { NULL, 0, NULL, 0 } | 1356 | { NULL, 0, NULL, 0 } |
1351 | }; | 1357 | }; |
1352 | 1358 | ||
@@ -1358,7 +1364,7 @@ int main(int argc, char *argv[]) | |||
1358 | 1364 | ||
1359 | page_size = getpagesize(); | 1365 | page_size = getpagesize(); |
1360 | 1366 | ||
1361 | while ((c = getopt_long(argc, argv, "aAd::Defhil1noprstvzTSN:LXB", | 1367 | while ((c = getopt_long(argc, argv, "aAd::Defhil1noprstvzTSN:LXBU", |
1362 | opts, NULL)) != -1) | 1368 | opts, NULL)) != -1) |
1363 | switch (c) { | 1369 | switch (c) { |
1364 | case '1': | 1370 | case '1': |
@@ -1439,6 +1445,9 @@ int main(int argc, char *argv[]) | |||
1439 | case 'B': | 1445 | case 'B': |
1440 | show_bytes = 1; | 1446 | show_bytes = 1; |
1441 | break; | 1447 | break; |
1448 | case 'U': | ||
1449 | unreclaim_only = 1; | ||
1450 | break; | ||
1442 | default: | 1451 | default: |
1443 | fatal("%s: Invalid option '%c'\n", argv[0], optopt); | 1452 | fatal("%s: Invalid option '%c'\n", argv[0], optopt); |
1444 | 1453 | ||
diff --git a/tools/wmi/Makefile b/tools/wmi/Makefile new file mode 100644 index 000000000000..e664f1167388 --- /dev/null +++ b/tools/wmi/Makefile | |||
@@ -0,0 +1,18 @@ | |||
1 | PREFIX ?= /usr | ||
2 | SBINDIR ?= sbin | ||
3 | INSTALL ?= install | ||
4 | CFLAGS += -D__EXPORTED_HEADERS__ -I../../include/uapi -I../../include | ||
5 | CC = $(CROSS_COMPILE)gcc | ||
6 | |||
7 | TARGET = dell-smbios-example | ||
8 | |||
9 | all: $(TARGET) | ||
10 | |||
11 | %: %.c | ||
12 | $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< | ||
13 | |||
14 | clean: | ||
15 | $(RM) $(TARGET) | ||
16 | |||
17 | install: dell-smbios-example | ||
18 | $(INSTALL) -D -m 755 $(TARGET) $(DESTDIR)$(PREFIX)/$(SBINDIR)/$(TARGET) | ||
diff --git a/tools/wmi/dell-smbios-example.c b/tools/wmi/dell-smbios-example.c new file mode 100644 index 000000000000..9d3bde081249 --- /dev/null +++ b/tools/wmi/dell-smbios-example.c | |||
@@ -0,0 +1,210 @@ | |||
1 | /* | ||
2 | * Sample application for SMBIOS communication over WMI interface | ||
3 | * Performs the following: | ||
4 | * - Simple cmd_class/cmd_select lookup for TPM information | ||
5 | * - Simple query of known tokens and their values | ||
6 | * - Simple activation of a token | ||
7 | * | ||
8 | * Copyright (C) 2017 Dell, Inc. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <errno.h> | ||
16 | #include <fcntl.h> | ||
17 | #include <stdio.h> | ||
18 | #include <stdlib.h> | ||
19 | #include <sys/ioctl.h> | ||
20 | #include <unistd.h> | ||
21 | |||
22 | /* if uapi header isn't installed, this might not yet exist */ | ||
23 | #ifndef __packed | ||
24 | #define __packed __attribute__((packed)) | ||
25 | #endif | ||
26 | #include <linux/wmi.h> | ||
27 | |||
28 | /* It would be better to discover these using udev, but for a simple | ||
29 | * application they're hardcoded | ||
30 | */ | ||
31 | static const char *ioctl_devfs = "/dev/wmi/dell-smbios"; | ||
32 | static const char *token_sysfs = | ||
33 | "/sys/bus/platform/devices/dell-smbios.0/tokens"; | ||
34 | |||
35 | static void show_buffer(struct dell_wmi_smbios_buffer *buffer) | ||
36 | { | ||
37 | printf("Call: %x/%x [%x,%x,%x,%x]\nResults: [%8x,%8x,%8x,%8x]\n", | ||
38 | buffer->std.cmd_class, buffer->std.cmd_select, | ||
39 | buffer->std.input[0], buffer->std.input[1], | ||
40 | buffer->std.input[2], buffer->std.input[3], | ||
41 | buffer->std.output[0], buffer->std.output[1], | ||
42 | buffer->std.output[2], buffer->std.output[3]); | ||
43 | } | ||
44 | |||
45 | static int run_wmi_smbios_cmd(struct dell_wmi_smbios_buffer *buffer) | ||
46 | { | ||
47 | int fd; | ||
48 | int ret; | ||
49 | |||
50 | fd = open(ioctl_devfs, O_NONBLOCK); | ||
51 | ret = ioctl(fd, DELL_WMI_SMBIOS_CMD, buffer); | ||
52 | close(fd); | ||
53 | return ret; | ||
54 | } | ||
55 | |||
56 | static int find_token(__u16 token, __u16 *location, __u16 *value) | ||
57 | { | ||
58 | char location_sysfs[60]; | ||
59 | char value_sysfs[57]; | ||
60 | char buf[4096]; | ||
61 | FILE *f; | ||
62 | int ret; | ||
63 | |||
64 | ret = sprintf(value_sysfs, "%s/%04x_value", token_sysfs, token); | ||
65 | if (ret < 0) { | ||
66 | printf("sprintf value failed\n"); | ||
67 | return 2; | ||
68 | } | ||
69 | f = fopen(value_sysfs, "rb"); | ||
70 | if (!f) { | ||
71 | printf("failed to open %s\n", value_sysfs); | ||
72 | return 2; | ||
73 | } | ||
74 | fread(buf, 1, 4096, f); | ||
75 | fclose(f); | ||
76 | *value = (__u16) strtol(buf, NULL, 16); | ||
77 | |||
78 | ret = sprintf(location_sysfs, "%s/%04x_location", token_sysfs, token); | ||
79 | if (ret < 0) { | ||
80 | printf("sprintf location failed\n"); | ||
81 | return 1; | ||
82 | } | ||
83 | f = fopen(location_sysfs, "rb"); | ||
84 | if (!f) { | ||
85 | printf("failed to open %s\n", location_sysfs); | ||
86 | return 2; | ||
87 | } | ||
88 | fread(buf, 1, 4096, f); | ||
89 | fclose(f); | ||
90 | *location = (__u16) strtol(buf, NULL, 16); | ||
91 | |||
92 | if (*location) | ||
93 | return 0; | ||
94 | return 2; | ||
95 | } | ||
96 | |||
97 | static int token_is_active(__u16 *location, __u16 *cmpvalue, | ||
98 | struct dell_wmi_smbios_buffer *buffer) | ||
99 | { | ||
100 | int ret; | ||
101 | |||
102 | buffer->std.cmd_class = CLASS_TOKEN_READ; | ||
103 | buffer->std.cmd_select = SELECT_TOKEN_STD; | ||
104 | buffer->std.input[0] = *location; | ||
105 | ret = run_wmi_smbios_cmd(buffer); | ||
106 | if (ret != 0 || buffer->std.output[0] != 0) | ||
107 | return ret; | ||
108 | ret = (buffer->std.output[1] == *cmpvalue); | ||
109 | return ret; | ||
110 | } | ||
111 | |||
112 | static int query_token(__u16 token, struct dell_wmi_smbios_buffer *buffer) | ||
113 | { | ||
114 | __u16 location; | ||
115 | __u16 value; | ||
116 | int ret; | ||
117 | |||
118 | ret = find_token(token, &location, &value); | ||
119 | if (ret != 0) { | ||
120 | printf("unable to find token %04x\n", token); | ||
121 | return 1; | ||
122 | } | ||
123 | return token_is_active(&location, &value, buffer); | ||
124 | } | ||
125 | |||
126 | static int activate_token(struct dell_wmi_smbios_buffer *buffer, | ||
127 | __u16 token) | ||
128 | { | ||
129 | __u16 location; | ||
130 | __u16 value; | ||
131 | int ret; | ||
132 | |||
133 | ret = find_token(token, &location, &value); | ||
134 | if (ret != 0) { | ||
135 | printf("unable to find token %04x\n", token); | ||
136 | return 1; | ||
137 | } | ||
138 | buffer->std.cmd_class = CLASS_TOKEN_WRITE; | ||
139 | buffer->std.cmd_select = SELECT_TOKEN_STD; | ||
140 | buffer->std.input[0] = location; | ||
141 | buffer->std.input[1] = 1; | ||
142 | ret = run_wmi_smbios_cmd(buffer); | ||
143 | return ret; | ||
144 | } | ||
145 | |||
146 | static int query_buffer_size(__u64 *buffer_size) | ||
147 | { | ||
148 | FILE *f; | ||
149 | |||
150 | f = fopen(ioctl_devfs, "rb"); | ||
151 | if (!f) | ||
152 | return -EINVAL; | ||
153 | fread(buffer_size, sizeof(__u64), 1, f); | ||
154 | fclose(f); | ||
155 | return EXIT_SUCCESS; | ||
156 | } | ||
157 | |||
158 | int main(void) | ||
159 | { | ||
160 | struct dell_wmi_smbios_buffer *buffer; | ||
161 | int ret; | ||
162 | __u64 value = 0; | ||
163 | |||
164 | ret = query_buffer_size(&value); | ||
165 | if (ret == EXIT_FAILURE || !value) { | ||
166 | printf("Unable to read buffer size\n"); | ||
167 | goto out; | ||
168 | } | ||
169 | printf("Detected required buffer size %lld\n", value); | ||
170 | |||
171 | buffer = malloc(value); | ||
172 | if (buffer == NULL) { | ||
173 | printf("failed to alloc memory for ioctl\n"); | ||
174 | ret = -ENOMEM; | ||
175 | goto out; | ||
176 | } | ||
177 | buffer->length = value; | ||
178 | |||
179 | /* simple SMBIOS call for looking up TPM info */ | ||
180 | buffer->std.cmd_class = CLASS_FLASH_INTERFACE; | ||
181 | buffer->std.cmd_select = SELECT_FLASH_INTERFACE; | ||
182 | buffer->std.input[0] = 2; | ||
183 | ret = run_wmi_smbios_cmd(buffer); | ||
184 | if (ret) { | ||
185 | printf("smbios ioctl failed: %d\n", ret); | ||
186 | ret = EXIT_FAILURE; | ||
187 | goto out; | ||
188 | } | ||
189 | show_buffer(buffer); | ||
190 | |||
191 | /* query some tokens */ | ||
192 | ret = query_token(CAPSULE_EN_TOKEN, buffer); | ||
193 | printf("UEFI Capsule enabled token is: %d\n", ret); | ||
194 | ret = query_token(CAPSULE_DIS_TOKEN, buffer); | ||
195 | printf("UEFI Capsule disabled token is: %d\n", ret); | ||
196 | |||
197 | /* activate UEFI capsule token if disabled */ | ||
198 | if (ret) { | ||
199 | printf("Enabling UEFI capsule token"); | ||
200 | if (activate_token(buffer, CAPSULE_EN_TOKEN)) { | ||
201 | printf("activate failed\n"); | ||
202 | ret = -1; | ||
203 | goto out; | ||
204 | } | ||
205 | } | ||
206 | ret = EXIT_SUCCESS; | ||
207 | out: | ||
208 | free(buffer); | ||
209 | return ret; | ||
210 | } | ||