summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2017-12-06 16:39:39 -0500
committerIngo Molnar <mingo@kernel.org>2017-12-06 16:39:39 -0500
commitd6eabce2577a695197e9433302fd6a9f0e1a7666 (patch)
treee5c5bcc7803879d5d911cc8faeb74a946c242395 /tools
parent6e948c67c47211afcc65c9ccdeedbd5db5c57077 (diff)
parent328b4ed93b69a6f2083d52f31a240a09e5de386a (diff)
Merge branch 'linus' into perf/urgent, to synchronize UAPI headers
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools')
-rw-r--r--tools/Makefile22
-rw-r--r--tools/bpf/Makefile (renamed from tools/net/Makefile)18
-rw-r--r--tools/bpf/bpf_asm.c (renamed from tools/net/bpf_asm.c)0
-rw-r--r--tools/bpf/bpf_dbg.c (renamed from tools/net/bpf_dbg.c)0
-rw-r--r--tools/bpf/bpf_exp.l (renamed from tools/net/bpf_exp.l)0
-rw-r--r--tools/bpf/bpf_exp.y (renamed from tools/net/bpf_exp.y)0
-rw-r--r--tools/bpf/bpf_jit_disasm.c (renamed from tools/net/bpf_jit_disasm.c)3
-rw-r--r--tools/bpf/bpftool/Documentation/Makefile34
-rw-r--r--tools/bpf/bpftool/Documentation/bpftool-map.rst131
-rw-r--r--tools/bpf/bpftool/Documentation/bpftool-prog.rst150
-rw-r--r--tools/bpf/bpftool/Documentation/bpftool.rst56
-rw-r--r--tools/bpf/bpftool/Makefile93
-rw-r--r--tools/bpf/bpftool/bash-completion/bpftool354
-rw-r--r--tools/bpf/bpftool/common.c405
-rw-r--r--tools/bpf/bpftool/jit_disasm.c162
-rw-r--r--tools/bpf/bpftool/json_writer.c356
-rw-r--r--tools/bpf/bpftool/json_writer.h72
-rw-r--r--tools/bpf/bpftool/main.c343
-rw-r--r--tools/bpf/bpftool/main.h123
-rw-r--r--tools/bpf/bpftool/map.c899
-rw-r--r--tools/bpf/bpftool/prog.c672
-rw-r--r--tools/gpio/gpio-utils.c17
-rw-r--r--tools/hv/hv_kvp_daemon.c70
-rw-r--r--tools/include/linux/kmemcheck.h8
-rw-r--r--tools/include/uapi/asm-generic/mman-common.h1
-rw-r--r--tools/include/uapi/linux/bpf.h152
-rwxr-xr-xtools/kvm/kvm_stat/kvm_stat30
-rw-r--r--tools/lib/bpf/bpf.c89
-rw-r--r--tools/lib/bpf/bpf.h27
-rw-r--r--tools/lib/bpf/libbpf.c179
-rw-r--r--tools/lib/bpf/libbpf.h1
-rw-r--r--tools/lib/traceevent/parse-filter.c6
-rw-r--r--tools/objtool/.gitignore2
-rw-r--r--tools/objtool/Makefile22
-rw-r--r--tools/objtool/arch/x86/Build10
-rw-r--r--tools/objtool/arch/x86/decode.c6
-rw-r--r--tools/objtool/arch/x86/include/asm/inat.h (renamed from tools/objtool/arch/x86/insn/inat.h)12
-rw-r--r--tools/objtool/arch/x86/include/asm/inat_types.h (renamed from tools/objtool/arch/x86/insn/inat_types.h)0
-rw-r--r--tools/objtool/arch/x86/include/asm/insn.h (renamed from tools/objtool/arch/x86/insn/insn.h)2
-rw-r--r--tools/objtool/arch/x86/include/asm/orc_types.h (renamed from tools/objtool/orc_types.h)0
-rw-r--r--tools/objtool/arch/x86/lib/inat.c (renamed from tools/objtool/arch/x86/insn/inat.c)2
-rw-r--r--tools/objtool/arch/x86/lib/insn.c (renamed from tools/objtool/arch/x86/insn/insn.c)4
-rw-r--r--tools/objtool/arch/x86/lib/x86-opcode-map.txt (renamed from tools/objtool/arch/x86/insn/x86-opcode-map.txt)0
-rw-r--r--tools/objtool/arch/x86/tools/gen-insn-attr-x86.awk (renamed from tools/objtool/arch/x86/insn/gen-insn-attr-x86.awk)0
-rw-r--r--tools/objtool/orc.h2
-rwxr-xr-xtools/objtool/sync-check.sh29
-rw-r--r--tools/perf/Makefile.config6
-rw-r--r--tools/perf/arch/s390/include/dwarf-regs-table.h71
-rw-r--r--tools/perf/arch/s390/include/perf_regs.h95
-rw-r--r--tools/perf/arch/s390/util/Build3
-rw-r--r--tools/perf/arch/s390/util/auxtrace.c118
-rw-r--r--tools/perf/arch/s390/util/dwarf-regs.c11
-rw-r--r--tools/perf/arch/s390/util/unwind-libdw.c63
-rw-r--r--tools/perf/builtin-kmem.c2
-rw-r--r--tools/power/acpi/tools/acpidump/Makefile1
-rw-r--r--tools/power/acpi/tools/acpidump/apdump.c3
-rw-r--r--tools/power/acpi/tools/acpidump/apmain.c4
-rw-r--r--tools/power/cpupower/.gitignore3
-rw-r--r--tools/power/cpupower/Makefile8
-rw-r--r--tools/power/cpupower/bench/system.c2
-rw-r--r--tools/power/cpupower/utils/cpufreq-info.c2
-rw-r--r--tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c9
-rw-r--r--tools/scripts/Makefile.include2
-rw-r--r--tools/testing/nvdimm/Kbuild1
-rw-r--r--tools/testing/nvdimm/test/nfit.c319
-rw-r--r--tools/testing/nvdimm/test/nfit_test.h52
-rw-r--r--tools/testing/radix-tree/multiorder.c2
-rw-r--r--tools/testing/scatterlist/Makefile30
-rw-r--r--tools/testing/scatterlist/linux/mm.h125
-rw-r--r--tools/testing/scatterlist/main.c79
-rw-r--r--tools/testing/selftests/Makefile3
-rw-r--r--tools/testing/selftests/android/Makefile46
-rw-r--r--tools/testing/selftests/android/ion/.gitignore2
-rw-r--r--tools/testing/selftests/android/ion/Makefile16
-rw-r--r--tools/testing/selftests/android/ion/README101
-rw-r--r--tools/testing/selftests/android/ion/config4
-rw-r--r--tools/testing/selftests/android/ion/ion.h143
-rwxr-xr-xtools/testing/selftests/android/ion/ion_test.sh55
-rw-r--r--tools/testing/selftests/android/ion/ionapp_export.c135
-rw-r--r--tools/testing/selftests/android/ion/ionapp_import.c88
-rw-r--r--tools/testing/selftests/android/ion/ionutils.c259
-rw-r--r--tools/testing/selftests/android/ion/ionutils.h55
-rw-r--r--tools/testing/selftests/android/ion/ipcsocket.c227
-rw-r--r--tools/testing/selftests/android/ion/ipcsocket.h35
-rwxr-xr-xtools/testing/selftests/android/run.sh3
-rw-r--r--tools/testing/selftests/bpf/Makefile25
-rw-r--r--tools/testing/selftests/bpf/bpf_helpers.h67
-rw-r--r--tools/testing/selftests/bpf/cgroup_helpers.c178
-rw-r--r--tools/testing/selftests/bpf/cgroup_helpers.h17
-rw-r--r--tools/testing/selftests/bpf/dev_cgroup.c60
-rw-r--r--tools/testing/selftests/bpf/sockmap_parse_prog.c3
-rw-r--r--tools/testing/selftests/bpf/sockmap_verdict_prog.c2
-rw-r--r--tools/testing/selftests/bpf/test_dev_cgroup.c93
-rw-r--r--tools/testing/selftests/bpf/test_lpm_map.c201
-rw-r--r--tools/testing/selftests/bpf/test_maps.c48
-rw-r--r--tools/testing/selftests/bpf/test_progs.c195
-rw-r--r--tools/testing/selftests/bpf/test_verifier.c994
-rw-r--r--tools/testing/selftests/bpf/test_verifier_log.c178
-rw-r--r--tools/testing/selftests/bpf/test_xdp_meta.c53
-rwxr-xr-xtools/testing/selftests/bpf/test_xdp_meta.sh51
-rw-r--r--tools/testing/selftests/breakpoints/breakpoint_test_arm64.c1
-rw-r--r--tools/testing/selftests/cpu-hotplug/config1
-rw-r--r--tools/testing/selftests/exec/execveat.c27
-rwxr-xr-xtools/testing/selftests/firmware/fw_fallback.sh38
-rwxr-xr-xtools/testing/selftests/firmware/fw_filesystem.sh34
-rw-r--r--tools/testing/selftests/ftrace/config4
-rwxr-xr-xtools/testing/selftests/ftrace/ftracetest7
-rw-r--r--tools/testing/selftests/ftrace/test.d/00basic/basic4.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/event/event-enable.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/event/event-pid.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/event/subsystem-enable.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/event/toplevel-enable.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/ftrace/fgraph-filter-stack.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/ftrace/fgraph-filter.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/ftrace/func-filter-pid.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/ftrace/func_event_triggers.tc5
-rw-r--r--tools/testing/selftests/ftrace/test.d/ftrace/func_profiler.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/ftrace/func_set_ftrace_file.tc4
-rw-r--r--tools/testing/selftests/ftrace/test.d/ftrace/func_traceonoff_triggers.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/instances/instance-event.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/instances/instance.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_type.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/template1
-rw-r--r--tools/testing/selftests/ftrace/test.d/trigger/trigger-eventonoff.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/trigger/trigger-filter.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/trigger/trigger-hist-mod.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/trigger/trigger-hist.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/trigger/trigger-multihist.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/trigger/trigger-snapshot.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/trigger/trigger-stacktrace.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/trigger/trigger-traceonoff.tc2
-rw-r--r--tools/testing/selftests/memfd/memfd_test.c4
-rw-r--r--tools/testing/selftests/memory-hotplug/Makefile4
-rwxr-xr-xtools/testing/selftests/net/rtnetlink.sh271
-rw-r--r--tools/testing/selftests/powerpc/benchmarks/context_switch.c17
-rw-r--r--tools/testing/selftests/powerpc/dscr/dscr_sysfs_test.c6
-rw-r--r--tools/testing/selftests/powerpc/tm/.gitignore1
-rw-r--r--tools/testing/selftests/powerpc/tm/Makefile3
-rw-r--r--tools/testing/selftests/powerpc/tm/tm-unavailable.c371
-rw-r--r--tools/testing/selftests/powerpc/tm/tm.h5
-rw-r--r--tools/testing/selftests/seccomp/.gitignore1
-rw-r--r--tools/testing/selftests/tc-testing/.gitignore1
-rw-r--r--tools/testing/selftests/tc-testing/creating-testcases/AddingTestCases.txt12
-rw-r--r--tools/testing/selftests/tc-testing/creating-testcases/example.json55
-rw-r--r--tools/testing/selftests/tc-testing/creating-testcases/template.json15
-rw-r--r--tools/testing/selftests/tc-testing/tc-tests/actions/gact.json469
-rw-r--r--tools/testing/selftests/tc-testing/tc-tests/actions/ife.json52
-rw-r--r--tools/testing/selftests/tc-testing/tc-tests/actions/mirred.json223
-rw-r--r--tools/testing/selftests/tc-testing/tc-tests/actions/police.json527
-rw-r--r--tools/testing/selftests/tc-testing/tc-tests/actions/simple.json130
-rw-r--r--tools/testing/selftests/tc-testing/tc-tests/actions/skbedit.json320
-rw-r--r--tools/testing/selftests/tc-testing/tc-tests/actions/skbmod.json372
-rw-r--r--tools/testing/selftests/tc-testing/tc-tests/actions/tests.json1165
-rwxr-xr-xtools/testing/selftests/tc-testing/tdc.py29
-rw-r--r--tools/testing/selftests/tc-testing/tdc_config.py14
-rw-r--r--tools/testing/selftests/tc-testing/tdc_config_local_template.py23
-rw-r--r--tools/testing/selftests/tc-testing/tdc_helper.py4
-rw-r--r--tools/testing/selftests/timers/.gitignore2
-rw-r--r--tools/testing/selftests/vDSO/vdso_test.c19
-rw-r--r--tools/testing/selftests/vm/.gitignore2
-rw-r--r--tools/testing/selftests/vm/Makefile1
-rw-r--r--tools/testing/selftests/vm/gup_benchmark.c91
-rw-r--r--tools/testing/selftests/x86/5lvl.c177
-rw-r--r--tools/testing/selftests/x86/Makefile2
-rw-r--r--tools/testing/selftests/x86/mpx-hw.h4
-rw-r--r--tools/testing/selftests/x86/pkey-helpers.h5
-rw-r--r--tools/testing/selftests/x86/protection_keys.c10
-rw-r--r--tools/testing/vsock/.gitignore2
-rw-r--r--tools/testing/vsock/Makefile9
-rw-r--r--tools/testing/vsock/README36
-rw-r--r--tools/testing/vsock/control.c219
-rw-r--r--tools/testing/vsock/control.h13
-rw-r--r--tools/testing/vsock/timeout.c64
-rw-r--r--tools/testing/vsock/timeout.h14
-rw-r--r--tools/testing/vsock/vsock_diag_test.c681
-rw-r--r--tools/thermal/tmon/Makefile18
-rw-r--r--tools/usb/usbip/Makefile.am3
-rw-r--r--tools/usb/usbip/libsrc/vhci_driver.c14
-rw-r--r--tools/vm/slabinfo.c11
-rw-r--r--tools/wmi/Makefile18
-rw-r--r--tools/wmi/dell-smbios-example.c210
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
58cpupower: FORCE 59cpupower: FORCE
59 $(call descend,power/$@) 60 $(call descend,power/$@)
60 61
61cgroup firewire hv guest spi usb virtio vm net iio gpio objtool leds: FORCE 62cgroup firewire hv guest spi usb virtio vm bpf iio gpio objtool leds wmi: FORCE
62 $(call descend,$@) 63 $(call descend,$@)
63 64
64liblockdep: FORCE 65liblockdep: FORCE
@@ -92,8 +93,8 @@ kvm_stat: FORCE
92 93
93all: acpi cgroup cpupower gpio hv firewire liblockdep \ 94all: 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
98acpi_install: 99acpi_install:
99 $(call descend,power/$(@:_install=),install) 100 $(call descend,power/$(@:_install=),install)
@@ -101,7 +102,7 @@ acpi_install:
101cpupower_install: 102cpupower_install:
102 $(call descend,power/$(@:_install=),install) 103 $(call descend,power/$(@:_install=),install)
103 104
104cgroup_install firewire_install gpio_install hv_install iio_install perf_install spi_install usb_install virtio_install vm_install net_install objtool_install: 105cgroup_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
107liblockdep_install: 108liblockdep_install:
@@ -125,8 +126,9 @@ kvm_stat_install:
125install: acpi_install cgroup_install cpupower_install gpio_install \ 126install: 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
131acpi_clean: 133acpi_clean:
132 $(call descend,power/acpi,clean) 134 $(call descend,power/acpi,clean)
@@ -134,7 +136,7 @@ acpi_clean:
134cpupower_clean: 136cpupower_clean:
135 $(call descend,power/cpupower,clean) 137 $(call descend,power/cpupower,clean)
136 138
137cgroup_clean hv_clean firewire_clean spi_clean usb_clean virtio_clean vm_clean net_clean iio_clean gpio_clean objtool_clean leds_clean: 139cgroup_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
140liblockdep_clean: 142liblockdep_clean:
@@ -170,8 +172,8 @@ build_clean:
170 172
171clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean \ 173clean: 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
4CC = gcc 4CC = gcc
5LEX = flex 5LEX = flex
6YACC = bison 6YACC = bison
7MAKE = make
7 8
8CFLAGS += -Wall -O2 9CFLAGS += -Wall -O2
9CFLAGS += -D__EXPORTED_HEADERS__ -I../../include/uapi -I../../include 10CFLAGS += -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
17all : bpf_jit_disasm bpf_dbg bpf_asm 18all: bpf_jit_disasm bpf_dbg bpf_asm bpftool
18 19
19bpf_jit_disasm : CFLAGS += -DPACKAGE='bpf_jit_disasm' 20bpf_jit_disasm : CFLAGS += -DPACKAGE='bpf_jit_disasm'
20bpf_jit_disasm : LDLIBS = -lopcodes -lbfd -ldl 21bpf_jit_disasm : LDLIBS = -lopcodes -lbfd -ldl
@@ -27,10 +28,21 @@ bpf_asm : LDLIBS =
27bpf_asm : bpf_asm.o bpf_exp.yacc.o bpf_exp.lex.o 28bpf_asm : bpf_asm.o bpf_exp.yacc.o bpf_exp.lex.o
28bpf_exp.lex.o : bpf_exp.yacc.c 29bpf_exp.lex.o : bpf_exp.yacc.c
29 30
30clean : 31clean: 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
33install : 34install: 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
39bpftool:
40 $(MAKE) -C bpftool
41
42bpftool_install:
43 $(MAKE) -C bpftool install
44
45bpftool_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)
51static void get_asm_insns(uint8_t *image, size_t len, int opcodes) 52static 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 @@
1include ../../../scripts/Makefile.include
2include ../../../scripts/utilities.mak
3
4INSTALL ?= install
5RM ?= rm -f
6
7# Make the path relative to DESTDIR, not prefix
8ifndef DESTDIR
9prefix ?= /usr/local
10endif
11mandir ?= $(prefix)/share/man
12man8dir = $(mandir)/man8
13
14MAN8_RST = $(wildcard *.rst)
15
16_DOC_MAN8 = $(patsubst %.rst,%.8,$(MAN8_RST))
17DOC_MAN8 = $(addprefix $(OUTPUT),$(_DOC_MAN8))
18
19man: man8
20man8: $(DOC_MAN8)
21
22$(OUTPUT)%.8: %.rst
23 rst2man $< > $@
24
25clean:
26 $(call QUIET_CLEAN, Documentation) $(RM) $(DOC_MAN8)
27
28install: 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================
2bpftool-map
3================
4-------------------------------------------------------------------------------
5tool for inspection and simple manipulation of eBPF maps
6-------------------------------------------------------------------------------
7
8:Manual section: 8
9
10SYNOPSIS
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
21MAP 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
37DESCRIPTION
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
74OPTIONS
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
92EXAMPLES
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
129SEE 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================
2bpftool-prog
3================
4-------------------------------------------------------------------------------
5tool for inspection and simple manipulation of eBPF progs
6-------------------------------------------------------------------------------
7
8:Manual section: 8
9
10SYNOPSIS
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
20MAP 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
31DESCRIPTION
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
63OPTIONS
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
81EXAMPLES
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
148SEE 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================
2BPFTOOL
3================
4-------------------------------------------------------------------------------
5tool for inspection and simple manipulation of eBPF programs and maps
6-------------------------------------------------------------------------------
7
8:Manual section: 8
9
10SYNOPSIS
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
31DESCRIPTION
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
39OPTIONS
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
54SEE 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 @@
1include ../../scripts/Makefile.include
2
3include ../../scripts/utilities.mak
4
5ifeq ($(srctree),)
6srctree := $(patsubst %/,%,$(dir $(CURDIR)))
7srctree := $(patsubst %/,%,$(dir $(srctree)))
8srctree := $(patsubst %/,%,$(dir $(srctree)))
9#$(info Determined 'srctree' to be $(srctree))
10endif
11
12ifneq ($(objtree),)
13#$(info Determined 'objtree' to be $(objtree))
14endif
15
16ifneq ($(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.
21VPATH += $(OUTPUT)
22export VPATH
23endif
24
25ifeq ($(V),1)
26 Q =
27else
28 Q = @
29endif
30
31BPF_DIR = $(srctree)/tools/lib/bpf/
32
33ifneq ($(OUTPUT),)
34 BPF_PATH=$(OUTPUT)
35else
36 BPF_PATH=$(BPF_DIR)
37endif
38
39LIBBPF = $(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
48prefix = /usr/local
49bash_compdir ?= /usr/share/bash-completion/completions
50
51CC = gcc
52
53CFLAGS += -O2
54CFLAGS += -W -Wall -Wextra -Wno-unused-parameter -Wshadow
55CFLAGS += -D__EXPORTED_HEADERS__ -I$(srctree)/tools/include/uapi -I$(srctree)/tools/include -I$(srctree)/tools/lib/bpf -I$(srctree)/kernel/bpf/
56LIBS = -lelf -lbfd -lopcodes $(LIBBPF)
57
58include $(wildcard *.d)
59
60all: $(OUTPUT)bpftool
61
62SRCS=$(wildcard *.c)
63OBJS=$(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
74clean: $(LIBBPF)-clean
75 $(call QUIET_CLEAN, bpftool)
76 $(Q)rm -rf $(OUTPUT)bpftool $(OUTPUT)*.o $(OUTPUT)*.d
77
78install:
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
84doc:
85 $(Q)$(MAKE) -C Documentation/
86
87doc-install:
88 $(Q)$(MAKE) -C Documentation/ install
89
90FORCE:
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} &&
352complete -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
55void 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
73void 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
86static 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
96static 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
127int 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
143int 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
166int 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
224out_free:
225 free(file);
226out_close:
227 close(fd);
228 return err;
229}
230
231const 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
245int 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
271char *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
317void 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
327int 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
394void 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
29static 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
47static int oper_count;
48static 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
79void 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
25struct 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 */
33static 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 */
41static 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 */
51static 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 */
61static 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 */
97json_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 */
110void 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
121void jsonw_pretty(json_writer_t *self, bool on)
122{
123 self->pretty = on;
124}
125
126/* Basic blocks */
127static 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
135static 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 */
148void 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
159void 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
167void 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 */
178void jsonw_start_object(json_writer_t *self)
179{
180 jsonw_begin(self, '{');
181}
182
183void jsonw_end_object(json_writer_t *self)
184{
185 jsonw_end(self, '}');
186}
187
188void jsonw_start_array(json_writer_t *self)
189{
190 jsonw_begin(self, '[');
191}
192
193void jsonw_end_array(json_writer_t *self)
194{
195 jsonw_end(self, ']');
196}
197
198/* JSON value types */
199void jsonw_string(json_writer_t *self, const char *value)
200{
201 jsonw_eor(self);
202 jsonw_puts(self, value);
203}
204
205void jsonw_bool(json_writer_t *self, bool val)
206{
207 jsonw_printf(self, "%s", val ? "true" : "false");
208}
209
210void jsonw_null(json_writer_t *self)
211{
212 jsonw_printf(self, "null");
213}
214
215void jsonw_float_fmt(json_writer_t *self, const char *fmt, double num)
216{
217 jsonw_printf(self, fmt, num);
218}
219
220#ifdef notused
221void jsonw_float(json_writer_t *self, double num)
222{
223 jsonw_printf(self, "%g", num);
224}
225#endif
226
227void jsonw_hu(json_writer_t *self, unsigned short num)
228{
229 jsonw_printf(self, "%hu", num);
230}
231
232void jsonw_uint(json_writer_t *self, uint64_t num)
233{
234 jsonw_printf(self, "%"PRIu64, num);
235}
236
237void jsonw_lluint(json_writer_t *self, unsigned long long int num)
238{
239 jsonw_printf(self, "%llu", num);
240}
241
242void jsonw_int(json_writer_t *self, int64_t num)
243{
244 jsonw_printf(self, "%"PRId64, num);
245}
246
247/* Basic name/value objects */
248void 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
254void 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
261void 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
268void 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
277void 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
283void 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
289void 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
297void 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
303void 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
310int 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 */
23typedef struct json_writer json_writer_t;
24
25/* Create a new JSON stream */
26json_writer_t *jsonw_new(FILE *f);
27/* End output to JSON stream */
28void jsonw_destroy(json_writer_t **self_p);
29
30/* Cause output to have pretty whitespace */
31void jsonw_pretty(json_writer_t *self, bool on);
32
33/* Add property name */
34void jsonw_name(json_writer_t *self, const char *name);
35
36/* Add value */
37void jsonw_vprintf_enquote(json_writer_t *self, const char *fmt, va_list ap);
38void jsonw_printf(json_writer_t *self, const char *fmt, ...);
39void jsonw_string(json_writer_t *self, const char *value);
40void jsonw_bool(json_writer_t *self, bool value);
41void jsonw_float(json_writer_t *self, double number);
42void jsonw_float_fmt(json_writer_t *self, const char *fmt, double num);
43void jsonw_uint(json_writer_t *self, uint64_t number);
44void jsonw_hu(json_writer_t *self, unsigned short number);
45void jsonw_int(json_writer_t *self, int64_t number);
46void jsonw_null(json_writer_t *self);
47void jsonw_lluint(json_writer_t *self, unsigned long long int num);
48
49/* Useful Combinations of name and value */
50void jsonw_string_field(json_writer_t *self, const char *prop, const char *val);
51void jsonw_bool_field(json_writer_t *self, const char *prop, bool value);
52void jsonw_float_field(json_writer_t *self, const char *prop, double num);
53void jsonw_uint_field(json_writer_t *self, const char *prop, uint64_t num);
54void jsonw_hu_field(json_writer_t *self, const char *prop, unsigned short num);
55void jsonw_int_field(json_writer_t *self, const char *prop, int64_t num);
56void jsonw_null_field(json_writer_t *self, const char *prop);
57void jsonw_lluint_field(json_writer_t *self, const char *prop,
58 unsigned long long int num);
59void jsonw_float_field_fmt(json_writer_t *self, const char *prop,
60 const char *fmt, double val);
61
62/* Collections */
63void jsonw_start_object(json_writer_t *self);
64void jsonw_end_object(json_writer_t *self);
65
66void jsonw_start_array(json_writer_t *self);
67void jsonw_end_array(json_writer_t *self);
68
69/* Override default exception handling */
70typedef 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
50const char *bin_name;
51static int last_argc;
52static char **last_argv;
53static int (*last_do_help)(int argc, char **argv);
54json_writer_t *json_wtr;
55bool pretty_output;
56bool json_output;
57bool show_pinned;
58struct pinned_obj_table prog_table;
59struct pinned_obj_table map_table;
60
61static void __noreturn clean_and_exit(int i)
62{
63 if (json_output)
64 jsonw_destroy(&json_wtr);
65
66 exit(i);
67}
68
69void usage(void)
70{
71 last_do_help(last_argc - 1, last_argv + 1);
72
73 clean_and_exit(-1);
74}
75
76static 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
96static 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
117int 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
138bool 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
148void 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
169static int do_batch(int argc, char **argv);
170
171static 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
180static 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 }
261err_close:
262 fclose(fp);
263
264 if (json_output)
265 jsonw_end_array(json_wtr);
266
267 return err;
268}
269
270int 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
65enum bpf_obj_type {
66 BPF_OBJ_UNKNOWN,
67 BPF_OBJ_PROG,
68 BPF_OBJ_MAP,
69};
70
71extern const char *bin_name;
72
73extern json_writer_t *json_wtr;
74extern bool json_output;
75extern bool show_pinned;
76extern struct pinned_obj_table prog_table;
77extern struct pinned_obj_table map_table;
78
79void p_err(const char *fmt, ...);
80void p_info(const char *fmt, ...);
81
82bool is_prefix(const char *pfx, const char *str);
83void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep);
84void usage(void) __noreturn;
85
86struct pinned_obj_table {
87 DECLARE_HASHTABLE(table, 16);
88};
89
90struct pinned_obj {
91 __u32 id;
92 char *path;
93 struct hlist_node hash;
94};
95
96int build_pinned_obj_table(struct pinned_obj_table *table,
97 enum bpf_obj_type type);
98void delete_pinned_obj_table(struct pinned_obj_table *tab);
99
100struct cmd {
101 const char *cmd;
102 int (*func)(int argc, char **argv);
103};
104
105int cmd_select(const struct cmd *cmds, int argc, char **argv,
106 int (*help)(int argc, char **argv));
107
108int get_fd_type(int fd);
109const char *get_fd_type_name(enum bpf_obj_type type);
110char *get_fdinfo(int fd, const char *key);
111int open_obj_pinned(char *path);
112int open_obj_pinned_any(char *path, enum bpf_obj_type exp_type);
113int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(__u32));
114
115int do_prog(int argc, char **arg);
116int do_map(int argc, char **arg);
117
118int prog_parse_fd(int *argc, char ***argv);
119
120void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes);
121void 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
52static 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
71static 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
126static 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
133static 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
139static bool map_is_map_of_progs(__u32 type)
140{
141 return type == BPF_MAP_TYPE_PROG_ARRAY;
142}
143
144static 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
152static 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
188static int
189map_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
208static 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
245static 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
282static 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
305static 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
410static 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
456static 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
492static 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
554static 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
626exit_free:
627 free(key);
628 free(value);
629 close(fd);
630
631 return err;
632}
633
634static 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
669exit_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
681static 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
726exit_free:
727 free(key);
728 free(value);
729 close(fd);
730
731 return err;
732}
733
734static 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
797exit_free:
798 free(nextkey);
799 free(key);
800 close(fd);
801
802 return err;
803}
804
805static 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
835exit_free:
836 free(key);
837 close(fd);
838
839 if (!err && json_output)
840 jsonw_null(json_wtr);
841 return err;
842}
843
844static 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
854static 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
884static 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
896int 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
52static 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
70static 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
96static 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
133int 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
183static 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
212static 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
274static 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
328static 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
348static 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
403static 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
412static 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
441static 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
456static 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
504static 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
623err_free:
624 free(buf);
625 return -1;
626}
627
628static 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
638static 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
661static const struct cmd cmds[] = {
662 { "show", do_show },
663 { "help", do_help },
664 { "dump", do_dump },
665 { "pin", do_pin },
666 { 0 }
667};
668
669int 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
99exit_close_error: 100exit_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
227static int kvp_file_init(void) 232static 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
5static 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
98enum bpf_map_type { 99enum 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
117enum bpf_prog_type { 119enum 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
135enum bpf_attach_type { 138enum 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
179union bpf_attr { 228union 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
729struct bpf_tunnel_key { 832struct bpf_tunnel_key {
@@ -784,6 +887,7 @@ enum xdp_action {
784struct xdp_md { 887struct xdp_md {
785 __u32 data; 888 __u32 data;
786 __u32 data_end; 889 __u32 data_end;
890 __u32 data_meta;
787}; 891};
788 892
789enum sk_action { 893enum 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
806struct bpf_map_info { 915struct 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
984struct 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
997struct 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
20The data is sampled from the KVM's debugfs entries and its perf events. 20The data is sampled from the KVM's debugfs entries and its perf events.
21""" 21"""
22from __future__ import print_function
22 23
23import curses 24import curses
24import sys 25import sys
26import locale
25import os 27import os
26import time 28import time
27import optparse 29import optparse
@@ -225,6 +227,8 @@ IOCTL_NUMBERS = {
225 'RESET': 0x00002403, 227 'RESET': 0x00002403,
226} 228}
227 229
230ENCODING = locale.getpreferredencoding(False)
231
228 232
229class Arch(object): 233class 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
1377def log(stats): 1381def 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 print 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 print 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
49static inline __u64 ptr_to_u64(const void *ptr) 51static 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
60int bpf_create_map_node(enum bpf_map_type map_type, int key_size, 62int 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,
81int bpf_create_map(enum bpf_map_type map_type, int key_size, 86int 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
88int bpf_create_map_in_map_node(enum bpf_map_type map_type, int key_size, 93int 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
101int 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
110int bpf_create_map_in_map(enum bpf_map_type map_type, int key_size, 126int 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
117int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns, 135int 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
168int 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
146int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns, 177int 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
294int 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
306int 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
263int bpf_prog_test_run(int prog_fd, int repeat, void *data, __u32 size, 326int 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
27int bpf_create_map_node(enum bpf_map_type map_type, int key_size, 27int 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);
30int 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);
30int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size, 33int 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);
32int bpf_create_map_in_map_node(enum bpf_map_type map_type, int key_size, 35int 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);
35int bpf_create_map_in_map(enum bpf_map_type map_type, int key_size, 38int 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
44int 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);
40int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns, 49int 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);
57int bpf_prog_attach(int prog_fd, int attachable_fd, enum bpf_attach_type type, 66int bpf_prog_attach(int prog_fd, int attachable_fd, enum bpf_attach_type type,
58 unsigned int flags); 67 unsigned int flags);
59int bpf_prog_detach(int attachable_fd, enum bpf_attach_type type); 68int bpf_prog_detach(int attachable_fd, enum bpf_attach_type type);
69int bpf_prog_detach2(int prog_fd, int attachable_fd, enum bpf_attach_type type);
60int bpf_prog_test_run(int prog_fd, int repeat, void *data, __u32 size, 70int 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);
65int bpf_prog_get_fd_by_id(__u32 id); 75int bpf_prog_get_fd_by_id(__u32 id);
66int bpf_map_get_fd_by_id(__u32 id); 76int bpf_map_get_fd_by_id(__u32 id);
67int bpf_obj_get_info_by_fd(int prog_fd, void *info, __u32 *info_len); 77int bpf_obj_get_info_by_fd(int prog_fd, void *info, __u32 *info_len);
68 78int 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)
171struct bpf_program { 171struct 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
295static int 297static int
296bpf_program__init(void *data, size_t size, char *name, int idx, 298bpf_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
332static int 335static int
333bpf_object__add_program(struct bpf_object *obj, void *data, size_t size, 336bpf_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
370static int
371bpf_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
367static struct bpf_object *bpf_object__new(const char *path, 418static 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
531static int
532bpf_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
556static int compare_bpf_map(const void *_a, const void *_b) 582static 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)
564static int 590static int
565bpf_object__init_maps(struct bpf_object *obj) 591bpf_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
664static int bpf_object__elf_collect(struct bpf_object *obj) 727static 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);
771out: 838out:
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
984static int 1052static int
985load_program(enum bpf_prog_type type, struct bpf_insn *insns, 1053load_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
444static struct filter_arg * 444static struct filter_arg *
445create_arg_cmp(enum filter_exp_type etype) 445create_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 @@
1arch/x86/insn/inat-tables.c 1arch/x86/lib/inat-tables.c
2objtool 2objtool
3fixdep 3fixdep
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
26all: $(OBJTOOL) 26all: $(OBJTOOL)
27 27
28INCLUDES := -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(HOSTARCH)/include/uapi 28INCLUDES := -I$(srctree)/tools/include \
29 -I$(srctree)/tools/arch/$(HOSTARCH)/include/uapi \
30 -I$(srctree)/tools/objtool/arch/$(ARCH)/include
29WARNINGS := $(EXTRA_WARNINGS) -Wno-switch-default -Wno-switch-enum -Wno-packed 31WARNINGS := $(EXTRA_WARNINGS) -Wno-switch-default -Wno-switch-enum -Wno-packed
30CFLAGS += -Wall -Werror $(WARNINGS) -fomit-frame-pointer -O2 -g $(INCLUDES) 32CFLAGS += -Wall -Werror $(WARNINGS) -fomit-frame-pointer -O2 -g $(INCLUDES)
31LDFLAGS += -lelf $(LIBSUBCMD) 33LDFLAGS += -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
66clean: 54clean:
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
71FORCE: 59FORCE:
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 @@
1objtool-y += decode.o 1objtool-y += decode.o
2 2
3inat_tables_script = arch/x86/insn/gen-insn-attr-x86.awk 3inat_tables_script = arch/x86/tools/gen-insn-attr-x86.awk
4inat_tables_maps = arch/x86/insn/x86-opcode-map.txt 4inat_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
12CFLAGS_decode.o += -I$(OUTPUT)arch/x86/insn 12CFLAGS_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 */
101extern insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode); 111extern insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode);
102extern int inat_get_last_prefix_id(insn_byte_t last_pfx); 112extern 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
26struct insn_field { 26struct 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
23struct objtool_file; 23struct 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
4FILES='
5arch/x86/lib/insn.c
6arch/x86/lib/inat.c
7arch/x86/lib/x86-opcode-map.txt
8arch/x86/tools/gen-insn-attr-x86.awk
9arch/x86/include/asm/insn.h
10arch/x86/include/asm/inat.h
11arch/x86/include/asm/inat_types.h
12arch/x86/include/asm/orc_types.h
13'
14
15check()
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
23if [ ! -d ../../kernel ] || [ ! -d ../../tools ] || [ ! -d ../objtool ]; then
24 exit 0
25fi
26
27for i in $FILES; do
28 check $i
29done
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
54endif 54endif
55 55
56ifeq ($(ARCH),s390)
57 NO_PERF_REGS := 0
58endif
59
56ifeq ($(NO_PERF_REGS),0) 60ifeq ($(NO_PERF_REGS),0)
57 $(call detected,CONFIG_PERF_REGS) 61 $(call detected,CONFIG_PERF_REGS)
58endif 62endif
@@ -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.
64ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm powerpc)) 68ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm powerpc s390))
65 NO_LIBDW_DWARF_UNWIND := 1 69 NO_LIBDW_DWARF_UNWIND := 1
66endif 70endif
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
5static 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 */
11static 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
8void 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
17static 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
2libperf-y += kvm-stat.o 2libperf-y += kvm-stat.o
3 3
4libperf-$(CONFIG_DWARF) += dwarf-regs.o 4libperf-$(CONFIG_DWARF) += dwarf-regs.o
5libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
5 6
6libperf-y += machine.o 7libperf-y += machine.o
8
9libperf-$(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
16static void cpumsf_free(struct auxtrace_record *itr)
17{
18 free(itr);
19}
20
21static 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
27static int
28cpumsf_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
36static unsigned long
37cpumsf_reference(struct auxtrace_record *itr __maybe_unused)
38{
39 return 0;
40}
41
42static int
43cpumsf_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
71static int
72cpumsf_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 */
83struct 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
15static 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
20const char *get_arch_regstr(unsigned int n) 15const 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
9bool 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
2libcpupower.so 2libcpupower.so
3libcpupower.so.0 3libcpupower.so.*
4libcpupower.so.0.0.0
5build/ccdv 4build/ccdv
6cpufreq-info 5cpufreq-info
7cpufreq-set 6cpufreq-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
27ifneq ($(OUTPUT),) 27ifneq ($(OUTPUT),)
28# check that the output directory actually exists 28# check that the output directory actually exists
29OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd) 29OUTDIR := $(shell cd $(OUTPUT) && pwd)
30$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist)) 30$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist))
31endif 31endif
32 32
33include ../../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
79sbindir ?= /usr/sbin 81sbindir ?= /usr/sbin
80mandir ?= /usr/man 82mandir ?= /usr/man
81includedir ?= /usr/include 83includedir ?= /usr/include
84ifeq ($(IS_64_BIT), 1)
85libdir ?= /usr/lib64
86else
82libdir ?= /usr/lib 87libdir ?= /usr/lib
88endif
83localedir ?= /usr/share/locale 89localedir ?= /usr/share/locale
84docdir ?= /usr/share/doc/packages/cpupower 90docdir ?= /usr/share/doc/packages/cpupower
85confdir ?= /etc/ 91confdir ?= /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
15ifneq ($(OUTPUT),) 15ifneq ($(OUTPUT),)
16OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd) 16OUTDIR := $(shell cd $(OUTPUT) && pwd)
17$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist)) 17$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist))
18endif 18endif
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
70libnvdimm-y += $(NVDIMM_SRC)/region.o 70libnvdimm-y += $(NVDIMM_SRC)/region.o
71libnvdimm-y += $(NVDIMM_SRC)/namespace_devs.o 71libnvdimm-y += $(NVDIMM_SRC)/namespace_devs.o
72libnvdimm-y += $(NVDIMM_SRC)/label.o 72libnvdimm-y += $(NVDIMM_SRC)/label.o
73libnvdimm-y += $(NVDIMM_SRC)/badrange.o
73libnvdimm-$(CONFIG_ND_CLAIM) += $(NVDIMM_SRC)/claim.o 74libnvdimm-$(CONFIG_ND_CLAIM) += $(NVDIMM_SRC)/claim.o
74libnvdimm-$(CONFIG_BTT) += $(NVDIMM_SRC)/btt_devs.o 75libnvdimm-$(CONFIG_BTT) += $(NVDIMM_SRC)/btt_devs.o
75libnvdimm-$(CONFIG_NVDIMM_PFN) += $(NVDIMM_SRC)/pfn_devs.o 76libnvdimm-$(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
175static struct workqueue_struct *nfit_wq;
176
173static struct nfit_test *to_nfit_test(struct device *dev) 177static 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
240static int nfit_test_cmd_ars_cap(struct nd_cmd_ars_cap *nd_cmd, 243static 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/* 262static 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 */
258static 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
278static int nfit_test_cmd_ars_start(struct ars_state *ars_state, 301static 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
323static int nfit_test_cmd_clear_error(struct nd_cmd_clear_error *clear_err, 347static 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
365struct region_search_spa {
366 u64 addr;
367 struct nd_region *region;
368};
369
370static int is_region_device(struct device *dev)
371{
372 return !strncmp(dev->kobj.name, "region", 6);
373}
374
375static 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
395static 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
431static 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
345static int nfit_test_cmd_smart(struct nd_cmd_smart *smart, unsigned int buf_len) 443static 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
479static 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
486static 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
512err:
513 err_inj->status = NFIT_ARS_INJECT_INVALID;
514 return rc;
515}
516
517static 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
538err:
539 err_clr->status = NFIT_ARS_INJECT_INVALID;
540 return rc;
541}
542
543static 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
381static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, 566static 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
567static int ars_state_init(struct device *dev, struct ars_state *ars_state) 784static 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
1436static void nfit_test1_setup(struct nfit_test *t) 1658static 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
38enum err_inj_options {
39 ND_ARS_ERR_INJ_OPT_NOTIFY = 0,
40};
41
42/* nfit commands */
43enum 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
50struct 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
65struct 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
72struct 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
78struct 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
35union acpi_object; 87union acpi_object;
36typedef void *acpi_handle; 88typedef 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 @@
1CFLAGS += -I. -I../../include -g -O2 -Wall -fsanitize=address
2LDFLAGS += -fsanitize=address -fsanitize=undefined
3TARGETS = main
4OFILES = main.o scatterlist.o
5
6ifeq ($(BUILD), 32)
7 CFLAGS += -m32
8 LDFLAGS += -m32
9endif
10
11targets: include $(TARGETS)
12
13main: $(OFILES)
14
15clean:
16 $(RM) $(TARGETS) $(OFILES) scatterlist.c linux/scatterlist.h linux/highmem.h linux/kmemleak.h asm/io.h
17 @rmdir asm
18
19scatterlist.c: ../../../lib/scatterlist.c
20 @sed -e 's/^static //' -e 's/__always_inline //' -e 's/inline //' < $< > $@
21
22.PHONY: include
23
24include: ../../../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
11typedef 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
44static 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
78static inline void *kmap(struct page *page)
79{
80 assert(0);
81
82 return NULL;
83}
84
85static inline void *kmap_atomic(struct page *page)
86{
87 assert(0);
88
89 return NULL;
90}
91
92static inline void kunmap(void *addr)
93{
94 assert(0);
95}
96
97static inline void kunmap_atomic(void *addr)
98{
99 assert(0);
100}
101
102static inline unsigned long __get_free_page(unsigned int flags)
103{
104 return (unsigned long)malloc(PAGE_SIZE);
105}
106
107static inline void free_page(unsigned long page)
108{
109 free((void *)page);
110}
111
112static 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
8static 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
20int 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
2TARGETS = bpf 2TARGETS = android
3TARGETS += bpf
3TARGETS += breakpoints 4TARGETS += breakpoints
4TARGETS += capabilities 5TARGETS += capabilities
5TARGETS += cpufreq 6TARGETS += 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 @@
1SUBDIRS := ion
2
3TEST_PROGS := run.sh
4
5.PHONY: all clean
6
7include ../lib.mk
8
9all:
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
21override define RUN_TESTS
22 @cd $(OUTPUT); ./run.sh
23endef
24
25override 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;
34endef
35
36override define EMIT_TESTS
37 echo "./run.sh"
38endef
39
40override 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
46endef
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 @@
1ionapp_export
2ionapp_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
2INCLUDEDIR := -I. -I../../../../../drivers/staging/android/uapi/
3CFLAGS := $(CFLAGS) $(INCLUDEDIR) -Wall -O2 -g
4
5TEST_GEN_FILES := ionapp_export ionapp_import
6
7all: $(TEST_GEN_FILES)
8
9$(TEST_GEN_FILES): ipcsocket.c ionutils.c
10
11TEST_PROGS := ion_test.sh
12
13include ../../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 @@
1ION BUFFER SHARING UTILITY
2==========================
3File: ion_test.sh : Utility to test ION driver buffer sharing mechanism.
4Author: Pintu Kumar <pintu.ping@gmail.com>
5
6Introduction:
7-------------
8This is a test utility to verify ION buffer sharing in user space
9between 2 independent processes.
10It uses unix domain socket (with SCM_RIGHTS) as IPC to transfer an FD to
11another process to share the same buffer.
12This utility demonstrates how ION buffer sharing can be implemented between
13two user space processes, using various heap types.
14The following heap types are supported by ION driver.
15ION_HEAP_TYPE_SYSTEM (0)
16ION_HEAP_TYPE_SYSTEM_CONTIG (1)
17ION_HEAP_TYPE_CARVEOUT (2)
18ION_HEAP_TYPE_CHUNK (3)
19ION_HEAP_TYPE_DMA (4)
20
21By default only the SYSTEM and SYSTEM_CONTIG heaps are supported.
22Each heap is associated with the respective heap id.
23This utility is designed in the form of client/server program.
24The server part (ionapp_export) is the exporter of the buffer.
25It is responsible for creating an ION client, allocating the buffer based on
26the heap id, writing some data to this buffer and then exporting the FD
27(associated with this buffer) to another process using socket IPC.
28This FD is called as buffer FD (which is different than the ION client FD).
29
30The client part (ionapp_import) is the importer of the buffer.
31It retrives the FD from the socket data and installs into its address space.
32This new FD internally points to the same kernel buffer.
33So first it reads the data that is stored in this buffer and prints it.
34Then it writes the different size of data (it could be different data) to the
35same buffer.
36Finally the buffer FD must be closed by both the exporter and importer.
37Thus the same kernel buffer is shared among two user space processes using
38ION driver and only one time allocation.
39
40Prerequisite:
41-------------
42This utility works only if /dev/ion interface is present.
43The following configs needs to be enabled in kernel to include ion driver.
44CONFIG_ANDROID=y
45CONFIG_STAGING=y
46CONFIG_ION=y
47CONFIG_ION_SYSTEM_HEAP=y
48
49This utility requires to be run as root user.
50
51
52Compile and test:
53-----------------
54This utility is made to be run as part of kselftest framework in kernel.
55To compile and run using kselftest you can simply do the following from the
56kernel top directory.
57linux$ make TARGETS=android kselftest
58Or you can also use:
59linux$ make -C tools/testing/selftests TARGETS=android run_tests
60Using the selftest it can directly execute the ion_test.sh script to test the
61buffer sharing using ion system heap.
62Currently the heap size is hard coded as just 10 bytes inside this script.
63You need to be a root user to run under selftest.
64
65You can also compile and test manually using the following steps:
66ion$ make
67These will generate 2 executable: ionapp_export, ionapp_import
68Now you can run the export and import manually by specifying the heap type
69and the heap size.
70You can also directly execute the shell script to run the test automatically.
71Simply use the following command to run the test.
72ion$ sudo ./ion_test.sh
73
74Test Results:
75-------------
76The utility is verified on Ubuntu-32 bit system with Linux Kernel 4.14.
77Here is the snapshot of the test result using kselftest.
78
79linux# make TARGETS=android kselftest
80heap_type: 0, heap_size: 10
81--------------------------------------
82heap type: 0
83 heap id: 1
84heap name: ion_system_heap
85--------------------------------------
86Fill buffer content:
870xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd
88Sharing fd: 6, Client fd: 5
89<ion_close_buffer_fd>: buffer release successfully....
90Received buffer fd: 4
91Read buffer content:
920xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0x0 0x0 0x0 0x0 0x0 0x0
930x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
94Fill buffer content:
950xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd
960xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd
970xfd 0xfd
98<ion_close_buffer_fd>: buffer release successfully....
99ion_test.sh: heap_type: 0 - [PASS]
100
101ion_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 @@
1CONFIG_ANDROID=y
2CONFIG_STAGING=y
3CONFIG_ION=y
4CONFIG_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 */
42enum 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 */
85struct 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 */
101struct 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 */
115struct 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
3heapsize=4096
4TCID="ion_test.sh"
5errcode=0
6
7run_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
23check_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
32check_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
42main_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
53main_function
54echo "$TCID: done"
55exit $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
32void 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
38int 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
127err_send:
128err_export:
129 ion_close_buffer_fd(&info);
130
131err_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
29int 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
80err_import:
81 ion_close_buffer_fd(&info);
82err_fd:
83err_recv:
84err_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
13void 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
30void 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
46int 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
139err_fd_data:
140err_mmap:
141 /* in case of error: close the buffer fd */
142 if (buffer_fd)
143 close(buffer_fd);
144
145err_query:
146err_heap:
147err_alloc:
148 /* In case of error: close the ion client fd */
149 if (ionfd)
150 close(ionfd);
151
152 return -1;
153}
154
155int 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
188err_mmap:
189 if (buffd)
190 close(buffd);
191
192err_buffd:
193 return -1;
194}
195
196void 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
211int 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
236int 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
12struct socket_info {
13 int sockfd;
14 int datafd;
15 unsigned long buflen;
16};
17
18struct 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 */
30void write_buffer(void *buffer, unsigned long len);
31
32/* This is used to read the data from the exported buffer */
33void 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 */
38int 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 */
43int ion_import_buffer_fd(struct ion_buffer_info *ion_info);
44
45/* This is used to close all references for the ION client */
46void ion_close_buffer_fd(struct ion_buffer_info *ion_info);
47
48/* This is used to send FD to another process using socket IPC */
49int socket_send_fd(struct socket_info *skinfo);
50
51/* This is used to receive FD from another process using socket IPC */
52int 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
14int 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
98err:
99 if (*sockfd)
100 close(*sockfd);
101
102 return ret;
103}
104
105int 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
161int 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
216int 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
8char 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 */
14struct 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 */
23int opensocket(int *sockfd, const char *name, int connecttype);
24
25/* This is the API to send socket data over IPC socket */
26int sendtosocket(int sockfd, struct socketdata *data);
27
28/* This is the API to receive socket data over IPC socket */
29int receivefromsocket(int sockfd, struct socketdata *data);
30
31/* This is the API to close the socket connection */
32int 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
13LDLIBS += -lcap -lelf 13LDLIBS += -lcap -lelf
14 14
15TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \ 15TEST_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
18TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o \ 18TEST_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
21TEST_PROGS := test_kmod.sh test_xdp_redirect.sh 22TEST_PROGS := test_kmod.sh test_xdp_redirect.sh test_xdp_meta.sh
22 23
23include ../lib.mk 24include ../lib.mk
24 25
25BPFOBJ := $(OUTPUT)/libbpf.a 26BPFOBJ := $(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
37CLANG ?= clang 38CLANG ?= clang
39LLC ?= llc
40
41PROBE := $(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.
45ifeq ($(PROBE),)
46 CPU ?= probe
47else
48 CPU ?= generic
49endif
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;
64static int (*bpf_xdp_adjust_head)(void *ctx, int offset) = 64static int (*bpf_xdp_adjust_head)(void *ctx, int offset) =
65 (void *) BPF_FUNC_xdp_adjust_head; 65 (void *) BPF_FUNC_xdp_adjust_head;
66static int (*bpf_xdp_adjust_meta)(void *ctx, int offset) =
67 (void *) BPF_FUNC_xdp_adjust_meta;
66static int (*bpf_setsockopt)(void *ctx, int level, int optname, void *optval, 68static 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;
71static int (*bpf_getsockopt)(void *ctx, int level, int optname, void *optval,
72 int optlen) =
73 (void *) BPF_FUNC_getsockopt;
69static int (*bpf_sk_redirect_map)(void *ctx, void *map, int key, int flags) = 74static 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;
71static int (*bpf_sock_map_update)(void *map, void *key, void *value, 76static 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;
79static 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;
82static 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) =
110static int (*bpf_skb_change_head)(void *, int len, int flags) = 121static 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 */
44int 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
76static 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
85static 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 */
120int 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 */
141void 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 */
160int 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
12int create_and_get_cgroup(char *path);
13int join_cgroup(char *path);
14int setup_cgroup_environment(void);
15void 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
12SEC("cgroup/dev")
13int 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
59char _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
24int 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
89err:
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
35static struct tlpm_node *tlpm_match(struct tlpm_node *list,
36 const uint8_t *key,
37 size_t n_bits);
38
35static struct tlpm_node *tlpm_add(struct tlpm_node *list, 39static 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
108static 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
96static void test_lpm_basic(void) 136static 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
160static void test_lpm_map(int keysize) 207static 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
422static 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
335int main(void) 524int 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
1046static 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
1069static 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
1046static void run_all_tests(void) 1091static 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
1065int main(void) 1113int 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>
15typedef __u16 __sum16; 16typedef __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
551static 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
498int main(void) 620int 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
7156static int probe_filter_length(const struct bpf_insn *fp) 8102static 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
19static 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
42static inline __u64 ptr_to_u64(const void *ptr)
43{
44 return (__u64) (unsigned long) ptr;
45}
46
47static 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
63static 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
78static 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
87static 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
123static 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
134int 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
11SEC("t")
12int 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
31SEC("x")
32int 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
53char _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
3cleanup()
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
16ip link set dev lo xdp off 2>/dev/null > /dev/null
17if [ $? -ne 0 ];then
18 echo "selftests: [SKIP] Could not run test without the ip xdp support"
19 exit 0
20fi
21set -e
22
23ip netns add ns1
24ip netns add ns2
25
26trap cleanup 0 2 3 6 9
27
28ip link add veth1 type veth peer name veth2
29
30ip link set veth1 netns ns1
31ip link set veth2 netns ns2
32
33ip netns exec ns1 ip addr add 10.1.1.11/24 dev veth1
34ip netns exec ns2 ip addr add 10.1.1.22/24 dev veth2
35
36ip netns exec ns1 tc qdisc add dev veth1 clsact
37ip netns exec ns2 tc qdisc add dev veth2 clsact
38
39ip netns exec ns1 tc filter add dev veth1 ingress bpf da obj test_xdp_meta.o sec t
40ip netns exec ns2 tc filter add dev veth2 ingress bpf da obj test_xdp_meta.o sec t
41
42ip netns exec ns1 ip link set dev veth1 xdp obj test_xdp_meta.o sec x
43ip netns exec ns2 ip link set dev veth2 xdp obj test_xdp_meta.o sec x
44
45ip netns exec ns1 ip link set dev veth1 up
46ip netns exec ns2 ip link set dev veth2 up
47
48ip netns exec ns1 ping -c 1 10.1.1.22
49ip netns exec ns2 ping -c 1 10.1.1.11
50
51exit 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 @@
1CONFIG_NOTIFIER_ERROR_INJECTION=y CONFIG_NOTIFIER_ERROR_INJECTION=y
2CONFIG_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
150static int check_execveat_pathmax(int dot_dfd, const char *src, int is_script) 150static 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
87load_fw_custom() 87load_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
114load_fw_custom_cancel() 120load_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
138load_fw_fallback_with_child() 150load_fw_fallback_with_child()
@@ -227,20 +239,22 @@ else
227 echo "$0: cancelling fallback mechanism works" 239 echo "$0: cancelling fallback mechanism works"
228fi 240fi
229 241
230load_fw_custom "$NAME" "$FW" 242if load_fw_custom "$NAME" "$FW" ; then
231if ! 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
234else 246 else
235 echo "$0: custom fallback loading mechanism works" 247 echo "$0: custom fallback loading mechanism works"
248 fi
236fi 249fi
237 250
238load_fw_custom_cancel "nope-$NAME" "$FW" 251if load_fw_custom_cancel "nope-$NAME" "$FW" ; then
239if 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
242else 255 else
243 echo "$0: cancelling custom fallback mechanism works" 256 echo "$0: cancelling custom fallback mechanism works"
257 fi
244fi 258fi
245 259
246set +e 260set +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
71fi 71fi
72 72
73if printf '\000' >"$DIR"/trigger_async_request 2> /dev/null; then 73if [ ! -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 75else
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
76fi 80fi
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
105fi 109fi
106 110
107# Try the asynchronous version too 111# Try the asynchronous version too
108if ! echo -n "$NAME" >"$DIR"/trigger_async_request ; then 112if [ ! -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
111fi
112
113# Verify the contents are what we expect.
114if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then
115 echo "$0: firmware was not loaded (async)" >&2
116 exit 1
117else 114else
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
119fi 127fi
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 @@
1CONFIG_KPROBES=y 1CONFIG_KPROBES=y
2CONFIG_FTRACE=y 2CONFIG_FTRACE=y
3CONFIG_FUNCTION_PROFILER=y
4CONFIG_TRACER_SNAPSHOT=y
5CONFIG_STACK_TRACER=y
6CONFIG_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=
222SIG_BASE=36 # Use realtime signals 222SIG_BASE=36 # Use realtime signals
223SIG_PID=$$ 223SIG_PID=$$
224 224
225exit_pass () {
226 exit 0
227}
228
225SIG_FAIL=$((SIG_BASE + FAIL)) 229SIG_FAIL=$((SIG_BASE + FAIL))
230exit_fail () {
231 exit 1
232}
226trap 'SIG_RESULT=$FAIL' $SIG_FAIL 233trap 'SIG_RESULT=$FAIL' $SIG_FAIL
227 234
228SIG_UNRESOLVED=$((SIG_BASE + UNRESOLVED)) 235SIG_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
3test -f available_events -a -f set_event -a -d events 3test -f available_events -a -f set_event -a -d events
4# check scheduler events are available 4# check scheduler events are available
5grep -q sched available_events && exit 0 || exit $FAIL 5grep -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() {
11fail() { #msg 11fail() { #msg
12 do_reset 12 do_reset
13 echo $1 13 echo $1
14 exit $FAIL 14 exit_fail
15} 15}
16 16
17yield() { 17yield() {
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() {
13fail() { #msg 13fail() { #msg
14 do_reset 14 do_reset
15 echo $1 15 echo $1
16 exit $FAIL 16 exit_fail
17} 17}
18 18
19yield() { 19yield() {
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() {
11fail() { #msg 11fail() { #msg
12 do_reset 12 do_reset
13 echo $1 13 echo $1
14 exit $FAIL 14 exit_fail
15} 15}
16 16
17yield() { 17yield() {
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() {
10fail() { #msg 10fail() { #msg
11 do_reset 11 do_reset
12 echo $1 12 echo $1
13 exit $FAIL 13 exit_fail
14} 14}
15 15
16yield() { 16yield() {
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() {
28fail() { # msg 28fail() { # msg
29 do_reset 29 do_reset
30 echo $1 30 echo $1
31 exit $FAIL 31 exit_fail
32} 32}
33 33
34disable_tracing 34disable_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() {
18fail() { # msg 18fail() { # msg
19 do_reset 19 do_reset
20 echo $1 20 echo $1
21 exit $FAIL 21 exit_fail
22} 22}
23 23
24disable_tracing 24disable_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() {
51fail() { # msg 51fail() { # msg
52 do_reset 52 do_reset
53 echo $1 53 echo $1
54 exit $FAIL 54 exit_fail
55} 55}
56 56
57yield() { 57yield() {
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() {
27fail() { # mesg 27fail() { # mesg
28 do_reset 28 do_reset
29 echo $1 29 echo $1
30 exit $FAIL 30 exit_fail
31} 31}
32 32
33SLEEP_TIME=".1" 33SLEEP_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
38echo "Testing function tracer with profiler:" 38echo "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() {
26fail() { # mesg 26fail() { # mesg
27 do_reset 27 do_reset
28 echo $1 28 echo $1
29 exit $FAIL 29 exit_fail
30} 30}
31 31
32do_reset 32do_reset
33 33
34FILTER=set_ftrace_filter 34FILTER=set_ftrace_filter
35FUNC1="schedule" 35FUNC1="schedule"
36FUNC2="do_IRQ" 36FUNC2="do_softirq"
37 37
38ALL_FUNCS="#### all functions enabled ####" 38ALL_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() {
27fail() { # mesg 27fail() { # mesg
28 do_reset 28 do_reset
29 echo $1 29 echo $1
30 exit $FAIL 30 exit_fail
31} 31}
32 32
33SLEEP_TIME=".1" 33SLEEP_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
17cd instances 17cd 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
17cd instances 17cd 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
9echo p:myevent _do_fork > kprobe_events 9echo p:myevent _do_fork > kprobe_events
10test -d events/kprobes/myevent 10test -d events/kprobes/myevent
11echo 1 > events/kprobes/myevent/enable 11echo 1 > events/kprobes/myevent/enable
12echo > kprobe_events && exit 1 # this must fail 12echo > kprobe_events && exit_fail # this must fail
13echo 0 > events/kprobes/myevent/enable 13echo 0 > events/kprobes/myevent/enable
14echo > kprobe_events # this must succeed 14echo > kprobe_events # this must succeed
15clear_trace 15clear_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
14echo 0 > events/kprobes/testprobe/enable 14echo 0 > events/kprobes/testprobe/enable
15echo "-:testprobe" >> kprobe_events 15echo "-:testprobe" >> kprobe_events
16clear_trace 16clear_trace
17test -d events/kprobes/testprobe && exit 1 || exit 0 17test -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
36echo "-:testprobe" >> kprobe_events 36echo "-:testprobe" >> kprobe_events
37clear_trace 37clear_trace
38test -d events/kprobes/testprobe && exit 1 || exit 0 38test -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
14echo 0 > events/kprobes/testprobe2/enable 14echo 0 > events/kprobes/testprobe2/enable
15echo '-:testprobe2' >> kprobe_events 15echo '-:testprobe2' >> kprobe_events
16clear_trace 16clear_trace
17test -d events/kprobes/testprobe2 && exit 1 || exit 0 17test -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
6exit 0 # Return 0 if the test is passed, otherwise return !0 6exit 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() {
12fail() { #msg 12fail() { #msg
13 do_reset 13 do_reset
14 echo $1 14 echo $1
15 exit $FAIL 15 exit_fail
16} 16}
17 17
18if [ ! -f set_event -o ! -d events/sched ]; then 18if [ ! -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() {
12fail() { #msg 12fail() { #msg
13 do_reset 13 do_reset
14 echo $1 14 echo $1
15 exit $FAIL 15 exit_fail
16} 16}
17 17
18if [ ! -f set_event -o ! -d events/sched ]; then 18if [ ! -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() {
12fail() { #msg 12fail() { #msg
13 do_reset 13 do_reset
14 echo $1 14 echo $1
15 exit $FAIL 15 exit_fail
16} 16}
17 17
18if [ ! -f set_event -o ! -d events/sched ]; then 18if [ ! -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() {
12fail() { #msg 12fail() { #msg
13 do_reset 13 do_reset
14 echo $1 14 echo $1
15 exit $FAIL 15 exit_fail
16} 16}
17 17
18if [ ! -f set_event -o ! -d events/sched ]; then 18if [ ! -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() {
12fail() { #msg 12fail() { #msg
13 do_reset 13 do_reset
14 echo $1 14 echo $1
15 exit $FAIL 15 exit_fail
16} 16}
17 17
18if [ ! -f set_event -o ! -d events/sched ]; then 18if [ ! -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() {
11fail() { #msg 11fail() { #msg
12 do_reset 12 do_reset
13 echo $1 13 echo $1
14 exit $FAIL 14 exit_fail
15} 15}
16 16
17if [ ! -f set_event -o ! -d events/sched ]; then 17if [ ! -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() {
11fail() { #msg 11fail() { #msg
12 do_reset 12 do_reset
13 echo $1 13 echo $1
14 exit $FAIL 14 exit_fail
15} 15}
16 16
17if [ ! -f set_event -o ! -d events/sched ]; then 17if [ ! -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() {
11fail() { #msg 11fail() { #msg
12 do_reset 12 do_reset
13 echo $1 13 echo $1
14 exit $FAIL 14 exit_fail
15} 15}
16 16
17if [ ! -f set_event -o ! -d events/sched ]; then 17if [ ! -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:
4include ../lib.mk 4include ../lib.mk
5 5
6TEST_PROGS := mem-on-off-test.sh 6TEST_PROGS := mem-on-off-test.sh
7override RUN_TESTS := ./mem-on-off-test.sh -r 2 || echo "selftests: memory-hotplug [FAIL]" 7override RUN_TESTS := ./mem-on-off-test.sh -r 2 && echo "selftests: memory-hotplug [PASS]" || echo "selftests: memory-hotplug [FAIL]"
8override EMIT_TESTS := echo "$(RUN_TESTS)" 8override EMIT_TESTS := echo "$(RUN_TESTS)"
9 9
10run_full_test: 10run_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
13clean: 13clean:
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
19check_fail()
20{
21 if [ $1 -eq 0 ]; then
22 ret=1
23 fi
24}
25
18kci_add_dummy() 26kci_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
40kci_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
33kci_test_bridge() 61kci_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
274kci_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
328kci_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
369kci_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
403kci_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
439kci_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
464kci_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
238kci_test_rtnl() 505kci_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
76static void start_thread_on(void *(*fn)(void *), void *arg, unsigned long cpu) 77static 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
12tm-signal-context-chk-vmx 12tm-signal-context-chk-vmx
13tm-signal-context-chk-vsx 13tm-signal-context-chk-vsx
14tm-vmx-unavail 14tm-vmx-unavail
15tm-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
5TEST_GEN_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack \ 5TEST_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
9include ../../lib.mk 9include ../../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
21SIGNAL_CONTEXT_CHK_TESTS := $(patsubst %,$(OUTPUT)/%,$(SIGNAL_CONTEXT_CHK_TESTS)) 22SIGNAL_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
37struct Flags {
38 int touch_fp;
39 int touch_vec;
40 int result;
41 int exception;
42} flags;
43
44bool 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. */
67bool 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
77void *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 */
277void *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. */
289void 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
321int 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
50static inline bool failure_is_unavailable(void)
51{
52 return (failure_code() & TM_CAUSE_FAC_UNAV) == TM_CAUSE_FAC_UNAV;
53}
54
50static inline bool failure_is_nesting(void) 55static 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 @@
1seccomp_bpf 1seccomp_bpf
2seccomp_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
34setup: The list of commands required to ensure the command under test 34setup: 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.
37cmdUnderTest: The tc command being tested itself. 43cmdUnderTest: The tc command being tested itself.
38expExitCode: The code returned by the command under test upon its termination. 44expExitCode: 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
49teardown: The list of commands to clean up after the test is completed. 55teardown: 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
54SETUP/TEARDOWN ERRORS 66SETUP/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
181def load_from_file(filename): 181def 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
23ENVIR = { }
24
25# put customizations in tdc_config_local.py
26try:
27 from tdc_config_local import *
28except ImportError as ie:
29 pass
30
31try:
32 NAMES.update(EXTRA_NAMES)
33except 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"""
2tdc_config_local.py - tdc plugin-writer-specified values
3
4Copyright (C) 2017 bjb@mojatatu.com
5"""
6
7import os
8
9ENVIR = os.environ.copy()
10
11ENV_LD_LIBRARY_PATH = os.getenv('LD_LIBRARY_PATH', '')
12ENV_OTHER_LIB = os.getenv('OTHER_LIB', '')
13
14
15# example adding value to NAMES, without editing tdc_config.py
16EXTRA_NAMES = dict()
17EXTRA_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
21ENVIR['VALGRIND_LIB'] = '/usr/lib/valgrind'
22ENVIR['VALGRIND_BIN'] = '/usr/bin/valgrind'
23ENVIR['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
18def get_unique_item(lst): 18def 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):
58def print_test_case(tcase): 58def 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
18valid-adjtimex 18valid-adjtimex
19adjtick 19adjtick
20set-tz 20set-tz
21freq-step
22rtctest_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);
19extern void vdso_init_from_sysinfo_ehdr(uintptr_t base); 19extern void vdso_init_from_sysinfo_ehdr(uintptr_t base);
20extern void vdso_init_from_auxv(void *auxv); 20extern 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__)
28const char *version = "LINUX_2.6.39";
29const char *name = "__kernel_gettimeofday";
30#else
31const char *version = "LINUX_2.6";
32const char *name = "__vdso_gettimeofday";
33#endif
34
22int main(int argc, char **argv) 35int 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
8transhuge-stress 8transhuge-stress
9userfaultfd 9userfaultfd
10mlock-intersect-test 10mlock-intersect-test
11mlock-random-test
12virtual_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
18TEST_GEN_FILES += userfaultfd 18TEST_GEN_FILES += userfaultfd
19TEST_GEN_FILES += mlock-random-test 19TEST_GEN_FILES += mlock-random-test
20TEST_GEN_FILES += virtual_address_range 20TEST_GEN_FILES += virtual_address_range
21TEST_GEN_FILES += gup_benchmark
21 22
22TEST_PROGS := run_vmtests 23TEST_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
19struct gup_benchmark {
20 __u64 delta_usec;
21 __u64 addr;
22 __u64 size;
23 __u32 nr_pages_per_call;
24 __u32 flags;
25};
26
27int 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
10struct 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
19static 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
152int 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
11TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \ 11TARGETS_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
14TARGETS_C_64BIT_ONLY := fsgsbase sysret_rip 14TARGETS_C_64BIT_ONLY := fsgsbase sysret_rip 5lvl
15 15
16TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY) 16TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY)
17TARGETS_C_64BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_64BIT_ONLY) 17TARGETS_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 @@
52struct mpx_bd_entry { 52struct 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
59struct mpx_bt_entry { 59struct 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
2vsock_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 @@
1all: test
2test: vsock_diag_test
3vsock_diag_test: vsock_diag_test.o timeout.o control.o
4
5CFLAGS += -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
7clean:
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 @@
1AF_VSOCK test suite
2-------------------
3These tests exercise net/vmw_vsock/ host<->guest sockets for VMware, KVM, and
4Hyper-V.
5
6The following tests are available:
7
8 * vsock_diag_test - vsock_diag.ko module for listing open sockets
9
10The following prerequisite steps are not automated and must be performed prior
11to running tests:
12
131. Build the kernel and these tests.
142. Install the kernel and tests on the host.
153. Install the kernel and tests inside the guest.
164. Boot the guest and ensure that the AF_VSOCK transport is enabled.
17
18Invoke 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
35static int control_fd = -1;
36
37/* Open the control socket, either in server or client mode */
38void 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
97next:
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 */
111void control_cleanup(void)
112{
113 close(control_fd);
114 control_fd = -1;
115}
116
117/* Write a line to the control socket */
118void 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 */
154char *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 */
207void 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
6void control_init(const char *control_host, const char *control_port,
7 bool server);
8void control_cleanup(void);
9void control_writeln(const char *str);
10char *control_readln(void);
11void 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
30static 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 */
36void 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 */
45void timeout_begin(unsigned int seconds)
46{
47 alarm(seconds);
48}
49
50/* Exit with an error message if the timeout has expired */
51void 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 */
60void 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
4enum {
5 /* Default timeout */
6 TIMEOUT = 10 /* seconds */
7};
8
9void sigalrm(int signo);
10void timeout_begin(unsigned int seconds);
11void timeout_check(const char *operation);
12void 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
37enum test_mode {
38 TEST_MODE_UNSET,
39 TEST_MODE_CLIENT,
40 TEST_MODE_SERVER
41};
42
43/* Per-socket status */
44struct vsock_stat {
45 struct list_head list;
46 struct vsock_diag_msg msg;
47};
48
49static 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
61static 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
79static 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
93static 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
106static 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
118static 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
126static 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
144static 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
153static 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
169static 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
178static 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
221static 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
250static 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 */
268static 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
329done:
330 close(fd);
331}
332
333static 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
342static 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
353static 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
391static 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
437static 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
510static 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
531static 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
541static 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
555static const char optstring[] = "";
556static 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
585static 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
605int 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.
3include ../../../scripts/Kbuild.include
4
2VERSION = 1.0 5VERSION = 1.0
3 6
4BINDIR=usr/bin 7BINDIR=usr/bin
5WARNFLAGS=-Wall -Wshadow -W -Wformat -Wimplicit-function-declaration -Wimplicit-int 8WARNFLAGS=-Wall -Wshadow -W -Wformat -Wimplicit-function-declaration -Wimplicit-int
6CFLAGS+= -O1 ${WARNFLAGS} -fstack-protector 9CFLAGS+= -O1 ${WARNFLAGS}
7CC=$(CROSS_COMPILE)gcc 10# Add "-fstack-protector" only if toolchain supports it.
11CFLAGS+= $(call cc-option,-fstack-protector)
12CC?= $(CROSS_COMPILE)gcc
13PKG_CONFIG?= pkg-config
8 14
9CFLAGS+=-D VERSION=\"$(VERSION)\" 15CFLAGS+=-D VERSION=\"$(VERSION)\"
10LDFLAGS+= 16LDFLAGS+=
@@ -19,12 +25,12 @@ STATIC := --static
19endif 25endif
20 26
21TMON_LIBS=-lm -lpthread 27TMON_LIBS=-lm -lpthread
22TMON_LIBS += $(shell pkg-config --libs $(STATIC) panelw ncursesw 2> /dev/null || \ 28TMON_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
26CFLAGS += $(shell pkg-config --cflags $(STATIC) panelw ncursesw 2> /dev/null || \ 32CFLAGS += $(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
29OBJS = tmon.o tui.o sysfs.o pid.o 35OBJS = tmon.o tui.o sysfs.o pid.o
30OBJS += 36OBJS +=
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 @@
2SUBDIRS := libsrc src 2SUBDIRS := libsrc src
3includedir = @includedir@/usbip 3includedir = @includedir@/usbip
4include_HEADERS := $(addprefix libsrc/, \ 4include_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
7dist_man_MANS := $(addprefix doc/, usbip.8 usbipd.8) 8dist_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:
329int usbip_vhci_get_free_port(uint32_t speed) 329int 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;
84int sort_loss; 84int sort_loss;
85int extended_totals; 85int extended_totals;
86int show_bytes; 86int show_bytes;
87int unreclaim_only;
87 88
88/* Debug options */ 89/* Debug options */
89int sanity; 90int 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 @@
1PREFIX ?= /usr
2SBINDIR ?= sbin
3INSTALL ?= install
4CFLAGS += -D__EXPORTED_HEADERS__ -I../../include/uapi -I../../include
5CC = $(CROSS_COMPILE)gcc
6
7TARGET = dell-smbios-example
8
9all: $(TARGET)
10
11%: %.c
12 $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
13
14clean:
15 $(RM) $(TARGET)
16
17install: 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 */
31static const char *ioctl_devfs = "/dev/wmi/dell-smbios";
32static const char *token_sysfs =
33 "/sys/bus/platform/devices/dell-smbios.0/tokens";
34
35static 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
45static 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
56static 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
97static 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
112static 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
126static 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
146static 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
158int 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;
207out:
208 free(buffer);
209 return ret;
210}