diff options
Diffstat (limited to 'tools')
397 files changed, 21592 insertions, 3024 deletions
diff --git a/tools/arch/arm64/include/uapi/asm/unistd.h b/tools/arch/arm64/include/uapi/asm/unistd.h new file mode 100644 index 000000000000..5072cbd15c82 --- /dev/null +++ b/tools/arch/arm64/include/uapi/asm/unistd.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Copyright (C) 2012 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#define __ARCH_WANT_RENAMEAT + +#include <asm-generic/unistd.h> diff --git a/tools/arch/parisc/include/uapi/asm/errno.h b/tools/arch/parisc/include/uapi/asm/errno.h index fc0df353ff0d..87245c584784 100644 --- a/tools/arch/parisc/include/uapi/asm/errno.h +++ b/tools/arch/parisc/include/uapi/asm/errno.h @@ -113,7 +113,6 @@ #define ELOOP 249 /* Too many symbolic links encountered */ #define ENOSYS 251 /* Function not implemented */ -#define ENOTSUP 252 /* Function not implemented (POSIX.4 / HPUX) */ #define ECANCELLED 253 /* aio request was canceled before complete (POSIX.4 / HPUX) */ #define ECANCELED ECANCELLED /* SuSv3 and Solaris wants one 'L' */ diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h index 5701f5cecd31..89a048c2faec 100644 --- a/tools/arch/x86/include/asm/cpufeatures.h +++ b/tools/arch/x86/include/asm/cpufeatures.h @@ -219,6 +219,8 @@ #define X86_FEATURE_IBPB ( 7*32+26) /* Indirect Branch Prediction Barrier */ #define X86_FEATURE_STIBP ( 7*32+27) /* Single Thread Indirect Branch Predictors */ #define X86_FEATURE_ZEN ( 7*32+28) /* "" CPU is AMD family 0x17 (Zen) */ +#define X86_FEATURE_L1TF_PTEINV ( 7*32+29) /* "" L1TF workaround PTE inversion */ +#define X86_FEATURE_IBRS_ENHANCED ( 7*32+30) /* Enhanced IBRS */ /* Virtualization flags: Linux defined, word 8 */ #define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */ @@ -229,7 +231,7 @@ #define X86_FEATURE_VMMCALL ( 8*32+15) /* Prefer VMMCALL to VMCALL */ #define X86_FEATURE_XENPV ( 8*32+16) /* "" Xen paravirtual guest */ - +#define X86_FEATURE_EPT_AD ( 8*32+17) /* Intel Extended Page Table access-dirty bit */ /* Intel-defined CPU features, CPUID level 0x00000007:0 (EBX), word 9 */ #define X86_FEATURE_FSGSBASE ( 9*32+ 0) /* RDFSBASE, WRFSBASE, RDGSBASE, WRGSBASE instructions*/ @@ -341,6 +343,7 @@ #define X86_FEATURE_PCONFIG (18*32+18) /* Intel PCONFIG */ #define X86_FEATURE_SPEC_CTRL (18*32+26) /* "" Speculation Control (IBRS + IBPB) */ #define X86_FEATURE_INTEL_STIBP (18*32+27) /* "" Single Thread Indirect Branch Predictors */ +#define X86_FEATURE_FLUSH_L1D (18*32+28) /* Flush L1D cache */ #define X86_FEATURE_ARCH_CAPABILITIES (18*32+29) /* IA32_ARCH_CAPABILITIES MSR (Intel) */ #define X86_FEATURE_SPEC_CTRL_SSBD (18*32+31) /* "" Speculative Store Bypass Disable */ @@ -373,5 +376,6 @@ #define X86_BUG_SPECTRE_V1 X86_BUG(15) /* CPU is affected by Spectre variant 1 attack with conditional branches */ #define X86_BUG_SPECTRE_V2 X86_BUG(16) /* CPU is affected by Spectre variant 2 attack with indirect branches */ #define X86_BUG_SPEC_STORE_BYPASS X86_BUG(17) /* CPU is affected by speculative store bypass attack */ +#define X86_BUG_L1TF X86_BUG(18) /* CPU is affected by L1 Terminal Fault */ #endif /* _ASM_X86_CPUFEATURES_H */ diff --git a/tools/arch/x86/lib/memcpy_64.S b/tools/arch/x86/lib/memcpy_64.S index 298ef1479240..3b24dc05251c 100644 --- a/tools/arch/x86/lib/memcpy_64.S +++ b/tools/arch/x86/lib/memcpy_64.S @@ -256,7 +256,7 @@ ENTRY(__memcpy_mcsafe) /* Copy successful. Return zero */ .L_done_memcpy_trap: - xorq %rax, %rax + xorl %eax, %eax ret ENDPROC(__memcpy_mcsafe) EXPORT_SYMBOL_GPL(__memcpy_mcsafe) diff --git a/tools/bpf/.gitignore b/tools/bpf/.gitignore new file mode 100644 index 000000000000..dfe2bd5a4b95 --- /dev/null +++ b/tools/bpf/.gitignore @@ -0,0 +1,5 @@ +FEATURE-DUMP.bpf +bpf_asm +bpf_dbg +bpf_exp.yacc.* +bpf_jit_disasm diff --git a/tools/bpf/Makefile.helpers b/tools/bpf/Makefile.helpers new file mode 100644 index 000000000000..c34fea77f39f --- /dev/null +++ b/tools/bpf/Makefile.helpers @@ -0,0 +1,59 @@ +ifndef allow-override + include ../scripts/Makefile.include + include ../scripts/utilities.mak +else + # Assume Makefile.helpers is being run from bpftool/Documentation + # subdirectory. Go up two more directories to fetch bpf.h header and + # associated script. + UP2DIR := ../../ +endif + +INSTALL ?= install +RM ?= rm -f +RMDIR ?= rmdir --ignore-fail-on-non-empty + +ifeq ($(V),1) + Q = +else + Q = @ +endif + +prefix ?= /usr/local +mandir ?= $(prefix)/man +man7dir = $(mandir)/man7 + +HELPERS_RST = bpf-helpers.rst +MAN7_RST = $(HELPERS_RST) + +_DOC_MAN7 = $(patsubst %.rst,%.7,$(MAN7_RST)) +DOC_MAN7 = $(addprefix $(OUTPUT),$(_DOC_MAN7)) + +helpers: man7 +man7: $(DOC_MAN7) + +RST2MAN_DEP := $(shell command -v rst2man 2>/dev/null) + +$(OUTPUT)$(HELPERS_RST): $(UP2DIR)../../include/uapi/linux/bpf.h + $(QUIET_GEN)$(UP2DIR)../../scripts/bpf_helpers_doc.py --filename $< > $@ + +$(OUTPUT)%.7: $(OUTPUT)%.rst +ifndef RST2MAN_DEP + $(error "rst2man not found, but required to generate man pages") +endif + $(QUIET_GEN)rst2man $< > $@ + +helpers-clean: + $(call QUIET_CLEAN, eBPF_helpers-manpage) + $(Q)$(RM) $(DOC_MAN7) $(OUTPUT)$(HELPERS_RST) + +helpers-install: helpers + $(call QUIET_INSTALL, eBPF_helpers-manpage) + $(Q)$(INSTALL) -d -m 755 $(DESTDIR)$(man7dir) + $(Q)$(INSTALL) -m 644 $(DOC_MAN7) $(DESTDIR)$(man7dir) + +helpers-uninstall: + $(call QUIET_UNINST, eBPF_helpers-manpage) + $(Q)$(RM) $(addprefix $(DESTDIR)$(man7dir)/,$(_DOC_MAN7)) + $(Q)$(RMDIR) $(DESTDIR)$(man7dir) + +.PHONY: helpers helpers-clean helpers-install helpers-uninstall diff --git a/tools/bpf/bpftool/.gitignore b/tools/bpf/bpftool/.gitignore index d7e678c2d396..67167e44b726 100644 --- a/tools/bpf/bpftool/.gitignore +++ b/tools/bpf/bpftool/.gitignore @@ -1,3 +1,5 @@ *.d bpftool +bpftool*.8 +bpf-helpers.* FEATURE-DUMP.bpftool diff --git a/tools/bpf/bpftool/Documentation/Makefile b/tools/bpf/bpftool/Documentation/Makefile index a9d47c1558bb..f7663a3e60c9 100644 --- a/tools/bpf/bpftool/Documentation/Makefile +++ b/tools/bpf/bpftool/Documentation/Makefile @@ -15,12 +15,15 @@ prefix ?= /usr/local mandir ?= $(prefix)/man man8dir = $(mandir)/man8 -MAN8_RST = $(wildcard *.rst) +# Load targets for building eBPF helpers man page. +include ../../Makefile.helpers + +MAN8_RST = $(filter-out $(HELPERS_RST),$(wildcard *.rst)) _DOC_MAN8 = $(patsubst %.rst,%.8,$(MAN8_RST)) DOC_MAN8 = $(addprefix $(OUTPUT),$(_DOC_MAN8)) -man: man8 +man: man8 helpers man8: $(DOC_MAN8) RST2MAN_DEP := $(shell command -v rst2man 2>/dev/null) @@ -31,16 +34,16 @@ ifndef RST2MAN_DEP endif $(QUIET_GEN)rst2man $< > $@ -clean: +clean: helpers-clean $(call QUIET_CLEAN, Documentation) $(Q)$(RM) $(DOC_MAN8) -install: man +install: man helpers-install $(call QUIET_INSTALL, Documentation-man) $(Q)$(INSTALL) -d -m 755 $(DESTDIR)$(man8dir) $(Q)$(INSTALL) -m 644 $(DOC_MAN8) $(DESTDIR)$(man8dir) -uninstall: +uninstall: helpers-uninstall $(call QUIET_UNINST, Documentation-man) $(Q)$(RM) $(addprefix $(DESTDIR)$(man8dir)/,$(_DOC_MAN8)) $(Q)$(RMDIR) $(DESTDIR)$(man8dir) diff --git a/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst b/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst index 7b0e6d453e92..edbe81534c6d 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst @@ -15,12 +15,13 @@ SYNOPSIS *OPTIONS* := { { **-j** | **--json** } [{ **-p** | **--pretty** }] | { **-f** | **--bpffs** } } *COMMANDS* := - { **show** | **list** | **attach** | **detach** | **help** } + { **show** | **list** | **tree** | **attach** | **detach** | **help** } MAP COMMANDS ============= | **bpftool** **cgroup { show | list }** *CGROUP* +| **bpftool** **cgroup tree** [*CGROUP_ROOT*] | **bpftool** **cgroup attach** *CGROUP* *ATTACH_TYPE* *PROG* [*ATTACH_FLAGS*] | **bpftool** **cgroup detach** *CGROUP* *ATTACH_TYPE* *PROG* | **bpftool** **cgroup help** @@ -39,6 +40,15 @@ DESCRIPTION Output will start with program ID followed by attach type, attach flags and program name. + **bpftool cgroup tree** [*CGROUP_ROOT*] + Iterate over all cgroups in *CGROUP_ROOT* and list all + attached programs. If *CGROUP_ROOT* is not specified, + bpftool uses cgroup v2 mountpoint. + + The output is similar to the output of cgroup show/list + commands: it starts with absolute cgroup path, followed by + program ID, attach type, attach flags and program name. + **bpftool cgroup attach** *CGROUP* *ATTACH_TYPE* *PROG* [*ATTACH_FLAGS*] Attach program *PROG* to the cgroup *CGROUP* with attach type *ATTACH_TYPE* and optional *ATTACH_FLAGS*. diff --git a/tools/bpf/bpftool/Documentation/bpftool-prog.rst b/tools/bpf/bpftool/Documentation/bpftool-prog.rst index 43d34a5c3ec5..64156a16d530 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-prog.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-prog.rst @@ -24,10 +24,20 @@ MAP COMMANDS | **bpftool** **prog dump xlated** *PROG* [{**file** *FILE* | **opcodes** | **visual**}] | **bpftool** **prog dump jited** *PROG* [{**file** *FILE* | **opcodes**}] | **bpftool** **prog pin** *PROG* *FILE* -| **bpftool** **prog load** *OBJ* *FILE* +| **bpftool** **prog load** *OBJ* *FILE* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*] | **bpftool** **prog help** | +| *MAP* := { **id** *MAP_ID* | **pinned** *FILE* } | *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* } +| *TYPE* := { +| **socket** | **kprobe** | **kretprobe** | **classifier** | **action** | +| **tracepoint** | **raw_tracepoint** | **xdp** | **perf_event** | **cgroup/skb** | +| **cgroup/sock** | **cgroup/dev** | **lwt_in** | **lwt_out** | **lwt_xmit** | +| **lwt_seg6local** | **sockops** | **sk_skb** | **sk_msg** | **lirc_mode2** | +| **cgroup/bind4** | **cgroup/bind6** | **cgroup/post_bind4** | **cgroup/post_bind6** | +| **cgroup/connect4** | **cgroup/connect6** | **cgroup/sendmsg4** | **cgroup/sendmsg6** +| } + DESCRIPTION =========== @@ -64,8 +74,19 @@ DESCRIPTION Note: *FILE* must be located in *bpffs* mount. - **bpftool prog load** *OBJ* *FILE* + **bpftool prog load** *OBJ* *FILE* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*] Load bpf program from binary *OBJ* and pin as *FILE*. + **type** is optional, if not specified program type will be + inferred from section names. + By default bpftool will create new maps as declared in the ELF + object being loaded. **map** parameter allows for the reuse + of existing maps. It can be specified multiple times, each + time for a different map. *IDX* refers to index of the map + to be replaced in the ELF file counting from 0, while *NAME* + allows to replace a map by name. *MAP* specifies the map to + use, referring to it by **id** or through a **pinned** file. + If **dev** *NAME* is specified program will be loaded onto + given networking device (offload). Note: *FILE* must be located in *bpffs* mount. @@ -159,6 +180,14 @@ EXAMPLES mov %rbx,0x0(%rbp) 48 89 5d 00 +| +| **# bpftool prog load xdp1_kern.o /sys/fs/bpf/xdp1 type xdp map name rxcnt id 7** +| **# bpftool prog show pinned /sys/fs/bpf/xdp1** +| 9: xdp name xdp_prog1 tag 539ec6ce11b52f98 gpl +| loaded_at 2018-06-25T16:17:31-0700 uid 0 +| xlated 488B jited 336B memlock 4096B map_ids 7 +| **# rm /sys/fs/bpf/xdp1** +| SEE ALSO ======== diff --git a/tools/bpf/bpftool/Makefile b/tools/bpf/bpftool/Makefile index 892dbf095bff..74288a2197ab 100644 --- a/tools/bpf/bpftool/Makefile +++ b/tools/bpf/bpftool/Makefile @@ -23,10 +23,10 @@ endif LIBBPF = $(BPF_PATH)libbpf.a -BPFTOOL_VERSION=$(shell make --no-print-directory -sC ../../.. kernelversion) +BPFTOOL_VERSION := $(shell make --no-print-directory -sC ../../.. kernelversion) $(LIBBPF): FORCE - $(Q)$(MAKE) -C $(BPF_DIR) OUTPUT=$(OUTPUT) $(OUTPUT)libbpf.a FEATURES_DUMP=$(FEATURE_DUMP_EXPORT) + $(Q)$(MAKE) -C $(BPF_DIR) OUTPUT=$(OUTPUT) $(OUTPUT)libbpf.a $(LIBBPF)-clean: $(call QUIET_CLEAN, libbpf) @@ -52,7 +52,7 @@ INSTALL ?= install RM ?= rm -f FEATURE_USER = .bpftool -FEATURE_TESTS = libbfd disassembler-four-args +FEATURE_TESTS = libbfd disassembler-four-args reallocarray FEATURE_DISPLAY = libbfd disassembler-four-args check_feat := 1 @@ -75,6 +75,10 @@ ifeq ($(feature-disassembler-four-args), 1) CFLAGS += -DDISASM_FOUR_ARGS_SIGNATURE endif +ifeq ($(feature-reallocarray), 0) +CFLAGS += -DCOMPAT_NEED_REALLOCARRAY +endif + include $(wildcard $(OUTPUT)*.d) all: $(OUTPUT)bpftool diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool index 1e1083321643..598066c40191 100644 --- a/tools/bpf/bpftool/bash-completion/bpftool +++ b/tools/bpf/bpftool/bash-completion/bpftool @@ -99,6 +99,35 @@ _bpftool_get_prog_tags() command sed -n 's/.*"tag": "\(.*\)",$/\1/p' )" -- "$cur" ) ) } +_bpftool_get_obj_map_names() +{ + local obj + + obj=$1 + + maps=$(objdump -j maps -t $obj 2>/dev/null | \ + command awk '/g . maps/ {print $NF}') + + COMPREPLY+=( $( compgen -W "$maps" -- "$cur" ) ) +} + +_bpftool_get_obj_map_idxs() +{ + local obj + + obj=$1 + + nmaps=$(objdump -j maps -t $obj 2>/dev/null | grep -c 'g . maps') + + COMPREPLY+=( $( compgen -W "$(seq 0 $((nmaps - 1)))" -- "$cur" ) ) +} + +_sysfs_get_netdevs() +{ + COMPREPLY+=( $( compgen -W "$( ls /sys/class/net 2>/dev/null )" -- \ + "$cur" ) ) +} + # For bpftool map update: retrieve type of the map to update. _bpftool_map_update_map_type() { @@ -153,6 +182,13 @@ _bpftool() local cur prev words objword _init_completion || return + # Deal with options + if [[ ${words[cword]} == -* ]]; then + local c='--version --json --pretty --bpffs' + COMPREPLY=( $( compgen -W "$c" -- "$cur" ) ) + return 0 + fi + # Deal with simplest keywords case $prev in help|hex|opcodes|visual) @@ -172,20 +208,23 @@ _bpftool() ;; esac - # Search for object and command - local object command cmdword - for (( cmdword=1; cmdword < ${#words[@]}-1; cmdword++ )); do - [[ -n $object ]] && command=${words[cmdword]} && break - [[ ${words[cmdword]} != -* ]] && object=${words[cmdword]} + # Remove all options so completions don't have to deal with them. + local i + for (( i=1; i < ${#words[@]}; )); do + if [[ ${words[i]::1} == - ]]; then + words=( "${words[@]:0:i}" "${words[@]:i+1}" ) + [[ $i -le $cword ]] && cword=$(( cword - 1 )) + else + i=$(( ++i )) + fi done + cur=${words[cword]} + prev=${words[cword - 1]} + + local object=${words[1]} command=${words[2]} - if [[ -z $object ]]; then + if [[ -z $object || $cword -eq 1 ]]; then case $cur in - -*) - local c='--version --json --pretty' - COMPREPLY=( $( compgen -W "$c" -- "$cur" ) ) - return 0 - ;; *) COMPREPLY=( $( compgen -W "$( bpftool help 2>&1 | \ command sed \ @@ -204,12 +243,14 @@ _bpftool() # Completion depends on object and command in use case $object in prog) - case $prev in - id) - _bpftool_get_prog_ids - return 0 - ;; - esac + if [[ $command != "load" ]]; then + case $prev in + id) + _bpftool_get_prog_ids + return 0 + ;; + esac + fi local PROG_TYPE='id pinned tag' case $command in @@ -252,8 +293,57 @@ _bpftool() return 0 ;; load) - _filedir - return 0 + local obj + + if [[ ${#words[@]} -lt 6 ]]; then + _filedir + return 0 + fi + + obj=${words[3]} + + if [[ ${words[-4]} == "map" ]]; then + COMPREPLY=( $( compgen -W "id pinned" -- "$cur" ) ) + return 0 + fi + if [[ ${words[-3]} == "map" ]]; then + if [[ ${words[-2]} == "idx" ]]; then + _bpftool_get_obj_map_idxs $obj + elif [[ ${words[-2]} == "name" ]]; then + _bpftool_get_obj_map_names $obj + fi + return 0 + fi + if [[ ${words[-2]} == "map" ]]; then + COMPREPLY=( $( compgen -W "idx name" -- "$cur" ) ) + return 0 + fi + + case $prev in + type) + COMPREPLY=( $( compgen -W "socket kprobe kretprobe classifier action tracepoint raw_tracepoint xdp perf_event cgroup/skb cgroup/sock cgroup/dev lwt_in lwt_out lwt_xmit lwt_seg6local sockops sk_skb sk_msg lirc_mode2 cgroup/bind4 cgroup/bind6 cgroup/connect4 cgroup/connect6 cgroup/sendmsg4 cgroup/sendmsg6 cgroup/post_bind4 cgroup/post_bind6" -- \ + "$cur" ) ) + return 0 + ;; + id) + _bpftool_get_map_ids + return 0 + ;; + pinned) + _filedir + return 0 + ;; + dev) + _sysfs_get_netdevs + return 0 + ;; + *) + COMPREPLY=( $( compgen -W "map" -- "$cur" ) ) + _bpftool_once_attr 'type' + _bpftool_once_attr 'dev' + return 0 + ;; + esac ;; *) [[ $prev == $object ]] && \ @@ -404,6 +494,10 @@ _bpftool() _filedir return 0 ;; + tree) + _filedir + return 0 + ;; attach|detach) local ATTACH_TYPES='ingress egress sock_create sock_ops \ device bind4 bind6 post_bind4 post_bind6 connect4 \ @@ -445,7 +539,7 @@ _bpftool() *) [[ $prev == $object ]] && \ COMPREPLY=( $( compgen -W 'help attach detach \ - show list' -- "$cur" ) ) + show list tree' -- "$cur" ) ) ;; esac ;; diff --git a/tools/bpf/bpftool/btf_dumper.c b/tools/bpf/bpftool/btf_dumper.c new file mode 100644 index 000000000000..55bc512a1831 --- /dev/null +++ b/tools/bpf/bpftool/btf_dumper.c @@ -0,0 +1,251 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2018 Facebook */ + +#include <ctype.h> +#include <stdio.h> /* for (FILE *) used by json_writer */ +#include <string.h> +#include <asm/byteorder.h> +#include <linux/bitops.h> +#include <linux/btf.h> +#include <linux/err.h> + +#include "btf.h" +#include "json_writer.h" +#include "main.h" + +#define BITS_PER_BYTE_MASK (BITS_PER_BYTE - 1) +#define BITS_PER_BYTE_MASKED(bits) ((bits) & BITS_PER_BYTE_MASK) +#define BITS_ROUNDDOWN_BYTES(bits) ((bits) >> 3) +#define BITS_ROUNDUP_BYTES(bits) \ + (BITS_ROUNDDOWN_BYTES(bits) + !!BITS_PER_BYTE_MASKED(bits)) + +static int btf_dumper_do_type(const struct btf_dumper *d, __u32 type_id, + __u8 bit_offset, const void *data); + +static void btf_dumper_ptr(const void *data, json_writer_t *jw, + bool is_plain_text) +{ + if (is_plain_text) + jsonw_printf(jw, "%p", *(unsigned long *)data); + else + jsonw_printf(jw, "%u", *(unsigned long *)data); +} + +static int btf_dumper_modifier(const struct btf_dumper *d, __u32 type_id, + const void *data) +{ + int actual_type_id; + + actual_type_id = btf__resolve_type(d->btf, type_id); + if (actual_type_id < 0) + return actual_type_id; + + return btf_dumper_do_type(d, actual_type_id, 0, data); +} + +static void btf_dumper_enum(const void *data, json_writer_t *jw) +{ + jsonw_printf(jw, "%d", *(int *)data); +} + +static int btf_dumper_array(const struct btf_dumper *d, __u32 type_id, + const void *data) +{ + const struct btf_type *t = btf__type_by_id(d->btf, type_id); + struct btf_array *arr = (struct btf_array *)(t + 1); + long long elem_size; + int ret = 0; + __u32 i; + + elem_size = btf__resolve_size(d->btf, arr->type); + if (elem_size < 0) + return elem_size; + + jsonw_start_array(d->jw); + for (i = 0; i < arr->nelems; i++) { + ret = btf_dumper_do_type(d, arr->type, 0, + data + i * elem_size); + if (ret) + break; + } + + jsonw_end_array(d->jw); + return ret; +} + +static void btf_dumper_int_bits(__u32 int_type, __u8 bit_offset, + const void *data, json_writer_t *jw, + bool is_plain_text) +{ + int left_shift_bits, right_shift_bits; + int nr_bits = BTF_INT_BITS(int_type); + int total_bits_offset; + int bytes_to_copy; + int bits_to_copy; + __u64 print_num; + + total_bits_offset = bit_offset + BTF_INT_OFFSET(int_type); + data += BITS_ROUNDDOWN_BYTES(total_bits_offset); + bit_offset = BITS_PER_BYTE_MASKED(total_bits_offset); + bits_to_copy = bit_offset + nr_bits; + bytes_to_copy = BITS_ROUNDUP_BYTES(bits_to_copy); + + print_num = 0; + memcpy(&print_num, data, bytes_to_copy); +#if defined(__BIG_ENDIAN_BITFIELD) + left_shift_bits = bit_offset; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + left_shift_bits = 64 - bits_to_copy; +#else +#error neither big nor little endian +#endif + right_shift_bits = 64 - nr_bits; + + print_num <<= left_shift_bits; + print_num >>= right_shift_bits; + if (is_plain_text) + jsonw_printf(jw, "0x%llx", print_num); + else + jsonw_printf(jw, "%llu", print_num); +} + +static int btf_dumper_int(const struct btf_type *t, __u8 bit_offset, + const void *data, json_writer_t *jw, + bool is_plain_text) +{ + __u32 *int_type; + __u32 nr_bits; + + int_type = (__u32 *)(t + 1); + nr_bits = BTF_INT_BITS(*int_type); + /* if this is bit field */ + if (bit_offset || BTF_INT_OFFSET(*int_type) || + BITS_PER_BYTE_MASKED(nr_bits)) { + btf_dumper_int_bits(*int_type, bit_offset, data, jw, + is_plain_text); + return 0; + } + + switch (BTF_INT_ENCODING(*int_type)) { + case 0: + if (BTF_INT_BITS(*int_type) == 64) + jsonw_printf(jw, "%lu", *(__u64 *)data); + else if (BTF_INT_BITS(*int_type) == 32) + jsonw_printf(jw, "%u", *(__u32 *)data); + else if (BTF_INT_BITS(*int_type) == 16) + jsonw_printf(jw, "%hu", *(__u16 *)data); + else if (BTF_INT_BITS(*int_type) == 8) + jsonw_printf(jw, "%hhu", *(__u8 *)data); + else + btf_dumper_int_bits(*int_type, bit_offset, data, jw, + is_plain_text); + break; + case BTF_INT_SIGNED: + if (BTF_INT_BITS(*int_type) == 64) + jsonw_printf(jw, "%ld", *(long long *)data); + else if (BTF_INT_BITS(*int_type) == 32) + jsonw_printf(jw, "%d", *(int *)data); + else if (BTF_INT_BITS(*int_type) == 16) + jsonw_printf(jw, "%hd", *(short *)data); + else if (BTF_INT_BITS(*int_type) == 8) + jsonw_printf(jw, "%hhd", *(char *)data); + else + btf_dumper_int_bits(*int_type, bit_offset, data, jw, + is_plain_text); + break; + case BTF_INT_CHAR: + if (isprint(*(char *)data)) + jsonw_printf(jw, "\"%c\"", *(char *)data); + else + if (is_plain_text) + jsonw_printf(jw, "0x%hhx", *(char *)data); + else + jsonw_printf(jw, "\"\\u00%02hhx\"", + *(char *)data); + break; + case BTF_INT_BOOL: + jsonw_bool(jw, *(int *)data); + break; + default: + /* shouldn't happen */ + return -EINVAL; + } + + return 0; +} + +static int btf_dumper_struct(const struct btf_dumper *d, __u32 type_id, + const void *data) +{ + const struct btf_type *t; + struct btf_member *m; + const void *data_off; + int ret = 0; + int i, vlen; + + t = btf__type_by_id(d->btf, type_id); + if (!t) + return -EINVAL; + + vlen = BTF_INFO_VLEN(t->info); + jsonw_start_object(d->jw); + m = (struct btf_member *)(t + 1); + + for (i = 0; i < vlen; i++) { + data_off = data + BITS_ROUNDDOWN_BYTES(m[i].offset); + jsonw_name(d->jw, btf__name_by_offset(d->btf, m[i].name_off)); + ret = btf_dumper_do_type(d, m[i].type, + BITS_PER_BYTE_MASKED(m[i].offset), + data_off); + if (ret) + break; + } + + jsonw_end_object(d->jw); + + return ret; +} + +static int btf_dumper_do_type(const struct btf_dumper *d, __u32 type_id, + __u8 bit_offset, const void *data) +{ + const struct btf_type *t = btf__type_by_id(d->btf, type_id); + + switch (BTF_INFO_KIND(t->info)) { + case BTF_KIND_INT: + return btf_dumper_int(t, bit_offset, data, d->jw, + d->is_plain_text); + case BTF_KIND_STRUCT: + case BTF_KIND_UNION: + return btf_dumper_struct(d, type_id, data); + case BTF_KIND_ARRAY: + return btf_dumper_array(d, type_id, data); + case BTF_KIND_ENUM: + btf_dumper_enum(data, d->jw); + return 0; + case BTF_KIND_PTR: + btf_dumper_ptr(data, d->jw, d->is_plain_text); + return 0; + case BTF_KIND_UNKN: + jsonw_printf(d->jw, "(unknown)"); + return 0; + case BTF_KIND_FWD: + /* map key or value can't be forward */ + jsonw_printf(d->jw, "(fwd-kind-invalid)"); + return -EINVAL; + case BTF_KIND_TYPEDEF: + case BTF_KIND_VOLATILE: + case BTF_KIND_CONST: + case BTF_KIND_RESTRICT: + return btf_dumper_modifier(d, type_id, data); + default: + jsonw_printf(d->jw, "(unsupported-kind"); + return -EINVAL; + } +} + +int btf_dumper_type(const struct btf_dumper *d, __u32 type_id, + const void *data) +{ + return btf_dumper_do_type(d, type_id, 0, data); +} diff --git a/tools/bpf/bpftool/cgroup.c b/tools/bpf/bpftool/cgroup.c index 16bee011e16c..ee7a9765c6b3 100644 --- a/tools/bpf/bpftool/cgroup.c +++ b/tools/bpf/bpftool/cgroup.c @@ -2,7 +2,12 @@ // Copyright (C) 2017 Facebook // Author: Roman Gushchin <guro@fb.com> +#define _XOPEN_SOURCE 500 +#include <errno.h> #include <fcntl.h> +#include <ftw.h> +#include <mntent.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> @@ -53,7 +58,8 @@ static enum bpf_attach_type parse_attach_type(const char *str) } static int show_bpf_prog(int id, const char *attach_type_str, - const char *attach_flags_str) + const char *attach_flags_str, + int level) { struct bpf_prog_info info = {}; __u32 info_len = sizeof(info); @@ -78,7 +84,8 @@ static int show_bpf_prog(int id, const char *attach_type_str, jsonw_string_field(json_wtr, "name", info.name); jsonw_end_object(json_wtr); } else { - printf("%-8u %-15s %-15s %-15s\n", info.id, + printf("%s%-8u %-15s %-15s %-15s\n", level ? " " : "", + info.id, attach_type_str, attach_flags_str, info.name); @@ -88,7 +95,20 @@ static int show_bpf_prog(int id, const char *attach_type_str, return 0; } -static int show_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type) +static int count_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type) +{ + __u32 prog_cnt = 0; + int ret; + + ret = bpf_prog_query(cgroup_fd, type, 0, NULL, NULL, &prog_cnt); + if (ret) + return -1; + + return prog_cnt; +} + +static int show_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type, + int level) { __u32 prog_ids[1024] = {0}; char *attach_flags_str; @@ -123,7 +143,7 @@ static int show_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type) for (iter = 0; iter < prog_cnt; iter++) show_bpf_prog(prog_ids[iter], attach_type_strings[type], - attach_flags_str); + attach_flags_str, level); return 0; } @@ -161,7 +181,7 @@ static int do_show(int argc, char **argv) * If we were able to get the show for at least one * attach type, let's return 0. */ - if (show_attached_bpf_progs(cgroup_fd, type) == 0) + if (show_attached_bpf_progs(cgroup_fd, type, 0) == 0) ret = 0; } @@ -173,6 +193,143 @@ exit: return ret; } +/* + * To distinguish nftw() errors and do_show_tree_fn() errors + * and avoid duplicating error messages, let's return -2 + * from do_show_tree_fn() in case of error. + */ +#define NFTW_ERR -1 +#define SHOW_TREE_FN_ERR -2 +static int do_show_tree_fn(const char *fpath, const struct stat *sb, + int typeflag, struct FTW *ftw) +{ + enum bpf_attach_type type; + bool skip = true; + int cgroup_fd; + + if (typeflag != FTW_D) + return 0; + + cgroup_fd = open(fpath, O_RDONLY); + if (cgroup_fd < 0) { + p_err("can't open cgroup %s: %s", fpath, strerror(errno)); + return SHOW_TREE_FN_ERR; + } + + for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { + int count = count_attached_bpf_progs(cgroup_fd, type); + + if (count < 0 && errno != EINVAL) { + p_err("can't query bpf programs attached to %s: %s", + fpath, strerror(errno)); + close(cgroup_fd); + return SHOW_TREE_FN_ERR; + } + if (count > 0) { + skip = false; + break; + } + } + + if (skip) { + close(cgroup_fd); + return 0; + } + + if (json_output) { + jsonw_start_object(json_wtr); + jsonw_string_field(json_wtr, "cgroup", fpath); + jsonw_name(json_wtr, "programs"); + jsonw_start_array(json_wtr); + } else { + printf("%s\n", fpath); + } + + for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) + show_attached_bpf_progs(cgroup_fd, type, ftw->level); + + if (json_output) { + jsonw_end_array(json_wtr); + jsonw_end_object(json_wtr); + } + + close(cgroup_fd); + + return 0; +} + +static char *find_cgroup_root(void) +{ + struct mntent *mnt; + FILE *f; + + f = fopen("/proc/mounts", "r"); + if (f == NULL) + return NULL; + + while ((mnt = getmntent(f))) { + if (strcmp(mnt->mnt_type, "cgroup2") == 0) { + fclose(f); + return strdup(mnt->mnt_dir); + } + } + + fclose(f); + return NULL; +} + +static int do_show_tree(int argc, char **argv) +{ + char *cgroup_root; + int ret; + + switch (argc) { + case 0: + cgroup_root = find_cgroup_root(); + if (!cgroup_root) { + p_err("cgroup v2 isn't mounted"); + return -1; + } + break; + case 1: + cgroup_root = argv[0]; + break; + default: + p_err("too many parameters for cgroup tree"); + return -1; + } + + + if (json_output) + jsonw_start_array(json_wtr); + else + printf("%s\n" + "%-8s %-15s %-15s %-15s\n", + "CgroupPath", + "ID", "AttachType", "AttachFlags", "Name"); + + switch (nftw(cgroup_root, do_show_tree_fn, 1024, FTW_MOUNT)) { + case NFTW_ERR: + p_err("can't iterate over %s: %s", cgroup_root, + strerror(errno)); + ret = -1; + break; + case SHOW_TREE_FN_ERR: + ret = -1; + break; + default: + ret = 0; + } + + if (json_output) + jsonw_end_array(json_wtr); + + if (argc == 0) + free(cgroup_root); + + return ret; +} + static int do_attach(int argc, char **argv) { enum bpf_attach_type attach_type; @@ -289,6 +446,7 @@ static int do_help(int argc, char **argv) fprintf(stderr, "Usage: %s %s { show | list } CGROUP\n" + " %s %s tree [CGROUP_ROOT]\n" " %s %s attach CGROUP ATTACH_TYPE PROG [ATTACH_FLAGS]\n" " %s %s detach CGROUP ATTACH_TYPE PROG\n" " %s %s help\n" @@ -298,6 +456,7 @@ static int do_help(int argc, char **argv) " " HELP_SPEC_PROGRAM "\n" " " HELP_SPEC_OPTIONS "\n" "", + bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]); @@ -307,6 +466,7 @@ static int do_help(int argc, char **argv) static const struct cmd cmds[] = { { "show", do_show }, { "list", do_show }, + { "tree", do_show_tree }, { "attach", do_attach }, { "detach", do_detach }, { "help", do_help }, diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c index 3f140eff039f..b3a0709ea7ed 100644 --- a/tools/bpf/bpftool/common.c +++ b/tools/bpf/bpftool/common.c @@ -31,8 +31,6 @@ * SOFTWARE. */ -/* Author: Jakub Kicinski <kubakici@wp.pl> */ - #include <ctype.h> #include <errno.h> #include <fcntl.h> diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c index eea7f14355f3..d15a62be6cf0 100644 --- a/tools/bpf/bpftool/main.c +++ b/tools/bpf/bpftool/main.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 Netronome Systems, Inc. + * Copyright (C) 2017-2018 Netronome Systems, Inc. * * This software is dual licensed under the GNU General License Version 2, * June 1991 as shown in the file COPYING in the top-level directory of this @@ -31,8 +31,6 @@ * SOFTWARE. */ -/* Author: Jakub Kicinski <kubakici@wp.pl> */ - #include <bfd.h> #include <ctype.h> #include <errno.h> diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h index 63fdb310b9a4..238e734d75b3 100644 --- a/tools/bpf/bpftool/main.h +++ b/tools/bpf/bpftool/main.h @@ -31,8 +31,6 @@ * SOFTWARE. */ -/* Author: Jakub Kicinski <kubakici@wp.pl> */ - #ifndef __BPF_TOOL_H #define __BPF_TOOL_H @@ -44,6 +42,7 @@ #include <linux/compiler.h> #include <linux/kernel.h> #include <linux/hashtable.h> +#include <tools/libc_compat.h> #include "json_writer.h" @@ -52,6 +51,21 @@ #define NEXT_ARG() ({ argc--; argv++; if (argc < 0) usage(); }) #define NEXT_ARGP() ({ (*argc)--; (*argv)++; if (*argc < 0) usage(); }) #define BAD_ARG() ({ p_err("what is '%s'?", *argv); -1; }) +#define GET_ARG() ({ argc--; *argv++; }) +#define REQ_ARGS(cnt) \ + ({ \ + int _cnt = (cnt); \ + bool _res; \ + \ + if (argc < _cnt) { \ + p_err("'%s' needs at least %d arguments, %d found", \ + argv[-1], _cnt, argc); \ + _res = false; \ + } else { \ + _res = true; \ + } \ + _res; \ + }) #define ERR_MAX_LEN 1024 @@ -61,6 +75,8 @@ "PROG := { id PROG_ID | pinned FILE | tag PROG_TAG }" #define HELP_SPEC_OPTIONS \ "OPTIONS := { {-j|--json} [{-p|--pretty}] | {-f|--bpffs} }" +#define HELP_SPEC_MAP \ + "MAP := { id MAP_ID | pinned FILE }" enum bpf_obj_type { BPF_OBJ_UNKNOWN, @@ -122,6 +138,7 @@ int do_cgroup(int argc, char **arg); int do_perf(int argc, char **arg); int prog_parse_fd(int *argc, char ***argv); +int map_parse_fd(int *argc, char ***argv); int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len); void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, @@ -133,4 +150,19 @@ unsigned int get_page_size(void); unsigned int get_possible_cpus(void); const char *ifindex_to_bfd_name_ns(__u32 ifindex, __u64 ns_dev, __u64 ns_ino); +struct btf_dumper { + const struct btf *btf; + json_writer_t *jw; + bool is_plain_text; +}; + +/* btf_dumper_type - print data along with type information + * @d: an instance containing context for dumping types + * @type_id: index in btf->types array. this points to the type to be dumped + * @data: pointer the actual data, i.e. the values to be printed + * + * Returns zero on success and negative error code otherwise + */ +int btf_dumper_type(const struct btf_dumper *d, __u32 type_id, + const void *data); #endif diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c index f74a8bcbda87..b2ec20e562bd 100644 --- a/tools/bpf/bpftool/map.c +++ b/tools/bpf/bpftool/map.c @@ -31,11 +31,10 @@ * SOFTWARE. */ -/* Author: Jakub Kicinski <kubakici@wp.pl> */ - #include <assert.h> #include <errno.h> #include <fcntl.h> +#include <linux/err.h> #include <linux/kernel.h> #include <stdbool.h> #include <stdio.h> @@ -47,6 +46,8 @@ #include <bpf.h> +#include "btf.h" +#include "json_writer.h" #include "main.h" static const char * const map_type_name[] = { @@ -68,6 +69,7 @@ static const char * const map_type_name[] = { [BPF_MAP_TYPE_SOCKMAP] = "sockmap", [BPF_MAP_TYPE_CPUMAP] = "cpumap", [BPF_MAP_TYPE_SOCKHASH] = "sockhash", + [BPF_MAP_TYPE_CGROUP_STORAGE] = "cgroup_storage", }; static bool map_is_per_cpu(__u32 type) @@ -97,7 +99,7 @@ static void *alloc_value(struct bpf_map_info *info) return malloc(info->value_size); } -static int map_parse_fd(int *argc, char ***argv) +int map_parse_fd(int *argc, char ***argv) { int fd; @@ -152,8 +154,109 @@ int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len) return fd; } +static int do_dump_btf(const struct btf_dumper *d, + struct bpf_map_info *map_info, void *key, + void *value) +{ + int ret; + + /* start of key-value pair */ + jsonw_start_object(d->jw); + + jsonw_name(d->jw, "key"); + + ret = btf_dumper_type(d, map_info->btf_key_type_id, key); + if (ret) + goto err_end_obj; + + jsonw_name(d->jw, "value"); + + ret = btf_dumper_type(d, map_info->btf_value_type_id, value); + +err_end_obj: + /* end of key-value pair */ + jsonw_end_object(d->jw); + + return ret; +} + +static int get_btf(struct bpf_map_info *map_info, struct btf **btf) +{ + struct bpf_btf_info btf_info = { 0 }; + __u32 len = sizeof(btf_info); + __u32 last_size; + int btf_fd; + void *ptr; + int err; + + err = 0; + *btf = NULL; + btf_fd = bpf_btf_get_fd_by_id(map_info->btf_id); + if (btf_fd < 0) + return 0; + + /* we won't know btf_size until we call bpf_obj_get_info_by_fd(). so + * let's start with a sane default - 4KiB here - and resize it only if + * bpf_obj_get_info_by_fd() needs a bigger buffer. + */ + btf_info.btf_size = 4096; + last_size = btf_info.btf_size; + ptr = malloc(last_size); + if (!ptr) { + err = -ENOMEM; + goto exit_free; + } + + bzero(ptr, last_size); + btf_info.btf = ptr_to_u64(ptr); + err = bpf_obj_get_info_by_fd(btf_fd, &btf_info, &len); + + if (!err && btf_info.btf_size > last_size) { + void *temp_ptr; + + last_size = btf_info.btf_size; + temp_ptr = realloc(ptr, last_size); + if (!temp_ptr) { + err = -ENOMEM; + goto exit_free; + } + ptr = temp_ptr; + bzero(ptr, last_size); + btf_info.btf = ptr_to_u64(ptr); + err = bpf_obj_get_info_by_fd(btf_fd, &btf_info, &len); + } + + if (err || btf_info.btf_size > last_size) { + err = errno; + goto exit_free; + } + + *btf = btf__new((__u8 *)btf_info.btf, btf_info.btf_size, NULL); + if (IS_ERR(*btf)) { + err = PTR_ERR(*btf); + *btf = NULL; + } + +exit_free: + close(btf_fd); + free(ptr); + + return err; +} + +static json_writer_t *get_btf_writer(void) +{ + json_writer_t *jw = jsonw_new(stdout); + + if (!jw) + return NULL; + jsonw_pretty(jw, true); + + return jw; +} + static void print_entry_json(struct bpf_map_info *info, unsigned char *key, - unsigned char *value) + unsigned char *value, struct btf *btf) { jsonw_start_object(json_wtr); @@ -162,6 +265,16 @@ static void print_entry_json(struct bpf_map_info *info, unsigned char *key, print_hex_data_json(key, info->key_size); jsonw_name(json_wtr, "value"); print_hex_data_json(value, info->value_size); + if (btf) { + struct btf_dumper d = { + .btf = btf, + .jw = json_wtr, + .is_plain_text = false, + }; + + jsonw_name(json_wtr, "formatted"); + do_dump_btf(&d, info, key, value); + } } else { unsigned int i, n, step; @@ -514,10 +627,12 @@ static int do_show(int argc, char **argv) static int do_dump(int argc, char **argv) { + struct bpf_map_info info = {}; void *key, *value, *prev_key; unsigned int num_elems = 0; - struct bpf_map_info info = {}; __u32 len = sizeof(info); + json_writer_t *btf_wtr; + struct btf *btf = NULL; int err; int fd; @@ -543,8 +658,27 @@ static int do_dump(int argc, char **argv) } prev_key = NULL; + + err = get_btf(&info, &btf); + if (err) { + p_err("failed to get btf"); + goto exit_free; + } + if (json_output) jsonw_start_array(json_wtr); + else + if (btf) { + btf_wtr = get_btf_writer(); + if (!btf_wtr) { + p_info("failed to create json writer for btf. falling back to plain output"); + btf__free(btf); + btf = NULL; + } else { + jsonw_start_array(btf_wtr); + } + } + while (true) { err = bpf_map_get_next_key(fd, prev_key, key); if (err) { @@ -555,9 +689,19 @@ static int do_dump(int argc, char **argv) if (!bpf_map_lookup_elem(fd, key, value)) { if (json_output) - print_entry_json(&info, key, value); + print_entry_json(&info, key, value, btf); else - print_entry_plain(&info, key, value); + if (btf) { + struct btf_dumper d = { + .btf = btf, + .jw = btf_wtr, + .is_plain_text = true, + }; + + do_dump_btf(&d, &info, key, value); + } else { + print_entry_plain(&info, key, value); + } } else { if (json_output) { jsonw_name(json_wtr, "key"); @@ -580,14 +724,19 @@ static int do_dump(int argc, char **argv) if (json_output) jsonw_end_array(json_wtr); - else + else if (btf) { + jsonw_end_array(btf_wtr); + jsonw_destroy(&btf_wtr); + } else { printf("Found %u element%s\n", num_elems, num_elems != 1 ? "s" : ""); + } exit_free: free(key); free(value); close(fd); + btf__free(btf); return err; } @@ -643,6 +792,8 @@ static int do_lookup(int argc, char **argv) { struct bpf_map_info info = {}; __u32 len = sizeof(info); + json_writer_t *btf_wtr; + struct btf *btf = NULL; void *key, *value; int err; int fd; @@ -667,27 +818,60 @@ static int do_lookup(int argc, char **argv) goto exit_free; err = bpf_map_lookup_elem(fd, key, value); - if (!err) { - if (json_output) - print_entry_json(&info, key, value); - else + if (err) { + if (errno == ENOENT) { + if (json_output) { + jsonw_null(json_wtr); + } else { + printf("key:\n"); + fprint_hex(stdout, key, info.key_size, " "); + printf("\n\nNot found\n"); + } + } else { + p_err("lookup failed: %s", strerror(errno)); + } + + goto exit_free; + } + + /* here means bpf_map_lookup_elem() succeeded */ + err = get_btf(&info, &btf); + if (err) { + p_err("failed to get btf"); + goto exit_free; + } + + if (json_output) { + print_entry_json(&info, key, value, btf); + } else if (btf) { + /* if here json_wtr wouldn't have been initialised, + * so let's create separate writer for btf + */ + btf_wtr = get_btf_writer(); + if (!btf_wtr) { + p_info("failed to create json writer for btf. falling back to plain output"); + btf__free(btf); + btf = NULL; print_entry_plain(&info, key, value); - } else if (errno == ENOENT) { - if (json_output) { - jsonw_null(json_wtr); } else { - printf("key:\n"); - fprint_hex(stdout, key, info.key_size, " "); - printf("\n\nNot found\n"); + struct btf_dumper d = { + .btf = btf, + .jw = btf_wtr, + .is_plain_text = true, + }; + + do_dump_btf(&d, &info, key, value); + jsonw_destroy(&btf_wtr); } } else { - p_err("lookup failed: %s", strerror(errno)); + print_entry_plain(&info, key, value); } exit_free: free(key); free(value); close(fd); + btf__free(btf); return err; } @@ -830,7 +1014,7 @@ static int do_help(int argc, char **argv) " %s %s event_pipe MAP [cpu N index M]\n" " %s %s help\n" "\n" - " MAP := { id MAP_ID | pinned FILE }\n" + " " HELP_SPEC_MAP "\n" " DATA := { [hex] BYTES }\n" " " HELP_SPEC_PROGRAM "\n" " VALUE := { DATA | MAP | PROG }\n" diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c index 959aa53ab678..dce960d22106 100644 --- a/tools/bpf/bpftool/prog.c +++ b/tools/bpf/bpftool/prog.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 Netronome Systems, Inc. + * Copyright (C) 2017-2018 Netronome Systems, Inc. * * This software is dual licensed under the GNU General License Version 2, * June 1991 as shown in the file COPYING in the top-level directory of this @@ -31,8 +31,7 @@ * SOFTWARE. */ -/* Author: Jakub Kicinski <kubakici@wp.pl> */ - +#define _GNU_SOURCE #include <errno.h> #include <fcntl.h> #include <stdarg.h> @@ -41,9 +40,12 @@ #include <string.h> #include <time.h> #include <unistd.h> +#include <net/if.h> #include <sys/types.h> #include <sys/stat.h> +#include <linux/err.h> + #include <bpf.h> #include <libbpf.h> @@ -681,31 +683,247 @@ static int do_pin(int argc, char **argv) return err; } +struct map_replace { + int idx; + int fd; + char *name; +}; + +int map_replace_compar(const void *p1, const void *p2) +{ + const struct map_replace *a = p1, *b = p2; + + return a->idx - b->idx; +} + static int do_load(int argc, char **argv) { + enum bpf_attach_type expected_attach_type; + struct bpf_object_open_attr attr = { + .prog_type = BPF_PROG_TYPE_UNSPEC, + }; + struct map_replace *map_replace = NULL; + unsigned int old_map_fds = 0; + struct bpf_program *prog; struct bpf_object *obj; - int prog_fd; - - if (argc != 2) - usage(); + struct bpf_map *map; + const char *pinfile; + unsigned int i, j; + __u32 ifindex = 0; + int idx, err; - if (bpf_prog_load(argv[0], BPF_PROG_TYPE_UNSPEC, &obj, &prog_fd)) { - p_err("failed to load program"); + if (!REQ_ARGS(2)) return -1; + attr.file = GET_ARG(); + pinfile = GET_ARG(); + + while (argc) { + if (is_prefix(*argv, "type")) { + char *type; + + NEXT_ARG(); + + if (attr.prog_type != BPF_PROG_TYPE_UNSPEC) { + p_err("program type already specified"); + goto err_free_reuse_maps; + } + if (!REQ_ARGS(1)) + goto err_free_reuse_maps; + + /* Put a '/' at the end of type to appease libbpf */ + type = malloc(strlen(*argv) + 2); + if (!type) { + p_err("mem alloc failed"); + goto err_free_reuse_maps; + } + *type = 0; + strcat(type, *argv); + strcat(type, "/"); + + err = libbpf_prog_type_by_name(type, &attr.prog_type, + &expected_attach_type); + free(type); + if (err < 0) { + p_err("unknown program type '%s'", *argv); + goto err_free_reuse_maps; + } + NEXT_ARG(); + } else if (is_prefix(*argv, "map")) { + char *endptr, *name; + int fd; + + NEXT_ARG(); + + if (!REQ_ARGS(4)) + goto err_free_reuse_maps; + + if (is_prefix(*argv, "idx")) { + NEXT_ARG(); + + idx = strtoul(*argv, &endptr, 0); + if (*endptr) { + p_err("can't parse %s as IDX", *argv); + goto err_free_reuse_maps; + } + name = NULL; + } else if (is_prefix(*argv, "name")) { + NEXT_ARG(); + + name = *argv; + idx = -1; + } else { + p_err("expected 'idx' or 'name', got: '%s'?", + *argv); + goto err_free_reuse_maps; + } + NEXT_ARG(); + + fd = map_parse_fd(&argc, &argv); + if (fd < 0) + goto err_free_reuse_maps; + + map_replace = reallocarray(map_replace, old_map_fds + 1, + sizeof(*map_replace)); + if (!map_replace) { + p_err("mem alloc failed"); + goto err_free_reuse_maps; + } + map_replace[old_map_fds].idx = idx; + map_replace[old_map_fds].name = name; + map_replace[old_map_fds].fd = fd; + old_map_fds++; + } else if (is_prefix(*argv, "dev")) { + NEXT_ARG(); + + if (ifindex) { + p_err("offload device already specified"); + goto err_free_reuse_maps; + } + if (!REQ_ARGS(1)) + goto err_free_reuse_maps; + + ifindex = if_nametoindex(*argv); + if (!ifindex) { + p_err("unrecognized netdevice '%s': %s", + *argv, strerror(errno)); + goto err_free_reuse_maps; + } + NEXT_ARG(); + } else { + p_err("expected no more arguments, 'type', 'map' or 'dev', got: '%s'?", + *argv); + goto err_free_reuse_maps; + } + } + + obj = bpf_object__open_xattr(&attr); + if (IS_ERR_OR_NULL(obj)) { + p_err("failed to open object file"); + goto err_free_reuse_maps; + } + + prog = bpf_program__next(NULL, obj); + if (!prog) { + p_err("object file doesn't contain any bpf program"); + goto err_close_obj; + } + + bpf_program__set_ifindex(prog, ifindex); + if (attr.prog_type == BPF_PROG_TYPE_UNSPEC) { + const char *sec_name = bpf_program__title(prog, false); + + err = libbpf_prog_type_by_name(sec_name, &attr.prog_type, + &expected_attach_type); + if (err < 0) { + p_err("failed to guess program type based on section name %s\n", + sec_name); + goto err_close_obj; + } + } + bpf_program__set_type(prog, attr.prog_type); + bpf_program__set_expected_attach_type(prog, expected_attach_type); + + qsort(map_replace, old_map_fds, sizeof(*map_replace), + map_replace_compar); + + /* After the sort maps by name will be first on the list, because they + * have idx == -1. Resolve them. + */ + j = 0; + while (j < old_map_fds && map_replace[j].name) { + i = 0; + bpf_map__for_each(map, obj) { + if (!strcmp(bpf_map__name(map), map_replace[j].name)) { + map_replace[j].idx = i; + break; + } + i++; + } + if (map_replace[j].idx == -1) { + p_err("unable to find map '%s'", map_replace[j].name); + goto err_close_obj; + } + j++; + } + /* Resort if any names were resolved */ + if (j) + qsort(map_replace, old_map_fds, sizeof(*map_replace), + map_replace_compar); + + /* Set ifindex and name reuse */ + j = 0; + idx = 0; + bpf_map__for_each(map, obj) { + if (!bpf_map__is_offload_neutral(map)) + bpf_map__set_ifindex(map, ifindex); + + if (j < old_map_fds && idx == map_replace[j].idx) { + err = bpf_map__reuse_fd(map, map_replace[j++].fd); + if (err) { + p_err("unable to set up map reuse: %d", err); + goto err_close_obj; + } + + /* Next reuse wants to apply to the same map */ + if (j < old_map_fds && map_replace[j].idx == idx) { + p_err("replacement for map idx %d specified more than once", + idx); + goto err_close_obj; + } + } + + idx++; + } + if (j < old_map_fds) { + p_err("map idx '%d' not used", map_replace[j].idx); + goto err_close_obj; + } + + err = bpf_object__load(obj); + if (err) { + p_err("failed to load object file"); + goto err_close_obj; } - if (do_pin_fd(prog_fd, argv[1])) + if (do_pin_fd(bpf_program__fd(prog), pinfile)) goto err_close_obj; if (json_output) jsonw_null(json_wtr); bpf_object__close(obj); + for (i = 0; i < old_map_fds; i++) + close(map_replace[i].fd); + free(map_replace); return 0; err_close_obj: bpf_object__close(obj); +err_free_reuse_maps: + for (i = 0; i < old_map_fds; i++) + close(map_replace[i].fd); + free(map_replace); return -1; } @@ -721,10 +939,19 @@ static int do_help(int argc, char **argv) " %s %s dump xlated PROG [{ file FILE | opcodes | visual }]\n" " %s %s dump jited PROG [{ file FILE | opcodes }]\n" " %s %s pin PROG FILE\n" - " %s %s load OBJ FILE\n" + " %s %s load OBJ FILE [type TYPE] [dev NAME] \\\n" + " [map { idx IDX | name NAME } MAP]\n" " %s %s help\n" "\n" + " " HELP_SPEC_MAP "\n" " " HELP_SPEC_PROGRAM "\n" + " TYPE := { socket | kprobe | kretprobe | classifier | action |\n" + " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n" + " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n" + " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n" + " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n" + " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n" + " cgroup/sendmsg4 | cgroup/sendmsg6 }\n" " " HELP_SPEC_OPTIONS "\n" "", bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], diff --git a/tools/bpf/bpftool/xlated_dumper.c b/tools/bpf/bpftool/xlated_dumper.c index b97f1da60dd1..3284759df98a 100644 --- a/tools/bpf/bpftool/xlated_dumper.c +++ b/tools/bpf/bpftool/xlated_dumper.c @@ -35,6 +35,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#define _GNU_SOURCE #include <stdarg.h> #include <stdio.h> #include <stdlib.h> @@ -66,9 +67,8 @@ void kernel_syms_load(struct dump_data *dd) while (!feof(fp)) { if (!fgets(buff, sizeof(buff), fp)) break; - tmp = realloc(dd->sym_mapping, - (dd->sym_count + 1) * - sizeof(*dd->sym_mapping)); + tmp = reallocarray(dd->sym_mapping, dd->sym_count + 1, + sizeof(*dd->sym_mapping)); if (!tmp) { out: free(dd->sym_mapping); diff --git a/tools/build/Build.include b/tools/build/Build.include index 950c1504ca37..9ec01f4454f9 100644 --- a/tools/build/Build.include +++ b/tools/build/Build.include @@ -98,4 +98,4 @@ cxx_flags = -Wp,-MD,$(depfile) -Wp,-MT,$@ $(CXXFLAGS) -D"BUILD_STR(s)=\#s" $(CXX ### ## HOSTCC C flags -host_c_flags = -Wp,-MD,$(depfile) -Wp,-MT,$@ $(HOSTCFLAGS) -D"BUILD_STR(s)=\#s" $(HOSTCFLAGS_$(basetarget).o) $(HOSTCFLAGS_$(obj)) +host_c_flags = -Wp,-MD,$(depfile) -Wp,-MT,$@ $(KBUILD_HOSTCFLAGS) -D"BUILD_STR(s)=\#s" $(HOSTCFLAGS_$(basetarget).o) $(HOSTCFLAGS_$(obj)) diff --git a/tools/build/Makefile b/tools/build/Makefile index 5edf65e684ab..727050c40f09 100644 --- a/tools/build/Makefile +++ b/tools/build/Makefile @@ -43,7 +43,7 @@ $(OUTPUT)fixdep-in.o: FORCE $(Q)$(MAKE) $(build)=fixdep $(OUTPUT)fixdep: $(OUTPUT)fixdep-in.o - $(QUIET_LINK)$(HOSTCC) $(HOSTLDFLAGS) -o $@ $< + $(QUIET_LINK)$(HOSTCC) $(KBUILD_HOSTLDFLAGS) -o $@ $< FORCE: diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature index 5b6dda3b1ca8..f216b2f5c3d7 100644 --- a/tools/build/Makefile.feature +++ b/tools/build/Makefile.feature @@ -57,6 +57,7 @@ FEATURE_TESTS_BASIC := \ libunwind-aarch64 \ pthread-attr-setaffinity-np \ pthread-barrier \ + reallocarray \ stackprotector-all \ timerfd \ libdw-dwarf-unwind \ diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile index dac9563b5470..0516259be70f 100644 --- a/tools/build/feature/Makefile +++ b/tools/build/feature/Makefile @@ -14,6 +14,7 @@ FILES= \ test-libaudit.bin \ test-libbfd.bin \ test-disassembler-four-args.bin \ + test-reallocarray.bin \ test-liberty.bin \ test-liberty-z.bin \ test-cplus-demangle.bin \ @@ -204,6 +205,9 @@ $(OUTPUT)test-libbfd.bin: $(OUTPUT)test-disassembler-four-args.bin: $(BUILD) -DPACKAGE='"perf"' -lbfd -lopcodes +$(OUTPUT)test-reallocarray.bin: + $(BUILD) + $(OUTPUT)test-liberty.bin: $(CC) $(CFLAGS) -Wall -Werror -o $@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty diff --git a/tools/build/feature/test-reallocarray.c b/tools/build/feature/test-reallocarray.c new file mode 100644 index 000000000000..8170de35150d --- /dev/null +++ b/tools/build/feature/test-reallocarray.c @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 +#define _GNU_SOURCE +#include <stdlib.h> + +int main(void) +{ + return !!reallocarray(NULL, 1, 1); +} diff --git a/tools/hv/hv_vss_daemon.c b/tools/hv/hv_vss_daemon.c index 34031a297f02..b13300172762 100644 --- a/tools/hv/hv_vss_daemon.c +++ b/tools/hv/hv_vss_daemon.c @@ -36,6 +36,8 @@ #include <linux/hyperv.h> #include <syslog.h> #include <getopt.h> +#include <stdbool.h> +#include <dirent.h> /* Don't use syslog() in the function since that can cause write to disk */ static int vss_do_freeze(char *dir, unsigned int cmd) @@ -68,6 +70,55 @@ static int vss_do_freeze(char *dir, unsigned int cmd) return !!ret; } +static bool is_dev_loop(const char *blkname) +{ + char *buffer; + DIR *dir; + struct dirent *entry; + bool ret = false; + + buffer = malloc(PATH_MAX); + if (!buffer) { + syslog(LOG_ERR, "Can't allocate memory!"); + exit(1); + } + + snprintf(buffer, PATH_MAX, "%s/loop", blkname); + if (!access(buffer, R_OK | X_OK)) { + ret = true; + goto free_buffer; + } else if (errno != ENOENT) { + syslog(LOG_ERR, "Can't access: %s; error:%d %s!", + buffer, errno, strerror(errno)); + } + + snprintf(buffer, PATH_MAX, "%s/slaves", blkname); + dir = opendir(buffer); + if (!dir) { + if (errno != ENOENT) + syslog(LOG_ERR, "Can't opendir: %s; error:%d %s!", + buffer, errno, strerror(errno)); + goto free_buffer; + } + + while ((entry = readdir(dir)) != NULL) { + if (strcmp(entry->d_name, ".") == 0 || + strcmp(entry->d_name, "..") == 0) + continue; + + snprintf(buffer, PATH_MAX, "%s/slaves/%s", blkname, + entry->d_name); + if (is_dev_loop(buffer)) { + ret = true; + break; + } + } + closedir(dir); +free_buffer: + free(buffer); + return ret; +} + static int vss_operate(int operation) { char match[] = "/dev/"; @@ -75,6 +126,7 @@ static int vss_operate(int operation) struct mntent *ent; struct stat sb; char errdir[1024] = {0}; + char blkdir[23]; /* /sys/dev/block/XXX:XXX */ unsigned int cmd; int error = 0, root_seen = 0, save_errno = 0; @@ -96,10 +148,15 @@ static int vss_operate(int operation) while ((ent = getmntent(mounts))) { if (strncmp(ent->mnt_fsname, match, strlen(match))) continue; - if (stat(ent->mnt_fsname, &sb) == -1) - continue; - if (S_ISBLK(sb.st_mode) && major(sb.st_rdev) == LOOP_MAJOR) - continue; + if (stat(ent->mnt_fsname, &sb)) { + syslog(LOG_ERR, "Can't stat: %s; error:%d %s!", + ent->mnt_fsname, errno, strerror(errno)); + } else { + sprintf(blkdir, "/sys/dev/block/%d:%d", + major(sb.st_rdev), minor(sb.st_rdev)); + if (is_dev_loop(blkdir)) + continue; + } if (hasmntopt(ent, MNTOPT_RO) != NULL) continue; if (strcmp(ent->mnt_type, "vfat") == 0) diff --git a/tools/hv/lsvmbus b/tools/hv/lsvmbus index 353e56768df8..55e7374bade0 100644 --- a/tools/hv/lsvmbus +++ b/tools/hv/lsvmbus @@ -17,7 +17,7 @@ if options.verbose is not None: vmbus_sys_path = '/sys/bus/vmbus/devices' if not os.path.isdir(vmbus_sys_path): - print "%s doesn't exist: exiting..." % vmbus_sys_path + print("%s doesn't exist: exiting..." % vmbus_sys_path) exit(-1) vmbus_dev_dict = { @@ -93,11 +93,11 @@ format2 = '%2s: Class_ID = %s - %s\n\tDevice_ID = %s\n\tSysfs path: %s\n%s' for d in vmbus_dev_list: if verbose == 0: - print ('VMBUS ID ' + format0) % (d.vmbus_id, d.dev_desc) + print(('VMBUS ID ' + format0) % (d.vmbus_id, d.dev_desc)) elif verbose == 1: - print ('VMBUS ID ' + format1) % \ - (d.vmbus_id, d.class_id, d.dev_desc, d.chn_vp_mapping) + print (('VMBUS ID ' + format1) % \ + (d.vmbus_id, d.class_id, d.dev_desc, d.chn_vp_mapping)) else: - print ('VMBUS ID ' + format2) % \ + print (('VMBUS ID ' + format2) % \ (d.vmbus_id, d.class_id, d.dev_desc, \ - d.device_id, d.sysfs_path, d.chn_vp_mapping) + d.device_id, d.sysfs_path, d.chn_vp_mapping)) diff --git a/tools/iio/iio_event_monitor.c b/tools/iio/iio_event_monitor.c index b61245e1181d..ac2de6b7e89f 100644 --- a/tools/iio/iio_event_monitor.c +++ b/tools/iio/iio_event_monitor.c @@ -58,6 +58,8 @@ static const char * const iio_chan_type_name_spec[] = { [IIO_PH] = "ph", [IIO_UVINDEX] = "uvindex", [IIO_GRAVITY] = "gravity", + [IIO_POSITIONRELATIVE] = "positionrelative", + [IIO_PHASE] = "phase", }; static const char * const iio_ev_type_text[] = { @@ -96,6 +98,7 @@ static const char * const iio_modifier_names[] = { [IIO_MOD_LIGHT_GREEN] = "green", [IIO_MOD_LIGHT_BLUE] = "blue", [IIO_MOD_LIGHT_UV] = "uv", + [IIO_MOD_LIGHT_DUV] = "duv", [IIO_MOD_QUATERNION] = "quaternion", [IIO_MOD_TEMP_AMBIENT] = "ambient", [IIO_MOD_TEMP_OBJECT] = "object", @@ -151,6 +154,8 @@ static bool event_is_known(struct iio_event_data *event) case IIO_PH: case IIO_UVINDEX: case IIO_GRAVITY: + case IIO_POSITIONRELATIVE: + case IIO_PHASE: break; default: return false; @@ -178,6 +183,7 @@ static bool event_is_known(struct iio_event_data *event) case IIO_MOD_LIGHT_GREEN: case IIO_MOD_LIGHT_BLUE: case IIO_MOD_LIGHT_UV: + case IIO_MOD_LIGHT_DUV: case IIO_MOD_QUATERNION: case IIO_MOD_TEMP_AMBIENT: case IIO_MOD_TEMP_OBJECT: diff --git a/tools/include/linux/bitmap.h b/tools/include/linux/bitmap.h index 63440cc8d618..e63662db131b 100644 --- a/tools/include/linux/bitmap.h +++ b/tools/include/linux/bitmap.h @@ -97,6 +97,23 @@ static inline int test_and_set_bit(int nr, unsigned long *addr) } /** + * test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to clear + * @addr: Address to count from + */ +static inline int test_and_clear_bit(int nr, unsigned long *addr) +{ + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + unsigned long old; + + old = *p; + *p = old & ~mask; + + return (old & mask) != 0; +} + +/** * bitmap_alloc - Allocate bitmap * @nbits: Number of bits */ diff --git a/tools/include/linux/compiler-gcc.h b/tools/include/linux/compiler-gcc.h index 70fe61295733..0d35f18006a1 100644 --- a/tools/include/linux/compiler-gcc.h +++ b/tools/include/linux/compiler-gcc.h @@ -36,3 +36,7 @@ #endif #define __printf(a, b) __attribute__((format(printf, a, b))) #define __scanf(a, b) __attribute__((format(scanf, a, b))) + +#if GCC_VERSION >= 50100 +#define COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW 1 +#endif diff --git a/tools/include/linux/overflow.h b/tools/include/linux/overflow.h new file mode 100644 index 000000000000..8712ff70995f --- /dev/null +++ b/tools/include/linux/overflow.h @@ -0,0 +1,278 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ +#ifndef __LINUX_OVERFLOW_H +#define __LINUX_OVERFLOW_H + +#include <linux/compiler.h> + +/* + * In the fallback code below, we need to compute the minimum and + * maximum values representable in a given type. These macros may also + * be useful elsewhere, so we provide them outside the + * COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW block. + * + * It would seem more obvious to do something like + * + * #define type_min(T) (T)(is_signed_type(T) ? (T)1 << (8*sizeof(T)-1) : 0) + * #define type_max(T) (T)(is_signed_type(T) ? ((T)1 << (8*sizeof(T)-1)) - 1 : ~(T)0) + * + * Unfortunately, the middle expressions, strictly speaking, have + * undefined behaviour, and at least some versions of gcc warn about + * the type_max expression (but not if -fsanitize=undefined is in + * effect; in that case, the warning is deferred to runtime...). + * + * The slightly excessive casting in type_min is to make sure the + * macros also produce sensible values for the exotic type _Bool. [The + * overflow checkers only almost work for _Bool, but that's + * a-feature-not-a-bug, since people shouldn't be doing arithmetic on + * _Bools. Besides, the gcc builtins don't allow _Bool* as third + * argument.] + * + * Idea stolen from + * https://mail-index.netbsd.org/tech-misc/2007/02/05/0000.html - + * credit to Christian Biere. + */ +#define is_signed_type(type) (((type)(-1)) < (type)1) +#define __type_half_max(type) ((type)1 << (8*sizeof(type) - 1 - is_signed_type(type))) +#define type_max(T) ((T)((__type_half_max(T) - 1) + __type_half_max(T))) +#define type_min(T) ((T)((T)-type_max(T)-(T)1)) + + +#ifdef COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW +/* + * For simplicity and code hygiene, the fallback code below insists on + * a, b and *d having the same type (similar to the min() and max() + * macros), whereas gcc's type-generic overflow checkers accept + * different types. Hence we don't just make check_add_overflow an + * alias for __builtin_add_overflow, but add type checks similar to + * below. + */ +#define check_add_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + __builtin_add_overflow(__a, __b, __d); \ +}) + +#define check_sub_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + __builtin_sub_overflow(__a, __b, __d); \ +}) + +#define check_mul_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + __builtin_mul_overflow(__a, __b, __d); \ +}) + +#else + + +/* Checking for unsigned overflow is relatively easy without causing UB. */ +#define __unsigned_add_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + *__d = __a + __b; \ + *__d < __a; \ +}) +#define __unsigned_sub_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + *__d = __a - __b; \ + __a < __b; \ +}) +/* + * If one of a or b is a compile-time constant, this avoids a division. + */ +#define __unsigned_mul_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + *__d = __a * __b; \ + __builtin_constant_p(__b) ? \ + __b > 0 && __a > type_max(typeof(__a)) / __b : \ + __a > 0 && __b > type_max(typeof(__b)) / __a; \ +}) + +/* + * For signed types, detecting overflow is much harder, especially if + * we want to avoid UB. But the interface of these macros is such that + * we must provide a result in *d, and in fact we must produce the + * result promised by gcc's builtins, which is simply the possibly + * wrapped-around value. Fortunately, we can just formally do the + * operations in the widest relevant unsigned type (u64) and then + * truncate the result - gcc is smart enough to generate the same code + * with and without the (u64) casts. + */ + +/* + * Adding two signed integers can overflow only if they have the same + * sign, and overflow has happened iff the result has the opposite + * sign. + */ +#define __signed_add_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + *__d = (u64)__a + (u64)__b; \ + (((~(__a ^ __b)) & (*__d ^ __a)) \ + & type_min(typeof(__a))) != 0; \ +}) + +/* + * Subtraction is similar, except that overflow can now happen only + * when the signs are opposite. In this case, overflow has happened if + * the result has the opposite sign of a. + */ +#define __signed_sub_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + *__d = (u64)__a - (u64)__b; \ + ((((__a ^ __b)) & (*__d ^ __a)) \ + & type_min(typeof(__a))) != 0; \ +}) + +/* + * Signed multiplication is rather hard. gcc always follows C99, so + * division is truncated towards 0. This means that we can write the + * overflow check like this: + * + * (a > 0 && (b > MAX/a || b < MIN/a)) || + * (a < -1 && (b > MIN/a || b < MAX/a) || + * (a == -1 && b == MIN) + * + * The redundant casts of -1 are to silence an annoying -Wtype-limits + * (included in -Wextra) warning: When the type is u8 or u16, the + * __b_c_e in check_mul_overflow obviously selects + * __unsigned_mul_overflow, but unfortunately gcc still parses this + * code and warns about the limited range of __b. + */ + +#define __signed_mul_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + typeof(a) __tmax = type_max(typeof(a)); \ + typeof(a) __tmin = type_min(typeof(a)); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + *__d = (u64)__a * (u64)__b; \ + (__b > 0 && (__a > __tmax/__b || __a < __tmin/__b)) || \ + (__b < (typeof(__b))-1 && (__a > __tmin/__b || __a < __tmax/__b)) || \ + (__b == (typeof(__b))-1 && __a == __tmin); \ +}) + + +#define check_add_overflow(a, b, d) \ + __builtin_choose_expr(is_signed_type(typeof(a)), \ + __signed_add_overflow(a, b, d), \ + __unsigned_add_overflow(a, b, d)) + +#define check_sub_overflow(a, b, d) \ + __builtin_choose_expr(is_signed_type(typeof(a)), \ + __signed_sub_overflow(a, b, d), \ + __unsigned_sub_overflow(a, b, d)) + +#define check_mul_overflow(a, b, d) \ + __builtin_choose_expr(is_signed_type(typeof(a)), \ + __signed_mul_overflow(a, b, d), \ + __unsigned_mul_overflow(a, b, d)) + + +#endif /* COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW */ + +/** + * array_size() - Calculate size of 2-dimensional array. + * + * @a: dimension one + * @b: dimension two + * + * Calculates size of 2-dimensional array: @a * @b. + * + * Returns: number of bytes needed to represent the array or SIZE_MAX on + * overflow. + */ +static inline __must_check size_t array_size(size_t a, size_t b) +{ + size_t bytes; + + if (check_mul_overflow(a, b, &bytes)) + return SIZE_MAX; + + return bytes; +} + +/** + * array3_size() - Calculate size of 3-dimensional array. + * + * @a: dimension one + * @b: dimension two + * @c: dimension three + * + * Calculates size of 3-dimensional array: @a * @b * @c. + * + * Returns: number of bytes needed to represent the array or SIZE_MAX on + * overflow. + */ +static inline __must_check size_t array3_size(size_t a, size_t b, size_t c) +{ + size_t bytes; + + if (check_mul_overflow(a, b, &bytes)) + return SIZE_MAX; + if (check_mul_overflow(bytes, c, &bytes)) + return SIZE_MAX; + + return bytes; +} + +static inline __must_check size_t __ab_c_size(size_t n, size_t size, size_t c) +{ + size_t bytes; + + if (check_mul_overflow(n, size, &bytes)) + return SIZE_MAX; + if (check_add_overflow(bytes, c, &bytes)) + return SIZE_MAX; + + return bytes; +} + +/** + * struct_size() - Calculate size of structure with trailing array. + * @p: Pointer to the structure. + * @member: Name of the array member. + * @n: Number of elements in the array. + * + * Calculates size of memory needed for structure @p followed by an + * array of @n @member elements. + * + * Return: number of bytes needed or SIZE_MAX on overflow. + */ +#define struct_size(p, member, n) \ + __ab_c_size(n, \ + sizeof(*(p)->member) + __must_be_array((p)->member),\ + sizeof(*(p))) + +#endif /* __LINUX_OVERFLOW_H */ diff --git a/tools/include/tools/libc_compat.h b/tools/include/tools/libc_compat.h new file mode 100644 index 000000000000..664ced8cb1b0 --- /dev/null +++ b/tools/include/tools/libc_compat.h @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (C) 2018 Netronome Systems, Inc. */ + +#ifndef __TOOLS_LIBC_COMPAT_H +#define __TOOLS_LIBC_COMPAT_H + +#include <stdlib.h> +#include <linux/overflow.h> + +#ifdef COMPAT_NEED_REALLOCARRAY +static inline void *reallocarray(void *ptr, size_t nmemb, size_t size) +{ + size_t bytes; + + if (unlikely(check_mul_overflow(nmemb, size, &bytes))) + return NULL; + return realloc(ptr, bytes); +} +#endif +#endif diff --git a/tools/include/uapi/asm-generic/unistd.h b/tools/include/uapi/asm-generic/unistd.h new file mode 100644 index 000000000000..42990676a55e --- /dev/null +++ b/tools/include/uapi/asm-generic/unistd.h @@ -0,0 +1,783 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#include <asm/bitsperlong.h> + +/* + * This file contains the system call numbers, based on the + * layout of the x86-64 architecture, which embeds the + * pointer to the syscall in the table. + * + * As a basic principle, no duplication of functionality + * should be added, e.g. we don't use lseek when llseek + * is present. New architectures should use this file + * and implement the less feature-full calls in user space. + */ + +#ifndef __SYSCALL +#define __SYSCALL(x, y) +#endif + +#if __BITS_PER_LONG == 32 || defined(__SYSCALL_COMPAT) +#define __SC_3264(_nr, _32, _64) __SYSCALL(_nr, _32) +#else +#define __SC_3264(_nr, _32, _64) __SYSCALL(_nr, _64) +#endif + +#ifdef __SYSCALL_COMPAT +#define __SC_COMP(_nr, _sys, _comp) __SYSCALL(_nr, _comp) +#define __SC_COMP_3264(_nr, _32, _64, _comp) __SYSCALL(_nr, _comp) +#else +#define __SC_COMP(_nr, _sys, _comp) __SYSCALL(_nr, _sys) +#define __SC_COMP_3264(_nr, _32, _64, _comp) __SC_3264(_nr, _32, _64) +#endif + +#define __NR_io_setup 0 +__SC_COMP(__NR_io_setup, sys_io_setup, compat_sys_io_setup) +#define __NR_io_destroy 1 +__SYSCALL(__NR_io_destroy, sys_io_destroy) +#define __NR_io_submit 2 +__SC_COMP(__NR_io_submit, sys_io_submit, compat_sys_io_submit) +#define __NR_io_cancel 3 +__SYSCALL(__NR_io_cancel, sys_io_cancel) +#define __NR_io_getevents 4 +__SC_COMP(__NR_io_getevents, sys_io_getevents, compat_sys_io_getevents) + +/* fs/xattr.c */ +#define __NR_setxattr 5 +__SYSCALL(__NR_setxattr, sys_setxattr) +#define __NR_lsetxattr 6 +__SYSCALL(__NR_lsetxattr, sys_lsetxattr) +#define __NR_fsetxattr 7 +__SYSCALL(__NR_fsetxattr, sys_fsetxattr) +#define __NR_getxattr 8 +__SYSCALL(__NR_getxattr, sys_getxattr) +#define __NR_lgetxattr 9 +__SYSCALL(__NR_lgetxattr, sys_lgetxattr) +#define __NR_fgetxattr 10 +__SYSCALL(__NR_fgetxattr, sys_fgetxattr) +#define __NR_listxattr 11 +__SYSCALL(__NR_listxattr, sys_listxattr) +#define __NR_llistxattr 12 +__SYSCALL(__NR_llistxattr, sys_llistxattr) +#define __NR_flistxattr 13 +__SYSCALL(__NR_flistxattr, sys_flistxattr) +#define __NR_removexattr 14 +__SYSCALL(__NR_removexattr, sys_removexattr) +#define __NR_lremovexattr 15 +__SYSCALL(__NR_lremovexattr, sys_lremovexattr) +#define __NR_fremovexattr 16 +__SYSCALL(__NR_fremovexattr, sys_fremovexattr) + +/* fs/dcache.c */ +#define __NR_getcwd 17 +__SYSCALL(__NR_getcwd, sys_getcwd) + +/* fs/cookies.c */ +#define __NR_lookup_dcookie 18 +__SC_COMP(__NR_lookup_dcookie, sys_lookup_dcookie, compat_sys_lookup_dcookie) + +/* fs/eventfd.c */ +#define __NR_eventfd2 19 +__SYSCALL(__NR_eventfd2, sys_eventfd2) + +/* fs/eventpoll.c */ +#define __NR_epoll_create1 20 +__SYSCALL(__NR_epoll_create1, sys_epoll_create1) +#define __NR_epoll_ctl 21 +__SYSCALL(__NR_epoll_ctl, sys_epoll_ctl) +#define __NR_epoll_pwait 22 +__SC_COMP(__NR_epoll_pwait, sys_epoll_pwait, compat_sys_epoll_pwait) + +/* fs/fcntl.c */ +#define __NR_dup 23 +__SYSCALL(__NR_dup, sys_dup) +#define __NR_dup3 24 +__SYSCALL(__NR_dup3, sys_dup3) +#define __NR3264_fcntl 25 +__SC_COMP_3264(__NR3264_fcntl, sys_fcntl64, sys_fcntl, compat_sys_fcntl64) + +/* fs/inotify_user.c */ +#define __NR_inotify_init1 26 +__SYSCALL(__NR_inotify_init1, sys_inotify_init1) +#define __NR_inotify_add_watch 27 +__SYSCALL(__NR_inotify_add_watch, sys_inotify_add_watch) +#define __NR_inotify_rm_watch 28 +__SYSCALL(__NR_inotify_rm_watch, sys_inotify_rm_watch) + +/* fs/ioctl.c */ +#define __NR_ioctl 29 +__SC_COMP(__NR_ioctl, sys_ioctl, compat_sys_ioctl) + +/* fs/ioprio.c */ +#define __NR_ioprio_set 30 +__SYSCALL(__NR_ioprio_set, sys_ioprio_set) +#define __NR_ioprio_get 31 +__SYSCALL(__NR_ioprio_get, sys_ioprio_get) + +/* fs/locks.c */ +#define __NR_flock 32 +__SYSCALL(__NR_flock, sys_flock) + +/* fs/namei.c */ +#define __NR_mknodat 33 +__SYSCALL(__NR_mknodat, sys_mknodat) +#define __NR_mkdirat 34 +__SYSCALL(__NR_mkdirat, sys_mkdirat) +#define __NR_unlinkat 35 +__SYSCALL(__NR_unlinkat, sys_unlinkat) +#define __NR_symlinkat 36 +__SYSCALL(__NR_symlinkat, sys_symlinkat) +#define __NR_linkat 37 +__SYSCALL(__NR_linkat, sys_linkat) +#ifdef __ARCH_WANT_RENAMEAT +/* renameat is superseded with flags by renameat2 */ +#define __NR_renameat 38 +__SYSCALL(__NR_renameat, sys_renameat) +#endif /* __ARCH_WANT_RENAMEAT */ + +/* fs/namespace.c */ +#define __NR_umount2 39 +__SYSCALL(__NR_umount2, sys_umount) +#define __NR_mount 40 +__SC_COMP(__NR_mount, sys_mount, compat_sys_mount) +#define __NR_pivot_root 41 +__SYSCALL(__NR_pivot_root, sys_pivot_root) + +/* fs/nfsctl.c */ +#define __NR_nfsservctl 42 +__SYSCALL(__NR_nfsservctl, sys_ni_syscall) + +/* fs/open.c */ +#define __NR3264_statfs 43 +__SC_COMP_3264(__NR3264_statfs, sys_statfs64, sys_statfs, \ + compat_sys_statfs64) +#define __NR3264_fstatfs 44 +__SC_COMP_3264(__NR3264_fstatfs, sys_fstatfs64, sys_fstatfs, \ + compat_sys_fstatfs64) +#define __NR3264_truncate 45 +__SC_COMP_3264(__NR3264_truncate, sys_truncate64, sys_truncate, \ + compat_sys_truncate64) +#define __NR3264_ftruncate 46 +__SC_COMP_3264(__NR3264_ftruncate, sys_ftruncate64, sys_ftruncate, \ + compat_sys_ftruncate64) + +#define __NR_fallocate 47 +__SC_COMP(__NR_fallocate, sys_fallocate, compat_sys_fallocate) +#define __NR_faccessat 48 +__SYSCALL(__NR_faccessat, sys_faccessat) +#define __NR_chdir 49 +__SYSCALL(__NR_chdir, sys_chdir) +#define __NR_fchdir 50 +__SYSCALL(__NR_fchdir, sys_fchdir) +#define __NR_chroot 51 +__SYSCALL(__NR_chroot, sys_chroot) +#define __NR_fchmod 52 +__SYSCALL(__NR_fchmod, sys_fchmod) +#define __NR_fchmodat 53 +__SYSCALL(__NR_fchmodat, sys_fchmodat) +#define __NR_fchownat 54 +__SYSCALL(__NR_fchownat, sys_fchownat) +#define __NR_fchown 55 +__SYSCALL(__NR_fchown, sys_fchown) +#define __NR_openat 56 +__SC_COMP(__NR_openat, sys_openat, compat_sys_openat) +#define __NR_close 57 +__SYSCALL(__NR_close, sys_close) +#define __NR_vhangup 58 +__SYSCALL(__NR_vhangup, sys_vhangup) + +/* fs/pipe.c */ +#define __NR_pipe2 59 +__SYSCALL(__NR_pipe2, sys_pipe2) + +/* fs/quota.c */ +#define __NR_quotactl 60 +__SYSCALL(__NR_quotactl, sys_quotactl) + +/* fs/readdir.c */ +#define __NR_getdents64 61 +__SYSCALL(__NR_getdents64, sys_getdents64) + +/* fs/read_write.c */ +#define __NR3264_lseek 62 +__SC_3264(__NR3264_lseek, sys_llseek, sys_lseek) +#define __NR_read 63 +__SYSCALL(__NR_read, sys_read) +#define __NR_write 64 +__SYSCALL(__NR_write, sys_write) +#define __NR_readv 65 +__SC_COMP(__NR_readv, sys_readv, compat_sys_readv) +#define __NR_writev 66 +__SC_COMP(__NR_writev, sys_writev, compat_sys_writev) +#define __NR_pread64 67 +__SC_COMP(__NR_pread64, sys_pread64, compat_sys_pread64) +#define __NR_pwrite64 68 +__SC_COMP(__NR_pwrite64, sys_pwrite64, compat_sys_pwrite64) +#define __NR_preadv 69 +__SC_COMP(__NR_preadv, sys_preadv, compat_sys_preadv) +#define __NR_pwritev 70 +__SC_COMP(__NR_pwritev, sys_pwritev, compat_sys_pwritev) + +/* fs/sendfile.c */ +#define __NR3264_sendfile 71 +__SYSCALL(__NR3264_sendfile, sys_sendfile64) + +/* fs/select.c */ +#define __NR_pselect6 72 +__SC_COMP(__NR_pselect6, sys_pselect6, compat_sys_pselect6) +#define __NR_ppoll 73 +__SC_COMP(__NR_ppoll, sys_ppoll, compat_sys_ppoll) + +/* fs/signalfd.c */ +#define __NR_signalfd4 74 +__SC_COMP(__NR_signalfd4, sys_signalfd4, compat_sys_signalfd4) + +/* fs/splice.c */ +#define __NR_vmsplice 75 +__SC_COMP(__NR_vmsplice, sys_vmsplice, compat_sys_vmsplice) +#define __NR_splice 76 +__SYSCALL(__NR_splice, sys_splice) +#define __NR_tee 77 +__SYSCALL(__NR_tee, sys_tee) + +/* fs/stat.c */ +#define __NR_readlinkat 78 +__SYSCALL(__NR_readlinkat, sys_readlinkat) +#define __NR3264_fstatat 79 +__SC_3264(__NR3264_fstatat, sys_fstatat64, sys_newfstatat) +#define __NR3264_fstat 80 +__SC_3264(__NR3264_fstat, sys_fstat64, sys_newfstat) + +/* fs/sync.c */ +#define __NR_sync 81 +__SYSCALL(__NR_sync, sys_sync) +#define __NR_fsync 82 +__SYSCALL(__NR_fsync, sys_fsync) +#define __NR_fdatasync 83 +__SYSCALL(__NR_fdatasync, sys_fdatasync) +#ifdef __ARCH_WANT_SYNC_FILE_RANGE2 +#define __NR_sync_file_range2 84 +__SC_COMP(__NR_sync_file_range2, sys_sync_file_range2, \ + compat_sys_sync_file_range2) +#else +#define __NR_sync_file_range 84 +__SC_COMP(__NR_sync_file_range, sys_sync_file_range, \ + compat_sys_sync_file_range) +#endif + +/* fs/timerfd.c */ +#define __NR_timerfd_create 85 +__SYSCALL(__NR_timerfd_create, sys_timerfd_create) +#define __NR_timerfd_settime 86 +__SC_COMP(__NR_timerfd_settime, sys_timerfd_settime, \ + compat_sys_timerfd_settime) +#define __NR_timerfd_gettime 87 +__SC_COMP(__NR_timerfd_gettime, sys_timerfd_gettime, \ + compat_sys_timerfd_gettime) + +/* fs/utimes.c */ +#define __NR_utimensat 88 +__SC_COMP(__NR_utimensat, sys_utimensat, compat_sys_utimensat) + +/* kernel/acct.c */ +#define __NR_acct 89 +__SYSCALL(__NR_acct, sys_acct) + +/* kernel/capability.c */ +#define __NR_capget 90 +__SYSCALL(__NR_capget, sys_capget) +#define __NR_capset 91 +__SYSCALL(__NR_capset, sys_capset) + +/* kernel/exec_domain.c */ +#define __NR_personality 92 +__SYSCALL(__NR_personality, sys_personality) + +/* kernel/exit.c */ +#define __NR_exit 93 +__SYSCALL(__NR_exit, sys_exit) +#define __NR_exit_group 94 +__SYSCALL(__NR_exit_group, sys_exit_group) +#define __NR_waitid 95 +__SC_COMP(__NR_waitid, sys_waitid, compat_sys_waitid) + +/* kernel/fork.c */ +#define __NR_set_tid_address 96 +__SYSCALL(__NR_set_tid_address, sys_set_tid_address) +#define __NR_unshare 97 +__SYSCALL(__NR_unshare, sys_unshare) + +/* kernel/futex.c */ +#define __NR_futex 98 +__SC_COMP(__NR_futex, sys_futex, compat_sys_futex) +#define __NR_set_robust_list 99 +__SC_COMP(__NR_set_robust_list, sys_set_robust_list, \ + compat_sys_set_robust_list) +#define __NR_get_robust_list 100 +__SC_COMP(__NR_get_robust_list, sys_get_robust_list, \ + compat_sys_get_robust_list) + +/* kernel/hrtimer.c */ +#define __NR_nanosleep 101 +__SC_COMP(__NR_nanosleep, sys_nanosleep, compat_sys_nanosleep) + +/* kernel/itimer.c */ +#define __NR_getitimer 102 +__SC_COMP(__NR_getitimer, sys_getitimer, compat_sys_getitimer) +#define __NR_setitimer 103 +__SC_COMP(__NR_setitimer, sys_setitimer, compat_sys_setitimer) + +/* kernel/kexec.c */ +#define __NR_kexec_load 104 +__SC_COMP(__NR_kexec_load, sys_kexec_load, compat_sys_kexec_load) + +/* kernel/module.c */ +#define __NR_init_module 105 +__SYSCALL(__NR_init_module, sys_init_module) +#define __NR_delete_module 106 +__SYSCALL(__NR_delete_module, sys_delete_module) + +/* kernel/posix-timers.c */ +#define __NR_timer_create 107 +__SC_COMP(__NR_timer_create, sys_timer_create, compat_sys_timer_create) +#define __NR_timer_gettime 108 +__SC_COMP(__NR_timer_gettime, sys_timer_gettime, compat_sys_timer_gettime) +#define __NR_timer_getoverrun 109 +__SYSCALL(__NR_timer_getoverrun, sys_timer_getoverrun) +#define __NR_timer_settime 110 +__SC_COMP(__NR_timer_settime, sys_timer_settime, compat_sys_timer_settime) +#define __NR_timer_delete 111 +__SYSCALL(__NR_timer_delete, sys_timer_delete) +#define __NR_clock_settime 112 +__SC_COMP(__NR_clock_settime, sys_clock_settime, compat_sys_clock_settime) +#define __NR_clock_gettime 113 +__SC_COMP(__NR_clock_gettime, sys_clock_gettime, compat_sys_clock_gettime) +#define __NR_clock_getres 114 +__SC_COMP(__NR_clock_getres, sys_clock_getres, compat_sys_clock_getres) +#define __NR_clock_nanosleep 115 +__SC_COMP(__NR_clock_nanosleep, sys_clock_nanosleep, \ + compat_sys_clock_nanosleep) + +/* kernel/printk.c */ +#define __NR_syslog 116 +__SYSCALL(__NR_syslog, sys_syslog) + +/* kernel/ptrace.c */ +#define __NR_ptrace 117 +__SYSCALL(__NR_ptrace, sys_ptrace) + +/* kernel/sched/core.c */ +#define __NR_sched_setparam 118 +__SYSCALL(__NR_sched_setparam, sys_sched_setparam) +#define __NR_sched_setscheduler 119 +__SYSCALL(__NR_sched_setscheduler, sys_sched_setscheduler) +#define __NR_sched_getscheduler 120 +__SYSCALL(__NR_sched_getscheduler, sys_sched_getscheduler) +#define __NR_sched_getparam 121 +__SYSCALL(__NR_sched_getparam, sys_sched_getparam) +#define __NR_sched_setaffinity 122 +__SC_COMP(__NR_sched_setaffinity, sys_sched_setaffinity, \ + compat_sys_sched_setaffinity) +#define __NR_sched_getaffinity 123 +__SC_COMP(__NR_sched_getaffinity, sys_sched_getaffinity, \ + compat_sys_sched_getaffinity) +#define __NR_sched_yield 124 +__SYSCALL(__NR_sched_yield, sys_sched_yield) +#define __NR_sched_get_priority_max 125 +__SYSCALL(__NR_sched_get_priority_max, sys_sched_get_priority_max) +#define __NR_sched_get_priority_min 126 +__SYSCALL(__NR_sched_get_priority_min, sys_sched_get_priority_min) +#define __NR_sched_rr_get_interval 127 +__SC_COMP(__NR_sched_rr_get_interval, sys_sched_rr_get_interval, \ + compat_sys_sched_rr_get_interval) + +/* kernel/signal.c */ +#define __NR_restart_syscall 128 +__SYSCALL(__NR_restart_syscall, sys_restart_syscall) +#define __NR_kill 129 +__SYSCALL(__NR_kill, sys_kill) +#define __NR_tkill 130 +__SYSCALL(__NR_tkill, sys_tkill) +#define __NR_tgkill 131 +__SYSCALL(__NR_tgkill, sys_tgkill) +#define __NR_sigaltstack 132 +__SC_COMP(__NR_sigaltstack, sys_sigaltstack, compat_sys_sigaltstack) +#define __NR_rt_sigsuspend 133 +__SC_COMP(__NR_rt_sigsuspend, sys_rt_sigsuspend, compat_sys_rt_sigsuspend) +#define __NR_rt_sigaction 134 +__SC_COMP(__NR_rt_sigaction, sys_rt_sigaction, compat_sys_rt_sigaction) +#define __NR_rt_sigprocmask 135 +__SC_COMP(__NR_rt_sigprocmask, sys_rt_sigprocmask, compat_sys_rt_sigprocmask) +#define __NR_rt_sigpending 136 +__SC_COMP(__NR_rt_sigpending, sys_rt_sigpending, compat_sys_rt_sigpending) +#define __NR_rt_sigtimedwait 137 +__SC_COMP(__NR_rt_sigtimedwait, sys_rt_sigtimedwait, \ + compat_sys_rt_sigtimedwait) +#define __NR_rt_sigqueueinfo 138 +__SC_COMP(__NR_rt_sigqueueinfo, sys_rt_sigqueueinfo, \ + compat_sys_rt_sigqueueinfo) +#define __NR_rt_sigreturn 139 +__SC_COMP(__NR_rt_sigreturn, sys_rt_sigreturn, compat_sys_rt_sigreturn) + +/* kernel/sys.c */ +#define __NR_setpriority 140 +__SYSCALL(__NR_setpriority, sys_setpriority) +#define __NR_getpriority 141 +__SYSCALL(__NR_getpriority, sys_getpriority) +#define __NR_reboot 142 +__SYSCALL(__NR_reboot, sys_reboot) +#define __NR_setregid 143 +__SYSCALL(__NR_setregid, sys_setregid) +#define __NR_setgid 144 +__SYSCALL(__NR_setgid, sys_setgid) +#define __NR_setreuid 145 +__SYSCALL(__NR_setreuid, sys_setreuid) +#define __NR_setuid 146 +__SYSCALL(__NR_setuid, sys_setuid) +#define __NR_setresuid 147 +__SYSCALL(__NR_setresuid, sys_setresuid) +#define __NR_getresuid 148 +__SYSCALL(__NR_getresuid, sys_getresuid) +#define __NR_setresgid 149 +__SYSCALL(__NR_setresgid, sys_setresgid) +#define __NR_getresgid 150 +__SYSCALL(__NR_getresgid, sys_getresgid) +#define __NR_setfsuid 151 +__SYSCALL(__NR_setfsuid, sys_setfsuid) +#define __NR_setfsgid 152 +__SYSCALL(__NR_setfsgid, sys_setfsgid) +#define __NR_times 153 +__SC_COMP(__NR_times, sys_times, compat_sys_times) +#define __NR_setpgid 154 +__SYSCALL(__NR_setpgid, sys_setpgid) +#define __NR_getpgid 155 +__SYSCALL(__NR_getpgid, sys_getpgid) +#define __NR_getsid 156 +__SYSCALL(__NR_getsid, sys_getsid) +#define __NR_setsid 157 +__SYSCALL(__NR_setsid, sys_setsid) +#define __NR_getgroups 158 +__SYSCALL(__NR_getgroups, sys_getgroups) +#define __NR_setgroups 159 +__SYSCALL(__NR_setgroups, sys_setgroups) +#define __NR_uname 160 +__SYSCALL(__NR_uname, sys_newuname) +#define __NR_sethostname 161 +__SYSCALL(__NR_sethostname, sys_sethostname) +#define __NR_setdomainname 162 +__SYSCALL(__NR_setdomainname, sys_setdomainname) +#define __NR_getrlimit 163 +__SC_COMP(__NR_getrlimit, sys_getrlimit, compat_sys_getrlimit) +#define __NR_setrlimit 164 +__SC_COMP(__NR_setrlimit, sys_setrlimit, compat_sys_setrlimit) +#define __NR_getrusage 165 +__SC_COMP(__NR_getrusage, sys_getrusage, compat_sys_getrusage) +#define __NR_umask 166 +__SYSCALL(__NR_umask, sys_umask) +#define __NR_prctl 167 +__SYSCALL(__NR_prctl, sys_prctl) +#define __NR_getcpu 168 +__SYSCALL(__NR_getcpu, sys_getcpu) + +/* kernel/time.c */ +#define __NR_gettimeofday 169 +__SC_COMP(__NR_gettimeofday, sys_gettimeofday, compat_sys_gettimeofday) +#define __NR_settimeofday 170 +__SC_COMP(__NR_settimeofday, sys_settimeofday, compat_sys_settimeofday) +#define __NR_adjtimex 171 +__SC_COMP(__NR_adjtimex, sys_adjtimex, compat_sys_adjtimex) + +/* kernel/timer.c */ +#define __NR_getpid 172 +__SYSCALL(__NR_getpid, sys_getpid) +#define __NR_getppid 173 +__SYSCALL(__NR_getppid, sys_getppid) +#define __NR_getuid 174 +__SYSCALL(__NR_getuid, sys_getuid) +#define __NR_geteuid 175 +__SYSCALL(__NR_geteuid, sys_geteuid) +#define __NR_getgid 176 +__SYSCALL(__NR_getgid, sys_getgid) +#define __NR_getegid 177 +__SYSCALL(__NR_getegid, sys_getegid) +#define __NR_gettid 178 +__SYSCALL(__NR_gettid, sys_gettid) +#define __NR_sysinfo 179 +__SC_COMP(__NR_sysinfo, sys_sysinfo, compat_sys_sysinfo) + +/* ipc/mqueue.c */ +#define __NR_mq_open 180 +__SC_COMP(__NR_mq_open, sys_mq_open, compat_sys_mq_open) +#define __NR_mq_unlink 181 +__SYSCALL(__NR_mq_unlink, sys_mq_unlink) +#define __NR_mq_timedsend 182 +__SC_COMP(__NR_mq_timedsend, sys_mq_timedsend, compat_sys_mq_timedsend) +#define __NR_mq_timedreceive 183 +__SC_COMP(__NR_mq_timedreceive, sys_mq_timedreceive, \ + compat_sys_mq_timedreceive) +#define __NR_mq_notify 184 +__SC_COMP(__NR_mq_notify, sys_mq_notify, compat_sys_mq_notify) +#define __NR_mq_getsetattr 185 +__SC_COMP(__NR_mq_getsetattr, sys_mq_getsetattr, compat_sys_mq_getsetattr) + +/* ipc/msg.c */ +#define __NR_msgget 186 +__SYSCALL(__NR_msgget, sys_msgget) +#define __NR_msgctl 187 +__SC_COMP(__NR_msgctl, sys_msgctl, compat_sys_msgctl) +#define __NR_msgrcv 188 +__SC_COMP(__NR_msgrcv, sys_msgrcv, compat_sys_msgrcv) +#define __NR_msgsnd 189 +__SC_COMP(__NR_msgsnd, sys_msgsnd, compat_sys_msgsnd) + +/* ipc/sem.c */ +#define __NR_semget 190 +__SYSCALL(__NR_semget, sys_semget) +#define __NR_semctl 191 +__SC_COMP(__NR_semctl, sys_semctl, compat_sys_semctl) +#define __NR_semtimedop 192 +__SC_COMP(__NR_semtimedop, sys_semtimedop, compat_sys_semtimedop) +#define __NR_semop 193 +__SYSCALL(__NR_semop, sys_semop) + +/* ipc/shm.c */ +#define __NR_shmget 194 +__SYSCALL(__NR_shmget, sys_shmget) +#define __NR_shmctl 195 +__SC_COMP(__NR_shmctl, sys_shmctl, compat_sys_shmctl) +#define __NR_shmat 196 +__SC_COMP(__NR_shmat, sys_shmat, compat_sys_shmat) +#define __NR_shmdt 197 +__SYSCALL(__NR_shmdt, sys_shmdt) + +/* net/socket.c */ +#define __NR_socket 198 +__SYSCALL(__NR_socket, sys_socket) +#define __NR_socketpair 199 +__SYSCALL(__NR_socketpair, sys_socketpair) +#define __NR_bind 200 +__SYSCALL(__NR_bind, sys_bind) +#define __NR_listen 201 +__SYSCALL(__NR_listen, sys_listen) +#define __NR_accept 202 +__SYSCALL(__NR_accept, sys_accept) +#define __NR_connect 203 +__SYSCALL(__NR_connect, sys_connect) +#define __NR_getsockname 204 +__SYSCALL(__NR_getsockname, sys_getsockname) +#define __NR_getpeername 205 +__SYSCALL(__NR_getpeername, sys_getpeername) +#define __NR_sendto 206 +__SYSCALL(__NR_sendto, sys_sendto) +#define __NR_recvfrom 207 +__SC_COMP(__NR_recvfrom, sys_recvfrom, compat_sys_recvfrom) +#define __NR_setsockopt 208 +__SC_COMP(__NR_setsockopt, sys_setsockopt, compat_sys_setsockopt) +#define __NR_getsockopt 209 +__SC_COMP(__NR_getsockopt, sys_getsockopt, compat_sys_getsockopt) +#define __NR_shutdown 210 +__SYSCALL(__NR_shutdown, sys_shutdown) +#define __NR_sendmsg 211 +__SC_COMP(__NR_sendmsg, sys_sendmsg, compat_sys_sendmsg) +#define __NR_recvmsg 212 +__SC_COMP(__NR_recvmsg, sys_recvmsg, compat_sys_recvmsg) + +/* mm/filemap.c */ +#define __NR_readahead 213 +__SC_COMP(__NR_readahead, sys_readahead, compat_sys_readahead) + +/* mm/nommu.c, also with MMU */ +#define __NR_brk 214 +__SYSCALL(__NR_brk, sys_brk) +#define __NR_munmap 215 +__SYSCALL(__NR_munmap, sys_munmap) +#define __NR_mremap 216 +__SYSCALL(__NR_mremap, sys_mremap) + +/* security/keys/keyctl.c */ +#define __NR_add_key 217 +__SYSCALL(__NR_add_key, sys_add_key) +#define __NR_request_key 218 +__SYSCALL(__NR_request_key, sys_request_key) +#define __NR_keyctl 219 +__SC_COMP(__NR_keyctl, sys_keyctl, compat_sys_keyctl) + +/* arch/example/kernel/sys_example.c */ +#define __NR_clone 220 +__SYSCALL(__NR_clone, sys_clone) +#define __NR_execve 221 +__SC_COMP(__NR_execve, sys_execve, compat_sys_execve) + +#define __NR3264_mmap 222 +__SC_3264(__NR3264_mmap, sys_mmap2, sys_mmap) +/* mm/fadvise.c */ +#define __NR3264_fadvise64 223 +__SC_COMP(__NR3264_fadvise64, sys_fadvise64_64, compat_sys_fadvise64_64) + +/* mm/, CONFIG_MMU only */ +#ifndef __ARCH_NOMMU +#define __NR_swapon 224 +__SYSCALL(__NR_swapon, sys_swapon) +#define __NR_swapoff 225 +__SYSCALL(__NR_swapoff, sys_swapoff) +#define __NR_mprotect 226 +__SYSCALL(__NR_mprotect, sys_mprotect) +#define __NR_msync 227 +__SYSCALL(__NR_msync, sys_msync) +#define __NR_mlock 228 +__SYSCALL(__NR_mlock, sys_mlock) +#define __NR_munlock 229 +__SYSCALL(__NR_munlock, sys_munlock) +#define __NR_mlockall 230 +__SYSCALL(__NR_mlockall, sys_mlockall) +#define __NR_munlockall 231 +__SYSCALL(__NR_munlockall, sys_munlockall) +#define __NR_mincore 232 +__SYSCALL(__NR_mincore, sys_mincore) +#define __NR_madvise 233 +__SYSCALL(__NR_madvise, sys_madvise) +#define __NR_remap_file_pages 234 +__SYSCALL(__NR_remap_file_pages, sys_remap_file_pages) +#define __NR_mbind 235 +__SC_COMP(__NR_mbind, sys_mbind, compat_sys_mbind) +#define __NR_get_mempolicy 236 +__SC_COMP(__NR_get_mempolicy, sys_get_mempolicy, compat_sys_get_mempolicy) +#define __NR_set_mempolicy 237 +__SC_COMP(__NR_set_mempolicy, sys_set_mempolicy, compat_sys_set_mempolicy) +#define __NR_migrate_pages 238 +__SC_COMP(__NR_migrate_pages, sys_migrate_pages, compat_sys_migrate_pages) +#define __NR_move_pages 239 +__SC_COMP(__NR_move_pages, sys_move_pages, compat_sys_move_pages) +#endif + +#define __NR_rt_tgsigqueueinfo 240 +__SC_COMP(__NR_rt_tgsigqueueinfo, sys_rt_tgsigqueueinfo, \ + compat_sys_rt_tgsigqueueinfo) +#define __NR_perf_event_open 241 +__SYSCALL(__NR_perf_event_open, sys_perf_event_open) +#define __NR_accept4 242 +__SYSCALL(__NR_accept4, sys_accept4) +#define __NR_recvmmsg 243 +__SC_COMP(__NR_recvmmsg, sys_recvmmsg, compat_sys_recvmmsg) + +/* + * Architectures may provide up to 16 syscalls of their own + * starting with this value. + */ +#define __NR_arch_specific_syscall 244 + +#define __NR_wait4 260 +__SC_COMP(__NR_wait4, sys_wait4, compat_sys_wait4) +#define __NR_prlimit64 261 +__SYSCALL(__NR_prlimit64, sys_prlimit64) +#define __NR_fanotify_init 262 +__SYSCALL(__NR_fanotify_init, sys_fanotify_init) +#define __NR_fanotify_mark 263 +__SYSCALL(__NR_fanotify_mark, sys_fanotify_mark) +#define __NR_name_to_handle_at 264 +__SYSCALL(__NR_name_to_handle_at, sys_name_to_handle_at) +#define __NR_open_by_handle_at 265 +__SC_COMP(__NR_open_by_handle_at, sys_open_by_handle_at, \ + compat_sys_open_by_handle_at) +#define __NR_clock_adjtime 266 +__SC_COMP(__NR_clock_adjtime, sys_clock_adjtime, compat_sys_clock_adjtime) +#define __NR_syncfs 267 +__SYSCALL(__NR_syncfs, sys_syncfs) +#define __NR_setns 268 +__SYSCALL(__NR_setns, sys_setns) +#define __NR_sendmmsg 269 +__SC_COMP(__NR_sendmmsg, sys_sendmmsg, compat_sys_sendmmsg) +#define __NR_process_vm_readv 270 +__SC_COMP(__NR_process_vm_readv, sys_process_vm_readv, \ + compat_sys_process_vm_readv) +#define __NR_process_vm_writev 271 +__SC_COMP(__NR_process_vm_writev, sys_process_vm_writev, \ + compat_sys_process_vm_writev) +#define __NR_kcmp 272 +__SYSCALL(__NR_kcmp, sys_kcmp) +#define __NR_finit_module 273 +__SYSCALL(__NR_finit_module, sys_finit_module) +#define __NR_sched_setattr 274 +__SYSCALL(__NR_sched_setattr, sys_sched_setattr) +#define __NR_sched_getattr 275 +__SYSCALL(__NR_sched_getattr, sys_sched_getattr) +#define __NR_renameat2 276 +__SYSCALL(__NR_renameat2, sys_renameat2) +#define __NR_seccomp 277 +__SYSCALL(__NR_seccomp, sys_seccomp) +#define __NR_getrandom 278 +__SYSCALL(__NR_getrandom, sys_getrandom) +#define __NR_memfd_create 279 +__SYSCALL(__NR_memfd_create, sys_memfd_create) +#define __NR_bpf 280 +__SYSCALL(__NR_bpf, sys_bpf) +#define __NR_execveat 281 +__SC_COMP(__NR_execveat, sys_execveat, compat_sys_execveat) +#define __NR_userfaultfd 282 +__SYSCALL(__NR_userfaultfd, sys_userfaultfd) +#define __NR_membarrier 283 +__SYSCALL(__NR_membarrier, sys_membarrier) +#define __NR_mlock2 284 +__SYSCALL(__NR_mlock2, sys_mlock2) +#define __NR_copy_file_range 285 +__SYSCALL(__NR_copy_file_range, sys_copy_file_range) +#define __NR_preadv2 286 +__SC_COMP(__NR_preadv2, sys_preadv2, compat_sys_preadv2) +#define __NR_pwritev2 287 +__SC_COMP(__NR_pwritev2, sys_pwritev2, compat_sys_pwritev2) +#define __NR_pkey_mprotect 288 +__SYSCALL(__NR_pkey_mprotect, sys_pkey_mprotect) +#define __NR_pkey_alloc 289 +__SYSCALL(__NR_pkey_alloc, sys_pkey_alloc) +#define __NR_pkey_free 290 +__SYSCALL(__NR_pkey_free, sys_pkey_free) +#define __NR_statx 291 +__SYSCALL(__NR_statx, sys_statx) +#define __NR_io_pgetevents 292 +__SC_COMP(__NR_io_pgetevents, sys_io_pgetevents, compat_sys_io_pgetevents) + +#undef __NR_syscalls +#define __NR_syscalls 293 + +/* + * 32 bit systems traditionally used different + * syscalls for off_t and loff_t arguments, while + * 64 bit systems only need the off_t version. + * For new 32 bit platforms, there is no need to + * implement the old 32 bit off_t syscalls, so + * they take different names. + * Here we map the numbers so that both versions + * use the same syscall table layout. + */ +#if __BITS_PER_LONG == 64 && !defined(__SYSCALL_COMPAT) +#define __NR_fcntl __NR3264_fcntl +#define __NR_statfs __NR3264_statfs +#define __NR_fstatfs __NR3264_fstatfs +#define __NR_truncate __NR3264_truncate +#define __NR_ftruncate __NR3264_ftruncate +#define __NR_lseek __NR3264_lseek +#define __NR_sendfile __NR3264_sendfile +#define __NR_newfstatat __NR3264_fstatat +#define __NR_fstat __NR3264_fstat +#define __NR_mmap __NR3264_mmap +#define __NR_fadvise64 __NR3264_fadvise64 +#ifdef __NR3264_stat +#define __NR_stat __NR3264_stat +#define __NR_lstat __NR3264_lstat +#endif +#else +#define __NR_fcntl64 __NR3264_fcntl +#define __NR_statfs64 __NR3264_statfs +#define __NR_fstatfs64 __NR3264_fstatfs +#define __NR_truncate64 __NR3264_truncate +#define __NR_ftruncate64 __NR3264_ftruncate +#define __NR_llseek __NR3264_lseek +#define __NR_sendfile64 __NR3264_sendfile +#define __NR_fstatat64 __NR3264_fstatat +#define __NR_fstat64 __NR3264_fstat +#define __NR_mmap2 __NR3264_mmap +#define __NR_fadvise64_64 __NR3264_fadvise64 +#ifdef __NR3264_stat +#define __NR_stat64 __NR3264_stat +#define __NR_lstat64 __NR3264_lstat +#endif +#endif diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index b7db3261c62d..66917a4eba27 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -75,6 +75,11 @@ struct bpf_lpm_trie_key { __u8 data[0]; /* Arbitrary size */ }; +struct bpf_cgroup_storage_key { + __u64 cgroup_inode_id; /* cgroup inode id */ + __u32 attach_type; /* program attach type */ +}; + /* BPF syscall commands, see bpf(2) man-page for details. */ enum bpf_cmd { BPF_MAP_CREATE, @@ -120,6 +125,8 @@ enum bpf_map_type { BPF_MAP_TYPE_CPUMAP, BPF_MAP_TYPE_XSKMAP, BPF_MAP_TYPE_SOCKHASH, + BPF_MAP_TYPE_CGROUP_STORAGE, + BPF_MAP_TYPE_REUSEPORT_SOCKARRAY, }; enum bpf_prog_type { @@ -144,6 +151,7 @@ enum bpf_prog_type { BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_PROG_TYPE_LWT_SEG6LOCAL, BPF_PROG_TYPE_LIRC_MODE2, + BPF_PROG_TYPE_SK_REUSEPORT, }; enum bpf_attach_type { @@ -1371,6 +1379,20 @@ union bpf_attr { * A 8-byte long non-decreasing number on success, or 0 if the * socket field is missing inside *skb*. * + * u64 bpf_get_socket_cookie(struct bpf_sock_addr *ctx) + * Description + * Equivalent to bpf_get_socket_cookie() helper that accepts + * *skb*, but gets socket from **struct bpf_sock_addr** contex. + * Return + * A 8-byte long non-decreasing number. + * + * u64 bpf_get_socket_cookie(struct bpf_sock_ops *ctx) + * Description + * Equivalent to bpf_get_socket_cookie() helper that accepts + * *skb*, but gets socket from **struct bpf_sock_ops** contex. + * Return + * A 8-byte long non-decreasing number. + * * u32 bpf_get_socket_uid(struct sk_buff *skb) * Return * The owner UID of the socket associated to *skb*. If the socket @@ -1826,7 +1848,7 @@ union bpf_attr { * A non-negative value equal to or less than *size* on success, * or a negative error in case of failure. * - * int skb_load_bytes_relative(const struct sk_buff *skb, u32 offset, void *to, u32 len, u32 start_header) + * int bpf_skb_load_bytes_relative(const struct sk_buff *skb, u32 offset, void *to, u32 len, u32 start_header) * Description * This helper is similar to **bpf_skb_load_bytes**\ () in that * it provides an easy way to load *len* bytes from *offset* @@ -1877,7 +1899,7 @@ union bpf_attr { * * < 0 if any input argument is invalid * * 0 on success (packet is forwarded, nexthop neighbor exists) * * > 0 one of **BPF_FIB_LKUP_RET_** codes explaining why the - * * packet is not forwarded or needs assist from full stack + * packet is not forwarded or needs assist from full stack * * int bpf_sock_hash_update(struct bpf_sock_ops_kern *skops, struct bpf_map *map, void *key, u64 flags) * Description @@ -2033,7 +2055,6 @@ union bpf_attr { * This helper is only available is the kernel was compiled with * the **CONFIG_BPF_LIRC_MODE2** configuration option set to * "**y**". - * * Return * 0 * @@ -2053,7 +2074,6 @@ union bpf_attr { * This helper is only available is the kernel was compiled with * the **CONFIG_BPF_LIRC_MODE2** configuration option set to * "**y**". - * * Return * 0 * @@ -2073,10 +2093,54 @@ union bpf_attr { * Return * The id is returned or 0 in case the id could not be retrieved. * + * u64 bpf_skb_ancestor_cgroup_id(struct sk_buff *skb, int ancestor_level) + * Description + * Return id of cgroup v2 that is ancestor of cgroup associated + * with the *skb* at the *ancestor_level*. The root cgroup is at + * *ancestor_level* zero and each step down the hierarchy + * increments the level. If *ancestor_level* == level of cgroup + * associated with *skb*, then return value will be same as that + * of **bpf_skb_cgroup_id**\ (). + * + * The helper is useful to implement policies based on cgroups + * that are upper in hierarchy than immediate cgroup associated + * with *skb*. + * + * The format of returned id and helper limitations are same as in + * **bpf_skb_cgroup_id**\ (). + * Return + * The id is returned or 0 in case the id could not be retrieved. + * * u64 bpf_get_current_cgroup_id(void) * Return * A 64-bit integer containing the current cgroup id based * on the cgroup within which the current task is running. + * + * void* get_local_storage(void *map, u64 flags) + * Description + * Get the pointer to the local storage area. + * The type and the size of the local storage is defined + * by the *map* argument. + * The *flags* meaning is specific for each map type, + * and has to be 0 for cgroup local storage. + * + * Depending on the bpf program type, a local storage area + * can be shared between multiple instances of the bpf program, + * running simultaneously. + * + * A user should care about the synchronization by himself. + * For example, by using the BPF_STX_XADD instruction to alter + * the shared data. + * Return + * Pointer to the local storage area. + * + * int bpf_sk_select_reuseport(struct sk_reuseport_md *reuse, struct bpf_map *map, void *key, u64 flags) + * Description + * Select a SO_REUSEPORT sk from a BPF_MAP_TYPE_REUSEPORT_ARRAY map + * It checks the selected sk is matching the incoming + * request in the skb. + * Return + * 0 on success, or a negative error in case of failure. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -2159,7 +2223,10 @@ union bpf_attr { FN(rc_repeat), \ FN(rc_keydown), \ FN(skb_cgroup_id), \ - FN(get_current_cgroup_id), + FN(get_current_cgroup_id), \ + FN(get_local_storage), \ + FN(sk_select_reuseport), \ + FN(skb_ancestor_cgroup_id), /* integer value in 'imm' field of BPF_CALL instruction selects which helper * function eBPF program intends to call @@ -2376,6 +2443,30 @@ struct sk_msg_md { __u32 local_port; /* stored in host byte order */ }; +struct sk_reuseport_md { + /* + * Start of directly accessible data. It begins from + * the tcp/udp header. + */ + void *data; + void *data_end; /* End of directly accessible data */ + /* + * Total length of packet (starting from the tcp/udp header). + * Note that the directly accessible bytes (data_end - data) + * could be less than this "len". Those bytes could be + * indirectly read by a helper "bpf_skb_load_bytes()". + */ + __u32 len; + /* + * Eth protocol in the mac header (network byte order). e.g. + * ETH_P_IP(0x0800) and ETH_P_IPV6(0x86DD) + */ + __u32 eth_protocol; + __u32 ip_protocol; /* IP protocol. e.g. IPPROTO_TCP, IPPROTO_UDP */ + __u32 bind_inany; /* Is sock bound to an INANY address? */ + __u32 hash; /* A hash of the packet 4 tuples */ +}; + #define BPF_TAG_SIZE 8 struct bpf_prog_info { @@ -2557,6 +2648,9 @@ enum { * Arg1: old_state * Arg2: new_state */ + BPF_SOCK_OPS_TCP_LISTEN_CB, /* Called on listen(2), right after + * socket transition to LISTEN state. + */ }; /* List of TCP states. There is a build check in net/ipv4/tcp.c to detect diff --git a/tools/include/uapi/linux/in.h b/tools/include/uapi/linux/in.h new file mode 100644 index 000000000000..48e8a225b985 --- /dev/null +++ b/tools/include/uapi/linux/in.h @@ -0,0 +1,301 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Definitions of the Internet Protocol. + * + * Version: @(#)in.h 1.0.1 04/21/93 + * + * Authors: Original taken from the GNU Project <netinet/in.h> file. + * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _UAPI_LINUX_IN_H +#define _UAPI_LINUX_IN_H + +#include <linux/types.h> +#include <linux/libc-compat.h> +#include <linux/socket.h> + +#if __UAPI_DEF_IN_IPPROTO +/* Standard well-defined IP protocols. */ +enum { + IPPROTO_IP = 0, /* Dummy protocol for TCP */ +#define IPPROTO_IP IPPROTO_IP + IPPROTO_ICMP = 1, /* Internet Control Message Protocol */ +#define IPPROTO_ICMP IPPROTO_ICMP + IPPROTO_IGMP = 2, /* Internet Group Management Protocol */ +#define IPPROTO_IGMP IPPROTO_IGMP + IPPROTO_IPIP = 4, /* IPIP tunnels (older KA9Q tunnels use 94) */ +#define IPPROTO_IPIP IPPROTO_IPIP + IPPROTO_TCP = 6, /* Transmission Control Protocol */ +#define IPPROTO_TCP IPPROTO_TCP + IPPROTO_EGP = 8, /* Exterior Gateway Protocol */ +#define IPPROTO_EGP IPPROTO_EGP + IPPROTO_PUP = 12, /* PUP protocol */ +#define IPPROTO_PUP IPPROTO_PUP + IPPROTO_UDP = 17, /* User Datagram Protocol */ +#define IPPROTO_UDP IPPROTO_UDP + IPPROTO_IDP = 22, /* XNS IDP protocol */ +#define IPPROTO_IDP IPPROTO_IDP + IPPROTO_TP = 29, /* SO Transport Protocol Class 4 */ +#define IPPROTO_TP IPPROTO_TP + IPPROTO_DCCP = 33, /* Datagram Congestion Control Protocol */ +#define IPPROTO_DCCP IPPROTO_DCCP + IPPROTO_IPV6 = 41, /* IPv6-in-IPv4 tunnelling */ +#define IPPROTO_IPV6 IPPROTO_IPV6 + IPPROTO_RSVP = 46, /* RSVP Protocol */ +#define IPPROTO_RSVP IPPROTO_RSVP + IPPROTO_GRE = 47, /* Cisco GRE tunnels (rfc 1701,1702) */ +#define IPPROTO_GRE IPPROTO_GRE + IPPROTO_ESP = 50, /* Encapsulation Security Payload protocol */ +#define IPPROTO_ESP IPPROTO_ESP + IPPROTO_AH = 51, /* Authentication Header protocol */ +#define IPPROTO_AH IPPROTO_AH + IPPROTO_MTP = 92, /* Multicast Transport Protocol */ +#define IPPROTO_MTP IPPROTO_MTP + IPPROTO_BEETPH = 94, /* IP option pseudo header for BEET */ +#define IPPROTO_BEETPH IPPROTO_BEETPH + IPPROTO_ENCAP = 98, /* Encapsulation Header */ +#define IPPROTO_ENCAP IPPROTO_ENCAP + IPPROTO_PIM = 103, /* Protocol Independent Multicast */ +#define IPPROTO_PIM IPPROTO_PIM + IPPROTO_COMP = 108, /* Compression Header Protocol */ +#define IPPROTO_COMP IPPROTO_COMP + IPPROTO_SCTP = 132, /* Stream Control Transport Protocol */ +#define IPPROTO_SCTP IPPROTO_SCTP + IPPROTO_UDPLITE = 136, /* UDP-Lite (RFC 3828) */ +#define IPPROTO_UDPLITE IPPROTO_UDPLITE + IPPROTO_MPLS = 137, /* MPLS in IP (RFC 4023) */ +#define IPPROTO_MPLS IPPROTO_MPLS + IPPROTO_RAW = 255, /* Raw IP packets */ +#define IPPROTO_RAW IPPROTO_RAW + IPPROTO_MAX +}; +#endif + +#if __UAPI_DEF_IN_ADDR +/* Internet address. */ +struct in_addr { + __be32 s_addr; +}; +#endif + +#define IP_TOS 1 +#define IP_TTL 2 +#define IP_HDRINCL 3 +#define IP_OPTIONS 4 +#define IP_ROUTER_ALERT 5 +#define IP_RECVOPTS 6 +#define IP_RETOPTS 7 +#define IP_PKTINFO 8 +#define IP_PKTOPTIONS 9 +#define IP_MTU_DISCOVER 10 +#define IP_RECVERR 11 +#define IP_RECVTTL 12 +#define IP_RECVTOS 13 +#define IP_MTU 14 +#define IP_FREEBIND 15 +#define IP_IPSEC_POLICY 16 +#define IP_XFRM_POLICY 17 +#define IP_PASSSEC 18 +#define IP_TRANSPARENT 19 + +/* BSD compatibility */ +#define IP_RECVRETOPTS IP_RETOPTS + +/* TProxy original addresses */ +#define IP_ORIGDSTADDR 20 +#define IP_RECVORIGDSTADDR IP_ORIGDSTADDR + +#define IP_MINTTL 21 +#define IP_NODEFRAG 22 +#define IP_CHECKSUM 23 +#define IP_BIND_ADDRESS_NO_PORT 24 +#define IP_RECVFRAGSIZE 25 + +/* IP_MTU_DISCOVER values */ +#define IP_PMTUDISC_DONT 0 /* Never send DF frames */ +#define IP_PMTUDISC_WANT 1 /* Use per route hints */ +#define IP_PMTUDISC_DO 2 /* Always DF */ +#define IP_PMTUDISC_PROBE 3 /* Ignore dst pmtu */ +/* Always use interface mtu (ignores dst pmtu) but don't set DF flag. + * Also incoming ICMP frag_needed notifications will be ignored on + * this socket to prevent accepting spoofed ones. + */ +#define IP_PMTUDISC_INTERFACE 4 +/* weaker version of IP_PMTUDISC_INTERFACE, which allos packets to get + * fragmented if they exeed the interface mtu + */ +#define IP_PMTUDISC_OMIT 5 + +#define IP_MULTICAST_IF 32 +#define IP_MULTICAST_TTL 33 +#define IP_MULTICAST_LOOP 34 +#define IP_ADD_MEMBERSHIP 35 +#define IP_DROP_MEMBERSHIP 36 +#define IP_UNBLOCK_SOURCE 37 +#define IP_BLOCK_SOURCE 38 +#define IP_ADD_SOURCE_MEMBERSHIP 39 +#define IP_DROP_SOURCE_MEMBERSHIP 40 +#define IP_MSFILTER 41 +#define MCAST_JOIN_GROUP 42 +#define MCAST_BLOCK_SOURCE 43 +#define MCAST_UNBLOCK_SOURCE 44 +#define MCAST_LEAVE_GROUP 45 +#define MCAST_JOIN_SOURCE_GROUP 46 +#define MCAST_LEAVE_SOURCE_GROUP 47 +#define MCAST_MSFILTER 48 +#define IP_MULTICAST_ALL 49 +#define IP_UNICAST_IF 50 + +#define MCAST_EXCLUDE 0 +#define MCAST_INCLUDE 1 + +/* These need to appear somewhere around here */ +#define IP_DEFAULT_MULTICAST_TTL 1 +#define IP_DEFAULT_MULTICAST_LOOP 1 + +/* Request struct for multicast socket ops */ + +#if __UAPI_DEF_IP_MREQ +struct ip_mreq { + struct in_addr imr_multiaddr; /* IP multicast address of group */ + struct in_addr imr_interface; /* local IP address of interface */ +}; + +struct ip_mreqn { + struct in_addr imr_multiaddr; /* IP multicast address of group */ + struct in_addr imr_address; /* local IP address of interface */ + int imr_ifindex; /* Interface index */ +}; + +struct ip_mreq_source { + __be32 imr_multiaddr; + __be32 imr_interface; + __be32 imr_sourceaddr; +}; + +struct ip_msfilter { + __be32 imsf_multiaddr; + __be32 imsf_interface; + __u32 imsf_fmode; + __u32 imsf_numsrc; + __be32 imsf_slist[1]; +}; + +#define IP_MSFILTER_SIZE(numsrc) \ + (sizeof(struct ip_msfilter) - sizeof(__u32) \ + + (numsrc) * sizeof(__u32)) + +struct group_req { + __u32 gr_interface; /* interface index */ + struct __kernel_sockaddr_storage gr_group; /* group address */ +}; + +struct group_source_req { + __u32 gsr_interface; /* interface index */ + struct __kernel_sockaddr_storage gsr_group; /* group address */ + struct __kernel_sockaddr_storage gsr_source; /* source address */ +}; + +struct group_filter { + __u32 gf_interface; /* interface index */ + struct __kernel_sockaddr_storage gf_group; /* multicast address */ + __u32 gf_fmode; /* filter mode */ + __u32 gf_numsrc; /* number of sources */ + struct __kernel_sockaddr_storage gf_slist[1]; /* interface index */ +}; + +#define GROUP_FILTER_SIZE(numsrc) \ + (sizeof(struct group_filter) - sizeof(struct __kernel_sockaddr_storage) \ + + (numsrc) * sizeof(struct __kernel_sockaddr_storage)) +#endif + +#if __UAPI_DEF_IN_PKTINFO +struct in_pktinfo { + int ipi_ifindex; + struct in_addr ipi_spec_dst; + struct in_addr ipi_addr; +}; +#endif + +/* Structure describing an Internet (IP) socket address. */ +#if __UAPI_DEF_SOCKADDR_IN +#define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */ +struct sockaddr_in { + __kernel_sa_family_t sin_family; /* Address family */ + __be16 sin_port; /* Port number */ + struct in_addr sin_addr; /* Internet address */ + + /* Pad to size of `struct sockaddr'. */ + unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) - + sizeof(unsigned short int) - sizeof(struct in_addr)]; +}; +#define sin_zero __pad /* for BSD UNIX comp. -FvK */ +#endif + +#if __UAPI_DEF_IN_CLASS +/* + * Definitions of the bits in an Internet address integer. + * On subnets, host and network parts are found according + * to the subnet mask, not these masks. + */ +#define IN_CLASSA(a) ((((long int) (a)) & 0x80000000) == 0) +#define IN_CLASSA_NET 0xff000000 +#define IN_CLASSA_NSHIFT 24 +#define IN_CLASSA_HOST (0xffffffff & ~IN_CLASSA_NET) +#define IN_CLASSA_MAX 128 + +#define IN_CLASSB(a) ((((long int) (a)) & 0xc0000000) == 0x80000000) +#define IN_CLASSB_NET 0xffff0000 +#define IN_CLASSB_NSHIFT 16 +#define IN_CLASSB_HOST (0xffffffff & ~IN_CLASSB_NET) +#define IN_CLASSB_MAX 65536 + +#define IN_CLASSC(a) ((((long int) (a)) & 0xe0000000) == 0xc0000000) +#define IN_CLASSC_NET 0xffffff00 +#define IN_CLASSC_NSHIFT 8 +#define IN_CLASSC_HOST (0xffffffff & ~IN_CLASSC_NET) + +#define IN_CLASSD(a) ((((long int) (a)) & 0xf0000000) == 0xe0000000) +#define IN_MULTICAST(a) IN_CLASSD(a) +#define IN_MULTICAST_NET 0xF0000000 + +#define IN_EXPERIMENTAL(a) ((((long int) (a)) & 0xf0000000) == 0xf0000000) +#define IN_BADCLASS(a) IN_EXPERIMENTAL((a)) + +/* Address to accept any incoming messages. */ +#define INADDR_ANY ((unsigned long int) 0x00000000) + +/* Address to send to all hosts. */ +#define INADDR_BROADCAST ((unsigned long int) 0xffffffff) + +/* Address indicating an error return. */ +#define INADDR_NONE ((unsigned long int) 0xffffffff) + +/* Network number for local host loopback. */ +#define IN_LOOPBACKNET 127 + +/* Address to loopback in software to local host. */ +#define INADDR_LOOPBACK 0x7f000001 /* 127.0.0.1 */ +#define IN_LOOPBACK(a) ((((long int) (a)) & 0xff000000) == 0x7f000000) + +/* Defines for Multicast INADDR */ +#define INADDR_UNSPEC_GROUP 0xe0000000U /* 224.0.0.0 */ +#define INADDR_ALLHOSTS_GROUP 0xe0000001U /* 224.0.0.1 */ +#define INADDR_ALLRTRS_GROUP 0xe0000002U /* 224.0.0.2 */ +#define INADDR_MAX_LOCAL_GROUP 0xe00000ffU /* 224.0.0.255 */ +#endif + +/* <asm/byteorder.h> contains the htonl type stuff.. */ +#include <asm/byteorder.h> + + +#endif /* _UAPI_LINUX_IN_H */ diff --git a/tools/lib/bpf/Build b/tools/lib/bpf/Build index 6070e655042d..13a861135127 100644 --- a/tools/lib/bpf/Build +++ b/tools/lib/bpf/Build @@ -1 +1 @@ -libbpf-y := libbpf.o bpf.o nlattr.o btf.o +libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf_errno.o diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile index 5390e7725e43..d49902e818b5 100644 --- a/tools/lib/bpf/Makefile +++ b/tools/lib/bpf/Makefile @@ -66,7 +66,7 @@ ifndef VERBOSE endif FEATURE_USER = .libbpf -FEATURE_TESTS = libelf libelf-getphdrnum libelf-mmap bpf +FEATURE_TESTS = libelf libelf-mmap bpf reallocarray FEATURE_DISPLAY = libelf bpf INCLUDES = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(ARCH)/include/uapi -I$(srctree)/tools/include/uapi -I$(srctree)/tools/perf @@ -116,8 +116,8 @@ ifeq ($(feature-libelf-mmap), 1) override CFLAGS += -DHAVE_LIBELF_MMAP_SUPPORT endif -ifeq ($(feature-libelf-getphdrnum), 1) - override CFLAGS += -DHAVE_ELF_GETPHDRNUM_SUPPORT +ifeq ($(feature-reallocarray), 0) + override CFLAGS += -DCOMPAT_NEED_REALLOCARRAY endif # Append required CFLAGS diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 9ddc89dae962..60aa4ca8b2c5 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -92,6 +92,7 @@ int bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr) attr.btf_key_type_id = create_attr->btf_key_type_id; attr.btf_value_type_id = create_attr->btf_value_type_id; attr.map_ifindex = create_attr->map_ifindex; + attr.inner_map_fd = create_attr->inner_map_fd; return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); } diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index 0639a30a457d..6f38164b2618 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -39,6 +39,7 @@ struct bpf_create_map_attr { __u32 btf_key_type_id; __u32 btf_value_type_id; __u32 map_ifindex; + __u32 inner_map_fd; }; int bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr); diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c index c36a3a76986a..cf94b0770522 100644 --- a/tools/lib/bpf/btf.c +++ b/tools/lib/bpf/btf.c @@ -16,6 +16,11 @@ #define BTF_MAX_NR_TYPES 65535 +#define IS_MODIFIER(k) (((k) == BTF_KIND_TYPEDEF) || \ + ((k) == BTF_KIND_VOLATILE) || \ + ((k) == BTF_KIND_CONST) || \ + ((k) == BTF_KIND_RESTRICT)) + static struct btf_type btf_void; struct btf { @@ -32,14 +37,6 @@ struct btf { int fd; }; -static const char *btf_name_by_offset(const struct btf *btf, __u32 offset) -{ - if (offset < btf->hdr->str_len) - return &btf->strings[offset]; - else - return NULL; -} - static int btf_add_type(struct btf *btf, struct btf_type *t) { if (btf->types_size - btf->nr_types < 2) { @@ -269,6 +266,26 @@ __s64 btf__resolve_size(const struct btf *btf, __u32 type_id) return nelems * size; } +int btf__resolve_type(const struct btf *btf, __u32 type_id) +{ + const struct btf_type *t; + int depth = 0; + + t = btf__type_by_id(btf, type_id); + while (depth < MAX_RESOLVE_DEPTH && + !btf_type_is_void_or_null(t) && + IS_MODIFIER(BTF_INFO_KIND(t->info))) { + type_id = t->type; + t = btf__type_by_id(btf, type_id); + depth++; + } + + if (depth == MAX_RESOLVE_DEPTH || btf_type_is_void_or_null(t)) + return -EINVAL; + + return type_id; +} + __s32 btf__find_by_name(const struct btf *btf, const char *type_name) { __u32 i; @@ -278,7 +295,7 @@ __s32 btf__find_by_name(const struct btf *btf, const char *type_name) for (i = 1; i <= btf->nr_types; i++) { const struct btf_type *t = btf->types[i]; - const char *name = btf_name_by_offset(btf, t->name_off); + const char *name = btf__name_by_offset(btf, t->name_off); if (name && !strcmp(type_name, name)) return i; @@ -368,3 +385,11 @@ int btf__fd(const struct btf *btf) { return btf->fd; } + +const char *btf__name_by_offset(const struct btf *btf, __u32 offset) +{ + if (offset < btf->hdr->str_len) + return &btf->strings[offset]; + else + return NULL; +} diff --git a/tools/lib/bpf/btf.h b/tools/lib/bpf/btf.h index caac3a404dc5..4897e0724d4e 100644 --- a/tools/lib/bpf/btf.h +++ b/tools/lib/bpf/btf.h @@ -19,6 +19,8 @@ struct btf *btf__new(__u8 *data, __u32 size, btf_print_fn_t err_log); __s32 btf__find_by_name(const struct btf *btf, const char *type_name); const struct btf_type *btf__type_by_id(const struct btf *btf, __u32 id); __s64 btf__resolve_size(const struct btf *btf, __u32 type_id); +int btf__resolve_type(const struct btf *btf, __u32 type_id); int btf__fd(const struct btf *btf); +const char *btf__name_by_offset(const struct btf *btf, __u32 offset); #endif diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 1aafdbe827fe..2abd0f112627 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -22,6 +22,7 @@ * License along with this program; if not, see <http://www.gnu.org/licenses> */ +#define _GNU_SOURCE #include <stdlib.h> #include <stdio.h> #include <stdarg.h> @@ -42,6 +43,7 @@ #include <sys/stat.h> #include <sys/types.h> #include <sys/vfs.h> +#include <tools/libc_compat.h> #include <libelf.h> #include <gelf.h> @@ -96,54 +98,6 @@ void libbpf_set_print(libbpf_print_fn_t warn, #define STRERR_BUFSIZE 128 -#define ERRNO_OFFSET(e) ((e) - __LIBBPF_ERRNO__START) -#define ERRCODE_OFFSET(c) ERRNO_OFFSET(LIBBPF_ERRNO__##c) -#define NR_ERRNO (__LIBBPF_ERRNO__END - __LIBBPF_ERRNO__START) - -static const char *libbpf_strerror_table[NR_ERRNO] = { - [ERRCODE_OFFSET(LIBELF)] = "Something wrong in libelf", - [ERRCODE_OFFSET(FORMAT)] = "BPF object format invalid", - [ERRCODE_OFFSET(KVERSION)] = "'version' section incorrect or lost", - [ERRCODE_OFFSET(ENDIAN)] = "Endian mismatch", - [ERRCODE_OFFSET(INTERNAL)] = "Internal error in libbpf", - [ERRCODE_OFFSET(RELOC)] = "Relocation failed", - [ERRCODE_OFFSET(VERIFY)] = "Kernel verifier blocks program loading", - [ERRCODE_OFFSET(PROG2BIG)] = "Program too big", - [ERRCODE_OFFSET(KVER)] = "Incorrect kernel version", - [ERRCODE_OFFSET(PROGTYPE)] = "Kernel doesn't support this program type", - [ERRCODE_OFFSET(WRNGPID)] = "Wrong pid in netlink message", - [ERRCODE_OFFSET(INVSEQ)] = "Invalid netlink sequence", -}; - -int libbpf_strerror(int err, char *buf, size_t size) -{ - if (!buf || !size) - return -1; - - err = err > 0 ? err : -err; - - if (err < __LIBBPF_ERRNO__START) { - int ret; - - ret = strerror_r(err, buf, size); - buf[size - 1] = '\0'; - return ret; - } - - if (err < __LIBBPF_ERRNO__END) { - const char *msg; - - msg = libbpf_strerror_table[ERRNO_OFFSET(err)]; - snprintf(buf, size, "%s", msg); - buf[size - 1] = '\0'; - return 0; - } - - snprintf(buf, size, "Unknown libbpf error %d", err); - buf[size - 1] = '\0'; - return -1; -} - #define CHECK_ERR(action, err, out) do { \ err = action; \ if (err) \ @@ -235,6 +189,7 @@ struct bpf_object { size_t nr_maps; bool loaded; + bool has_pseudo_calls; /* * Information when doing elf related work. Only valid if fd @@ -369,7 +324,7 @@ bpf_object__add_program(struct bpf_object *obj, void *data, size_t size, progs = obj->programs; nr_progs = obj->nr_programs; - progs = realloc(progs, sizeof(progs[0]) * (nr_progs + 1)); + progs = reallocarray(progs, nr_progs + 1, sizeof(progs[0])); if (!progs) { /* * In this case the original obj->programs @@ -401,10 +356,6 @@ bpf_object__init_prog_names(struct bpf_object *obj) const char *name = NULL; prog = &obj->programs[pi]; - if (prog->idx == obj->efile.text_shndx) { - name = ".text"; - goto skip_search; - } for (si = 0; si < symbols->d_size / sizeof(GElf_Sym) && !name; si++) { @@ -427,12 +378,15 @@ bpf_object__init_prog_names(struct bpf_object *obj) } } + if (!name && prog->idx == obj->efile.text_shndx) + name = ".text"; + if (!name) { pr_warning("failed to find sym for prog %s\n", prog->section_name); return -EINVAL; } -skip_search: + prog->name = strdup(name); if (!prog->name) { pr_warning("failed to allocate memory for prog sym %s\n", @@ -514,8 +468,10 @@ static int bpf_object__elf_init(struct bpf_object *obj) } else { obj->efile.fd = open(obj->path, O_RDONLY); if (obj->efile.fd < 0) { - pr_warning("failed to open %s: %s\n", obj->path, - strerror(errno)); + char errmsg[STRERR_BUFSIZE]; + char *cp = strerror_r(errno, errmsg, sizeof(errmsg)); + + pr_warning("failed to open %s: %s\n", obj->path, cp); return -errno; } @@ -854,10 +810,11 @@ static int bpf_object__elf_collect(struct bpf_object *obj) data->d_size, name, idx); if (err) { char errmsg[STRERR_BUFSIZE]; + char *cp = strerror_r(-err, errmsg, + sizeof(errmsg)); - strerror_r(-err, errmsg, sizeof(errmsg)); pr_warning("failed to alloc program %s (%s): %s", - name, obj->path, errmsg); + name, obj->path, cp); } } else if (sh.sh_type == SHT_REL) { void *reloc = obj->efile.reloc; @@ -871,8 +828,8 @@ static int bpf_object__elf_collect(struct bpf_object *obj) continue; } - reloc = realloc(reloc, - sizeof(*obj->efile.reloc) * nr_reloc); + reloc = reallocarray(reloc, nr_reloc, + sizeof(*obj->efile.reloc)); if (!reloc) { pr_warning("realloc failed\n"); err = -ENOMEM; @@ -920,6 +877,18 @@ bpf_object__find_prog_by_idx(struct bpf_object *obj, int idx) return NULL; } +struct bpf_program * +bpf_object__find_program_by_title(struct bpf_object *obj, const char *title) +{ + struct bpf_program *pos; + + bpf_object__for_each_program(pos, obj) { + if (pos->section_name && !strcmp(pos->section_name, title)) + return pos; + } + return NULL; +} + static int bpf_program__collect_reloc(struct bpf_program *prog, GElf_Shdr *shdr, Elf_Data *data, struct bpf_object *obj) @@ -982,6 +951,7 @@ bpf_program__collect_reloc(struct bpf_program *prog, GElf_Shdr *shdr, prog->reloc_desc[i].type = RELO_CALL; prog->reloc_desc[i].insn_idx = insn_idx; prog->reloc_desc[i].text_off = sym.st_value; + obj->has_pseudo_calls = true; continue; } @@ -1085,6 +1055,53 @@ static int bpf_map_find_btf_info(struct bpf_map *map, const struct btf *btf) return 0; } +int bpf_map__reuse_fd(struct bpf_map *map, int fd) +{ + struct bpf_map_info info = {}; + __u32 len = sizeof(info); + int new_fd, err; + char *new_name; + + err = bpf_obj_get_info_by_fd(fd, &info, &len); + if (err) + return err; + + new_name = strdup(info.name); + if (!new_name) + return -errno; + + new_fd = open("/", O_RDONLY | O_CLOEXEC); + if (new_fd < 0) + goto err_free_new_name; + + new_fd = dup3(fd, new_fd, O_CLOEXEC); + if (new_fd < 0) + goto err_close_new_fd; + + err = zclose(map->fd); + if (err) + goto err_close_new_fd; + free(map->name); + + map->fd = new_fd; + map->name = new_name; + map->def.type = info.type; + map->def.key_size = info.key_size; + map->def.value_size = info.value_size; + map->def.max_entries = info.max_entries; + map->def.map_flags = info.map_flags; + map->btf_key_type_id = info.btf_key_type_id; + map->btf_value_type_id = info.btf_value_type_id; + + return 0; + +err_close_new_fd: + close(new_fd); +err_free_new_name: + free(new_name); + return -errno; +} + static int bpf_object__create_maps(struct bpf_object *obj) { @@ -1095,8 +1112,15 @@ bpf_object__create_maps(struct bpf_object *obj) for (i = 0; i < obj->nr_maps; i++) { struct bpf_map *map = &obj->maps[i]; struct bpf_map_def *def = &map->def; + char *cp, errmsg[STRERR_BUFSIZE]; int *pfd = &map->fd; + if (map->fd >= 0) { + pr_debug("skip map create (preset) %s: fd=%d\n", + map->name, map->fd); + continue; + } + create_attr.name = map->name; create_attr.map_ifindex = map->map_ifindex; create_attr.map_type = def->type; @@ -1116,8 +1140,9 @@ bpf_object__create_maps(struct bpf_object *obj) *pfd = bpf_create_map_xattr(&create_attr); if (*pfd < 0 && create_attr.btf_key_type_id) { + cp = strerror_r(errno, errmsg, sizeof(errmsg)); pr_warning("Error in bpf_create_map_xattr(%s):%s(%d). Retrying without BTF.\n", - map->name, strerror(errno), errno); + map->name, cp, errno); create_attr.btf_fd = 0; create_attr.btf_key_type_id = 0; create_attr.btf_value_type_id = 0; @@ -1130,9 +1155,9 @@ bpf_object__create_maps(struct bpf_object *obj) size_t j; err = *pfd; + cp = strerror_r(errno, errmsg, sizeof(errmsg)); pr_warning("failed to create map (name: '%s'): %s\n", - map->name, - strerror(errno)); + map->name, cp); for (j = 0; j < i; j++) zclose(obj->maps[j].fd); return err; @@ -1167,7 +1192,7 @@ bpf_program__reloc_text(struct bpf_program *prog, struct bpf_object *obj, return -LIBBPF_ERRNO__RELOC; } new_cnt = prog->insns_cnt + text->insns_cnt; - new_insn = realloc(prog->insns, new_cnt * sizeof(*insn)); + new_insn = reallocarray(prog->insns, new_cnt, sizeof(*insn)); if (!new_insn) { pr_warning("oom in prog realloc\n"); return -ENOMEM; @@ -1284,6 +1309,7 @@ load_program(enum bpf_prog_type type, enum bpf_attach_type expected_attach_type, char *license, u32 kern_version, int *pfd, int prog_ifindex) { struct bpf_load_program_attr load_attr; + char *cp, errmsg[STRERR_BUFSIZE]; char *log_buf; int ret; @@ -1313,7 +1339,8 @@ load_program(enum bpf_prog_type type, enum bpf_attach_type expected_attach_type, } ret = -LIBBPF_ERRNO__LOAD; - pr_warning("load bpf program failed: %s\n", strerror(errno)); + cp = strerror_r(errno, errmsg, sizeof(errmsg)); + pr_warning("load bpf program failed: %s\n", cp); if (log_buf && log_buf[0] != '\0') { ret = -LIBBPF_ERRNO__VERIFY; @@ -1431,6 +1458,12 @@ out: return err; } +static bool bpf_program__is_function_storage(struct bpf_program *prog, + struct bpf_object *obj) +{ + return prog->idx == obj->efile.text_shndx && obj->has_pseudo_calls; +} + static int bpf_object__load_progs(struct bpf_object *obj) { @@ -1438,7 +1471,7 @@ bpf_object__load_progs(struct bpf_object *obj) int err; for (i = 0; i < obj->nr_programs; i++) { - if (obj->programs[i].idx == obj->efile.text_shndx) + if (bpf_program__is_function_storage(&obj->programs[i], obj)) continue; err = bpf_program__load(&obj->programs[i], obj->license, @@ -1468,6 +1501,7 @@ static bool bpf_prog_type__needs_kver(enum bpf_prog_type type) case BPF_PROG_TYPE_SK_MSG: case BPF_PROG_TYPE_CGROUP_SOCK_ADDR: case BPF_PROG_TYPE_LIRC_MODE2: + case BPF_PROG_TYPE_SK_REUSEPORT: return false; case BPF_PROG_TYPE_UNSPEC: case BPF_PROG_TYPE_KPROBE: @@ -1518,15 +1552,26 @@ out: return ERR_PTR(err); } -struct bpf_object *bpf_object__open(const char *path) +struct bpf_object *bpf_object__open_xattr(struct bpf_object_open_attr *attr) { /* param validation */ - if (!path) + if (!attr->file) return NULL; - pr_debug("loading %s\n", path); + pr_debug("loading %s\n", attr->file); - return __bpf_object__open(path, NULL, 0, true); + return __bpf_object__open(attr->file, NULL, 0, + bpf_prog_type__needs_kver(attr->prog_type)); +} + +struct bpf_object *bpf_object__open(const char *path) +{ + struct bpf_object_open_attr attr = { + .file = path, + .prog_type = BPF_PROG_TYPE_UNSPEC, + }; + + return bpf_object__open_xattr(&attr); } struct bpf_object *bpf_object__open_buffer(void *obj_buf, @@ -1595,6 +1640,7 @@ out: static int check_path(const char *path) { + char *cp, errmsg[STRERR_BUFSIZE]; struct statfs st_fs; char *dname, *dir; int err = 0; @@ -1608,7 +1654,8 @@ static int check_path(const char *path) dir = dirname(dname); if (statfs(dir, &st_fs)) { - pr_warning("failed to statfs %s: %s\n", dir, strerror(errno)); + cp = strerror_r(errno, errmsg, sizeof(errmsg)); + pr_warning("failed to statfs %s: %s\n", dir, cp); err = -errno; } free(dname); @@ -1624,6 +1671,7 @@ static int check_path(const char *path) int bpf_program__pin_instance(struct bpf_program *prog, const char *path, int instance) { + char *cp, errmsg[STRERR_BUFSIZE]; int err; err = check_path(path); @@ -1642,7 +1690,8 @@ int bpf_program__pin_instance(struct bpf_program *prog, const char *path, } if (bpf_obj_pin(prog->instances.fds[instance], path)) { - pr_warning("failed to pin program: %s\n", strerror(errno)); + cp = strerror_r(errno, errmsg, sizeof(errmsg)); + pr_warning("failed to pin program: %s\n", cp); return -errno; } pr_debug("pinned program '%s'\n", path); @@ -1652,13 +1701,16 @@ int bpf_program__pin_instance(struct bpf_program *prog, const char *path, static int make_dir(const char *path) { + char *cp, errmsg[STRERR_BUFSIZE]; int err = 0; if (mkdir(path, 0700) && errno != EEXIST) err = -errno; - if (err) - pr_warning("failed to mkdir %s: %s\n", path, strerror(-err)); + if (err) { + cp = strerror_r(-err, errmsg, sizeof(errmsg)); + pr_warning("failed to mkdir %s: %s\n", path, cp); + } return err; } @@ -1705,6 +1757,7 @@ int bpf_program__pin(struct bpf_program *prog, const char *path) int bpf_map__pin(struct bpf_map *map, const char *path) { + char *cp, errmsg[STRERR_BUFSIZE]; int err; err = check_path(path); @@ -1717,7 +1770,8 @@ int bpf_map__pin(struct bpf_map *map, const char *path) } if (bpf_obj_pin(map->fd, path)) { - pr_warning("failed to pin map: %s\n", strerror(errno)); + cp = strerror_r(errno, errmsg, sizeof(errmsg)); + pr_warning("failed to pin map: %s\n", cp); return -errno; } @@ -1863,8 +1917,8 @@ void *bpf_object__priv(struct bpf_object *obj) return obj ? obj->priv : ERR_PTR(-EINVAL); } -struct bpf_program * -bpf_program__next(struct bpf_program *prev, struct bpf_object *obj) +static struct bpf_program * +__bpf_program__next(struct bpf_program *prev, struct bpf_object *obj) { size_t idx; @@ -1885,6 +1939,18 @@ bpf_program__next(struct bpf_program *prev, struct bpf_object *obj) return &obj->programs[idx]; } +struct bpf_program * +bpf_program__next(struct bpf_program *prev, struct bpf_object *obj) +{ + struct bpf_program *prog = prev; + + do { + prog = __bpf_program__next(prog, obj); + } while (prog && bpf_program__is_function_storage(prog, obj)); + + return prog; +} + int bpf_program__set_priv(struct bpf_program *prog, void *priv, bpf_program_clear_priv_t clear_priv) { @@ -1901,6 +1967,11 @@ void *bpf_program__priv(struct bpf_program *prog) return prog ? prog->priv : ERR_PTR(-EINVAL); } +void bpf_program__set_ifindex(struct bpf_program *prog, __u32 ifindex) +{ + prog->prog_ifindex = ifindex; +} + const char *bpf_program__title(struct bpf_program *prog, bool needs_copy) { const char *title; @@ -1954,6 +2025,9 @@ int bpf_program__nth_fd(struct bpf_program *prog, int n) { int fd; + if (!prog) + return -EINVAL; + if (n >= prog->instances.nr || n < 0) { pr_warning("Can't get the %dth fd from program %s: only %d instances\n", n, prog->section_name, prog->instances.nr); @@ -2042,9 +2116,11 @@ static const struct { BPF_PROG_SEC("lwt_in", BPF_PROG_TYPE_LWT_IN), BPF_PROG_SEC("lwt_out", BPF_PROG_TYPE_LWT_OUT), BPF_PROG_SEC("lwt_xmit", BPF_PROG_TYPE_LWT_XMIT), + BPF_PROG_SEC("lwt_seg6local", BPF_PROG_TYPE_LWT_SEG6LOCAL), BPF_PROG_SEC("sockops", BPF_PROG_TYPE_SOCK_OPS), BPF_PROG_SEC("sk_skb", BPF_PROG_TYPE_SK_SKB), BPF_PROG_SEC("sk_msg", BPF_PROG_TYPE_SK_MSG), + BPF_PROG_SEC("lirc_mode2", BPF_PROG_TYPE_LIRC_MODE2), BPF_SA_PROG_SEC("cgroup/bind4", BPF_CGROUP_INET4_BIND), BPF_SA_PROG_SEC("cgroup/bind6", BPF_CGROUP_INET6_BIND), BPF_SA_PROG_SEC("cgroup/connect4", BPF_CGROUP_INET4_CONNECT), @@ -2060,23 +2136,31 @@ static const struct { #undef BPF_S_PROG_SEC #undef BPF_SA_PROG_SEC -static int bpf_program__identify_section(struct bpf_program *prog) +int libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type, + enum bpf_attach_type *expected_attach_type) { int i; - if (!prog->section_name) - goto err; - - for (i = 0; i < ARRAY_SIZE(section_names); i++) - if (strncmp(prog->section_name, section_names[i].sec, - section_names[i].len) == 0) - return i; + if (!name) + return -EINVAL; -err: - pr_warning("failed to guess program type based on section name %s\n", - prog->section_name); + for (i = 0; i < ARRAY_SIZE(section_names); i++) { + if (strncmp(name, section_names[i].sec, section_names[i].len)) + continue; + *prog_type = section_names[i].prog_type; + *expected_attach_type = section_names[i].expected_attach_type; + return 0; + } + return -EINVAL; +} - return -1; +static int +bpf_program__identify_section(struct bpf_program *prog, + enum bpf_prog_type *prog_type, + enum bpf_attach_type *expected_attach_type) +{ + return libbpf_prog_type_by_name(prog->section_name, prog_type, + expected_attach_type); } int bpf_map__fd(struct bpf_map *map) @@ -2125,6 +2209,16 @@ void *bpf_map__priv(struct bpf_map *map) return map ? map->priv : ERR_PTR(-EINVAL); } +bool bpf_map__is_offload_neutral(struct bpf_map *map) +{ + return map->def.type == BPF_MAP_TYPE_PERF_EVENT_ARRAY; +} + +void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex) +{ + map->map_ifindex = ifindex; +} + struct bpf_map * bpf_map__next(struct bpf_map *prev, struct bpf_object *obj) { @@ -2199,12 +2293,15 @@ int bpf_prog_load(const char *file, enum bpf_prog_type type, int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr, struct bpf_object **pobj, int *prog_fd) { + struct bpf_object_open_attr open_attr = { + .file = attr->file, + .prog_type = attr->prog_type, + }; struct bpf_program *prog, *first_prog = NULL; enum bpf_attach_type expected_attach_type; enum bpf_prog_type prog_type; struct bpf_object *obj; struct bpf_map *map; - int section_idx; int err; if (!attr) @@ -2212,8 +2309,7 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr, if (!attr->file) return -EINVAL; - obj = __bpf_object__open(attr->file, NULL, 0, - bpf_prog_type__needs_kver(attr->prog_type)); + obj = bpf_object__open_xattr(&open_attr); if (IS_ERR_OR_NULL(obj)) return -ENOENT; @@ -2226,26 +2322,27 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr, prog->prog_ifindex = attr->ifindex; expected_attach_type = attr->expected_attach_type; if (prog_type == BPF_PROG_TYPE_UNSPEC) { - section_idx = bpf_program__identify_section(prog); - if (section_idx < 0) { + err = bpf_program__identify_section(prog, &prog_type, + &expected_attach_type); + if (err < 0) { + pr_warning("failed to guess program type based on section name %s\n", + prog->section_name); bpf_object__close(obj); return -EINVAL; } - prog_type = section_names[section_idx].prog_type; - expected_attach_type = - section_names[section_idx].expected_attach_type; } bpf_program__set_type(prog, prog_type); bpf_program__set_expected_attach_type(prog, expected_attach_type); - if (prog->idx != obj->efile.text_shndx && !first_prog) + if (!bpf_program__is_function_storage(prog, obj) && !first_prog) first_prog = prog; } bpf_map__for_each(map, obj) { - map->map_ifindex = attr->ifindex; + if (!bpf_map__is_offload_neutral(map)) + map->map_ifindex = attr->ifindex; } if (!first_prog) { diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index b33ae02f7d0e..96c55fac54c3 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -66,7 +66,13 @@ void libbpf_set_print(libbpf_print_fn_t warn, /* Hide internal to user */ struct bpf_object; +struct bpf_object_open_attr { + const char *file; + enum bpf_prog_type prog_type; +}; + struct bpf_object *bpf_object__open(const char *path); +struct bpf_object *bpf_object__open_xattr(struct bpf_object_open_attr *attr); struct bpf_object *bpf_object__open_buffer(void *obj_buf, size_t obj_buf_sz, const char *name); @@ -80,6 +86,9 @@ const char *bpf_object__name(struct bpf_object *obj); unsigned int bpf_object__kversion(struct bpf_object *obj); int bpf_object__btf_fd(const struct bpf_object *obj); +struct bpf_program * +bpf_object__find_program_by_title(struct bpf_object *obj, const char *title); + struct bpf_object *bpf_object__next(struct bpf_object *prev); #define bpf_object__for_each_safe(pos, tmp) \ for ((pos) = bpf_object__next(NULL), \ @@ -92,6 +101,9 @@ int bpf_object__set_priv(struct bpf_object *obj, void *priv, bpf_object_clear_priv_t clear_priv); void *bpf_object__priv(struct bpf_object *prog); +int libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type, + enum bpf_attach_type *expected_attach_type); + /* Accessors of bpf_program */ struct bpf_program; struct bpf_program *bpf_program__next(struct bpf_program *prog, @@ -109,6 +121,7 @@ int bpf_program__set_priv(struct bpf_program *prog, void *priv, bpf_program_clear_priv_t clear_priv); void *bpf_program__priv(struct bpf_program *prog); +void bpf_program__set_ifindex(struct bpf_program *prog, __u32 ifindex); const char *bpf_program__title(struct bpf_program *prog, bool needs_copy); @@ -251,6 +264,9 @@ typedef void (*bpf_map_clear_priv_t)(struct bpf_map *, void *); int bpf_map__set_priv(struct bpf_map *map, void *priv, bpf_map_clear_priv_t clear_priv); void *bpf_map__priv(struct bpf_map *map); +int bpf_map__reuse_fd(struct bpf_map *map, int fd); +bool bpf_map__is_offload_neutral(struct bpf_map *map); +void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex); int bpf_map__pin(struct bpf_map *map, const char *path); long libbpf_get_error(const void *ptr); diff --git a/tools/lib/bpf/libbpf_errno.c b/tools/lib/bpf/libbpf_errno.c new file mode 100644 index 000000000000..d9ba851bd7f9 --- /dev/null +++ b/tools/lib/bpf/libbpf_errno.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: LGPL-2.1 + +/* + * Copyright (C) 2013-2015 Alexei Starovoitov <ast@kernel.org> + * Copyright (C) 2015 Wang Nan <wangnan0@huawei.com> + * Copyright (C) 2015 Huawei Inc. + * Copyright (C) 2017 Nicira, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License (not later!) + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses> + */ + +#include <stdio.h> +#include <string.h> + +#include "libbpf.h" + +#define ERRNO_OFFSET(e) ((e) - __LIBBPF_ERRNO__START) +#define ERRCODE_OFFSET(c) ERRNO_OFFSET(LIBBPF_ERRNO__##c) +#define NR_ERRNO (__LIBBPF_ERRNO__END - __LIBBPF_ERRNO__START) + +static const char *libbpf_strerror_table[NR_ERRNO] = { + [ERRCODE_OFFSET(LIBELF)] = "Something wrong in libelf", + [ERRCODE_OFFSET(FORMAT)] = "BPF object format invalid", + [ERRCODE_OFFSET(KVERSION)] = "'version' section incorrect or lost", + [ERRCODE_OFFSET(ENDIAN)] = "Endian mismatch", + [ERRCODE_OFFSET(INTERNAL)] = "Internal error in libbpf", + [ERRCODE_OFFSET(RELOC)] = "Relocation failed", + [ERRCODE_OFFSET(VERIFY)] = "Kernel verifier blocks program loading", + [ERRCODE_OFFSET(PROG2BIG)] = "Program too big", + [ERRCODE_OFFSET(KVER)] = "Incorrect kernel version", + [ERRCODE_OFFSET(PROGTYPE)] = "Kernel doesn't support this program type", + [ERRCODE_OFFSET(WRNGPID)] = "Wrong pid in netlink message", + [ERRCODE_OFFSET(INVSEQ)] = "Invalid netlink sequence", +}; + +int libbpf_strerror(int err, char *buf, size_t size) +{ + if (!buf || !size) + return -1; + + err = err > 0 ? err : -err; + + if (err < __LIBBPF_ERRNO__START) { + int ret; + + ret = strerror_r(err, buf, size); + buf[size - 1] = '\0'; + return ret; + } + + if (err < __LIBBPF_ERRNO__END) { + const char *msg; + + msg = libbpf_strerror_table[ERRNO_OFFSET(err)]; + snprintf(buf, size, "%s", msg); + buf[size - 1] = '\0'; + return 0; + } + + snprintf(buf, size, "Unknown libbpf error %d", err); + buf[size - 1] = '\0'; + return -1; +} diff --git a/tools/lib/lockdep/Makefile b/tools/lib/lockdep/Makefile index 9b0ca3ad1ef3..9dafb8cb752f 100644 --- a/tools/lib/lockdep/Makefile +++ b/tools/lib/lockdep/Makefile @@ -129,12 +129,12 @@ $(OUTPUT)liblockdep.a: $(LIB_IN) tags: force $(RM) tags find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px \ - --regex-c++='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/' + --regex-c++='/_PE\(([^,)]*).*/TEP_ERRNO__\1/' TAGS: force $(RM) TAGS find . -name '*.[ch]' | xargs etags \ - --regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/' + --regex='/_PE(\([^,)]*\).*/TEP_ERRNO__\1/' define do_install $(print_install) \ diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile index 46cd5f871ad7..0b4e833088a4 100644 --- a/tools/lib/traceevent/Makefile +++ b/tools/lib/traceevent/Makefile @@ -233,12 +233,12 @@ endef tags: force $(RM) tags find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px \ - --regex-c++='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/' + --regex-c++='/_PE\(([^,)]*).*/TEP_ERRNO__\1/' TAGS: force $(RM) TAGS find . -name '*.[ch]' | xargs etags \ - --regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/' + --regex='/_PE(\([^,)]*\).*/TEP_ERRNO__\1/' define do_install_mkdir if [ ! -d '$(DESTDIR_SQ)$1' ]; then \ diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index e5f2acbb70cc..ce1e20227c64 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c @@ -1,21 +1,7 @@ +// SPDX-License-Identifier: LGPL-2.1 /* * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License (not later!) - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, see <http://www.gnu.org/licenses> - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * The parts for function graph printing was taken and modified from the * Linux Kernel that were written by @@ -73,12 +59,12 @@ static void init_input_buf(const char *buf, unsigned long long size) input_buf_ptr = 0; } -const char *pevent_get_input_buf(void) +const char *tep_get_input_buf(void) { return input_buf; } -unsigned long long pevent_get_input_buf_ptr(void) +unsigned long long tep_get_input_buf_ptr(void) { return input_buf_ptr; } @@ -88,21 +74,21 @@ struct event_handler { int id; const char *sys_name; const char *event_name; - pevent_event_handler_func func; + tep_event_handler_func func; void *context; }; -struct pevent_func_params { - struct pevent_func_params *next; - enum pevent_func_arg_type type; +struct func_params { + struct func_params *next; + enum tep_func_arg_type type; }; -struct pevent_function_handler { - struct pevent_function_handler *next; - enum pevent_func_arg_type ret_type; +struct tep_function_handler { + struct tep_function_handler *next; + enum tep_func_arg_type ret_type; char *name; - pevent_func_handler func; - struct pevent_func_params *params; + tep_func_handler func; + struct func_params *params; int nr_args; }; @@ -110,17 +96,17 @@ static unsigned long long process_defined_func(struct trace_seq *s, void *data, int size, struct event_format *event, struct print_arg *arg); -static void free_func_handle(struct pevent_function_handler *func); +static void free_func_handle(struct tep_function_handler *func); /** - * pevent_buffer_init - init buffer for parsing + * tep_buffer_init - init buffer for parsing * @buf: buffer to parse * @size: the size of the buffer * - * For use with pevent_read_token(), this initializes the internal - * buffer that pevent_read_token() will parse. + * For use with tep_read_token(), this initializes the internal + * buffer that tep_read_token() will parse. */ -void pevent_buffer_init(const char *buf, unsigned long long size) +void tep_buffer_init(const char *buf, unsigned long long size) { init_input_buf(buf, size); } @@ -160,7 +146,7 @@ struct cmdline_list { int pid; }; -static int cmdline_init(struct pevent *pevent) +static int cmdline_init(struct tep_handle *pevent) { struct cmdline_list *cmdlist = pevent->cmdlist; struct cmdline_list *item; @@ -189,7 +175,7 @@ static int cmdline_init(struct pevent *pevent) return 0; } -static const char *find_cmdline(struct pevent *pevent, int pid) +static const char *find_cmdline(struct tep_handle *pevent, int pid) { const struct cmdline *comm; struct cmdline key; @@ -211,14 +197,14 @@ static const char *find_cmdline(struct pevent *pevent, int pid) } /** - * pevent_pid_is_registered - return if a pid has a cmdline registered + * tep_pid_is_registered - return if a pid has a cmdline registered * @pevent: handle for the pevent * @pid: The pid to check if it has a cmdline registered with. * * Returns 1 if the pid has a cmdline mapped to it * 0 otherwise. */ -int pevent_pid_is_registered(struct pevent *pevent, int pid) +int tep_pid_is_registered(struct tep_handle *pevent, int pid) { const struct cmdline *comm; struct cmdline key; @@ -244,7 +230,7 @@ int pevent_pid_is_registered(struct pevent *pevent, int pid) * we must add this pid. This is much slower than when cmdlines * are added before the array is initialized. */ -static int add_new_comm(struct pevent *pevent, const char *comm, int pid) +static int add_new_comm(struct tep_handle *pevent, const char *comm, int pid) { struct cmdline *cmdlines = pevent->cmdlines; const struct cmdline *cmdline; @@ -288,7 +274,7 @@ static int add_new_comm(struct pevent *pevent, const char *comm, int pid) } /** - * pevent_register_comm - register a pid / comm mapping + * tep_register_comm - register a pid / comm mapping * @pevent: handle for the pevent * @comm: the command line to register * @pid: the pid to map the command line to @@ -296,7 +282,7 @@ static int add_new_comm(struct pevent *pevent, const char *comm, int pid) * This adds a mapping to search for command line names with * a given pid. The comm is duplicated. */ -int pevent_register_comm(struct pevent *pevent, const char *comm, int pid) +int tep_register_comm(struct tep_handle *pevent, const char *comm, int pid) { struct cmdline_list *item; @@ -324,7 +310,7 @@ int pevent_register_comm(struct pevent *pevent, const char *comm, int pid) return 0; } -int pevent_register_trace_clock(struct pevent *pevent, const char *trace_clock) +int tep_register_trace_clock(struct tep_handle *pevent, const char *trace_clock) { pevent->trace_clock = strdup(trace_clock); if (!pevent->trace_clock) { @@ -381,7 +367,7 @@ static int func_bcmp(const void *a, const void *b) return 1; } -static int func_map_init(struct pevent *pevent) +static int func_map_init(struct tep_handle *pevent) { struct func_list *funclist; struct func_list *item; @@ -421,7 +407,7 @@ static int func_map_init(struct pevent *pevent) } static struct func_map * -__find_func(struct pevent *pevent, unsigned long long addr) +__find_func(struct tep_handle *pevent, unsigned long long addr) { struct func_map *func; struct func_map key; @@ -438,13 +424,13 @@ __find_func(struct pevent *pevent, unsigned long long addr) } struct func_resolver { - pevent_func_resolver_t *func; - void *priv; - struct func_map map; + tep_func_resolver_t *func; + void *priv; + struct func_map map; }; /** - * pevent_set_function_resolver - set an alternative function resolver + * tep_set_function_resolver - set an alternative function resolver * @pevent: handle for the pevent * @resolver: function to be used * @priv: resolver function private state. @@ -453,8 +439,8 @@ struct func_resolver { * keep using it instead of duplicating all the entries inside * pevent->funclist. */ -int pevent_set_function_resolver(struct pevent *pevent, - pevent_func_resolver_t *func, void *priv) +int tep_set_function_resolver(struct tep_handle *pevent, + tep_func_resolver_t *func, void *priv) { struct func_resolver *resolver = malloc(sizeof(*resolver)); @@ -471,20 +457,20 @@ int pevent_set_function_resolver(struct pevent *pevent, } /** - * pevent_reset_function_resolver - reset alternative function resolver + * tep_reset_function_resolver - reset alternative function resolver * @pevent: handle for the pevent * * Stop using whatever alternative resolver was set, use the default * one instead. */ -void pevent_reset_function_resolver(struct pevent *pevent) +void tep_reset_function_resolver(struct tep_handle *pevent) { free(pevent->func_resolver); pevent->func_resolver = NULL; } static struct func_map * -find_func(struct pevent *pevent, unsigned long long addr) +find_func(struct tep_handle *pevent, unsigned long long addr) { struct func_map *map; @@ -503,7 +489,7 @@ find_func(struct pevent *pevent, unsigned long long addr) } /** - * pevent_find_function - find a function by a given address + * tep_find_function - find a function by a given address * @pevent: handle for the pevent * @addr: the address to find the function with * @@ -511,7 +497,7 @@ find_func(struct pevent *pevent, unsigned long long addr) * address. Note, the address does not have to be exact, it * will select the function that would contain the address. */ -const char *pevent_find_function(struct pevent *pevent, unsigned long long addr) +const char *tep_find_function(struct tep_handle *pevent, unsigned long long addr) { struct func_map *map; @@ -523,16 +509,16 @@ const char *pevent_find_function(struct pevent *pevent, unsigned long long addr) } /** - * pevent_find_function_address - find a function address by a given address + * tep_find_function_address - find a function address by a given address * @pevent: handle for the pevent * @addr: the address to find the function with * * Returns the address the function starts at. This can be used in - * conjunction with pevent_find_function to print both the function + * conjunction with tep_find_function to print both the function * name and the function offset. */ unsigned long long -pevent_find_function_address(struct pevent *pevent, unsigned long long addr) +tep_find_function_address(struct tep_handle *pevent, unsigned long long addr) { struct func_map *map; @@ -544,7 +530,7 @@ pevent_find_function_address(struct pevent *pevent, unsigned long long addr) } /** - * pevent_register_function - register a function with a given address + * tep_register_function - register a function with a given address * @pevent: handle for the pevent * @function: the function name to register * @addr: the address the function starts at @@ -553,8 +539,8 @@ pevent_find_function_address(struct pevent *pevent, unsigned long long addr) * This registers a function name with an address and module. * The @func passed in is duplicated. */ -int pevent_register_function(struct pevent *pevent, char *func, - unsigned long long addr, char *mod) +int tep_register_function(struct tep_handle *pevent, char *func, + unsigned long long addr, char *mod) { struct func_list *item = malloc(sizeof(*item)); @@ -589,12 +575,12 @@ out_free: } /** - * pevent_print_funcs - print out the stored functions + * tep_print_funcs - print out the stored functions * @pevent: handle for the pevent * * This prints out the stored functions. */ -void pevent_print_funcs(struct pevent *pevent) +void tep_print_funcs(struct tep_handle *pevent) { int i; @@ -636,7 +622,7 @@ static int printk_cmp(const void *a, const void *b) return 0; } -static int printk_map_init(struct pevent *pevent) +static int printk_map_init(struct tep_handle *pevent) { struct printk_list *printklist; struct printk_list *item; @@ -668,7 +654,7 @@ static int printk_map_init(struct pevent *pevent) } static struct printk_map * -find_printk(struct pevent *pevent, unsigned long long addr) +find_printk(struct tep_handle *pevent, unsigned long long addr) { struct printk_map *printk; struct printk_map key; @@ -685,7 +671,7 @@ find_printk(struct pevent *pevent, unsigned long long addr) } /** - * pevent_register_print_string - register a string by its address + * tep_register_print_string - register a string by its address * @pevent: handle for the pevent * @fmt: the string format to register * @addr: the address the string was located at @@ -693,8 +679,8 @@ find_printk(struct pevent *pevent, unsigned long long addr) * This registers a string by the address it was stored in the kernel. * The @fmt passed in is duplicated. */ -int pevent_register_print_string(struct pevent *pevent, const char *fmt, - unsigned long long addr) +int tep_register_print_string(struct tep_handle *pevent, const char *fmt, + unsigned long long addr) { struct printk_list *item = malloc(sizeof(*item)); char *p; @@ -732,12 +718,12 @@ out_free: } /** - * pevent_print_printk - print out the stored strings + * tep_print_printk - print out the stored strings * @pevent: handle for the pevent * * This prints the string formats that were stored. */ -void pevent_print_printk(struct pevent *pevent) +void tep_print_printk(struct tep_handle *pevent) { int i; @@ -756,7 +742,7 @@ static struct event_format *alloc_event(void) return calloc(1, sizeof(struct event_format)); } -static int add_event(struct pevent *pevent, struct event_format *event) +static int add_event(struct tep_handle *pevent, struct event_format *event) { int i; struct event_format **events = realloc(pevent->events, sizeof(event) * @@ -913,11 +899,11 @@ static int __peek_char(void) } /** - * pevent_peek_char - peek at the next character that will be read + * tep_peek_char - peek at the next character that will be read * * Returns the next character read, or -1 if end of buffer. */ -int pevent_peek_char(void) +int tep_peek_char(void) { return __peek_char(); } @@ -1157,24 +1143,24 @@ static enum event_type read_token(char **tok) } /** - * pevent_read_token - access to utilites to use the pevent parser + * tep_read_token - access to utilites to use the pevent parser * @tok: The token to return * * This will parse tokens from the string given by - * pevent_init_data(). + * tep_init_data(). * * Returns the token type. */ -enum event_type pevent_read_token(char **tok) +enum event_type tep_read_token(char **tok) { return read_token(tok); } /** - * pevent_free_token - free a token returned by pevent_read_token + * tep_free_token - free a token returned by tep_read_token * @token: the token to free */ -void pevent_free_token(char *token) +void tep_free_token(char *token) { free_token(token); } @@ -2101,11 +2087,11 @@ process_entry(struct event_format *event __maybe_unused, struct print_arg *arg, arg->field.name = field; if (is_flag_field) { - arg->field.field = pevent_find_any_field(event, arg->field.name); + arg->field.field = tep_find_any_field(event, arg->field.name); arg->field.field->flags |= FIELD_IS_FLAG; is_flag_field = 0; } else if (is_symbolic_field) { - arg->field.field = pevent_find_any_field(event, arg->field.name); + arg->field.field = tep_find_any_field(event, arg->field.name); arg->field.field->flags |= FIELD_IS_SYMBOLIC; is_symbolic_field = 0; } @@ -2714,7 +2700,7 @@ process_dynamic_array(struct event_format *event, struct print_arg *arg, char ** /* Find the field */ - field = pevent_find_field(event, token); + field = tep_find_field(event, token); if (!field) goto out_free; @@ -2771,7 +2757,7 @@ process_dynamic_array_len(struct event_format *event, struct print_arg *arg, arg->type = PRINT_DYNAMIC_ARRAY_LEN; /* Find the field */ - field = pevent_find_field(event, token); + field = tep_find_field(event, token); if (!field) goto out_free; @@ -2914,10 +2900,10 @@ process_bitmask(struct event_format *event __maybe_unused, struct print_arg *arg return EVENT_ERROR; } -static struct pevent_function_handler * -find_func_handler(struct pevent *pevent, char *func_name) +static struct tep_function_handler * +find_func_handler(struct tep_handle *pevent, char *func_name) { - struct pevent_function_handler *func; + struct tep_function_handler *func; if (!pevent) return NULL; @@ -2930,10 +2916,10 @@ find_func_handler(struct pevent *pevent, char *func_name) return func; } -static void remove_func_handler(struct pevent *pevent, char *func_name) +static void remove_func_handler(struct tep_handle *pevent, char *func_name) { - struct pevent_function_handler *func; - struct pevent_function_handler **next; + struct tep_function_handler *func; + struct tep_function_handler **next; next = &pevent->func_handlers; while ((func = *next)) { @@ -2947,7 +2933,7 @@ static void remove_func_handler(struct pevent *pevent, char *func_name) } static enum event_type -process_func_handler(struct event_format *event, struct pevent_function_handler *func, +process_func_handler(struct event_format *event, struct tep_function_handler *func, struct print_arg *arg, char **tok) { struct print_arg **next_arg; @@ -3008,7 +2994,7 @@ static enum event_type process_function(struct event_format *event, struct print_arg *arg, char *token, char **tok) { - struct pevent_function_handler *func; + struct tep_function_handler *func; if (strcmp(token, "__print_flags") == 0) { free_token(token); @@ -3265,7 +3251,7 @@ static int event_read_print(struct event_format *event) } /** - * pevent_find_common_field - return a common field by event + * tep_find_common_field - return a common field by event * @event: handle for the event * @name: the name of the common field to return * @@ -3273,7 +3259,7 @@ static int event_read_print(struct event_format *event) * This only searchs the common fields and not all field. */ struct format_field * -pevent_find_common_field(struct event_format *event, const char *name) +tep_find_common_field(struct event_format *event, const char *name) { struct format_field *format; @@ -3287,7 +3273,7 @@ pevent_find_common_field(struct event_format *event, const char *name) } /** - * pevent_find_field - find a non-common field + * tep_find_field - find a non-common field * @event: handle for the event * @name: the name of the non-common field * @@ -3295,7 +3281,7 @@ pevent_find_common_field(struct event_format *event, const char *name) * This does not search common fields. */ struct format_field * -pevent_find_field(struct event_format *event, const char *name) +tep_find_field(struct event_format *event, const char *name) { struct format_field *format; @@ -3309,7 +3295,7 @@ pevent_find_field(struct event_format *event, const char *name) } /** - * pevent_find_any_field - find any field by name + * tep_find_any_field - find any field by name * @event: handle for the event * @name: the name of the field * @@ -3318,18 +3304,18 @@ pevent_find_field(struct event_format *event, const char *name) * the non-common ones if a common one was not found. */ struct format_field * -pevent_find_any_field(struct event_format *event, const char *name) +tep_find_any_field(struct event_format *event, const char *name) { struct format_field *format; - format = pevent_find_common_field(event, name); + format = tep_find_common_field(event, name); if (format) return format; - return pevent_find_field(event, name); + return tep_find_field(event, name); } /** - * pevent_read_number - read a number from data + * tep_read_number - read a number from data * @pevent: handle for the pevent * @ptr: the raw data * @size: the size of the data that holds the number @@ -3337,8 +3323,8 @@ pevent_find_any_field(struct event_format *event, const char *name) * Returns the number (converted to host) from the * raw data. */ -unsigned long long pevent_read_number(struct pevent *pevent, - const void *ptr, int size) +unsigned long long tep_read_number(struct tep_handle *pevent, + const void *ptr, int size) { switch (size) { case 1: @@ -3356,7 +3342,7 @@ unsigned long long pevent_read_number(struct pevent *pevent, } /** - * pevent_read_number_field - read a number from data + * tep_read_number_field - read a number from data * @field: a handle to the field * @data: the raw data to read * @value: the value to place the number in @@ -3366,8 +3352,8 @@ unsigned long long pevent_read_number(struct pevent *pevent, * * Returns 0 on success, -1 otherwise. */ -int pevent_read_number_field(struct format_field *field, const void *data, - unsigned long long *value) +int tep_read_number_field(struct format_field *field, const void *data, + unsigned long long *value) { if (!field) return -1; @@ -3376,15 +3362,15 @@ int pevent_read_number_field(struct format_field *field, const void *data, case 2: case 4: case 8: - *value = pevent_read_number(field->event->pevent, - data + field->offset, field->size); + *value = tep_read_number(field->event->pevent, + data + field->offset, field->size); return 0; default: return -1; } } -static int get_common_info(struct pevent *pevent, +static int get_common_info(struct tep_handle *pevent, const char *type, int *offset, int *size) { struct event_format *event; @@ -3400,7 +3386,7 @@ static int get_common_info(struct pevent *pevent, } event = pevent->events[0]; - field = pevent_find_common_field(event, type); + field = tep_find_common_field(event, type); if (!field) return -1; @@ -3410,7 +3396,7 @@ static int get_common_info(struct pevent *pevent, return 0; } -static int __parse_common(struct pevent *pevent, void *data, +static int __parse_common(struct tep_handle *pevent, void *data, int *size, int *offset, const char *name) { int ret; @@ -3420,45 +3406,45 @@ static int __parse_common(struct pevent *pevent, void *data, if (ret < 0) return ret; } - return pevent_read_number(pevent, data + *offset, *size); + return tep_read_number(pevent, data + *offset, *size); } -static int trace_parse_common_type(struct pevent *pevent, void *data) +static int trace_parse_common_type(struct tep_handle *pevent, void *data) { return __parse_common(pevent, data, &pevent->type_size, &pevent->type_offset, "common_type"); } -static int parse_common_pid(struct pevent *pevent, void *data) +static int parse_common_pid(struct tep_handle *pevent, void *data) { return __parse_common(pevent, data, &pevent->pid_size, &pevent->pid_offset, "common_pid"); } -static int parse_common_pc(struct pevent *pevent, void *data) +static int parse_common_pc(struct tep_handle *pevent, void *data) { return __parse_common(pevent, data, &pevent->pc_size, &pevent->pc_offset, "common_preempt_count"); } -static int parse_common_flags(struct pevent *pevent, void *data) +static int parse_common_flags(struct tep_handle *pevent, void *data) { return __parse_common(pevent, data, &pevent->flags_size, &pevent->flags_offset, "common_flags"); } -static int parse_common_lock_depth(struct pevent *pevent, void *data) +static int parse_common_lock_depth(struct tep_handle *pevent, void *data) { return __parse_common(pevent, data, &pevent->ld_size, &pevent->ld_offset, "common_lock_depth"); } -static int parse_common_migrate_disable(struct pevent *pevent, void *data) +static int parse_common_migrate_disable(struct tep_handle *pevent, void *data) { return __parse_common(pevent, data, &pevent->ld_size, &pevent->ld_offset, @@ -3468,13 +3454,13 @@ static int parse_common_migrate_disable(struct pevent *pevent, void *data) static int events_id_cmp(const void *a, const void *b); /** - * pevent_find_event - find an event by given id + * tep_find_event - find an event by given id * @pevent: a handle to the pevent * @id: the id of the event * * Returns an event that has a given @id. */ -struct event_format *pevent_find_event(struct pevent *pevent, int id) +struct event_format *tep_find_event(struct tep_handle *pevent, int id) { struct event_format **eventptr; struct event_format key; @@ -3498,7 +3484,7 @@ struct event_format *pevent_find_event(struct pevent *pevent, int id) } /** - * pevent_find_event_by_name - find an event by given name + * tep_find_event_by_name - find an event by given name * @pevent: a handle to the pevent * @sys: the system name to search for * @name: the name of the event to search for @@ -3507,8 +3493,8 @@ struct event_format *pevent_find_event(struct pevent *pevent, int id) * @sys. If @sys is NULL the first event with @name is returned. */ struct event_format * -pevent_find_event_by_name(struct pevent *pevent, - const char *sys, const char *name) +tep_find_event_by_name(struct tep_handle *pevent, + const char *sys, const char *name) { struct event_format *event; int i; @@ -3537,7 +3523,7 @@ pevent_find_event_by_name(struct pevent *pevent, static unsigned long long eval_num_arg(void *data, int size, struct event_format *event, struct print_arg *arg) { - struct pevent *pevent = event->pevent; + struct tep_handle *pevent = event->pevent; unsigned long long val = 0; unsigned long long left, right; struct print_arg *typearg = NULL; @@ -3553,14 +3539,14 @@ eval_num_arg(void *data, int size, struct event_format *event, struct print_arg return strtoull(arg->atom.atom, NULL, 0); case PRINT_FIELD: if (!arg->field.field) { - arg->field.field = pevent_find_any_field(event, arg->field.name); + arg->field.field = tep_find_any_field(event, arg->field.name); if (!arg->field.field) goto out_warning_field; } /* must be a number */ - val = pevent_read_number(pevent, data + arg->field.field->offset, - arg->field.field->size); + val = tep_read_number(pevent, data + arg->field.field->offset, + arg->field.field->size); break; case PRINT_FLAGS: case PRINT_SYMBOL: @@ -3603,7 +3589,7 @@ eval_num_arg(void *data, int size, struct event_format *event, struct print_arg switch (larg->type) { case PRINT_DYNAMIC_ARRAY: - offset = pevent_read_number(pevent, + offset = tep_read_number(pevent, data + larg->dynarray.field->offset, larg->dynarray.field->size); if (larg->dynarray.field->elementsize) @@ -3619,7 +3605,7 @@ eval_num_arg(void *data, int size, struct event_format *event, struct print_arg case PRINT_FIELD: if (!larg->field.field) { larg->field.field = - pevent_find_any_field(event, larg->field.name); + tep_find_any_field(event, larg->field.name); if (!larg->field.field) { arg = larg; goto out_warning_field; @@ -3632,8 +3618,8 @@ eval_num_arg(void *data, int size, struct event_format *event, struct print_arg default: goto default_op; /* oops, all bets off */ } - val = pevent_read_number(pevent, - data + offset, field_size); + val = tep_read_number(pevent, + data + offset, field_size); if (typearg) val = eval_type(val, typearg, 1); break; @@ -3733,9 +3719,9 @@ eval_num_arg(void *data, int size, struct event_format *event, struct print_arg } break; case PRINT_DYNAMIC_ARRAY_LEN: - offset = pevent_read_number(pevent, - data + arg->dynarray.field->offset, - arg->dynarray.field->size); + offset = tep_read_number(pevent, + data + arg->dynarray.field->offset, + arg->dynarray.field->size); /* * The total allocated length of the dynamic array is * stored in the top half of the field, and the offset @@ -3745,9 +3731,9 @@ eval_num_arg(void *data, int size, struct event_format *event, struct print_arg break; case PRINT_DYNAMIC_ARRAY: /* Without [], we pass the address to the dynamic data */ - offset = pevent_read_number(pevent, - data + arg->dynarray.field->offset, - arg->dynarray.field->size); + offset = tep_read_number(pevent, + data + arg->dynarray.field->offset, + arg->dynarray.field->size); /* * The total allocated length of the dynamic array is * stored in the top half of the field, and the offset @@ -3820,7 +3806,7 @@ static void print_str_to_seq(struct trace_seq *s, const char *format, trace_seq_printf(s, format, str); } -static void print_bitmask_to_seq(struct pevent *pevent, +static void print_bitmask_to_seq(struct tep_handle *pevent, struct trace_seq *s, const char *format, int len_arg, const void *data, int size) { @@ -3878,7 +3864,7 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, struct event_format *event, const char *format, int len_arg, struct print_arg *arg) { - struct pevent *pevent = event->pevent; + struct tep_handle *pevent = event->pevent; struct print_flag_sym *flag; struct format_field *field; struct printk_map *printk; @@ -3899,7 +3885,7 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, case PRINT_FIELD: field = arg->field.field; if (!field) { - field = pevent_find_any_field(event, arg->field.name); + field = tep_find_any_field(event, arg->field.name); if (!field) { str = arg->field.name; goto out_warning_field; @@ -3992,7 +3978,7 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, case PRINT_HEX_STR: if (arg->hex.field->type == PRINT_DYNAMIC_ARRAY) { unsigned long offset; - offset = pevent_read_number(pevent, + offset = tep_read_number(pevent, data + arg->hex.field->dynarray.field->offset, arg->hex.field->dynarray.field->size); hex = data + (offset & 0xffff); @@ -4000,7 +3986,7 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, field = arg->hex.field->field.field; if (!field) { str = arg->hex.field->field.name; - field = pevent_find_any_field(event, str); + field = tep_find_any_field(event, str); if (!field) goto out_warning_field; arg->hex.field->field.field = field; @@ -4023,15 +4009,15 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, unsigned long offset; struct format_field *field = arg->int_array.field->dynarray.field; - offset = pevent_read_number(pevent, - data + field->offset, - field->size); + offset = tep_read_number(pevent, + data + field->offset, + field->size); num = data + (offset & 0xffff); } else { field = arg->int_array.field->field.field; if (!field) { str = arg->int_array.field->field.name; - field = pevent_find_any_field(event, str); + field = tep_find_any_field(event, str); if (!field) goto out_warning_field; arg->int_array.field->field.field = field; @@ -4071,7 +4057,7 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, if (arg->string.offset == -1) { struct format_field *f; - f = pevent_find_any_field(event, arg->string.string); + f = tep_find_any_field(event, arg->string.string); arg->string.offset = f->offset; } str_offset = data2host4(pevent, data + arg->string.offset); @@ -4089,7 +4075,7 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, if (arg->bitmask.offset == -1) { struct format_field *f; - f = pevent_find_any_field(event, arg->bitmask.bitmask); + f = tep_find_any_field(event, arg->bitmask.bitmask); arg->bitmask.offset = f->offset; } bitmask_offset = data2host4(pevent, data + arg->bitmask.offset); @@ -4132,8 +4118,8 @@ static unsigned long long process_defined_func(struct trace_seq *s, void *data, int size, struct event_format *event, struct print_arg *arg) { - struct pevent_function_handler *func_handle = arg->func.func; - struct pevent_func_params *param; + struct tep_function_handler *func_handle = arg->func.func; + struct func_params *param; unsigned long long *args; unsigned long long ret; struct print_arg *farg; @@ -4159,12 +4145,12 @@ process_defined_func(struct trace_seq *s, void *data, int size, for (i = 0; i < func_handle->nr_args; i++) { switch (param->type) { - case PEVENT_FUNC_ARG_INT: - case PEVENT_FUNC_ARG_LONG: - case PEVENT_FUNC_ARG_PTR: + case TEP_FUNC_ARG_INT: + case TEP_FUNC_ARG_LONG: + case TEP_FUNC_ARG_PTR: args[i] = eval_num_arg(data, size, event, farg); break; - case PEVENT_FUNC_ARG_STRING: + case TEP_FUNC_ARG_STRING: trace_seq_init(&str); print_str_arg(&str, data, size, event, "%s", -1, farg); trace_seq_terminate(&str); @@ -4227,7 +4213,7 @@ static void free_args(struct print_arg *args) static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struct event_format *event) { - struct pevent *pevent = event->pevent; + struct tep_handle *pevent = event->pevent; struct format_field *field, *ip_field; struct print_arg *args, *arg, **next; unsigned long long ip, val; @@ -4239,12 +4225,12 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc ip_field = pevent->bprint_ip_field; if (!field) { - field = pevent_find_field(event, "buf"); + field = tep_find_field(event, "buf"); if (!field) { do_warning_event(event, "can't find buffer field for binary printk"); return NULL; } - ip_field = pevent_find_field(event, "ip"); + ip_field = tep_find_field(event, "ip"); if (!ip_field) { do_warning_event(event, "can't find ip field for binary printk"); return NULL; @@ -4253,7 +4239,7 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc pevent->bprint_ip_field = ip_field; } - ip = pevent_read_number(pevent, data + ip_field->offset, ip_field->size); + ip = tep_read_number(pevent, data + ip_field->offset, ip_field->size); /* * The first arg is the IP pointer. @@ -4347,7 +4333,7 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc /* the pointers are always 4 bytes aligned */ bptr = (void *)(((unsigned long)bptr + 3) & ~3); - val = pevent_read_number(pevent, bptr, vsize); + val = tep_read_number(pevent, bptr, vsize); bptr += vsize; arg = alloc_arg(); if (!arg) { @@ -4404,7 +4390,7 @@ static char * get_bprint_format(void *data, int size __maybe_unused, struct event_format *event) { - struct pevent *pevent = event->pevent; + struct tep_handle *pevent = event->pevent; unsigned long long addr; struct format_field *field; struct printk_map *printk; @@ -4413,7 +4399,7 @@ get_bprint_format(void *data, int size __maybe_unused, field = pevent->bprint_fmt_field; if (!field) { - field = pevent_find_field(event, "fmt"); + field = tep_find_field(event, "fmt"); if (!field) { do_warning_event(event, "can't find format field for binary printk"); return NULL; @@ -4421,7 +4407,7 @@ get_bprint_format(void *data, int size __maybe_unused, pevent->bprint_fmt_field = field; } - addr = pevent_read_number(pevent, data + field->offset, field->size); + addr = tep_read_number(pevent, data + field->offset, field->size); printk = find_printk(pevent, addr); if (!printk) { @@ -4457,7 +4443,7 @@ static void print_mac_arg(struct trace_seq *s, int mac, void *data, int size, fmt = "%.2x%.2x%.2x%.2x%.2x%.2x"; if (!arg->field.field) { arg->field.field = - pevent_find_any_field(event, arg->field.name); + tep_find_any_field(event, arg->field.name); if (!arg->field.field) { do_warning_event(event, "%s: field %s not found", __func__, arg->field.name); @@ -4607,7 +4593,7 @@ static int print_ipv4_arg(struct trace_seq *s, const char *ptr, char i, if (!arg->field.field) { arg->field.field = - pevent_find_any_field(event, arg->field.name); + tep_find_any_field(event, arg->field.name); if (!arg->field.field) { do_warning("%s: field %s not found", __func__, arg->field.name); @@ -4653,7 +4639,7 @@ static int print_ipv6_arg(struct trace_seq *s, const char *ptr, char i, if (!arg->field.field) { arg->field.field = - pevent_find_any_field(event, arg->field.name); + tep_find_any_field(event, arg->field.name); if (!arg->field.field) { do_warning("%s: field %s not found", __func__, arg->field.name); @@ -4711,7 +4697,7 @@ static int print_ipsa_arg(struct trace_seq *s, const char *ptr, char i, if (!arg->field.field) { arg->field.field = - pevent_find_any_field(event, arg->field.name); + tep_find_any_field(event, arg->field.name); if (!arg->field.field) { do_warning("%s: field %s not found", __func__, arg->field.name); @@ -4800,18 +4786,18 @@ static int is_printable_array(char *p, unsigned int len) return 1; } -void pevent_print_field(struct trace_seq *s, void *data, - struct format_field *field) +void tep_print_field(struct trace_seq *s, void *data, + struct format_field *field) { unsigned long long val; unsigned int offset, len, i; - struct pevent *pevent = field->event->pevent; + struct tep_handle *pevent = field->event->pevent; if (field->flags & FIELD_IS_ARRAY) { offset = field->offset; len = field->size; if (field->flags & FIELD_IS_DYNAMIC) { - val = pevent_read_number(pevent, data + offset, len); + val = tep_read_number(pevent, data + offset, len); offset = val; len = offset >> 16; offset &= 0xffff; @@ -4831,8 +4817,8 @@ void pevent_print_field(struct trace_seq *s, void *data, field->flags &= ~FIELD_IS_STRING; } } else { - val = pevent_read_number(pevent, data + field->offset, - field->size); + val = tep_read_number(pevent, data + field->offset, + field->size); if (field->flags & FIELD_IS_POINTER) { trace_seq_printf(s, "0x%llx", val); } else if (field->flags & FIELD_IS_SIGNED) { @@ -4865,22 +4851,22 @@ void pevent_print_field(struct trace_seq *s, void *data, } } -void pevent_print_fields(struct trace_seq *s, void *data, - int size __maybe_unused, struct event_format *event) +void tep_print_fields(struct trace_seq *s, void *data, + int size __maybe_unused, struct event_format *event) { struct format_field *field; field = event->format.fields; while (field) { trace_seq_printf(s, " %s=", field->name); - pevent_print_field(s, data, field); + tep_print_field(s, data, field); field = field->next; } } static void pretty_print(struct trace_seq *s, void *data, int size, struct event_format *event) { - struct pevent *pevent = event->pevent; + struct tep_handle *pevent = event->pevent; struct print_fmt *print_fmt = &event->print_fmt; struct print_arg *arg = print_fmt->args; struct print_arg *args = NULL; @@ -4899,7 +4885,7 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event if (event->flags & EVENT_FL_FAILED) { trace_seq_printf(s, "[FAILED TO PARSE]"); - pevent_print_fields(s, data, size, event); + tep_print_fields(s, data, size, event); return; } @@ -5140,7 +5126,7 @@ out_failed: } /** - * pevent_data_lat_fmt - parse the data for the latency format + * tep_data_lat_fmt - parse the data for the latency format * @pevent: a handle to the pevent * @s: the trace_seq to write to * @record: the record to read from @@ -5149,8 +5135,8 @@ out_failed: * need rescheduling, in hard/soft interrupt, preempt count * and lock depth) and places it into the trace_seq. */ -void pevent_data_lat_fmt(struct pevent *pevent, - struct trace_seq *s, struct pevent_record *record) +void tep_data_lat_fmt(struct tep_handle *pevent, + struct trace_seq *s, struct tep_record *record) { static int check_lock_depth = 1; static int check_migrate_disable = 1; @@ -5223,55 +5209,55 @@ void pevent_data_lat_fmt(struct pevent *pevent, } /** - * pevent_data_type - parse out the given event type + * tep_data_type - parse out the given event type * @pevent: a handle to the pevent * @rec: the record to read from * * This returns the event id from the @rec. */ -int pevent_data_type(struct pevent *pevent, struct pevent_record *rec) +int tep_data_type(struct tep_handle *pevent, struct tep_record *rec) { return trace_parse_common_type(pevent, rec->data); } /** - * pevent_data_event_from_type - find the event by a given type + * tep_data_event_from_type - find the event by a given type * @pevent: a handle to the pevent * @type: the type of the event. * * This returns the event form a given @type; */ -struct event_format *pevent_data_event_from_type(struct pevent *pevent, int type) +struct event_format *tep_data_event_from_type(struct tep_handle *pevent, int type) { - return pevent_find_event(pevent, type); + return tep_find_event(pevent, type); } /** - * pevent_data_pid - parse the PID from record + * tep_data_pid - parse the PID from record * @pevent: a handle to the pevent * @rec: the record to parse * * This returns the PID from a record. */ -int pevent_data_pid(struct pevent *pevent, struct pevent_record *rec) +int tep_data_pid(struct tep_handle *pevent, struct tep_record *rec) { return parse_common_pid(pevent, rec->data); } /** - * pevent_data_preempt_count - parse the preempt count from the record + * tep_data_preempt_count - parse the preempt count from the record * @pevent: a handle to the pevent * @rec: the record to parse * * This returns the preempt count from a record. */ -int pevent_data_preempt_count(struct pevent *pevent, struct pevent_record *rec) +int tep_data_preempt_count(struct tep_handle *pevent, struct tep_record *rec) { return parse_common_pc(pevent, rec->data); } /** - * pevent_data_flags - parse the latency flags from the record + * tep_data_flags - parse the latency flags from the record * @pevent: a handle to the pevent * @rec: the record to parse * @@ -5279,20 +5265,20 @@ int pevent_data_preempt_count(struct pevent *pevent, struct pevent_record *rec) * * Use trace_flag_type enum for the flags (see event-parse.h). */ -int pevent_data_flags(struct pevent *pevent, struct pevent_record *rec) +int tep_data_flags(struct tep_handle *pevent, struct tep_record *rec) { return parse_common_flags(pevent, rec->data); } /** - * pevent_data_comm_from_pid - return the command line from PID + * tep_data_comm_from_pid - return the command line from PID * @pevent: a handle to the pevent * @pid: the PID of the task to search for * * This returns a pointer to the command line that has the given * @pid. */ -const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid) +const char *tep_data_comm_from_pid(struct tep_handle *pevent, int pid) { const char *comm; @@ -5301,7 +5287,7 @@ const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid) } static struct cmdline * -pid_from_cmdlist(struct pevent *pevent, const char *comm, struct cmdline *next) +pid_from_cmdlist(struct tep_handle *pevent, const char *comm, struct cmdline *next) { struct cmdline_list *cmdlist = (struct cmdline_list *)next; @@ -5317,7 +5303,7 @@ pid_from_cmdlist(struct pevent *pevent, const char *comm, struct cmdline *next) } /** - * pevent_data_pid_from_comm - return the pid from a given comm + * tep_data_pid_from_comm - return the pid from a given comm * @pevent: a handle to the pevent * @comm: the cmdline to find the pid from * @next: the cmdline structure to find the next comm @@ -5329,8 +5315,8 @@ pid_from_cmdlist(struct pevent *pevent, const char *comm, struct cmdline *next) * next pid. * Also, it does a linear seach, so it may be slow. */ -struct cmdline *pevent_data_pid_from_comm(struct pevent *pevent, const char *comm, - struct cmdline *next) +struct cmdline *tep_data_pid_from_comm(struct tep_handle *pevent, const char *comm, + struct cmdline *next) { struct cmdline *cmdline; @@ -5365,13 +5351,13 @@ struct cmdline *pevent_data_pid_from_comm(struct pevent *pevent, const char *com } /** - * pevent_cmdline_pid - return the pid associated to a given cmdline + * tep_cmdline_pid - return the pid associated to a given cmdline * @cmdline: The cmdline structure to get the pid from * * Returns the pid for a give cmdline. If @cmdline is NULL, then * -1 is returned. */ -int pevent_cmdline_pid(struct pevent *pevent, struct cmdline *cmdline) +int tep_cmdline_pid(struct tep_handle *pevent, struct cmdline *cmdline) { struct cmdline_list *cmdlist = (struct cmdline_list *)cmdline; @@ -5391,7 +5377,7 @@ int pevent_cmdline_pid(struct pevent *pevent, struct cmdline *cmdline) } /** - * pevent_data_comm_from_pid - parse the data into the print format + * tep_event_info - parse the data into the print format * @s: the trace_seq to write to * @event: the handle to the event * @record: the record to read from @@ -5399,13 +5385,13 @@ int pevent_cmdline_pid(struct pevent *pevent, struct cmdline *cmdline) * This parses the raw @data using the given @event information and * writes the print format into the trace_seq. */ -void pevent_event_info(struct trace_seq *s, struct event_format *event, - struct pevent_record *record) +void tep_event_info(struct trace_seq *s, struct event_format *event, + struct tep_record *record) { int print_pretty = 1; if (event->pevent->print_raw || (event->flags & EVENT_FL_PRINTRAW)) - pevent_print_fields(s, record->data, record->size, event); + tep_print_fields(s, record->data, record->size, event); else { if (event->handler && !(event->flags & EVENT_FL_NOHANDLE)) @@ -5433,7 +5419,7 @@ static bool is_timestamp_in_us(char *trace_clock, bool use_trace_clock) } /** - * pevent_find_event_by_record - return the event from a given record + * tep_find_event_by_record - return the event from a given record * @pevent: a handle to the pevent * @record: The record to get the event from * @@ -5441,7 +5427,7 @@ static bool is_timestamp_in_us(char *trace_clock, bool use_trace_clock) * is found. */ struct event_format * -pevent_find_event_by_record(struct pevent *pevent, struct pevent_record *record) +tep_find_event_by_record(struct tep_handle *pevent, struct tep_record *record) { int type; @@ -5452,11 +5438,11 @@ pevent_find_event_by_record(struct pevent *pevent, struct pevent_record *record) type = trace_parse_common_type(pevent, record->data); - return pevent_find_event(pevent, type); + return tep_find_event(pevent, type); } /** - * pevent_print_event_task - Write the event task comm, pid and CPU + * tep_print_event_task - Write the event task comm, pid and CPU * @pevent: a handle to the pevent * @s: the trace_seq to write to * @event: the handle to the record's event @@ -5464,9 +5450,9 @@ pevent_find_event_by_record(struct pevent *pevent, struct pevent_record *record) * * Writes the tasks comm, pid and CPU to @s. */ -void pevent_print_event_task(struct pevent *pevent, struct trace_seq *s, - struct event_format *event, - struct pevent_record *record) +void tep_print_event_task(struct tep_handle *pevent, struct trace_seq *s, + struct event_format *event, + struct tep_record *record) { void *data = record->data; const char *comm; @@ -5483,7 +5469,7 @@ void pevent_print_event_task(struct pevent *pevent, struct trace_seq *s, } /** - * pevent_print_event_time - Write the event timestamp + * tep_print_event_time - Write the event timestamp * @pevent: a handle to the pevent * @s: the trace_seq to write to * @event: the handle to the record's event @@ -5492,10 +5478,10 @@ void pevent_print_event_task(struct pevent *pevent, struct trace_seq *s, * * Writes the timestamp of the record into @s. */ -void pevent_print_event_time(struct pevent *pevent, struct trace_seq *s, - struct event_format *event, - struct pevent_record *record, - bool use_trace_clock) +void tep_print_event_time(struct tep_handle *pevent, struct trace_seq *s, + struct event_format *event, + struct tep_record *record, + bool use_trace_clock) { unsigned long secs; unsigned long usecs; @@ -5511,11 +5497,11 @@ void pevent_print_event_time(struct pevent *pevent, struct trace_seq *s, } if (pevent->latency_format) { - pevent_data_lat_fmt(pevent, s, record); + tep_data_lat_fmt(pevent, s, record); } if (use_usec_format) { - if (pevent->flags & PEVENT_NSEC_OUTPUT) { + if (pevent->flags & TEP_NSEC_OUTPUT) { usecs = nsecs; p = 9; } else { @@ -5534,7 +5520,7 @@ void pevent_print_event_time(struct pevent *pevent, struct trace_seq *s, } /** - * pevent_print_event_data - Write the event data section + * tep_print_event_data - Write the event data section * @pevent: a handle to the pevent * @s: the trace_seq to write to * @event: the handle to the record's event @@ -5542,9 +5528,9 @@ void pevent_print_event_time(struct pevent *pevent, struct trace_seq *s, * * Writes the parsing of the record's data to @s. */ -void pevent_print_event_data(struct pevent *pevent, struct trace_seq *s, - struct event_format *event, - struct pevent_record *record) +void tep_print_event_data(struct tep_handle *pevent, struct trace_seq *s, + struct event_format *event, + struct tep_record *record) { static const char *spaces = " "; /* 20 spaces */ int len; @@ -5556,15 +5542,15 @@ void pevent_print_event_data(struct pevent *pevent, struct trace_seq *s, if (len < 20) trace_seq_printf(s, "%.*s", 20 - len, spaces); - pevent_event_info(s, event, record); + tep_event_info(s, event, record); } -void pevent_print_event(struct pevent *pevent, struct trace_seq *s, - struct pevent_record *record, bool use_trace_clock) +void tep_print_event(struct tep_handle *pevent, struct trace_seq *s, + struct tep_record *record, bool use_trace_clock) { struct event_format *event; - event = pevent_find_event_by_record(pevent, record); + event = tep_find_event_by_record(pevent, record); if (!event) { int i; int type = trace_parse_common_type(pevent, record->data); @@ -5577,9 +5563,9 @@ void pevent_print_event(struct pevent *pevent, struct trace_seq *s, return; } - pevent_print_event_task(pevent, s, event, record); - pevent_print_event_time(pevent, s, event, record, use_trace_clock); - pevent_print_event_data(pevent, s, event, record); + tep_print_event_task(pevent, s, event, record); + tep_print_event_time(pevent, s, event, record, use_trace_clock); + tep_print_event_data(pevent, s, event, record); } static int events_id_cmp(const void *a, const void *b) @@ -5630,7 +5616,7 @@ static int events_system_cmp(const void *a, const void *b) return events_id_cmp(a, b); } -struct event_format **pevent_list_events(struct pevent *pevent, enum event_sort_type sort_type) +struct event_format **tep_list_events(struct tep_handle *pevent, enum event_sort_type sort_type) { struct event_format **events; int (*sort)(const void *a, const void *b); @@ -5709,13 +5695,13 @@ get_event_fields(const char *type, const char *name, } /** - * pevent_event_common_fields - return a list of common fields for an event + * tep_event_common_fields - return a list of common fields for an event * @event: the event to return the common fields of. * * Returns an allocated array of fields. The last item in the array is NULL. * The array must be freed with free(). */ -struct format_field **pevent_event_common_fields(struct event_format *event) +struct format_field **tep_event_common_fields(struct event_format *event) { return get_event_fields("common", event->name, event->format.nr_common, @@ -5723,13 +5709,13 @@ struct format_field **pevent_event_common_fields(struct event_format *event) } /** - * pevent_event_fields - return a list of event specific fields for an event + * tep_event_fields - return a list of event specific fields for an event * @event: the event to return the fields of. * * Returns an allocated array of fields. The last item in the array is NULL. * The array must be freed with free(). */ -struct format_field **pevent_event_fields(struct event_format *event) +struct format_field **tep_event_fields(struct event_format *event) { return get_event_fields("event", event->name, event->format.nr_fields, @@ -5930,7 +5916,7 @@ static void parse_header_field(const char *field, } /** - * pevent_parse_header_page - parse the data stored in the header page + * tep_parse_header_page - parse the data stored in the header page * @pevent: the handle to the pevent * @buf: the buffer storing the header page format string * @size: the size of @buf @@ -5941,8 +5927,8 @@ static void parse_header_field(const char *field, * * /sys/kernel/debug/tracing/events/header_page */ -int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long size, - int long_size) +int tep_parse_header_page(struct tep_handle *pevent, char *buf, unsigned long size, + int long_size) { int ignore; @@ -5994,7 +5980,7 @@ static void free_handler(struct event_handler *handle) free(handle); } -static int find_event_handle(struct pevent *pevent, struct event_format *event) +static int find_event_handle(struct tep_handle *pevent, struct event_format *event) { struct event_handler *handle, **next; @@ -6023,7 +6009,7 @@ static int find_event_handle(struct pevent *pevent, struct event_format *event) } /** - * __pevent_parse_format - parse the event format + * __tep_parse_format - parse the event format * @buf: the buffer storing the event format string * @size: the size of @buf * @sys: the system the event belongs to @@ -6035,9 +6021,9 @@ static int find_event_handle(struct pevent *pevent, struct event_format *event) * * /sys/kernel/debug/tracing/events/.../.../format */ -enum pevent_errno __pevent_parse_format(struct event_format **eventp, - struct pevent *pevent, const char *buf, - unsigned long size, const char *sys) +enum tep_errno __tep_parse_format(struct event_format **eventp, + struct tep_handle *pevent, const char *buf, + unsigned long size, const char *sys) { struct event_format *event; int ret; @@ -6046,12 +6032,12 @@ enum pevent_errno __pevent_parse_format(struct event_format **eventp, *eventp = event = alloc_event(); if (!event) - return PEVENT_ERRNO__MEM_ALLOC_FAILED; + return TEP_ERRNO__MEM_ALLOC_FAILED; event->name = event_read_name(); if (!event->name) { /* Bad event? */ - ret = PEVENT_ERRNO__MEM_ALLOC_FAILED; + ret = TEP_ERRNO__MEM_ALLOC_FAILED; goto event_alloc_failed; } @@ -6064,7 +6050,7 @@ enum pevent_errno __pevent_parse_format(struct event_format **eventp, event->id = event_read_id(); if (event->id < 0) { - ret = PEVENT_ERRNO__READ_ID_FAILED; + ret = TEP_ERRNO__READ_ID_FAILED; /* * This isn't an allocation error actually. * But as the ID is critical, just bail out. @@ -6074,7 +6060,7 @@ enum pevent_errno __pevent_parse_format(struct event_format **eventp, event->system = strdup(sys); if (!event->system) { - ret = PEVENT_ERRNO__MEM_ALLOC_FAILED; + ret = TEP_ERRNO__MEM_ALLOC_FAILED; goto event_alloc_failed; } @@ -6083,7 +6069,7 @@ enum pevent_errno __pevent_parse_format(struct event_format **eventp, ret = event_read_format(event); if (ret < 0) { - ret = PEVENT_ERRNO__READ_FORMAT_FAILED; + ret = TEP_ERRNO__READ_FORMAT_FAILED; goto event_parse_failed; } @@ -6098,7 +6084,7 @@ enum pevent_errno __pevent_parse_format(struct event_format **eventp, show_warning = 1; if (ret < 0) { - ret = PEVENT_ERRNO__READ_PRINT_FAILED; + ret = TEP_ERRNO__READ_PRINT_FAILED; goto event_parse_failed; } @@ -6112,14 +6098,14 @@ enum pevent_errno __pevent_parse_format(struct event_format **eventp, arg = alloc_arg(); if (!arg) { event->flags |= EVENT_FL_FAILED; - return PEVENT_ERRNO__OLD_FTRACE_ARG_FAILED; + return TEP_ERRNO__OLD_FTRACE_ARG_FAILED; } arg->type = PRINT_FIELD; arg->field.name = strdup(field->name); if (!arg->field.name) { event->flags |= EVENT_FL_FAILED; free_arg(arg); - return PEVENT_ERRNO__OLD_FTRACE_ARG_FAILED; + return TEP_ERRNO__OLD_FTRACE_ARG_FAILED; } arg->field.field = field; *list = arg; @@ -6142,20 +6128,20 @@ enum pevent_errno __pevent_parse_format(struct event_format **eventp, return ret; } -static enum pevent_errno -__pevent_parse_event(struct pevent *pevent, - struct event_format **eventp, - const char *buf, unsigned long size, - const char *sys) +static enum tep_errno +__parse_event(struct tep_handle *pevent, + struct event_format **eventp, + const char *buf, unsigned long size, + const char *sys) { - int ret = __pevent_parse_format(eventp, pevent, buf, size, sys); + int ret = __tep_parse_format(eventp, pevent, buf, size, sys); struct event_format *event = *eventp; if (event == NULL) return ret; if (pevent && add_event(pevent, event)) { - ret = PEVENT_ERRNO__MEM_ALLOC_FAILED; + ret = TEP_ERRNO__MEM_ALLOC_FAILED; goto event_add_failed; } @@ -6166,12 +6152,12 @@ __pevent_parse_event(struct pevent *pevent, return 0; event_add_failed: - pevent_free_format(event); + tep_free_format(event); return ret; } /** - * pevent_parse_format - parse the event format + * tep_parse_format - parse the event format * @pevent: the handle to the pevent * @eventp: returned format * @buf: the buffer storing the event format string @@ -6185,16 +6171,16 @@ event_add_failed: * * /sys/kernel/debug/tracing/events/.../.../format */ -enum pevent_errno pevent_parse_format(struct pevent *pevent, - struct event_format **eventp, - const char *buf, - unsigned long size, const char *sys) +enum tep_errno tep_parse_format(struct tep_handle *pevent, + struct event_format **eventp, + const char *buf, + unsigned long size, const char *sys) { - return __pevent_parse_event(pevent, eventp, buf, size, sys); + return __parse_event(pevent, eventp, buf, size, sys); } /** - * pevent_parse_event - parse the event format + * tep_parse_event - parse the event format * @pevent: the handle to the pevent * @buf: the buffer storing the event format string * @size: the size of @buf @@ -6207,22 +6193,22 @@ enum pevent_errno pevent_parse_format(struct pevent *pevent, * * /sys/kernel/debug/tracing/events/.../.../format */ -enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf, - unsigned long size, const char *sys) +enum tep_errno tep_parse_event(struct tep_handle *pevent, const char *buf, + unsigned long size, const char *sys) { struct event_format *event = NULL; - return __pevent_parse_event(pevent, &event, buf, size, sys); + return __parse_event(pevent, &event, buf, size, sys); } #undef _PE #define _PE(code, str) str -static const char * const pevent_error_str[] = { - PEVENT_ERRORS +static const char * const tep_error_str[] = { + TEP_ERRORS }; #undef _PE -int pevent_strerror(struct pevent *pevent __maybe_unused, - enum pevent_errno errnum, char *buf, size_t buflen) +int tep_strerror(struct tep_handle *pevent __maybe_unused, + enum tep_errno errnum, char *buf, size_t buflen) { int idx; const char *msg; @@ -6232,19 +6218,19 @@ int pevent_strerror(struct pevent *pevent __maybe_unused, return 0; } - if (errnum <= __PEVENT_ERRNO__START || - errnum >= __PEVENT_ERRNO__END) + if (errnum <= __TEP_ERRNO__START || + errnum >= __TEP_ERRNO__END) return -1; - idx = errnum - __PEVENT_ERRNO__START - 1; - msg = pevent_error_str[idx]; + idx = errnum - __TEP_ERRNO__START - 1; + msg = tep_error_str[idx]; snprintf(buf, buflen, "%s", msg); return 0; } int get_field_val(struct trace_seq *s, struct format_field *field, - const char *name, struct pevent_record *record, + const char *name, struct tep_record *record, unsigned long long *val, int err) { if (!field) { @@ -6253,7 +6239,7 @@ int get_field_val(struct trace_seq *s, struct format_field *field, return -1; } - if (pevent_read_number_field(field, record->data, val)) { + if (tep_read_number_field(field, record->data, val)) { if (err) trace_seq_printf(s, " %s=INVALID", name); return -1; @@ -6263,7 +6249,7 @@ int get_field_val(struct trace_seq *s, struct format_field *field, } /** - * pevent_get_field_raw - return the raw pointer into the data field + * tep_get_field_raw - return the raw pointer into the data field * @s: The seq to print to on error * @event: the event that the field is for * @name: The name of the field @@ -6276,9 +6262,9 @@ int get_field_val(struct trace_seq *s, struct format_field *field, * * On failure, it returns NULL. */ -void *pevent_get_field_raw(struct trace_seq *s, struct event_format *event, - const char *name, struct pevent_record *record, - int *len, int err) +void *tep_get_field_raw(struct trace_seq *s, struct event_format *event, + const char *name, struct tep_record *record, + int *len, int err) { struct format_field *field; void *data = record->data; @@ -6288,7 +6274,7 @@ void *pevent_get_field_raw(struct trace_seq *s, struct event_format *event, if (!event) return NULL; - field = pevent_find_field(event, name); + field = tep_find_field(event, name); if (!field) { if (err) @@ -6302,7 +6288,7 @@ void *pevent_get_field_raw(struct trace_seq *s, struct event_format *event, offset = field->offset; if (field->flags & FIELD_IS_DYNAMIC) { - offset = pevent_read_number(event->pevent, + offset = tep_read_number(event->pevent, data + offset, field->size); *len = offset >> 16; offset &= 0xffff; @@ -6313,7 +6299,7 @@ void *pevent_get_field_raw(struct trace_seq *s, struct event_format *event, } /** - * pevent_get_field_val - find a field and return its value + * tep_get_field_val - find a field and return its value * @s: The seq to print to on error * @event: the event that the field is for * @name: The name of the field @@ -6323,22 +6309,22 @@ void *pevent_get_field_raw(struct trace_seq *s, struct event_format *event, * * Returns 0 on success -1 on field not found. */ -int pevent_get_field_val(struct trace_seq *s, struct event_format *event, - const char *name, struct pevent_record *record, - unsigned long long *val, int err) +int tep_get_field_val(struct trace_seq *s, struct event_format *event, + const char *name, struct tep_record *record, + unsigned long long *val, int err) { struct format_field *field; if (!event) return -1; - field = pevent_find_field(event, name); + field = tep_find_field(event, name); return get_field_val(s, field, name, record, val, err); } /** - * pevent_get_common_field_val - find a common field and return its value + * tep_get_common_field_val - find a common field and return its value * @s: The seq to print to on error * @event: the event that the field is for * @name: The name of the field @@ -6348,22 +6334,22 @@ int pevent_get_field_val(struct trace_seq *s, struct event_format *event, * * Returns 0 on success -1 on field not found. */ -int pevent_get_common_field_val(struct trace_seq *s, struct event_format *event, - const char *name, struct pevent_record *record, - unsigned long long *val, int err) +int tep_get_common_field_val(struct trace_seq *s, struct event_format *event, + const char *name, struct tep_record *record, + unsigned long long *val, int err) { struct format_field *field; if (!event) return -1; - field = pevent_find_common_field(event, name); + field = tep_find_common_field(event, name); return get_field_val(s, field, name, record, val, err); } /** - * pevent_get_any_field_val - find a any field and return its value + * tep_get_any_field_val - find a any field and return its value * @s: The seq to print to on error * @event: the event that the field is for * @name: The name of the field @@ -6373,22 +6359,22 @@ int pevent_get_common_field_val(struct trace_seq *s, struct event_format *event, * * Returns 0 on success -1 on field not found. */ -int pevent_get_any_field_val(struct trace_seq *s, struct event_format *event, - const char *name, struct pevent_record *record, - unsigned long long *val, int err) +int tep_get_any_field_val(struct trace_seq *s, struct event_format *event, + const char *name, struct tep_record *record, + unsigned long long *val, int err) { struct format_field *field; if (!event) return -1; - field = pevent_find_any_field(event, name); + field = tep_find_any_field(event, name); return get_field_val(s, field, name, record, val, err); } /** - * pevent_print_num_field - print a field and a format + * tep_print_num_field - print a field and a format * @s: The seq to print to * @fmt: The printf format to print the field with. * @event: the event that the field is for @@ -6398,17 +6384,17 @@ int pevent_get_any_field_val(struct trace_seq *s, struct event_format *event, * * Returns: 0 on success, -1 field not found, or 1 if buffer is full. */ -int pevent_print_num_field(struct trace_seq *s, const char *fmt, - struct event_format *event, const char *name, - struct pevent_record *record, int err) +int tep_print_num_field(struct trace_seq *s, const char *fmt, + struct event_format *event, const char *name, + struct tep_record *record, int err) { - struct format_field *field = pevent_find_field(event, name); + struct format_field *field = tep_find_field(event, name); unsigned long long val; if (!field) goto failed; - if (pevent_read_number_field(field, record->data, &val)) + if (tep_read_number_field(field, record->data, &val)) goto failed; return trace_seq_printf(s, fmt, val); @@ -6420,7 +6406,7 @@ int pevent_print_num_field(struct trace_seq *s, const char *fmt, } /** - * pevent_print_func_field - print a field and a format for function pointers + * tep_print_func_field - print a field and a format for function pointers * @s: The seq to print to * @fmt: The printf format to print the field with. * @event: the event that the field is for @@ -6430,12 +6416,12 @@ int pevent_print_num_field(struct trace_seq *s, const char *fmt, * * Returns: 0 on success, -1 field not found, or 1 if buffer is full. */ -int pevent_print_func_field(struct trace_seq *s, const char *fmt, - struct event_format *event, const char *name, - struct pevent_record *record, int err) +int tep_print_func_field(struct trace_seq *s, const char *fmt, + struct event_format *event, const char *name, + struct tep_record *record, int err) { - struct format_field *field = pevent_find_field(event, name); - struct pevent *pevent = event->pevent; + struct format_field *field = tep_find_field(event, name); + struct tep_handle *pevent = event->pevent; unsigned long long val; struct func_map *func; char tmp[128]; @@ -6443,7 +6429,7 @@ int pevent_print_func_field(struct trace_seq *s, const char *fmt, if (!field) goto failed; - if (pevent_read_number_field(field, record->data, &val)) + if (tep_read_number_field(field, record->data, &val)) goto failed; func = find_func(pevent, val); @@ -6461,9 +6447,9 @@ int pevent_print_func_field(struct trace_seq *s, const char *fmt, return -1; } -static void free_func_handle(struct pevent_function_handler *func) +static void free_func_handle(struct tep_function_handler *func) { - struct pevent_func_params *params; + struct func_params *params; free(func->name); @@ -6477,29 +6463,29 @@ static void free_func_handle(struct pevent_function_handler *func) } /** - * pevent_register_print_function - register a helper function + * tep_register_print_function - register a helper function * @pevent: the handle to the pevent * @func: the function to process the helper function * @ret_type: the return type of the helper function * @name: the name of the helper function - * @parameters: A list of enum pevent_func_arg_type + * @parameters: A list of enum tep_func_arg_type * * Some events may have helper functions in the print format arguments. * This allows a plugin to dynamically create a way to process one * of these functions. * - * The @parameters is a variable list of pevent_func_arg_type enums that - * must end with PEVENT_FUNC_ARG_VOID. + * The @parameters is a variable list of tep_func_arg_type enums that + * must end with TEP_FUNC_ARG_VOID. */ -int pevent_register_print_function(struct pevent *pevent, - pevent_func_handler func, - enum pevent_func_arg_type ret_type, - char *name, ...) -{ - struct pevent_function_handler *func_handle; - struct pevent_func_params **next_param; - struct pevent_func_params *param; - enum pevent_func_arg_type type; +int tep_register_print_function(struct tep_handle *pevent, + tep_func_handler func, + enum tep_func_arg_type ret_type, + char *name, ...) +{ + struct tep_function_handler *func_handle; + struct func_params **next_param; + struct func_params *param; + enum tep_func_arg_type type; va_list ap; int ret; @@ -6517,7 +6503,7 @@ int pevent_register_print_function(struct pevent *pevent, func_handle = calloc(1, sizeof(*func_handle)); if (!func_handle) { do_warning("Failed to allocate function handler"); - return PEVENT_ERRNO__MEM_ALLOC_FAILED; + return TEP_ERRNO__MEM_ALLOC_FAILED; } func_handle->ret_type = ret_type; @@ -6526,26 +6512,26 @@ int pevent_register_print_function(struct pevent *pevent, if (!func_handle->name) { do_warning("Failed to allocate function name"); free(func_handle); - return PEVENT_ERRNO__MEM_ALLOC_FAILED; + return TEP_ERRNO__MEM_ALLOC_FAILED; } next_param = &(func_handle->params); va_start(ap, name); for (;;) { - type = va_arg(ap, enum pevent_func_arg_type); - if (type == PEVENT_FUNC_ARG_VOID) + type = va_arg(ap, enum tep_func_arg_type); + if (type == TEP_FUNC_ARG_VOID) break; - if (type >= PEVENT_FUNC_ARG_MAX_TYPES) { + if (type >= TEP_FUNC_ARG_MAX_TYPES) { do_warning("Invalid argument type %d", type); - ret = PEVENT_ERRNO__INVALID_ARG_TYPE; + ret = TEP_ERRNO__INVALID_ARG_TYPE; goto out_free; } param = malloc(sizeof(*param)); if (!param) { do_warning("Failed to allocate function param"); - ret = PEVENT_ERRNO__MEM_ALLOC_FAILED; + ret = TEP_ERRNO__MEM_ALLOC_FAILED; goto out_free; } param->type = type; @@ -6569,7 +6555,7 @@ int pevent_register_print_function(struct pevent *pevent, } /** - * pevent_unregister_print_function - unregister a helper function + * tep_unregister_print_function - unregister a helper function * @pevent: the handle to the pevent * @func: the function to process the helper function * @name: the name of the helper function @@ -6578,10 +6564,10 @@ int pevent_register_print_function(struct pevent *pevent, * * Returns 0 if the handler was removed successully, -1 otherwise. */ -int pevent_unregister_print_function(struct pevent *pevent, - pevent_func_handler func, char *name) +int tep_unregister_print_function(struct tep_handle *pevent, + tep_func_handler func, char *name) { - struct pevent_function_handler *func_handle; + struct tep_function_handler *func_handle; func_handle = find_func_handler(pevent, name); if (func_handle && func_handle->func == func) { @@ -6591,15 +6577,15 @@ int pevent_unregister_print_function(struct pevent *pevent, return -1; } -static struct event_format *pevent_search_event(struct pevent *pevent, int id, - const char *sys_name, - const char *event_name) +static struct event_format *search_event(struct tep_handle *pevent, int id, + const char *sys_name, + const char *event_name) { struct event_format *event; if (id >= 0) { /* search by id */ - event = pevent_find_event(pevent, id); + event = tep_find_event(pevent, id); if (!event) return NULL; if (event_name && (strcmp(event_name, event->name) != 0)) @@ -6607,7 +6593,7 @@ static struct event_format *pevent_search_event(struct pevent *pevent, int id, if (sys_name && (strcmp(sys_name, event->system) != 0)) return NULL; } else { - event = pevent_find_event_by_name(pevent, sys_name, event_name); + event = tep_find_event_by_name(pevent, sys_name, event_name); if (!event) return NULL; } @@ -6615,7 +6601,7 @@ static struct event_format *pevent_search_event(struct pevent *pevent, int id, } /** - * pevent_register_event_handler - register a way to parse an event + * tep_register_event_handler - register a way to parse an event * @pevent: the handle to the pevent * @id: the id of the event to register * @sys_name: the system name the event belongs to @@ -6631,14 +6617,14 @@ static struct event_format *pevent_search_event(struct pevent *pevent, int id, * If @id is >= 0, then it is used to find the event. * else @sys_name and @event_name are used. */ -int pevent_register_event_handler(struct pevent *pevent, int id, - const char *sys_name, const char *event_name, - pevent_event_handler_func func, void *context) +int tep_register_event_handler(struct tep_handle *pevent, int id, + const char *sys_name, const char *event_name, + tep_event_handler_func func, void *context) { struct event_format *event; struct event_handler *handle; - event = pevent_search_event(pevent, id, sys_name, event_name); + event = search_event(pevent, id, sys_name, event_name); if (event == NULL) goto not_found; @@ -6654,7 +6640,7 @@ int pevent_register_event_handler(struct pevent *pevent, int id, handle = calloc(1, sizeof(*handle)); if (!handle) { do_warning("Failed to allocate event handler"); - return PEVENT_ERRNO__MEM_ALLOC_FAILED; + return TEP_ERRNO__MEM_ALLOC_FAILED; } handle->id = id; @@ -6669,7 +6655,7 @@ int pevent_register_event_handler(struct pevent *pevent, int id, free((void *)handle->event_name); free((void *)handle->sys_name); free(handle); - return PEVENT_ERRNO__MEM_ALLOC_FAILED; + return TEP_ERRNO__MEM_ALLOC_FAILED; } handle->func = func; @@ -6682,7 +6668,7 @@ int pevent_register_event_handler(struct pevent *pevent, int id, static int handle_matches(struct event_handler *handler, int id, const char *sys_name, const char *event_name, - pevent_event_handler_func func, void *context) + tep_event_handler_func func, void *context) { if (id >= 0 && id != handler->id) return 0; @@ -6700,7 +6686,7 @@ static int handle_matches(struct event_handler *handler, int id, } /** - * pevent_unregister_event_handler - unregister an existing event handler + * tep_unregister_event_handler - unregister an existing event handler * @pevent: the handle to the pevent * @id: the id of the event to unregister * @sys_name: the system name the handler belongs to @@ -6715,15 +6701,15 @@ static int handle_matches(struct event_handler *handler, int id, * * Returns 0 if handler was removed successfully, -1 if event was not found. */ -int pevent_unregister_event_handler(struct pevent *pevent, int id, - const char *sys_name, const char *event_name, - pevent_event_handler_func func, void *context) +int tep_unregister_event_handler(struct tep_handle *pevent, int id, + const char *sys_name, const char *event_name, + tep_event_handler_func func, void *context) { struct event_format *event; struct event_handler *handle; struct event_handler **next; - event = pevent_search_event(pevent, id, sys_name, event_name); + event = search_event(pevent, id, sys_name, event_name); if (event == NULL) goto not_found; @@ -6754,11 +6740,11 @@ not_found: } /** - * pevent_alloc - create a pevent handle + * tep_alloc - create a pevent handle */ -struct pevent *pevent_alloc(void) +struct tep_handle *tep_alloc(void) { - struct pevent *pevent = calloc(1, sizeof(*pevent)); + struct tep_handle *pevent = calloc(1, sizeof(*pevent)); if (pevent) pevent->ref_count = 1; @@ -6766,12 +6752,12 @@ struct pevent *pevent_alloc(void) return pevent; } -void pevent_ref(struct pevent *pevent) +void tep_ref(struct tep_handle *pevent) { pevent->ref_count++; } -void pevent_free_format_field(struct format_field *field) +void tep_free_format_field(struct format_field *field) { free(field->type); if (field->alias != field->name) @@ -6786,7 +6772,7 @@ static void free_format_fields(struct format_field *field) while (field) { next = field->next; - pevent_free_format_field(field); + tep_free_format_field(field); field = next; } } @@ -6797,7 +6783,7 @@ static void free_formats(struct format *format) free_format_fields(format->fields); } -void pevent_free_format(struct event_format *event) +void tep_free_format(struct event_format *event) { free(event->name); free(event->system); @@ -6811,15 +6797,15 @@ void pevent_free_format(struct event_format *event) } /** - * pevent_free - free a pevent handle + * tep_free - free a pevent handle * @pevent: the pevent handle to free */ -void pevent_free(struct pevent *pevent) +void tep_free(struct tep_handle *pevent) { struct cmdline_list *cmdlist, *cmdnext; struct func_list *funclist, *funcnext; struct printk_list *printklist, *printknext; - struct pevent_function_handler *func_handler; + struct tep_function_handler *func_handler; struct event_handler *handle; int i; @@ -6883,7 +6869,7 @@ void pevent_free(struct pevent *pevent) } for (i = 0; i < pevent->nr_events; i++) - pevent_free_format(pevent->events[i]); + tep_free_format(pevent->events[i]); while (pevent->handlers) { handle = pevent->handlers; @@ -6899,7 +6885,7 @@ void pevent_free(struct pevent *pevent) free(pevent); } -void pevent_unref(struct pevent *pevent) +void tep_unref(struct tep_handle *pevent) { - pevent_free(pevent); + tep_free(pevent); } diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index 0c03538df74c..44b7c2d41f9f 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h @@ -41,7 +41,7 @@ #define DEBUG_RECORD 0 #endif -struct pevent_record { +struct tep_record { unsigned long long ts; unsigned long long offset; long long missed_events; /* buffer dropped events before */ @@ -53,8 +53,8 @@ struct pevent_record { int locked; /* Do not free, even if ref_count is zero */ void *priv; #if DEBUG_RECORD - struct pevent_record *prev; - struct pevent_record *next; + struct tep_record *prev; + struct tep_record *next; long alloc_addr; #endif }; @@ -98,19 +98,19 @@ extern int trace_seq_do_printf(struct trace_seq *s); /* ----------------------- pevent ----------------------- */ -struct pevent; +struct tep_handle; struct event_format; -typedef int (*pevent_event_handler_func)(struct trace_seq *s, - struct pevent_record *record, - struct event_format *event, - void *context); +typedef int (*tep_event_handler_func)(struct trace_seq *s, + struct tep_record *record, + struct event_format *event, + void *context); -typedef int (*pevent_plugin_load_func)(struct pevent *pevent); -typedef int (*pevent_plugin_unload_func)(struct pevent *pevent); +typedef int (*tep_plugin_load_func)(struct tep_handle *pevent); +typedef int (*tep_plugin_unload_func)(struct tep_handle *pevent); -struct pevent_plugin_option { - struct pevent_plugin_option *next; +struct tep_plugin_option { + struct tep_plugin_option *next; void *handle; char *file; char *name; @@ -124,20 +124,20 @@ struct pevent_plugin_option { /* * Plugin hooks that can be called: * - * PEVENT_PLUGIN_LOADER: (required) + * TEP_PLUGIN_LOADER: (required) * The function name to initialized the plugin. * - * int PEVENT_PLUGIN_LOADER(struct pevent *pevent) + * int TEP_PLUGIN_LOADER(struct tep_handle *pevent) * - * PEVENT_PLUGIN_UNLOADER: (optional) + * TEP_PLUGIN_UNLOADER: (optional) * The function called just before unloading * - * int PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) + * int TEP_PLUGIN_UNLOADER(struct tep_handle *pevent) * - * PEVENT_PLUGIN_OPTIONS: (optional) + * TEP_PLUGIN_OPTIONS: (optional) * Plugin options that can be set before loading * - * struct pevent_plugin_option PEVENT_PLUGIN_OPTIONS[] = { + * struct tep_plugin_option TEP_PLUGIN_OPTIONS[] = { * { * .name = "option-name", * .plugin_alias = "override-file-name", (optional) @@ -158,19 +158,19 @@ struct pevent_plugin_option { * .set will be processed. If .value is defined, then it is considered * a string option and .set will be ignored. * - * PEVENT_PLUGIN_ALIAS: (optional) + * TEP_PLUGIN_ALIAS: (optional) * The name to use for finding options (uses filename if not defined) */ -#define PEVENT_PLUGIN_LOADER pevent_plugin_loader -#define PEVENT_PLUGIN_UNLOADER pevent_plugin_unloader -#define PEVENT_PLUGIN_OPTIONS pevent_plugin_options -#define PEVENT_PLUGIN_ALIAS pevent_plugin_alias +#define TEP_PLUGIN_LOADER tep_plugin_loader +#define TEP_PLUGIN_UNLOADER tep_plugin_unloader +#define TEP_PLUGIN_OPTIONS tep_plugin_options +#define TEP_PLUGIN_ALIAS tep_plugin_alias #define _MAKE_STR(x) #x #define MAKE_STR(x) _MAKE_STR(x) -#define PEVENT_PLUGIN_LOADER_NAME MAKE_STR(PEVENT_PLUGIN_LOADER) -#define PEVENT_PLUGIN_UNLOADER_NAME MAKE_STR(PEVENT_PLUGIN_UNLOADER) -#define PEVENT_PLUGIN_OPTIONS_NAME MAKE_STR(PEVENT_PLUGIN_OPTIONS) -#define PEVENT_PLUGIN_ALIAS_NAME MAKE_STR(PEVENT_PLUGIN_ALIAS) +#define TEP_PLUGIN_LOADER_NAME MAKE_STR(TEP_PLUGIN_LOADER) +#define TEP_PLUGIN_UNLOADER_NAME MAKE_STR(TEP_PLUGIN_UNLOADER) +#define TEP_PLUGIN_OPTIONS_NAME MAKE_STR(TEP_PLUGIN_OPTIONS) +#define TEP_PLUGIN_ALIAS_NAME MAKE_STR(TEP_PLUGIN_ALIAS) enum format_flags { FIELD_IS_ARRAY = 1, @@ -269,10 +269,10 @@ struct print_arg_op { struct print_arg *right; }; -struct pevent_function_handler; +struct tep_function_handler; struct print_arg_func { - struct pevent_function_handler *func; + struct tep_function_handler *func; struct print_arg *args; }; @@ -320,14 +320,14 @@ struct print_fmt { }; struct event_format { - struct pevent *pevent; + struct tep_handle *pevent; char *name; int id; int flags; struct format format; struct print_fmt print_fmt; char *system; - pevent_event_handler_func handler; + tep_event_handler_func handler; void *context; }; @@ -361,25 +361,25 @@ enum event_type { EVENT_SQUOTE, }; -typedef unsigned long long (*pevent_func_handler)(struct trace_seq *s, - unsigned long long *args); +typedef unsigned long long (*tep_func_handler)(struct trace_seq *s, + unsigned long long *args); -enum pevent_func_arg_type { - PEVENT_FUNC_ARG_VOID, - PEVENT_FUNC_ARG_INT, - PEVENT_FUNC_ARG_LONG, - PEVENT_FUNC_ARG_STRING, - PEVENT_FUNC_ARG_PTR, - PEVENT_FUNC_ARG_MAX_TYPES +enum tep_func_arg_type { + TEP_FUNC_ARG_VOID, + TEP_FUNC_ARG_INT, + TEP_FUNC_ARG_LONG, + TEP_FUNC_ARG_STRING, + TEP_FUNC_ARG_PTR, + TEP_FUNC_ARG_MAX_TYPES }; -enum pevent_flag { - PEVENT_NSEC_OUTPUT = 1, /* output in NSECS */ - PEVENT_DISABLE_SYS_PLUGINS = 1 << 1, - PEVENT_DISABLE_PLUGINS = 1 << 2, +enum tep_flag { + TEP_NSEC_OUTPUT = 1, /* output in NSECS */ + TEP_DISABLE_SYS_PLUGINS = 1 << 1, + TEP_DISABLE_PLUGINS = 1 << 2, }; -#define PEVENT_ERRORS \ +#define TEP_ERRORS \ _PE(MEM_ALLOC_FAILED, "failed to allocate memory"), \ _PE(PARSE_EVENT_FAILED, "failed to parse event"), \ _PE(READ_ID_FAILED, "failed to read event id"), \ @@ -411,10 +411,10 @@ enum pevent_flag { _PE(FILTER_MISS, "record does not match to filter") #undef _PE -#define _PE(__code, __str) PEVENT_ERRNO__ ## __code -enum pevent_errno { - PEVENT_ERRNO__SUCCESS = 0, - PEVENT_ERRNO__FILTER_MATCH = PEVENT_ERRNO__SUCCESS, +#define _PE(__code, __str) TEP_ERRNO__ ## __code +enum tep_errno { + TEP_ERRNO__SUCCESS = 0, + TEP_ERRNO__FILTER_MATCH = TEP_ERRNO__SUCCESS, /* * Choose an arbitrary negative big number not to clash with standard @@ -423,11 +423,11 @@ enum pevent_errno { * * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html */ - __PEVENT_ERRNO__START = -100000, + __TEP_ERRNO__START = -100000, - PEVENT_ERRORS, + TEP_ERRORS, - __PEVENT_ERRNO__END, + __TEP_ERRNO__END, }; #undef _PE @@ -435,17 +435,17 @@ struct plugin_list; #define INVALID_PLUGIN_LIST_OPTION ((char **)((unsigned long)-1)) -struct plugin_list *traceevent_load_plugins(struct pevent *pevent); -void traceevent_unload_plugins(struct plugin_list *plugin_list, - struct pevent *pevent); -char **traceevent_plugin_list_options(void); -void traceevent_plugin_free_options_list(char **list); -int traceevent_plugin_add_options(const char *name, - struct pevent_plugin_option *options); -void traceevent_plugin_remove_options(struct pevent_plugin_option *options); -void traceevent_print_plugins(struct trace_seq *s, - const char *prefix, const char *suffix, - const struct plugin_list *list); +struct plugin_list *tep_load_plugins(struct tep_handle *pevent); +void tep_unload_plugins(struct plugin_list *plugin_list, + struct tep_handle *pevent); +char **tep_plugin_list_options(void); +void tep_plugin_free_options_list(char **list); +int tep_plugin_add_options(const char *name, + struct tep_plugin_option *options); +void tep_plugin_remove_options(struct tep_plugin_option *options); +void tep_print_plugins(struct trace_seq *s, + const char *prefix, const char *suffix, + const struct plugin_list *list); struct cmdline; struct cmdline_list; @@ -454,10 +454,10 @@ struct func_list; struct event_handler; struct func_resolver; -typedef char *(pevent_func_resolver_t)(void *priv, - unsigned long long *addrp, char **modp); +typedef char *(tep_func_resolver_t)(void *priv, + unsigned long long *addrp, char **modp); -struct pevent { +struct tep_handle { int ref_count; int header_page_ts_offset; @@ -524,7 +524,7 @@ struct pevent { struct format_field *bprint_buf_field; struct event_handler *handlers; - struct pevent_function_handler *func_handlers; + struct tep_function_handler *func_handlers; /* cache */ struct event_format *last_event; @@ -532,13 +532,13 @@ struct pevent { char *trace_clock; }; -static inline void pevent_set_flag(struct pevent *pevent, int flag) +static inline void tep_set_flag(struct tep_handle *pevent, int flag) { pevent->flags |= flag; } static inline unsigned short -__data2host2(struct pevent *pevent, unsigned short data) +__data2host2(struct tep_handle *pevent, unsigned short data) { unsigned short swap; @@ -552,7 +552,7 @@ __data2host2(struct pevent *pevent, unsigned short data) } static inline unsigned int -__data2host4(struct pevent *pevent, unsigned int data) +__data2host4(struct tep_handle *pevent, unsigned int data) { unsigned int swap; @@ -568,7 +568,7 @@ __data2host4(struct pevent *pevent, unsigned int data) } static inline unsigned long long -__data2host8(struct pevent *pevent, unsigned long long data) +__data2host8(struct tep_handle *pevent, unsigned long long data) { unsigned long long swap; @@ -597,7 +597,7 @@ __data2host8(struct pevent *pevent, unsigned long long data) __data2host8(pevent, __val); \ }) -static inline int traceevent_host_bigendian(void) +static inline int tep_host_bigendian(void) { unsigned char str[] = { 0x1, 0x2, 0x3, 0x4 }; unsigned int val; @@ -615,198 +615,198 @@ enum trace_flag_type { TRACE_FLAG_SOFTIRQ = 0x10, }; -int pevent_set_function_resolver(struct pevent *pevent, - pevent_func_resolver_t *func, void *priv); -void pevent_reset_function_resolver(struct pevent *pevent); -int pevent_register_comm(struct pevent *pevent, const char *comm, int pid); -int pevent_register_trace_clock(struct pevent *pevent, const char *trace_clock); -int pevent_register_function(struct pevent *pevent, char *name, - unsigned long long addr, char *mod); -int pevent_register_print_string(struct pevent *pevent, const char *fmt, - unsigned long long addr); -int pevent_pid_is_registered(struct pevent *pevent, int pid); - -void pevent_print_event_task(struct pevent *pevent, struct trace_seq *s, - struct event_format *event, - struct pevent_record *record); -void pevent_print_event_time(struct pevent *pevent, struct trace_seq *s, - struct event_format *event, - struct pevent_record *record, - bool use_trace_clock); -void pevent_print_event_data(struct pevent *pevent, struct trace_seq *s, - struct event_format *event, - struct pevent_record *record); -void pevent_print_event(struct pevent *pevent, struct trace_seq *s, - struct pevent_record *record, bool use_trace_clock); - -int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long size, - int long_size); - -enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf, - unsigned long size, const char *sys); -enum pevent_errno pevent_parse_format(struct pevent *pevent, - struct event_format **eventp, - const char *buf, - unsigned long size, const char *sys); -void pevent_free_format(struct event_format *event); -void pevent_free_format_field(struct format_field *field); - -void *pevent_get_field_raw(struct trace_seq *s, struct event_format *event, - const char *name, struct pevent_record *record, - int *len, int err); - -int pevent_get_field_val(struct trace_seq *s, struct event_format *event, - const char *name, struct pevent_record *record, - unsigned long long *val, int err); -int pevent_get_common_field_val(struct trace_seq *s, struct event_format *event, - const char *name, struct pevent_record *record, - unsigned long long *val, int err); -int pevent_get_any_field_val(struct trace_seq *s, struct event_format *event, - const char *name, struct pevent_record *record, +int tep_set_function_resolver(struct tep_handle *pevent, + tep_func_resolver_t *func, void *priv); +void tep_reset_function_resolver(struct tep_handle *pevent); +int tep_register_comm(struct tep_handle *pevent, const char *comm, int pid); +int tep_register_trace_clock(struct tep_handle *pevent, const char *trace_clock); +int tep_register_function(struct tep_handle *pevent, char *name, + unsigned long long addr, char *mod); +int tep_register_print_string(struct tep_handle *pevent, const char *fmt, + unsigned long long addr); +int tep_pid_is_registered(struct tep_handle *pevent, int pid); + +void tep_print_event_task(struct tep_handle *pevent, struct trace_seq *s, + struct event_format *event, + struct tep_record *record); +void tep_print_event_time(struct tep_handle *pevent, struct trace_seq *s, + struct event_format *event, + struct tep_record *record, + bool use_trace_clock); +void tep_print_event_data(struct tep_handle *pevent, struct trace_seq *s, + struct event_format *event, + struct tep_record *record); +void tep_print_event(struct tep_handle *pevent, struct trace_seq *s, + struct tep_record *record, bool use_trace_clock); + +int tep_parse_header_page(struct tep_handle *pevent, char *buf, unsigned long size, + int long_size); + +enum tep_errno tep_parse_event(struct tep_handle *pevent, const char *buf, + unsigned long size, const char *sys); +enum tep_errno tep_parse_format(struct tep_handle *pevent, + struct event_format **eventp, + const char *buf, + unsigned long size, const char *sys); +void tep_free_format(struct event_format *event); +void tep_free_format_field(struct format_field *field); + +void *tep_get_field_raw(struct trace_seq *s, struct event_format *event, + const char *name, struct tep_record *record, + int *len, int err); + +int tep_get_field_val(struct trace_seq *s, struct event_format *event, + const char *name, struct tep_record *record, + unsigned long long *val, int err); +int tep_get_common_field_val(struct trace_seq *s, struct event_format *event, + const char *name, struct tep_record *record, unsigned long long *val, int err); +int tep_get_any_field_val(struct trace_seq *s, struct event_format *event, + const char *name, struct tep_record *record, + unsigned long long *val, int err); -int pevent_print_num_field(struct trace_seq *s, const char *fmt, +int tep_print_num_field(struct trace_seq *s, const char *fmt, struct event_format *event, const char *name, - struct pevent_record *record, int err); - -int pevent_print_func_field(struct trace_seq *s, const char *fmt, - struct event_format *event, const char *name, - struct pevent_record *record, int err); - -int pevent_register_event_handler(struct pevent *pevent, int id, - const char *sys_name, const char *event_name, - pevent_event_handler_func func, void *context); -int pevent_unregister_event_handler(struct pevent *pevent, int id, - const char *sys_name, const char *event_name, - pevent_event_handler_func func, void *context); -int pevent_register_print_function(struct pevent *pevent, - pevent_func_handler func, - enum pevent_func_arg_type ret_type, - char *name, ...); -int pevent_unregister_print_function(struct pevent *pevent, - pevent_func_handler func, char *name); - -struct format_field *pevent_find_common_field(struct event_format *event, const char *name); -struct format_field *pevent_find_field(struct event_format *event, const char *name); -struct format_field *pevent_find_any_field(struct event_format *event, const char *name); - -const char *pevent_find_function(struct pevent *pevent, unsigned long long addr); + struct tep_record *record, int err); + +int tep_print_func_field(struct trace_seq *s, const char *fmt, + struct event_format *event, const char *name, + struct tep_record *record, int err); + +int tep_register_event_handler(struct tep_handle *pevent, int id, + const char *sys_name, const char *event_name, + tep_event_handler_func func, void *context); +int tep_unregister_event_handler(struct tep_handle *pevent, int id, + const char *sys_name, const char *event_name, + tep_event_handler_func func, void *context); +int tep_register_print_function(struct tep_handle *pevent, + tep_func_handler func, + enum tep_func_arg_type ret_type, + char *name, ...); +int tep_unregister_print_function(struct tep_handle *pevent, + tep_func_handler func, char *name); + +struct format_field *tep_find_common_field(struct event_format *event, const char *name); +struct format_field *tep_find_field(struct event_format *event, const char *name); +struct format_field *tep_find_any_field(struct event_format *event, const char *name); + +const char *tep_find_function(struct tep_handle *pevent, unsigned long long addr); unsigned long long -pevent_find_function_address(struct pevent *pevent, unsigned long long addr); -unsigned long long pevent_read_number(struct pevent *pevent, const void *ptr, int size); -int pevent_read_number_field(struct format_field *field, const void *data, - unsigned long long *value); +tep_find_function_address(struct tep_handle *pevent, unsigned long long addr); +unsigned long long tep_read_number(struct tep_handle *pevent, const void *ptr, int size); +int tep_read_number_field(struct format_field *field, const void *data, + unsigned long long *value); -struct event_format *pevent_find_event(struct pevent *pevent, int id); +struct event_format *tep_find_event(struct tep_handle *pevent, int id); struct event_format * -pevent_find_event_by_name(struct pevent *pevent, const char *sys, const char *name); +tep_find_event_by_name(struct tep_handle *pevent, const char *sys, const char *name); struct event_format * -pevent_find_event_by_record(struct pevent *pevent, struct pevent_record *record); - -void pevent_data_lat_fmt(struct pevent *pevent, - struct trace_seq *s, struct pevent_record *record); -int pevent_data_type(struct pevent *pevent, struct pevent_record *rec); -struct event_format *pevent_data_event_from_type(struct pevent *pevent, int type); -int pevent_data_pid(struct pevent *pevent, struct pevent_record *rec); -int pevent_data_preempt_count(struct pevent *pevent, struct pevent_record *rec); -int pevent_data_flags(struct pevent *pevent, struct pevent_record *rec); -const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid); +tep_find_event_by_record(struct tep_handle *pevent, struct tep_record *record); + +void tep_data_lat_fmt(struct tep_handle *pevent, + struct trace_seq *s, struct tep_record *record); +int tep_data_type(struct tep_handle *pevent, struct tep_record *rec); +struct event_format *tep_data_event_from_type(struct tep_handle *pevent, int type); +int tep_data_pid(struct tep_handle *pevent, struct tep_record *rec); +int tep_data_preempt_count(struct tep_handle *pevent, struct tep_record *rec); +int tep_data_flags(struct tep_handle *pevent, struct tep_record *rec); +const char *tep_data_comm_from_pid(struct tep_handle *pevent, int pid); struct cmdline; -struct cmdline *pevent_data_pid_from_comm(struct pevent *pevent, const char *comm, - struct cmdline *next); -int pevent_cmdline_pid(struct pevent *pevent, struct cmdline *cmdline); - -void pevent_print_field(struct trace_seq *s, void *data, - struct format_field *field); -void pevent_print_fields(struct trace_seq *s, void *data, - int size __maybe_unused, struct event_format *event); -void pevent_event_info(struct trace_seq *s, struct event_format *event, - struct pevent_record *record); -int pevent_strerror(struct pevent *pevent, enum pevent_errno errnum, +struct cmdline *tep_data_pid_from_comm(struct tep_handle *pevent, const char *comm, + struct cmdline *next); +int tep_cmdline_pid(struct tep_handle *pevent, struct cmdline *cmdline); + +void tep_print_field(struct trace_seq *s, void *data, + struct format_field *field); +void tep_print_fields(struct trace_seq *s, void *data, + int size __maybe_unused, struct event_format *event); +void tep_event_info(struct trace_seq *s, struct event_format *event, + struct tep_record *record); +int tep_strerror(struct tep_handle *pevent, enum tep_errno errnum, char *buf, size_t buflen); -struct event_format **pevent_list_events(struct pevent *pevent, enum event_sort_type); -struct format_field **pevent_event_common_fields(struct event_format *event); -struct format_field **pevent_event_fields(struct event_format *event); +struct event_format **tep_list_events(struct tep_handle *pevent, enum event_sort_type); +struct format_field **tep_event_common_fields(struct event_format *event); +struct format_field **tep_event_fields(struct event_format *event); -static inline int pevent_get_cpus(struct pevent *pevent) +static inline int tep_get_cpus(struct tep_handle *pevent) { return pevent->cpus; } -static inline void pevent_set_cpus(struct pevent *pevent, int cpus) +static inline void tep_set_cpus(struct tep_handle *pevent, int cpus) { pevent->cpus = cpus; } -static inline int pevent_get_long_size(struct pevent *pevent) +static inline int tep_get_long_size(struct tep_handle *pevent) { return pevent->long_size; } -static inline void pevent_set_long_size(struct pevent *pevent, int long_size) +static inline void tep_set_long_size(struct tep_handle *pevent, int long_size) { pevent->long_size = long_size; } -static inline int pevent_get_page_size(struct pevent *pevent) +static inline int tep_get_page_size(struct tep_handle *pevent) { return pevent->page_size; } -static inline void pevent_set_page_size(struct pevent *pevent, int _page_size) +static inline void tep_set_page_size(struct tep_handle *pevent, int _page_size) { pevent->page_size = _page_size; } -static inline int pevent_is_file_bigendian(struct pevent *pevent) +static inline int tep_is_file_bigendian(struct tep_handle *pevent) { return pevent->file_bigendian; } -static inline void pevent_set_file_bigendian(struct pevent *pevent, int endian) +static inline void tep_set_file_bigendian(struct tep_handle *pevent, int endian) { pevent->file_bigendian = endian; } -static inline int pevent_is_host_bigendian(struct pevent *pevent) +static inline int tep_is_host_bigendian(struct tep_handle *pevent) { return pevent->host_bigendian; } -static inline void pevent_set_host_bigendian(struct pevent *pevent, int endian) +static inline void tep_set_host_bigendian(struct tep_handle *pevent, int endian) { pevent->host_bigendian = endian; } -static inline int pevent_is_latency_format(struct pevent *pevent) +static inline int tep_is_latency_format(struct tep_handle *pevent) { return pevent->latency_format; } -static inline void pevent_set_latency_format(struct pevent *pevent, int lat) +static inline void tep_set_latency_format(struct tep_handle *pevent, int lat) { pevent->latency_format = lat; } -struct pevent *pevent_alloc(void); -void pevent_free(struct pevent *pevent); -void pevent_ref(struct pevent *pevent); -void pevent_unref(struct pevent *pevent); +struct tep_handle *tep_alloc(void); +void tep_free(struct tep_handle *pevent); +void tep_ref(struct tep_handle *pevent); +void tep_unref(struct tep_handle *pevent); /* access to the internal parser */ -void pevent_buffer_init(const char *buf, unsigned long long size); -enum event_type pevent_read_token(char **tok); -void pevent_free_token(char *token); -int pevent_peek_char(void); -const char *pevent_get_input_buf(void); -unsigned long long pevent_get_input_buf_ptr(void); +void tep_buffer_init(const char *buf, unsigned long long size); +enum event_type tep_read_token(char **tok); +void tep_free_token(char *token); +int tep_peek_char(void); +const char *tep_get_input_buf(void); +unsigned long long tep_get_input_buf_ptr(void); /* for debugging */ -void pevent_print_funcs(struct pevent *pevent); -void pevent_print_printk(struct pevent *pevent); +void tep_print_funcs(struct tep_handle *pevent); +void tep_print_printk(struct tep_handle *pevent); /* ----------------------- filtering ----------------------- */ @@ -930,22 +930,22 @@ struct filter_type { struct filter_arg *filter; }; -#define PEVENT_FILTER_ERROR_BUFSZ 1024 +#define TEP_FILTER_ERROR_BUFSZ 1024 struct event_filter { - struct pevent *pevent; + struct tep_handle *pevent; int filters; struct filter_type *event_filters; - char error_buffer[PEVENT_FILTER_ERROR_BUFSZ]; + char error_buffer[TEP_FILTER_ERROR_BUFSZ]; }; -struct event_filter *pevent_filter_alloc(struct pevent *pevent); +struct event_filter *tep_filter_alloc(struct tep_handle *pevent); /* for backward compatibility */ -#define FILTER_NONE PEVENT_ERRNO__NO_FILTER -#define FILTER_NOEXIST PEVENT_ERRNO__FILTER_NOT_FOUND -#define FILTER_MISS PEVENT_ERRNO__FILTER_MISS -#define FILTER_MATCH PEVENT_ERRNO__FILTER_MATCH +#define FILTER_NONE TEP_ERRNO__NO_FILTER +#define FILTER_NOEXIST TEP_ERRNO__FILTER_NOT_FOUND +#define FILTER_MISS TEP_ERRNO__FILTER_MISS +#define FILTER_MATCH TEP_ERRNO__FILTER_MATCH enum filter_trivial_type { FILTER_TRIVIAL_FALSE, @@ -953,39 +953,39 @@ enum filter_trivial_type { FILTER_TRIVIAL_BOTH, }; -enum pevent_errno pevent_filter_add_filter_str(struct event_filter *filter, - const char *filter_str); +enum tep_errno tep_filter_add_filter_str(struct event_filter *filter, + const char *filter_str); -enum pevent_errno pevent_filter_match(struct event_filter *filter, - struct pevent_record *record); +enum tep_errno tep_filter_match(struct event_filter *filter, + struct tep_record *record); -int pevent_filter_strerror(struct event_filter *filter, enum pevent_errno err, - char *buf, size_t buflen); +int tep_filter_strerror(struct event_filter *filter, enum tep_errno err, + char *buf, size_t buflen); -int pevent_event_filtered(struct event_filter *filter, - int event_id); +int tep_event_filtered(struct event_filter *filter, + int event_id); -void pevent_filter_reset(struct event_filter *filter); +void tep_filter_reset(struct event_filter *filter); -int pevent_filter_clear_trivial(struct event_filter *filter, - enum filter_trivial_type type); +int tep_filter_clear_trivial(struct event_filter *filter, + enum filter_trivial_type type); -void pevent_filter_free(struct event_filter *filter); +void tep_filter_free(struct event_filter *filter); -char *pevent_filter_make_string(struct event_filter *filter, int event_id); +char *tep_filter_make_string(struct event_filter *filter, int event_id); -int pevent_filter_remove_event(struct event_filter *filter, - int event_id); +int tep_filter_remove_event(struct event_filter *filter, + int event_id); -int pevent_filter_event_has_trivial(struct event_filter *filter, - int event_id, - enum filter_trivial_type type); +int tep_filter_event_has_trivial(struct event_filter *filter, + int event_id, + enum filter_trivial_type type); -int pevent_filter_copy(struct event_filter *dest, struct event_filter *source); +int tep_filter_copy(struct event_filter *dest, struct event_filter *source); -int pevent_update_trivial(struct event_filter *dest, struct event_filter *source, - enum filter_trivial_type type); +int tep_update_trivial(struct event_filter *dest, struct event_filter *source, + enum filter_trivial_type type); -int pevent_filter_compare(struct event_filter *filter1, struct event_filter *filter2); +int tep_filter_compare(struct event_filter *filter1, struct event_filter *filter2); #endif /* _PARSE_EVENTS_H */ diff --git a/tools/lib/traceevent/event-plugin.c b/tools/lib/traceevent/event-plugin.c index d542cb60ca1a..f17e25097e1e 100644 --- a/tools/lib/traceevent/event-plugin.c +++ b/tools/lib/traceevent/event-plugin.c @@ -1,21 +1,7 @@ +// SPDX-License-Identifier: LGPL-2.1 /* * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License (not later!) - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, see <http://www.gnu.org/licenses> - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #include <ctype.h> @@ -34,7 +20,7 @@ static struct registered_plugin_options { struct registered_plugin_options *next; - struct pevent_plugin_option *options; + struct tep_plugin_option *options; } *registered_options; static struct trace_plugin_options { @@ -58,7 +44,7 @@ static void lower_case(char *str) *str = tolower(*str); } -static int update_option_value(struct pevent_plugin_option *op, const char *val) +static int update_option_value(struct tep_plugin_option *op, const char *val) { char *op_val; @@ -97,7 +83,7 @@ static int update_option_value(struct pevent_plugin_option *op, const char *val) } /** - * traceevent_plugin_list_options - get list of plugin options + * tep_plugin_list_options - get list of plugin options * * Returns an array of char strings that list the currently registered * plugin options in the format of <plugin>:<option>. This list can be @@ -106,12 +92,12 @@ static int update_option_value(struct pevent_plugin_option *op, const char *val) * Returns NULL if there's no options registered. On error it returns * INVALID_PLUGIN_LIST_OPTION * - * Must be freed with traceevent_plugin_free_options_list(). + * Must be freed with tep_plugin_free_options_list(). */ -char **traceevent_plugin_list_options(void) +char **tep_plugin_list_options(void) { struct registered_plugin_options *reg; - struct pevent_plugin_option *op; + struct tep_plugin_option *op; char **list = NULL; char *name; int count = 0; @@ -146,7 +132,7 @@ char **traceevent_plugin_list_options(void) return INVALID_PLUGIN_LIST_OPTION; } -void traceevent_plugin_free_options_list(char **list) +void tep_plugin_free_options_list(char **list) { int i; @@ -163,7 +149,7 @@ void traceevent_plugin_free_options_list(char **list) } static int -update_option(const char *file, struct pevent_plugin_option *option) +update_option(const char *file, struct tep_plugin_option *option) { struct trace_plugin_options *op; char *plugin; @@ -215,14 +201,14 @@ update_option(const char *file, struct pevent_plugin_option *option) } /** - * traceevent_plugin_add_options - Add a set of options by a plugin + * tep_plugin_add_options - Add a set of options by a plugin * @name: The name of the plugin adding the options * @options: The set of options being loaded * * Sets the options with the values that have been added by user. */ -int traceevent_plugin_add_options(const char *name, - struct pevent_plugin_option *options) +int tep_plugin_add_options(const char *name, + struct tep_plugin_option *options) { struct registered_plugin_options *reg; @@ -241,10 +227,10 @@ int traceevent_plugin_add_options(const char *name, } /** - * traceevent_plugin_remove_options - remove plugin options that were registered - * @options: Options to removed that were registered with traceevent_plugin_add_options + * tep_plugin_remove_options - remove plugin options that were registered + * @options: Options to removed that were registered with tep_plugin_add_options */ -void traceevent_plugin_remove_options(struct pevent_plugin_option *options) +void tep_plugin_remove_options(struct tep_plugin_option *options) { struct registered_plugin_options **last; struct registered_plugin_options *reg; @@ -260,19 +246,19 @@ void traceevent_plugin_remove_options(struct pevent_plugin_option *options) } /** - * traceevent_print_plugins - print out the list of plugins loaded + * tep_print_plugins - print out the list of plugins loaded * @s: the trace_seq descripter to write to * @prefix: The prefix string to add before listing the option name * @suffix: The suffix string ot append after the option name - * @list: The list of plugins (usually returned by traceevent_load_plugins() + * @list: The list of plugins (usually returned by tep_load_plugins() * * Writes to the trace_seq @s the list of plugins (files) that is - * returned by traceevent_load_plugins(). Use @prefix and @suffix for formating: + * returned by tep_load_plugins(). Use @prefix and @suffix for formating: * @prefix = " ", @suffix = "\n". */ -void traceevent_print_plugins(struct trace_seq *s, - const char *prefix, const char *suffix, - const struct plugin_list *list) +void tep_print_plugins(struct trace_seq *s, + const char *prefix, const char *suffix, + const struct plugin_list *list) { while (list) { trace_seq_printf(s, "%s%s%s", prefix, list->name, suffix); @@ -281,11 +267,11 @@ void traceevent_print_plugins(struct trace_seq *s, } static void -load_plugin(struct pevent *pevent, const char *path, +load_plugin(struct tep_handle *pevent, const char *path, const char *file, void *data) { struct plugin_list **plugin_list = data; - pevent_plugin_load_func func; + tep_plugin_load_func func; struct plugin_list *list; const char *alias; char *plugin; @@ -305,14 +291,14 @@ load_plugin(struct pevent *pevent, const char *path, goto out_free; } - alias = dlsym(handle, PEVENT_PLUGIN_ALIAS_NAME); + alias = dlsym(handle, TEP_PLUGIN_ALIAS_NAME); if (!alias) alias = file; - func = dlsym(handle, PEVENT_PLUGIN_LOADER_NAME); + func = dlsym(handle, TEP_PLUGIN_LOADER_NAME); if (!func) { warning("could not find func '%s' in plugin '%s'\n%s\n", - PEVENT_PLUGIN_LOADER_NAME, plugin, dlerror()); + TEP_PLUGIN_LOADER_NAME, plugin, dlerror()); goto out_free; } @@ -336,9 +322,9 @@ load_plugin(struct pevent *pevent, const char *path, } static void -load_plugins_dir(struct pevent *pevent, const char *suffix, +load_plugins_dir(struct tep_handle *pevent, const char *suffix, const char *path, - void (*load_plugin)(struct pevent *pevent, + void (*load_plugin)(struct tep_handle *pevent, const char *path, const char *name, void *data), @@ -378,8 +364,8 @@ load_plugins_dir(struct pevent *pevent, const char *suffix, } static void -load_plugins(struct pevent *pevent, const char *suffix, - void (*load_plugin)(struct pevent *pevent, +load_plugins(struct tep_handle *pevent, const char *suffix, + void (*load_plugin)(struct tep_handle *pevent, const char *path, const char *name, void *data), @@ -390,7 +376,7 @@ load_plugins(struct pevent *pevent, const char *suffix, char *envdir; int ret; - if (pevent->flags & PEVENT_DISABLE_PLUGINS) + if (pevent->flags & TEP_DISABLE_PLUGINS) return; /* @@ -398,7 +384,7 @@ load_plugins(struct pevent *pevent, const char *suffix, * check that first. */ #ifdef PLUGIN_DIR - if (!(pevent->flags & PEVENT_DISABLE_SYS_PLUGINS)) + if (!(pevent->flags & TEP_DISABLE_SYS_PLUGINS)) load_plugins_dir(pevent, suffix, PLUGIN_DIR, load_plugin, data); #endif @@ -431,7 +417,7 @@ load_plugins(struct pevent *pevent, const char *suffix, } struct plugin_list* -traceevent_load_plugins(struct pevent *pevent) +tep_load_plugins(struct tep_handle *pevent) { struct plugin_list *list = NULL; @@ -440,15 +426,15 @@ traceevent_load_plugins(struct pevent *pevent) } void -traceevent_unload_plugins(struct plugin_list *plugin_list, struct pevent *pevent) +tep_unload_plugins(struct plugin_list *plugin_list, struct tep_handle *pevent) { - pevent_plugin_unload_func func; + tep_plugin_unload_func func; struct plugin_list *list; while (plugin_list) { list = plugin_list; plugin_list = list->next; - func = dlsym(list->handle, PEVENT_PLUGIN_UNLOADER_NAME); + func = dlsym(list->handle, TEP_PLUGIN_UNLOADER_NAME); if (func) func(pevent); dlclose(list->handle); diff --git a/tools/lib/traceevent/event-utils.h b/tools/lib/traceevent/event-utils.h index d1dc2170e402..0560b96a31d1 100644 --- a/tools/lib/traceevent/event-utils.h +++ b/tools/lib/traceevent/event-utils.h @@ -1,21 +1,7 @@ +/* SPDX-License-Identifier: LGPL-2.1 */ /* * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License (not later!) - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, see <http://www.gnu.org/licenses> - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #ifndef __UTIL_H #define __UTIL_H diff --git a/tools/lib/traceevent/kbuffer-parse.c b/tools/lib/traceevent/kbuffer-parse.c index ca424b157e46..af2a1f3b7424 100644 --- a/tools/lib/traceevent/kbuffer-parse.c +++ b/tools/lib/traceevent/kbuffer-parse.c @@ -1,22 +1,7 @@ +// SPDX-License-Identifier: LGPL-2.1 /* * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License (not later!) - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #include <stdio.h> #include <stdlib.h> diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c index 431e8b309f6e..e76154c02ee7 100644 --- a/tools/lib/traceevent/parse-filter.c +++ b/tools/lib/traceevent/parse-filter.c @@ -1,21 +1,7 @@ +// SPDX-License-Identifier: LGPL-2.1 /* * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License (not later!) - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, see <http://www.gnu.org/licenses> - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #include <stdio.h> #include <stdlib.h> @@ -51,8 +37,8 @@ static void show_error(char *error_buf, const char *fmt, ...) int len; int i; - input = pevent_get_input_buf(); - index = pevent_get_input_buf_ptr(); + input = tep_get_input_buf(); + index = tep_get_input_buf_ptr(); len = input ? strlen(input) : 0; if (len) { @@ -66,13 +52,13 @@ static void show_error(char *error_buf, const char *fmt, ...) } va_start(ap, fmt); - vsnprintf(error_buf + len, PEVENT_FILTER_ERROR_BUFSZ - len, fmt, ap); + vsnprintf(error_buf + len, TEP_FILTER_ERROR_BUFSZ - len, fmt, ap); va_end(ap); } static void free_token(char *token) { - pevent_free_token(token); + tep_free_token(token); } static enum event_type read_token(char **tok) @@ -82,13 +68,13 @@ static enum event_type read_token(char **tok) do { free_token(token); - type = pevent_read_token(&token); + type = tep_read_token(&token); } while (type == EVENT_NEWLINE || type == EVENT_SPACE); /* If token is = or ! check to see if the next char is ~ */ if (token && (strcmp(token, "=") == 0 || strcmp(token, "!") == 0) && - pevent_peek_char() == '~') { + tep_peek_char() == '~') { /* append it */ *tok = malloc(3); if (*tok == NULL) { @@ -98,7 +84,7 @@ static enum event_type read_token(char **tok) sprintf(*tok, "%c%c", *token, '~'); free_token(token); /* Now remove the '~' from the buffer */ - pevent_read_token(&token); + tep_read_token(&token); free_token(token); } else *tok = token; @@ -167,7 +153,7 @@ add_filter_type(struct event_filter *filter, int id) filter_type = &filter->event_filters[i]; filter_type->event_id = id; - filter_type->event = pevent_find_event(filter->pevent, id); + filter_type->event = tep_find_event(filter->pevent, id); filter_type->filter = NULL; filter->filters++; @@ -176,10 +162,10 @@ add_filter_type(struct event_filter *filter, int id) } /** - * pevent_filter_alloc - create a new event filter + * tep_filter_alloc - create a new event filter * @pevent: The pevent that this filter is associated with */ -struct event_filter *pevent_filter_alloc(struct pevent *pevent) +struct event_filter *tep_filter_alloc(struct tep_handle *pevent) { struct event_filter *filter; @@ -189,7 +175,7 @@ struct event_filter *pevent_filter_alloc(struct pevent *pevent) memset(filter, 0, sizeof(*filter)); filter->pevent = pevent; - pevent_ref(pevent); + tep_ref(pevent); return filter; } @@ -268,8 +254,8 @@ static int event_match(struct event_format *event, !regexec(ereg, event->name, 0, NULL, 0); } -static enum pevent_errno -find_event(struct pevent *pevent, struct event_list **events, +static enum tep_errno +find_event(struct tep_handle *pevent, struct event_list **events, char *sys_name, char *event_name) { struct event_format *event; @@ -289,26 +275,26 @@ find_event(struct pevent *pevent, struct event_list **events, ret = asprintf(®, "^%s$", event_name); if (ret < 0) - return PEVENT_ERRNO__MEM_ALLOC_FAILED; + return TEP_ERRNO__MEM_ALLOC_FAILED; ret = regcomp(&ereg, reg, REG_ICASE|REG_NOSUB); free(reg); if (ret) - return PEVENT_ERRNO__INVALID_EVENT_NAME; + return TEP_ERRNO__INVALID_EVENT_NAME; if (sys_name) { ret = asprintf(®, "^%s$", sys_name); if (ret < 0) { regfree(&ereg); - return PEVENT_ERRNO__MEM_ALLOC_FAILED; + return TEP_ERRNO__MEM_ALLOC_FAILED; } ret = regcomp(&sreg, reg, REG_ICASE|REG_NOSUB); free(reg); if (ret) { regfree(&ereg); - return PEVENT_ERRNO__INVALID_EVENT_NAME; + return TEP_ERRNO__INVALID_EVENT_NAME; } } @@ -328,9 +314,9 @@ find_event(struct pevent *pevent, struct event_list **events, regfree(&sreg); if (!match) - return PEVENT_ERRNO__EVENT_NOT_FOUND; + return TEP_ERRNO__EVENT_NOT_FOUND; if (fail) - return PEVENT_ERRNO__MEM_ALLOC_FAILED; + return TEP_ERRNO__MEM_ALLOC_FAILED; return 0; } @@ -346,7 +332,7 @@ static void free_events(struct event_list *events) } } -static enum pevent_errno +static enum tep_errno create_arg_item(struct event_format *event, const char *token, enum event_type type, struct filter_arg **parg, char *error_str) { @@ -356,7 +342,7 @@ create_arg_item(struct event_format *event, const char *token, arg = allocate_arg(); if (arg == NULL) { show_error(error_str, "failed to allocate filter arg"); - return PEVENT_ERRNO__MEM_ALLOC_FAILED; + return TEP_ERRNO__MEM_ALLOC_FAILED; } switch (type) { @@ -370,7 +356,7 @@ create_arg_item(struct event_format *event, const char *token, if (!arg->value.str) { free_arg(arg); show_error(error_str, "failed to allocate string filter arg"); - return PEVENT_ERRNO__MEM_ALLOC_FAILED; + return TEP_ERRNO__MEM_ALLOC_FAILED; } break; case EVENT_ITEM: @@ -382,7 +368,7 @@ create_arg_item(struct event_format *event, const char *token, break; } /* Consider this a field */ - field = pevent_find_any_field(event, token); + field = tep_find_any_field(event, token); if (!field) { /* If token is 'COMM' or 'CPU' then it is special */ if (strcmp(token, COMM) == 0) { @@ -402,7 +388,7 @@ create_arg_item(struct event_format *event, const char *token, default: free_arg(arg); show_error(error_str, "expected a value but found %s", token); - return PEVENT_ERRNO__UNEXPECTED_TYPE; + return TEP_ERRNO__UNEXPECTED_TYPE; } *parg = arg; return 0; @@ -454,7 +440,7 @@ create_arg_cmp(enum filter_cmp_type ctype) return arg; } -static enum pevent_errno +static enum tep_errno add_right(struct filter_arg *op, struct filter_arg *arg, char *error_str) { struct filter_arg *left; @@ -487,7 +473,7 @@ add_right(struct filter_arg *op, struct filter_arg *arg, char *error_str) break; default: show_error(error_str, "Illegal rvalue"); - return PEVENT_ERRNO__ILLEGAL_RVALUE; + return TEP_ERRNO__ILLEGAL_RVALUE; } /* @@ -534,7 +520,7 @@ add_right(struct filter_arg *op, struct filter_arg *arg, char *error_str) if (left->type != FILTER_ARG_FIELD) { show_error(error_str, "Illegal lvalue for string comparison"); - return PEVENT_ERRNO__ILLEGAL_LVALUE; + return TEP_ERRNO__ILLEGAL_LVALUE; } /* Make sure this is a valid string compare */ @@ -553,13 +539,13 @@ add_right(struct filter_arg *op, struct filter_arg *arg, char *error_str) show_error(error_str, "RegEx '%s' did not compute", str); - return PEVENT_ERRNO__INVALID_REGEX; + return TEP_ERRNO__INVALID_REGEX; } break; default: show_error(error_str, "Illegal comparison for string"); - return PEVENT_ERRNO__ILLEGAL_STRING_CMP; + return TEP_ERRNO__ILLEGAL_STRING_CMP; } op->type = FILTER_ARG_STR; @@ -568,7 +554,7 @@ add_right(struct filter_arg *op, struct filter_arg *arg, char *error_str) op->str.val = strdup(str); if (!op->str.val) { show_error(error_str, "Failed to allocate string filter"); - return PEVENT_ERRNO__MEM_ALLOC_FAILED; + return TEP_ERRNO__MEM_ALLOC_FAILED; } /* * Need a buffer to copy data for tests @@ -576,7 +562,7 @@ add_right(struct filter_arg *op, struct filter_arg *arg, char *error_str) op->str.buffer = malloc(op->str.field->size + 1); if (!op->str.buffer) { show_error(error_str, "Failed to allocate string filter"); - return PEVENT_ERRNO__MEM_ALLOC_FAILED; + return TEP_ERRNO__MEM_ALLOC_FAILED; } /* Null terminate this buffer */ op->str.buffer[op->str.field->size] = 0; @@ -595,7 +581,7 @@ add_right(struct filter_arg *op, struct filter_arg *arg, char *error_str) case FILTER_CMP_NOT_REGEX: show_error(error_str, "Op not allowed with integers"); - return PEVENT_ERRNO__ILLEGAL_INTEGER_CMP; + return TEP_ERRNO__ILLEGAL_INTEGER_CMP; default: break; @@ -616,7 +602,7 @@ add_right(struct filter_arg *op, struct filter_arg *arg, char *error_str) out_fail: show_error(error_str, "Syntax error"); - return PEVENT_ERRNO__SYNTAX_ERROR; + return TEP_ERRNO__SYNTAX_ERROR; } static struct filter_arg * @@ -629,7 +615,7 @@ rotate_op_right(struct filter_arg *a, struct filter_arg *b) return arg; } -static enum pevent_errno add_left(struct filter_arg *op, struct filter_arg *arg) +static enum tep_errno add_left(struct filter_arg *op, struct filter_arg *arg) { switch (op->type) { case FILTER_ARG_EXP: @@ -648,11 +634,11 @@ static enum pevent_errno add_left(struct filter_arg *op, struct filter_arg *arg) /* left arg of compares must be a field */ if (arg->type != FILTER_ARG_FIELD && arg->type != FILTER_ARG_BOOLEAN) - return PEVENT_ERRNO__INVALID_ARG_TYPE; + return TEP_ERRNO__INVALID_ARG_TYPE; op->num.left = arg; break; default: - return PEVENT_ERRNO__INVALID_ARG_TYPE; + return TEP_ERRNO__INVALID_ARG_TYPE; } return 0; } @@ -765,7 +751,7 @@ enum filter_vals { FILTER_VAL_TRUE, }; -static enum pevent_errno +static enum tep_errno reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child, struct filter_arg *arg, char *error_str) { @@ -775,7 +761,7 @@ reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child, if (parent->type != FILTER_ARG_OP && arg->type != FILTER_ARG_OP) { show_error(error_str, "can not reparent other than OP"); - return PEVENT_ERRNO__REPARENT_NOT_OP; + return TEP_ERRNO__REPARENT_NOT_OP; } /* Get the sibling */ @@ -787,7 +773,7 @@ reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child, other_child = old_child->op.right; } else { show_error(error_str, "Error in reparent op, find other child"); - return PEVENT_ERRNO__REPARENT_FAILED; + return TEP_ERRNO__REPARENT_FAILED; } /* Detach arg from old_child */ @@ -808,7 +794,7 @@ reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child, ptr = &parent->op.left; else { show_error(error_str, "Error in reparent op"); - return PEVENT_ERRNO__REPARENT_FAILED; + return TEP_ERRNO__REPARENT_FAILED; } *ptr = arg; @@ -817,7 +803,7 @@ reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child, return 0; } -/* Returns either filter_vals (success) or pevent_errno (failfure) */ +/* Returns either filter_vals (success) or tep_errno (failfure) */ static int test_arg(struct filter_arg *parent, struct filter_arg *arg, char *error_str) { @@ -912,7 +898,7 @@ static int test_arg(struct filter_arg *parent, struct filter_arg *arg, return rval; default: show_error(error_str, "bad arg in filter tree"); - return PEVENT_ERRNO__BAD_FILTER_ARG; + return TEP_ERRNO__BAD_FILTER_ARG; } return FILTER_VAL_NORM; } @@ -937,7 +923,7 @@ static int collapse_tree(struct filter_arg *arg, arg->boolean.value = ret == FILTER_VAL_TRUE; } else { show_error(error_str, "Failed to allocate filter arg"); - ret = PEVENT_ERRNO__MEM_ALLOC_FAILED; + ret = TEP_ERRNO__MEM_ALLOC_FAILED; } break; @@ -952,7 +938,7 @@ static int collapse_tree(struct filter_arg *arg, return ret; } -static enum pevent_errno +static enum tep_errno process_filter(struct event_format *event, struct filter_arg **parg, char *error_str, int not) { @@ -966,7 +952,7 @@ process_filter(struct event_format *event, struct filter_arg **parg, enum filter_op_type btype; enum filter_exp_type etype; enum filter_cmp_type ctype; - enum pevent_errno ret; + enum tep_errno ret; *parg = NULL; @@ -1004,7 +990,7 @@ process_filter(struct event_format *event, struct filter_arg **parg, case EVENT_DELIM: if (*token == ',') { show_error(error_str, "Illegal token ','"); - ret = PEVENT_ERRNO__ILLEGAL_TOKEN; + ret = TEP_ERRNO__ILLEGAL_TOKEN; goto fail; } @@ -1012,22 +998,22 @@ process_filter(struct event_format *event, struct filter_arg **parg, if (left_item) { show_error(error_str, "Open paren can not come after item"); - ret = PEVENT_ERRNO__INVALID_PAREN; + ret = TEP_ERRNO__INVALID_PAREN; goto fail; } if (current_exp) { show_error(error_str, "Open paren can not come after expression"); - ret = PEVENT_ERRNO__INVALID_PAREN; + ret = TEP_ERRNO__INVALID_PAREN; goto fail; } ret = process_filter(event, &arg, error_str, 0); - if (ret != PEVENT_ERRNO__UNBALANCED_PAREN) { + if (ret != TEP_ERRNO__UNBALANCED_PAREN) { if (ret == 0) { show_error(error_str, "Unbalanced number of '('"); - ret = PEVENT_ERRNO__UNBALANCED_PAREN; + ret = TEP_ERRNO__UNBALANCED_PAREN; } goto fail; } @@ -1064,7 +1050,7 @@ process_filter(struct event_format *event, struct filter_arg **parg, else *parg = current_exp; free(token); - return PEVENT_ERRNO__UNBALANCED_PAREN; + return TEP_ERRNO__UNBALANCED_PAREN; } break; @@ -1091,7 +1077,7 @@ process_filter(struct event_format *event, struct filter_arg **parg, case OP_NONE: show_error(error_str, "Unknown op token %s", token); - ret = PEVENT_ERRNO__UNKNOWN_TOKEN; + ret = TEP_ERRNO__UNKNOWN_TOKEN; goto fail; } @@ -1179,11 +1165,11 @@ process_filter(struct event_format *event, struct filter_arg **parg, fail_alloc: show_error(error_str, "failed to allocate filter arg"); - ret = PEVENT_ERRNO__MEM_ALLOC_FAILED; + ret = TEP_ERRNO__MEM_ALLOC_FAILED; goto fail; fail_syntax: show_error(error_str, "Syntax error"); - ret = PEVENT_ERRNO__SYNTAX_ERROR; + ret = TEP_ERRNO__SYNTAX_ERROR; fail: free_arg(current_op); free_arg(current_exp); @@ -1192,13 +1178,13 @@ process_filter(struct event_format *event, struct filter_arg **parg, return ret; } -static enum pevent_errno +static enum tep_errno process_event(struct event_format *event, const char *filter_str, struct filter_arg **parg, char *error_str) { int ret; - pevent_buffer_init(filter_str, strlen(filter_str)); + tep_buffer_init(filter_str, strlen(filter_str)); ret = process_filter(event, parg, error_str, 0); if (ret < 0) @@ -1208,7 +1194,7 @@ process_event(struct event_format *event, const char *filter_str, if (!*parg) { *parg = allocate_arg(); if (*parg == NULL) - return PEVENT_ERRNO__MEM_ALLOC_FAILED; + return TEP_ERRNO__MEM_ALLOC_FAILED; (*parg)->type = FILTER_ARG_BOOLEAN; (*parg)->boolean.value = FILTER_FALSE; @@ -1217,13 +1203,13 @@ process_event(struct event_format *event, const char *filter_str, return 0; } -static enum pevent_errno +static enum tep_errno filter_event(struct event_filter *filter, struct event_format *event, const char *filter_str, char *error_str) { struct filter_type *filter_type; struct filter_arg *arg; - enum pevent_errno ret; + enum tep_errno ret; if (filter_str) { ret = process_event(event, filter_str, &arg, error_str); @@ -1234,7 +1220,7 @@ filter_event(struct event_filter *filter, struct event_format *event, /* just add a TRUE arg */ arg = allocate_arg(); if (arg == NULL) - return PEVENT_ERRNO__MEM_ALLOC_FAILED; + return TEP_ERRNO__MEM_ALLOC_FAILED; arg->type = FILTER_ARG_BOOLEAN; arg->boolean.value = FILTER_TRUE; @@ -1242,7 +1228,7 @@ filter_event(struct event_filter *filter, struct event_format *event, filter_type = add_filter_type(filter, event->id); if (filter_type == NULL) - return PEVENT_ERRNO__MEM_ALLOC_FAILED; + return TEP_ERRNO__MEM_ALLOC_FAILED; if (filter_type->filter) free_arg(filter_type->filter); @@ -1254,23 +1240,23 @@ filter_event(struct event_filter *filter, struct event_format *event, static void filter_init_error_buf(struct event_filter *filter) { /* clear buffer to reset show error */ - pevent_buffer_init("", 0); + tep_buffer_init("", 0); filter->error_buffer[0] = '\0'; } /** - * pevent_filter_add_filter_str - add a new filter + * tep_filter_add_filter_str - add a new filter * @filter: the event filter to add to * @filter_str: the filter string that contains the filter * * Returns 0 if the filter was successfully added or a - * negative error code. Use pevent_filter_strerror() to see + * negative error code. Use tep_filter_strerror() to see * actual error message in case of error. */ -enum pevent_errno pevent_filter_add_filter_str(struct event_filter *filter, - const char *filter_str) +enum tep_errno tep_filter_add_filter_str(struct event_filter *filter, + const char *filter_str) { - struct pevent *pevent = filter->pevent; + struct tep_handle *pevent = filter->pevent; struct event_list *event; struct event_list *events = NULL; const char *filter_start; @@ -1279,7 +1265,7 @@ enum pevent_errno pevent_filter_add_filter_str(struct event_filter *filter, char *event_name = NULL; char *sys_name = NULL; char *sp; - enum pevent_errno rtn = 0; /* PEVENT_ERRNO__SUCCESS */ + enum tep_errno rtn = 0; /* TEP_ERRNO__SUCCESS */ int len; int ret; @@ -1305,7 +1291,7 @@ enum pevent_errno pevent_filter_add_filter_str(struct event_filter *filter, if (this_event == NULL) { /* This can only happen when events is NULL, but still */ free_events(events); - return PEVENT_ERRNO__MEM_ALLOC_FAILED; + return TEP_ERRNO__MEM_ALLOC_FAILED; } memcpy(this_event, filter_str, len); this_event[len] = 0; @@ -1322,7 +1308,7 @@ enum pevent_errno pevent_filter_add_filter_str(struct event_filter *filter, /* This can only happen when events is NULL, but still */ free_events(events); free(this_event); - return PEVENT_ERRNO__FILTER_NOT_FOUND; + return TEP_ERRNO__FILTER_NOT_FOUND; } /* Find this event */ @@ -1349,7 +1335,7 @@ enum pevent_errno pevent_filter_add_filter_str(struct event_filter *filter, if (ret >= 0 && pevent->test_filters) { char *test; - test = pevent_filter_make_string(filter, event->event->id); + test = tep_filter_make_string(filter, event->event->id); if (test) { printf(" '%s: %s'\n", event->event->name, test); free(test); @@ -1371,7 +1357,7 @@ static void free_filter_type(struct filter_type *filter_type) } /** - * pevent_filter_strerror - fill error message in a buffer + * tep_filter_strerror - fill error message in a buffer * @filter: the event filter contains error * @err: the error code * @buf: the buffer to be filled in @@ -1379,10 +1365,10 @@ static void free_filter_type(struct filter_type *filter_type) * * Returns 0 if message was filled successfully, -1 if error */ -int pevent_filter_strerror(struct event_filter *filter, enum pevent_errno err, - char *buf, size_t buflen) +int tep_filter_strerror(struct event_filter *filter, enum tep_errno err, + char *buf, size_t buflen) { - if (err <= __PEVENT_ERRNO__START || err >= __PEVENT_ERRNO__END) + if (err <= __TEP_ERRNO__START || err >= __TEP_ERRNO__END) return -1; if (strlen(filter->error_buffer) > 0) { @@ -1393,11 +1379,11 @@ int pevent_filter_strerror(struct event_filter *filter, enum pevent_errno err, return 0; } - return pevent_strerror(filter->pevent, err, buf, buflen); + return tep_strerror(filter->pevent, err, buf, buflen); } /** - * pevent_filter_remove_event - remove a filter for an event + * tep_filter_remove_event - remove a filter for an event * @filter: the event filter to remove from * @event_id: the event to remove a filter for * @@ -1407,8 +1393,8 @@ int pevent_filter_strerror(struct event_filter *filter, enum pevent_errno err, * Returns 1: if an event was removed * 0: if the event was not found */ -int pevent_filter_remove_event(struct event_filter *filter, - int event_id) +int tep_filter_remove_event(struct event_filter *filter, + int event_id) { struct filter_type *filter_type; unsigned long len; @@ -1437,12 +1423,12 @@ int pevent_filter_remove_event(struct event_filter *filter, } /** - * pevent_filter_reset - clear all filters in a filter + * tep_filter_reset - clear all filters in a filter * @filter: the event filter to reset * * Removes all filters from a filter and resets it. */ -void pevent_filter_reset(struct event_filter *filter) +void tep_filter_reset(struct event_filter *filter) { int i; @@ -1454,11 +1440,11 @@ void pevent_filter_reset(struct event_filter *filter) filter->event_filters = NULL; } -void pevent_filter_free(struct event_filter *filter) +void tep_filter_free(struct event_filter *filter) { - pevent_unref(filter->pevent); + tep_unref(filter->pevent); - pevent_filter_reset(filter); + tep_filter_reset(filter); free(filter); } @@ -1478,7 +1464,7 @@ static int copy_filter_type(struct event_filter *filter, /* Can't assume that the pevent's are the same */ sys = filter_type->event->system; name = filter_type->event->name; - event = pevent_find_event_by_name(filter->pevent, sys, name); + event = tep_find_event_by_name(filter->pevent, sys, name); if (!event) return -1; @@ -1515,18 +1501,18 @@ static int copy_filter_type(struct event_filter *filter, } /** - * pevent_filter_copy - copy a filter using another filter + * tep_filter_copy - copy a filter using another filter * @dest - the filter to copy to * @source - the filter to copy from * * Returns 0 on success and -1 if not all filters were copied */ -int pevent_filter_copy(struct event_filter *dest, struct event_filter *source) +int tep_filter_copy(struct event_filter *dest, struct event_filter *source) { int ret = 0; int i; - pevent_filter_reset(dest); + tep_filter_reset(dest); for (i = 0; i < source->filters; i++) { if (copy_filter_type(dest, source, &source->event_filters[i])) @@ -1537,7 +1523,7 @@ int pevent_filter_copy(struct event_filter *dest, struct event_filter *source) /** - * pevent_update_trivial - update the trivial filters with the given filter + * tep_update_trivial - update the trivial filters with the given filter * @dest - the filter to update * @source - the filter as the source of the update * @type - the type of trivial filter to update. @@ -1547,11 +1533,11 @@ int pevent_filter_copy(struct event_filter *dest, struct event_filter *source) * Returns 0 on success and -1 if there was a problem updating, but * events may have still been updated on error. */ -int pevent_update_trivial(struct event_filter *dest, struct event_filter *source, - enum filter_trivial_type type) +int tep_update_trivial(struct event_filter *dest, struct event_filter *source, + enum filter_trivial_type type) { - struct pevent *src_pevent; - struct pevent *dest_pevent; + struct tep_handle *src_pevent; + struct tep_handle *dest_pevent; struct event_format *event; struct filter_type *filter_type; struct filter_arg *arg; @@ -1578,14 +1564,14 @@ int pevent_update_trivial(struct event_filter *dest, struct event_filter *source if (src_pevent != dest_pevent) { /* do a look up */ - event = pevent_find_event_by_name(src_pevent, - event->system, - event->name); + event = tep_find_event_by_name(src_pevent, + event->system, + event->name); if (!event) return -1; } - str = pevent_filter_make_string(source, event->id); + str = tep_filter_make_string(source, event->id); if (!str) continue; @@ -1598,7 +1584,7 @@ int pevent_update_trivial(struct event_filter *dest, struct event_filter *source } /** - * pevent_filter_clear_trivial - clear TRUE and FALSE filters + * tep_filter_clear_trivial - clear TRUE and FALSE filters * @filter: the filter to remove trivial filters from * @type: remove only true, false, or both * @@ -1606,8 +1592,8 @@ int pevent_update_trivial(struct event_filter *dest, struct event_filter *source * * Returns 0 on success and -1 if there was a problem. */ -int pevent_filter_clear_trivial(struct event_filter *filter, - enum filter_trivial_type type) +int tep_filter_clear_trivial(struct event_filter *filter, + enum filter_trivial_type type) { struct filter_type *filter_type; int count = 0; @@ -1653,14 +1639,14 @@ int pevent_filter_clear_trivial(struct event_filter *filter, return 0; for (i = 0; i < count; i++) - pevent_filter_remove_event(filter, ids[i]); + tep_filter_remove_event(filter, ids[i]); free(ids); return 0; } /** - * pevent_filter_event_has_trivial - return true event contains trivial filter + * tep_filter_event_has_trivial - return true event contains trivial filter * @filter: the filter with the information * @event_id: the id of the event to test * @type: trivial type to test for (TRUE, FALSE, EITHER) @@ -1668,9 +1654,9 @@ int pevent_filter_clear_trivial(struct event_filter *filter, * Returns 1 if the event contains a matching trivial type * otherwise 0. */ -int pevent_filter_event_has_trivial(struct event_filter *filter, - int event_id, - enum filter_trivial_type type) +int tep_filter_event_has_trivial(struct event_filter *filter, + int event_id, + enum filter_trivial_type type) { struct filter_type *filter_type; @@ -1697,22 +1683,22 @@ int pevent_filter_event_has_trivial(struct event_filter *filter, } static int test_filter(struct event_format *event, struct filter_arg *arg, - struct pevent_record *record, enum pevent_errno *err); + struct tep_record *record, enum tep_errno *err); static const char * -get_comm(struct event_format *event, struct pevent_record *record) +get_comm(struct event_format *event, struct tep_record *record) { const char *comm; int pid; - pid = pevent_data_pid(event->pevent, record); - comm = pevent_data_comm_from_pid(event->pevent, pid); + pid = tep_data_pid(event->pevent, record); + comm = tep_data_comm_from_pid(event->pevent, pid); return comm; } static unsigned long long get_value(struct event_format *event, - struct format_field *field, struct pevent_record *record) + struct format_field *field, struct tep_record *record) { unsigned long long val; @@ -1728,7 +1714,7 @@ get_value(struct event_format *event, if (field == &cpu) return record->cpu; - pevent_read_number_field(field, record->data, &val); + tep_read_number_field(field, record->data, &val); if (!(field->flags & FIELD_IS_SIGNED)) return val; @@ -1748,11 +1734,11 @@ get_value(struct event_format *event, static unsigned long long get_arg_value(struct event_format *event, struct filter_arg *arg, - struct pevent_record *record, enum pevent_errno *err); + struct tep_record *record, enum tep_errno *err); static unsigned long long get_exp_value(struct event_format *event, struct filter_arg *arg, - struct pevent_record *record, enum pevent_errno *err) + struct tep_record *record, enum tep_errno *err) { unsigned long long lval, rval; @@ -1800,14 +1786,14 @@ get_exp_value(struct event_format *event, struct filter_arg *arg, case FILTER_EXP_NOT: default: if (!*err) - *err = PEVENT_ERRNO__INVALID_EXP_TYPE; + *err = TEP_ERRNO__INVALID_EXP_TYPE; } return 0; } static unsigned long long get_arg_value(struct event_format *event, struct filter_arg *arg, - struct pevent_record *record, enum pevent_errno *err) + struct tep_record *record, enum tep_errno *err) { switch (arg->type) { case FILTER_ARG_FIELD: @@ -1816,7 +1802,7 @@ get_arg_value(struct event_format *event, struct filter_arg *arg, case FILTER_ARG_VALUE: if (arg->value.type != FILTER_NUMBER) { if (!*err) - *err = PEVENT_ERRNO__NOT_A_NUMBER; + *err = TEP_ERRNO__NOT_A_NUMBER; } return arg->value.val; @@ -1825,13 +1811,13 @@ get_arg_value(struct event_format *event, struct filter_arg *arg, default: if (!*err) - *err = PEVENT_ERRNO__INVALID_ARG_TYPE; + *err = TEP_ERRNO__INVALID_ARG_TYPE; } return 0; } static int test_num(struct event_format *event, struct filter_arg *arg, - struct pevent_record *record, enum pevent_errno *err) + struct tep_record *record, enum tep_errno *err) { unsigned long long lval, rval; @@ -1866,15 +1852,15 @@ static int test_num(struct event_format *event, struct filter_arg *arg, default: if (!*err) - *err = PEVENT_ERRNO__ILLEGAL_INTEGER_CMP; + *err = TEP_ERRNO__ILLEGAL_INTEGER_CMP; return 0; } } -static const char *get_field_str(struct filter_arg *arg, struct pevent_record *record) +static const char *get_field_str(struct filter_arg *arg, struct tep_record *record) { struct event_format *event; - struct pevent *pevent; + struct tep_handle *pevent; unsigned long long addr; const char *val = NULL; unsigned int size; @@ -1909,7 +1895,7 @@ static const char *get_field_str(struct filter_arg *arg, struct pevent_record *r if (arg->str.field->flags & (FIELD_IS_POINTER | FIELD_IS_LONG)) /* convert to a kernel symbol */ - val = pevent_find_function(pevent, addr); + val = tep_find_function(pevent, addr); if (val == NULL) { /* just use the hex of the string name */ @@ -1922,7 +1908,7 @@ static const char *get_field_str(struct filter_arg *arg, struct pevent_record *r } static int test_str(struct event_format *event, struct filter_arg *arg, - struct pevent_record *record, enum pevent_errno *err) + struct tep_record *record, enum tep_errno *err) { const char *val; @@ -1947,13 +1933,13 @@ static int test_str(struct event_format *event, struct filter_arg *arg, default: if (!*err) - *err = PEVENT_ERRNO__ILLEGAL_STRING_CMP; + *err = TEP_ERRNO__ILLEGAL_STRING_CMP; return 0; } } static int test_op(struct event_format *event, struct filter_arg *arg, - struct pevent_record *record, enum pevent_errno *err) + struct tep_record *record, enum tep_errno *err) { switch (arg->op.type) { case FILTER_OP_AND: @@ -1969,13 +1955,13 @@ static int test_op(struct event_format *event, struct filter_arg *arg, default: if (!*err) - *err = PEVENT_ERRNO__INVALID_OP_TYPE; + *err = TEP_ERRNO__INVALID_OP_TYPE; return 0; } } static int test_filter(struct event_format *event, struct filter_arg *arg, - struct pevent_record *record, enum pevent_errno *err) + struct tep_record *record, enum tep_errno *err) { if (*err) { /* @@ -2009,20 +1995,20 @@ static int test_filter(struct event_format *event, struct filter_arg *arg, default: if (!*err) - *err = PEVENT_ERRNO__INVALID_ARG_TYPE; + *err = TEP_ERRNO__INVALID_ARG_TYPE; return 0; } } /** - * pevent_event_filtered - return true if event has filter + * tep_event_filtered - return true if event has filter * @filter: filter struct with filter information * @event_id: event id to test if filter exists * * Returns 1 if filter found for @event_id * otherwise 0; */ -int pevent_event_filtered(struct event_filter *filter, int event_id) +int tep_event_filtered(struct event_filter *filter, int event_id) { struct filter_type *filter_type; @@ -2035,42 +2021,42 @@ int pevent_event_filtered(struct event_filter *filter, int event_id) } /** - * pevent_filter_match - test if a record matches a filter + * tep_filter_match - test if a record matches a filter * @filter: filter struct with filter information * @record: the record to test against the filter * - * Returns: match result or error code (prefixed with PEVENT_ERRNO__) + * Returns: match result or error code (prefixed with TEP_ERRNO__) * FILTER_MATCH - filter found for event and @record matches * FILTER_MISS - filter found for event and @record does not match * FILTER_NOT_FOUND - no filter found for @record's event * NO_FILTER - if no filters exist * otherwise - error occurred during test */ -enum pevent_errno pevent_filter_match(struct event_filter *filter, - struct pevent_record *record) +enum tep_errno tep_filter_match(struct event_filter *filter, + struct tep_record *record) { - struct pevent *pevent = filter->pevent; + struct tep_handle *pevent = filter->pevent; struct filter_type *filter_type; int event_id; int ret; - enum pevent_errno err = 0; + enum tep_errno err = 0; filter_init_error_buf(filter); if (!filter->filters) - return PEVENT_ERRNO__NO_FILTER; + return TEP_ERRNO__NO_FILTER; - event_id = pevent_data_type(pevent, record); + event_id = tep_data_type(pevent, record); filter_type = find_filter_type(filter, event_id); if (!filter_type) - return PEVENT_ERRNO__FILTER_NOT_FOUND; + return TEP_ERRNO__FILTER_NOT_FOUND; ret = test_filter(filter_type->event, filter_type->filter, record, &err); if (err) return err; - return ret ? PEVENT_ERRNO__FILTER_MATCH : PEVENT_ERRNO__FILTER_MISS; + return ret ? TEP_ERRNO__FILTER_MATCH : TEP_ERRNO__FILTER_MISS; } static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) @@ -2364,7 +2350,7 @@ static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg) } /** - * pevent_filter_make_string - return a string showing the filter + * tep_filter_make_string - return a string showing the filter * @filter: filter struct with filter information * @event_id: the event id to return the filter string with * @@ -2373,7 +2359,7 @@ static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg) * NULL is returned if no filter is found or allocation failed. */ char * -pevent_filter_make_string(struct event_filter *filter, int event_id) +tep_filter_make_string(struct event_filter *filter, int event_id) { struct filter_type *filter_type; @@ -2389,7 +2375,7 @@ pevent_filter_make_string(struct event_filter *filter, int event_id) } /** - * pevent_filter_compare - compare two filters and return if they are the same + * tep_filter_compare - compare two filters and return if they are the same * @filter1: Filter to compare with @filter2 * @filter2: Filter to compare with @filter1 * @@ -2397,7 +2383,7 @@ pevent_filter_make_string(struct event_filter *filter, int event_id) * 1 if the two filters hold the same content. * 0 if they do not. */ -int pevent_filter_compare(struct event_filter *filter1, struct event_filter *filter2) +int tep_filter_compare(struct event_filter *filter1, struct event_filter *filter2) { struct filter_type *filter_type1; struct filter_type *filter_type2; diff --git a/tools/lib/traceevent/parse-utils.c b/tools/lib/traceevent/parse-utils.c index eda07fa31dca..77e4ec6402dd 100644 --- a/tools/lib/traceevent/parse-utils.c +++ b/tools/lib/traceevent/parse-utils.c @@ -1,21 +1,7 @@ +// SPDX-License-Identifier: LGPL-2.1 /* * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License (not later!) - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, see <http://www.gnu.org/licenses> - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #include <stdio.h> #include <stdlib.h> diff --git a/tools/lib/traceevent/plugin_cfg80211.c b/tools/lib/traceevent/plugin_cfg80211.c index 8f8586912da7..a51b366f47da 100644 --- a/tools/lib/traceevent/plugin_cfg80211.c +++ b/tools/lib/traceevent/plugin_cfg80211.c @@ -25,19 +25,19 @@ process___le16_to_cpup(struct trace_seq *s, unsigned long long *args) return val ? (long long) le16toh(*val) : 0; } -int PEVENT_PLUGIN_LOADER(struct pevent *pevent) +int TEP_PLUGIN_LOADER(struct tep_handle *pevent) { - pevent_register_print_function(pevent, - process___le16_to_cpup, - PEVENT_FUNC_ARG_INT, - "__le16_to_cpup", - PEVENT_FUNC_ARG_PTR, - PEVENT_FUNC_ARG_VOID); + tep_register_print_function(pevent, + process___le16_to_cpup, + TEP_FUNC_ARG_INT, + "__le16_to_cpup", + TEP_FUNC_ARG_PTR, + TEP_FUNC_ARG_VOID); return 0; } -void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) +void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent) { - pevent_unregister_print_function(pevent, process___le16_to_cpup, - "__le16_to_cpup"); + tep_unregister_print_function(pevent, process___le16_to_cpup, + "__le16_to_cpup"); } diff --git a/tools/lib/traceevent/plugin_function.c b/tools/lib/traceevent/plugin_function.c index 42dbf73758f3..424747475d37 100644 --- a/tools/lib/traceevent/plugin_function.c +++ b/tools/lib/traceevent/plugin_function.c @@ -33,7 +33,7 @@ static int cpus = -1; #define STK_BLK 10 -struct pevent_plugin_option plugin_options[] = +struct tep_plugin_option plugin_options[] = { { .name = "parent", @@ -53,8 +53,8 @@ struct pevent_plugin_option plugin_options[] = } }; -static struct pevent_plugin_option *ftrace_parent = &plugin_options[0]; -static struct pevent_plugin_option *ftrace_indent = &plugin_options[1]; +static struct tep_plugin_option *ftrace_parent = &plugin_options[0]; +static struct tep_plugin_option *ftrace_indent = &plugin_options[1]; static void add_child(struct func_stack *stack, const char *child, int pos) { @@ -122,25 +122,25 @@ static int add_and_get_index(const char *parent, const char *child, int cpu) return 0; } -static int function_handler(struct trace_seq *s, struct pevent_record *record, +static int function_handler(struct trace_seq *s, struct tep_record *record, struct event_format *event, void *context) { - struct pevent *pevent = event->pevent; + struct tep_handle *pevent = event->pevent; unsigned long long function; unsigned long long pfunction; const char *func; const char *parent; int index = 0; - if (pevent_get_field_val(s, event, "ip", record, &function, 1)) + if (tep_get_field_val(s, event, "ip", record, &function, 1)) return trace_seq_putc(s, '!'); - func = pevent_find_function(pevent, function); + func = tep_find_function(pevent, function); - if (pevent_get_field_val(s, event, "parent_ip", record, &pfunction, 1)) + if (tep_get_field_val(s, event, "parent_ip", record, &pfunction, 1)) return trace_seq_putc(s, '!'); - parent = pevent_find_function(pevent, pfunction); + parent = tep_find_function(pevent, pfunction); if (parent && ftrace_indent->set) index = add_and_get_index(parent, func, record->cpu); @@ -163,22 +163,22 @@ static int function_handler(struct trace_seq *s, struct pevent_record *record, return 0; } -int PEVENT_PLUGIN_LOADER(struct pevent *pevent) +int TEP_PLUGIN_LOADER(struct tep_handle *pevent) { - pevent_register_event_handler(pevent, -1, "ftrace", "function", - function_handler, NULL); + tep_register_event_handler(pevent, -1, "ftrace", "function", + function_handler, NULL); - traceevent_plugin_add_options("ftrace", plugin_options); + tep_plugin_add_options("ftrace", plugin_options); return 0; } -void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) +void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent) { int i, x; - pevent_unregister_event_handler(pevent, -1, "ftrace", "function", - function_handler, NULL); + tep_unregister_event_handler(pevent, -1, "ftrace", "function", + function_handler, NULL); for (i = 0; i <= cpus; i++) { for (x = 0; x < fstack[i].size && fstack[i].stack[x]; x++) @@ -186,7 +186,7 @@ void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) free(fstack[i].stack); } - traceevent_plugin_remove_options(plugin_options); + tep_plugin_remove_options(plugin_options); free(fstack); fstack = NULL; diff --git a/tools/lib/traceevent/plugin_hrtimer.c b/tools/lib/traceevent/plugin_hrtimer.c index 12bf14cc1152..b43bfec565d8 100644 --- a/tools/lib/traceevent/plugin_hrtimer.c +++ b/tools/lib/traceevent/plugin_hrtimer.c @@ -25,64 +25,64 @@ #include "event-parse.h" static int timer_expire_handler(struct trace_seq *s, - struct pevent_record *record, + struct tep_record *record, struct event_format *event, void *context) { trace_seq_printf(s, "hrtimer="); - if (pevent_print_num_field(s, "0x%llx", event, "timer", - record, 0) == -1) - pevent_print_num_field(s, "0x%llx", event, "hrtimer", - record, 1); + if (tep_print_num_field(s, "0x%llx", event, "timer", + record, 0) == -1) + tep_print_num_field(s, "0x%llx", event, "hrtimer", + record, 1); trace_seq_printf(s, " now="); - pevent_print_num_field(s, "%llu", event, "now", record, 1); + tep_print_num_field(s, "%llu", event, "now", record, 1); - pevent_print_func_field(s, " function=%s", event, "function", + tep_print_func_field(s, " function=%s", event, "function", record, 0); return 0; } static int timer_start_handler(struct trace_seq *s, - struct pevent_record *record, + struct tep_record *record, struct event_format *event, void *context) { trace_seq_printf(s, "hrtimer="); - if (pevent_print_num_field(s, "0x%llx", event, "timer", - record, 0) == -1) - pevent_print_num_field(s, "0x%llx", event, "hrtimer", - record, 1); + if (tep_print_num_field(s, "0x%llx", event, "timer", + record, 0) == -1) + tep_print_num_field(s, "0x%llx", event, "hrtimer", + record, 1); - pevent_print_func_field(s, " function=%s", event, "function", - record, 0); + tep_print_func_field(s, " function=%s", event, "function", + record, 0); trace_seq_printf(s, " expires="); - pevent_print_num_field(s, "%llu", event, "expires", record, 1); + tep_print_num_field(s, "%llu", event, "expires", record, 1); trace_seq_printf(s, " softexpires="); - pevent_print_num_field(s, "%llu", event, "softexpires", record, 1); + tep_print_num_field(s, "%llu", event, "softexpires", record, 1); return 0; } -int PEVENT_PLUGIN_LOADER(struct pevent *pevent) +int TEP_PLUGIN_LOADER(struct tep_handle *pevent) { - pevent_register_event_handler(pevent, -1, - "timer", "hrtimer_expire_entry", - timer_expire_handler, NULL); + tep_register_event_handler(pevent, -1, + "timer", "hrtimer_expire_entry", + timer_expire_handler, NULL); - pevent_register_event_handler(pevent, -1, "timer", "hrtimer_start", - timer_start_handler, NULL); + tep_register_event_handler(pevent, -1, "timer", "hrtimer_start", + timer_start_handler, NULL); return 0; } -void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) +void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent) { - pevent_unregister_event_handler(pevent, -1, - "timer", "hrtimer_expire_entry", - timer_expire_handler, NULL); + tep_unregister_event_handler(pevent, -1, + "timer", "hrtimer_expire_entry", + timer_expire_handler, NULL); - pevent_unregister_event_handler(pevent, -1, "timer", "hrtimer_start", - timer_start_handler, NULL); + tep_unregister_event_handler(pevent, -1, "timer", "hrtimer_start", + timer_start_handler, NULL); } diff --git a/tools/lib/traceevent/plugin_jbd2.c b/tools/lib/traceevent/plugin_jbd2.c index 5c23d5bd27ce..45a9acd19640 100644 --- a/tools/lib/traceevent/plugin_jbd2.c +++ b/tools/lib/traceevent/plugin_jbd2.c @@ -47,29 +47,29 @@ process_jiffies_to_msecs(struct trace_seq *s, unsigned long long *args) return jiffies; } -int PEVENT_PLUGIN_LOADER(struct pevent *pevent) +int TEP_PLUGIN_LOADER(struct tep_handle *pevent) { - pevent_register_print_function(pevent, - process_jbd2_dev_to_name, - PEVENT_FUNC_ARG_STRING, - "jbd2_dev_to_name", - PEVENT_FUNC_ARG_INT, - PEVENT_FUNC_ARG_VOID); + tep_register_print_function(pevent, + process_jbd2_dev_to_name, + TEP_FUNC_ARG_STRING, + "jbd2_dev_to_name", + TEP_FUNC_ARG_INT, + TEP_FUNC_ARG_VOID); - pevent_register_print_function(pevent, - process_jiffies_to_msecs, - PEVENT_FUNC_ARG_LONG, - "jiffies_to_msecs", - PEVENT_FUNC_ARG_LONG, - PEVENT_FUNC_ARG_VOID); + tep_register_print_function(pevent, + process_jiffies_to_msecs, + TEP_FUNC_ARG_LONG, + "jiffies_to_msecs", + TEP_FUNC_ARG_LONG, + TEP_FUNC_ARG_VOID); return 0; } -void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) +void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent) { - pevent_unregister_print_function(pevent, process_jbd2_dev_to_name, - "jbd2_dev_to_name"); + tep_unregister_print_function(pevent, process_jbd2_dev_to_name, + "jbd2_dev_to_name"); - pevent_unregister_print_function(pevent, process_jiffies_to_msecs, - "jiffies_to_msecs"); + tep_unregister_print_function(pevent, process_jiffies_to_msecs, + "jiffies_to_msecs"); } diff --git a/tools/lib/traceevent/plugin_kmem.c b/tools/lib/traceevent/plugin_kmem.c index 70650ff48d78..73966b05abce 100644 --- a/tools/lib/traceevent/plugin_kmem.c +++ b/tools/lib/traceevent/plugin_kmem.c @@ -23,7 +23,7 @@ #include "event-parse.h" -static int call_site_handler(struct trace_seq *s, struct pevent_record *record, +static int call_site_handler(struct trace_seq *s, struct tep_record *record, struct event_format *event, void *context) { struct format_field *field; @@ -31,64 +31,64 @@ static int call_site_handler(struct trace_seq *s, struct pevent_record *record, void *data = record->data; const char *func; - field = pevent_find_field(event, "call_site"); + field = tep_find_field(event, "call_site"); if (!field) return 1; - if (pevent_read_number_field(field, data, &val)) + if (tep_read_number_field(field, data, &val)) return 1; - func = pevent_find_function(event->pevent, val); + func = tep_find_function(event->pevent, val); if (!func) return 1; - addr = pevent_find_function_address(event->pevent, val); + addr = tep_find_function_address(event->pevent, val); trace_seq_printf(s, "(%s+0x%x) ", func, (int)(val - addr)); return 1; } -int PEVENT_PLUGIN_LOADER(struct pevent *pevent) +int TEP_PLUGIN_LOADER(struct tep_handle *pevent) { - pevent_register_event_handler(pevent, -1, "kmem", "kfree", - call_site_handler, NULL); + tep_register_event_handler(pevent, -1, "kmem", "kfree", + call_site_handler, NULL); - pevent_register_event_handler(pevent, -1, "kmem", "kmalloc", - call_site_handler, NULL); + tep_register_event_handler(pevent, -1, "kmem", "kmalloc", + call_site_handler, NULL); - pevent_register_event_handler(pevent, -1, "kmem", "kmalloc_node", - call_site_handler, NULL); + tep_register_event_handler(pevent, -1, "kmem", "kmalloc_node", + call_site_handler, NULL); - pevent_register_event_handler(pevent, -1, "kmem", "kmem_cache_alloc", - call_site_handler, NULL); + tep_register_event_handler(pevent, -1, "kmem", "kmem_cache_alloc", + call_site_handler, NULL); - pevent_register_event_handler(pevent, -1, "kmem", - "kmem_cache_alloc_node", - call_site_handler, NULL); + tep_register_event_handler(pevent, -1, "kmem", + "kmem_cache_alloc_node", + call_site_handler, NULL); - pevent_register_event_handler(pevent, -1, "kmem", "kmem_cache_free", - call_site_handler, NULL); + tep_register_event_handler(pevent, -1, "kmem", "kmem_cache_free", + call_site_handler, NULL); return 0; } -void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) +void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent) { - pevent_unregister_event_handler(pevent, -1, "kmem", "kfree", - call_site_handler, NULL); + tep_unregister_event_handler(pevent, -1, "kmem", "kfree", + call_site_handler, NULL); - pevent_unregister_event_handler(pevent, -1, "kmem", "kmalloc", - call_site_handler, NULL); + tep_unregister_event_handler(pevent, -1, "kmem", "kmalloc", + call_site_handler, NULL); - pevent_unregister_event_handler(pevent, -1, "kmem", "kmalloc_node", - call_site_handler, NULL); + tep_unregister_event_handler(pevent, -1, "kmem", "kmalloc_node", + call_site_handler, NULL); - pevent_unregister_event_handler(pevent, -1, "kmem", "kmem_cache_alloc", - call_site_handler, NULL); + tep_unregister_event_handler(pevent, -1, "kmem", "kmem_cache_alloc", + call_site_handler, NULL); - pevent_unregister_event_handler(pevent, -1, "kmem", - "kmem_cache_alloc_node", - call_site_handler, NULL); + tep_unregister_event_handler(pevent, -1, "kmem", + "kmem_cache_alloc_node", + call_site_handler, NULL); - pevent_unregister_event_handler(pevent, -1, "kmem", "kmem_cache_free", - call_site_handler, NULL); + tep_unregister_event_handler(pevent, -1, "kmem", "kmem_cache_free", + call_site_handler, NULL); } diff --git a/tools/lib/traceevent/plugin_kvm.c b/tools/lib/traceevent/plugin_kvm.c index 18536f756577..1d0d15906225 100644 --- a/tools/lib/traceevent/plugin_kvm.c +++ b/tools/lib/traceevent/plugin_kvm.c @@ -247,17 +247,17 @@ static const char *find_exit_reason(unsigned isa, int val) return strings[i].str; } -static int print_exit_reason(struct trace_seq *s, struct pevent_record *record, +static int print_exit_reason(struct trace_seq *s, struct tep_record *record, struct event_format *event, const char *field) { unsigned long long isa; unsigned long long val; const char *reason; - if (pevent_get_field_val(s, event, field, record, &val, 1) < 0) + if (tep_get_field_val(s, event, field, record, &val, 1) < 0) return -1; - if (pevent_get_field_val(s, event, "isa", record, &isa, 0) < 0) + if (tep_get_field_val(s, event, "isa", record, &isa, 0) < 0) isa = 1; reason = find_exit_reason(isa, val); @@ -268,7 +268,7 @@ static int print_exit_reason(struct trace_seq *s, struct pevent_record *record, return 0; } -static int kvm_exit_handler(struct trace_seq *s, struct pevent_record *record, +static int kvm_exit_handler(struct trace_seq *s, struct tep_record *record, struct event_format *event, void *context) { unsigned long long info1 = 0, info2 = 0; @@ -276,10 +276,10 @@ static int kvm_exit_handler(struct trace_seq *s, struct pevent_record *record, if (print_exit_reason(s, record, event, "exit_reason") < 0) return -1; - pevent_print_num_field(s, " rip 0x%lx", event, "guest_rip", record, 1); + tep_print_num_field(s, " rip 0x%lx", event, "guest_rip", record, 1); - if (pevent_get_field_val(s, event, "info1", record, &info1, 0) >= 0 - && pevent_get_field_val(s, event, "info2", record, &info2, 0) >= 0) + if (tep_get_field_val(s, event, "info1", record, &info1, 0) >= 0 + && tep_get_field_val(s, event, "info2", record, &info2, 0) >= 0) trace_seq_printf(s, " info %llx %llx", info1, info2); return 0; @@ -291,7 +291,7 @@ static int kvm_exit_handler(struct trace_seq *s, struct pevent_record *record, #define KVM_EMUL_INSN_F_CS_L (1 << 3) static int kvm_emulate_insn_handler(struct trace_seq *s, - struct pevent_record *record, + struct tep_record *record, struct event_format *event, void *context) { unsigned long long rip, csbase, len, flags, failed; @@ -299,22 +299,22 @@ static int kvm_emulate_insn_handler(struct trace_seq *s, uint8_t *insn; const char *disasm; - if (pevent_get_field_val(s, event, "rip", record, &rip, 1) < 0) + if (tep_get_field_val(s, event, "rip", record, &rip, 1) < 0) return -1; - if (pevent_get_field_val(s, event, "csbase", record, &csbase, 1) < 0) + if (tep_get_field_val(s, event, "csbase", record, &csbase, 1) < 0) return -1; - if (pevent_get_field_val(s, event, "len", record, &len, 1) < 0) + if (tep_get_field_val(s, event, "len", record, &len, 1) < 0) return -1; - if (pevent_get_field_val(s, event, "flags", record, &flags, 1) < 0) + if (tep_get_field_val(s, event, "flags", record, &flags, 1) < 0) return -1; - if (pevent_get_field_val(s, event, "failed", record, &failed, 1) < 0) + if (tep_get_field_val(s, event, "failed", record, &failed, 1) < 0) return -1; - insn = pevent_get_field_raw(s, event, "insn", record, &llen, 1); + insn = tep_get_field_raw(s, event, "insn", record, &llen, 1); if (!insn) return -1; @@ -330,24 +330,24 @@ static int kvm_emulate_insn_handler(struct trace_seq *s, } -static int kvm_nested_vmexit_inject_handler(struct trace_seq *s, struct pevent_record *record, +static int kvm_nested_vmexit_inject_handler(struct trace_seq *s, struct tep_record *record, struct event_format *event, void *context) { if (print_exit_reason(s, record, event, "exit_code") < 0) return -1; - pevent_print_num_field(s, " info1 %llx", event, "exit_info1", record, 1); - pevent_print_num_field(s, " info2 %llx", event, "exit_info2", record, 1); - pevent_print_num_field(s, " int_info %llx", event, "exit_int_info", record, 1); - pevent_print_num_field(s, " int_info_err %llx", event, "exit_int_info_err", record, 1); + tep_print_num_field(s, " info1 %llx", event, "exit_info1", record, 1); + tep_print_num_field(s, " info2 %llx", event, "exit_info2", record, 1); + tep_print_num_field(s, " int_info %llx", event, "exit_int_info", record, 1); + tep_print_num_field(s, " int_info_err %llx", event, "exit_int_info_err", record, 1); return 0; } -static int kvm_nested_vmexit_handler(struct trace_seq *s, struct pevent_record *record, +static int kvm_nested_vmexit_handler(struct trace_seq *s, struct tep_record *record, struct event_format *event, void *context) { - pevent_print_num_field(s, "rip %llx ", event, "rip", record, 1); + tep_print_num_field(s, "rip %llx ", event, "rip", record, 1); return kvm_nested_vmexit_inject_handler(s, record, event, context); } @@ -370,7 +370,7 @@ union kvm_mmu_page_role { }; }; -static int kvm_mmu_print_role(struct trace_seq *s, struct pevent_record *record, +static int kvm_mmu_print_role(struct trace_seq *s, struct tep_record *record, struct event_format *event, void *context) { unsigned long long val; @@ -379,7 +379,7 @@ static int kvm_mmu_print_role(struct trace_seq *s, struct pevent_record *record, }; union kvm_mmu_page_role role; - if (pevent_get_field_val(s, event, "role", record, &val, 1) < 0) + if (tep_get_field_val(s, event, "role", record, &val, 1) < 0) return -1; role.word = (int)val; @@ -388,8 +388,8 @@ static int kvm_mmu_print_role(struct trace_seq *s, struct pevent_record *record, * We can only use the structure if file is of the same * endianess. */ - if (pevent_is_file_bigendian(event->pevent) == - pevent_is_host_bigendian(event->pevent)) { + if (tep_is_file_bigendian(event->pevent) == + tep_is_host_bigendian(event->pevent)) { trace_seq_printf(s, "%u q%u%s %s%s %spae %snxe %swp%s%s%s", role.level, @@ -406,10 +406,10 @@ static int kvm_mmu_print_role(struct trace_seq *s, struct pevent_record *record, } else trace_seq_printf(s, "WORD: %08x", role.word); - pevent_print_num_field(s, " root %u ", event, - "root_count", record, 1); + tep_print_num_field(s, " root %u ", event, + "root_count", record, 1); - if (pevent_get_field_val(s, event, "unsync", record, &val, 1) < 0) + if (tep_get_field_val(s, event, "unsync", record, &val, 1) < 0) return -1; trace_seq_printf(s, "%s%c", val ? "unsync" : "sync", 0); @@ -417,17 +417,17 @@ static int kvm_mmu_print_role(struct trace_seq *s, struct pevent_record *record, } static int kvm_mmu_get_page_handler(struct trace_seq *s, - struct pevent_record *record, + struct tep_record *record, struct event_format *event, void *context) { unsigned long long val; - if (pevent_get_field_val(s, event, "created", record, &val, 1) < 0) + if (tep_get_field_val(s, event, "created", record, &val, 1) < 0) return -1; trace_seq_printf(s, "%s ", val ? "new" : "existing"); - if (pevent_get_field_val(s, event, "gfn", record, &val, 1) < 0) + if (tep_get_field_val(s, event, "gfn", record, &val, 1) < 0) return -1; trace_seq_printf(s, "sp gfn %llx ", val); @@ -444,79 +444,79 @@ process_is_writable_pte(struct trace_seq *s, unsigned long long *args) return pte & PT_WRITABLE_MASK; } -int PEVENT_PLUGIN_LOADER(struct pevent *pevent) +int TEP_PLUGIN_LOADER(struct tep_handle *pevent) { init_disassembler(); - pevent_register_event_handler(pevent, -1, "kvm", "kvm_exit", - kvm_exit_handler, NULL); + tep_register_event_handler(pevent, -1, "kvm", "kvm_exit", + kvm_exit_handler, NULL); - pevent_register_event_handler(pevent, -1, "kvm", "kvm_emulate_insn", - kvm_emulate_insn_handler, NULL); + tep_register_event_handler(pevent, -1, "kvm", "kvm_emulate_insn", + kvm_emulate_insn_handler, NULL); - pevent_register_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit", - kvm_nested_vmexit_handler, NULL); + tep_register_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit", + kvm_nested_vmexit_handler, NULL); - pevent_register_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit_inject", - kvm_nested_vmexit_inject_handler, NULL); + tep_register_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit_inject", + kvm_nested_vmexit_inject_handler, NULL); - pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page", - kvm_mmu_get_page_handler, NULL); + tep_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page", + kvm_mmu_get_page_handler, NULL); - pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page", - kvm_mmu_print_role, NULL); + tep_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page", + kvm_mmu_print_role, NULL); - pevent_register_event_handler(pevent, -1, - "kvmmmu", "kvm_mmu_unsync_page", - kvm_mmu_print_role, NULL); + tep_register_event_handler(pevent, -1, + "kvmmmu", "kvm_mmu_unsync_page", + kvm_mmu_print_role, NULL); - pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page", - kvm_mmu_print_role, NULL); + tep_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page", + kvm_mmu_print_role, NULL); - pevent_register_event_handler(pevent, -1, "kvmmmu", + tep_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_prepare_zap_page", kvm_mmu_print_role, NULL); - pevent_register_print_function(pevent, - process_is_writable_pte, - PEVENT_FUNC_ARG_INT, - "is_writable_pte", - PEVENT_FUNC_ARG_LONG, - PEVENT_FUNC_ARG_VOID); + tep_register_print_function(pevent, + process_is_writable_pte, + TEP_FUNC_ARG_INT, + "is_writable_pte", + TEP_FUNC_ARG_LONG, + TEP_FUNC_ARG_VOID); return 0; } -void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) +void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent) { - pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_exit", - kvm_exit_handler, NULL); + tep_unregister_event_handler(pevent, -1, "kvm", "kvm_exit", + kvm_exit_handler, NULL); - pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_emulate_insn", - kvm_emulate_insn_handler, NULL); + tep_unregister_event_handler(pevent, -1, "kvm", "kvm_emulate_insn", + kvm_emulate_insn_handler, NULL); - pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit", - kvm_nested_vmexit_handler, NULL); + tep_unregister_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit", + kvm_nested_vmexit_handler, NULL); - pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit_inject", - kvm_nested_vmexit_inject_handler, NULL); + tep_unregister_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit_inject", + kvm_nested_vmexit_inject_handler, NULL); - pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page", - kvm_mmu_get_page_handler, NULL); + tep_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page", + kvm_mmu_get_page_handler, NULL); - pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page", - kvm_mmu_print_role, NULL); + tep_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page", + kvm_mmu_print_role, NULL); - pevent_unregister_event_handler(pevent, -1, - "kvmmmu", "kvm_mmu_unsync_page", - kvm_mmu_print_role, NULL); + tep_unregister_event_handler(pevent, -1, + "kvmmmu", "kvm_mmu_unsync_page", + kvm_mmu_print_role, NULL); - pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page", - kvm_mmu_print_role, NULL); + tep_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page", + kvm_mmu_print_role, NULL); - pevent_unregister_event_handler(pevent, -1, "kvmmmu", + tep_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_prepare_zap_page", kvm_mmu_print_role, NULL); - pevent_unregister_print_function(pevent, process_is_writable_pte, - "is_writable_pte"); + tep_unregister_print_function(pevent, process_is_writable_pte, + "is_writable_pte"); } diff --git a/tools/lib/traceevent/plugin_mac80211.c b/tools/lib/traceevent/plugin_mac80211.c index 7e15a0f1c2fd..de50a5316203 100644 --- a/tools/lib/traceevent/plugin_mac80211.c +++ b/tools/lib/traceevent/plugin_mac80211.c @@ -28,7 +28,7 @@ static void print_string(struct trace_seq *s, struct event_format *event, const char *name, const void *data) { - struct format_field *f = pevent_find_field(event, name); + struct format_field *f = tep_find_field(event, name); int offset; int length; @@ -42,7 +42,7 @@ static void print_string(struct trace_seq *s, struct event_format *event, if (!strncmp(f->type, "__data_loc", 10)) { unsigned long long v; - if (pevent_read_number_field(f, data, &v)) { + if (tep_read_number_field(f, data, &v)) { trace_seq_printf(s, "invalid_data_loc"); return; } @@ -53,12 +53,12 @@ static void print_string(struct trace_seq *s, struct event_format *event, trace_seq_printf(s, "%.*s", length, (char *)data + offset); } -#define SF(fn) pevent_print_num_field(s, fn ":%d", event, fn, record, 0) -#define SFX(fn) pevent_print_num_field(s, fn ":%#x", event, fn, record, 0) +#define SF(fn) tep_print_num_field(s, fn ":%d", event, fn, record, 0) +#define SFX(fn) tep_print_num_field(s, fn ":%#x", event, fn, record, 0) #define SP() trace_seq_putc(s, ' ') static int drv_bss_info_changed(struct trace_seq *s, - struct pevent_record *record, + struct tep_record *record, struct event_format *event, void *context) { void *data = record->data; @@ -66,7 +66,7 @@ static int drv_bss_info_changed(struct trace_seq *s, print_string(s, event, "wiphy_name", data); trace_seq_printf(s, " vif:"); print_string(s, event, "vif_name", data); - pevent_print_num_field(s, "(%d)", event, "vif_type", record, 1); + tep_print_num_field(s, "(%d)", event, "vif_type", record, 1); trace_seq_printf(s, "\n%*s", INDENT, ""); SF("assoc"); SP(); @@ -86,17 +86,17 @@ static int drv_bss_info_changed(struct trace_seq *s, return 0; } -int PEVENT_PLUGIN_LOADER(struct pevent *pevent) +int TEP_PLUGIN_LOADER(struct tep_handle *pevent) { - pevent_register_event_handler(pevent, -1, "mac80211", - "drv_bss_info_changed", - drv_bss_info_changed, NULL); + tep_register_event_handler(pevent, -1, "mac80211", + "drv_bss_info_changed", + drv_bss_info_changed, NULL); return 0; } -void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) +void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent) { - pevent_unregister_event_handler(pevent, -1, "mac80211", - "drv_bss_info_changed", - drv_bss_info_changed, NULL); + tep_unregister_event_handler(pevent, -1, "mac80211", + "drv_bss_info_changed", + drv_bss_info_changed, NULL); } diff --git a/tools/lib/traceevent/plugin_sched_switch.c b/tools/lib/traceevent/plugin_sched_switch.c index ec30c2fcbac0..eecb4bd95c11 100644 --- a/tools/lib/traceevent/plugin_sched_switch.c +++ b/tools/lib/traceevent/plugin_sched_switch.c @@ -45,7 +45,7 @@ static void write_state(struct trace_seq *s, int val) } static void write_and_save_comm(struct format_field *field, - struct pevent_record *record, + struct tep_record *record, struct trace_seq *s, int pid) { const char *comm; @@ -61,100 +61,100 @@ static void write_and_save_comm(struct format_field *field, comm = &s->buffer[len]; /* Help out the comm to ids. This will handle dups */ - pevent_register_comm(field->event->pevent, comm, pid); + tep_register_comm(field->event->pevent, comm, pid); } static int sched_wakeup_handler(struct trace_seq *s, - struct pevent_record *record, + struct tep_record *record, struct event_format *event, void *context) { struct format_field *field; unsigned long long val; - if (pevent_get_field_val(s, event, "pid", record, &val, 1)) + if (tep_get_field_val(s, event, "pid", record, &val, 1)) return trace_seq_putc(s, '!'); - field = pevent_find_any_field(event, "comm"); + field = tep_find_any_field(event, "comm"); if (field) { write_and_save_comm(field, record, s, val); trace_seq_putc(s, ':'); } trace_seq_printf(s, "%lld", val); - if (pevent_get_field_val(s, event, "prio", record, &val, 0) == 0) + if (tep_get_field_val(s, event, "prio", record, &val, 0) == 0) trace_seq_printf(s, " [%lld]", val); - if (pevent_get_field_val(s, event, "success", record, &val, 1) == 0) + if (tep_get_field_val(s, event, "success", record, &val, 1) == 0) trace_seq_printf(s, " success=%lld", val); - if (pevent_get_field_val(s, event, "target_cpu", record, &val, 0) == 0) + if (tep_get_field_val(s, event, "target_cpu", record, &val, 0) == 0) trace_seq_printf(s, " CPU:%03llu", val); return 0; } static int sched_switch_handler(struct trace_seq *s, - struct pevent_record *record, + struct tep_record *record, struct event_format *event, void *context) { struct format_field *field; unsigned long long val; - if (pevent_get_field_val(s, event, "prev_pid", record, &val, 1)) + if (tep_get_field_val(s, event, "prev_pid", record, &val, 1)) return trace_seq_putc(s, '!'); - field = pevent_find_any_field(event, "prev_comm"); + field = tep_find_any_field(event, "prev_comm"); if (field) { write_and_save_comm(field, record, s, val); trace_seq_putc(s, ':'); } trace_seq_printf(s, "%lld ", val); - if (pevent_get_field_val(s, event, "prev_prio", record, &val, 0) == 0) + if (tep_get_field_val(s, event, "prev_prio", record, &val, 0) == 0) trace_seq_printf(s, "[%d] ", (int) val); - if (pevent_get_field_val(s, event, "prev_state", record, &val, 0) == 0) + if (tep_get_field_val(s, event, "prev_state", record, &val, 0) == 0) write_state(s, val); trace_seq_puts(s, " ==> "); - if (pevent_get_field_val(s, event, "next_pid", record, &val, 1)) + if (tep_get_field_val(s, event, "next_pid", record, &val, 1)) return trace_seq_putc(s, '!'); - field = pevent_find_any_field(event, "next_comm"); + field = tep_find_any_field(event, "next_comm"); if (field) { write_and_save_comm(field, record, s, val); trace_seq_putc(s, ':'); } trace_seq_printf(s, "%lld", val); - if (pevent_get_field_val(s, event, "next_prio", record, &val, 0) == 0) + if (tep_get_field_val(s, event, "next_prio", record, &val, 0) == 0) trace_seq_printf(s, " [%d]", (int) val); return 0; } -int PEVENT_PLUGIN_LOADER(struct pevent *pevent) +int TEP_PLUGIN_LOADER(struct tep_handle *pevent) { - pevent_register_event_handler(pevent, -1, "sched", "sched_switch", - sched_switch_handler, NULL); + tep_register_event_handler(pevent, -1, "sched", "sched_switch", + sched_switch_handler, NULL); - pevent_register_event_handler(pevent, -1, "sched", "sched_wakeup", - sched_wakeup_handler, NULL); + tep_register_event_handler(pevent, -1, "sched", "sched_wakeup", + sched_wakeup_handler, NULL); - pevent_register_event_handler(pevent, -1, "sched", "sched_wakeup_new", - sched_wakeup_handler, NULL); + tep_register_event_handler(pevent, -1, "sched", "sched_wakeup_new", + sched_wakeup_handler, NULL); return 0; } -void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) +void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent) { - pevent_unregister_event_handler(pevent, -1, "sched", "sched_switch", - sched_switch_handler, NULL); + tep_unregister_event_handler(pevent, -1, "sched", "sched_switch", + sched_switch_handler, NULL); - pevent_unregister_event_handler(pevent, -1, "sched", "sched_wakeup", - sched_wakeup_handler, NULL); + tep_unregister_event_handler(pevent, -1, "sched", "sched_wakeup", + sched_wakeup_handler, NULL); - pevent_unregister_event_handler(pevent, -1, "sched", "sched_wakeup_new", - sched_wakeup_handler, NULL); + tep_unregister_event_handler(pevent, -1, "sched", "sched_wakeup_new", + sched_wakeup_handler, NULL); } diff --git a/tools/lib/traceevent/plugin_scsi.c b/tools/lib/traceevent/plugin_scsi.c index 5e750af2b461..5ec346f6b842 100644 --- a/tools/lib/traceevent/plugin_scsi.c +++ b/tools/lib/traceevent/plugin_scsi.c @@ -413,21 +413,21 @@ unsigned long long process_scsi_trace_parse_cdb(struct trace_seq *s, return 0; } -int PEVENT_PLUGIN_LOADER(struct pevent *pevent) +int TEP_PLUGIN_LOADER(struct tep_handle *pevent) { - pevent_register_print_function(pevent, - process_scsi_trace_parse_cdb, - PEVENT_FUNC_ARG_STRING, - "scsi_trace_parse_cdb", - PEVENT_FUNC_ARG_PTR, - PEVENT_FUNC_ARG_PTR, - PEVENT_FUNC_ARG_INT, - PEVENT_FUNC_ARG_VOID); + tep_register_print_function(pevent, + process_scsi_trace_parse_cdb, + TEP_FUNC_ARG_STRING, + "scsi_trace_parse_cdb", + TEP_FUNC_ARG_PTR, + TEP_FUNC_ARG_PTR, + TEP_FUNC_ARG_INT, + TEP_FUNC_ARG_VOID); return 0; } -void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) +void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent) { - pevent_unregister_print_function(pevent, process_scsi_trace_parse_cdb, - "scsi_trace_parse_cdb"); + tep_unregister_print_function(pevent, process_scsi_trace_parse_cdb, + "scsi_trace_parse_cdb"); } diff --git a/tools/lib/traceevent/plugin_xen.c b/tools/lib/traceevent/plugin_xen.c index 690173bfa13e..b2acbd6e9c86 100644 --- a/tools/lib/traceevent/plugin_xen.c +++ b/tools/lib/traceevent/plugin_xen.c @@ -119,19 +119,19 @@ unsigned long long process_xen_hypercall_name(struct trace_seq *s, return 0; } -int PEVENT_PLUGIN_LOADER(struct pevent *pevent) +int TEP_PLUGIN_LOADER(struct tep_handle *pevent) { - pevent_register_print_function(pevent, - process_xen_hypercall_name, - PEVENT_FUNC_ARG_STRING, - "xen_hypercall_name", - PEVENT_FUNC_ARG_INT, - PEVENT_FUNC_ARG_VOID); + tep_register_print_function(pevent, + process_xen_hypercall_name, + TEP_FUNC_ARG_STRING, + "xen_hypercall_name", + TEP_FUNC_ARG_INT, + TEP_FUNC_ARG_VOID); return 0; } -void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) +void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent) { - pevent_unregister_print_function(pevent, process_xen_hypercall_name, - "xen_hypercall_name"); + tep_unregister_print_function(pevent, process_xen_hypercall_name, + "xen_hypercall_name"); } diff --git a/tools/lib/traceevent/trace-seq.c b/tools/lib/traceevent/trace-seq.c index 292dc9f1d233..e3bac4543d3b 100644 --- a/tools/lib/traceevent/trace-seq.c +++ b/tools/lib/traceevent/trace-seq.c @@ -1,21 +1,7 @@ +// SPDX-License-Identifier: LGPL-2.1 /* * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License (not later!) - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, see <http://www.gnu.org/licenses> - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #include <stdio.h> #include <stdlib.h> diff --git a/tools/memory-model/Documentation/explanation.txt b/tools/memory-model/Documentation/explanation.txt index 1b09f3175a1f..0cbd1ef8f86d 100644 --- a/tools/memory-model/Documentation/explanation.txt +++ b/tools/memory-model/Documentation/explanation.txt @@ -804,7 +804,7 @@ type of fence: Second, some types of fence affect the way the memory subsystem propagates stores. When a fence instruction is executed on CPU C: - For each other CPU C', smb_wmb() forces all po-earlier stores + For each other CPU C', smp_wmb() forces all po-earlier stores on C to propagate to C' before any po-later stores do. For each other CPU C', any store which propagates to C before diff --git a/tools/memory-model/Documentation/recipes.txt b/tools/memory-model/Documentation/recipes.txt index ee4309a87fc4..af72700cc20a 100644 --- a/tools/memory-model/Documentation/recipes.txt +++ b/tools/memory-model/Documentation/recipes.txt @@ -126,7 +126,7 @@ However, it is not necessarily the case that accesses ordered by locking will be seen as ordered by CPUs not holding that lock. Consider this example: - /* See Z6.0+pooncelock+pooncelock+pombonce.litmus. */ + /* See Z6.0+pooncerelease+poacquirerelease+fencembonceonce.litmus. */ void CPU0(void) { spin_lock(&mylock); @@ -292,7 +292,7 @@ and to use smp_load_acquire() instead of smp_rmb(). However, the older smp_wmb() and smp_rmb() APIs are still heavily used, so it is important to understand their use cases. The general approach is shown below: - /* See MP+wmbonceonce+rmbonceonce.litmus. */ + /* See MP+fencewmbonceonce+fencermbonceonce.litmus. */ void CPU0(void) { WRITE_ONCE(x, 1); @@ -322,9 +322,9 @@ the following write-side code fragment: And the xlog_valid_lsn() function in fs/xfs/xfs_log_priv.h contains the corresponding read-side code fragment: - cur_cycle = ACCESS_ONCE(log->l_curr_cycle); + cur_cycle = READ_ONCE(log->l_curr_cycle); smp_rmb(); - cur_block = ACCESS_ONCE(log->l_curr_block); + cur_block = READ_ONCE(log->l_curr_block); Alternatively, consider the following comment in function perf_output_put_handle() in kernel/events/ring_buffer.c: @@ -360,7 +360,7 @@ can be seen in the LB+poonceonces.litmus litmus test. One way of avoiding the counter-intuitive outcome is through the use of a control dependency paired with a full memory barrier: - /* See LB+ctrlonceonce+mbonceonce.litmus. */ + /* See LB+fencembonceonce+ctrlonceonce.litmus. */ void CPU0(void) { r0 = READ_ONCE(x); @@ -476,7 +476,7 @@ that one CPU first stores to one variable and then loads from a second, while another CPU stores to the second variable and then loads from the first. Preserving order requires nothing less than full barriers: - /* See SB+mbonceonces.litmus. */ + /* See SB+fencembonceonces.litmus. */ void CPU0(void) { WRITE_ONCE(x, 1); diff --git a/tools/memory-model/README b/tools/memory-model/README index 734f7feaa5dc..ee987ce20aae 100644 --- a/tools/memory-model/README +++ b/tools/memory-model/README @@ -35,13 +35,13 @@ BASIC USAGE: HERD7 The memory model is used, in conjunction with "herd7", to exhaustively explore the state space of small litmus tests. -For example, to run SB+mbonceonces.litmus against the memory model: +For example, to run SB+fencembonceonces.litmus against the memory model: - $ herd7 -conf linux-kernel.cfg litmus-tests/SB+mbonceonces.litmus + $ herd7 -conf linux-kernel.cfg litmus-tests/SB+fencembonceonces.litmus Here is the corresponding output: - Test SB+mbonceonces Allowed + Test SB+fencembonceonces Allowed States 3 0:r0=0; 1:r0=1; 0:r0=1; 1:r0=0; @@ -50,8 +50,8 @@ Here is the corresponding output: Witnesses Positive: 0 Negative: 3 Condition exists (0:r0=0 /\ 1:r0=0) - Observation SB+mbonceonces Never 0 3 - Time SB+mbonceonces 0.01 + Observation SB+fencembonceonces Never 0 3 + Time SB+fencembonceonces 0.01 Hash=d66d99523e2cac6b06e66f4c995ebb48 The "Positive: 0 Negative: 3" and the "Never 0 3" each indicate that @@ -67,16 +67,16 @@ BASIC USAGE: KLITMUS7 The "klitmus7" tool converts a litmus test into a Linux kernel module, which may then be loaded and run. -For example, to run SB+mbonceonces.litmus against hardware: +For example, to run SB+fencembonceonces.litmus against hardware: $ mkdir mymodules - $ klitmus7 -o mymodules litmus-tests/SB+mbonceonces.litmus + $ klitmus7 -o mymodules litmus-tests/SB+fencembonceonces.litmus $ cd mymodules ; make $ sudo sh run.sh The corresponding output includes: - Test SB+mbonceonces Allowed + Test SB+fencembonceonces Allowed Histogram (3 states) 644580 :>0:r0=1; 1:r0=0; 644328 :>0:r0=0; 1:r0=1; @@ -86,8 +86,8 @@ The corresponding output includes: Positive: 0, Negative: 2000000 Condition exists (0:r0=0 /\ 1:r0=0) is NOT validated Hash=d66d99523e2cac6b06e66f4c995ebb48 - Observation SB+mbonceonces Never 0 2000000 - Time SB+mbonceonces 0.16 + Observation SB+fencembonceonces Never 0 2000000 + Time SB+fencembonceonces 0.16 The "Positive: 0 Negative: 2000000" and the "Never 0 2000000" indicate that during two million trials, the state specified in this litmus diff --git a/tools/memory-model/linux-kernel.bell b/tools/memory-model/linux-kernel.bell index 64f5740e0e75..b84fb2f67109 100644 --- a/tools/memory-model/linux-kernel.bell +++ b/tools/memory-model/linux-kernel.bell @@ -13,7 +13,7 @@ "Linux-kernel memory consistency model" -enum Accesses = 'once (*READ_ONCE,WRITE_ONCE,ACCESS_ONCE*) || +enum Accesses = 'once (*READ_ONCE,WRITE_ONCE*) || 'release (*smp_store_release*) || 'acquire (*smp_load_acquire*) || 'noreturn (* R of non-return RMW *) diff --git a/tools/memory-model/litmus-tests/IRIW+mbonceonces+OnceOnce.litmus b/tools/memory-model/litmus-tests/IRIW+fencembonceonces+OnceOnce.litmus index 98a3716efa37..e729d2776e89 100644 --- a/tools/memory-model/litmus-tests/IRIW+mbonceonces+OnceOnce.litmus +++ b/tools/memory-model/litmus-tests/IRIW+fencembonceonces+OnceOnce.litmus @@ -1,4 +1,4 @@ -C IRIW+mbonceonces+OnceOnce +C IRIW+fencembonceonces+OnceOnce (* * Result: Never diff --git a/tools/memory-model/litmus-tests/ISA2+pooncelock+pooncelock+pombonce.litmus b/tools/memory-model/litmus-tests/ISA2+pooncelock+pooncelock+pombonce.litmus index 7a39a0aaa976..0f749e419b34 100644 --- a/tools/memory-model/litmus-tests/ISA2+pooncelock+pooncelock+pombonce.litmus +++ b/tools/memory-model/litmus-tests/ISA2+pooncelock+pooncelock+pombonce.litmus @@ -1,4 +1,4 @@ -C ISA2+pooncelock+pooncelock+pombonce.litmus +C ISA2+pooncelock+pooncelock+pombonce (* * Result: Sometimes diff --git a/tools/memory-model/litmus-tests/LB+ctrlonceonce+mbonceonce.litmus b/tools/memory-model/litmus-tests/LB+fencembonceonce+ctrlonceonce.litmus index de6708229dd1..4727f5aaf03b 100644 --- a/tools/memory-model/litmus-tests/LB+ctrlonceonce+mbonceonce.litmus +++ b/tools/memory-model/litmus-tests/LB+fencembonceonce+ctrlonceonce.litmus @@ -1,4 +1,4 @@ -C LB+ctrlonceonce+mbonceonce +C LB+fencembonceonce+ctrlonceonce (* * Result: Never diff --git a/tools/memory-model/litmus-tests/MP+wmbonceonce+rmbonceonce.litmus b/tools/memory-model/litmus-tests/MP+fencewmbonceonce+fencermbonceonce.litmus index c078f38ff27a..a273da9faa6d 100644 --- a/tools/memory-model/litmus-tests/MP+wmbonceonce+rmbonceonce.litmus +++ b/tools/memory-model/litmus-tests/MP+fencewmbonceonce+fencermbonceonce.litmus @@ -1,4 +1,4 @@ -C MP+wmbonceonce+rmbonceonce +C MP+fencewmbonceonce+fencermbonceonce (* * Result: Never diff --git a/tools/memory-model/litmus-tests/R+mbonceonces.litmus b/tools/memory-model/litmus-tests/R+fencembonceonces.litmus index a0e884ad2132..222a0b850b4a 100644 --- a/tools/memory-model/litmus-tests/R+mbonceonces.litmus +++ b/tools/memory-model/litmus-tests/R+fencembonceonces.litmus @@ -1,4 +1,4 @@ -C R+mbonceonces +C R+fencembonceonces (* * Result: Never diff --git a/tools/memory-model/litmus-tests/README b/tools/memory-model/litmus-tests/README index 17eb9a8c222d..4581ec2d3c57 100644 --- a/tools/memory-model/litmus-tests/README +++ b/tools/memory-model/litmus-tests/README @@ -18,7 +18,7 @@ CoWW+poonceonce.litmus Test of write-write coherence, that is, whether or not two successive writes to the same variable are ordered. -IRIW+mbonceonces+OnceOnce.litmus +IRIW+fencembonceonces+OnceOnce.litmus Test of independent reads from independent writes with smp_mb() between each pairs of reads. In other words, is smp_mb() sufficient to cause two different reading processes to agree on @@ -47,7 +47,7 @@ ISA2+pooncerelease+poacquirerelease+poacquireonce.litmus Can a release-acquire chain order a prior store against a later load? -LB+ctrlonceonce+mbonceonce.litmus +LB+fencembonceonce+ctrlonceonce.litmus Does a control dependency and an smp_mb() suffice for the load-buffering litmus test, where each process reads from one of two variables then writes to the other? @@ -88,14 +88,14 @@ MP+porevlocks.litmus As below, but with the first access of the writer process and the second access of reader process protected by a lock. -MP+wmbonceonce+rmbonceonce.litmus +MP+fencewmbonceonce+fencermbonceonce.litmus Does a smp_wmb() (between the stores) and an smp_rmb() (between the loads) suffice for the message-passing litmus test, where one process writes data and then a flag, and the other process reads the flag and then the data. (This is similar to the ISA2 tests, but with two processes instead of three.) -R+mbonceonces.litmus +R+fencembonceonces.litmus This is the fully ordered (via smp_mb()) version of one of the classic counterintuitive litmus tests that illustrates the effects of store propagation delays. @@ -103,7 +103,7 @@ R+mbonceonces.litmus R+poonceonces.litmus As above, but without the smp_mb() invocations. -SB+mbonceonces.litmus +SB+fencembonceonces.litmus This is the fully ordered (again, via smp_mb() version of store buffering, which forms the core of Dekker's mutual-exclusion algorithm. @@ -111,15 +111,24 @@ SB+mbonceonces.litmus SB+poonceonces.litmus As above, but without the smp_mb() invocations. +SB+rfionceonce-poonceonces.litmus + This litmus test demonstrates that LKMM is not fully multicopy + atomic. (Neither is it other multicopy atomic.) This litmus test + also demonstrates the "locations" debugging aid, which designates + additional registers and locations to be printed out in the dump + of final states in the herd7 output. Without the "locations" + statement, only those registers and locations mentioned in the + "exists" clause will be printed. + S+poonceonces.litmus As below, but without the smp_wmb() and acquire load. -S+wmbonceonce+poacquireonce.litmus +S+fencewmbonceonce+poacquireonce.litmus Can a smp_wmb(), instead of a release, and an acquire order a prior store against a subsequent store? WRC+poonceonces+Once.litmus -WRC+pooncerelease+rmbonceonce+Once.litmus +WRC+pooncerelease+fencermbonceonce+Once.litmus These two are members of an extension of the MP litmus-test class in which the first write is moved to a separate process. The second is forbidden because smp_store_release() is @@ -134,7 +143,7 @@ Z6.0+pooncelock+poonceLock+pombonce.litmus As above, but with smp_mb__after_spinlock() immediately following the spin_lock(). -Z6.0+pooncerelease+poacquirerelease+mbonceonce.litmus +Z6.0+pooncerelease+poacquirerelease+fencembonceonce.litmus Is the ordering provided by a release-acquire chain sufficient to make ordering apparent to accesses by a process that does not participate in that release-acquire chain? diff --git a/tools/memory-model/litmus-tests/S+wmbonceonce+poacquireonce.litmus b/tools/memory-model/litmus-tests/S+fencewmbonceonce+poacquireonce.litmus index c53350205d28..18479823cd6c 100644 --- a/tools/memory-model/litmus-tests/S+wmbonceonce+poacquireonce.litmus +++ b/tools/memory-model/litmus-tests/S+fencewmbonceonce+poacquireonce.litmus @@ -1,4 +1,4 @@ -C S+wmbonceonce+poacquireonce +C S+fencewmbonceonce+poacquireonce (* * Result: Never diff --git a/tools/memory-model/litmus-tests/SB+mbonceonces.litmus b/tools/memory-model/litmus-tests/SB+fencembonceonces.litmus index 74b874ffa8da..ed5fff18d223 100644 --- a/tools/memory-model/litmus-tests/SB+mbonceonces.litmus +++ b/tools/memory-model/litmus-tests/SB+fencembonceonces.litmus @@ -1,4 +1,4 @@ -C SB+mbonceonces +C SB+fencembonceonces (* * Result: Never diff --git a/tools/memory-model/litmus-tests/SB+rfionceonce-poonceonces.litmus b/tools/memory-model/litmus-tests/SB+rfionceonce-poonceonces.litmus new file mode 100644 index 000000000000..04a16603660b --- /dev/null +++ b/tools/memory-model/litmus-tests/SB+rfionceonce-poonceonces.litmus @@ -0,0 +1,32 @@ +C SB+rfionceonce-poonceonces + +(* + * Result: Sometimes + * + * This litmus test demonstrates that LKMM is not fully multicopy atomic. + *) + +{} + +P0(int *x, int *y) +{ + int r1; + int r2; + + WRITE_ONCE(*x, 1); + r1 = READ_ONCE(*x); + r2 = READ_ONCE(*y); +} + +P1(int *x, int *y) +{ + int r3; + int r4; + + WRITE_ONCE(*y, 1); + r3 = READ_ONCE(*y); + r4 = READ_ONCE(*x); +} + +locations [0:r1; 1:r3; x; y] (* Debug aid: Print things not in "exists". *) +exists (0:r2=0 /\ 1:r4=0) diff --git a/tools/memory-model/litmus-tests/WRC+pooncerelease+rmbonceonce+Once.litmus b/tools/memory-model/litmus-tests/WRC+pooncerelease+fencermbonceonce+Once.litmus index ad3448b941e6..e9947250d7de 100644 --- a/tools/memory-model/litmus-tests/WRC+pooncerelease+rmbonceonce+Once.litmus +++ b/tools/memory-model/litmus-tests/WRC+pooncerelease+fencermbonceonce+Once.litmus @@ -1,4 +1,4 @@ -C WRC+pooncerelease+rmbonceonce+Once +C WRC+pooncerelease+fencermbonceonce+Once (* * Result: Never diff --git a/tools/memory-model/litmus-tests/Z6.0+pooncerelease+poacquirerelease+mbonceonce.litmus b/tools/memory-model/litmus-tests/Z6.0+pooncerelease+poacquirerelease+fencembonceonce.litmus index a20fc3fafb53..88e70b87a683 100644 --- a/tools/memory-model/litmus-tests/Z6.0+pooncerelease+poacquirerelease+mbonceonce.litmus +++ b/tools/memory-model/litmus-tests/Z6.0+pooncerelease+poacquirerelease+fencembonceonce.litmus @@ -1,4 +1,4 @@ -C Z6.0+pooncerelease+poacquirerelease+mbonceonce +C Z6.0+pooncerelease+poacquirerelease+fencembonceonce (* * Result: Sometimes diff --git a/tools/memory-model/scripts/checkalllitmus.sh b/tools/memory-model/scripts/checkalllitmus.sh index af0aa15ab84e..ca528f9a24d4 100644..100755 --- a/tools/memory-model/scripts/checkalllitmus.sh +++ b/tools/memory-model/scripts/checkalllitmus.sh @@ -9,7 +9,7 @@ # appended. # # Usage: -# sh checkalllitmus.sh [ directory ] +# checkalllitmus.sh [ directory ] # # The LINUX_HERD_OPTIONS environment variable may be used to specify # arguments to herd, whose default is defined by the checklitmus.sh script. diff --git a/tools/memory-model/scripts/checklitmus.sh b/tools/memory-model/scripts/checklitmus.sh index e2e477472844..bf12a75c0719 100644..100755 --- a/tools/memory-model/scripts/checklitmus.sh +++ b/tools/memory-model/scripts/checklitmus.sh @@ -8,7 +8,7 @@ # with ".out" appended. # # Usage: -# sh checklitmus.sh file.litmus +# checklitmus.sh file.litmus # # The LINUX_HERD_OPTIONS environment variable may be used to specify # arguments to herd, which default to "-conf linux-kernel.cfg". Thus, diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile index f76d9914686a..c9d038f91af6 100644 --- a/tools/objtool/Makefile +++ b/tools/objtool/Makefile @@ -31,8 +31,8 @@ INCLUDES := -I$(srctree)/tools/include \ -I$(srctree)/tools/arch/$(HOSTARCH)/include/uapi \ -I$(srctree)/tools/objtool/arch/$(ARCH)/include WARNINGS := $(EXTRA_WARNINGS) -Wno-switch-default -Wno-switch-enum -Wno-packed -CFLAGS += -Werror $(WARNINGS) $(HOSTCFLAGS) -g $(INCLUDES) -LDFLAGS += -lelf $(LIBSUBCMD) $(HOSTLDFLAGS) +CFLAGS += -Werror $(WARNINGS) $(KBUILD_HOSTCFLAGS) -g $(INCLUDES) +LDFLAGS += -lelf $(LIBSUBCMD) $(KBUILD_HOSTLDFLAGS) # Allow old libelf to be used: elfshdr := $(shell echo '$(pound)include <libelf.h>' | $(CC) $(CFLAGS) -x c -E - | grep elf_getshdr) diff --git a/tools/objtool/arch/x86/include/asm/orc_types.h b/tools/objtool/arch/x86/include/asm/orc_types.h index 9c9dc579bd7d..46f516dd80ce 100644 --- a/tools/objtool/arch/x86/include/asm/orc_types.h +++ b/tools/objtool/arch/x86/include/asm/orc_types.h @@ -88,6 +88,7 @@ struct orc_entry { unsigned sp_reg:4; unsigned bp_reg:4; unsigned type:2; + unsigned end:1; } __packed; /* @@ -101,6 +102,7 @@ struct unwind_hint { s16 sp_offset; u8 sp_reg; u8 type; + u8 end; }; #endif /* __ASSEMBLY__ */ diff --git a/tools/objtool/check.c b/tools/objtool/check.c index f4a25bd1871f..2928939b98ec 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -1157,6 +1157,7 @@ static int read_unwind_hints(struct objtool_file *file) cfa->offset = hint->sp_offset; insn->state.type = hint->type; + insn->state.end = hint->end; } return 0; diff --git a/tools/objtool/check.h b/tools/objtool/check.h index c6b68fcb926f..95700a2bcb7c 100644 --- a/tools/objtool/check.h +++ b/tools/objtool/check.h @@ -31,7 +31,7 @@ struct insn_state { int stack_size; unsigned char type; bool bp_scratch; - bool drap; + bool drap, end; int drap_reg, drap_offset; struct cfi_reg vals[CFI_NUM_REGS]; }; diff --git a/tools/objtool/orc_dump.c b/tools/objtool/orc_dump.c index c3343820916a..faa444270ee3 100644 --- a/tools/objtool/orc_dump.c +++ b/tools/objtool/orc_dump.c @@ -203,7 +203,8 @@ int orc_dump(const char *_objname) print_reg(orc[i].bp_reg, orc[i].bp_offset); - printf(" type:%s\n", orc_type_name(orc[i].type)); + printf(" type:%s end:%d\n", + orc_type_name(orc[i].type), orc[i].end); } elf_end(elf); diff --git a/tools/objtool/orc_gen.c b/tools/objtool/orc_gen.c index 18384d9be4e1..3f98dcfbc177 100644 --- a/tools/objtool/orc_gen.c +++ b/tools/objtool/orc_gen.c @@ -31,6 +31,8 @@ int create_orc(struct objtool_file *file) struct cfi_reg *cfa = &insn->state.cfa; struct cfi_reg *bp = &insn->state.regs[CFI_BP]; + orc->end = insn->state.end; + if (cfa->base == CFI_UNDEFINED) { orc->sp_reg = ORC_REG_UNDEFINED; continue; diff --git a/tools/pci/pcitest.c b/tools/pci/pcitest.c index 9074b477bff0..af146bb03b4d 100644 --- a/tools/pci/pcitest.c +++ b/tools/pci/pcitest.c @@ -31,12 +31,17 @@ #define BILLION 1E9 static char *result[] = { "NOT OKAY", "OKAY" }; +static char *irq[] = { "LEGACY", "MSI", "MSI-X" }; struct pci_test { char *device; char barnum; bool legacyirq; unsigned int msinum; + unsigned int msixnum; + int irqtype; + bool set_irqtype; + bool get_irqtype; bool read; bool write; bool copy; @@ -65,6 +70,24 @@ static int run_test(struct pci_test *test) fprintf(stdout, "%s\n", result[ret]); } + if (test->set_irqtype) { + ret = ioctl(fd, PCITEST_SET_IRQTYPE, test->irqtype); + fprintf(stdout, "SET IRQ TYPE TO %s:\t\t", irq[test->irqtype]); + if (ret < 0) + fprintf(stdout, "FAILED\n"); + else + fprintf(stdout, "%s\n", result[ret]); + } + + if (test->get_irqtype) { + ret = ioctl(fd, PCITEST_GET_IRQTYPE); + fprintf(stdout, "GET IRQ TYPE:\t\t"); + if (ret < 0) + fprintf(stdout, "FAILED\n"); + else + fprintf(stdout, "%s\n", irq[ret]); + } + if (test->legacyirq) { ret = ioctl(fd, PCITEST_LEGACY_IRQ, 0); fprintf(stdout, "LEGACY IRQ:\t"); @@ -83,6 +106,15 @@ static int run_test(struct pci_test *test) fprintf(stdout, "%s\n", result[ret]); } + if (test->msixnum > 0 && test->msixnum <= 2048) { + ret = ioctl(fd, PCITEST_MSIX, test->msixnum); + fprintf(stdout, "MSI-X%d:\t\t", test->msixnum); + if (ret < 0) + fprintf(stdout, "TEST FAILED\n"); + else + fprintf(stdout, "%s\n", result[ret]); + } + if (test->write) { ret = ioctl(fd, PCITEST_WRITE, test->size); fprintf(stdout, "WRITE (%7ld bytes):\t\t", test->size); @@ -133,7 +165,7 @@ int main(int argc, char **argv) /* set default endpoint device */ test->device = "/dev/pci-endpoint-test.0"; - while ((c = getopt(argc, argv, "D:b:m:lrwcs:")) != EOF) + while ((c = getopt(argc, argv, "D:b:m:x:i:Ilrwcs:")) != EOF) switch (c) { case 'D': test->device = optarg; @@ -151,6 +183,20 @@ int main(int argc, char **argv) if (test->msinum < 1 || test->msinum > 32) goto usage; continue; + case 'x': + test->msixnum = atoi(optarg); + if (test->msixnum < 1 || test->msixnum > 2048) + goto usage; + continue; + case 'i': + test->irqtype = atoi(optarg); + if (test->irqtype < 0 || test->irqtype > 2) + goto usage; + test->set_irqtype = true; + continue; + case 'I': + test->get_irqtype = true; + continue; case 'r': test->read = true; continue; @@ -173,6 +219,9 @@ usage: "\t-D <dev> PCI endpoint test device {default: /dev/pci-endpoint-test.0}\n" "\t-b <bar num> BAR test (bar number between 0..5)\n" "\t-m <msi num> MSI test (msi number between 1..32)\n" + "\t-x <msix num> \tMSI-X test (msix number between 1..2048)\n" + "\t-i <irq type> \tSet IRQ type (0 - Legacy, 1 - MSI, 2 - MSI-X)\n" + "\t-I Get current IRQ type configured\n" "\t-l Legacy IRQ test\n" "\t-r Read buffer test\n" "\t-w Write buffer test\n" diff --git a/tools/pci/pcitest.sh b/tools/pci/pcitest.sh index 77e8c85ef744..75ed48ff2990 100644 --- a/tools/pci/pcitest.sh +++ b/tools/pci/pcitest.sh @@ -16,7 +16,10 @@ echo echo "Interrupt tests" echo +pcitest -i 0 pcitest -l + +pcitest -i 1 msi=1 while [ $msi -lt 33 ] @@ -26,9 +29,21 @@ do done echo +pcitest -i 2 +msix=1 + +while [ $msix -lt 2049 ] +do + pcitest -x $msix + msix=`expr $msix + 1` +done +echo + echo "Read Tests" echo +pcitest -i 1 + pcitest -r -s 1 pcitest -r -s 1024 pcitest -r -s 1025 diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt index 749cc6055dac..e8c972f89357 100644 --- a/tools/perf/Documentation/perf-annotate.txt +++ b/tools/perf/Documentation/perf-annotate.txt @@ -118,6 +118,15 @@ OPTIONS --group:: Show event group information together +--percent-type:: + Set annotation percent type from following choices: + global-period, local-period, global-hits, local-hits + + The local/global keywords set if the percentage is computed + in the scope of the function (local) or the whole data (global). + The period/hits keywords set the base the percentage is computed + on - the samples period or the number of samples (hits). + SEE ALSO -------- linkperf:perf-record[1], linkperf:perf-report[1] diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt index 11300dbe35c5..236b9b97dfdb 100644 --- a/tools/perf/Documentation/perf-list.txt +++ b/tools/perf/Documentation/perf-list.txt @@ -18,6 +18,10 @@ various perf commands with the -e option. OPTIONS ------- +-d:: +--desc:: +Print extra event descriptions. (default) + --no-desc:: Don't print descriptions. @@ -25,11 +29,13 @@ Don't print descriptions. --long-desc:: Print longer event descriptions. +--debug:: +Enable debugging output. + --details:: Print how named events are resolved internally into perf events, and also any extra expressions computed by perf stat. - [[EVENT_MODIFIERS]] EVENT MODIFIERS --------------- @@ -234,7 +240,7 @@ perf also supports group leader sampling using the :S specifier. perf record -e '{cycles,instructions}:S' ... perf report --group -Normally all events in a event group sample, but with :S only +Normally all events in an event group sample, but with :S only the first event (the leader) samples, and it only reads the values of the other events in the group. diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 04168da4268e..246dee081efd 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -94,7 +94,7 @@ OPTIONS "perf report" to view group events together. --filter=<filter>:: - Event filter. This option should follow a event selector (-e) which + Event filter. This option should follow an event selector (-e) which selects either tracepoint event(s) or a hardware trace PMU (e.g. Intel PT or CoreSight). @@ -153,7 +153,7 @@ OPTIONS --exclude-perf:: Don't record events issued by perf itself. This option should follow - a event selector (-e) which selects tracepoint event(s). It adds a + an event selector (-e) which selects tracepoint event(s). It adds a filter expression 'common_pid != $PERFPID' to filters. If other '--filter' exists, the new filter expression will be combined with them by '&&'. diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index 917e36fde6d8..474a4941f65d 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt @@ -477,6 +477,15 @@ include::itrace.txt[] Display monitored tasks stored in perf data. Displaying pid/tid/ppid plus the command string aligned to distinguish parent and child tasks. +--percent-type:: + Set annotation percent type from following choices: + global-period, local-period, global-hits, local-hits + + The local/global keywords set if the percentage is computed + in the scope of the function (local) or the whole data (global). + The period/hits keywords set the base the percentage is computed + on - the samples period or the number of samples (hits). + include::callchain-overhead-calculation.txt[] SEE ALSO diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 225454416ed5..7902a5681fc8 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -84,10 +84,10 @@ endif # has_clean endif # MAKECMDGOALS # -# The clean target is not really parallel, don't print the jobs info: +# Explicitly disable parallelism for the clean target. # clean: - $(make) + $(make) -j1 # # The build-test target is not really parallel, don't print the jobs info, diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index f5a3b402589e..f6d1a03c7523 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -54,6 +54,8 @@ endif ifeq ($(SRCARCH),arm64) NO_PERF_REGS := 0 + NO_SYSCALL_TABLE := 0 + CFLAGS += -I$(OUTPUT)arch/arm64/include/generated LIBUNWIND_LIBS = -lunwind -lunwind-aarch64 endif @@ -905,8 +907,8 @@ bindir = $(abspath $(prefix)/$(bindir_relative)) mandir = share/man infodir = share/info perfexecdir = libexec/perf-core -perf_include_dir = lib/include/perf -perf_examples_dir = lib/examples/perf +perf_include_dir = lib/perf/include +perf_examples_dir = lib/perf/examples sharedir = $(prefix)/share template_dir = share/perf-core/templates STRACE_GROUPS_DIR = share/perf-core/strace/groups diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index ecc9fc952655..b3d1b12a5081 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -384,6 +384,8 @@ export INSTALL SHELL_PATH SHELL = $(SHELL_PATH) +linux_uapi_dir := $(srctree)/tools/include/uapi/linux + beauty_outdir := $(OUTPUT)trace/beauty/generated beauty_ioctl_outdir := $(beauty_outdir)/ioctl drm_ioctl_array := $(beauty_ioctl_outdir)/drm_ioctl_array.c @@ -431,6 +433,12 @@ kvm_ioctl_tbl := $(srctree)/tools/perf/trace/beauty/kvm_ioctl.sh $(kvm_ioctl_array): $(kvm_hdr_dir)/kvm.h $(kvm_ioctl_tbl) $(Q)$(SHELL) '$(kvm_ioctl_tbl)' $(kvm_hdr_dir) > $@ +socket_ipproto_array := $(beauty_outdir)/socket_ipproto_array.c +socket_ipproto_tbl := $(srctree)/tools/perf/trace/beauty/socket_ipproto.sh + +$(socket_ipproto_array): $(linux_uapi_dir)/in.h $(socket_ipproto_tbl) + $(Q)$(SHELL) '$(socket_ipproto_tbl)' $(linux_uapi_dir) > $@ + vhost_virtio_ioctl_array := $(beauty_ioctl_outdir)/vhost_virtio_ioctl_array.c vhost_virtio_hdr_dir := $(srctree)/tools/include/uapi/linux vhost_virtio_ioctl_tbl := $(srctree)/tools/perf/trace/beauty/vhost_virtio_ioctl.sh @@ -566,6 +574,7 @@ prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h archheaders $(drm_ioc $(sndrv_ctl_ioctl_array) \ $(kcmp_type_array) \ $(kvm_ioctl_array) \ + $(socket_ipproto_array) \ $(vhost_virtio_ioctl_array) \ $(madvise_behavior_array) \ $(perf_ioctl_array) \ @@ -860,6 +869,7 @@ clean:: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clea $(OUTPUT)$(sndrv_pcm_ioctl_array) \ $(OUTPUT)$(kvm_ioctl_array) \ $(OUTPUT)$(kcmp_type_array) \ + $(OUTPUT)$(socket_ipproto_array) \ $(OUTPUT)$(vhost_virtio_ioctl_array) \ $(OUTPUT)$(perf_ioctl_array) \ $(OUTPUT)$(prctl_option_array) \ diff --git a/tools/perf/arch/arm64/Makefile b/tools/perf/arch/arm64/Makefile index 91de4860faad..f013b115dc86 100644 --- a/tools/perf/arch/arm64/Makefile +++ b/tools/perf/arch/arm64/Makefile @@ -4,3 +4,24 @@ PERF_HAVE_DWARF_REGS := 1 endif PERF_HAVE_JITDUMP := 1 PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1 + +# +# Syscall table generation for perf +# + +out := $(OUTPUT)arch/arm64/include/generated/asm +header := $(out)/syscalls.c +sysdef := $(srctree)/tools/include/uapi/asm-generic/unistd.h +sysprf := $(srctree)/tools/perf/arch/arm64/entry/syscalls/ +systbl := $(sysprf)/mksyscalltbl + +# Create output directory if not already present +_dummy := $(shell [ -d '$(out)' ] || mkdir -p '$(out)') + +$(header): $(sysdef) $(systbl) + $(Q)$(SHELL) '$(systbl)' '$(CC)' '$(HOSTCC)' $(sysdef) > $@ + +clean:: + $(call QUIET_CLEAN, arm64) $(RM) $(header) + +archheaders: $(header) diff --git a/tools/perf/arch/arm64/entry/syscalls/mksyscalltbl b/tools/perf/arch/arm64/entry/syscalls/mksyscalltbl new file mode 100755 index 000000000000..52e197317d3e --- /dev/null +++ b/tools/perf/arch/arm64/entry/syscalls/mksyscalltbl @@ -0,0 +1,62 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# +# Generate system call table for perf. Derived from +# powerpc script. +# +# Copyright IBM Corp. 2017 +# Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com> +# Changed by: Ravi Bangoria <ravi.bangoria@linux.vnet.ibm.com> +# Changed by: Kim Phillips <kim.phillips@arm.com> + +gcc=$1 +hostcc=$2 +input=$3 + +if ! test -r $input; then + echo "Could not read input file" >&2 + exit 1 +fi + +create_table_from_c() +{ + local sc nr last_sc + + create_table_exe=`mktemp /tmp/create-table-XXXXXX` + + { + + cat <<-_EoHEADER + #include <stdio.h> + #define __ARCH_WANT_RENAMEAT + #include "$input" + int main(int argc, char *argv[]) + { + _EoHEADER + + while read sc nr; do + printf "%s\n" " printf(\"\\t[%d] = \\\"$sc\\\",\\n\", __NR_$sc);" + last_sc=$sc + done + + printf "%s\n" " printf(\"#define SYSCALLTBL_ARM64_MAX_ID %d\\n\", __NR_$last_sc);" + printf "}\n" + + } | $hostcc -o $create_table_exe -x c - + + $create_table_exe + + rm -f $create_table_exe +} + +create_table() +{ + echo "static const char *syscalltbl_arm64[] = {" + create_table_from_c + echo "};" +} + +$gcc -E -dM -x c $input \ + |sed -ne 's/^#define __NR_//p' \ + |sort -t' ' -k2 -nu \ + |create_table diff --git a/tools/perf/arch/arm64/util/arm-spe.c b/tools/perf/arch/arm64/util/arm-spe.c index 1120e39c1b00..5ccfce87e693 100644 --- a/tools/perf/arch/arm64/util/arm-spe.c +++ b/tools/perf/arch/arm64/util/arm-spe.c @@ -194,6 +194,7 @@ struct auxtrace_record *arm_spe_recording_init(int *err, sper->itr.read_finish = arm_spe_read_finish; sper->itr.alignment = 0; + *err = 0; return &sper->itr; } diff --git a/tools/perf/arch/powerpc/util/skip-callchain-idx.c b/tools/perf/arch/powerpc/util/skip-callchain-idx.c index ef5d59a5742e..7c6eeb4633fe 100644 --- a/tools/perf/arch/powerpc/util/skip-callchain-idx.c +++ b/tools/perf/arch/powerpc/util/skip-callchain-idx.c @@ -58,9 +58,13 @@ static int check_return_reg(int ra_regno, Dwarf_Frame *frame) } /* - * Check if return address is on the stack. + * Check if return address is on the stack. If return address + * is in a register (typically R0), it is yet to be saved on + * the stack. */ - if (nops != 0 || ops != NULL) + if ((nops != 0 || ops != NULL) && + !(nops == 1 && ops[0].atom == DW_OP_regx && + ops[0].number2 == 0 && ops[0].offset == 0)) return 0; /* @@ -246,7 +250,7 @@ int arch_skip_callchain_idx(struct thread *thread, struct ip_callchain *chain) if (!chain || chain->nr < 3) return skip_slot; - ip = chain->ips[2]; + ip = chain->ips[1]; thread__find_symbol(thread, PERF_RECORD_MISC_USER, ip, &al); diff --git a/tools/perf/arch/powerpc/util/sym-handling.c b/tools/perf/arch/powerpc/util/sym-handling.c index 53d83d7e6a09..20e7d74d86cd 100644 --- a/tools/perf/arch/powerpc/util/sym-handling.c +++ b/tools/perf/arch/powerpc/util/sym-handling.c @@ -141,8 +141,10 @@ void arch__post_process_probe_trace_events(struct perf_probe_event *pev, for (i = 0; i < ntevs; i++) { tev = &pev->tevs[i]; map__for_each_symbol(map, sym, tmp) { - if (map->unmap_ip(map, sym->start) == tev->point.address) + if (map->unmap_ip(map, sym->start) == tev->point.address) { arch__fix_tev_from_maps(pev, tev, map, sym); + break; + } } } } diff --git a/tools/perf/arch/s390/util/auxtrace.c b/tools/perf/arch/s390/util/auxtrace.c index 3afe8256eff2..44c857388897 100644 --- a/tools/perf/arch/s390/util/auxtrace.c +++ b/tools/perf/arch/s390/util/auxtrace.c @@ -30,6 +30,7 @@ cpumsf_info_fill(struct auxtrace_record *itr __maybe_unused, struct auxtrace_info_event *auxtrace_info __maybe_unused, size_t priv_size __maybe_unused) { + auxtrace_info->type = PERF_AUXTRACE_S390_CPUMSF; return 0; } diff --git a/tools/perf/arch/s390/util/kvm-stat.c b/tools/perf/arch/s390/util/kvm-stat.c index d233e2eb9592..aaabab5e2830 100644 --- a/tools/perf/arch/s390/util/kvm-stat.c +++ b/tools/perf/arch/s390/util/kvm-stat.c @@ -102,7 +102,7 @@ const char * const kvm_skip_events[] = { int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid) { - if (strstr(cpuid, "IBM/S390")) { + if (strstr(cpuid, "IBM")) { kvm->exit_reasons = sie_exit_reasons; kvm->exit_reasons_isa = "SIE"; } else diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile index 1a38e78117ce..8cc6642fce7a 100644 --- a/tools/perf/arch/x86/Makefile +++ b/tools/perf/arch/x86/Makefile @@ -19,9 +19,6 @@ systbl := $(sys)/syscalltbl.sh _dummy := $(shell [ -d '$(out)' ] || mkdir -p '$(out)') $(header): $(sys)/syscall_64.tbl $(systbl) - @(test -d ../../kernel -a -d ../../tools -a -d ../perf && ( \ - (diff -B arch/x86/entry/syscalls/syscall_64.tbl ../../arch/x86/entry/syscalls/syscall_64.tbl >/dev/null) \ - || echo "Warning: Kernel ABI header at 'tools/perf/arch/x86/entry/syscalls/syscall_64.tbl' differs from latest version at 'arch/x86/entry/syscalls/syscall_64.tbl'" >&2 )) || true $(Q)$(SHELL) '$(systbl)' $(sys)/syscall_64.tbl 'x86_64' > $@ clean:: diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 8180319285af..830481b8db26 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -542,6 +542,10 @@ int cmd_annotate(int argc, const char **argv) OPT_CALLBACK_DEFAULT(0, "stdio-color", NULL, "mode", "'always' (default), 'never' or 'auto' only applicable to --stdio mode", stdio__config_color, "always"), + OPT_CALLBACK(0, "percent-type", &annotate.opts, "local-period", + "Set percent type local/global-period/hits", + annotate_parse_percent_type), + OPT_END() }; int ret; diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index 6a8738f7ead3..f3aa9d02a5ab 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -2193,7 +2193,7 @@ static void print_cacheline(struct c2c_hists *c2c_hists, fprintf(out, "%s\n", bf); fprintf(out, " -------------------------------------------------------------\n"); - hists__fprintf(&c2c_hists->hists, false, 0, 0, 0, out, true); + hists__fprintf(&c2c_hists->hists, false, 0, 0, 0, out, false); } static void print_pareto(FILE *out) @@ -2268,7 +2268,7 @@ static void perf_c2c__hists_fprintf(FILE *out, struct perf_session *session) fprintf(out, "=================================================\n"); fprintf(out, "#\n"); - hists__fprintf(&c2c.hists.hists, true, 0, 0, 0, stdout, false); + hists__fprintf(&c2c.hists.hists, true, 0, 0, 0, stdout, true); fprintf(out, "\n"); fprintf(out, "=================================================\n"); @@ -2349,6 +2349,9 @@ static int perf_c2c__browse_cacheline(struct hist_entry *he) " s Toggle full length of symbol and source line columns \n" " q Return back to cacheline list \n"; + if (!he) + return 0; + /* Display compact version first. */ c2c.symbol_full = false; diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index d660cb7b222b..39db2ee32d48 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -696,7 +696,7 @@ static void hists__process(struct hists *hists) hists__output_resort(hists, NULL); hists__fprintf(hists, !quiet, 0, 0, 0, stdout, - symbol_conf.use_callchain); + !symbol_conf.use_callchain); } static void data__fprintf(void) diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 54d3f21b0e62..b63bca4b0c2a 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -729,7 +729,7 @@ static char *compact_gfp_string(unsigned long gfp_flags) static int parse_gfp_flags(struct perf_evsel *evsel, struct perf_sample *sample, unsigned int gfp_flags) { - struct pevent_record record = { + struct tep_record record = { .cpu = sample->cpu, .data = sample->raw_data, .size = sample->raw_size, @@ -747,7 +747,7 @@ static int parse_gfp_flags(struct perf_evsel *evsel, struct perf_sample *sample, } trace_seq_init(&seq); - pevent_event_info(&seq, evsel->tp_format, &record); + tep_event_info(&seq, evsel->tp_format, &record); str = strtok_r(seq.buffer, " ", &pos); while (str) { @@ -1974,7 +1974,7 @@ int cmd_kmem(int argc, const char **argv) goto out_delete; } - kmem_page_size = pevent_get_page_size(evsel->tp_format->pevent); + kmem_page_size = tep_get_page_size(evsel->tp_format->pevent); symbol_conf.use_callchain = true; } diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index c04dc7b53797..76e12bcd1765 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -478,8 +478,8 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, hists__fprintf_nr_sample_events(hists, rep, evname, stdout); hists__fprintf(hists, !quiet, 0, 0, rep->min_percent, stdout, - symbol_conf.use_callchain || - symbol_conf.show_branchflag_count); + !(symbol_conf.use_callchain || + symbol_conf.show_branchflag_count)); fprintf(stdout, "\n\n"); } @@ -1124,6 +1124,9 @@ int cmd_report(int argc, const char **argv) "Time span of interest (start,stop)"), OPT_BOOLEAN(0, "inline", &symbol_conf.inline_name, "Show inline function"), + OPT_CALLBACK(0, "percent-type", &report.annotation_opts, "local-period", + "Set percent type local/global-period/hits", + annotate_parse_percent_type), OPT_END() }; struct perf_data data = { @@ -1366,9 +1369,9 @@ repeat: } if (session->tevent.pevent && - pevent_set_function_resolver(session->tevent.pevent, - machine__resolve_kernel_addr, - &session->machines.host) < 0) { + tep_set_function_resolver(session->tevent.pevent, + machine__resolve_kernel_addr, + &session->machines.host) < 0) { pr_err("%s: failed to set libtraceevent function resolver\n", __func__); return -1; diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 568ddfac3213..ba481d73f910 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -3429,9 +3429,9 @@ int cmd_script(int argc, const char **argv) symbol_conf.use_callchain = false; if (session->tevent.pevent && - pevent_set_function_resolver(session->tevent.pevent, - machine__resolve_kernel_addr, - &session->machines.host) < 0) { + tep_set_function_resolver(session->tevent.pevent, + machine__resolve_kernel_addr, + &session->machines.host) < 0) { pr_err("%s: failed to set libtraceevent function resolver\n", __func__); err = -1; goto out_delete; diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 05be023c3f0e..d097b5b47eb8 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -296,18 +296,6 @@ static int create_perf_stat_counter(struct perf_evsel *evsel) return perf_evsel__open_per_thread(evsel, evsel_list->threads); } -/* - * Does the counter have nsecs as a unit? - */ -static inline int nsec_counter(struct perf_evsel *evsel) -{ - if (perf_evsel__match(evsel, SOFTWARE, SW_CPU_CLOCK) || - perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) - return 1; - - return 0; -} - static int process_synthesized_event(struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_sample *sample __maybe_unused, @@ -1058,34 +1046,6 @@ static void print_metric_header(void *ctx, const char *color __maybe_unused, fprintf(os->fh, "%*s ", metric_only_len, unit); } -static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg) -{ - FILE *output = stat_config.output; - double msecs = avg / NSEC_PER_MSEC; - const char *fmt_v, *fmt_n; - char name[25]; - - fmt_v = csv_output ? "%.6f%s" : "%18.6f%s"; - fmt_n = csv_output ? "%s" : "%-25s"; - - aggr_printout(evsel, id, nr); - - scnprintf(name, sizeof(name), "%s%s", - perf_evsel__name(evsel), csv_output ? "" : " (msec)"); - - fprintf(output, fmt_v, msecs, csv_sep); - - if (csv_output) - fprintf(output, "%s%s", evsel->unit, csv_sep); - else - fprintf(output, "%-*s%s", unit_width, evsel->unit, csv_sep); - - fprintf(output, fmt_n, name); - - if (evsel->cgrp) - fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); -} - static int first_shadow_cpu(struct perf_evsel *evsel, int id) { int i; @@ -1241,11 +1201,7 @@ static void printout(int id, int nr, struct perf_evsel *counter, double uval, return; } - if (metric_only) - /* nothing */; - else if (nsec_counter(counter)) - nsec_printout(id, nr, counter, uval); - else + if (!metric_only) abs_printout(id, nr, counter, uval); out.print_metric = pm; @@ -1331,7 +1287,7 @@ static void collect_all_aliases(struct perf_evsel *counter, alias->scale != counter->scale || alias->cgrp != counter->cgrp || strcmp(alias->unit, counter->unit) || - nsec_counter(alias) != nsec_counter(counter)) + perf_evsel__is_clock(alias) != perf_evsel__is_clock(counter)) break; alias->merged_stat = true; cb(alias, data, false); @@ -2449,6 +2405,18 @@ static int add_default_attributes(void) return 0; if (transaction_run) { + /* Handle -T as -M transaction. Once platform specific metrics + * support has been added to the json files, all archictures + * will use this approach. To determine transaction support + * on an architecture test for such a metric name. + */ + if (metricgroup__has_metric("transaction")) { + struct option opt = { .value = &evsel_list }; + + return metricgroup__parse_groups(&opt, "transaction", + &metric_events); + } + if (pmu_have_event("cpu", "cycles-ct") && pmu_have_event("cpu", "el-start")) err = parse_events(evsel_list, transaction_attrs, diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index ffdc2769ff9f..d21d8751e749 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -307,7 +307,7 @@ static void perf_top__print_sym_table(struct perf_top *top) hists__output_recalc_col_len(hists, top->print_entries - printed); putchar('\n'); hists__fprintf(hists, false, top->print_entries - printed, win_width, - top->min_percent, stdout, symbol_conf.use_callchain); + top->min_percent, stdout, !symbol_conf.use_callchain); } static void prompt_integer(int *target, const char *msg) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 6a748eca2edb..22ab8e67c760 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -77,7 +77,8 @@ struct trace { struct syscall *table; struct { struct perf_evsel *sys_enter, - *sys_exit; + *sys_exit, + *augmented; } events; } syscalls; struct record_opts opts; @@ -121,7 +122,6 @@ struct trace { bool force; bool vfs_getname; int trace_pgfaults; - int open_id; }; struct tp_field { @@ -157,13 +157,11 @@ TP_UINT_FIELD__SWAPPED(16); TP_UINT_FIELD__SWAPPED(32); TP_UINT_FIELD__SWAPPED(64); -static int tp_field__init_uint(struct tp_field *field, - struct format_field *format_field, - bool needs_swap) +static int __tp_field__init_uint(struct tp_field *field, int size, int offset, bool needs_swap) { - field->offset = format_field->offset; + field->offset = offset; - switch (format_field->size) { + switch (size) { case 1: field->integer = tp_field__u8; break; @@ -183,18 +181,28 @@ static int tp_field__init_uint(struct tp_field *field, return 0; } +static int tp_field__init_uint(struct tp_field *field, struct format_field *format_field, bool needs_swap) +{ + return __tp_field__init_uint(field, format_field->size, format_field->offset, needs_swap); +} + static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample) { return sample->raw_data + field->offset; } -static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field) +static int __tp_field__init_ptr(struct tp_field *field, int offset) { - field->offset = format_field->offset; + field->offset = offset; field->pointer = tp_field__ptr; return 0; } +static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field) +{ + return __tp_field__init_ptr(field, format_field->offset); +} + struct syscall_tp { struct tp_field id; union { @@ -240,7 +248,47 @@ static void perf_evsel__delete_priv(struct perf_evsel *evsel) perf_evsel__delete(evsel); } -static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler) +static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel) +{ + struct syscall_tp *sc = evsel->priv = malloc(sizeof(struct syscall_tp)); + + if (evsel->priv != NULL) { + if (perf_evsel__init_tp_uint_field(evsel, &sc->id, "__syscall_nr")) + goto out_delete; + return 0; + } + + return -ENOMEM; +out_delete: + zfree(&evsel->priv); + return -ENOENT; +} + +static int perf_evsel__init_augmented_syscall_tp(struct perf_evsel *evsel) +{ + struct syscall_tp *sc = evsel->priv = malloc(sizeof(struct syscall_tp)); + + if (evsel->priv != NULL) { /* field, sizeof_field, offsetof_field */ + if (__tp_field__init_uint(&sc->id, sizeof(long), sizeof(long long), evsel->needs_swap)) + goto out_delete; + + return 0; + } + + return -ENOMEM; +out_delete: + zfree(&evsel->priv); + return -EINVAL; +} + +static int perf_evsel__init_augmented_syscall_tp_args(struct perf_evsel *evsel) +{ + struct syscall_tp *sc = evsel->priv; + + return __tp_field__init_ptr(&sc->args, sc->id.offset + sizeof(u64)); +} + +static int perf_evsel__init_raw_syscall_tp(struct perf_evsel *evsel, void *handler) { evsel->priv = malloc(sizeof(struct syscall_tp)); if (evsel->priv != NULL) { @@ -258,7 +306,7 @@ out_delete: return -ENOENT; } -static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler) +static struct perf_evsel *perf_evsel__raw_syscall_newtp(const char *direction, void *handler) { struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction); @@ -269,7 +317,7 @@ static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void if (IS_ERR(evsel)) return NULL; - if (perf_evsel__init_syscall_tp(evsel, handler)) + if (perf_evsel__init_raw_syscall_tp(evsel, handler)) goto out_delete; return evsel; @@ -291,7 +339,7 @@ size_t strarray__scnprintf(struct strarray *sa, char *bf, size_t size, const cha { int idx = val - sa->offset; - if (idx < 0 || idx >= sa->nr_entries) + if (idx < 0 || idx >= sa->nr_entries || sa->entries[idx] == NULL) return scnprintf(bf, size, intfmt, val); return scnprintf(bf, size, "%s", sa->entries[idx]); @@ -761,10 +809,12 @@ static struct syscall_fmt { .arg = { [0] = STRARRAY(resource, rlimit_resources), }, }, { .name = "socket", .arg = { [0] = STRARRAY(family, socket_families), - [1] = { .scnprintf = SCA_SK_TYPE, /* type */ }, }, }, + [1] = { .scnprintf = SCA_SK_TYPE, /* type */ }, + [2] = { .scnprintf = SCA_SK_PROTO, /* protocol */ }, }, }, { .name = "socketpair", .arg = { [0] = STRARRAY(family, socket_families), - [1] = { .scnprintf = SCA_SK_TYPE, /* type */ }, }, }, + [1] = { .scnprintf = SCA_SK_TYPE, /* type */ }, + [2] = { .scnprintf = SCA_SK_PROTO, /* protocol */ }, }, }, { .name = "stat", .alias = "newstat", }, { .name = "statx", .arg = { [0] = { .scnprintf = SCA_FDAT, /* fdat */ }, @@ -803,12 +853,17 @@ static struct syscall_fmt *syscall_fmt__find(const char *name) return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp); } +/* + * is_exit: is this "exit" or "exit_group"? + * is_open: is this "open" or "openat"? To associate the fd returned in sys_exit with the pathname in sys_enter. + */ struct syscall { struct event_format *tp_format; int nr_args; + bool is_exit; + bool is_open; struct format_field *args; const char *name; - bool is_exit; struct syscall_fmt *fmt; struct syscall_arg_fmt *arg_fmt; }; @@ -1297,6 +1352,7 @@ static int trace__read_syscall_info(struct trace *trace, int id) } sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit"); + sc->is_open = !strcmp(name, "open") || !strcmp(name, "openat"); return syscall__set_arg_fmts(sc); } @@ -1659,6 +1715,37 @@ out_put: return err; } +static int trace__fprintf_sys_enter(struct trace *trace, struct perf_evsel *evsel, + struct perf_sample *sample) +{ + struct thread_trace *ttrace; + struct thread *thread; + int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1; + struct syscall *sc = trace__syscall_info(trace, evsel, id); + char msg[1024]; + void *args; + + if (sc == NULL) + return -1; + + thread = machine__findnew_thread(trace->host, sample->pid, sample->tid); + ttrace = thread__trace(thread, trace->output); + /* + * We need to get ttrace just to make sure it is there when syscall__scnprintf_args() + * and the rest of the beautifiers accessing it via struct syscall_arg touches it. + */ + if (ttrace == NULL) + goto out_put; + + args = perf_evsel__sc_tp_ptr(evsel, args, sample); + syscall__scnprintf_args(sc, msg, sizeof(msg), args, trace, thread); + fprintf(trace->output, "%s", msg); + err = 0; +out_put: + thread__put(thread); + return err; +} + static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel, struct perf_sample *sample, struct callchain_cursor *cursor) @@ -1720,7 +1807,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, ret = perf_evsel__sc_tp_uint(evsel, ret, sample); - if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) { + if (sc->is_open && ret >= 0 && ttrace->filename.pending_open) { trace__set_fd_pathname(thread, ret, ttrace->filename.name); ttrace->filename.pending_open = false; ++trace->stats.vfs_getname; @@ -1955,11 +2042,17 @@ static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel, fprintf(trace->output, "%s:", evsel->name); if (perf_evsel__is_bpf_output(evsel)) { - bpf_output__fprintf(trace, sample); + if (evsel == trace->syscalls.events.augmented) + trace__fprintf_sys_enter(trace, evsel, sample); + else + bpf_output__fprintf(trace, sample); } else if (evsel->tp_format) { - event_format__fprintf(evsel->tp_format, sample->cpu, - sample->raw_data, sample->raw_size, - trace->output); + if (strncmp(evsel->tp_format->name, "sys_enter_", 10) || + trace__fprintf_sys_enter(trace, evsel, sample)) { + event_format__fprintf(evsel->tp_format, sample->cpu, + sample->raw_data, sample->raw_size, + trace->output); + } } fprintf(trace->output, "\n"); @@ -2240,14 +2333,14 @@ static int trace__add_syscall_newtp(struct trace *trace) struct perf_evlist *evlist = trace->evlist; struct perf_evsel *sys_enter, *sys_exit; - sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter); + sys_enter = perf_evsel__raw_syscall_newtp("sys_enter", trace__sys_enter); if (sys_enter == NULL) goto out; if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args)) goto out_delete_sys_enter; - sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit); + sys_exit = perf_evsel__raw_syscall_newtp("sys_exit", trace__sys_exit); if (sys_exit == NULL) goto out_delete_sys_enter; @@ -2669,7 +2762,7 @@ static int trace__replay(struct trace *trace) "syscalls:sys_enter"); if (evsel && - (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 || + (perf_evsel__init_raw_syscall_tp(evsel, trace__sys_enter) < 0 || perf_evsel__init_sc_tp_ptr_field(evsel, args))) { pr_err("Error during initialize raw_syscalls:sys_enter event\n"); goto out; @@ -2681,7 +2774,7 @@ static int trace__replay(struct trace *trace) evsel = perf_evlist__find_tracepoint_by_name(session->evlist, "syscalls:sys_exit"); if (evsel && - (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 || + (perf_evsel__init_raw_syscall_tp(evsel, trace__sys_exit) < 0 || perf_evsel__init_sc_tp_uint_field(evsel, ret))) { pr_err("Error during initialize raw_syscalls:sys_exit event\n"); goto out; @@ -2921,6 +3014,36 @@ static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler) evsel->handler = handler; } +static int evlist__set_syscall_tp_fields(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel; + + evlist__for_each_entry(evlist, evsel) { + if (evsel->priv || !evsel->tp_format) + continue; + + if (strcmp(evsel->tp_format->system, "syscalls")) + continue; + + if (perf_evsel__init_syscall_tp(evsel)) + return -1; + + if (!strncmp(evsel->tp_format->name, "sys_enter_", 10)) { + struct syscall_tp *sc = evsel->priv; + + if (__tp_field__init_ptr(&sc->args, sc->id.offset + sizeof(u64))) + return -1; + } else if (!strncmp(evsel->tp_format->name, "sys_exit_", 9)) { + struct syscall_tp *sc = evsel->priv; + + if (__tp_field__init_uint(&sc->ret, sizeof(u64), sc->id.offset + sizeof(u64), evsel->needs_swap)) + return -1; + } + } + + return 0; +} + /* * XXX: Hackish, just splitting the combined -e+--event (syscalls * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use @@ -2990,6 +3113,7 @@ static int trace__parse_events_option(const struct option *opt, const char *str, if (trace__validate_ev_qualifier(trace)) goto out; + trace->trace_syscalls = true; } err = 0; @@ -3045,7 +3169,7 @@ int cmd_trace(int argc, const char **argv) }, .output = stderr, .show_comm = true, - .trace_syscalls = true, + .trace_syscalls = false, .kernel_syscallchains = false, .max_stack = UINT_MAX, }; @@ -3120,8 +3244,9 @@ int cmd_trace(int argc, const char **argv) }; bool __maybe_unused max_stack_user_set = true; bool mmap_pages_user_set = true; + struct perf_evsel *evsel; const char * const trace_subcommands[] = { "record", NULL }; - int err; + int err = -1; char bf[BUFSIZ]; signal(SIGSEGV, sighandler_dump_stack); @@ -3144,6 +3269,20 @@ int cmd_trace(int argc, const char **argv) "cgroup monitoring only available in system-wide mode"); } + evsel = bpf__setup_output_event(trace.evlist, "__augmented_syscalls__"); + if (IS_ERR(evsel)) { + bpf__strerror_setup_output_event(trace.evlist, PTR_ERR(evsel), bf, sizeof(bf)); + pr_err("ERROR: Setup trace syscalls enter failed: %s\n", bf); + goto out; + } + + if (evsel) { + if (perf_evsel__init_augmented_syscall_tp(evsel) || + perf_evsel__init_augmented_syscall_tp_args(evsel)) + goto out; + trace.syscalls.events.augmented = evsel; + } + err = bpf__setup_stdout(trace.evlist); if (err) { bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf)); @@ -3179,8 +3318,13 @@ int cmd_trace(int argc, const char **argv) symbol_conf.use_callchain = true; } - if (trace.evlist->nr_entries > 0) + if (trace.evlist->nr_entries > 0) { evlist__set_evsel_handler(trace.evlist, trace__event_handler); + if (evlist__set_syscall_tp_fields(trace.evlist)) { + perror("failed to set syscalls:* tracepoint fields"); + goto out; + } + } if ((argc >= 1) && (strcmp(argv[0], "record") == 0)) return trace__record(&trace, argc-1, &argv[1]); @@ -3191,13 +3335,7 @@ int cmd_trace(int argc, const char **argv) if (!trace.trace_syscalls && !trace.trace_pgfaults && trace.evlist->nr_entries == 0 /* Was --events used? */) { - pr_err("Please specify something to trace.\n"); - return -1; - } - - if (!trace.trace_syscalls && trace.ev_qualifier) { - pr_err("The -e option can't be used with --no-syscalls.\n"); - goto out; + trace.trace_syscalls = true; } if (output_name != NULL) { @@ -3208,8 +3346,6 @@ int cmd_trace(int argc, const char **argv) } } - trace.open_id = syscalltbl__id(trace.sctbl, "open"); - err = target__validate(&trace.opts.target); if (err) { target__strerror(&trace.opts.target, err, bf, sizeof(bf)); diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh index 10f333e2e825..466540ee8ea7 100755 --- a/tools/perf/check-headers.sh +++ b/tools/perf/check-headers.sh @@ -7,6 +7,7 @@ include/uapi/drm/i915_drm.h include/uapi/linux/fcntl.h include/uapi/linux/kcmp.h include/uapi/linux/kvm.h +include/uapi/linux/in.h include/uapi/linux/perf_event.h include/uapi/linux/prctl.h include/uapi/linux/sched.h @@ -35,6 +36,7 @@ arch/s390/include/uapi/asm/ptrace.h arch/s390/include/uapi/asm/sie.h arch/arm/include/uapi/asm/kvm.h arch/arm64/include/uapi/asm/kvm.h +arch/arm64/include/uapi/asm/unistd.h arch/alpha/include/uapi/asm/errno.h arch/mips/include/asm/errno.h arch/mips/include/uapi/asm/errno.h @@ -53,6 +55,7 @@ include/uapi/asm-generic/errno.h include/uapi/asm-generic/errno-base.h include/uapi/asm-generic/ioctls.h include/uapi/asm-generic/mman-common.h +include/uapi/asm-generic/unistd.h ' check_2 () { @@ -64,8 +67,12 @@ check_2 () { cmd="diff $* $file1 $file2 > /dev/null" - test -f $file2 && - eval $cmd || echo "Warning: Kernel ABI header at 'tools/$file' differs from latest version at '$file'" >&2 + test -f $file2 && { + eval $cmd || { + echo "Warning: Kernel ABI header at '$file1' differs from latest version at '$file2'" >&2 + echo diff -u $file1 $file2 + } + } } check () { @@ -73,7 +80,7 @@ check () { shift - check_2 ../$file ../../$file $* + check_2 tools/$file $file $* } # Check if we have the kernel headers (tools/perf/../../include), else @@ -81,6 +88,8 @@ check () { # differences. test -d ../../include || exit 0 +cd ../.. + # simple diff check for i in $HEADERS; do check $i -B @@ -91,3 +100,8 @@ check arch/x86/lib/memcpy_64.S '-I "^EXPORT_SYMBOL" -I "^#include <asm/ex check arch/x86/lib/memset_64.S '-I "^EXPORT_SYMBOL" -I "^#include <asm/export.h>"' check include/uapi/asm-generic/mman.h '-I "^#include <\(uapi/\)*asm-generic/mman-common.h>"' check include/uapi/linux/mman.h '-I "^#include <\(uapi/\)*asm/mman.h>"' + +# diff non-symmetric files +check_2 tools/perf/arch/x86/entry/syscalls/syscall_64.tbl arch/x86/entry/syscalls/syscall_64.tbl + +cd tools/perf diff --git a/tools/perf/examples/bpf/augmented_syscalls.c b/tools/perf/examples/bpf/augmented_syscalls.c new file mode 100644 index 000000000000..69a31386d8cd --- /dev/null +++ b/tools/perf/examples/bpf/augmented_syscalls.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Augment the openat syscall with the contents of the filename pointer argument. + * + * Test it with: + * + * perf trace -e tools/perf/examples/bpf/augmented_syscalls.c cat /etc/passwd > /dev/null + * + * It'll catch some openat syscalls related to the dynamic linked and + * the last one should be the one for '/etc/passwd'. + * + * This matches what is marshalled into the raw_syscall:sys_enter payload + * expected by the 'perf trace' beautifiers, and can be used by them unmodified, + * which will be done as that feature is implemented in the next csets, for now + * it will appear in a dump done by the default tracepoint handler in 'perf trace', + * that uses bpf_output__fprintf() to just dump those contents, as done with + * the bpf-output event associated with the __bpf_output__ map declared in + * tools/perf/include/bpf/stdio.h. + */ + +#include <stdio.h> + +struct bpf_map SEC("maps") __augmented_syscalls__ = { + .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY, + .key_size = sizeof(int), + .value_size = sizeof(u32), + .max_entries = __NR_CPUS__, +}; + +struct syscall_enter_openat_args { + unsigned long long common_tp_fields; + long syscall_nr; + long dfd; + char *filename_ptr; + long flags; + long mode; +}; + +struct augmented_enter_openat_args { + struct syscall_enter_openat_args args; + char filename[64]; +}; + +int syscall_enter(openat)(struct syscall_enter_openat_args *args) +{ + struct augmented_enter_openat_args augmented_args; + + probe_read(&augmented_args.args, sizeof(augmented_args.args), args); + probe_read_str(&augmented_args.filename, sizeof(augmented_args.filename), args->filename_ptr); + perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, + &augmented_args, sizeof(augmented_args)); + return 1; +} + +license(GPL); diff --git a/tools/perf/examples/bpf/hello.c b/tools/perf/examples/bpf/hello.c new file mode 100644 index 000000000000..cf3c2fdc7f79 --- /dev/null +++ b/tools/perf/examples/bpf/hello.c @@ -0,0 +1,9 @@ +#include <stdio.h> + +int syscall_enter(openat)(void *args) +{ + puts("Hello, world\n"); + return 0; +} + +license(GPL); diff --git a/tools/perf/examples/bpf/sys_enter_openat.c b/tools/perf/examples/bpf/sys_enter_openat.c new file mode 100644 index 000000000000..9cd124b09392 --- /dev/null +++ b/tools/perf/examples/bpf/sys_enter_openat.c @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hook into 'openat' syscall entry tracepoint + * + * Test it with: + * + * perf trace -e tools/perf/examples/bpf/sys_enter_openat.c cat /etc/passwd > /dev/null + * + * It'll catch some openat syscalls related to the dynamic linked and + * the last one should be the one for '/etc/passwd'. + * + * The syscall_enter_openat_args can be used to get the syscall fields + * and use them for filtering calls, i.e. use in expressions for + * the return value. + */ + +#include <bpf.h> + +struct syscall_enter_openat_args { + unsigned long long unused; + long syscall_nr; + long dfd; + char *filename_ptr; + long flags; + long mode; +}; + +int syscall_enter(openat)(struct syscall_enter_openat_args *args) +{ + return 1; +} + +license(GPL); diff --git a/tools/perf/include/bpf/bpf.h b/tools/perf/include/bpf/bpf.h index dd764ad5efdf..47897d65e799 100644 --- a/tools/perf/include/bpf/bpf.h +++ b/tools/perf/include/bpf/bpf.h @@ -1,13 +1,36 @@ // SPDX-License-Identifier: GPL-2.0 #ifndef _PERF_BPF_H #define _PERF_BPF_H + +#include <uapi/linux/bpf.h> + +/* + * A helper structure used by eBPF C program to describe map attributes to + * elf_bpf loader, taken from tools/testing/selftests/bpf/bpf_helpers.h: + */ +struct bpf_map { + unsigned int type; + unsigned int key_size; + unsigned int value_size; + unsigned int max_entries; + unsigned int map_flags; + unsigned int inner_map_idx; + unsigned int numa_node; +}; + #define SEC(NAME) __attribute__((section(NAME), used)) #define probe(function, vars) \ SEC(#function "=" #function " " #vars) function +#define syscall_enter(name) \ + SEC("syscalls:sys_enter_" #name) syscall_enter_ ## name + #define license(name) \ char _license[] SEC("license") = #name; \ int _version SEC("version") = LINUX_VERSION_CODE; +static int (*probe_read)(void *dst, int size, const void *unsafe_addr) = (void *)BPF_FUNC_probe_read; +static int (*probe_read_str)(void *dst, int size, const void *unsafe_addr) = (void *)BPF_FUNC_probe_read_str; + #endif /* _PERF_BPF_H */ diff --git a/tools/perf/include/bpf/stdio.h b/tools/perf/include/bpf/stdio.h new file mode 100644 index 000000000000..2899cb7bfed8 --- /dev/null +++ b/tools/perf/include/bpf/stdio.h @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <bpf.h> + +struct bpf_map SEC("maps") __bpf_stdout__ = { + .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY, + .key_size = sizeof(int), + .value_size = sizeof(u32), + .max_entries = __NR_CPUS__, +}; + +static int (*perf_event_output)(void *, struct bpf_map *, int, void *, unsigned long) = + (void *)BPF_FUNC_perf_event_output; + +#define puts(from) \ + ({ const int __len = sizeof(from); \ + char __from[__len] = from; \ + perf_event_output(args, &__bpf_stdout__, BPF_F_CURRENT_CPU, \ + &__from, __len & (sizeof(from) - 1)); }) diff --git a/tools/perf/perf.h b/tools/perf/perf.h index d215714f48df..21bf7f5a3cf5 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -25,7 +25,9 @@ static inline unsigned long long rdclock(void) return ts.tv_sec * 1000000000ULL + ts.tv_nsec; } +#ifndef MAX_NR_CPUS #define MAX_NR_CPUS 1024 +#endif extern const char *input_name; extern bool perf_host, perf_guest; diff --git a/tools/perf/pmu-events/arch/arm64/ampere/emag/core-imp-def.json b/tools/perf/pmu-events/arch/arm64/ampere/emag/core-imp-def.json new file mode 100644 index 000000000000..bc03c06c3918 --- /dev/null +++ b/tools/perf/pmu-events/arch/arm64/ampere/emag/core-imp-def.json @@ -0,0 +1,32 @@ +[ + { + "ArchStdEvent": "L1D_CACHE_RD", + }, + { + "ArchStdEvent": "L1D_CACHE_WR", + }, + { + "ArchStdEvent": "L1D_CACHE_REFILL_RD", + }, + { + "ArchStdEvent": "L1D_CACHE_REFILL_WR", + }, + { + "ArchStdEvent": "L1D_TLB_REFILL_RD", + }, + { + "ArchStdEvent": "L1D_TLB_REFILL_WR", + }, + { + "ArchStdEvent": "L1D_TLB_RD", + }, + { + "ArchStdEvent": "L1D_TLB_WR", + }, + { + "ArchStdEvent": "BUS_ACCESS_RD", + }, + { + "ArchStdEvent": "BUS_ACCESS_WR", + } +] diff --git a/tools/perf/pmu-events/arch/arm64/cavium/thunderx2/core-imp-def.json b/tools/perf/pmu-events/arch/arm64/cavium/thunderx2/core-imp-def.json index bc03c06c3918..752e47eb6977 100644 --- a/tools/perf/pmu-events/arch/arm64/cavium/thunderx2/core-imp-def.json +++ b/tools/perf/pmu-events/arch/arm64/cavium/thunderx2/core-imp-def.json @@ -12,6 +12,21 @@ "ArchStdEvent": "L1D_CACHE_REFILL_WR", }, { + "ArchStdEvent": "L1D_CACHE_REFILL_INNER", + }, + { + "ArchStdEvent": "L1D_CACHE_REFILL_OUTER", + }, + { + "ArchStdEvent": "L1D_CACHE_WB_VICTIM", + }, + { + "ArchStdEvent": "L1D_CACHE_WB_CLEAN", + }, + { + "ArchStdEvent": "L1D_CACHE_INVAL", + }, + { "ArchStdEvent": "L1D_TLB_REFILL_RD", }, { @@ -24,9 +39,75 @@ "ArchStdEvent": "L1D_TLB_WR", }, { + "ArchStdEvent": "L2D_TLB_REFILL_RD", + }, + { + "ArchStdEvent": "L2D_TLB_REFILL_WR", + }, + { + "ArchStdEvent": "L2D_TLB_RD", + }, + { + "ArchStdEvent": "L2D_TLB_WR", + }, + { "ArchStdEvent": "BUS_ACCESS_RD", - }, - { + }, + { "ArchStdEvent": "BUS_ACCESS_WR", - } + }, + { + "ArchStdEvent": "MEM_ACCESS_RD", + }, + { + "ArchStdEvent": "MEM_ACCESS_WR", + }, + { + "ArchStdEvent": "UNALIGNED_LD_SPEC", + }, + { + "ArchStdEvent": "UNALIGNED_ST_SPEC", + }, + { + "ArchStdEvent": "UNALIGNED_LDST_SPEC", + }, + { + "ArchStdEvent": "EXC_UNDEF", + }, + { + "ArchStdEvent": "EXC_SVC", + }, + { + "ArchStdEvent": "EXC_PABORT", + }, + { + "ArchStdEvent": "EXC_DABORT", + }, + { + "ArchStdEvent": "EXC_IRQ", + }, + { + "ArchStdEvent": "EXC_FIQ", + }, + { + "ArchStdEvent": "EXC_SMC", + }, + { + "ArchStdEvent": "EXC_HVC", + }, + { + "ArchStdEvent": "EXC_TRAP_PABORT", + }, + { + "ArchStdEvent": "EXC_TRAP_DABORT", + }, + { + "ArchStdEvent": "EXC_TRAP_OTHER", + }, + { + "ArchStdEvent": "EXC_TRAP_IRQ", + }, + { + "ArchStdEvent": "EXC_TRAP_FIQ", + } ] diff --git a/tools/perf/pmu-events/arch/arm64/mapfile.csv b/tools/perf/pmu-events/arch/arm64/mapfile.csv index f03e26ecb658..59cd8604b0bd 100644 --- a/tools/perf/pmu-events/arch/arm64/mapfile.csv +++ b/tools/perf/pmu-events/arch/arm64/mapfile.csv @@ -16,3 +16,4 @@ 0x00000000420f5160,v1,cavium/thunderx2,core 0x00000000430f0af0,v1,cavium/thunderx2,core 0x00000000480fd010,v1,hisilicon/hip08,core +0x00000000500f0000,v1,ampere/emag,core diff --git a/tools/perf/pmu-events/arch/s390/cf_z10/basic.json b/tools/perf/pmu-events/arch/s390/cf_z10/basic.json index 8bf16759ca53..2dd8dafff2ef 100644 --- a/tools/perf/pmu-events/arch/s390/cf_z10/basic.json +++ b/tools/perf/pmu-events/arch/s390/cf_z10/basic.json @@ -1,71 +1,83 @@ [ { + "Unit": "CPU-M-CF", "EventCode": "0", "EventName": "CPU_CYCLES", "BriefDescription": "CPU Cycles", "PublicDescription": "Cycle Count" }, { + "Unit": "CPU-M-CF", "EventCode": "1", "EventName": "INSTRUCTIONS", "BriefDescription": "Instructions", "PublicDescription": "Instruction Count" }, { + "Unit": "CPU-M-CF", "EventCode": "2", "EventName": "L1I_DIR_WRITES", "BriefDescription": "L1I Directory Writes", "PublicDescription": "Level-1 I-Cache Directory Write Count" }, { + "Unit": "CPU-M-CF", "EventCode": "3", "EventName": "L1I_PENALTY_CYCLES", "BriefDescription": "L1I Penalty Cycles", "PublicDescription": "Level-1 I-Cache Penalty Cycle Count" }, { + "Unit": "CPU-M-CF", "EventCode": "4", "EventName": "L1D_DIR_WRITES", "BriefDescription": "L1D Directory Writes", "PublicDescription": "Level-1 D-Cache Directory Write Count" }, { + "Unit": "CPU-M-CF", "EventCode": "5", "EventName": "L1D_PENALTY_CYCLES", "BriefDescription": "L1D Penalty Cycles", "PublicDescription": "Level-1 D-Cache Penalty Cycle Count" }, { + "Unit": "CPU-M-CF", "EventCode": "32", "EventName": "PROBLEM_STATE_CPU_CYCLES", "BriefDescription": "Problem-State CPU Cycles", "PublicDescription": "Problem-State Cycle Count" }, { + "Unit": "CPU-M-CF", "EventCode": "33", "EventName": "PROBLEM_STATE_INSTRUCTIONS", "BriefDescription": "Problem-State Instructions", "PublicDescription": "Problem-State Instruction Count" }, { + "Unit": "CPU-M-CF", "EventCode": "34", "EventName": "PROBLEM_STATE_L1I_DIR_WRITES", "BriefDescription": "Problem-State L1I Directory Writes", "PublicDescription": "Problem-State Level-1 I-Cache Directory Write Count" }, { + "Unit": "CPU-M-CF", "EventCode": "35", "EventName": "PROBLEM_STATE_L1I_PENALTY_CYCLES", "BriefDescription": "Problem-State L1I Penalty Cycles", "PublicDescription": "Problem-State Level-1 I-Cache Penalty Cycle Count" }, { + "Unit": "CPU-M-CF", "EventCode": "36", "EventName": "PROBLEM_STATE_L1D_DIR_WRITES", "BriefDescription": "Problem-State L1D Directory Writes", "PublicDescription": "Problem-State Level-1 D-Cache Directory Write Count" }, { + "Unit": "CPU-M-CF", "EventCode": "37", "EventName": "PROBLEM_STATE_L1D_PENALTY_CYCLES", "BriefDescription": "Problem-State L1D Penalty Cycles", diff --git a/tools/perf/pmu-events/arch/s390/cf_z10/crypto.json b/tools/perf/pmu-events/arch/s390/cf_z10/crypto.json index 7e5b72492141..db286f19e7b6 100644 --- a/tools/perf/pmu-events/arch/s390/cf_z10/crypto.json +++ b/tools/perf/pmu-events/arch/s390/cf_z10/crypto.json @@ -1,95 +1,111 @@ [ { + "Unit": "CPU-M-CF", "EventCode": "64", "EventName": "PRNG_FUNCTIONS", "BriefDescription": "PRNG Functions", "PublicDescription": "Total number of the PRNG functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "65", "EventName": "PRNG_CYCLES", "BriefDescription": "PRNG Cycles", "PublicDescription": "Total number of CPU cycles when the DEA/AES coprocessor is busy performing PRNG functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "66", "EventName": "PRNG_BLOCKED_FUNCTIONS", "BriefDescription": "PRNG Blocked Functions", "PublicDescription": "Total number of the PRNG functions that are issued by the CPU and are blocked because the DEA/AES coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "67", "EventName": "PRNG_BLOCKED_CYCLES", "BriefDescription": "PRNG Blocked Cycles", "PublicDescription": "Total number of CPU cycles blocked for the PRNG functions issued by the CPU because the DEA/AES coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "68", "EventName": "SHA_FUNCTIONS", "BriefDescription": "SHA Functions", "PublicDescription": "Total number of SHA functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "69", "EventName": "SHA_CYCLES", "BriefDescription": "SHA Cycles", "PublicDescription": "Total number of CPU cycles when the SHA coprocessor is busy performing the SHA functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "70", "EventName": "SHA_BLOCKED_FUNCTIONS", "BriefDescription": "SHA Blocked Functions", "PublicDescription": "Total number of the SHA functions that are issued by the CPU and are blocked because the SHA coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "71", "EventName": "SHA_BLOCKED_CYCLES", "BriefDescription": "SHA Bloced Cycles", "PublicDescription": "Total number of CPU cycles blocked for the SHA functions issued by the CPU because the SHA coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "72", "EventName": "DEA_FUNCTIONS", "BriefDescription": "DEA Functions", "PublicDescription": "Total number of the DEA functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "73", "EventName": "DEA_CYCLES", "BriefDescription": "DEA Cycles", "PublicDescription": "Total number of CPU cycles when the DEA/AES coprocessor is busy performing the DEA functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "74", "EventName": "DEA_BLOCKED_FUNCTIONS", "BriefDescription": "DEA Blocked Functions", "PublicDescription": "Total number of the DEA functions that are issued by the CPU and are blocked because the DEA/AES coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "75", "EventName": "DEA_BLOCKED_CYCLES", "BriefDescription": "DEA Blocked Cycles", "PublicDescription": "Total number of CPU cycles blocked for the DEA functions issued by the CPU because the DEA/AES coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "76", "EventName": "AES_FUNCTIONS", "BriefDescription": "AES Functions", "PublicDescription": "Total number of AES functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "77", "EventName": "AES_CYCLES", "BriefDescription": "AES Cycles", "PublicDescription": "Total number of CPU cycles when the DEA/AES coprocessor is busy performing the AES functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "78", "EventName": "AES_BLOCKED_FUNCTIONS", "BriefDescription": "AES Blocked Functions", "PublicDescription": "Total number of AES functions that are issued by the CPU and are blocked because the DEA/AES coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "79", "EventName": "AES_BLOCKED_CYCLES", "BriefDescription": "AES Blocked Cycles", diff --git a/tools/perf/pmu-events/arch/s390/cf_z10/extended.json b/tools/perf/pmu-events/arch/s390/cf_z10/extended.json index 0feedb40f30f..b6b7f29ca831 100644 --- a/tools/perf/pmu-events/arch/s390/cf_z10/extended.json +++ b/tools/perf/pmu-events/arch/s390/cf_z10/extended.json @@ -1,107 +1,125 @@ [ { + "Unit": "CPU-M-CF", "EventCode": "128", "EventName": "L1I_L2_SOURCED_WRITES", "BriefDescription": "L1I L2 Sourced Writes", "PublicDescription": "A directory write to the Level-1 I-Cache directory where the returned cache line was sourced from the Level-2 (L1.5) cache" }, { + "Unit": "CPU-M-CF", "EventCode": "129", "EventName": "L1D_L2_SOURCED_WRITES", "BriefDescription": "L1D L2 Sourced Writes", "PublicDescription": "A directory write to the Level-1 D-Cache directory where the installed cache line was sourced from the Level-2 (L1.5) cache" }, { + "Unit": "CPU-M-CF", "EventCode": "130", "EventName": "L1I_L3_LOCAL_WRITES", "BriefDescription": "L1I L3 Local Writes", "PublicDescription": "A directory write to the Level-1 I-Cache directory where the installed cache line was sourced from the Level-3 cache that is on the same book as the Instruction cache (Local L2 cache)" }, { + "Unit": "CPU-M-CF", "EventCode": "131", "EventName": "L1D_L3_LOCAL_WRITES", "BriefDescription": "L1D L3 Local Writes", "PublicDescription": "A directory write to the Level-1 D-Cache directory where the installtion cache line was source from the Level-3 cache that is on the same book as the Data cache (Local L2 cache)" }, { + "Unit": "CPU-M-CF", "EventCode": "132", "EventName": "L1I_L3_REMOTE_WRITES", "BriefDescription": "L1I L3 Remote Writes", "PublicDescription": "A directory write to the Level-1 I-Cache directory where the installed cache line was sourced from a Level-3 cache that is not on the same book as the Instruction cache (Remote L2 cache)" }, { + "Unit": "CPU-M-CF", "EventCode": "133", "EventName": "L1D_L3_REMOTE_WRITES", "BriefDescription": "L1D L3 Remote Writes", "PublicDescription": "A directory write to the Level-1 D-Cache directory where the installed cache line was sourced from a Level-3 cache that is not on the same book as the Data cache (Remote L2 cache)" }, { + "Unit": "CPU-M-CF", "EventCode": "134", "EventName": "L1D_LMEM_SOURCED_WRITES", "BriefDescription": "L1D Local Memory Sourced Writes", "PublicDescription": "A directory write to the Level-1 D-Cache directory where the installed cache line was sourced from memory that is attached to the same book as the Data cache (Local Memory)" }, { + "Unit": "CPU-M-CF", "EventCode": "135", "EventName": "L1I_LMEM_SOURCED_WRITES", "BriefDescription": "L1I Local Memory Sourced Writes", "PublicDescription": "A directory write to the Level-1 I-Cache where the installed cache line was sourced from memory that is attached to the s ame book as the Instruction cache (Local Memory)" }, { + "Unit": "CPU-M-CF", "EventCode": "136", "EventName": "L1D_RO_EXCL_WRITES", "BriefDescription": "L1D Read-only Exclusive Writes", "PublicDescription": "A directory write to the Level-1 D-Cache where the line was originally in a Read-Only state in the cache but has been updated to be in the Exclusive state that allows stores to the cache line" }, { + "Unit": "CPU-M-CF", "EventCode": "137", "EventName": "L1I_CACHELINE_INVALIDATES", "BriefDescription": "L1I Cacheline Invalidates", "PublicDescription": "A cache line in the Level-1 I-Cache has been invalidated by a store on the same CPU as the Level-1 I-Cache" }, { + "Unit": "CPU-M-CF", "EventCode": "138", "EventName": "ITLB1_WRITES", "BriefDescription": "ITLB1 Writes", "PublicDescription": "A translation entry has been written into the Level-1 Instruction Translation Lookaside Buffer" }, { + "Unit": "CPU-M-CF", "EventCode": "139", "EventName": "DTLB1_WRITES", "BriefDescription": "DTLB1 Writes", "PublicDescription": "A translation entry has been written to the Level-1 Data Translation Lookaside Buffer" }, { + "Unit": "CPU-M-CF", "EventCode": "140", "EventName": "TLB2_PTE_WRITES", "BriefDescription": "TLB2 PTE Writes", "PublicDescription": "A translation entry has been written to the Level-2 TLB Page Table Entry arrays" }, { + "Unit": "CPU-M-CF", "EventCode": "141", "EventName": "TLB2_CRSTE_WRITES", "BriefDescription": "TLB2 CRSTE Writes", "PublicDescription": "A translation entry has been written to the Level-2 TLB Common Region Segment Table Entry arrays" }, { + "Unit": "CPU-M-CF", "EventCode": "142", "EventName": "TLB2_CRSTE_HPAGE_WRITES", "BriefDescription": "TLB2 CRSTE One-Megabyte Page Writes", "PublicDescription": "A translation entry has been written to the Level-2 TLB Common Region Segment Table Entry arrays for a one-megabyte large page translation" }, { + "Unit": "CPU-M-CF", "EventCode": "145", "EventName": "ITLB1_MISSES", "BriefDescription": "ITLB1 Misses", "PublicDescription": "Level-1 Instruction TLB miss in progress. Incremented by one for every cycle an ITLB1 miss is in progress" }, { + "Unit": "CPU-M-CF", "EventCode": "146", "EventName": "DTLB1_MISSES", "BriefDescription": "DTLB1 Misses", "PublicDescription": "Level-1 Data TLB miss in progress. Incremented by one for every cycle an DTLB1 miss is in progress" }, { + "Unit": "CPU-M-CF", "EventCode": "147", "EventName": "L2C_STORES_SENT", "BriefDescription": "L2C Stores Sent", diff --git a/tools/perf/pmu-events/arch/s390/cf_z13/basic.json b/tools/perf/pmu-events/arch/s390/cf_z13/basic.json index 8bf16759ca53..2dd8dafff2ef 100644 --- a/tools/perf/pmu-events/arch/s390/cf_z13/basic.json +++ b/tools/perf/pmu-events/arch/s390/cf_z13/basic.json @@ -1,71 +1,83 @@ [ { + "Unit": "CPU-M-CF", "EventCode": "0", "EventName": "CPU_CYCLES", "BriefDescription": "CPU Cycles", "PublicDescription": "Cycle Count" }, { + "Unit": "CPU-M-CF", "EventCode": "1", "EventName": "INSTRUCTIONS", "BriefDescription": "Instructions", "PublicDescription": "Instruction Count" }, { + "Unit": "CPU-M-CF", "EventCode": "2", "EventName": "L1I_DIR_WRITES", "BriefDescription": "L1I Directory Writes", "PublicDescription": "Level-1 I-Cache Directory Write Count" }, { + "Unit": "CPU-M-CF", "EventCode": "3", "EventName": "L1I_PENALTY_CYCLES", "BriefDescription": "L1I Penalty Cycles", "PublicDescription": "Level-1 I-Cache Penalty Cycle Count" }, { + "Unit": "CPU-M-CF", "EventCode": "4", "EventName": "L1D_DIR_WRITES", "BriefDescription": "L1D Directory Writes", "PublicDescription": "Level-1 D-Cache Directory Write Count" }, { + "Unit": "CPU-M-CF", "EventCode": "5", "EventName": "L1D_PENALTY_CYCLES", "BriefDescription": "L1D Penalty Cycles", "PublicDescription": "Level-1 D-Cache Penalty Cycle Count" }, { + "Unit": "CPU-M-CF", "EventCode": "32", "EventName": "PROBLEM_STATE_CPU_CYCLES", "BriefDescription": "Problem-State CPU Cycles", "PublicDescription": "Problem-State Cycle Count" }, { + "Unit": "CPU-M-CF", "EventCode": "33", "EventName": "PROBLEM_STATE_INSTRUCTIONS", "BriefDescription": "Problem-State Instructions", "PublicDescription": "Problem-State Instruction Count" }, { + "Unit": "CPU-M-CF", "EventCode": "34", "EventName": "PROBLEM_STATE_L1I_DIR_WRITES", "BriefDescription": "Problem-State L1I Directory Writes", "PublicDescription": "Problem-State Level-1 I-Cache Directory Write Count" }, { + "Unit": "CPU-M-CF", "EventCode": "35", "EventName": "PROBLEM_STATE_L1I_PENALTY_CYCLES", "BriefDescription": "Problem-State L1I Penalty Cycles", "PublicDescription": "Problem-State Level-1 I-Cache Penalty Cycle Count" }, { + "Unit": "CPU-M-CF", "EventCode": "36", "EventName": "PROBLEM_STATE_L1D_DIR_WRITES", "BriefDescription": "Problem-State L1D Directory Writes", "PublicDescription": "Problem-State Level-1 D-Cache Directory Write Count" }, { + "Unit": "CPU-M-CF", "EventCode": "37", "EventName": "PROBLEM_STATE_L1D_PENALTY_CYCLES", "BriefDescription": "Problem-State L1D Penalty Cycles", diff --git a/tools/perf/pmu-events/arch/s390/cf_z13/crypto.json b/tools/perf/pmu-events/arch/s390/cf_z13/crypto.json index 7e5b72492141..db286f19e7b6 100644 --- a/tools/perf/pmu-events/arch/s390/cf_z13/crypto.json +++ b/tools/perf/pmu-events/arch/s390/cf_z13/crypto.json @@ -1,95 +1,111 @@ [ { + "Unit": "CPU-M-CF", "EventCode": "64", "EventName": "PRNG_FUNCTIONS", "BriefDescription": "PRNG Functions", "PublicDescription": "Total number of the PRNG functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "65", "EventName": "PRNG_CYCLES", "BriefDescription": "PRNG Cycles", "PublicDescription": "Total number of CPU cycles when the DEA/AES coprocessor is busy performing PRNG functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "66", "EventName": "PRNG_BLOCKED_FUNCTIONS", "BriefDescription": "PRNG Blocked Functions", "PublicDescription": "Total number of the PRNG functions that are issued by the CPU and are blocked because the DEA/AES coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "67", "EventName": "PRNG_BLOCKED_CYCLES", "BriefDescription": "PRNG Blocked Cycles", "PublicDescription": "Total number of CPU cycles blocked for the PRNG functions issued by the CPU because the DEA/AES coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "68", "EventName": "SHA_FUNCTIONS", "BriefDescription": "SHA Functions", "PublicDescription": "Total number of SHA functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "69", "EventName": "SHA_CYCLES", "BriefDescription": "SHA Cycles", "PublicDescription": "Total number of CPU cycles when the SHA coprocessor is busy performing the SHA functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "70", "EventName": "SHA_BLOCKED_FUNCTIONS", "BriefDescription": "SHA Blocked Functions", "PublicDescription": "Total number of the SHA functions that are issued by the CPU and are blocked because the SHA coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "71", "EventName": "SHA_BLOCKED_CYCLES", "BriefDescription": "SHA Bloced Cycles", "PublicDescription": "Total number of CPU cycles blocked for the SHA functions issued by the CPU because the SHA coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "72", "EventName": "DEA_FUNCTIONS", "BriefDescription": "DEA Functions", "PublicDescription": "Total number of the DEA functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "73", "EventName": "DEA_CYCLES", "BriefDescription": "DEA Cycles", "PublicDescription": "Total number of CPU cycles when the DEA/AES coprocessor is busy performing the DEA functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "74", "EventName": "DEA_BLOCKED_FUNCTIONS", "BriefDescription": "DEA Blocked Functions", "PublicDescription": "Total number of the DEA functions that are issued by the CPU and are blocked because the DEA/AES coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "75", "EventName": "DEA_BLOCKED_CYCLES", "BriefDescription": "DEA Blocked Cycles", "PublicDescription": "Total number of CPU cycles blocked for the DEA functions issued by the CPU because the DEA/AES coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "76", "EventName": "AES_FUNCTIONS", "BriefDescription": "AES Functions", "PublicDescription": "Total number of AES functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "77", "EventName": "AES_CYCLES", "BriefDescription": "AES Cycles", "PublicDescription": "Total number of CPU cycles when the DEA/AES coprocessor is busy performing the AES functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "78", "EventName": "AES_BLOCKED_FUNCTIONS", "BriefDescription": "AES Blocked Functions", "PublicDescription": "Total number of AES functions that are issued by the CPU and are blocked because the DEA/AES coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "79", "EventName": "AES_BLOCKED_CYCLES", "BriefDescription": "AES Blocked Cycles", diff --git a/tools/perf/pmu-events/arch/s390/cf_z13/extended.json b/tools/perf/pmu-events/arch/s390/cf_z13/extended.json index 9a002b6967f1..436ce33f1182 100644 --- a/tools/perf/pmu-events/arch/s390/cf_z13/extended.json +++ b/tools/perf/pmu-events/arch/s390/cf_z13/extended.json @@ -1,335 +1,391 @@ [ { + "Unit": "CPU-M-CF", "EventCode": "128", "EventName": "L1D_RO_EXCL_WRITES", "BriefDescription": "L1D Read-only Exclusive Writes", "PublicDescription": "A directory write to the Level-1 Data cache where the line was originally in a Read-Only state in the cache but has been updated to be in the Exclusive state that allows stores to the cache line." }, { + "Unit": "CPU-M-CF", "EventCode": "129", "EventName": "DTLB1_WRITES", "BriefDescription": "DTLB1 Writes", "PublicDescription": "A translation entry has been written to the Level-1 Data Translation Lookaside Buffer" }, { + "Unit": "CPU-M-CF", "EventCode": "130", "EventName": "DTLB1_MISSES", "BriefDescription": "DTLB1 Misses", "PublicDescription": "Level-1 Data TLB miss in progress. Incremented by one for every cycle a DTLB1 miss is in progress." }, { + "Unit": "CPU-M-CF", "EventCode": "131", "EventName": "DTLB1_HPAGE_WRITES", "BriefDescription": "DTLB1 One-Megabyte Page Writes", "PublicDescription": "A translation entry has been written to the Level-1 Data Translation Lookaside Buffer for a one-megabyte page" }, { + "Unit": "CPU-M-CF", "EventCode": "132", "EventName": "DTLB1_GPAGE_WRITES", "BriefDescription": "DTLB1 Two-Gigabyte Page Writes", "PublicDescription": "Counter:132 Name:DTLB1_GPAGE_WRITES A translation entry has been written to the Level-1 Data Translation Lookaside Buffer for a two-gigabyte page." }, { + "Unit": "CPU-M-CF", "EventCode": "133", "EventName": "L1D_L2D_SOURCED_WRITES", "BriefDescription": "L1D L2D Sourced Writes", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from the Level-2 Data cache" }, { + "Unit": "CPU-M-CF", "EventCode": "134", "EventName": "ITLB1_WRITES", "BriefDescription": "ITLB1 Writes", "PublicDescription": "A translation entry has been written to the Level-1 Instruction Translation Lookaside Buffer" }, { + "Unit": "CPU-M-CF", "EventCode": "135", "EventName": "ITLB1_MISSES", "BriefDescription": "ITLB1 Misses", "PublicDescription": "Level-1 Instruction TLB miss in progress. Incremented by one for every cycle an ITLB1 miss is in progress" }, { + "Unit": "CPU-M-CF", "EventCode": "136", "EventName": "L1I_L2I_SOURCED_WRITES", "BriefDescription": "L1I L2I Sourced Writes", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from the Level-2 Instruction cache" }, { + "Unit": "CPU-M-CF", "EventCode": "137", "EventName": "TLB2_PTE_WRITES", "BriefDescription": "TLB2 PTE Writes", "PublicDescription": "A translation entry has been written to the Level-2 TLB Page Table Entry arrays" }, { + "Unit": "CPU-M-CF", "EventCode": "138", "EventName": "TLB2_CRSTE_HPAGE_WRITES", "BriefDescription": "TLB2 CRSTE One-Megabyte Page Writes", "PublicDescription": "A translation entry has been written to the Level-2 TLB Combined Region Segment Table Entry arrays for a one-megabyte large page translation" }, { + "Unit": "CPU-M-CF", "EventCode": "139", "EventName": "TLB2_CRSTE_WRITES", "BriefDescription": "TLB2 CRSTE Writes", "PublicDescription": "A translation entry has been written to the Level-2 TLB Combined Region Segment Table Entry arrays" }, { + "Unit": "CPU-M-CF", "EventCode": "140", "EventName": "TX_C_TEND", "BriefDescription": "Completed TEND instructions in constrained TX mode", "PublicDescription": "A TEND instruction has completed in a constrained transactional-execution mode" }, { + "Unit": "CPU-M-CF", "EventCode": "141", "EventName": "TX_NC_TEND", "BriefDescription": "Completed TEND instructions in non-constrained TX mode", "PublicDescription": "A TEND instruction has completed in a non-constrained transactional-execution mode" }, { + "Unit": "CPU-M-CF", "EventCode": "143", "EventName": "L1C_TLB1_MISSES", "BriefDescription": "L1C TLB1 Misses", "PublicDescription": "Increments by one for any cycle where a Level-1 cache or Level-1 TLB miss is in progress." }, { + "Unit": "CPU-M-CF", "EventCode": "144", "EventName": "L1D_ONCHIP_L3_SOURCED_WRITES", "BriefDescription": "L1D On-Chip L3 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an On-Chip Level-3 cache without intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "145", "EventName": "L1D_ONCHIP_L3_SOURCED_WRITES_IV", "BriefDescription": "L1D On-Chip L3 Sourced Writes with Intervention", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an On-Chip Level-3 cache with intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "146", "EventName": "L1D_ONNODE_L4_SOURCED_WRITES", "BriefDescription": "L1D On-Node L4 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an On-Node Level-4 cache" }, { + "Unit": "CPU-M-CF", "EventCode": "147", "EventName": "L1D_ONNODE_L3_SOURCED_WRITES_IV", "BriefDescription": "L1D On-Node L3 Sourced Writes with Intervention", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an On-Node Level-3 cache with intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "148", "EventName": "L1D_ONNODE_L3_SOURCED_WRITES", "BriefDescription": "L1D On-Node L3 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an On-Node Level-3 cache without intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "149", "EventName": "L1D_ONDRAWER_L4_SOURCED_WRITES", "BriefDescription": "L1D On-Drawer L4 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an On-Drawer Level-4 cache" }, { + "Unit": "CPU-M-CF", "EventCode": "150", "EventName": "L1D_ONDRAWER_L3_SOURCED_WRITES_IV", "BriefDescription": "L1D On-Drawer L3 Sourced Writes with Intervention", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an On-Drawer Level-3 cache with intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "151", "EventName": "L1D_ONDRAWER_L3_SOURCED_WRITES", "BriefDescription": "L1D On-Drawer L3 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an On-Drawer Level-3 cache without intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "152", "EventName": "L1D_OFFDRAWER_SCOL_L4_SOURCED_WRITES", "BriefDescription": "L1D Off-Drawer Same-Column L4 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an Off-Drawer Same-Column Level-4 cache" }, { + "Unit": "CPU-M-CF", "EventCode": "153", "EventName": "L1D_OFFDRAWER_SCOL_L3_SOURCED_WRITES_IV", "BriefDescription": "L1D Off-Drawer Same-Column L3 Sourced Writes with Intervention", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an Off-Drawer Same-Column Level-3 cache with intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "154", "EventName": "L1D_OFFDRAWER_SCOL_L3_SOURCED_WRITES", "BriefDescription": "L1D Off-Drawer Same-Column L3 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an Off-Drawer Same-Column Level-3 cache without intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "155", "EventName": "L1D_OFFDRAWER_FCOL_L4_SOURCED_WRITES", "BriefDescription": "L1D Off-Drawer Far-Column L3 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an Off-Drawer Far-Column Level-4 cache" }, { + "Unit": "CPU-M-CF", "EventCode": "156", "EventName": "L1D_OFFDRAWER_FCOL_L3_SOURCED_WRITES_IV", "BriefDescription": "L1D Off-Drawer Far-Column L3 Sourced Writes with Intervention", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an Off-Drawer Far-Column Level-3 cache with intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "157", "EventName": "L1D_OFFDRAWER_FCOL_L3_SOURCED_WRITES", "BriefDescription": "L1D Off-Drawer Far-Column L3 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an Off-Drawer Far-Column Level-3 cache without intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "158", "EventName": "L1D_ONNODE_MEM_SOURCED_WRITES", "BriefDescription": "L1D On-Node Memory Sourced Writes", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from On-Node memory" }, { + "Unit": "CPU-M-CF", "EventCode": "159", "EventName": "L1D_ONDRAWER_MEM_SOURCED_WRITES", "BriefDescription": "L1D On-Drawer Memory Sourced Writes", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from On-Drawer memory" }, { + "Unit": "CPU-M-CF", "EventCode": "160", "EventName": "L1D_OFFDRAWER_MEM_SOURCED_WRITES", "BriefDescription": "L1D Off-Drawer Memory Sourced Writes", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from On-Drawer memory" }, { + "Unit": "CPU-M-CF", "EventCode": "161", "EventName": "L1D_ONCHIP_MEM_SOURCED_WRITES", "BriefDescription": "L1D On-Chip Memory Sourced Writes", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from On-Chip memory" }, { + "Unit": "CPU-M-CF", "EventCode": "162", "EventName": "L1I_ONCHIP_L3_SOURCED_WRITES", "BriefDescription": "L1I On-Chip L3 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an On-Chip Level-3 cache without intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "163", "EventName": "L1I_ONCHIP_L3_SOURCED_WRITES_IV", "BriefDescription": "L1I On-Chip L3 Sourced Writes with Intervention", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an On Chip Level-3 cache with intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "164", "EventName": "L1I_ONNODE_L4_SOURCED_WRITES", "BriefDescription": "L1I On-Chip L4 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an On-Node Level-4 cache" }, { + "Unit": "CPU-M-CF", "EventCode": "165", "EventName": "L1I_ONNODE_L3_SOURCED_WRITES_IV", "BriefDescription": "L1I On-Node L3 Sourced Writes with Intervention", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an On-Node Level-3 cache with intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "166", "EventName": "L1I_ONNODE_L3_SOURCED_WRITES", "BriefDescription": "L1I On-Node L3 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an On-Node Level-3 cache without intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "167", "EventName": "L1I_ONDRAWER_L4_SOURCED_WRITES", "BriefDescription": "L1I On-Drawer L4 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an On-Drawer Level-4 cache" }, { + "Unit": "CPU-M-CF", "EventCode": "168", "EventName": "L1I_ONDRAWER_L3_SOURCED_WRITES_IV", "BriefDescription": "L1I On-Drawer L3 Sourced Writes with Intervention", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an On-Drawer Level-3 cache with intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "169", "EventName": "L1I_ONDRAWER_L3_SOURCED_WRITES", "BriefDescription": "L1I On-Drawer L3 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an On-Drawer Level-3 cache without intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "170", "EventName": "L1I_OFFDRAWER_SCOL_L4_SOURCED_WRITES", "BriefDescription": "L1I Off-Drawer Same-Column L4 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an Off-Drawer Same-Column Level-4 cache" }, { + "Unit": "CPU-M-CF", "EventCode": "171", "EventName": "L1I_OFFDRAWER_SCOL_L3_SOURCED_WRITES_IV", "BriefDescription": "L1I Off-Drawer Same-Column L3 Sourced Writes with Intervention", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an Off-Drawer Same-Column Level-3 cache with intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "172", "EventName": "L1I_OFFDRAWER_SCOL_L3_SOURCED_WRITES", "BriefDescription": "L1I Off-Drawer Same-Column L3 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an Off-Drawer Same-Column Level-3 cache without intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "173", "EventName": "L1I_OFFDRAWER_FCOL_L4_SOURCED_WRITES", "BriefDescription": "L1I Off-Drawer Far-Column L4 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an Off-Drawer Far-Column Level-4 cache" }, { + "Unit": "CPU-M-CF", "EventCode": "174", "EventName": "L1I_OFFDRAWER_FCOL_L3_SOURCED_WRITES_IV", "BriefDescription": "L1I Off-Drawer Far-Column L3 Sourced Writes with Intervention", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an Off-Drawer Far-Column Level-3 cache with intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "175", "EventName": "L1I_OFFDRAWER_FCOL_L3_SOURCED_WRITES", "BriefDescription": "L1I Off-Drawer Far-Column L3 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an Off-Drawer Far-Column Level-3 cache without intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "176", "EventName": "L1I_ONNODE_MEM_SOURCED_WRITES", "BriefDescription": "L1I On-Node Memory Sourced Writes", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from On-Node memory" }, { + "Unit": "CPU-M-CF", "EventCode": "177", "EventName": "L1I_ONDRAWER_MEM_SOURCED_WRITES", "BriefDescription": "L1I On-Drawer Memory Sourced Writes", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from On-Drawer memory" }, { + "Unit": "CPU-M-CF", "EventCode": "178", "EventName": "L1I_OFFDRAWER_MEM_SOURCED_WRITES", "BriefDescription": "L1I Off-Drawer Memory Sourced Writes", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from On-Drawer memory" }, { + "Unit": "CPU-M-CF", "EventCode": "179", "EventName": "L1I_ONCHIP_MEM_SOURCED_WRITES", "BriefDescription": "L1I On-Chip Memory Sourced Writes", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from On-Chip memory" }, { + "Unit": "CPU-M-CF", "EventCode": "218", "EventName": "TX_NC_TABORT", "BriefDescription": "Aborted transactions in non-constrained TX mode", "PublicDescription": "A transaction abort has occurred in a non-constrained transactional-execution mode" }, { + "Unit": "CPU-M-CF", "EventCode": "219", "EventName": "TX_C_TABORT_NO_SPECIAL", "BriefDescription": "Aborted transactions in constrained TX mode not using special completion logic", "PublicDescription": "A transaction abort has occurred in a constrained transactional-execution mode and the CPU is not using any special logic to allow the transaction to complete" }, { + "Unit": "CPU-M-CF", "EventCode": "220", "EventName": "TX_C_TABORT_SPECIAL", "BriefDescription": "Aborted transactions in constrained TX mode using special completion logic", "PublicDescription": "A transaction abort has occurred in a constrained transactional-execution mode and the CPU is using special logic to allow the transaction to complete" }, { + "Unit": "CPU-M-CF", "EventCode": "448", "EventName": "MT_DIAG_CYCLES_ONE_THR_ACTIVE", "BriefDescription": "Cycle count with one thread active", "PublicDescription": "Cycle count with one thread active" }, { + "Unit": "CPU-M-CF", "EventCode": "449", "EventName": "MT_DIAG_CYCLES_TWO_THR_ACTIVE", "BriefDescription": "Cycle count with two threads active", diff --git a/tools/perf/pmu-events/arch/s390/cf_z13/transaction.json b/tools/perf/pmu-events/arch/s390/cf_z13/transaction.json new file mode 100644 index 000000000000..1a0034f79f73 --- /dev/null +++ b/tools/perf/pmu-events/arch/s390/cf_z13/transaction.json @@ -0,0 +1,7 @@ +[ + { + "BriefDescription": "Transaction count", + "MetricName": "transaction", + "MetricExpr": "TX_C_TEND + TX_NC_TEND + TX_NC_TABORT + TX_C_TABORT_SPECIAL + TX_C_TABORT_NO_SPECIAL" + } +] diff --git a/tools/perf/pmu-events/arch/s390/cf_z14/basic.json b/tools/perf/pmu-events/arch/s390/cf_z14/basic.json index 8f653c9d899d..17fb5241928b 100644 --- a/tools/perf/pmu-events/arch/s390/cf_z14/basic.json +++ b/tools/perf/pmu-events/arch/s390/cf_z14/basic.json @@ -1,47 +1,55 @@ [ { + "Unit": "CPU-M-CF", "EventCode": "0", "EventName": "CPU_CYCLES", "BriefDescription": "CPU Cycles", "PublicDescription": "Cycle Count" }, { + "Unit": "CPU-M-CF", "EventCode": "1", "EventName": "INSTRUCTIONS", "BriefDescription": "Instructions", "PublicDescription": "Instruction Count" }, { + "Unit": "CPU-M-CF", "EventCode": "2", "EventName": "L1I_DIR_WRITES", "BriefDescription": "L1I Directory Writes", "PublicDescription": "Level-1 I-Cache Directory Write Count" }, { + "Unit": "CPU-M-CF", "EventCode": "3", "EventName": "L1I_PENALTY_CYCLES", "BriefDescription": "L1I Penalty Cycles", "PublicDescription": "Level-1 I-Cache Penalty Cycle Count" }, { + "Unit": "CPU-M-CF", "EventCode": "4", "EventName": "L1D_DIR_WRITES", "BriefDescription": "L1D Directory Writes", "PublicDescription": "Level-1 D-Cache Directory Write Count" }, { + "Unit": "CPU-M-CF", "EventCode": "5", "EventName": "L1D_PENALTY_CYCLES", "BriefDescription": "L1D Penalty Cycles", "PublicDescription": "Level-1 D-Cache Penalty Cycle Count" }, { + "Unit": "CPU-M-CF", "EventCode": "32", "EventName": "PROBLEM_STATE_CPU_CYCLES", "BriefDescription": "Problem-State CPU Cycles", "PublicDescription": "Problem-State Cycle Count" }, { + "Unit": "CPU-M-CF", "EventCode": "33", "EventName": "PROBLEM_STATE_INSTRUCTIONS", "BriefDescription": "Problem-State Instructions", diff --git a/tools/perf/pmu-events/arch/s390/cf_z14/crypto.json b/tools/perf/pmu-events/arch/s390/cf_z14/crypto.json index 7e5b72492141..db286f19e7b6 100644 --- a/tools/perf/pmu-events/arch/s390/cf_z14/crypto.json +++ b/tools/perf/pmu-events/arch/s390/cf_z14/crypto.json @@ -1,95 +1,111 @@ [ { + "Unit": "CPU-M-CF", "EventCode": "64", "EventName": "PRNG_FUNCTIONS", "BriefDescription": "PRNG Functions", "PublicDescription": "Total number of the PRNG functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "65", "EventName": "PRNG_CYCLES", "BriefDescription": "PRNG Cycles", "PublicDescription": "Total number of CPU cycles when the DEA/AES coprocessor is busy performing PRNG functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "66", "EventName": "PRNG_BLOCKED_FUNCTIONS", "BriefDescription": "PRNG Blocked Functions", "PublicDescription": "Total number of the PRNG functions that are issued by the CPU and are blocked because the DEA/AES coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "67", "EventName": "PRNG_BLOCKED_CYCLES", "BriefDescription": "PRNG Blocked Cycles", "PublicDescription": "Total number of CPU cycles blocked for the PRNG functions issued by the CPU because the DEA/AES coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "68", "EventName": "SHA_FUNCTIONS", "BriefDescription": "SHA Functions", "PublicDescription": "Total number of SHA functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "69", "EventName": "SHA_CYCLES", "BriefDescription": "SHA Cycles", "PublicDescription": "Total number of CPU cycles when the SHA coprocessor is busy performing the SHA functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "70", "EventName": "SHA_BLOCKED_FUNCTIONS", "BriefDescription": "SHA Blocked Functions", "PublicDescription": "Total number of the SHA functions that are issued by the CPU and are blocked because the SHA coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "71", "EventName": "SHA_BLOCKED_CYCLES", "BriefDescription": "SHA Bloced Cycles", "PublicDescription": "Total number of CPU cycles blocked for the SHA functions issued by the CPU because the SHA coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "72", "EventName": "DEA_FUNCTIONS", "BriefDescription": "DEA Functions", "PublicDescription": "Total number of the DEA functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "73", "EventName": "DEA_CYCLES", "BriefDescription": "DEA Cycles", "PublicDescription": "Total number of CPU cycles when the DEA/AES coprocessor is busy performing the DEA functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "74", "EventName": "DEA_BLOCKED_FUNCTIONS", "BriefDescription": "DEA Blocked Functions", "PublicDescription": "Total number of the DEA functions that are issued by the CPU and are blocked because the DEA/AES coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "75", "EventName": "DEA_BLOCKED_CYCLES", "BriefDescription": "DEA Blocked Cycles", "PublicDescription": "Total number of CPU cycles blocked for the DEA functions issued by the CPU because the DEA/AES coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "76", "EventName": "AES_FUNCTIONS", "BriefDescription": "AES Functions", "PublicDescription": "Total number of AES functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "77", "EventName": "AES_CYCLES", "BriefDescription": "AES Cycles", "PublicDescription": "Total number of CPU cycles when the DEA/AES coprocessor is busy performing the AES functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "78", "EventName": "AES_BLOCKED_FUNCTIONS", "BriefDescription": "AES Blocked Functions", "PublicDescription": "Total number of AES functions that are issued by the CPU and are blocked because the DEA/AES coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "79", "EventName": "AES_BLOCKED_CYCLES", "BriefDescription": "AES Blocked Cycles", diff --git a/tools/perf/pmu-events/arch/s390/cf_z14/extended.json b/tools/perf/pmu-events/arch/s390/cf_z14/extended.json index aa4dfb46b65b..e7a3524b748f 100644 --- a/tools/perf/pmu-events/arch/s390/cf_z14/extended.json +++ b/tools/perf/pmu-events/arch/s390/cf_z14/extended.json @@ -1,317 +1,370 @@ [ { + "Unit": "CPU-M-CF", "EventCode": "128", "EventName": "L1D_RO_EXCL_WRITES", "BriefDescription": "L1D Read-only Exclusive Writes", "PublicDescription": "Counter:128 Name:L1D_RO_EXCL_WRITES A directory write to the Level-1 Data cache where the line was originally in a Read-Only state in the cache but has been updated to be in the Exclusive state that allows stores to the cache line" }, { + "Unit": "CPU-M-CF", "EventCode": "129", "EventName": "DTLB2_WRITES", "BriefDescription": "DTLB2 Writes", "PublicDescription": "A translation has been written into The Translation Lookaside Buffer 2 (TLB2) and the request was made by the data cache" }, { + "Unit": "CPU-M-CF", "EventCode": "130", "EventName": "DTLB2_MISSES", "BriefDescription": "DTLB2 Misses", "PublicDescription": "A TLB2 miss is in progress for a request made by the data cache. Incremented by one for every TLB2 miss in progress for the Level-1 Data cache on this cycle" }, { + "Unit": "CPU-M-CF", "EventCode": "131", "EventName": "DTLB2_HPAGE_WRITES", "BriefDescription": "DTLB2 One-Megabyte Page Writes", "PublicDescription": "A translation entry was written into the Combined Region and Segment Table Entry array in the Level-2 TLB for a one-megabyte page or a Last Host Translation was done" }, { + "Unit": "CPU-M-CF", "EventCode": "132", "EventName": "DTLB2_GPAGE_WRITES", "BriefDescription": "DTLB2 Two-Gigabyte Page Writes", "PublicDescription": "A translation entry for a two-gigabyte page was written into the Level-2 TLB" }, { + "Unit": "CPU-M-CF", "EventCode": "133", "EventName": "L1D_L2D_SOURCED_WRITES", "BriefDescription": "L1D L2D Sourced Writes", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from the Level-2 Data cache" }, { + "Unit": "CPU-M-CF", "EventCode": "134", "EventName": "ITLB2_WRITES", "BriefDescription": "ITLB2 Writes", "PublicDescription": "A translation entry has been written into the Translation Lookaside Buffer 2 (TLB2) and the request was made by the instruction cache" }, { + "Unit": "CPU-M-CF", "EventCode": "135", "EventName": "ITLB2_MISSES", "BriefDescription": "ITLB2 Misses", "PublicDescription": "A TLB2 miss is in progress for a request made by the instruction cache. Incremented by one for every TLB2 miss in progress for the Level-1 Instruction cache in a cycle" }, { + "Unit": "CPU-M-CF", "EventCode": "136", "EventName": "L1I_L2I_SOURCED_WRITES", "BriefDescription": "L1I L2I Sourced Writes", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from the Level-2 Instruction cache" }, { + "Unit": "CPU-M-CF", "EventCode": "137", "EventName": "TLB2_PTE_WRITES", "BriefDescription": "TLB2 PTE Writes", "PublicDescription": "A translation entry was written into the Page Table Entry array in the Level-2 TLB" }, { + "Unit": "CPU-M-CF", "EventCode": "138", "EventName": "TLB2_CRSTE_WRITES", "BriefDescription": "TLB2 CRSTE Writes", "PublicDescription": "Translation entries were written into the Combined Region and Segment Table Entry array and the Page Table Entry array in the Level-2 TLB" }, { + "Unit": "CPU-M-CF", "EventCode": "139", "EventName": "TLB2_ENGINES_BUSY", "BriefDescription": "TLB2 Engines Busy", "PublicDescription": "The number of Level-2 TLB translation engines busy in a cycle" }, { + "Unit": "CPU-M-CF", "EventCode": "140", "EventName": "TX_C_TEND", "BriefDescription": "Completed TEND instructions in constrained TX mode", "PublicDescription": "A TEND instruction has completed in a constrained transactional-execution mode" }, { + "Unit": "CPU-M-CF", "EventCode": "141", "EventName": "TX_NC_TEND", "BriefDescription": "Completed TEND instructions in non-constrained TX mode", "PublicDescription": "A TEND instruction has completed in a non-constrained transactional-execution mode" }, { + "Unit": "CPU-M-CF", "EventCode": "143", "EventName": "L1C_TLB2_MISSES", "BriefDescription": "L1C TLB2 Misses", "PublicDescription": "Increments by one for any cycle where a level-1 cache or level-2 TLB miss is in progress" }, { + "Unit": "CPU-M-CF", "EventCode": "144", "EventName": "L1D_ONCHIP_L3_SOURCED_WRITES", "BriefDescription": "L1D On-Chip L3 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an On-Chip Level-3 cache without intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "145", "EventName": "L1D_ONCHIP_MEMORY_SOURCED_WRITES", "BriefDescription": "L1D On-Chip Memory Sourced Writes", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from On-Chip memory" }, { + "Unit": "CPU-M-CF", "EventCode": "146", "EventName": "L1D_ONCHIP_L3_SOURCED_WRITES_IV", "BriefDescription": "L1D On-Chip L3 Sourced Writes with Intervention", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an On-Chip Level-3 cache with intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "147", "EventName": "L1D_ONCLUSTER_L3_SOURCED_WRITES", "BriefDescription": "L1D On-Cluster L3 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from On-Cluster Level-3 cache withountervention" }, { + "Unit": "CPU-M-CF", "EventCode": "148", "EventName": "L1D_ONCLUSTER_MEMORY_SOURCED_WRITES", "BriefDescription": "L1D On-Cluster Memory Sourced Writes", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an On-Cluster memory" }, { + "Unit": "CPU-M-CF", "EventCode": "149", "EventName": "L1D_ONCLUSTER_L3_SOURCED_WRITES_IV", "BriefDescription": "L1D On-Cluster L3 Sourced Writes with Intervention", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an On-Cluster Level-3 cache with intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "150", "EventName": "L1D_OFFCLUSTER_L3_SOURCED_WRITES", "BriefDescription": "L1D Off-Cluster L3 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an Off-Cluster Level-3 cache without intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "151", "EventName": "L1D_OFFCLUSTER_MEMORY_SOURCED_WRITES", "BriefDescription": "L1D Off-Cluster Memory Sourced Writes", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from Off-Cluster memory" }, { + "Unit": "CPU-M-CF", "EventCode": "152", "EventName": "L1D_OFFCLUSTER_L3_SOURCED_WRITES_IV", "BriefDescription": "L1D Off-Cluster L3 Sourced Writes with Intervention", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an Off-Cluster Level-3 cache with intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "153", "EventName": "L1D_OFFDRAWER_L3_SOURCED_WRITES", "BriefDescription": "L1D Off-Drawer L3 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an Off-Drawer Level-3 cache without intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "154", "EventName": "L1D_OFFDRAWER_MEMORY_SOURCED_WRITES", "BriefDescription": "L1D Off-Drawer Memory Sourced Writes", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from Off-Drawer memory" }, { + "Unit": "CPU-M-CF", "EventCode": "155", "EventName": "L1D_OFFDRAWER_L3_SOURCED_WRITES_IV", "BriefDescription": "L1D Off-Drawer L3 Sourced Writes with Intervention", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an Off-Drawer Level-3 cache with intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "156", "EventName": "L1D_ONDRAWER_L4_SOURCED_WRITES", "BriefDescription": "L1D On-Drawer L4 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from On-Drawer Level-4 cache" }, { + "Unit": "CPU-M-CF", "EventCode": "157", "EventName": "L1D_OFFDRAWER_L4_SOURCED_WRITES", "BriefDescription": "L1D Off-Drawer L4 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from Off-Drawer Level-4 cache" }, { + "Unit": "CPU-M-CF", "EventCode": "158", "EventName": "L1D_ONCHIP_L3_SOURCED_WRITES_RO", "BriefDescription": "L1D On-Chip L3 Sourced Writes read-only", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from On-Chip L3 but a read-only invalidate was done to remove other copies of the cache line" }, { + "Unit": "CPU-M-CF", "EventCode": "162", "EventName": "L1I_ONCHIP_L3_SOURCED_WRITES", "BriefDescription": "L1I On-Chip L3 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache ine was sourced from an On-Chip Level-3 cache without intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "163", "EventName": "L1I_ONCHIP_MEMORY_SOURCED_WRITES", "BriefDescription": "L1I On-Chip Memory Sourced Writes", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache ine was sourced from On-Chip memory" }, { + "Unit": "CPU-M-CF", "EventCode": "164", "EventName": "L1I_ONCHIP_L3_SOURCED_WRITES_IV", "BriefDescription": "L1I On-Chip L3 Sourced Writes with Intervention", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache ine was sourced from an On-Chip Level-3 cache with intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "165", "EventName": "L1I_ONCLUSTER_L3_SOURCED_WRITES", "BriefDescription": "L1I On-Cluster L3 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an On-Cluster Level-3 cache without intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "166", "EventName": "L1I_ONCLUSTER_MEMORY_SOURCED_WRITES", "BriefDescription": "L1I On-Cluster Memory Sourced Writes", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an On-Cluster memory" }, { + "Unit": "CPU-M-CF", "EventCode": "167", "EventName": "L1I_ONCLUSTER_L3_SOURCED_WRITES_IV", "BriefDescription": "L1I On-Cluster L3 Sourced Writes with Intervention", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from On-Cluster Level-3 cache with intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "168", "EventName": "L1I_OFFCLUSTER_L3_SOURCED_WRITES", "BriefDescription": "L1I Off-Cluster L3 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an Off-Cluster Level-3 cache without intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "169", "EventName": "L1I_OFFCLUSTER_MEMORY_SOURCED_WRITES", "BriefDescription": "L1I Off-Cluster Memory Sourced Writes", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from Off-Cluster memory" }, { + "Unit": "CPU-M-CF", "EventCode": "170", "EventName": "L1I_OFFCLUSTER_L3_SOURCED_WRITES_IV", "BriefDescription": "L1I Off-Cluster L3 Sourced Writes with Intervention", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an Off-Cluster Level-3 cache with intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "171", "EventName": "L1I_OFFDRAWER_L3_SOURCED_WRITES", "BriefDescription": "L1I Off-Drawer L3 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an Off-Drawer Level-3 cache without intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "172", "EventName": "L1I_OFFDRAWER_MEMORY_SOURCED_WRITES", "BriefDescription": "L1I Off-Drawer Memory Sourced Writes", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from Off-Drawer memory" }, { + "Unit": "CPU-M-CF", "EventCode": "173", "EventName": "L1I_OFFDRAWER_L3_SOURCED_WRITES_IV", "BriefDescription": "L1I Off-Drawer L3 Sourced Writes with Intervention", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an Off-Drawer Level-3 cache with intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "174", "EventName": "L1I_ONDRAWER_L4_SOURCED_WRITES", "BriefDescription": "L1I On-Drawer L4 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from On-Drawer Level-4 cache" }, { + "Unit": "CPU-M-CF", "EventCode": "175", "EventName": "L1I_OFFDRAWER_L4_SOURCED_WRITES", "BriefDescription": "L1I Off-Drawer L4 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from Off-Drawer Level-4 cache" }, { + "Unit": "CPU-M-CF", "EventCode": "224", "EventName": "BCD_DFP_EXECUTION_SLOTS", "BriefDescription": "BCD DFP Execution Slots", "PublicDescription": "Count of floating point execution slots used for finished Binary Coded Decimal to Decimal Floating Point conversions. Instructions: CDZT, CXZT, CZDT, CZXT" }, { + "Unit": "CPU-M-CF", "EventCode": "225", "EventName": "VX_BCD_EXECUTION_SLOTS", "BriefDescription": "VX BCD Execution Slots", "PublicDescription": "Count of floating point execution slots used for finished vector arithmetic Binary Coded Decimal instructions. Instructions: VAP, VSP, VMPVMSP, VDP, VSDP, VRP, VLIP, VSRP, VPSOPVCP, VTP, VPKZ, VUPKZ, VCVB, VCVBG, VCVDVCVDG" }, { + "Unit": "CPU-M-CF", "EventCode": "226", "EventName": "DECIMAL_INSTRUCTIONS", "BriefDescription": "Decimal Instructions", "PublicDescription": "Decimal instructions dispatched. Instructions: CVB, CVD, AP, CP, DP, ED, EDMK, MP, SRP, SP, ZAP" }, { + "Unit": "CPU-M-CF", "EventCode": "232", "EventName": "LAST_HOST_TRANSLATIONS", "BriefDescription": "Last host translation done", "PublicDescription": "Last Host Translation done" }, { + "Unit": "CPU-M-CF", "EventCode": "243", "EventName": "TX_NC_TABORT", "BriefDescription": "Aborted transactions in non-constrained TX mode", "PublicDescription": "A transaction abort has occurred in a non-constrained transactional-execution mode" }, { + "Unit": "CPU-M-CF", "EventCode": "244", "EventName": "TX_C_TABORT_NO_SPECIAL", "BriefDescription": "Aborted transactions in constrained TX mode not using special completion logic", "PublicDescription": "A transaction abort has occurred in a constrained transactional-execution mode and the CPU is not using any special logic to allow the transaction to complete" }, { + "Unit": "CPU-M-CF", "EventCode": "245", "EventName": "TX_C_TABORT_SPECIAL", "BriefDescription": "Aborted transactions in constrained TX mode using special completion logic", "PublicDescription": "A transaction abort has occurred in a constrained transactional-execution mode and the CPU is using special logic to allow the transaction to complete" }, { + "Unit": "CPU-M-CF", "EventCode": "448", "EventName": "MT_DIAG_CYCLES_ONE_THR_ACTIVE", "BriefDescription": "Cycle count with one thread active", "PublicDescription": "Cycle count with one thread active" }, { + "Unit": "CPU-M-CF", "EventCode": "449", "EventName": "MT_DIAG_CYCLES_TWO_THR_ACTIVE", "BriefDescription": "Cycle count with two threads active", diff --git a/tools/perf/pmu-events/arch/s390/cf_z14/transaction.json b/tools/perf/pmu-events/arch/s390/cf_z14/transaction.json new file mode 100644 index 000000000000..1a0034f79f73 --- /dev/null +++ b/tools/perf/pmu-events/arch/s390/cf_z14/transaction.json @@ -0,0 +1,7 @@ +[ + { + "BriefDescription": "Transaction count", + "MetricName": "transaction", + "MetricExpr": "TX_C_TEND + TX_NC_TEND + TX_NC_TABORT + TX_C_TABORT_SPECIAL + TX_C_TABORT_NO_SPECIAL" + } +] diff --git a/tools/perf/pmu-events/arch/s390/cf_z196/basic.json b/tools/perf/pmu-events/arch/s390/cf_z196/basic.json index 8bf16759ca53..2dd8dafff2ef 100644 --- a/tools/perf/pmu-events/arch/s390/cf_z196/basic.json +++ b/tools/perf/pmu-events/arch/s390/cf_z196/basic.json @@ -1,71 +1,83 @@ [ { + "Unit": "CPU-M-CF", "EventCode": "0", "EventName": "CPU_CYCLES", "BriefDescription": "CPU Cycles", "PublicDescription": "Cycle Count" }, { + "Unit": "CPU-M-CF", "EventCode": "1", "EventName": "INSTRUCTIONS", "BriefDescription": "Instructions", "PublicDescription": "Instruction Count" }, { + "Unit": "CPU-M-CF", "EventCode": "2", "EventName": "L1I_DIR_WRITES", "BriefDescription": "L1I Directory Writes", "PublicDescription": "Level-1 I-Cache Directory Write Count" }, { + "Unit": "CPU-M-CF", "EventCode": "3", "EventName": "L1I_PENALTY_CYCLES", "BriefDescription": "L1I Penalty Cycles", "PublicDescription": "Level-1 I-Cache Penalty Cycle Count" }, { + "Unit": "CPU-M-CF", "EventCode": "4", "EventName": "L1D_DIR_WRITES", "BriefDescription": "L1D Directory Writes", "PublicDescription": "Level-1 D-Cache Directory Write Count" }, { + "Unit": "CPU-M-CF", "EventCode": "5", "EventName": "L1D_PENALTY_CYCLES", "BriefDescription": "L1D Penalty Cycles", "PublicDescription": "Level-1 D-Cache Penalty Cycle Count" }, { + "Unit": "CPU-M-CF", "EventCode": "32", "EventName": "PROBLEM_STATE_CPU_CYCLES", "BriefDescription": "Problem-State CPU Cycles", "PublicDescription": "Problem-State Cycle Count" }, { + "Unit": "CPU-M-CF", "EventCode": "33", "EventName": "PROBLEM_STATE_INSTRUCTIONS", "BriefDescription": "Problem-State Instructions", "PublicDescription": "Problem-State Instruction Count" }, { + "Unit": "CPU-M-CF", "EventCode": "34", "EventName": "PROBLEM_STATE_L1I_DIR_WRITES", "BriefDescription": "Problem-State L1I Directory Writes", "PublicDescription": "Problem-State Level-1 I-Cache Directory Write Count" }, { + "Unit": "CPU-M-CF", "EventCode": "35", "EventName": "PROBLEM_STATE_L1I_PENALTY_CYCLES", "BriefDescription": "Problem-State L1I Penalty Cycles", "PublicDescription": "Problem-State Level-1 I-Cache Penalty Cycle Count" }, { + "Unit": "CPU-M-CF", "EventCode": "36", "EventName": "PROBLEM_STATE_L1D_DIR_WRITES", "BriefDescription": "Problem-State L1D Directory Writes", "PublicDescription": "Problem-State Level-1 D-Cache Directory Write Count" }, { + "Unit": "CPU-M-CF", "EventCode": "37", "EventName": "PROBLEM_STATE_L1D_PENALTY_CYCLES", "BriefDescription": "Problem-State L1D Penalty Cycles", diff --git a/tools/perf/pmu-events/arch/s390/cf_z196/crypto.json b/tools/perf/pmu-events/arch/s390/cf_z196/crypto.json index 7e5b72492141..db286f19e7b6 100644 --- a/tools/perf/pmu-events/arch/s390/cf_z196/crypto.json +++ b/tools/perf/pmu-events/arch/s390/cf_z196/crypto.json @@ -1,95 +1,111 @@ [ { + "Unit": "CPU-M-CF", "EventCode": "64", "EventName": "PRNG_FUNCTIONS", "BriefDescription": "PRNG Functions", "PublicDescription": "Total number of the PRNG functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "65", "EventName": "PRNG_CYCLES", "BriefDescription": "PRNG Cycles", "PublicDescription": "Total number of CPU cycles when the DEA/AES coprocessor is busy performing PRNG functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "66", "EventName": "PRNG_BLOCKED_FUNCTIONS", "BriefDescription": "PRNG Blocked Functions", "PublicDescription": "Total number of the PRNG functions that are issued by the CPU and are blocked because the DEA/AES coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "67", "EventName": "PRNG_BLOCKED_CYCLES", "BriefDescription": "PRNG Blocked Cycles", "PublicDescription": "Total number of CPU cycles blocked for the PRNG functions issued by the CPU because the DEA/AES coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "68", "EventName": "SHA_FUNCTIONS", "BriefDescription": "SHA Functions", "PublicDescription": "Total number of SHA functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "69", "EventName": "SHA_CYCLES", "BriefDescription": "SHA Cycles", "PublicDescription": "Total number of CPU cycles when the SHA coprocessor is busy performing the SHA functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "70", "EventName": "SHA_BLOCKED_FUNCTIONS", "BriefDescription": "SHA Blocked Functions", "PublicDescription": "Total number of the SHA functions that are issued by the CPU and are blocked because the SHA coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "71", "EventName": "SHA_BLOCKED_CYCLES", "BriefDescription": "SHA Bloced Cycles", "PublicDescription": "Total number of CPU cycles blocked for the SHA functions issued by the CPU because the SHA coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "72", "EventName": "DEA_FUNCTIONS", "BriefDescription": "DEA Functions", "PublicDescription": "Total number of the DEA functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "73", "EventName": "DEA_CYCLES", "BriefDescription": "DEA Cycles", "PublicDescription": "Total number of CPU cycles when the DEA/AES coprocessor is busy performing the DEA functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "74", "EventName": "DEA_BLOCKED_FUNCTIONS", "BriefDescription": "DEA Blocked Functions", "PublicDescription": "Total number of the DEA functions that are issued by the CPU and are blocked because the DEA/AES coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "75", "EventName": "DEA_BLOCKED_CYCLES", "BriefDescription": "DEA Blocked Cycles", "PublicDescription": "Total number of CPU cycles blocked for the DEA functions issued by the CPU because the DEA/AES coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "76", "EventName": "AES_FUNCTIONS", "BriefDescription": "AES Functions", "PublicDescription": "Total number of AES functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "77", "EventName": "AES_CYCLES", "BriefDescription": "AES Cycles", "PublicDescription": "Total number of CPU cycles when the DEA/AES coprocessor is busy performing the AES functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "78", "EventName": "AES_BLOCKED_FUNCTIONS", "BriefDescription": "AES Blocked Functions", "PublicDescription": "Total number of AES functions that are issued by the CPU and are blocked because the DEA/AES coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "79", "EventName": "AES_BLOCKED_CYCLES", "BriefDescription": "AES Blocked Cycles", diff --git a/tools/perf/pmu-events/arch/s390/cf_z196/extended.json b/tools/perf/pmu-events/arch/s390/cf_z196/extended.json index b6d7fec7c2e7..b7b42a870bb0 100644 --- a/tools/perf/pmu-events/arch/s390/cf_z196/extended.json +++ b/tools/perf/pmu-events/arch/s390/cf_z196/extended.json @@ -1,143 +1,167 @@ [ { + "Unit": "CPU-M-CF", "EventCode": "128", "EventName": "L1D_L2_SOURCED_WRITES", "BriefDescription": "L1D L2 Sourced Writes", "PublicDescription": "A directory write to the Level-1 D-Cache directory where the returned cache line was sourced from the Level-2 cache" }, { + "Unit": "CPU-M-CF", "EventCode": "129", "EventName": "L1I_L2_SOURCED_WRITES", "BriefDescription": "L1I L2 Sourced Writes", "PublicDescription": "A directory write to the Level-1 I-Cache directory where the returned cache line was sourced from the Level-2 cache" }, { + "Unit": "CPU-M-CF", "EventCode": "130", "EventName": "DTLB1_MISSES", "BriefDescription": "DTLB1 Misses", "PublicDescription": "Level-1 Data TLB miss in progress. Incremented by one for every cycle a DTLB1 miss is in progress." }, { + "Unit": "CPU-M-CF", "EventCode": "131", "EventName": "ITLB1_MISSES", "BriefDescription": "ITLB1 Misses", "PublicDescription": "Level-1 Instruction TLB miss in progress. Incremented by one for every cycle a ITLB1 miss is in progress." }, { + "Unit": "CPU-M-CF", "EventCode": "133", "EventName": "L2C_STORES_SENT", "BriefDescription": "L2C Stores Sent", "PublicDescription": "Incremented by one for every store sent to Level-2 cache" }, { + "Unit": "CPU-M-CF", "EventCode": "134", "EventName": "L1D_OFFBOOK_L3_SOURCED_WRITES", "BriefDescription": "L1D Off-Book L3 Sourced Writes", "PublicDescription": "A directory write to the Level-1 D-Cache directory where the returned cache line was sourced from an Off Book Level-3 cache" }, { + "Unit": "CPU-M-CF", "EventCode": "135", "EventName": "L1D_ONBOOK_L4_SOURCED_WRITES", "BriefDescription": "L1D On-Book L4 Sourced Writes", "PublicDescription": "A directory write to the Level-1 D-Cache directory where the returned cache line was sourced from an On Book Level-4 cache" }, { + "Unit": "CPU-M-CF", "EventCode": "136", "EventName": "L1I_ONBOOK_L4_SOURCED_WRITES", "BriefDescription": "L1I On-Book L4 Sourced Writes", "PublicDescription": "A directory write to the Level-1 I-Cache directory where the returned cache line was sourced from an On Book Level-4 cache" }, { + "Unit": "CPU-M-CF", "EventCode": "137", "EventName": "L1D_RO_EXCL_WRITES", "BriefDescription": "L1D Read-only Exclusive Writes", "PublicDescription": "A directory write to the Level-1 D-Cache where the line was originally in a Read-Only state in the cache but has been updated to be in the Exclusive state that allows stores to the cache line" }, { + "Unit": "CPU-M-CF", "EventCode": "138", "EventName": "L1D_OFFBOOK_L4_SOURCED_WRITES", "BriefDescription": "L1D Off-Book L4 Sourced Writes", "PublicDescription": "A directory write to the Level-1 D-Cache directory where the returned cache line was sourced from an Off Book Level-4 cache" }, { + "Unit": "CPU-M-CF", "EventCode": "139", "EventName": "L1I_OFFBOOK_L4_SOURCED_WRITES", "BriefDescription": "L1I Off-Book L4 Sourced Writes", "PublicDescription": "A directory write to the Level-1 I-Cache directory where the returned cache line was sourced from an Off Book Level-4 cache" }, { + "Unit": "CPU-M-CF", "EventCode": "140", "EventName": "DTLB1_HPAGE_WRITES", "BriefDescription": "DTLB1 One-Megabyte Page Writes", "PublicDescription": "A translation entry has been written to the Level-1 Data Translation Lookaside Buffer for a one-megabyte page" }, { + "Unit": "CPU-M-CF", "EventCode": "141", "EventName": "L1D_LMEM_SOURCED_WRITES", "BriefDescription": "L1D Local Memory Sourced Writes", "PublicDescription": "A directory write to the Level-1 D-Cache where the installed cache line was sourced from memory that is attached to the same book as the Data cache (Local Memory)" }, { + "Unit": "CPU-M-CF", "EventCode": "142", "EventName": "L1I_LMEM_SOURCED_WRITES", "BriefDescription": "L1I Local Memory Sourced Writes", "PublicDescription": "A directory write to the Level-1 I-Cache where the installed cache line was sourced from memory that is attached to the same book as the Instruction cache (Local Memory)" }, { + "Unit": "CPU-M-CF", "EventCode": "143", "EventName": "L1I_OFFBOOK_L3_SOURCED_WRITES", "BriefDescription": "L1I Off-Book L3 Sourced Writes", "PublicDescription": "A directory write to the Level-1 I-Cache directory where the returned cache line was sourced from an Off Book Level-3 cache" }, { + "Unit": "CPU-M-CF", "EventCode": "144", "EventName": "DTLB1_WRITES", "BriefDescription": "DTLB1 Writes", "PublicDescription": "A translation entry has been written to the Level-1 Data Translation Lookaside Buffer" }, { + "Unit": "CPU-M-CF", "EventCode": "145", "EventName": "ITLB1_WRITES", "BriefDescription": "ITLB1 Writes", "PublicDescription": "A translation entry has been written to the Level-1 Instruction Translation Lookaside Buffer" }, { + "Unit": "CPU-M-CF", "EventCode": "146", "EventName": "TLB2_PTE_WRITES", "BriefDescription": "TLB2 PTE Writes", "PublicDescription": "A translation entry has been written to the Level-2 TLB Page Table Entry arrays" }, { + "Unit": "CPU-M-CF", "EventCode": "147", "EventName": "TLB2_CRSTE_HPAGE_WRITES", "BriefDescription": "TLB2 CRSTE One-Megabyte Page Writes", "PublicDescription": "A translation entry has been written to the Level-2 TLB Common Region Segment Table Entry arrays for a one-megabyte large page translation" }, { + "Unit": "CPU-M-CF", "EventCode": "148", "EventName": "TLB2_CRSTE_WRITES", "BriefDescription": "TLB2 CRSTE Writes", "PublicDescription": "A translation entry has been written to the Level-2 TLB Common Region Segment Table Entry arrays" }, { + "Unit": "CPU-M-CF", "EventCode": "150", "EventName": "L1D_ONCHIP_L3_SOURCED_WRITES", "BriefDescription": "L1D On-Chip L3 Sourced Writes", "PublicDescription": "A directory write to the Level-1 D-Cache directory where the returned cache line was sourced from an On Chip Level-3 cache" }, { + "Unit": "CPU-M-CF", "EventCode": "152", "EventName": "L1D_OFFCHIP_L3_SOURCED_WRITES", "BriefDescription": "L1D Off-Chip L3 Sourced Writes", "PublicDescription": "A directory write to the Level-1 D-Cache directory where the returned cache line was sourced from an Off Chip/On Book Level-3 cache" }, { + "Unit": "CPU-M-CF", "EventCode": "153", "EventName": "L1I_ONCHIP_L3_SOURCED_WRITES", "BriefDescription": "L1I On-Chip L3 Sourced Writes", "PublicDescription": "A directory write to the Level-1 I-Cache directory where the returned cache line was sourced from an On Chip Level-3 cache" }, { + "Unit": "CPU-M-CF", "EventCode": "155", "EventName": "L1I_OFFCHIP_L3_SOURCED_WRITES", "BriefDescription": "L1I Off-Chip L3 Sourced Writes", diff --git a/tools/perf/pmu-events/arch/s390/cf_zec12/basic.json b/tools/perf/pmu-events/arch/s390/cf_zec12/basic.json index 8bf16759ca53..2dd8dafff2ef 100644 --- a/tools/perf/pmu-events/arch/s390/cf_zec12/basic.json +++ b/tools/perf/pmu-events/arch/s390/cf_zec12/basic.json @@ -1,71 +1,83 @@ [ { + "Unit": "CPU-M-CF", "EventCode": "0", "EventName": "CPU_CYCLES", "BriefDescription": "CPU Cycles", "PublicDescription": "Cycle Count" }, { + "Unit": "CPU-M-CF", "EventCode": "1", "EventName": "INSTRUCTIONS", "BriefDescription": "Instructions", "PublicDescription": "Instruction Count" }, { + "Unit": "CPU-M-CF", "EventCode": "2", "EventName": "L1I_DIR_WRITES", "BriefDescription": "L1I Directory Writes", "PublicDescription": "Level-1 I-Cache Directory Write Count" }, { + "Unit": "CPU-M-CF", "EventCode": "3", "EventName": "L1I_PENALTY_CYCLES", "BriefDescription": "L1I Penalty Cycles", "PublicDescription": "Level-1 I-Cache Penalty Cycle Count" }, { + "Unit": "CPU-M-CF", "EventCode": "4", "EventName": "L1D_DIR_WRITES", "BriefDescription": "L1D Directory Writes", "PublicDescription": "Level-1 D-Cache Directory Write Count" }, { + "Unit": "CPU-M-CF", "EventCode": "5", "EventName": "L1D_PENALTY_CYCLES", "BriefDescription": "L1D Penalty Cycles", "PublicDescription": "Level-1 D-Cache Penalty Cycle Count" }, { + "Unit": "CPU-M-CF", "EventCode": "32", "EventName": "PROBLEM_STATE_CPU_CYCLES", "BriefDescription": "Problem-State CPU Cycles", "PublicDescription": "Problem-State Cycle Count" }, { + "Unit": "CPU-M-CF", "EventCode": "33", "EventName": "PROBLEM_STATE_INSTRUCTIONS", "BriefDescription": "Problem-State Instructions", "PublicDescription": "Problem-State Instruction Count" }, { + "Unit": "CPU-M-CF", "EventCode": "34", "EventName": "PROBLEM_STATE_L1I_DIR_WRITES", "BriefDescription": "Problem-State L1I Directory Writes", "PublicDescription": "Problem-State Level-1 I-Cache Directory Write Count" }, { + "Unit": "CPU-M-CF", "EventCode": "35", "EventName": "PROBLEM_STATE_L1I_PENALTY_CYCLES", "BriefDescription": "Problem-State L1I Penalty Cycles", "PublicDescription": "Problem-State Level-1 I-Cache Penalty Cycle Count" }, { + "Unit": "CPU-M-CF", "EventCode": "36", "EventName": "PROBLEM_STATE_L1D_DIR_WRITES", "BriefDescription": "Problem-State L1D Directory Writes", "PublicDescription": "Problem-State Level-1 D-Cache Directory Write Count" }, { + "Unit": "CPU-M-CF", "EventCode": "37", "EventName": "PROBLEM_STATE_L1D_PENALTY_CYCLES", "BriefDescription": "Problem-State L1D Penalty Cycles", diff --git a/tools/perf/pmu-events/arch/s390/cf_zec12/crypto.json b/tools/perf/pmu-events/arch/s390/cf_zec12/crypto.json index 7e5b72492141..db286f19e7b6 100644 --- a/tools/perf/pmu-events/arch/s390/cf_zec12/crypto.json +++ b/tools/perf/pmu-events/arch/s390/cf_zec12/crypto.json @@ -1,95 +1,111 @@ [ { + "Unit": "CPU-M-CF", "EventCode": "64", "EventName": "PRNG_FUNCTIONS", "BriefDescription": "PRNG Functions", "PublicDescription": "Total number of the PRNG functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "65", "EventName": "PRNG_CYCLES", "BriefDescription": "PRNG Cycles", "PublicDescription": "Total number of CPU cycles when the DEA/AES coprocessor is busy performing PRNG functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "66", "EventName": "PRNG_BLOCKED_FUNCTIONS", "BriefDescription": "PRNG Blocked Functions", "PublicDescription": "Total number of the PRNG functions that are issued by the CPU and are blocked because the DEA/AES coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "67", "EventName": "PRNG_BLOCKED_CYCLES", "BriefDescription": "PRNG Blocked Cycles", "PublicDescription": "Total number of CPU cycles blocked for the PRNG functions issued by the CPU because the DEA/AES coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "68", "EventName": "SHA_FUNCTIONS", "BriefDescription": "SHA Functions", "PublicDescription": "Total number of SHA functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "69", "EventName": "SHA_CYCLES", "BriefDescription": "SHA Cycles", "PublicDescription": "Total number of CPU cycles when the SHA coprocessor is busy performing the SHA functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "70", "EventName": "SHA_BLOCKED_FUNCTIONS", "BriefDescription": "SHA Blocked Functions", "PublicDescription": "Total number of the SHA functions that are issued by the CPU and are blocked because the SHA coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "71", "EventName": "SHA_BLOCKED_CYCLES", "BriefDescription": "SHA Bloced Cycles", "PublicDescription": "Total number of CPU cycles blocked for the SHA functions issued by the CPU because the SHA coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "72", "EventName": "DEA_FUNCTIONS", "BriefDescription": "DEA Functions", "PublicDescription": "Total number of the DEA functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "73", "EventName": "DEA_CYCLES", "BriefDescription": "DEA Cycles", "PublicDescription": "Total number of CPU cycles when the DEA/AES coprocessor is busy performing the DEA functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "74", "EventName": "DEA_BLOCKED_FUNCTIONS", "BriefDescription": "DEA Blocked Functions", "PublicDescription": "Total number of the DEA functions that are issued by the CPU and are blocked because the DEA/AES coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "75", "EventName": "DEA_BLOCKED_CYCLES", "BriefDescription": "DEA Blocked Cycles", "PublicDescription": "Total number of CPU cycles blocked for the DEA functions issued by the CPU because the DEA/AES coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "76", "EventName": "AES_FUNCTIONS", "BriefDescription": "AES Functions", "PublicDescription": "Total number of AES functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "77", "EventName": "AES_CYCLES", "BriefDescription": "AES Cycles", "PublicDescription": "Total number of CPU cycles when the DEA/AES coprocessor is busy performing the AES functions issued by the CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "78", "EventName": "AES_BLOCKED_FUNCTIONS", "BriefDescription": "AES Blocked Functions", "PublicDescription": "Total number of AES functions that are issued by the CPU and are blocked because the DEA/AES coprocessor is busy performing a function issued by another CPU" }, { + "Unit": "CPU-M-CF", "EventCode": "79", "EventName": "AES_BLOCKED_CYCLES", "BriefDescription": "AES Blocked Cycles", diff --git a/tools/perf/pmu-events/arch/s390/cf_zec12/extended.json b/tools/perf/pmu-events/arch/s390/cf_zec12/extended.json index 8682126aabb2..162251037219 100644 --- a/tools/perf/pmu-events/arch/s390/cf_zec12/extended.json +++ b/tools/perf/pmu-events/arch/s390/cf_zec12/extended.json @@ -1,209 +1,244 @@ [ { + "Unit": "CPU-M-CF", "EventCode": "128", "EventName": "DTLB1_MISSES", "BriefDescription": "DTLB1 Misses", "PublicDescription": "Level-1 Data TLB miss in progress. Incremented by one for every cycle a DTLB1 miss is in progress." }, { + "Unit": "CPU-M-CF", "EventCode": "129", "EventName": "ITLB1_MISSES", "BriefDescription": "ITLB1 Misses", "PublicDescription": "Level-1 Instruction TLB miss in progress. Incremented by one for every cycle a ITLB1 miss is in progress." }, { + "Unit": "CPU-M-CF", "EventCode": "130", "EventName": "L1D_L2I_SOURCED_WRITES", "BriefDescription": "L1D L2I Sourced Writes", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from the Level-2 Instruction cache" }, { + "Unit": "CPU-M-CF", "EventCode": "131", "EventName": "L1I_L2I_SOURCED_WRITES", "BriefDescription": "L1I L2I Sourced Writes", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from the Level-2 Instruction cache" }, { + "Unit": "CPU-M-CF", "EventCode": "132", "EventName": "L1D_L2D_SOURCED_WRITES", "BriefDescription": "L1D L2D Sourced Writes", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from the Level-2 Data cache" }, { + "Unit": "CPU-M-CF", "EventCode": "133", "EventName": "DTLB1_WRITES", "BriefDescription": "DTLB1 Writes", "PublicDescription": "A translation entry has been written to the Level-1 Data Translation Lookaside Buffer" }, { + "Unit": "CPU-M-CF", "EventCode": "135", "EventName": "L1D_LMEM_SOURCED_WRITES", "BriefDescription": "L1D Local Memory Sourced Writes", "PublicDescription": "A directory write to the Level-1 Data cache where the installed cache line was sourced from memory that is attached to the same book as the Data cache (Local Memory)" }, { + "Unit": "CPU-M-CF", "EventCode": "137", "EventName": "L1I_LMEM_SOURCED_WRITES", "BriefDescription": "L1I Local Memory Sourced Writes", "PublicDescription": "A directory write to the Level-1 Instruction cache where the installed cache line was sourced from memory that is attached to the same book as the Instruction cache (Local Memory)" }, { + "Unit": "CPU-M-CF", "EventCode": "138", "EventName": "L1D_RO_EXCL_WRITES", "BriefDescription": "L1D Read-only Exclusive Writes", "PublicDescription": "A directory write to the Level-1 D-Cache where the line was originally in a Read-Only state in the cache but has been updated to be in the Exclusive state that allows stores to the cache line" }, { + "Unit": "CPU-M-CF", "EventCode": "139", "EventName": "DTLB1_HPAGE_WRITES", "BriefDescription": "DTLB1 One-Megabyte Page Writes", "PublicDescription": "A translation entry has been written to the Level-1 Data Translation Lookaside Buffer for a one-megabyte page" }, { + "Unit": "CPU-M-CF", "EventCode": "140", "EventName": "ITLB1_WRITES", "BriefDescription": "ITLB1 Writes", "PublicDescription": "A translation entry has been written to the Level-1 Instruction Translation Lookaside Buffer" }, { + "Unit": "CPU-M-CF", "EventCode": "141", "EventName": "TLB2_PTE_WRITES", "BriefDescription": "TLB2 PTE Writes", "PublicDescription": "A translation entry has been written to the Level-2 TLB Page Table Entry arrays" }, { + "Unit": "CPU-M-CF", "EventCode": "142", "EventName": "TLB2_CRSTE_HPAGE_WRITES", "BriefDescription": "TLB2 CRSTE One-Megabyte Page Writes", "PublicDescription": "A translation entry has been written to the Level-2 TLB Common Region Segment Table Entry arrays for a one-megabyte large page translation" }, { + "Unit": "CPU-M-CF", "EventCode": "143", "EventName": "TLB2_CRSTE_WRITES", "BriefDescription": "TLB2 CRSTE Writes", "PublicDescription": "A translation entry has been written to the Level-2 TLB Common Region Segment Table Entry arrays" }, { + "Unit": "CPU-M-CF", "EventCode": "144", "EventName": "L1D_ONCHIP_L3_SOURCED_WRITES", "BriefDescription": "L1D On-Chip L3 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an On Chip Level-3 cache without intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "145", "EventName": "L1D_OFFCHIP_L3_SOURCED_WRITES", "BriefDescription": "L1D Off-Chip L3 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an Off Chip/On Book Level-3 cache without intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "146", "EventName": "L1D_OFFBOOK_L3_SOURCED_WRITES", "BriefDescription": "L1D Off-Book L3 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an Off Book Level-3 cache without intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "147", "EventName": "L1D_ONBOOK_L4_SOURCED_WRITES", "BriefDescription": "L1D On-Book L4 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an On Book Level-4 cache" }, { + "Unit": "CPU-M-CF", "EventCode": "148", "EventName": "L1D_OFFBOOK_L4_SOURCED_WRITES", "BriefDescription": "L1D Off-Book L4 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an Off Book Level-4 cache" }, { + "Unit": "CPU-M-CF", "EventCode": "149", "EventName": "TX_NC_TEND", "BriefDescription": "Completed TEND instructions in non-constrained TX mode", "PublicDescription": "A TEND instruction has completed in a nonconstrained transactional-execution mode" }, { + "Unit": "CPU-M-CF", "EventCode": "150", "EventName": "L1D_ONCHIP_L3_SOURCED_WRITES_IV", "BriefDescription": "L1D On-Chip L3 Sourced Writes with Intervention", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from a On Chip Level-3 cache with intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "151", "EventName": "L1D_OFFCHIP_L3_SOURCED_WRITES_IV", "BriefDescription": "L1D Off-Chip L3 Sourced Writes with Intervention", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an Off Chip/On Book Level-3 cache with intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "152", "EventName": "L1D_OFFBOOK_L3_SOURCED_WRITES_IV", "BriefDescription": "L1D Off-Book L3 Sourced Writes with Intervention", "PublicDescription": "A directory write to the Level-1 Data cache directory where the returned cache line was sourced from an Off Book Level-3 cache with intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "153", "EventName": "L1I_ONCHIP_L3_SOURCED_WRITES", "BriefDescription": "L1I On-Chip L3 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an On Chip Level-3 cache without intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "154", "EventName": "L1I_OFFCHIP_L3_SOURCED_WRITES", "BriefDescription": "L1I Off-Chip L3 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an Off Chip/On Book Level-3 cache without intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "155", "EventName": "L1I_OFFBOOK_L3_SOURCED_WRITES", "BriefDescription": "L1I Off-Book L3 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an Off Book Level-3 cache without intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "156", "EventName": "L1I_ONBOOK_L4_SOURCED_WRITES", "BriefDescription": "L1I On-Book L4 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an On Book Level-4 cache" }, { + "Unit": "CPU-M-CF", "EventCode": "157", "EventName": "L1I_OFFBOOK_L4_SOURCED_WRITES", "BriefDescription": "L1I Off-Book L4 Sourced Writes", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an Off Book Level-4 cache" }, { + "Unit": "CPU-M-CF", "EventCode": "158", "EventName": "TX_C_TEND", "BriefDescription": "Completed TEND instructions in constrained TX mode", "PublicDescription": "A TEND instruction has completed in a constrained transactional-execution mode" }, { + "Unit": "CPU-M-CF", "EventCode": "159", "EventName": "L1I_ONCHIP_L3_SOURCED_WRITES_IV", "BriefDescription": "L1I On-Chip L3 Sourced Writes with Intervention", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an On Chip Level-3 cache with intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "160", "EventName": "L1I_OFFCHIP_L3_SOURCED_WRITES_IV", "BriefDescription": "L1I Off-Chip L3 Sourced Writes with Intervention", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an Off Chip/On Book Level-3 cache with intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "161", "EventName": "L1I_OFFBOOK_L3_SOURCED_WRITES_IV", "BriefDescription": "L1I Off-Book L3 Sourced Writes with Intervention", "PublicDescription": "A directory write to the Level-1 Instruction cache directory where the returned cache line was sourced from an Off Book Level-3 cache with intervention" }, { + "Unit": "CPU-M-CF", "EventCode": "177", "EventName": "TX_NC_TABORT", "BriefDescription": "Aborted transactions in non-constrained TX mode", "PublicDescription": "A transaction abort has occurred in a nonconstrained transactional-execution mode" }, { + "Unit": "CPU-M-CF", "EventCode": "178", "EventName": "TX_C_TABORT_NO_SPECIAL", "BriefDescription": "Aborted transactions in constrained TX mode not using special completion logic", "PublicDescription": "A transaction abort has occurred in a constrained transactional-execution mode and the CPU is not using any special logic to allow the transaction to complete" }, { + "Unit": "CPU-M-CF", "EventCode": "179", "EventName": "TX_C_TABORT_SPECIAL", "BriefDescription": "Aborted transactions in constrained TX mode using special completion logic", diff --git a/tools/perf/pmu-events/arch/s390/cf_zec12/transaction.json b/tools/perf/pmu-events/arch/s390/cf_zec12/transaction.json new file mode 100644 index 000000000000..1a0034f79f73 --- /dev/null +++ b/tools/perf/pmu-events/arch/s390/cf_zec12/transaction.json @@ -0,0 +1,7 @@ +[ + { + "BriefDescription": "Transaction count", + "MetricName": "transaction", + "MetricExpr": "TX_C_TEND + TX_NC_TEND + TX_NC_TABORT + TX_C_TABORT_SPECIAL + TX_C_TABORT_NO_SPECIAL" + } +] diff --git a/tools/perf/pmu-events/jevents.c b/tools/perf/pmu-events/jevents.c index db3a594ee1e4..68c92bb599ee 100644 --- a/tools/perf/pmu-events/jevents.c +++ b/tools/perf/pmu-events/jevents.c @@ -233,6 +233,8 @@ static struct map { { "QPI LL", "uncore_qpi" }, { "SBO", "uncore_sbox" }, { "iMPH-U", "uncore_arb" }, + { "CPU-M-CF", "cpum_cf" }, + { "CPU-M-SF", "cpum_sf" }, {} }; diff --git a/tools/perf/tests/bitmap.c b/tools/perf/tests/bitmap.c index 47bedf25ba69..96e7fc1ad3f9 100644 --- a/tools/perf/tests/bitmap.c +++ b/tools/perf/tests/bitmap.c @@ -16,8 +16,6 @@ static unsigned long *get_bitmap(const char *str, int nbits) bm = bitmap_alloc(nbits); if (map && bm) { - bitmap_zero(bm, nbits); - for (i = 0; i < map->nr; i++) set_bit(map->map[i], bm); } diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index dd850a26d579..d7a5e1b9aa6f 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -385,7 +385,7 @@ static int test_and_print(struct test *t, bool force_skip, int subtest) if (!t->subtest.get_nr) pr_debug("%s:", t->desc); else - pr_debug("%s subtest %d:", t->desc, subtest); + pr_debug("%s subtest %d:", t->desc, subtest + 1); switch (err) { case TEST_OK: diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index 4892bd2dc33e..6b049f3f5cf4 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c @@ -232,6 +232,7 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, u64 objdump_addr; const char *objdump_name; char decomp_name[KMOD_DECOMP_LEN]; + bool decomp = false; int ret; pr_debug("Reading object code for memory address: %#"PRIx64"\n", addr); @@ -305,6 +306,7 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, return -1; } + decomp = true; objdump_name = decomp_name; } @@ -312,7 +314,7 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, objdump_addr = map__rip_2objdump(al.map, al.addr); ret = read_via_objdump(objdump_name, objdump_addr, buf2, len); - if (dso__needs_decompress(al.map->dso)) + if (decomp) unlink(objdump_name); if (ret > 0) { diff --git a/tools/perf/tests/kmod-path.c b/tools/perf/tests/kmod-path.c index 148dd31cc201..0579a70bbbff 100644 --- a/tools/perf/tests/kmod-path.c +++ b/tools/perf/tests/kmod-path.c @@ -5,34 +5,28 @@ #include "dso.h" #include "debug.h" -static int test(const char *path, bool alloc_name, bool alloc_ext, - bool kmod, bool comp, const char *name, const char *ext) +static int test(const char *path, bool alloc_name, bool kmod, + int comp, const char *name) { struct kmod_path m; memset(&m, 0x0, sizeof(m)); TEST_ASSERT_VAL("kmod_path__parse", - !__kmod_path__parse(&m, path, alloc_name, alloc_ext)); + !__kmod_path__parse(&m, path, alloc_name)); - pr_debug("%s - alloc name %d, alloc ext %d, kmod %d, comp %d, name '%s', ext '%s'\n", - path, alloc_name, alloc_ext, m.kmod, m.comp, m.name, m.ext); + pr_debug("%s - alloc name %d, kmod %d, comp %d, name '%s'\n", + path, alloc_name, m.kmod, m.comp, m.name); TEST_ASSERT_VAL("wrong kmod", m.kmod == kmod); TEST_ASSERT_VAL("wrong comp", m.comp == comp); - if (ext) - TEST_ASSERT_VAL("wrong ext", m.ext && !strcmp(ext, m.ext)); - else - TEST_ASSERT_VAL("wrong ext", !m.ext); - if (name) TEST_ASSERT_VAL("wrong name", m.name && !strcmp(name, m.name)); else TEST_ASSERT_VAL("wrong name", !m.name); free(m.name); - free(m.ext); return 0; } @@ -45,118 +39,118 @@ static int test_is_kernel_module(const char *path, int cpumode, bool expect) return 0; } -#define T(path, an, ae, k, c, n, e) \ - TEST_ASSERT_VAL("failed", !test(path, an, ae, k, c, n, e)) +#define T(path, an, k, c, n) \ + TEST_ASSERT_VAL("failed", !test(path, an, k, c, n)) #define M(path, c, e) \ TEST_ASSERT_VAL("failed", !test_is_kernel_module(path, c, e)) int test__kmod_path__parse(struct test *t __maybe_unused, int subtest __maybe_unused) { - /* path alloc_name alloc_ext kmod comp name ext */ - T("/xxxx/xxxx/x-x.ko", true , true , true, false, "[x_x]", NULL); - T("/xxxx/xxxx/x-x.ko", false , true , true, false, NULL , NULL); - T("/xxxx/xxxx/x-x.ko", true , false , true, false, "[x_x]", NULL); - T("/xxxx/xxxx/x-x.ko", false , false , true, false, NULL , NULL); + /* path alloc_name kmod comp name */ + T("/xxxx/xxxx/x-x.ko", true , true, 0 , "[x_x]"); + T("/xxxx/xxxx/x-x.ko", false , true, 0 , NULL ); + T("/xxxx/xxxx/x-x.ko", true , true, 0 , "[x_x]"); + T("/xxxx/xxxx/x-x.ko", false , true, 0 , NULL ); M("/xxxx/xxxx/x-x.ko", PERF_RECORD_MISC_CPUMODE_UNKNOWN, true); M("/xxxx/xxxx/x-x.ko", PERF_RECORD_MISC_KERNEL, true); M("/xxxx/xxxx/x-x.ko", PERF_RECORD_MISC_USER, false); #ifdef HAVE_ZLIB_SUPPORT - /* path alloc_name alloc_ext kmod comp name ext */ - T("/xxxx/xxxx/x.ko.gz", true , true , true, true, "[x]", "gz"); - T("/xxxx/xxxx/x.ko.gz", false , true , true, true, NULL , "gz"); - T("/xxxx/xxxx/x.ko.gz", true , false , true, true, "[x]", NULL); - T("/xxxx/xxxx/x.ko.gz", false , false , true, true, NULL , NULL); + /* path alloc_name kmod comp name */ + T("/xxxx/xxxx/x.ko.gz", true , true, 1 , "[x]"); + T("/xxxx/xxxx/x.ko.gz", false , true, 1 , NULL ); + T("/xxxx/xxxx/x.ko.gz", true , true, 1 , "[x]"); + T("/xxxx/xxxx/x.ko.gz", false , true, 1 , NULL ); M("/xxxx/xxxx/x.ko.gz", PERF_RECORD_MISC_CPUMODE_UNKNOWN, true); M("/xxxx/xxxx/x.ko.gz", PERF_RECORD_MISC_KERNEL, true); M("/xxxx/xxxx/x.ko.gz", PERF_RECORD_MISC_USER, false); - /* path alloc_name alloc_ext kmod comp name ext */ - T("/xxxx/xxxx/x.gz", true , true , false, true, "x.gz" ,"gz"); - T("/xxxx/xxxx/x.gz", false , true , false, true, NULL ,"gz"); - T("/xxxx/xxxx/x.gz", true , false , false, true, "x.gz" , NULL); - T("/xxxx/xxxx/x.gz", false , false , false, true, NULL , NULL); + /* path alloc_name kmod comp name */ + T("/xxxx/xxxx/x.gz", true , false, 1 , "x.gz"); + T("/xxxx/xxxx/x.gz", false , false, 1 , NULL ); + T("/xxxx/xxxx/x.gz", true , false, 1 , "x.gz"); + T("/xxxx/xxxx/x.gz", false , false, 1 , NULL ); M("/xxxx/xxxx/x.gz", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false); M("/xxxx/xxxx/x.gz", PERF_RECORD_MISC_KERNEL, false); M("/xxxx/xxxx/x.gz", PERF_RECORD_MISC_USER, false); - /* path alloc_name alloc_ext kmod comp name ext */ - T("x.gz", true , true , false, true, "x.gz", "gz"); - T("x.gz", false , true , false, true, NULL , "gz"); - T("x.gz", true , false , false, true, "x.gz", NULL); - T("x.gz", false , false , false, true, NULL , NULL); + /* path alloc_name kmod comp name */ + T("x.gz", true , false, 1 , "x.gz"); + T("x.gz", false , false, 1 , NULL ); + T("x.gz", true , false, 1 , "x.gz"); + T("x.gz", false , false, 1 , NULL ); M("x.gz", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false); M("x.gz", PERF_RECORD_MISC_KERNEL, false); M("x.gz", PERF_RECORD_MISC_USER, false); - /* path alloc_name alloc_ext kmod comp name ext */ - T("x.ko.gz", true , true , true, true, "[x]", "gz"); - T("x.ko.gz", false , true , true, true, NULL , "gz"); - T("x.ko.gz", true , false , true, true, "[x]", NULL); - T("x.ko.gz", false , false , true, true, NULL , NULL); + /* path alloc_name kmod comp name */ + T("x.ko.gz", true , true, 1 , "[x]"); + T("x.ko.gz", false , true, 1 , NULL ); + T("x.ko.gz", true , true, 1 , "[x]"); + T("x.ko.gz", false , true, 1 , NULL ); M("x.ko.gz", PERF_RECORD_MISC_CPUMODE_UNKNOWN, true); M("x.ko.gz", PERF_RECORD_MISC_KERNEL, true); M("x.ko.gz", PERF_RECORD_MISC_USER, false); #endif - /* path alloc_name alloc_ext kmod comp name ext */ - T("[test_module]", true , true , true, false, "[test_module]", NULL); - T("[test_module]", false , true , true, false, NULL , NULL); - T("[test_module]", true , false , true, false, "[test_module]", NULL); - T("[test_module]", false , false , true, false, NULL , NULL); + /* path alloc_name kmod comp name */ + T("[test_module]", true , true, false, "[test_module]"); + T("[test_module]", false , true, false, NULL ); + T("[test_module]", true , true, false, "[test_module]"); + T("[test_module]", false , true, false, NULL ); M("[test_module]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, true); M("[test_module]", PERF_RECORD_MISC_KERNEL, true); M("[test_module]", PERF_RECORD_MISC_USER, false); - /* path alloc_name alloc_ext kmod comp name ext */ - T("[test.module]", true , true , true, false, "[test.module]", NULL); - T("[test.module]", false , true , true, false, NULL , NULL); - T("[test.module]", true , false , true, false, "[test.module]", NULL); - T("[test.module]", false , false , true, false, NULL , NULL); + /* path alloc_name kmod comp name */ + T("[test.module]", true , true, false, "[test.module]"); + T("[test.module]", false , true, false, NULL ); + T("[test.module]", true , true, false, "[test.module]"); + T("[test.module]", false , true, false, NULL ); M("[test.module]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, true); M("[test.module]", PERF_RECORD_MISC_KERNEL, true); M("[test.module]", PERF_RECORD_MISC_USER, false); - /* path alloc_name alloc_ext kmod comp name ext */ - T("[vdso]", true , true , false, false, "[vdso]", NULL); - T("[vdso]", false , true , false, false, NULL , NULL); - T("[vdso]", true , false , false, false, "[vdso]", NULL); - T("[vdso]", false , false , false, false, NULL , NULL); + /* path alloc_name kmod comp name */ + T("[vdso]", true , false, false, "[vdso]"); + T("[vdso]", false , false, false, NULL ); + T("[vdso]", true , false, false, "[vdso]"); + T("[vdso]", false , false, false, NULL ); M("[vdso]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false); M("[vdso]", PERF_RECORD_MISC_KERNEL, false); M("[vdso]", PERF_RECORD_MISC_USER, false); - T("[vdso32]", true , true , false, false, "[vdso32]", NULL); - T("[vdso32]", false , true , false, false, NULL , NULL); - T("[vdso32]", true , false , false, false, "[vdso32]", NULL); - T("[vdso32]", false , false , false, false, NULL , NULL); + T("[vdso32]", true , false, false, "[vdso32]"); + T("[vdso32]", false , false, false, NULL ); + T("[vdso32]", true , false, false, "[vdso32]"); + T("[vdso32]", false , false, false, NULL ); M("[vdso32]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false); M("[vdso32]", PERF_RECORD_MISC_KERNEL, false); M("[vdso32]", PERF_RECORD_MISC_USER, false); - T("[vdsox32]", true , true , false, false, "[vdsox32]", NULL); - T("[vdsox32]", false , true , false, false, NULL , NULL); - T("[vdsox32]", true , false , false, false, "[vdsox32]", NULL); - T("[vdsox32]", false , false , false, false, NULL , NULL); + T("[vdsox32]", true , false, false, "[vdsox32]"); + T("[vdsox32]", false , false, false, NULL ); + T("[vdsox32]", true , false, false, "[vdsox32]"); + T("[vdsox32]", false , false, false, NULL ); M("[vdsox32]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false); M("[vdsox32]", PERF_RECORD_MISC_KERNEL, false); M("[vdsox32]", PERF_RECORD_MISC_USER, false); - /* path alloc_name alloc_ext kmod comp name ext */ - T("[vsyscall]", true , true , false, false, "[vsyscall]", NULL); - T("[vsyscall]", false , true , false, false, NULL , NULL); - T("[vsyscall]", true , false , false, false, "[vsyscall]", NULL); - T("[vsyscall]", false , false , false, false, NULL , NULL); + /* path alloc_name kmod comp name */ + T("[vsyscall]", true , false, false, "[vsyscall]"); + T("[vsyscall]", false , false, false, NULL ); + T("[vsyscall]", true , false, false, "[vsyscall]"); + T("[vsyscall]", false , false, false, NULL ); M("[vsyscall]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false); M("[vsyscall]", PERF_RECORD_MISC_KERNEL, false); M("[vsyscall]", PERF_RECORD_MISC_USER, false); - /* path alloc_name alloc_ext kmod comp name ext */ - T("[kernel.kallsyms]", true , true , false, false, "[kernel.kallsyms]", NULL); - T("[kernel.kallsyms]", false , true , false, false, NULL , NULL); - T("[kernel.kallsyms]", true , false , false, false, "[kernel.kallsyms]", NULL); - T("[kernel.kallsyms]", false , false , false, false, NULL , NULL); + /* path alloc_name kmod comp name */ + T("[kernel.kallsyms]", true , false, false, "[kernel.kallsyms]"); + T("[kernel.kallsyms]", false , false, false, NULL ); + T("[kernel.kallsyms]", true , false, false, "[kernel.kallsyms]"); + T("[kernel.kallsyms]", false , false, false, NULL ); M("[kernel.kallsyms]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false); M("[kernel.kallsyms]", PERF_RECORD_MISC_KERNEL, false); M("[kernel.kallsyms]", PERF_RECORD_MISC_USER, false); diff --git a/tools/perf/tests/mem2node.c b/tools/perf/tests/mem2node.c index 0c3c87f86e03..9e9e4d37cc77 100644 --- a/tools/perf/tests/mem2node.c +++ b/tools/perf/tests/mem2node.c @@ -24,8 +24,6 @@ static unsigned long *get_bitmap(const char *str, int nbits) bm = bitmap_alloc(nbits); if (map && bm) { - bitmap_zero(bm, nbits); - for (i = 0; i < map->nr; i++) { set_bit(map->map[i], bm); } diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 61211918bfba..3b97ac018d5a 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -1322,6 +1322,14 @@ static int test__intel_pt(struct perf_evlist *evlist) return 0; } +static int test__checkevent_complex_name(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel = perf_evlist__first(evlist); + + TEST_ASSERT_VAL("wrong complex name parsing", strcmp(evsel->name, "COMPLEX_CYCLES_NAME:orig=cycles,desc=chip-clock-ticks") == 0); + return 0; +} + static int count_tracepoints(void) { struct dirent *events_ent; @@ -1658,6 +1666,11 @@ static struct evlist_test test__events[] = { .check = test__intel_pt, .id = 52, }, + { + .name = "cycles/name='COMPLEX_CYCLES_NAME:orig=cycles,desc=chip-clock-ticks'/Duk", + .check = test__checkevent_complex_name, + .id = 53 + } }; static struct evlist_test test__events_pmu[] = { @@ -1676,6 +1689,11 @@ static struct evlist_test test__events_pmu[] = { .check = test__checkevent_pmu_partial_time_callgraph, .id = 2, }, + { + .name = "cpu/name='COMPLEX_CYCLES_NAME:orig=cycles,desc=chip-clock-ticks',period=0x1,event=0x2/ukp", + .check = test__checkevent_complex_name, + .id = 3, + } }; struct terms_test { diff --git a/tools/perf/tests/shell/record+probe_libc_inet_pton.sh b/tools/perf/tests/shell/record+probe_libc_inet_pton.sh index 94e513e62b34..3013ac8f83d0 100755 --- a/tools/perf/tests/shell/record+probe_libc_inet_pton.sh +++ b/tools/perf/tests/shell/record+probe_libc_inet_pton.sh @@ -13,11 +13,24 @@ libc=$(grep -w libc /proc/self/maps | head -1 | sed -r 's/.*[[:space:]](\/.*)/\1/g') nm -Dg $libc 2>/dev/null | fgrep -q inet_pton || exit 254 +event_pattern='probe_libc:inet_pton(\_[[:digit:]]+)?' + +add_libc_inet_pton_event() { + + event_name=$(perf probe -f -x $libc -a inet_pton 2>&1 | tail -n +2 | head -n -5 | \ + grep -P -o "$event_pattern(?=[[:space:]]\(on inet_pton in $libc\))") + + if [ $? -ne 0 -o -z "$event_name" ] ; then + printf "FAIL: could not add event\n" + return 1 + fi +} + trace_libc_inet_pton_backtrace() { expected=`mktemp -u /tmp/expected.XXX` - echo "ping[][0-9 \.:]+probe_libc:inet_pton: \([[:xdigit:]]+\)" > $expected + echo "ping[][0-9 \.:]+$event_name: \([[:xdigit:]]+\)" > $expected echo ".*inet_pton\+0x[[:xdigit:]]+[[:space:]]\($libc|inlined\)$" >> $expected case "$(uname -m)" in s390x) @@ -26,6 +39,12 @@ trace_libc_inet_pton_backtrace() { echo "(__GI_)?getaddrinfo\+0x[[:xdigit:]]+[[:space:]]\($libc|inlined\)$" >> $expected echo "main\+0x[[:xdigit:]]+[[:space:]]\(.*/bin/ping.*\)$" >> $expected ;; + ppc64|ppc64le) + eventattr='max-stack=4' + echo "gaih_inet.*\+0x[[:xdigit:]]+[[:space:]]\($libc\)$" >> $expected + echo "getaddrinfo\+0x[[:xdigit:]]+[[:space:]]\($libc\)$" >> $expected + echo ".*\+0x[[:xdigit:]]+[[:space:]]\(.*/bin/ping.*\)$" >> $expected + ;; *) eventattr='max-stack=3' echo "getaddrinfo\+0x[[:xdigit:]]+[[:space:]]\($libc\)$" >> $expected @@ -35,7 +54,7 @@ trace_libc_inet_pton_backtrace() { perf_data=`mktemp -u /tmp/perf.data.XXX` perf_script=`mktemp -u /tmp/perf.script.XXX` - perf record -e probe_libc:inet_pton/$eventattr/ -o $perf_data ping -6 -c 1 ::1 > /dev/null 2>&1 + perf record -e $event_name/$eventattr/ -o $perf_data ping -6 -c 1 ::1 > /dev/null 2>&1 perf script -i $perf_data > $perf_script exec 3<$perf_script @@ -46,7 +65,7 @@ trace_libc_inet_pton_backtrace() { echo "$line" | egrep -q "$pattern" if [ $? -ne 0 ] ; then printf "FAIL: expected backtrace entry \"%s\" got \"%s\"\n" "$pattern" "$line" - exit 1 + return 1 fi done @@ -56,13 +75,20 @@ trace_libc_inet_pton_backtrace() { # even if the perf script output does not match. } +delete_libc_inet_pton_event() { + + if [ -n "$event_name" ] ; then + perf probe -q -d $event_name + fi +} + # Check for IPv6 interface existence ip a sh lo | fgrep -q inet6 || exit 2 skip_if_no_perf_probe && \ -perf probe -q $libc inet_pton && \ +add_libc_inet_pton_event && \ trace_libc_inet_pton_backtrace err=$? rm -f ${perf_data} ${perf_script} ${expected} -perf probe -q -d probe_libc:inet_pton +delete_libc_inet_pton_event exit $err diff --git a/tools/perf/trace/beauty/Build b/tools/perf/trace/beauty/Build index 66330d4b739b..f528ba35e140 100644 --- a/tools/perf/trace/beauty/Build +++ b/tools/perf/trace/beauty/Build @@ -7,4 +7,5 @@ endif libperf-y += kcmp.o libperf-y += pkey_alloc.o libperf-y += prctl.o +libperf-y += socket.o libperf-y += statx.o diff --git a/tools/perf/trace/beauty/beauty.h b/tools/perf/trace/beauty/beauty.h index 984a504d335c..9615af5d412b 100644 --- a/tools/perf/trace/beauty/beauty.h +++ b/tools/perf/trace/beauty/beauty.h @@ -106,6 +106,9 @@ size_t syscall_arg__scnprintf_prctl_arg2(char *bf, size_t size, struct syscall_a size_t syscall_arg__scnprintf_prctl_arg3(char *bf, size_t size, struct syscall_arg *arg); #define SCA_PRCTL_ARG3 syscall_arg__scnprintf_prctl_arg3 +size_t syscall_arg__scnprintf_socket_protocol(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_SK_PROTO syscall_arg__scnprintf_socket_protocol + size_t syscall_arg__scnprintf_statx_flags(char *bf, size_t size, struct syscall_arg *arg); #define SCA_STATX_FLAGS syscall_arg__scnprintf_statx_flags diff --git a/tools/perf/trace/beauty/drm_ioctl.sh b/tools/perf/trace/beauty/drm_ioctl.sh index 2149d3a98e42..9d3816815e60 100755 --- a/tools/perf/trace/beauty/drm_ioctl.sh +++ b/tools/perf/trace/beauty/drm_ioctl.sh @@ -1,13 +1,14 @@ #!/bin/sh -drm_header_dir=$1 +[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/drm/ + printf "#ifndef DRM_COMMAND_BASE\n" -grep "#define DRM_COMMAND_BASE" $drm_header_dir/drm.h +grep "#define DRM_COMMAND_BASE" $header_dir/drm.h printf "#endif\n" printf "static const char *drm_ioctl_cmds[] = {\n" -grep "^#define DRM_IOCTL.*DRM_IO" $drm_header_dir/drm.h | \ +grep "^#define DRM_IOCTL.*DRM_IO" $header_dir/drm.h | \ sed -r 's/^#define +DRM_IOCTL_([A-Z0-9_]+)[ ]+DRM_IO[A-Z]* *\( *(0x[[:xdigit:]]+),*.*/ [\2] = "\1",/g' -grep "^#define DRM_I915_[A-Z_0-9]\+[ ]\+0x" $drm_header_dir/i915_drm.h | \ +grep "^#define DRM_I915_[A-Z_0-9]\+[ ]\+0x" $header_dir/i915_drm.h | \ sed -r 's/^#define +DRM_I915_([A-Z0-9_]+)[ ]+(0x[[:xdigit:]]+)/\t[DRM_COMMAND_BASE + \2] = "I915_\1",/g' printf "};\n" diff --git a/tools/perf/trace/beauty/kcmp_type.sh b/tools/perf/trace/beauty/kcmp_type.sh index 40d063b8c082..a3c304caa336 100755 --- a/tools/perf/trace/beauty/kcmp_type.sh +++ b/tools/perf/trace/beauty/kcmp_type.sh @@ -1,6 +1,6 @@ #!/bin/sh -header_dir=$1 +[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ printf "static const char *kcmp_types[] = {\n" regex='^[[:space:]]+(KCMP_(\w+)),' diff --git a/tools/perf/trace/beauty/kvm_ioctl.sh b/tools/perf/trace/beauty/kvm_ioctl.sh index bd28817afced..c4699fd46bb6 100755 --- a/tools/perf/trace/beauty/kvm_ioctl.sh +++ b/tools/perf/trace/beauty/kvm_ioctl.sh @@ -1,10 +1,10 @@ #!/bin/sh -kvm_header_dir=$1 +[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ printf "static const char *kvm_ioctl_cmds[] = {\n" regex='^#[[:space:]]*define[[:space:]]+KVM_(\w+)[[:space:]]+_IO[RW]*\([[:space:]]*KVMIO[[:space:]]*,[[:space:]]*(0x[[:xdigit:]]+).*' -egrep $regex ${kvm_header_dir}/kvm.h | \ +egrep $regex ${header_dir}/kvm.h | \ sed -r "s/$regex/\2 \1/g" | \ egrep -v " ((ARM|PPC|S390)_|[GS]ET_(DEBUGREGS|PIT2|XSAVE|TSC_KHZ)|CREATE_SPAPR_TCE_64)" | \ sort | xargs printf "\t[%s] = \"%s\",\n" diff --git a/tools/perf/trace/beauty/madvise_behavior.sh b/tools/perf/trace/beauty/madvise_behavior.sh index 60ef8640ee70..431639eb4d29 100755 --- a/tools/perf/trace/beauty/madvise_behavior.sh +++ b/tools/perf/trace/beauty/madvise_behavior.sh @@ -1,6 +1,6 @@ #!/bin/sh -header_dir=$1 +[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/asm-generic/ printf "static const char *madvise_advices[] = {\n" regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+MADV_([[:alnum:]_]+)[[:space:]]+([[:digit:]]+)[[:space:]]*.*' diff --git a/tools/perf/trace/beauty/perf_ioctl.sh b/tools/perf/trace/beauty/perf_ioctl.sh index faea4237c793..6492c74df928 100755 --- a/tools/perf/trace/beauty/perf_ioctl.sh +++ b/tools/perf/trace/beauty/perf_ioctl.sh @@ -1,6 +1,6 @@ #!/bin/sh -header_dir=$1 +[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ printf "static const char *perf_ioctl_cmds[] = {\n" regex='^#[[:space:]]*define[[:space:]]+PERF_EVENT_IOC_(\w+)[[:space:]]+_IO[RW]*[[:space:]]*\([[:space:]]*.\$.[[:space:]]*,[[:space:]]*([[:digit:]]+).*' diff --git a/tools/perf/trace/beauty/pkey_alloc_access_rights.sh b/tools/perf/trace/beauty/pkey_alloc_access_rights.sh index 62e51a02b839..e0a51aeb20b2 100755 --- a/tools/perf/trace/beauty/pkey_alloc_access_rights.sh +++ b/tools/perf/trace/beauty/pkey_alloc_access_rights.sh @@ -1,6 +1,6 @@ #!/bin/sh -header_dir=$1 +[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/asm-generic/ printf "static const char *pkey_alloc_access_rights[] = {\n" regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+PKEY_([[:alnum:]_]+)[[:space:]]+(0x[[:xdigit:]]+)[[:space:]]*' diff --git a/tools/perf/trace/beauty/sndrv_ctl_ioctl.sh b/tools/perf/trace/beauty/sndrv_ctl_ioctl.sh index aad5ab130539..eb511bb5fbd3 100755 --- a/tools/perf/trace/beauty/sndrv_ctl_ioctl.sh +++ b/tools/perf/trace/beauty/sndrv_ctl_ioctl.sh @@ -1,8 +1,8 @@ #!/bin/sh -sound_header_dir=$1 +[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/sound/ printf "static const char *sndrv_ctl_ioctl_cmds[] = {\n" -grep "^#define[\t ]\+SNDRV_CTL_IOCTL_" $sound_header_dir/asound.h | \ +grep "^#define[\t ]\+SNDRV_CTL_IOCTL_" $header_dir/asound.h | \ sed -r 's/^#define +SNDRV_CTL_IOCTL_([A-Z0-9_]+)[\t ]+_IO[RW]*\( *.U., *(0x[[:xdigit:]]+),?.*/\t[\2] = \"\1\",/g' printf "};\n" diff --git a/tools/perf/trace/beauty/sndrv_pcm_ioctl.sh b/tools/perf/trace/beauty/sndrv_pcm_ioctl.sh index b7e9ef6b2f55..6818392968b2 100755 --- a/tools/perf/trace/beauty/sndrv_pcm_ioctl.sh +++ b/tools/perf/trace/beauty/sndrv_pcm_ioctl.sh @@ -1,8 +1,8 @@ #!/bin/sh -sound_header_dir=$1 +[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/sound/ printf "static const char *sndrv_pcm_ioctl_cmds[] = {\n" -grep "^#define[\t ]\+SNDRV_PCM_IOCTL_" $sound_header_dir/asound.h | \ +grep "^#define[\t ]\+SNDRV_PCM_IOCTL_" $header_dir/asound.h | \ sed -r 's/^#define +SNDRV_PCM_IOCTL_([A-Z0-9_]+)[\t ]+_IO[RW]*\( *.A., *(0x[[:xdigit:]]+),?.*/\t[\2] = \"\1\",/g' printf "};\n" diff --git a/tools/perf/trace/beauty/socket.c b/tools/perf/trace/beauty/socket.c new file mode 100644 index 000000000000..65227269384b --- /dev/null +++ b/tools/perf/trace/beauty/socket.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * trace/beauty/socket.c + * + * Copyright (C) 2018, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> + */ + +#include "trace/beauty/beauty.h" +#include <sys/types.h> +#include <sys/socket.h> + +static size_t socket__scnprintf_ipproto(int protocol, char *bf, size_t size) +{ +#include "trace/beauty/generated/socket_ipproto_array.c" + static DEFINE_STRARRAY(socket_ipproto); + + return strarray__scnprintf(&strarray__socket_ipproto, bf, size, "%d", protocol); +} + +size_t syscall_arg__scnprintf_socket_protocol(char *bf, size_t size, struct syscall_arg *arg) +{ + int domain = syscall_arg__val(arg, 0); + + if (domain == AF_INET || domain == AF_INET6) + return socket__scnprintf_ipproto(arg->val, bf, size); + + return syscall_arg__scnprintf_int(bf, size, arg); +} diff --git a/tools/perf/trace/beauty/socket_ipproto.sh b/tools/perf/trace/beauty/socket_ipproto.sh new file mode 100755 index 000000000000..a3cc24633bec --- /dev/null +++ b/tools/perf/trace/beauty/socket_ipproto.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ + +printf "static const char *socket_ipproto[] = {\n" +regex='^[[:space:]]+IPPROTO_(\w+)[[:space:]]+=[[:space:]]+([[:digit:]]+),.*' + +egrep $regex ${header_dir}/in.h | \ + sed -r "s/$regex/\2 \1/g" | \ + sort | xargs printf "\t[%s] = \"%s\",\n" +printf "};\n" diff --git a/tools/perf/trace/beauty/vhost_virtio_ioctl.sh b/tools/perf/trace/beauty/vhost_virtio_ioctl.sh index 76f1de697787..0f6a5197d0be 100755 --- a/tools/perf/trace/beauty/vhost_virtio_ioctl.sh +++ b/tools/perf/trace/beauty/vhost_virtio_ioctl.sh @@ -1,17 +1,17 @@ #!/bin/sh -vhost_virtio_header_dir=$1 +[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ printf "static const char *vhost_virtio_ioctl_cmds[] = {\n" regex='^#[[:space:]]*define[[:space:]]+VHOST_(\w+)[[:space:]]+_IOW?\([[:space:]]*VHOST_VIRTIO[[:space:]]*,[[:space:]]*(0x[[:xdigit:]]+).*' -egrep $regex ${vhost_virtio_header_dir}/vhost.h | \ +egrep $regex ${header_dir}/vhost.h | \ sed -r "s/$regex/\2 \1/g" | \ sort | xargs printf "\t[%s] = \"%s\",\n" printf "};\n" printf "static const char *vhost_virtio_ioctl_read_cmds[] = {\n" regex='^#[[:space:]]*define[[:space:]]+VHOST_(\w+)[[:space:]]+_IOW?R\([[:space:]]*VHOST_VIRTIO[[:space:]]*,[[:space:]]*(0x[[:xdigit:]]+).*' -egrep $regex ${vhost_virtio_header_dir}/vhost.h | \ +egrep $regex ${header_dir}/vhost.h | \ sed -r "s/$regex/\2 \1/g" | \ sort | xargs printf "\t[%s] = \"%s\",\n" printf "};\n" diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 3b4f1c10ff57..1d00e5ec7906 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -15,6 +15,7 @@ #include <linux/kernel.h> #include <linux/string.h> #include <sys/ttydefaults.h> +#include <asm/bug.h> struct disasm_line_samples { double percent; @@ -115,7 +116,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int if (!browser->navkeypressed) ops.width += 1; - annotation_line__write(al, notes, &ops); + annotation_line__write(al, notes, &ops, ab->opts); if (ops.current_entry) ab->selection = al; @@ -227,10 +228,10 @@ static int disasm__cmp(struct annotation_line *a, struct annotation_line *b) { int i; - for (i = 0; i < a->samples_nr; i++) { - if (a->samples[i].percent == b->samples[i].percent) + for (i = 0; i < a->data_nr; i++) { + if (a->data[i].percent == b->data[i].percent) continue; - return a->samples[i].percent < b->samples[i].percent; + return a->data[i].percent < b->data[i].percent; } return 0; } @@ -314,11 +315,14 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser, continue; } - for (i = 0; i < pos->al.samples_nr; i++) { - struct annotation_data *sample = &pos->al.samples[i]; + for (i = 0; i < pos->al.data_nr; i++) { + double percent; - if (max_percent < sample->percent) - max_percent = sample->percent; + percent = annotation_data__percent(&pos->al.data[i], + browser->opts->percent_type); + + if (max_percent < percent) + max_percent = percent; } if (max_percent < 0.01 && pos->al.ipc == 0) { @@ -380,9 +384,10 @@ static void ui_browser__init_asm_mode(struct ui_browser *browser) #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64) static int sym_title(struct symbol *sym, struct map *map, char *title, - size_t sz) + size_t sz, int percent_type) { - return snprintf(title, sz, "%s %s", sym->name, map->dso->long_name); + return snprintf(title, sz, "%s %s [Percent: %s]", sym->name, map->dso->long_name, + percent_type_str(percent_type)); } /* @@ -420,7 +425,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser, pthread_mutex_unlock(¬es->lock); symbol__tui_annotate(dl->ops.target.sym, ms->map, evsel, hbt, browser->opts); - sym_title(ms->sym, ms->map, title, sizeof(title)); + sym_title(ms->sym, ms->map, title, sizeof(title), browser->opts->percent_type); ui_browser__show_title(&browser->b, title); return true; } @@ -595,6 +600,7 @@ bool annotate_browser__continue_search_reverse(struct annotate_browser *browser, static int annotate_browser__show(struct ui_browser *browser, char *title, const char *help) { + struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); struct map_symbol *ms = browser->priv; struct symbol *sym = ms->sym; char symbol_dso[SYM_TITLE_MAX_SIZE]; @@ -602,7 +608,7 @@ static int annotate_browser__show(struct ui_browser *browser, char *title, const if (ui_browser__show(browser, title, help) < 0) return -1; - sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso)); + sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso), ab->opts->percent_type); ui_browser__gotorc_title(browser, 0, 0); ui_browser__set_color(browser, HE_COLORSET_ROOT); @@ -610,6 +616,39 @@ static int annotate_browser__show(struct ui_browser *browser, char *title, const return 0; } +static void +switch_percent_type(struct annotation_options *opts, bool base) +{ + switch (opts->percent_type) { + case PERCENT_HITS_LOCAL: + if (base) + opts->percent_type = PERCENT_PERIOD_LOCAL; + else + opts->percent_type = PERCENT_HITS_GLOBAL; + break; + case PERCENT_HITS_GLOBAL: + if (base) + opts->percent_type = PERCENT_PERIOD_GLOBAL; + else + opts->percent_type = PERCENT_HITS_LOCAL; + break; + case PERCENT_PERIOD_LOCAL: + if (base) + opts->percent_type = PERCENT_HITS_LOCAL; + else + opts->percent_type = PERCENT_PERIOD_GLOBAL; + break; + case PERCENT_PERIOD_GLOBAL: + if (base) + opts->percent_type = PERCENT_HITS_GLOBAL; + else + opts->percent_type = PERCENT_PERIOD_LOCAL; + break; + default: + WARN_ON(1); + } +} + static int annotate_browser__run(struct annotate_browser *browser, struct perf_evsel *evsel, struct hist_browser_timer *hbt) @@ -624,8 +663,7 @@ static int annotate_browser__run(struct annotate_browser *browser, char title[256]; int key; - annotation__scnprintf_samples_period(notes, title, sizeof(title), evsel); - + hists__scnprintf_title(hists, title, sizeof(title)); if (annotate_browser__show(&browser->b, title, help) < 0) return -1; @@ -701,6 +739,8 @@ static int annotate_browser__run(struct annotate_browser *browser, "k Toggle line numbers\n" "P Print to [symbol_name].annotation file.\n" "r Run available scripts\n" + "p Toggle percent type [local/global]\n" + "b Toggle percent base [period/hits]\n" "? Search string backwards\n"); continue; case 'r': @@ -781,7 +821,7 @@ show_sup_ins: continue; } case 'P': - map_symbol__annotation_dump(ms, evsel); + map_symbol__annotation_dump(ms, evsel, browser->opts); continue; case 't': if (notes->options->show_total_period) { @@ -800,6 +840,12 @@ show_sup_ins: notes->options->show_minmax_cycle = true; annotation__update_column_widths(notes); continue; + case 'p': + case 'b': + switch_percent_type(browser->opts, key == 'b'); + hists__scnprintf_title(hists, title, sizeof(title)); + annotate_browser__show(&browser->b, title, help); + continue; case K_LEFT: case K_ESC: case 'q': diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index 69b7a28f7a1c..74c4ae1f0a05 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c @@ -529,7 +529,7 @@ out: static int hist_entry__fprintf(struct hist_entry *he, size_t size, char *bf, size_t bfsz, FILE *fp, - bool use_callchain) + bool ignore_callchains) { int ret; int callchain_ret = 0; @@ -550,7 +550,7 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size, ret = fprintf(fp, "%s\n", bf); - if (hist_entry__has_callchains(he) && use_callchain) + if (hist_entry__has_callchains(he) && !ignore_callchains) callchain_ret = hist_entry_callchain__fprintf(he, total_period, 0, fp); @@ -755,7 +755,7 @@ int hists__fprintf_headers(struct hists *hists, FILE *fp) size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, int max_cols, float min_pcnt, FILE *fp, - bool use_callchain) + bool ignore_callchains) { struct rb_node *nd; size_t ret = 0; @@ -799,7 +799,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, if (percent < min_pcnt) continue; - ret += hist_entry__fprintf(h, max_cols, line, linesz, fp, use_callchain); + ret += hist_entry__fprintf(h, max_cols, line, linesz, fp, ignore_callchains); if (max_rows && ++nr_rows >= max_rows) break; diff --git a/tools/perf/util/Build b/tools/perf/util/Build index b604ef334dc9..7efe15b9618d 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -87,6 +87,7 @@ libperf-$(CONFIG_AUXTRACE) += intel-pt.o libperf-$(CONFIG_AUXTRACE) += intel-bts.o libperf-$(CONFIG_AUXTRACE) += arm-spe.o libperf-$(CONFIG_AUXTRACE) += arm-spe-pkt-decoder.o +libperf-$(CONFIG_AUXTRACE) += s390-cpumsf.o ifdef CONFIG_LIBOPENCSD libperf-$(CONFIG_AUXTRACE) += cs-etm.o diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index f91775b4bc3c..20061cf42288 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -49,6 +49,7 @@ struct annotation_options annotation__default_options = { .jump_arrows = true, .annotate_src = true, .offset_level = ANNOTATION__OFFSET_JUMP_TARGETS, + .percent_type = PERCENT_PERIOD_LOCAL, }; static regex_t file_lineno; @@ -1108,7 +1109,7 @@ annotation_line__new(struct annotate_args *args, size_t privsize) if (perf_evsel__is_group_event(evsel)) nr = evsel->nr_members; - size += sizeof(al->samples[0]) * nr; + size += sizeof(al->data[0]) * nr; al = zalloc(size); if (al) { @@ -1117,7 +1118,7 @@ annotation_line__new(struct annotate_args *args, size_t privsize) al->offset = args->offset; al->line = strdup(args->line); al->line_nr = args->line_nr; - al->samples_nr = nr; + al->data_nr = nr; } return al; @@ -1297,7 +1298,8 @@ static int disasm_line__print(struct disasm_line *dl, u64 start, int addr_fmt_wi static int annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start, struct perf_evsel *evsel, u64 len, int min_pcnt, int printed, - int max_lines, struct annotation_line *queue, int addr_fmt_width) + int max_lines, struct annotation_line *queue, int addr_fmt_width, + int percent_type) { struct disasm_line *dl = container_of(al, struct disasm_line, al); static const char *prev_line; @@ -1309,15 +1311,18 @@ annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start const char *color; struct annotation *notes = symbol__annotation(sym); - for (i = 0; i < al->samples_nr; i++) { - struct annotation_data *sample = &al->samples[i]; + for (i = 0; i < al->data_nr; i++) { + double percent; - if (sample->percent > max_percent) - max_percent = sample->percent; + percent = annotation_data__percent(&al->data[i], + percent_type); + + if (percent > max_percent) + max_percent = percent; } - if (al->samples_nr > nr_percent) - nr_percent = al->samples_nr; + if (al->data_nr > nr_percent) + nr_percent = al->data_nr; if (max_percent < min_pcnt) return -1; @@ -1330,7 +1335,8 @@ annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start if (queue == al) break; annotation_line__print(queue, sym, start, evsel, len, - 0, 0, 1, NULL, addr_fmt_width); + 0, 0, 1, NULL, addr_fmt_width, + percent_type); } } @@ -1351,18 +1357,20 @@ annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start } for (i = 0; i < nr_percent; i++) { - struct annotation_data *sample = &al->samples[i]; + struct annotation_data *data = &al->data[i]; + double percent; - color = get_percent_color(sample->percent); + percent = annotation_data__percent(data, percent_type); + color = get_percent_color(percent); if (symbol_conf.show_total_period) color_fprintf(stdout, color, " %11" PRIu64, - sample->he.period); + data->he.period); else if (symbol_conf.show_nr_samples) color_fprintf(stdout, color, " %7" PRIu64, - sample->he.nr_samples); + data->he.nr_samples); else - color_fprintf(stdout, color, " %7.2f", sample->percent); + color_fprintf(stdout, color, " %7.2f", percent); } printf(" : "); @@ -1621,6 +1629,7 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) char symfs_filename[PATH_MAX]; struct kcore_extract kce; bool delete_extract = false; + bool decomp = false; int stdout_fd[2]; int lineno = 0; int nline; @@ -1654,6 +1663,7 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) tmp, sizeof(tmp)) < 0) goto out; + decomp = true; strcpy(symfs_filename, tmp); } @@ -1740,7 +1750,7 @@ out_free_command: out_remove_tmp: close(stdout_fd[0]); - if (dso__needs_decompress(dso)) + if (decomp) unlink(symfs_filename); if (delete_extract) @@ -1753,34 +1763,45 @@ out_close_stdout: goto out_free_command; } -static void calc_percent(struct sym_hist *hist, - struct annotation_data *sample, +static void calc_percent(struct sym_hist *sym_hist, + struct hists *hists, + struct annotation_data *data, s64 offset, s64 end) { unsigned int hits = 0; u64 period = 0; while (offset < end) { - hits += hist->addr[offset].nr_samples; - period += hist->addr[offset].period; + hits += sym_hist->addr[offset].nr_samples; + period += sym_hist->addr[offset].period; ++offset; } - if (hist->nr_samples) { - sample->he.period = period; - sample->he.nr_samples = hits; - sample->percent = 100.0 * hits / hist->nr_samples; + if (sym_hist->nr_samples) { + data->he.period = period; + data->he.nr_samples = hits; + data->percent[PERCENT_HITS_LOCAL] = 100.0 * hits / sym_hist->nr_samples; } + + if (hists->stats.nr_non_filtered_samples) + data->percent[PERCENT_HITS_GLOBAL] = 100.0 * hits / hists->stats.nr_non_filtered_samples; + + if (sym_hist->period) + data->percent[PERCENT_PERIOD_LOCAL] = 100.0 * period / sym_hist->period; + + if (hists->stats.total_period) + data->percent[PERCENT_PERIOD_GLOBAL] = 100.0 * period / hists->stats.total_period; } static void annotation__calc_percent(struct annotation *notes, - struct perf_evsel *evsel, s64 len) + struct perf_evsel *leader, s64 len) { struct annotation_line *al, *next; + struct perf_evsel *evsel; list_for_each_entry(al, ¬es->src->source, node) { s64 end; - int i; + int i = 0; if (al->offset == -1) continue; @@ -1788,14 +1809,17 @@ static void annotation__calc_percent(struct annotation *notes, next = annotation_line__next(al, ¬es->src->source); end = next ? next->offset : len; - for (i = 0; i < al->samples_nr; i++) { - struct annotation_data *sample; - struct sym_hist *hist; + for_each_group_evsel(evsel, leader) { + struct hists *hists = evsel__hists(evsel); + struct annotation_data *data; + struct sym_hist *sym_hist; + + BUG_ON(i >= al->data_nr); - hist = annotation__histogram(notes, evsel->idx + i); - sample = &al->samples[i]; + sym_hist = annotation__histogram(notes, evsel->idx); + data = &al->data[i++]; - calc_percent(hist, sample, al->offset, end); + calc_percent(sym_hist, hists, data, al->offset, end); } } } @@ -1846,7 +1870,8 @@ int symbol__annotate(struct symbol *sym, struct map *map, return symbol__disassemble(sym, &args); } -static void insert_source_line(struct rb_root *root, struct annotation_line *al) +static void insert_source_line(struct rb_root *root, struct annotation_line *al, + struct annotation_options *opts) { struct annotation_line *iter; struct rb_node **p = &root->rb_node; @@ -1859,8 +1884,10 @@ static void insert_source_line(struct rb_root *root, struct annotation_line *al) ret = strcmp(iter->path, al->path); if (ret == 0) { - for (i = 0; i < al->samples_nr; i++) - iter->samples[i].percent_sum += al->samples[i].percent; + for (i = 0; i < al->data_nr; i++) { + iter->data[i].percent_sum += annotation_data__percent(&al->data[i], + opts->percent_type); + } return; } @@ -1870,8 +1897,10 @@ static void insert_source_line(struct rb_root *root, struct annotation_line *al) p = &(*p)->rb_right; } - for (i = 0; i < al->samples_nr; i++) - al->samples[i].percent_sum = al->samples[i].percent; + for (i = 0; i < al->data_nr; i++) { + al->data[i].percent_sum = annotation_data__percent(&al->data[i], + opts->percent_type); + } rb_link_node(&al->rb_node, parent, p); rb_insert_color(&al->rb_node, root); @@ -1881,10 +1910,10 @@ static int cmp_source_line(struct annotation_line *a, struct annotation_line *b) { int i; - for (i = 0; i < a->samples_nr; i++) { - if (a->samples[i].percent_sum == b->samples[i].percent_sum) + for (i = 0; i < a->data_nr; i++) { + if (a->data[i].percent_sum == b->data[i].percent_sum) continue; - return a->samples[i].percent_sum > b->samples[i].percent_sum; + return a->data[i].percent_sum > b->data[i].percent_sum; } return 0; @@ -1949,8 +1978,8 @@ static void print_summary(struct rb_root *root, const char *filename) int i; al = rb_entry(node, struct annotation_line, rb_node); - for (i = 0; i < al->samples_nr; i++) { - percent = al->samples[i].percent_sum; + for (i = 0; i < al->data_nr; i++) { + percent = al->data[i].percent_sum; color = get_percent_color(percent); color_fprintf(stdout, color, " %7.2f", percent); @@ -2029,10 +2058,12 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, evsel_name = buf; } - graph_dotted_len = printf(" %-*.*s| Source code & Disassembly of %s for %s (%" PRIu64 " samples)\n", + graph_dotted_len = printf(" %-*.*s| Source code & Disassembly of %s for %s (%" PRIu64 " samples, " + "percent: %s)\n", width, width, symbol_conf.show_total_period ? "Period" : symbol_conf.show_nr_samples ? "Samples" : "Percent", - d_filename, evsel_name, h->nr_samples); + d_filename, evsel_name, h->nr_samples, + percent_type_str(opts->percent_type)); printf("%-*.*s----\n", graph_dotted_len, graph_dotted_len, graph_dotted_line); @@ -2052,7 +2083,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, err = annotation_line__print(pos, sym, start, evsel, len, opts->min_pcnt, printed, opts->max_lines, - queue, addr_fmt_width); + queue, addr_fmt_width, opts->percent_type); switch (err) { case 0: @@ -2129,10 +2160,11 @@ static void FILE__write_graph(void *fp, int graph) fputs(s, fp); } -int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp) +static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp, + struct annotation_options *opts) { struct annotation *notes = symbol__annotation(sym); - struct annotation_write_ops ops = { + struct annotation_write_ops wops = { .first_line = true, .obj = fp, .set_color = FILE__set_color, @@ -2146,15 +2178,16 @@ int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp) list_for_each_entry(al, ¬es->src->source, node) { if (annotation_line__filter(al, notes)) continue; - annotation_line__write(al, notes, &ops); + annotation_line__write(al, notes, &wops, opts); fputc('\n', fp); - ops.first_line = false; + wops.first_line = false; } return 0; } -int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel) +int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel, + struct annotation_options *opts) { const char *ev_name = perf_evsel__name(evsel); char buf[1024]; @@ -2176,7 +2209,7 @@ int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel) fprintf(fp, "%s() %s\nEvent: %s\n\n", ms->sym->name, ms->map->dso->long_name, ev_name); - symbol__annotate_fprintf2(ms->sym, fp); + symbol__annotate_fprintf2(ms->sym, fp, opts); fclose(fp); err = 0; @@ -2346,7 +2379,8 @@ void annotation__update_column_widths(struct annotation *notes) } static void annotation__calc_lines(struct annotation *notes, struct map *map, - struct rb_root *root) + struct rb_root *root, + struct annotation_options *opts) { struct annotation_line *al; struct rb_root tmp_root = RB_ROOT; @@ -2355,13 +2389,14 @@ static void annotation__calc_lines(struct annotation *notes, struct map *map, double percent_max = 0.0; int i; - for (i = 0; i < al->samples_nr; i++) { - struct annotation_data *sample; + for (i = 0; i < al->data_nr; i++) { + double percent; - sample = &al->samples[i]; + percent = annotation_data__percent(&al->data[i], + opts->percent_type); - if (sample->percent > percent_max) - percent_max = sample->percent; + if (percent > percent_max) + percent_max = percent; } if (percent_max <= 0.5) @@ -2369,18 +2404,19 @@ static void annotation__calc_lines(struct annotation *notes, struct map *map, al->path = get_srcline(map->dso, notes->start + al->offset, NULL, false, true, notes->start + al->offset); - insert_source_line(&tmp_root, al); + insert_source_line(&tmp_root, al, opts); } resort_source_line(root, &tmp_root); } static void symbol__calc_lines(struct symbol *sym, struct map *map, - struct rb_root *root) + struct rb_root *root, + struct annotation_options *opts) { struct annotation *notes = symbol__annotation(sym); - annotation__calc_lines(notes, map, root); + annotation__calc_lines(notes, map, root, opts); } int symbol__tty_annotate2(struct symbol *sym, struct map *map, @@ -2389,7 +2425,7 @@ int symbol__tty_annotate2(struct symbol *sym, struct map *map, { struct dso *dso = map->dso; struct rb_root source_line = RB_ROOT; - struct annotation *notes = symbol__annotation(sym); + struct hists *hists = evsel__hists(evsel); char buf[1024]; if (symbol__annotate2(sym, map, evsel, opts, NULL) < 0) @@ -2397,13 +2433,14 @@ int symbol__tty_annotate2(struct symbol *sym, struct map *map, if (opts->print_lines) { srcline_full_filename = opts->full_path; - symbol__calc_lines(sym, map, &source_line); + symbol__calc_lines(sym, map, &source_line, opts); print_summary(&source_line, dso->long_name); } - annotation__scnprintf_samples_period(notes, buf, sizeof(buf), evsel); - fprintf(stdout, "%s\n%s() %s\n", buf, sym->name, dso->long_name); - symbol__annotate_fprintf2(sym, stdout); + hists__scnprintf_title(hists, buf, sizeof(buf)); + fprintf(stdout, "%s, [percent: %s]\n%s() %s\n", + buf, percent_type_str(opts->percent_type), sym->name, dso->long_name); + symbol__annotate_fprintf2(sym, stdout, opts); annotated_source__purge(symbol__annotation(sym)->src); @@ -2424,7 +2461,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, if (opts->print_lines) { srcline_full_filename = opts->full_path; - symbol__calc_lines(sym, map, &source_line); + symbol__calc_lines(sym, map, &source_line, opts); print_summary(&source_line, dso->long_name); } @@ -2441,14 +2478,21 @@ bool ui__has_annotation(void) } -double annotation_line__max_percent(struct annotation_line *al, struct annotation *notes) +static double annotation_line__max_percent(struct annotation_line *al, + struct annotation *notes, + unsigned int percent_type) { double percent_max = 0.0; int i; for (i = 0; i < notes->nr_events; i++) { - if (al->samples[i].percent > percent_max) - percent_max = al->samples[i].percent; + double percent; + + percent = annotation_data__percent(&al->data[i], + percent_type); + + if (percent > percent_max) + percent_max = percent; } return percent_max; @@ -2487,7 +2531,7 @@ call_like: static void __annotation_line__write(struct annotation_line *al, struct annotation *notes, bool first_line, bool current_entry, bool change_color, int width, - void *obj, + void *obj, unsigned int percent_type, int (*obj__set_color)(void *obj, int color), void (*obj__set_percent_color)(void *obj, double percent, bool current), int (*obj__set_jumps_percent_color)(void *obj, int nr, bool current), @@ -2495,7 +2539,7 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati void (*obj__write_graph)(void *obj, int graph)) { - double percent_max = annotation_line__max_percent(al, notes); + double percent_max = annotation_line__max_percent(al, notes, percent_type); int pcnt_width = annotation__pcnt_width(notes), cycles_width = annotation__cycles_width(notes); bool show_title = false; @@ -2514,15 +2558,18 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati int i; for (i = 0; i < notes->nr_events; i++) { - obj__set_percent_color(obj, al->samples[i].percent, current_entry); + double percent; + + percent = annotation_data__percent(&al->data[i], percent_type); + + obj__set_percent_color(obj, percent, current_entry); if (notes->options->show_total_period) { - obj__printf(obj, "%11" PRIu64 " ", al->samples[i].he.period); + obj__printf(obj, "%11" PRIu64 " ", al->data[i].he.period); } else if (notes->options->show_nr_samples) { obj__printf(obj, "%6" PRIu64 " ", - al->samples[i].he.nr_samples); + al->data[i].he.nr_samples); } else { - obj__printf(obj, "%6.2f ", - al->samples[i].percent); + obj__printf(obj, "%6.2f ", percent); } } } else { @@ -2640,13 +2687,15 @@ print_addr: } void annotation_line__write(struct annotation_line *al, struct annotation *notes, - struct annotation_write_ops *ops) + struct annotation_write_ops *wops, + struct annotation_options *opts) { - __annotation_line__write(al, notes, ops->first_line, ops->current_entry, - ops->change_color, ops->width, ops->obj, - ops->set_color, ops->set_percent_color, - ops->set_jumps_percent_color, ops->printf, - ops->write_graph); + __annotation_line__write(al, notes, wops->first_line, wops->current_entry, + wops->change_color, wops->width, wops->obj, + opts->percent_type, + wops->set_color, wops->set_percent_color, + wops->set_jumps_percent_color, wops->printf, + wops->write_graph); } int symbol__annotate2(struct symbol *sym, struct map *map, struct perf_evsel *evsel, @@ -2688,46 +2737,6 @@ out_free_offsets: return -1; } -int __annotation__scnprintf_samples_period(struct annotation *notes, - char *bf, size_t size, - struct perf_evsel *evsel, - bool show_freq) -{ - const char *ev_name = perf_evsel__name(evsel); - char buf[1024], ref[30] = " show reference callgraph, "; - char sample_freq_str[64] = ""; - unsigned long nr_samples = 0; - int nr_members = 1; - bool enable_ref = false; - u64 nr_events = 0; - char unit; - int i; - - if (perf_evsel__is_group_event(evsel)) { - perf_evsel__group_desc(evsel, buf, sizeof(buf)); - ev_name = buf; - nr_members = evsel->nr_members; - } - - for (i = 0; i < nr_members; i++) { - struct sym_hist *ah = annotation__histogram(notes, evsel->idx + i); - - nr_samples += ah->nr_samples; - nr_events += ah->period; - } - - if (symbol_conf.show_ref_callgraph && strstr(ev_name, "call-graph=no")) - enable_ref = true; - - if (show_freq) - scnprintf(sample_freq_str, sizeof(sample_freq_str), " %d Hz,", evsel->attr.sample_freq); - - nr_samples = convert_unit(nr_samples, &unit); - return scnprintf(bf, size, "Samples: %lu%c of event%s '%s',%s%sEvent count (approx.): %" PRIu64, - nr_samples, unit, evsel->nr_members > 1 ? "s" : "", - ev_name, sample_freq_str, enable_ref ? ref : " ", nr_events); -} - #define ANNOTATION__CFG(n) \ { .name = #n, .value = &annotation__default_options.n, } @@ -2792,3 +2801,55 @@ void annotation_config__init(void) annotation__default_options.show_total_period = symbol_conf.show_total_period; annotation__default_options.show_nr_samples = symbol_conf.show_nr_samples; } + +static unsigned int parse_percent_type(char *str1, char *str2) +{ + unsigned int type = (unsigned int) -1; + + if (!strcmp("period", str1)) { + if (!strcmp("local", str2)) + type = PERCENT_PERIOD_LOCAL; + else if (!strcmp("global", str2)) + type = PERCENT_PERIOD_GLOBAL; + } + + if (!strcmp("hits", str1)) { + if (!strcmp("local", str2)) + type = PERCENT_HITS_LOCAL; + else if (!strcmp("global", str2)) + type = PERCENT_HITS_GLOBAL; + } + + return type; +} + +int annotate_parse_percent_type(const struct option *opt, const char *_str, + int unset __maybe_unused) +{ + struct annotation_options *opts = opt->value; + unsigned int type; + char *str1, *str2; + int err = -1; + + str1 = strdup(_str); + if (!str1) + return -ENOMEM; + + str2 = strchr(str1, '-'); + if (!str2) + goto out; + + *str2++ = 0; + + type = parse_percent_type(str1, str2); + if (type == (unsigned int) -1) + type = parse_percent_type(str2, str1); + if (type != (unsigned int) -1) { + opts->percent_type = type; + err = 0; + } + +out: + free(str1); + return err; +} diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index a4c0d91907e6..005a5fe8a8c6 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -11,6 +11,7 @@ #include <linux/list.h> #include <linux/rbtree.h> #include <pthread.h> +#include <asm/bug.h> struct ins_ops; @@ -82,6 +83,7 @@ struct annotation_options { int context; const char *objdump_path; const char *disassembler_style; + unsigned int percent_type; }; enum { @@ -101,8 +103,16 @@ struct sym_hist_entry { u64 period; }; +enum { + PERCENT_HITS_LOCAL, + PERCENT_HITS_GLOBAL, + PERCENT_PERIOD_LOCAL, + PERCENT_PERIOD_GLOBAL, + PERCENT_MAX, +}; + struct annotation_data { - double percent; + double percent[PERCENT_MAX]; double percent_sum; struct sym_hist_entry he; }; @@ -122,8 +132,8 @@ struct annotation_line { char *path; u32 idx; int idx_asm; - int samples_nr; - struct annotation_data samples[0]; + int data_nr; + struct annotation_data data[0]; }; struct disasm_line { @@ -134,6 +144,27 @@ struct disasm_line { struct annotation_line al; }; +static inline double annotation_data__percent(struct annotation_data *data, + unsigned int which) +{ + return which < PERCENT_MAX ? data->percent[which] : -1; +} + +static inline const char *percent_type_str(unsigned int type) +{ + static const char *str[PERCENT_MAX] = { + "local hits", + "global hits", + "local period", + "global period", + }; + + if (WARN_ON(type >= PERCENT_MAX)) + return "N/A"; + + return str[type]; +} + static inline struct disasm_line *disasm_line(struct annotation_line *al) { return al ? container_of(al, struct disasm_line, al) : NULL; @@ -169,22 +200,15 @@ struct annotation_write_ops { void (*write_graph)(void *obj, int graph); }; -double annotation_line__max_percent(struct annotation_line *al, struct annotation *notes); void annotation_line__write(struct annotation_line *al, struct annotation *notes, - struct annotation_write_ops *ops); + struct annotation_write_ops *ops, + struct annotation_options *opts); int __annotation__scnprintf_samples_period(struct annotation *notes, char *bf, size_t size, struct perf_evsel *evsel, bool show_freq); -static inline int annotation__scnprintf_samples_period(struct annotation *notes, - char *bf, size_t size, - struct perf_evsel *evsel) -{ - return __annotation__scnprintf_samples_period(notes, bf, size, evsel, true); -} - int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); size_t disasm__fprintf(struct list_head *head, FILE *fp); void symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel); @@ -340,12 +364,12 @@ int symbol__strerror_disassemble(struct symbol *sym, struct map *map, int symbol__annotate_printf(struct symbol *sym, struct map *map, struct perf_evsel *evsel, struct annotation_options *options); -int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp); void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); void annotated_source__purge(struct annotated_source *as); -int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel); +int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel, + struct annotation_options *opts); bool ui__has_annotation(void); @@ -373,4 +397,6 @@ static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, void annotation_config__init(void); +int annotate_parse_percent_type(const struct option *opt, const char *_str, + int unset); #endif /* __PERF_ANNOTATE_H */ diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index d056447520a2..db1511359c5e 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c @@ -56,6 +56,7 @@ #include "intel-pt.h" #include "intel-bts.h" #include "arm-spe.h" +#include "s390-cpumsf.h" #include "sane_ctype.h" #include "symbol/kallsyms.h" @@ -202,6 +203,9 @@ static int auxtrace_queues__grow(struct auxtrace_queues *queues, for (i = 0; i < queues->nr_queues; i++) { list_splice_tail(&queues->queue_array[i].head, &queue_array[i].head); + queue_array[i].tid = queues->queue_array[i].tid; + queue_array[i].cpu = queues->queue_array[i].cpu; + queue_array[i].set = queues->queue_array[i].set; queue_array[i].priv = queues->queue_array[i].priv; } @@ -920,6 +924,8 @@ int perf_event__process_auxtrace_info(struct perf_tool *tool __maybe_unused, return arm_spe_process_auxtrace_info(event, session); case PERF_AUXTRACE_CS_ETM: return cs_etm__process_auxtrace_info(event, session); + case PERF_AUXTRACE_S390_CPUMSF: + return s390_cpumsf_process_auxtrace_info(event, session); case PERF_AUXTRACE_UNKNOWN: default: return -EINVAL; diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h index e731f55da072..71fc3bd74299 100644 --- a/tools/perf/util/auxtrace.h +++ b/tools/perf/util/auxtrace.h @@ -44,6 +44,7 @@ enum auxtrace_type { PERF_AUXTRACE_INTEL_BTS, PERF_AUXTRACE_CS_ETM, PERF_AUXTRACE_ARM_SPE, + PERF_AUXTRACE_S390_CPUMSF, }; enum itrace_period_type { diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index cee658733e2c..47aac41349a2 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c @@ -747,7 +747,9 @@ int bpf__load(struct bpf_object *obj) err = bpf_object__load(obj); if (err) { - pr_debug("bpf: load objects failed\n"); + char bf[128]; + libbpf_strerror(err, bf, sizeof(bf)); + pr_debug("bpf: load objects failed: err=%d: (%s)\n", err, bf); return err; } return 0; @@ -1527,13 +1529,13 @@ int bpf__apply_obj_config(void) bpf_object__for_each_safe(obj, objtmp) \ bpf_map__for_each(pos, obj) -#define bpf__for_each_stdout_map(pos, obj, objtmp) \ +#define bpf__for_each_map_named(pos, obj, objtmp, name) \ bpf__for_each_map(pos, obj, objtmp) \ if (bpf_map__name(pos) && \ - (strcmp("__bpf_stdout__", \ + (strcmp(name, \ bpf_map__name(pos)) == 0)) -int bpf__setup_stdout(struct perf_evlist *evlist) +struct perf_evsel *bpf__setup_output_event(struct perf_evlist *evlist, const char *name) { struct bpf_map_priv *tmpl_priv = NULL; struct bpf_object *obj, *tmp; @@ -1542,11 +1544,11 @@ int bpf__setup_stdout(struct perf_evlist *evlist) int err; bool need_init = false; - bpf__for_each_stdout_map(map, obj, tmp) { + bpf__for_each_map_named(map, obj, tmp, name) { struct bpf_map_priv *priv = bpf_map__priv(map); if (IS_ERR(priv)) - return -BPF_LOADER_ERRNO__INTERNAL; + return ERR_PTR(-BPF_LOADER_ERRNO__INTERNAL); /* * No need to check map type: type should have been @@ -1559,49 +1561,61 @@ int bpf__setup_stdout(struct perf_evlist *evlist) } if (!need_init) - return 0; + return NULL; if (!tmpl_priv) { - err = parse_events(evlist, "bpf-output/no-inherit=1,name=__bpf_stdout__/", - NULL); + char *event_definition = NULL; + + if (asprintf(&event_definition, "bpf-output/no-inherit=1,name=%s/", name) < 0) + return ERR_PTR(-ENOMEM); + + err = parse_events(evlist, event_definition, NULL); + free(event_definition); + if (err) { - pr_debug("ERROR: failed to create bpf-output event\n"); - return -err; + pr_debug("ERROR: failed to create the \"%s\" bpf-output event\n", name); + return ERR_PTR(-err); } evsel = perf_evlist__last(evlist); } - bpf__for_each_stdout_map(map, obj, tmp) { + bpf__for_each_map_named(map, obj, tmp, name) { struct bpf_map_priv *priv = bpf_map__priv(map); if (IS_ERR(priv)) - return -BPF_LOADER_ERRNO__INTERNAL; + return ERR_PTR(-BPF_LOADER_ERRNO__INTERNAL); if (priv) continue; if (tmpl_priv) { priv = bpf_map_priv__clone(tmpl_priv); if (!priv) - return -ENOMEM; + return ERR_PTR(-ENOMEM); err = bpf_map__set_priv(map, priv, bpf_map_priv__clear); if (err) { bpf_map_priv__clear(map, priv); - return err; + return ERR_PTR(err); } } else if (evsel) { struct bpf_map_op *op; op = bpf_map__add_newop(map, NULL); if (IS_ERR(op)) - return PTR_ERR(op); + return ERR_PTR(PTR_ERR(op)); op->op_type = BPF_MAP_OP_SET_EVSEL; op->v.evsel = evsel; } } - return 0; + return evsel; +} + +int bpf__setup_stdout(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel = bpf__setup_output_event(evlist, "__bpf_stdout__"); + return IS_ERR(evsel) ? PTR_ERR(evsel) : 0; } #define ERRNO_OFFSET(e) ((e) - __BPF_LOADER_ERRNO__START) @@ -1778,8 +1792,8 @@ int bpf__strerror_apply_obj_config(int err, char *buf, size_t size) return 0; } -int bpf__strerror_setup_stdout(struct perf_evlist *evlist __maybe_unused, - int err, char *buf, size_t size) +int bpf__strerror_setup_output_event(struct perf_evlist *evlist __maybe_unused, + int err, char *buf, size_t size) { bpf__strerror_head(err, buf, size); bpf__strerror_end(buf, size); diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h index 5d3aefd6fae7..62d245a90e1d 100644 --- a/tools/perf/util/bpf-loader.h +++ b/tools/perf/util/bpf-loader.h @@ -43,6 +43,7 @@ enum bpf_loader_errno { __BPF_LOADER_ERRNO__END, }; +struct perf_evsel; struct bpf_object; struct parse_events_term; #define PERF_BPF_PROBE_GROUP "perf_bpf_probe" @@ -82,9 +83,8 @@ int bpf__apply_obj_config(void); int bpf__strerror_apply_obj_config(int err, char *buf, size_t size); int bpf__setup_stdout(struct perf_evlist *evlist); -int bpf__strerror_setup_stdout(struct perf_evlist *evlist, int err, - char *buf, size_t size); - +struct perf_evsel *bpf__setup_output_event(struct perf_evlist *evlist, const char *name); +int bpf__strerror_setup_output_event(struct perf_evlist *evlist, int err, char *buf, size_t size); #else #include <errno.h> @@ -138,6 +138,12 @@ bpf__setup_stdout(struct perf_evlist *evlist __maybe_unused) return 0; } +static inline struct perf_evsel * +bpf__setup_output_event(struct perf_evlist *evlist __maybe_unused, const char *name __maybe_unused) +{ + return NULL; +} + static inline int __bpf_strerror(char *buf, size_t size) { @@ -193,11 +199,16 @@ bpf__strerror_apply_obj_config(int err __maybe_unused, } static inline int -bpf__strerror_setup_stdout(struct perf_evlist *evlist __maybe_unused, - int err __maybe_unused, char *buf, - size_t size) +bpf__strerror_setup_output_event(struct perf_evlist *evlist __maybe_unused, + int err __maybe_unused, char *buf, size_t size) { return __bpf_strerror(buf, size); } + #endif + +static inline int bpf__strerror_setup_stdout(struct perf_evlist *evlist, int err, char *buf, size_t size) +{ + return bpf__strerror_setup_output_event(evlist, err, buf, size); +} #endif diff --git a/tools/perf/util/comm.c b/tools/perf/util/comm.c index 7798a2cc8a86..31279a7bd919 100644 --- a/tools/perf/util/comm.c +++ b/tools/perf/util/comm.c @@ -20,9 +20,10 @@ static struct rw_semaphore comm_str_lock = {.lock = PTHREAD_RWLOCK_INITIALIZER,} static struct comm_str *comm_str__get(struct comm_str *cs) { - if (cs) - refcount_inc(&cs->refcnt); - return cs; + if (cs && refcount_inc_not_zero(&cs->refcnt)) + return cs; + + return NULL; } static void comm_str__put(struct comm_str *cs) @@ -67,9 +68,14 @@ struct comm_str *__comm_str__findnew(const char *str, struct rb_root *root) parent = *p; iter = rb_entry(parent, struct comm_str, rb_node); + /* + * If we race with comm_str__put, iter->refcnt is 0 + * and it will be removed within comm_str__put call + * shortly, ignore it in this search. + */ cmp = strcmp(str, iter->str); - if (!cmp) - return comm_str__get(iter); + if (!cmp && comm_str__get(iter)) + return iter; if (cmp < 0) p = &(*p)->rb_left; diff --git a/tools/perf/util/compress.h b/tools/perf/util/compress.h index ecca688a25fb..892e92e7e7fc 100644 --- a/tools/perf/util/compress.h +++ b/tools/perf/util/compress.h @@ -4,10 +4,12 @@ #ifdef HAVE_ZLIB_SUPPORT int gzip_decompress_to_file(const char *input, int output_fd); +bool gzip_is_compressed(const char *input); #endif #ifdef HAVE_LZMA_SUPPORT int lzma_decompress_to_file(const char *input, int output_fd); +bool lzma_is_compressed(const char *input); #endif #endif /* PERF_COMPRESS_H */ diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c index 4d5fc374e730..938def6d0bb9 100644 --- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c +++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c @@ -31,6 +31,8 @@ #endif #endif +#define CS_ETM_INVAL_ADDR 0xdeadbeefdeadbeefUL + struct cs_etm_decoder { void *data; void (*packet_printer)(const char *msg); @@ -261,8 +263,8 @@ static void cs_etm_decoder__clear_buffer(struct cs_etm_decoder *decoder) decoder->tail = 0; decoder->packet_count = 0; for (i = 0; i < MAX_BUFFER; i++) { - decoder->packet_buffer[i].start_addr = 0xdeadbeefdeadbeefUL; - decoder->packet_buffer[i].end_addr = 0xdeadbeefdeadbeefUL; + decoder->packet_buffer[i].start_addr = CS_ETM_INVAL_ADDR; + decoder->packet_buffer[i].end_addr = CS_ETM_INVAL_ADDR; decoder->packet_buffer[i].last_instr_taken_branch = false; decoder->packet_buffer[i].exc = false; decoder->packet_buffer[i].exc_ret = false; @@ -295,8 +297,8 @@ cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder, decoder->packet_buffer[et].exc = false; decoder->packet_buffer[et].exc_ret = false; decoder->packet_buffer[et].cpu = *((int *)inode->priv); - decoder->packet_buffer[et].start_addr = 0xdeadbeefdeadbeefUL; - decoder->packet_buffer[et].end_addr = 0xdeadbeefdeadbeefUL; + decoder->packet_buffer[et].start_addr = CS_ETM_INVAL_ADDR; + decoder->packet_buffer[et].end_addr = CS_ETM_INVAL_ADDR; if (decoder->packet_count == MAX_BUFFER - 1) return OCSD_RESP_WAIT; diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h index 743f5f444304..612b5755f742 100644 --- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h +++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h @@ -23,6 +23,7 @@ struct cs_etm_buffer { }; enum cs_etm_sample_type { + CS_ETM_EMPTY = 0, CS_ETM_RANGE = 1 << 0, CS_ETM_TRACE_ON = 1 << 1, }; diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c index 822ba915d144..2ae640257fdb 100644 --- a/tools/perf/util/cs-etm.c +++ b/tools/perf/util/cs-etm.c @@ -494,6 +494,10 @@ static inline void cs_etm__reset_last_branch_rb(struct cs_etm_queue *etmq) static inline u64 cs_etm__last_executed_instr(struct cs_etm_packet *packet) { + /* Returns 0 for the CS_ETM_TRACE_ON packet */ + if (packet->sample_type == CS_ETM_TRACE_ON) + return 0; + /* * The packet records the execution range with an exclusive end address * @@ -505,6 +509,15 @@ static inline u64 cs_etm__last_executed_instr(struct cs_etm_packet *packet) return packet->end_addr - A64_INSTR_SIZE; } +static inline u64 cs_etm__first_executed_instr(struct cs_etm_packet *packet) +{ + /* Returns 0 for the CS_ETM_TRACE_ON packet */ + if (packet->sample_type == CS_ETM_TRACE_ON) + return 0; + + return packet->start_addr; +} + static inline u64 cs_etm__instr_count(const struct cs_etm_packet *packet) { /* @@ -546,7 +559,7 @@ static void cs_etm__update_last_branch_rb(struct cs_etm_queue *etmq) be = &bs->entries[etmq->last_branch_pos]; be->from = cs_etm__last_executed_instr(etmq->prev_packet); - be->to = etmq->packet->start_addr; + be->to = cs_etm__first_executed_instr(etmq->packet); /* No support for mispredict */ be->flags.mispred = 0; be->flags.predicted = 1; @@ -701,7 +714,7 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq) sample.ip = cs_etm__last_executed_instr(etmq->prev_packet); sample.pid = etmq->pid; sample.tid = etmq->tid; - sample.addr = etmq->packet->start_addr; + sample.addr = cs_etm__first_executed_instr(etmq->packet); sample.id = etmq->etm->branches_id; sample.stream_id = etmq->etm->branches_id; sample.period = 1; @@ -897,13 +910,23 @@ static int cs_etm__sample(struct cs_etm_queue *etmq) etmq->period_instructions = instrs_over; } - if (etm->sample_branches && - etmq->prev_packet && - etmq->prev_packet->sample_type == CS_ETM_RANGE && - etmq->prev_packet->last_instr_taken_branch) { - ret = cs_etm__synth_branch_sample(etmq); - if (ret) - return ret; + if (etm->sample_branches && etmq->prev_packet) { + bool generate_sample = false; + + /* Generate sample for tracing on packet */ + if (etmq->prev_packet->sample_type == CS_ETM_TRACE_ON) + generate_sample = true; + + /* Generate sample for branch taken packet */ + if (etmq->prev_packet->sample_type == CS_ETM_RANGE && + etmq->prev_packet->last_instr_taken_branch) + generate_sample = true; + + if (generate_sample) { + ret = cs_etm__synth_branch_sample(etmq); + if (ret) + return ret; + } } if (etm->sample_branches || etm->synth_opts.last_branch) { @@ -922,10 +945,17 @@ static int cs_etm__sample(struct cs_etm_queue *etmq) static int cs_etm__flush(struct cs_etm_queue *etmq) { int err = 0; + struct cs_etm_auxtrace *etm = etmq->etm; struct cs_etm_packet *tmp; + if (!etmq->prev_packet) + return 0; + + /* Handle start tracing packet */ + if (etmq->prev_packet->sample_type == CS_ETM_EMPTY) + goto swap_packet; + if (etmq->etm->synth_opts.last_branch && - etmq->prev_packet && etmq->prev_packet->sample_type == CS_ETM_RANGE) { /* * Generate a last branch event for the branches left in the @@ -939,8 +969,22 @@ static int cs_etm__flush(struct cs_etm_queue *etmq) err = cs_etm__synth_instruction_sample( etmq, addr, etmq->period_instructions); + if (err) + return err; + etmq->period_instructions = 0; + } + + if (etm->sample_branches && + etmq->prev_packet->sample_type == CS_ETM_RANGE) { + err = cs_etm__synth_branch_sample(etmq); + if (err) + return err; + } + +swap_packet: + if (etmq->etm->synth_opts.last_branch) { /* * Swap PACKET with PREV_PACKET: PACKET becomes PREV_PACKET for * the next incoming packet. @@ -1020,6 +1064,13 @@ static int cs_etm__run_decoder(struct cs_etm_queue *etmq) */ cs_etm__flush(etmq); break; + case CS_ETM_EMPTY: + /* + * Should not receive empty packet, + * report error. + */ + pr_err("CS ETM Trace: empty packet\n"); + return -EINVAL; default: break; } diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index 5744c12641a5..abd38abf1d91 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c @@ -310,8 +310,8 @@ static int add_tracepoint_field_value(struct ctf_writer *cw, if (flags & FIELD_IS_DYNAMIC) { unsigned long long tmp_val; - tmp_val = pevent_read_number(fmtf->event->pevent, - data + offset, len); + tmp_val = tep_read_number(fmtf->event->pevent, + data + offset, len); offset = tmp_val; len = offset >> 16; offset &= 0xffff; @@ -353,7 +353,7 @@ static int add_tracepoint_field_value(struct ctf_writer *cw, else { unsigned long long value_int; - value_int = pevent_read_number( + value_int = tep_read_number( fmtf->event->pevent, data + offset + i * len, len); diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index 51cf82cf1882..bbed90e5d9bb 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -189,28 +189,34 @@ int dso__read_binary_type_filename(const struct dso *dso, return ret; } +enum { + COMP_ID__NONE = 0, +}; + static const struct { const char *fmt; int (*decompress)(const char *input, int output); + bool (*is_compressed)(const char *input); } compressions[] = { + [COMP_ID__NONE] = { .fmt = NULL, }, #ifdef HAVE_ZLIB_SUPPORT - { "gz", gzip_decompress_to_file }, + { "gz", gzip_decompress_to_file, gzip_is_compressed }, #endif #ifdef HAVE_LZMA_SUPPORT - { "xz", lzma_decompress_to_file }, + { "xz", lzma_decompress_to_file, lzma_is_compressed }, #endif - { NULL, NULL }, + { NULL, NULL, NULL }, }; -bool is_supported_compression(const char *ext) +static int is_supported_compression(const char *ext) { unsigned i; - for (i = 0; compressions[i].fmt; i++) { + for (i = 1; compressions[i].fmt; i++) { if (!strcmp(ext, compressions[i].fmt)) - return true; + return i; } - return false; + return COMP_ID__NONE; } bool is_kernel_module(const char *pathname, int cpumode) @@ -239,80 +245,73 @@ bool is_kernel_module(const char *pathname, int cpumode) return m.kmod; } -bool decompress_to_file(const char *ext, const char *filename, int output_fd) -{ - unsigned i; - - for (i = 0; compressions[i].fmt; i++) { - if (!strcmp(ext, compressions[i].fmt)) - return !compressions[i].decompress(filename, - output_fd); - } - return false; -} - bool dso__needs_decompress(struct dso *dso) { return dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP || dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP; } -static int decompress_kmodule(struct dso *dso, const char *name, char *tmpbuf) +static int decompress_kmodule(struct dso *dso, const char *name, + char *pathname, size_t len) { + char tmpbuf[] = KMOD_DECOMP_NAME; int fd = -1; - struct kmod_path m; if (!dso__needs_decompress(dso)) return -1; - if (kmod_path__parse_ext(&m, dso->long_name)) + if (dso->comp == COMP_ID__NONE) return -1; - if (!m.comp) - goto out; + /* + * We have proper compression id for DSO and yet the file + * behind the 'name' can still be plain uncompressed object. + * + * The reason is behind the logic we open the DSO object files, + * when we try all possible 'debug' objects until we find the + * data. So even if the DSO is represented by 'krava.xz' module, + * we can end up here opening ~/.debug/....23432432/debug' file + * which is not compressed. + * + * To keep this transparent, we detect this and return the file + * descriptor to the uncompressed file. + */ + if (!compressions[dso->comp].is_compressed(name)) + return open(name, O_RDONLY); fd = mkstemp(tmpbuf); if (fd < 0) { dso->load_errno = errno; - goto out; + return -1; } - if (!decompress_to_file(m.ext, name, fd)) { + if (compressions[dso->comp].decompress(name, fd)) { dso->load_errno = DSO_LOAD_ERRNO__DECOMPRESSION_FAILURE; close(fd); fd = -1; } -out: - free(m.ext); + if (!pathname || (fd < 0)) + unlink(tmpbuf); + + if (pathname && (fd >= 0)) + strncpy(pathname, tmpbuf, len); + return fd; } int dso__decompress_kmodule_fd(struct dso *dso, const char *name) { - char tmpbuf[] = KMOD_DECOMP_NAME; - int fd; - - fd = decompress_kmodule(dso, name, tmpbuf); - unlink(tmpbuf); - return fd; + return decompress_kmodule(dso, name, NULL, 0); } int dso__decompress_kmodule_path(struct dso *dso, const char *name, char *pathname, size_t len) { - char tmpbuf[] = KMOD_DECOMP_NAME; - int fd; + int fd = decompress_kmodule(dso, name, pathname, len); - fd = decompress_kmodule(dso, name, tmpbuf); - if (fd < 0) { - unlink(tmpbuf); - return -1; - } - - strncpy(pathname, tmpbuf, len); close(fd); - return 0; + return fd >= 0 ? 0 : -1; } /* @@ -332,7 +331,7 @@ int dso__decompress_kmodule_path(struct dso *dso, const char *name, * Returns 0 if there's no strdup error, -ENOMEM otherwise. */ int __kmod_path__parse(struct kmod_path *m, const char *path, - bool alloc_name, bool alloc_ext) + bool alloc_name) { const char *name = strrchr(path, '/'); const char *ext = strrchr(path, '.'); @@ -372,10 +371,9 @@ int __kmod_path__parse(struct kmod_path *m, const char *path, return 0; } - if (is_supported_compression(ext + 1)) { - m->comp = true; + m->comp = is_supported_compression(ext + 1); + if (m->comp > COMP_ID__NONE) ext -= 3; - } /* Check .ko extension only if there's enough name left. */ if (ext > name) @@ -393,14 +391,6 @@ int __kmod_path__parse(struct kmod_path *m, const char *path, strxfrchar(m->name, '-', '_'); } - if (alloc_ext && m->comp) { - m->ext = strdup(ext + 4); - if (!m->ext) { - free((void *) m->name); - return -ENOMEM; - } - } - return 0; } @@ -413,8 +403,10 @@ void dso__set_module_info(struct dso *dso, struct kmod_path *m, dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE; /* _KMODULE_COMP should be next to _KMODULE */ - if (m->kmod && m->comp) + if (m->kmod && m->comp) { dso->symtab_type++; + dso->comp = m->comp; + } dso__set_short_name(dso, strdup(m->name), true); } @@ -468,6 +460,7 @@ static int __open_dso(struct dso *dso, struct machine *machine) int fd = -EINVAL; char *root_dir = (char *)""; char *name = malloc(PATH_MAX); + bool decomp = false; if (!name) return -ENOMEM; @@ -491,12 +484,13 @@ static int __open_dso(struct dso *dso, struct machine *machine) goto out; } + decomp = true; strcpy(name, newpath); } fd = do_open(name); - if (dso__needs_decompress(dso)) + if (decomp) unlink(name); out: @@ -1218,6 +1212,7 @@ struct dso *dso__new(const char *name) dso->a2l_fails = 1; dso->kernel = DSO_TYPE_USER; dso->needs_swap = DSO_SWAP__UNSET; + dso->comp = COMP_ID__NONE; RB_CLEAR_NODE(&dso->rb_node); dso->root = NULL; INIT_LIST_HEAD(&dso->node); diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index ef69de2e69ea..c5380500bed4 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h @@ -175,6 +175,7 @@ struct dso { u16 short_name_len; void *dwfl; /* DWARF debug info */ struct auxtrace_cache *auxtrace_cache; + int comp; /* dso data file */ struct { @@ -250,9 +251,7 @@ int dso__kernel_module_get_build_id(struct dso *dso, const char *root_dir); char dso__symtab_origin(const struct dso *dso); int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type, char *root_dir, char *filename, size_t size); -bool is_supported_compression(const char *ext); bool is_kernel_module(const char *pathname, int cpumode); -bool decompress_to_file(const char *ext, const char *filename, int output_fd); bool dso__needs_decompress(struct dso *dso); int dso__decompress_kmodule_fd(struct dso *dso, const char *name); int dso__decompress_kmodule_path(struct dso *dso, const char *name, @@ -263,17 +262,15 @@ int dso__decompress_kmodule_path(struct dso *dso, const char *name, struct kmod_path { char *name; - char *ext; - bool comp; + int comp; bool kmod; }; int __kmod_path__parse(struct kmod_path *m, const char *path, - bool alloc_name, bool alloc_ext); + bool alloc_name); -#define kmod_path__parse(__m, __p) __kmod_path__parse(__m, __p, false, false) -#define kmod_path__parse_name(__m, __p) __kmod_path__parse(__m, __p, true , false) -#define kmod_path__parse_ext(__m, __p) __kmod_path__parse(__m, __p, false, true) +#define kmod_path__parse(__m, __p) __kmod_path__parse(__m, __p, false) +#define kmod_path__parse_name(__m, __p) __kmod_path__parse(__m, __p, true) void dso__set_module_info(struct dso *dso, struct kmod_path *m, struct machine *machine); diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 0c8ecf0c78a4..0cd42150f712 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -541,10 +541,17 @@ static int __event__synthesize_thread(union perf_event *comm_event, tgid, process, machine) < 0) return -1; + /* + * send mmap only for thread group leader + * see thread__init_map_groups + */ + if (pid == tgid && + perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, + process, machine, mmap_data, + proc_map_timeout)) + return -1; - return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, - process, machine, mmap_data, - proc_map_timeout); + return 0; } if (machine__is_default_guest(machine)) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index e7a4b31a84fb..be440df29615 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -803,7 +803,7 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, if (*output == -1) { *output = fd; - if (perf_mmap__mmap(&maps[idx], mp, *output) < 0) + if (perf_mmap__mmap(&maps[idx], mp, *output, evlist_cpu) < 0) return -1; } else { if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 94fce4f537e9..c980bbff6353 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -260,6 +260,17 @@ struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx) evsel->attr.sample_period = 1; } + if (perf_evsel__is_clock(evsel)) { + /* + * The evsel->unit points to static alias->unit + * so it's ok to use static string in here. + */ + static const char *unit = "msec"; + + evsel->unit = unit; + evsel->scale = 1e-6; + } + return evsel; } @@ -848,6 +859,12 @@ static void apply_config_terms(struct perf_evsel *evsel, } } +static bool is_dummy_event(struct perf_evsel *evsel) +{ + return (evsel->attr.type == PERF_TYPE_SOFTWARE) && + (evsel->attr.config == PERF_COUNT_SW_DUMMY); +} + /* * The enable_on_exec/disabled value strategy: * @@ -1086,6 +1103,14 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts, else perf_evsel__reset_sample_bit(evsel, PERIOD); } + + /* + * For initial_delay, a dummy event is added implicitly. + * The software event will trigger -EOPNOTSUPP error out, + * if BRANCH_STACK bit is set. + */ + if (opts->initial_delay && is_dummy_event(evsel)) + perf_evsel__reset_sample_bit(evsel, BRANCH_STACK); } static int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) @@ -2658,7 +2683,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, struct format_field *perf_evsel__field(struct perf_evsel *evsel, const char *name) { - return pevent_find_field(evsel->tp_format, name); + return tep_find_field(evsel->tp_format, name); } void *perf_evsel__rawptr(struct perf_evsel *evsel, struct perf_sample *sample, diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index d277930b19a1..163c960614d3 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -402,10 +402,13 @@ bool perf_evsel__is_function_event(struct perf_evsel *evsel); static inline bool perf_evsel__is_bpf_output(struct perf_evsel *evsel) { - struct perf_event_attr *attr = &evsel->attr; + return perf_evsel__match(evsel, SOFTWARE, SW_BPF_OUTPUT); +} - return (attr->config == PERF_COUNT_SW_BPF_OUTPUT) && - (attr->type == PERF_TYPE_SOFTWARE); +static inline bool perf_evsel__is_clock(struct perf_evsel *evsel) +{ + return perf_evsel__match(evsel, SOFTWARE, SW_CPU_CLOCK) || + perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK); } struct perf_attr_details { @@ -449,11 +452,18 @@ static inline int perf_evsel__group_idx(struct perf_evsel *evsel) return evsel->idx - evsel->leader->idx; } +/* Iterates group WITHOUT the leader. */ #define for_each_group_member(_evsel, _leader) \ for ((_evsel) = list_entry((_leader)->node.next, struct perf_evsel, node); \ (_evsel) && (_evsel)->leader == (_leader); \ (_evsel) = list_entry((_evsel)->node.next, struct perf_evsel, node)) +/* Iterates group WITH the leader. */ +#define for_each_group_evsel(_evsel, _leader) \ +for ((_evsel) = _leader; \ + (_evsel) && (_evsel)->leader == (_leader); \ + (_evsel) = list_entry((_evsel)->node.next, struct perf_evsel, node)) + static inline bool perf_evsel__has_branch_callstack(const struct perf_evsel *evsel) { return evsel->attr.branch_sample_type & PERF_SAMPLE_BRANCH_CALL_STACK; diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 653ff65aa2c3..3cadc252dd89 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -279,8 +279,6 @@ static int do_read_bitmap(struct feat_fd *ff, unsigned long **pset, u64 *psize) if (!set) return -ENOMEM; - bitmap_zero(set, size); - p = (u64 *) set; for (i = 0; (u64) i < BITS_TO_U64(size); i++) { @@ -1285,7 +1283,6 @@ static int memory_node__read(struct memory_node *n, unsigned long idx) return -ENOMEM; } - bitmap_zero(n->set, size); n->node = idx; n->size = size; @@ -2587,7 +2584,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = { FEAT_OPR(NUMA_TOPOLOGY, numa_topology, true), FEAT_OPN(BRANCH_STACK, branch_stack, false), FEAT_OPR(PMU_MAPPINGS, pmu_mappings, false), - FEAT_OPN(GROUP_DESC, group_desc, false), + FEAT_OPR(GROUP_DESC, group_desc, false), FEAT_OPN(AUXTRACE, auxtrace, false), FEAT_OPN(STAT, stat, false), FEAT_OPN(CACHE, cache, true), @@ -3207,7 +3204,7 @@ static int read_attr(int fd, struct perf_header *ph, } static int perf_evsel__prepare_tracepoint_event(struct perf_evsel *evsel, - struct pevent *pevent) + struct tep_handle *pevent) { struct event_format *event; char bf[128]; @@ -3221,7 +3218,7 @@ static int perf_evsel__prepare_tracepoint_event(struct perf_evsel *evsel, return -1; } - event = pevent_find_event(pevent, evsel->attr.config); + event = tep_find_event(pevent, evsel->attr.config); if (event == NULL) { pr_debug("cannot find event format for %d\n", (int)evsel->attr.config); return -1; @@ -3239,7 +3236,7 @@ static int perf_evsel__prepare_tracepoint_event(struct perf_evsel *evsel, } static int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist, - struct pevent *pevent) + struct tep_handle *pevent) { struct perf_evsel *pos; diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 73049f7f0f60..3badd7f1e1b8 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -181,7 +181,7 @@ size_t events_stats__fprintf(struct events_stats *stats, FILE *fp); size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, int max_cols, float min_pcnt, FILE *fp, - bool use_callchain); + bool ignore_callchains); size_t perf_evlist__fprintf_nr_events(struct perf_evlist *evlist, FILE *fp); void hists__filter_by_dso(struct hists *hists); diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c index 5e94857dfca2..19262f98cd4e 100644 --- a/tools/perf/util/llvm-utils.c +++ b/tools/perf/util/llvm-utils.c @@ -22,12 +22,14 @@ "$CLANG_OPTIONS $KERNEL_INC_OPTIONS $PERF_BPF_INC_OPTIONS " \ "-Wno-unused-value -Wno-pointer-sign " \ "-working-directory $WORKING_DIR " \ - "-c \"$CLANG_SOURCE\" -target bpf -O2 -o -" + "-c \"$CLANG_SOURCE\" -target bpf $CLANG_EMIT_LLVM -O2 -o - $LLVM_OPTIONS_PIPE" struct llvm_param llvm_param = { .clang_path = "clang", + .llc_path = "llc", .clang_bpf_cmd_template = CLANG_BPF_CMD_DEFAULT_TEMPLATE, .clang_opt = NULL, + .opts = NULL, .kbuild_dir = NULL, .kbuild_opts = NULL, .user_set_param = false, @@ -51,6 +53,8 @@ int perf_llvm_config(const char *var, const char *value) llvm_param.kbuild_opts = strdup(value); else if (!strcmp(var, "dump-obj")) llvm_param.dump_obj = !!perf_config_bool(var, value); + else if (!strcmp(var, "opts")) + llvm_param.opts = strdup(value); else { pr_debug("Invalid LLVM config option: %s\n", value); return -1; @@ -430,11 +434,13 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf, unsigned int kernel_version; char linux_version_code_str[64]; const char *clang_opt = llvm_param.clang_opt; - char clang_path[PATH_MAX], abspath[PATH_MAX], nr_cpus_avail_str[64]; + char clang_path[PATH_MAX], llc_path[PATH_MAX], abspath[PATH_MAX], nr_cpus_avail_str[64]; char serr[STRERR_BUFSIZE]; char *kbuild_dir = NULL, *kbuild_include_opts = NULL, *perf_bpf_include_opts = NULL; const char *template = llvm_param.clang_bpf_cmd_template; + char *pipe_template = NULL; + const char *opts = llvm_param.opts; char *command_echo = NULL, *command_out; char *perf_include_dir = system_path(PERF_INCLUDE_DIR); @@ -484,6 +490,26 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf, force_set_env("PERF_BPF_INC_OPTIONS", perf_bpf_include_opts); force_set_env("WORKING_DIR", kbuild_dir ? : "."); + if (opts) { + err = search_program(llvm_param.llc_path, "llc", llc_path); + if (err) { + pr_err("ERROR:\tunable to find llc.\n" + "Hint:\tTry to install latest clang/llvm to support BPF. Check your $PATH\n" + " \tand 'llc-path' option in [llvm] section of ~/.perfconfig.\n"); + version_notice(); + goto errout; + } + + if (asprintf(&pipe_template, "%s -emit-llvm | %s -march=bpf %s -filetype=obj -o -", + template, llc_path, opts) < 0) { + pr_err("ERROR:\tnot enough memory to setup command line\n"); + goto errout; + } + + template = pipe_template; + + } + /* * Since we may reset clang's working dir, path of source file * should be transferred into absolute path, except we want @@ -535,6 +561,7 @@ errout: free(obj_buf); free(perf_bpf_include_opts); free(perf_include_dir); + free(pipe_template); if (p_obj_buf) *p_obj_buf = NULL; if (p_obj_buf_sz) diff --git a/tools/perf/util/llvm-utils.h b/tools/perf/util/llvm-utils.h index d3ad8deb5db4..bf3f3f4c4fe2 100644 --- a/tools/perf/util/llvm-utils.h +++ b/tools/perf/util/llvm-utils.h @@ -11,6 +11,8 @@ struct llvm_param { /* Path of clang executable */ const char *clang_path; + /* Path of llc executable */ + const char *llc_path; /* * Template of clang bpf compiling. 5 env variables * can be used: @@ -23,6 +25,13 @@ struct llvm_param { const char *clang_bpf_cmd_template; /* Will be filled in $CLANG_OPTIONS */ const char *clang_opt; + /* + * If present it'll add -emit-llvm to $CLANG_OPTIONS to pipe + * the clang output to llc, useful for new llvm options not + * yet selectable via 'clang -mllvm option', such as -mattr=dwarfris + * in clang 6.0/llvm 7 + */ + const char *opts; /* Where to find kbuild system */ const char *kbuild_dir; /* diff --git a/tools/perf/util/lzma.c b/tools/perf/util/lzma.c index 07498eaddc08..b1dd29a9d915 100644 --- a/tools/perf/util/lzma.c +++ b/tools/perf/util/lzma.c @@ -3,9 +3,13 @@ #include <lzma.h> #include <stdio.h> #include <linux/compiler.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> #include "compress.h" #include "util.h" #include "debug.h" +#include <unistd.h> #define BUFSIZE 8192 @@ -99,3 +103,19 @@ err_fclose: fclose(infile); return err; } + +bool lzma_is_compressed(const char *input) +{ + int fd = open(input, O_RDONLY); + const uint8_t magic[6] = { 0xFD, '7', 'z', 'X', 'Z', 0x00 }; + char buf[6] = { 0 }; + ssize_t rc; + + if (fd < 0) + return -1; + + rc = read(fd, buf, sizeof(buf)); + close(fd); + return rc == sizeof(buf) ? + memcmp(buf, magic, sizeof(buf)) == 0 : false; +} diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index e7b4a8b513f2..c4acd2001db0 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -408,23 +408,16 @@ out_err: } /* - * Caller must eventually drop thread->refcnt returned with a successful - * lookup/new thread inserted. + * Front-end cache - TID lookups come in blocks, + * so most of the time we dont have to look up + * the full rbtree: */ -static struct thread *____machine__findnew_thread(struct machine *machine, - struct threads *threads, - pid_t pid, pid_t tid, - bool create) +static struct thread* +__threads__get_last_match(struct threads *threads, struct machine *machine, + int pid, int tid) { - struct rb_node **p = &threads->entries.rb_node; - struct rb_node *parent = NULL; struct thread *th; - /* - * Front-end cache - TID lookups come in blocks, - * so most of the time we dont have to look up - * the full rbtree: - */ th = threads->last_match; if (th != NULL) { if (th->tid == tid) { @@ -435,12 +428,57 @@ static struct thread *____machine__findnew_thread(struct machine *machine, threads->last_match = NULL; } + return NULL; +} + +static struct thread* +threads__get_last_match(struct threads *threads, struct machine *machine, + int pid, int tid) +{ + struct thread *th = NULL; + + if (perf_singlethreaded) + th = __threads__get_last_match(threads, machine, pid, tid); + + return th; +} + +static void +__threads__set_last_match(struct threads *threads, struct thread *th) +{ + threads->last_match = th; +} + +static void +threads__set_last_match(struct threads *threads, struct thread *th) +{ + if (perf_singlethreaded) + __threads__set_last_match(threads, th); +} + +/* + * Caller must eventually drop thread->refcnt returned with a successful + * lookup/new thread inserted. + */ +static struct thread *____machine__findnew_thread(struct machine *machine, + struct threads *threads, + pid_t pid, pid_t tid, + bool create) +{ + struct rb_node **p = &threads->entries.rb_node; + struct rb_node *parent = NULL; + struct thread *th; + + th = threads__get_last_match(threads, machine, pid, tid); + if (th) + return th; + while (*p != NULL) { parent = *p; th = rb_entry(parent, struct thread, rb_node); if (th->tid == tid) { - threads->last_match = th; + threads__set_last_match(threads, th); machine__update_thread_pid(machine, th, pid); return thread__get(th); } @@ -477,7 +515,7 @@ static struct thread *____machine__findnew_thread(struct machine *machine, * It is now in the rbtree, get a ref */ thread__get(th); - threads->last_match = th; + threads__set_last_match(threads, th); ++threads->nr; } @@ -1174,8 +1212,10 @@ static int map_groups__set_module_path(struct map_groups *mg, const char *path, * Full name could reveal us kmod compression, so * we need to update the symtab_type if needed. */ - if (m->comp && is_kmod_dso(map->dso)) + if (m->comp && is_kmod_dso(map->dso)) { map->dso->symtab_type++; + map->dso->comp = m->comp; + } return 0; } @@ -1635,7 +1675,7 @@ static void __machine__remove_thread(struct machine *machine, struct thread *th, struct threads *threads = machine__threads(machine, th->tid); if (threads->last_match == th) - threads->last_match = NULL; + threads__set_last_match(threads, NULL); BUG_ON(refcount_read(&th->refcnt) == 0); if (lock) @@ -2272,6 +2312,7 @@ static int unwind_entry(struct unwind_entry *entry, void *arg) { struct callchain_cursor *cursor = arg; const char *srcline = NULL; + u64 addr; if (symbol_conf.hide_unresolved && entry->sym == NULL) return 0; @@ -2279,7 +2320,13 @@ static int unwind_entry(struct unwind_entry *entry, void *arg) if (append_inlines(cursor, entry->map, entry->sym, entry->ip) == 0) return 0; - srcline = callchain_srcline(entry->map, entry->sym, entry->ip); + /* + * Convert entry->ip from a virtual address to an offset in + * its corresponding binary. + */ + addr = map__map_ip(entry->map, entry->ip); + + srcline = callchain_srcline(entry->map, entry->sym, addr); return callchain_cursor_append(cursor, entry->ip, entry->map, entry->sym, false, NULL, 0, 0, 0, srcline); diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index 1de7660d93e9..d856b85862e2 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h @@ -265,7 +265,7 @@ pid_t machine__get_current_tid(struct machine *machine, int cpu); int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid, pid_t tid); /* - * For use with libtraceevent's pevent_set_function_resolver() + * For use with libtraceevent's tep_set_function_resolver() */ char *machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp); diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 89ac5b5dc218..36d0763311ef 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -381,20 +381,6 @@ struct map *map__clone(struct map *from) return map; } -int map__overlap(struct map *l, struct map *r) -{ - if (l->start > r->start) { - struct map *t = l; - l = r; - r = t; - } - - if (l->end > r->start) - return 1; - - return 0; -} - size_t map__fprintf(struct map *map, FILE *fp) { return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n", @@ -675,20 +661,42 @@ static void __map_groups__insert(struct map_groups *mg, struct map *map) static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) { struct rb_root *root; - struct rb_node *next; + struct rb_node *next, *first; int err = 0; down_write(&maps->lock); root = &maps->entries; - next = rb_first(root); + /* + * Find first map where end > map->start. + * Same as find_vma() in kernel. + */ + next = root->rb_node; + first = NULL; + while (next) { + struct map *pos = rb_entry(next, struct map, rb_node); + + if (pos->end > map->start) { + first = next; + if (pos->start <= map->start) + break; + next = next->rb_left; + } else + next = next->rb_right; + } + + next = first; while (next) { struct map *pos = rb_entry(next, struct map, rb_node); next = rb_next(&pos->rb_node); - if (!map__overlap(pos, map)) - continue; + /* + * Stop if current map starts after map->end. + * Maps are ordered by start: next will not overlap for sure. + */ + if (pos->start >= map->end) + break; if (verbose >= 2) { diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 4cb90f242bed..e0f327b51e66 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -166,7 +166,6 @@ static inline void __map__zput(struct map **map) #define map__zput(map) __map__zput(&map) -int map__overlap(struct map *l, struct map *r); size_t map__fprintf(struct map *map, FILE *fp); size_t map__fprintf_dsoname(struct map *map, FILE *fp); char *map__srcline(struct map *map, u64 addr, struct symbol *sym); diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c index 1ddc3d1d0147..a28f9b5cc4ff 100644 --- a/tools/perf/util/metricgroup.c +++ b/tools/perf/util/metricgroup.c @@ -326,8 +326,8 @@ void metricgroup__print(bool metrics, bool metricgroups, char *filter, if (raw) s = (char *)pe->metric_name; else { - if (asprintf(&s, "%s\n\t[%s]", - pe->metric_name, pe->desc) < 0) + if (asprintf(&s, "%s\n%*s%s]", + pe->metric_name, 8, "[", pe->desc) < 0) return; } @@ -490,3 +490,25 @@ out: metricgroup__free_egroups(&group_list); return ret; } + +bool metricgroup__has_metric(const char *metric) +{ + struct pmu_events_map *map = perf_pmu__find_map(NULL); + struct pmu_event *pe; + int i; + + if (!map) + return false; + + for (i = 0; ; i++) { + pe = &map->table[i]; + + if (!pe->name && !pe->metric_group && !pe->metric_name) + break; + if (!pe->metric_expr) + continue; + if (match_metric(pe->metric_name, metric)) + return true; + } + return false; +} diff --git a/tools/perf/util/metricgroup.h b/tools/perf/util/metricgroup.h index 06854e125ee7..8a155dba0581 100644 --- a/tools/perf/util/metricgroup.h +++ b/tools/perf/util/metricgroup.h @@ -28,4 +28,5 @@ int metricgroup__parse_groups(const struct option *opt, struct rblist *metric_events); void metricgroup__print(bool metrics, bool groups, char *filter, bool raw); +bool metricgroup__has_metric(const char *metric); #endif diff --git a/tools/perf/util/mmap.c b/tools/perf/util/mmap.c index fc832676a798..215f69f41672 100644 --- a/tools/perf/util/mmap.c +++ b/tools/perf/util/mmap.c @@ -164,7 +164,7 @@ void perf_mmap__munmap(struct perf_mmap *map) auxtrace_mmap__munmap(&map->auxtrace_mmap); } -int perf_mmap__mmap(struct perf_mmap *map, struct mmap_params *mp, int fd) +int perf_mmap__mmap(struct perf_mmap *map, struct mmap_params *mp, int fd, int cpu) { /* * The last one will be done at perf_mmap__consume(), so that we @@ -191,6 +191,7 @@ int perf_mmap__mmap(struct perf_mmap *map, struct mmap_params *mp, int fd) return -1; } map->fd = fd; + map->cpu = cpu; if (auxtrace_mmap__mmap(&map->auxtrace_mmap, &mp->auxtrace_mp, map->base, fd)) diff --git a/tools/perf/util/mmap.h b/tools/perf/util/mmap.h index d82294db1295..05a6d47c7956 100644 --- a/tools/perf/util/mmap.h +++ b/tools/perf/util/mmap.h @@ -18,6 +18,7 @@ struct perf_mmap { void *base; int mask; int fd; + int cpu; refcount_t refcnt; u64 prev; u64 start; @@ -60,7 +61,7 @@ struct mmap_params { struct auxtrace_mmap_params auxtrace_mp; }; -int perf_mmap__mmap(struct perf_mmap *map, struct mmap_params *mp, int fd); +int perf_mmap__mmap(struct perf_mmap *map, struct mmap_params *mp, int fd, int cpu); void perf_mmap__munmap(struct perf_mmap *map); void perf_mmap__get(struct perf_mmap *map); diff --git a/tools/perf/util/namespaces.c b/tools/perf/util/namespaces.c index 5be021701f34..cf8bd123cf73 100644 --- a/tools/perf/util/namespaces.c +++ b/tools/perf/util/namespaces.c @@ -139,6 +139,9 @@ struct nsinfo *nsinfo__copy(struct nsinfo *nsi) { struct nsinfo *nnsi; + if (nsi == NULL) + return NULL; + nnsi = calloc(1, sizeof(*nnsi)); if (nnsi != NULL) { nnsi->pid = nsi->pid; diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 15eec49e71a1..f8cd3e7c9186 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1991,8 +1991,11 @@ static int set_filter(struct perf_evsel *evsel, const void *arg) int nr_addr_filters = 0; struct perf_pmu *pmu = NULL; - if (evsel == NULL) - goto err; + if (evsel == NULL) { + fprintf(stderr, + "--filter option should follow a -e tracepoint or HW tracer option\n"); + return -1; + } if (evsel->attr.type == PERF_TYPE_TRACEPOINT) { if (perf_evsel__append_tp_filter(evsel, str) < 0) { @@ -2014,8 +2017,11 @@ static int set_filter(struct perf_evsel *evsel, const void *arg) perf_pmu__scan_file(pmu, "nr_addr_filters", "%d", &nr_addr_filters); - if (!nr_addr_filters) - goto err; + if (!nr_addr_filters) { + fprintf(stderr, + "This CPU does not support address filtering\n"); + return -1; + } if (perf_evsel__append_addr_filter(evsel, str) < 0) { fprintf(stderr, @@ -2024,12 +2030,6 @@ static int set_filter(struct perf_evsel *evsel, const void *arg) } return 0; - -err: - fprintf(stderr, - "--filter option should follow a -e tracepoint or HW tracer option\n"); - - return -1; } int parse_filter(const struct option *opt, const char *str, diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 3ba6a1742f91..afd68524ffa9 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -652,12 +652,6 @@ static int is_arm_pmu_core(const char *name) if (stat(path, &st) == 0) return 1; - /* Look for cpu sysfs (specific to s390) */ - scnprintf(path, PATH_MAX, "%s/bus/event_source/devices/%s", - sysfs, name); - if (stat(path, &st) == 0 && !strncmp(name, "cpum_", 5)) - return 1; - return 0; } diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 863b61478edd..ce501ba14b08 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -11,6 +11,7 @@ #include "cpumap.h" #include "print_binary.h" #include "thread_map.h" +#include "mmap.h" #if PY_MAJOR_VERSION < 3 #define _PyUnicode_FromString(arg) \ @@ -341,7 +342,7 @@ static bool is_tracepoint(struct pyrf_event *pevent) static PyObject* tracepoint_field(struct pyrf_event *pe, struct format_field *field) { - struct pevent *pevent = field->event->pevent; + struct tep_handle *pevent = field->event->pevent; void *data = pe->sample.raw_data; PyObject *ret = NULL; unsigned long long val; @@ -351,7 +352,7 @@ tracepoint_field(struct pyrf_event *pe, struct format_field *field) offset = field->offset; len = field->size; if (field->flags & FIELD_IS_DYNAMIC) { - val = pevent_read_number(pevent, data + offset, len); + val = tep_read_number(pevent, data + offset, len); offset = val; len = offset >> 16; offset &= 0xffff; @@ -364,8 +365,8 @@ tracepoint_field(struct pyrf_event *pe, struct format_field *field) field->flags &= ~FIELD_IS_STRING; } } else { - val = pevent_read_number(pevent, data + field->offset, - field->size); + val = tep_read_number(pevent, data + field->offset, + field->size); if (field->flags & FIELD_IS_POINTER) ret = PyLong_FromUnsignedLong((unsigned long) val); else if (field->flags & FIELD_IS_SIGNED) @@ -394,7 +395,7 @@ get_tracepoint_field(struct pyrf_event *pevent, PyObject *attr_name) evsel->tp_format = tp_format; } - field = pevent_find_any_field(evsel->tp_format, str); + field = tep_find_any_field(evsel->tp_format, str); if (!field) return NULL; @@ -976,6 +977,20 @@ static PyObject *pyrf_evlist__add(struct pyrf_evlist *pevlist, return Py_BuildValue("i", evlist->nr_entries); } +static struct perf_mmap *get_md(struct perf_evlist *evlist, int cpu) +{ + int i; + + for (i = 0; i < evlist->nr_mmaps; i++) { + struct perf_mmap *md = &evlist->mmap[i]; + + if (md->cpu == cpu) + return md; + } + + return NULL; +} + static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, PyObject *args, PyObject *kwargs) { @@ -990,7 +1005,10 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, &cpu, &sample_id_all)) return NULL; - md = &evlist->mmap[cpu]; + md = get_md(evlist, cpu); + if (!md) + return NULL; + if (perf_mmap__read_init(md) < 0) goto end; diff --git a/tools/perf/util/s390-cpumsf-kernel.h b/tools/perf/util/s390-cpumsf-kernel.h new file mode 100644 index 000000000000..de8c7ad0eca8 --- /dev/null +++ b/tools/perf/util/s390-cpumsf-kernel.h @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Auxtrace support for s390 CPU measurement sampling facility + * + * Copyright IBM Corp. 2018 + * Author(s): Hendrik Brueckner <brueckner@linux.ibm.com> + * Thomas Richter <tmricht@linux.ibm.com> + */ +#ifndef S390_CPUMSF_KERNEL_H +#define S390_CPUMSF_KERNEL_H + +#define S390_CPUMSF_PAGESZ 4096 /* Size of sample block units */ +#define S390_CPUMSF_DIAG_DEF_FIRST 0x8001 /* Diagnostic entry lowest id */ + +struct hws_basic_entry { + unsigned int def:16; /* 0-15 Data Entry Format */ + unsigned int R:4; /* 16-19 reserved */ + unsigned int U:4; /* 20-23 Number of unique instruct. */ + unsigned int z:2; /* zeros */ + unsigned int T:1; /* 26 PSW DAT mode */ + unsigned int W:1; /* 27 PSW wait state */ + unsigned int P:1; /* 28 PSW Problem state */ + unsigned int AS:2; /* 29-30 PSW address-space control */ + unsigned int I:1; /* 31 entry valid or invalid */ + unsigned int CL:2; /* 32-33 Configuration Level */ + unsigned int:14; + unsigned int prim_asn:16; /* primary ASN */ + unsigned long long ia; /* Instruction Address */ + unsigned long long gpp; /* Guest Program Parameter */ + unsigned long long hpp; /* Host Program Parameter */ +}; + +struct hws_diag_entry { + unsigned int def:16; /* 0-15 Data Entry Format */ + unsigned int R:15; /* 16-19 and 20-30 reserved */ + unsigned int I:1; /* 31 entry valid or invalid */ + u8 data[]; /* Machine-dependent sample data */ +}; + +struct hws_combined_entry { + struct hws_basic_entry basic; /* Basic-sampling data entry */ + struct hws_diag_entry diag; /* Diagnostic-sampling data entry */ +}; + +struct hws_trailer_entry { + union { + struct { + unsigned int f:1; /* 0 - Block Full Indicator */ + unsigned int a:1; /* 1 - Alert request control */ + unsigned int t:1; /* 2 - Timestamp format */ + unsigned int:29; /* 3 - 31: Reserved */ + unsigned int bsdes:16; /* 32-47: size of basic SDE */ + unsigned int dsdes:16; /* 48-63: size of diagnostic SDE */ + }; + unsigned long long flags; /* 0 - 64: All indicators */ + }; + unsigned long long overflow; /* 64 - sample Overflow count */ + unsigned char timestamp[16]; /* 16 - 31 timestamp */ + unsigned long long reserved1; /* 32 -Reserved */ + unsigned long long reserved2; /* */ + union { /* 48 - reserved for programming use */ + struct { + unsigned long long clock_base:1; /* in progusage2 */ + unsigned long long progusage1:63; + unsigned long long progusage2; + }; + unsigned long long progusage[2]; + }; +}; + +#endif diff --git a/tools/perf/util/s390-cpumsf.c b/tools/perf/util/s390-cpumsf.c new file mode 100644 index 000000000000..d2c78ffd9fee --- /dev/null +++ b/tools/perf/util/s390-cpumsf.c @@ -0,0 +1,945 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright IBM Corp. 2018 + * Auxtrace support for s390 CPU-Measurement Sampling Facility + * + * Author(s): Thomas Richter <tmricht@linux.ibm.com> + * + * Auxiliary traces are collected during 'perf record' using rbd000 event. + * Several PERF_RECORD_XXX are generated during recording: + * + * PERF_RECORD_AUX: + * Records that new data landed in the AUX buffer part. + * PERF_RECORD_AUXTRACE: + * Defines auxtrace data. Followed by the actual data. The contents of + * the auxtrace data is dependent on the event and the CPU. + * This record is generated by perf record command. For details + * see Documentation/perf.data-file-format.txt. + * PERF_RECORD_AUXTRACE_INFO: + * Defines a table of contains for PERF_RECORD_AUXTRACE records. This + * record is generated during 'perf record' command. Each record contains up + * to 256 entries describing offset and size of the AUXTRACE data in the + * perf.data file. + * PERF_RECORD_AUXTRACE_ERROR: + * Indicates an error during AUXTRACE collection such as buffer overflow. + * PERF_RECORD_FINISHED_ROUND: + * Perf events are not necessarily in time stamp order, as they can be + * collected in parallel on different CPUs. If the events should be + * processed in time order they need to be sorted first. + * Perf report guarantees that there is no reordering over a + * PERF_RECORD_FINISHED_ROUND boundary event. All perf records with a + * time stamp lower than this record are processed (and displayed) before + * the succeeding perf record are processed. + * + * These records are evaluated during perf report command. + * + * 1. PERF_RECORD_AUXTRACE_INFO is used to set up the infrastructure for + * auxiliary trace data processing. See s390_cpumsf_process_auxtrace_info() + * below. + * Auxiliary trace data is collected per CPU. To merge the data into the report + * an auxtrace_queue is created for each CPU. It is assumed that the auxtrace + * data is in ascending order. + * + * Each queue has a double linked list of auxtrace_buffers. This list contains + * the offset and size of a CPU's auxtrace data. During auxtrace processing + * the data portion is mmap()'ed. + * + * To sort the queues in chronological order, all queue access is controlled + * by the auxtrace_heap. This is basicly a stack, each stack element has two + * entries, the queue number and a time stamp. However the stack is sorted by + * the time stamps. The highest time stamp is at the bottom the lowest + * (nearest) time stamp is at the top. That sort order is maintained at all + * times! + * + * After the auxtrace infrastructure has been setup, the auxtrace queues are + * filled with data (offset/size pairs) and the auxtrace_heap is populated. + * + * 2. PERF_RECORD_XXX processing triggers access to the auxtrace_queues. + * Each record is handled by s390_cpumsf_process_event(). The time stamp of + * the perf record is compared with the time stamp located on the auxtrace_heap + * top element. If that time stamp is lower than the time stamp from the + * record sample, the auxtrace queues will be processed. As auxtrace queues + * control many auxtrace_buffers and each buffer can be quite large, the + * auxtrace buffer might be processed only partially. In this case the + * position in the auxtrace_buffer of that queue is remembered and the time + * stamp of the last processed entry of the auxtrace_buffer replaces the + * current auxtrace_heap top. + * + * 3. Auxtrace_queues might run of out data and are feeded by the + * PERF_RECORD_AUXTRACE handling, see s390_cpumsf_process_auxtrace_event(). + * + * Event Generation + * Each sampling-data entry in the auxilary trace data generates a perf sample. + * This sample is filled + * with data from the auxtrace such as PID/TID, instruction address, CPU state, + * etc. This sample is processed with perf_session__deliver_synth_event() to + * be included into the GUI. + * + * 4. PERF_RECORD_FINISHED_ROUND event is used to process all the remaining + * auxiliary traces entries until the time stamp of this record is reached + * auxtrace_heap top. This is triggered by ordered_event->deliver(). + * + * + * Perf event processing. + * Event processing of PERF_RECORD_XXX entries relies on time stamp entries. + * This is the function call sequence: + * + * __cmd_report() + * | + * perf_session__process_events() + * | + * __perf_session__process_events() + * | + * perf_session__process_event() + * | This functions splits the PERF_RECORD_XXX records. + * | - Those generated by perf record command (type number equal or higher + * | than PERF_RECORD_USER_TYPE_START) are handled by + * | perf_session__process_user_event(see below) + * | - Those generated by the kernel are handled by + * | perf_evlist__parse_sample_timestamp() + * | + * perf_evlist__parse_sample_timestamp() + * | Extract time stamp from sample data. + * | + * perf_session__queue_event() + * | If timestamp is positive the sample is entered into an ordered_event + * | list, sort order is the timestamp. The event processing is deferred until + * | later (see perf_session__process_user_event()). + * | Other timestamps (0 or -1) are handled immediately by + * | perf_session__deliver_event(). These are events generated at start up + * | of command perf record. They create PERF_RECORD_COMM and PERF_RECORD_MMAP* + * | records. They are needed to create a list of running processes and its + * | memory mappings and layout. They are needed at the beginning to enable + * | command perf report to create process trees and memory mappings. + * | + * perf_session__deliver_event() + * | Delivers a PERF_RECORD_XXX entry for handling. + * | + * auxtrace__process_event() + * | The timestamp of the PERF_RECORD_XXX entry is taken to correlate with + * | time stamps from the auxiliary trace buffers. This enables + * | synchronization between auxiliary trace data and the events on the + * | perf.data file. + * | + * machine__deliver_event() + * | Handles the PERF_RECORD_XXX event. This depends on the record type. + * It might update the process tree, update a process memory map or enter + * a sample with IP and call back chain data into GUI data pool. + * + * + * Deferred processing determined by perf_session__process_user_event() is + * finally processed when a PERF_RECORD_FINISHED_ROUND is encountered. These + * are generated during command perf record. + * The timestamp of PERF_RECORD_FINISHED_ROUND event is taken to process all + * PERF_RECORD_XXX entries stored in the ordered_event list. This list was + * built up while reading the perf.data file. + * Each event is now processed by calling perf_session__deliver_event(). + * This enables time synchronization between the data in the perf.data file and + * the data in the auxiliary trace buffers. + */ + +#include <endian.h> +#include <errno.h> +#include <byteswap.h> +#include <inttypes.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/bitops.h> +#include <linux/log2.h> + +#include "cpumap.h" +#include "color.h" +#include "evsel.h" +#include "evlist.h" +#include "machine.h" +#include "session.h" +#include "util.h" +#include "thread.h" +#include "debug.h" +#include "auxtrace.h" +#include "s390-cpumsf.h" +#include "s390-cpumsf-kernel.h" + +struct s390_cpumsf { + struct auxtrace auxtrace; + struct auxtrace_queues queues; + struct auxtrace_heap heap; + struct perf_session *session; + struct machine *machine; + u32 auxtrace_type; + u32 pmu_type; + u16 machine_type; + bool data_queued; +}; + +struct s390_cpumsf_queue { + struct s390_cpumsf *sf; + unsigned int queue_nr; + struct auxtrace_buffer *buffer; + int cpu; +}; + +/* Display s390 CPU measurement facility basic-sampling data entry */ +static bool s390_cpumsf_basic_show(const char *color, size_t pos, + struct hws_basic_entry *basic) +{ + if (basic->def != 1) { + pr_err("Invalid AUX trace basic entry [%#08zx]\n", pos); + return false; + } + color_fprintf(stdout, color, " [%#08zx] Basic Def:%04x Inst:%#04x" + " %c%c%c%c AS:%d ASN:%#04x IA:%#018llx\n" + "\t\tCL:%d HPP:%#018llx GPP:%#018llx\n", + pos, basic->def, basic->U, + basic->T ? 'T' : ' ', + basic->W ? 'W' : ' ', + basic->P ? 'P' : ' ', + basic->I ? 'I' : ' ', + basic->AS, basic->prim_asn, basic->ia, basic->CL, + basic->hpp, basic->gpp); + return true; +} + +/* Display s390 CPU measurement facility diagnostic-sampling data entry */ +static bool s390_cpumsf_diag_show(const char *color, size_t pos, + struct hws_diag_entry *diag) +{ + if (diag->def < S390_CPUMSF_DIAG_DEF_FIRST) { + pr_err("Invalid AUX trace diagnostic entry [%#08zx]\n", pos); + return false; + } + color_fprintf(stdout, color, " [%#08zx] Diag Def:%04x %c\n", + pos, diag->def, diag->I ? 'I' : ' '); + return true; +} + +/* Return TOD timestamp contained in an trailer entry */ +static unsigned long long trailer_timestamp(struct hws_trailer_entry *te) +{ + /* te->t set: TOD in STCKE format, bytes 8-15 + * to->t not set: TOD in STCK format, bytes 0-7 + */ + unsigned long long ts; + + memcpy(&ts, &te->timestamp[te->t], sizeof(ts)); + return ts; +} + +/* Display s390 CPU measurement facility trailer entry */ +static bool s390_cpumsf_trailer_show(const char *color, size_t pos, + struct hws_trailer_entry *te) +{ + if (te->bsdes != sizeof(struct hws_basic_entry)) { + pr_err("Invalid AUX trace trailer entry [%#08zx]\n", pos); + return false; + } + color_fprintf(stdout, color, " [%#08zx] Trailer %c%c%c bsdes:%d" + " dsdes:%d Overflow:%lld Time:%#llx\n" + "\t\tC:%d TOD:%#lx 1:%#llx 2:%#llx\n", + pos, + te->f ? 'F' : ' ', + te->a ? 'A' : ' ', + te->t ? 'T' : ' ', + te->bsdes, te->dsdes, te->overflow, + trailer_timestamp(te), te->clock_base, te->progusage2, + te->progusage[0], te->progusage[1]); + return true; +} + +/* Test a sample data block. It must be 4KB or a multiple thereof in size and + * 4KB page aligned. Each sample data page has a trailer entry at the + * end which contains the sample entry data sizes. + * + * Return true if the sample data block passes the checks and set the + * basic set entry size and diagnostic set entry size. + * + * Return false on failure. + * + * Note: Old hardware does not set the basic or diagnostic entry sizes + * in the trailer entry. Use the type number instead. + */ +static bool s390_cpumsf_validate(int machine_type, + unsigned char *buf, size_t len, + unsigned short *bsdes, + unsigned short *dsdes) +{ + struct hws_basic_entry *basic = (struct hws_basic_entry *)buf; + struct hws_trailer_entry *te; + + *dsdes = *bsdes = 0; + if (len & (S390_CPUMSF_PAGESZ - 1)) /* Illegal size */ + return false; + if (basic->def != 1) /* No basic set entry, must be first */ + return false; + /* Check for trailer entry at end of SDB */ + te = (struct hws_trailer_entry *)(buf + S390_CPUMSF_PAGESZ + - sizeof(*te)); + *bsdes = te->bsdes; + *dsdes = te->dsdes; + if (!te->bsdes && !te->dsdes) { + /* Very old hardware, use CPUID */ + switch (machine_type) { + case 2097: + case 2098: + *dsdes = 64; + *bsdes = 32; + break; + case 2817: + case 2818: + *dsdes = 74; + *bsdes = 32; + break; + case 2827: + case 2828: + *dsdes = 85; + *bsdes = 32; + break; + default: + /* Illegal trailer entry */ + return false; + } + } + return true; +} + +/* Return true if there is room for another entry */ +static bool s390_cpumsf_reached_trailer(size_t entry_sz, size_t pos) +{ + size_t payload = S390_CPUMSF_PAGESZ - sizeof(struct hws_trailer_entry); + + if (payload - (pos & (S390_CPUMSF_PAGESZ - 1)) < entry_sz) + return false; + return true; +} + +/* Dump an auxiliary buffer. These buffers are multiple of + * 4KB SDB pages. + */ +static void s390_cpumsf_dump(struct s390_cpumsf *sf, + unsigned char *buf, size_t len) +{ + const char *color = PERF_COLOR_BLUE; + struct hws_basic_entry *basic; + struct hws_diag_entry *diag; + unsigned short bsdes, dsdes; + size_t pos = 0; + + color_fprintf(stdout, color, + ". ... s390 AUX data: size %zu bytes\n", + len); + + if (!s390_cpumsf_validate(sf->machine_type, buf, len, &bsdes, + &dsdes)) { + pr_err("Invalid AUX trace data block size:%zu" + " (type:%d bsdes:%hd dsdes:%hd)\n", + len, sf->machine_type, bsdes, dsdes); + return; + } + + /* s390 kernel always returns 4KB blocks fully occupied, + * no partially filled SDBs. + */ + while (pos < len) { + /* Handle Basic entry */ + basic = (struct hws_basic_entry *)(buf + pos); + if (s390_cpumsf_basic_show(color, pos, basic)) + pos += bsdes; + else + return; + + /* Handle Diagnostic entry */ + diag = (struct hws_diag_entry *)(buf + pos); + if (s390_cpumsf_diag_show(color, pos, diag)) + pos += dsdes; + else + return; + + /* Check for trailer entry */ + if (!s390_cpumsf_reached_trailer(bsdes + dsdes, pos)) { + /* Show trailer entry */ + struct hws_trailer_entry te; + + pos = (pos + S390_CPUMSF_PAGESZ) + & ~(S390_CPUMSF_PAGESZ - 1); + pos -= sizeof(te); + memcpy(&te, buf + pos, sizeof(te)); + /* Set descriptor sizes in case of old hardware + * where these values are not set. + */ + te.bsdes = bsdes; + te.dsdes = dsdes; + if (s390_cpumsf_trailer_show(color, pos, &te)) + pos += sizeof(te); + else + return; + } + } +} + +static void s390_cpumsf_dump_event(struct s390_cpumsf *sf, unsigned char *buf, + size_t len) +{ + printf(".\n"); + s390_cpumsf_dump(sf, buf, len); +} + +#define S390_LPP_PID_MASK 0xffffffff + +static bool s390_cpumsf_make_event(size_t pos, + struct hws_basic_entry *basic, + struct s390_cpumsf_queue *sfq) +{ + struct perf_sample sample = { + .ip = basic->ia, + .pid = basic->hpp & S390_LPP_PID_MASK, + .tid = basic->hpp & S390_LPP_PID_MASK, + .cpumode = PERF_RECORD_MISC_CPUMODE_UNKNOWN, + .cpu = sfq->cpu, + .period = 1 + }; + union perf_event event; + + memset(&event, 0, sizeof(event)); + if (basic->CL == 1) /* Native LPAR mode */ + sample.cpumode = basic->P ? PERF_RECORD_MISC_USER + : PERF_RECORD_MISC_KERNEL; + else if (basic->CL == 2) /* Guest kernel/user space */ + sample.cpumode = basic->P ? PERF_RECORD_MISC_GUEST_USER + : PERF_RECORD_MISC_GUEST_KERNEL; + else if (basic->gpp || basic->prim_asn != 0xffff) + /* Use heuristics on old hardware */ + sample.cpumode = basic->P ? PERF_RECORD_MISC_GUEST_USER + : PERF_RECORD_MISC_GUEST_KERNEL; + else + sample.cpumode = basic->P ? PERF_RECORD_MISC_USER + : PERF_RECORD_MISC_KERNEL; + + event.sample.header.type = PERF_RECORD_SAMPLE; + event.sample.header.misc = sample.cpumode; + event.sample.header.size = sizeof(struct perf_event_header); + + pr_debug4("%s pos:%#zx ip:%#" PRIx64 " P:%d CL:%d pid:%d.%d cpumode:%d cpu:%d\n", + __func__, pos, sample.ip, basic->P, basic->CL, sample.pid, + sample.tid, sample.cpumode, sample.cpu); + if (perf_session__deliver_synth_event(sfq->sf->session, &event, + &sample)) { + pr_err("s390 Auxiliary Trace: failed to deliver event\n"); + return false; + } + return true; +} + +static unsigned long long get_trailer_time(const unsigned char *buf) +{ + struct hws_trailer_entry *te; + unsigned long long aux_time; + + te = (struct hws_trailer_entry *)(buf + S390_CPUMSF_PAGESZ + - sizeof(*te)); + + if (!te->clock_base) /* TOD_CLOCK_BASE value missing */ + return 0; + + /* Correct calculation to convert time stamp in trailer entry to + * nano seconds (taken from arch/s390 function tod_to_ns()). + * TOD_CLOCK_BASE is stored in trailer entry member progusage2. + */ + aux_time = trailer_timestamp(te) - te->progusage2; + aux_time = (aux_time >> 9) * 125 + (((aux_time & 0x1ff) * 125) >> 9); + return aux_time; +} + +/* Process the data samples of a single queue. The first parameter is a + * pointer to the queue, the second parameter is the time stamp. This + * is the time stamp: + * - of the event that triggered this processing. + * - or the time stamp when the last proccesing of this queue stopped. + * In this case it stopped at a 4KB page boundary and record the + * position on where to continue processing on the next invocation + * (see buffer->use_data and buffer->use_size). + * + * When this function returns the second parameter is updated to + * reflect the time stamp of the last processed auxiliary data entry + * (taken from the trailer entry of that page). The caller uses this + * returned time stamp to record the last processed entry in this + * queue. + * + * The function returns: + * 0: Processing successful. The second parameter returns the + * time stamp from the trailer entry until which position + * processing took place. Subsequent calls resume from this + * position. + * <0: An error occurred during processing. The second parameter + * returns the maximum time stamp. + * >0: Done on this queue. The second parameter returns the + * maximum time stamp. + */ +static int s390_cpumsf_samples(struct s390_cpumsf_queue *sfq, u64 *ts) +{ + struct s390_cpumsf *sf = sfq->sf; + unsigned char *buf = sfq->buffer->use_data; + size_t len = sfq->buffer->use_size; + struct hws_basic_entry *basic; + unsigned short bsdes, dsdes; + size_t pos = 0; + int err = 1; + u64 aux_ts; + + if (!s390_cpumsf_validate(sf->machine_type, buf, len, &bsdes, + &dsdes)) { + *ts = ~0ULL; + return -1; + } + + /* Get trailer entry time stamp and check if entries in + * this auxiliary page are ready for processing. If the + * time stamp of the first entry is too high, whole buffer + * can be skipped. In this case return time stamp. + */ + aux_ts = get_trailer_time(buf); + if (!aux_ts) { + pr_err("[%#08" PRIx64 "] Invalid AUX trailer entry TOD clock base\n", + sfq->buffer->data_offset); + aux_ts = ~0ULL; + goto out; + } + if (aux_ts > *ts) { + *ts = aux_ts; + return 0; + } + + while (pos < len) { + /* Handle Basic entry */ + basic = (struct hws_basic_entry *)(buf + pos); + if (s390_cpumsf_make_event(pos, basic, sfq)) + pos += bsdes; + else { + err = -EBADF; + goto out; + } + + pos += dsdes; /* Skip diagnositic entry */ + + /* Check for trailer entry */ + if (!s390_cpumsf_reached_trailer(bsdes + dsdes, pos)) { + pos = (pos + S390_CPUMSF_PAGESZ) + & ~(S390_CPUMSF_PAGESZ - 1); + /* Check existence of next page */ + if (pos >= len) + break; + aux_ts = get_trailer_time(buf + pos); + if (!aux_ts) { + aux_ts = ~0ULL; + goto out; + } + if (aux_ts > *ts) { + *ts = aux_ts; + sfq->buffer->use_data += pos; + sfq->buffer->use_size -= pos; + return 0; + } + } + } +out: + *ts = aux_ts; + sfq->buffer->use_size = 0; + sfq->buffer->use_data = NULL; + return err; /* Buffer completely scanned or error */ +} + +/* Run the s390 auxiliary trace decoder. + * Select the queue buffer to operate on, the caller already selected + * the proper queue, depending on second parameter 'ts'. + * This is the time stamp until which the auxiliary entries should + * be processed. This value is updated by called functions and + * returned to the caller. + * + * Resume processing in the current buffer. If there is no buffer + * get a new buffer from the queue and setup start position for + * processing. + * When a buffer is completely processed remove it from the queue + * before returning. + * + * This function returns + * 1: When the queue is empty. Second parameter will be set to + * maximum time stamp. + * 0: Normal processing done. + * <0: Error during queue buffer setup. This causes the caller + * to stop processing completely. + */ +static int s390_cpumsf_run_decoder(struct s390_cpumsf_queue *sfq, + u64 *ts) +{ + + struct auxtrace_buffer *buffer; + struct auxtrace_queue *queue; + int err; + + queue = &sfq->sf->queues.queue_array[sfq->queue_nr]; + + /* Get buffer and last position in buffer to resume + * decoding the auxiliary entries. One buffer might be large + * and decoding might stop in between. This depends on the time + * stamp of the trailer entry in each page of the auxiliary + * data and the time stamp of the event triggering the decoding. + */ + if (sfq->buffer == NULL) { + sfq->buffer = buffer = auxtrace_buffer__next(queue, + sfq->buffer); + if (!buffer) { + *ts = ~0ULL; + return 1; /* Processing done on this queue */ + } + /* Start with a new buffer on this queue */ + if (buffer->data) { + buffer->use_size = buffer->size; + buffer->use_data = buffer->data; + } + } else + buffer = sfq->buffer; + + if (!buffer->data) { + int fd = perf_data__fd(sfq->sf->session->data); + + buffer->data = auxtrace_buffer__get_data(buffer, fd); + if (!buffer->data) + return -ENOMEM; + buffer->use_size = buffer->size; + buffer->use_data = buffer->data; + } + pr_debug4("%s queue_nr:%d buffer:%" PRId64 " offset:%#" PRIx64 " size:%#zx rest:%#zx\n", + __func__, sfq->queue_nr, buffer->buffer_nr, buffer->offset, + buffer->size, buffer->use_size); + err = s390_cpumsf_samples(sfq, ts); + + /* If non-zero, there is either an error (err < 0) or the buffer is + * completely done (err > 0). The error is unrecoverable, usually + * some descriptors could not be read successfully, so continue with + * the next buffer. + * In both cases the parameter 'ts' has been updated. + */ + if (err) { + sfq->buffer = NULL; + list_del(&buffer->list); + auxtrace_buffer__free(buffer); + if (err > 0) /* Buffer done, no error */ + err = 0; + } + return err; +} + +static struct s390_cpumsf_queue * +s390_cpumsf_alloc_queue(struct s390_cpumsf *sf, unsigned int queue_nr) +{ + struct s390_cpumsf_queue *sfq; + + sfq = zalloc(sizeof(struct s390_cpumsf_queue)); + if (sfq == NULL) + return NULL; + + sfq->sf = sf; + sfq->queue_nr = queue_nr; + sfq->cpu = -1; + return sfq; +} + +static int s390_cpumsf_setup_queue(struct s390_cpumsf *sf, + struct auxtrace_queue *queue, + unsigned int queue_nr, u64 ts) +{ + struct s390_cpumsf_queue *sfq = queue->priv; + + if (list_empty(&queue->head)) + return 0; + + if (sfq == NULL) { + sfq = s390_cpumsf_alloc_queue(sf, queue_nr); + if (!sfq) + return -ENOMEM; + queue->priv = sfq; + + if (queue->cpu != -1) + sfq->cpu = queue->cpu; + } + return auxtrace_heap__add(&sf->heap, queue_nr, ts); +} + +static int s390_cpumsf_setup_queues(struct s390_cpumsf *sf, u64 ts) +{ + unsigned int i; + int ret = 0; + + for (i = 0; i < sf->queues.nr_queues; i++) { + ret = s390_cpumsf_setup_queue(sf, &sf->queues.queue_array[i], + i, ts); + if (ret) + break; + } + return ret; +} + +static int s390_cpumsf_update_queues(struct s390_cpumsf *sf, u64 ts) +{ + if (!sf->queues.new_data) + return 0; + + sf->queues.new_data = false; + return s390_cpumsf_setup_queues(sf, ts); +} + +static int s390_cpumsf_process_queues(struct s390_cpumsf *sf, u64 timestamp) +{ + unsigned int queue_nr; + u64 ts; + int ret; + + while (1) { + struct auxtrace_queue *queue; + struct s390_cpumsf_queue *sfq; + + if (!sf->heap.heap_cnt) + return 0; + + if (sf->heap.heap_array[0].ordinal >= timestamp) + return 0; + + queue_nr = sf->heap.heap_array[0].queue_nr; + queue = &sf->queues.queue_array[queue_nr]; + sfq = queue->priv; + + auxtrace_heap__pop(&sf->heap); + if (sf->heap.heap_cnt) { + ts = sf->heap.heap_array[0].ordinal + 1; + if (ts > timestamp) + ts = timestamp; + } else { + ts = timestamp; + } + + ret = s390_cpumsf_run_decoder(sfq, &ts); + if (ret < 0) { + auxtrace_heap__add(&sf->heap, queue_nr, ts); + return ret; + } + if (!ret) { + ret = auxtrace_heap__add(&sf->heap, queue_nr, ts); + if (ret < 0) + return ret; + } + } + return 0; +} + +static int s390_cpumsf_synth_error(struct s390_cpumsf *sf, int code, int cpu, + pid_t pid, pid_t tid, u64 ip) +{ + char msg[MAX_AUXTRACE_ERROR_MSG]; + union perf_event event; + int err; + + strncpy(msg, "Lost Auxiliary Trace Buffer", sizeof(msg) - 1); + auxtrace_synth_error(&event.auxtrace_error, PERF_AUXTRACE_ERROR_ITRACE, + code, cpu, pid, tid, ip, msg); + + err = perf_session__deliver_synth_event(sf->session, &event, NULL); + if (err) + pr_err("s390 Auxiliary Trace: failed to deliver error event," + "error %d\n", err); + return err; +} + +static int s390_cpumsf_lost(struct s390_cpumsf *sf, struct perf_sample *sample) +{ + return s390_cpumsf_synth_error(sf, 1, sample->cpu, + sample->pid, sample->tid, 0); +} + +static int +s390_cpumsf_process_event(struct perf_session *session __maybe_unused, + union perf_event *event, + struct perf_sample *sample, + struct perf_tool *tool) +{ + struct s390_cpumsf *sf = container_of(session->auxtrace, + struct s390_cpumsf, + auxtrace); + u64 timestamp = sample->time; + int err = 0; + + if (dump_trace) + return 0; + + if (!tool->ordered_events) { + pr_err("s390 Auxiliary Trace requires ordered events\n"); + return -EINVAL; + } + + if (event->header.type == PERF_RECORD_AUX && + event->aux.flags & PERF_AUX_FLAG_TRUNCATED) + return s390_cpumsf_lost(sf, sample); + + if (timestamp) { + err = s390_cpumsf_update_queues(sf, timestamp); + if (!err) + err = s390_cpumsf_process_queues(sf, timestamp); + } + return err; +} + +struct s390_cpumsf_synth { + struct perf_tool cpumsf_tool; + struct perf_session *session; +}; + +static int +s390_cpumsf_process_auxtrace_event(struct perf_session *session, + union perf_event *event __maybe_unused, + struct perf_tool *tool __maybe_unused) +{ + struct s390_cpumsf *sf = container_of(session->auxtrace, + struct s390_cpumsf, + auxtrace); + + int fd = perf_data__fd(session->data); + struct auxtrace_buffer *buffer; + off_t data_offset; + int err; + + if (sf->data_queued) + return 0; + + if (perf_data__is_pipe(session->data)) { + data_offset = 0; + } else { + data_offset = lseek(fd, 0, SEEK_CUR); + if (data_offset == -1) + return -errno; + } + + err = auxtrace_queues__add_event(&sf->queues, session, event, + data_offset, &buffer); + if (err) + return err; + + /* Dump here after copying piped trace out of the pipe */ + if (dump_trace) { + if (auxtrace_buffer__get_data(buffer, fd)) { + s390_cpumsf_dump_event(sf, buffer->data, + buffer->size); + auxtrace_buffer__put_data(buffer); + } + } + return 0; +} + +static void s390_cpumsf_free_events(struct perf_session *session __maybe_unused) +{ +} + +static int s390_cpumsf_flush(struct perf_session *session __maybe_unused, + struct perf_tool *tool __maybe_unused) +{ + return 0; +} + +static void s390_cpumsf_free_queues(struct perf_session *session) +{ + struct s390_cpumsf *sf = container_of(session->auxtrace, + struct s390_cpumsf, + auxtrace); + struct auxtrace_queues *queues = &sf->queues; + unsigned int i; + + for (i = 0; i < queues->nr_queues; i++) + zfree(&queues->queue_array[i].priv); + auxtrace_queues__free(queues); +} + +static void s390_cpumsf_free(struct perf_session *session) +{ + struct s390_cpumsf *sf = container_of(session->auxtrace, + struct s390_cpumsf, + auxtrace); + + auxtrace_heap__free(&sf->heap); + s390_cpumsf_free_queues(session); + session->auxtrace = NULL; + free(sf); +} + +static int s390_cpumsf_get_type(const char *cpuid) +{ + int ret, family = 0; + + ret = sscanf(cpuid, "%*[^,],%u", &family); + return (ret == 1) ? family : 0; +} + +/* Check itrace options set on perf report command. + * Return true, if none are set or all options specified can be + * handled on s390. + * Return false otherwise. + */ +static bool check_auxtrace_itrace(struct itrace_synth_opts *itops) +{ + if (!itops || !itops->set) + return true; + pr_err("No --itrace options supported\n"); + return false; +} + +int s390_cpumsf_process_auxtrace_info(union perf_event *event, + struct perf_session *session) +{ + struct auxtrace_info_event *auxtrace_info = &event->auxtrace_info; + struct s390_cpumsf *sf; + int err; + + if (auxtrace_info->header.size < sizeof(struct auxtrace_info_event)) + return -EINVAL; + + sf = zalloc(sizeof(struct s390_cpumsf)); + if (sf == NULL) + return -ENOMEM; + + if (!check_auxtrace_itrace(session->itrace_synth_opts)) { + err = -EINVAL; + goto err_free; + } + + err = auxtrace_queues__init(&sf->queues); + if (err) + goto err_free; + + sf->session = session; + sf->machine = &session->machines.host; /* No kvm support */ + sf->auxtrace_type = auxtrace_info->type; + sf->pmu_type = PERF_TYPE_RAW; + sf->machine_type = s390_cpumsf_get_type(session->evlist->env->cpuid); + + sf->auxtrace.process_event = s390_cpumsf_process_event; + sf->auxtrace.process_auxtrace_event = s390_cpumsf_process_auxtrace_event; + sf->auxtrace.flush_events = s390_cpumsf_flush; + sf->auxtrace.free_events = s390_cpumsf_free_events; + sf->auxtrace.free = s390_cpumsf_free; + session->auxtrace = &sf->auxtrace; + + if (dump_trace) + return 0; + + err = auxtrace_queues__process_index(&sf->queues, session); + if (err) + goto err_free_queues; + + if (sf->queues.populated) + sf->data_queued = true; + + return 0; + +err_free_queues: + auxtrace_queues__free(&sf->queues); + session->auxtrace = NULL; +err_free: + free(sf); + return err; +} diff --git a/tools/perf/util/s390-cpumsf.h b/tools/perf/util/s390-cpumsf.h new file mode 100644 index 000000000000..fb64d100555c --- /dev/null +++ b/tools/perf/util/s390-cpumsf.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright IBM Corp. 2018 + * Auxtrace support for s390 CPU-Measurement Sampling Facility + * + * Author(s): Thomas Richter <tmricht@linux.ibm.com> + */ + +#ifndef INCLUDE__PERF_S390_CPUMSF_H +#define INCLUDE__PERF_S390_CPUMSF_H + +union perf_event; +struct perf_session; +struct perf_pmu; + +struct auxtrace_record * +s390_cpumsf_recording_init(int *err, struct perf_pmu *s390_cpumsf_pmu); + +int s390_cpumsf_process_auxtrace_info(union perf_event *event, + struct perf_session *session); +#endif diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index 7b79c413486b..45484f0f7292 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c @@ -535,7 +535,7 @@ static int perl_stop_script(void) return 0; } -static int perl_generate_script(struct pevent *pevent, const char *outfile) +static int perl_generate_script(struct tep_handle *pevent, const char *outfile) { struct event_format *event = NULL; struct format_field *f; diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index bc32e57d17be..dfc6093f118c 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -871,8 +871,8 @@ static void python_process_tracepoint(struct perf_sample *sample, offset = field->offset; len = field->size; if (field->flags & FIELD_IS_DYNAMIC) { - val = pevent_read_number(scripting_context->pevent, - data + offset, len); + val = tep_read_number(scripting_context->pevent, + data + offset, len); offset = val; len = offset >> 16; offset &= 0xffff; @@ -1588,7 +1588,7 @@ static int python_stop_script(void) return 0; } -static int python_generate_script(struct pevent *pevent, const char *outfile) +static int python_generate_script(struct tep_handle *pevent, const char *outfile) { struct event_format *event = NULL; struct format_field *f; diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py index 001be4f9d3b9..97efbcad076e 100644 --- a/tools/perf/util/setup.py +++ b/tools/perf/util/setup.py @@ -1,12 +1,20 @@ #!/usr/bin/python from os import getenv +from subprocess import Popen, PIPE +from re import sub + +def clang_has_option(option): + return [o for o in Popen(['clang', option], stderr=PIPE).stderr.readlines() if "unknown argument" in o] == [ ] cc = getenv("CC") if cc == "clang": from _sysconfigdata import build_time_vars - from re import sub build_time_vars["CFLAGS"] = sub("-specs=[^ ]+", "", build_time_vars["CFLAGS"]) + if not clang_has_option("-mcet"): + build_time_vars["CFLAGS"] = sub("-mcet", "", build_time_vars["CFLAGS"]) + if not clang_has_option("-fcf-protection"): + build_time_vars["CFLAGS"] = sub("-fcf-protection", "", build_time_vars["CFLAGS"]) from distutils.core import setup, Extension diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index fed2952ab45a..b284276ec963 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -601,7 +601,7 @@ static char *get_trace_output(struct hist_entry *he) { struct trace_seq seq; struct perf_evsel *evsel; - struct pevent_record rec = { + struct tep_record rec = { .data = he->raw_data, .size = he->raw_size, }; @@ -610,10 +610,10 @@ static char *get_trace_output(struct hist_entry *he) trace_seq_init(&seq); if (symbol_conf.raw_trace) { - pevent_print_fields(&seq, he->raw_data, he->raw_size, - evsel->tp_format); + tep_print_fields(&seq, he->raw_data, he->raw_size, + evsel->tp_format); } else { - pevent_event_info(&seq, evsel->tp_format, &rec); + tep_event_info(&seq, evsel->tp_format, &rec); } /* * Trim the buffer, it starts at 4KB and we're not going to @@ -2047,7 +2047,7 @@ static int __sort__hde_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct trace_seq seq; raw_field: trace_seq_init(&seq); - pevent_print_field(&seq, he->raw_data, hde->field); + tep_print_field(&seq, he->raw_data, hde->field); str = seq.buffer; } @@ -2074,7 +2074,7 @@ static int64_t __sort__hde_cmp(struct perf_hpp_fmt *fmt, if (field->flags & FIELD_IS_DYNAMIC) { unsigned long long dyn; - pevent_read_number_field(field, a->raw_data, &dyn); + tep_read_number_field(field, a->raw_data, &dyn); offset = dyn & 0xffff; size = (dyn >> 16) & 0xffff; @@ -2311,7 +2311,7 @@ static int add_all_matching_fields(struct perf_evlist *evlist, if (evsel->attr.type != PERF_TYPE_TRACEPOINT) continue; - field = pevent_find_any_field(evsel->tp_format, field_name); + field = tep_find_any_field(evsel->tp_format, field_name); if (field == NULL) continue; @@ -2378,7 +2378,7 @@ static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok, if (!strcmp(field_name, "*")) { ret = add_evsel_fields(evsel, raw_trace, level); } else { - field = pevent_find_any_field(evsel->tp_format, field_name); + field = tep_find_any_field(evsel->tp_format, field_name); if (field == NULL) { pr_debug("Cannot find event field for %s.%s\n", event_name, field_name); diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 8bf302cafcec..a97cf8e6be86 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -276,7 +276,7 @@ extern struct sort_entry sort_thread; extern struct list_head hist_entry__sort_list; struct perf_evlist; -struct pevent; +struct tep_handle; int setup_sorting(struct perf_evlist *evlist); int setup_output_field(void); void reset_output_field(void); diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c index 594d14a02b67..99990f5f2512 100644 --- a/tools/perf/util/stat-shadow.c +++ b/tools/perf/util/stat-shadow.c @@ -913,11 +913,10 @@ void perf_stat__print_shadow_stats(struct perf_evsel *evsel, ratio = total / avg; print_metric(ctxp, NULL, "%8.0f", "cycles / elision", ratio); - } else if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK) || - perf_evsel__match(evsel, SOFTWARE, SW_CPU_CLOCK)) { + } else if (perf_evsel__is_clock(evsel)) { if ((ratio = avg_stats(&walltime_nsecs_stats)) != 0) print_metric(ctxp, NULL, "%8.3f", "CPUs utilized", - avg / ratio); + avg / (ratio * evsel->scale)); else print_metric(ctxp, NULL, NULL, "CPUs utilized", 0); } else if (perf_stat_evsel__is(evsel, TOPDOWN_FETCH_BUBBLES)) { diff --git a/tools/perf/util/syscalltbl.c b/tools/perf/util/syscalltbl.c index 0ee7f568d60c..3393d7ee9401 100644 --- a/tools/perf/util/syscalltbl.c +++ b/tools/perf/util/syscalltbl.c @@ -38,6 +38,10 @@ static const char **syscalltbl_native = syscalltbl_powerpc_64; #include <asm/syscalls_32.c> const int syscalltbl_native_max_id = SYSCALLTBL_POWERPC_32_MAX_ID; static const char **syscalltbl_native = syscalltbl_powerpc_32; +#elif defined(__aarch64__) +#include <asm/syscalls.c> +const int syscalltbl_native_max_id = SYSCALLTBL_ARM64_MAX_ID; +static const char **syscalltbl_native = syscalltbl_arm64; #endif struct syscall { diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index e0a6e9a6a053..920b1d58a068 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -32,7 +32,7 @@ static int get_common_field(struct scripting_context *context, int *offset, int *size, const char *type) { - struct pevent *pevent = context->pevent; + struct tep_handle *pevent = context->pevent; struct event_format *event; struct format_field *field; @@ -41,14 +41,14 @@ static int get_common_field(struct scripting_context *context, return 0; event = pevent->events[0]; - field = pevent_find_common_field(event, type); + field = tep_find_common_field(event, type); if (!field) return 0; *offset = field->offset; *size = field->size; } - return pevent_read_number(pevent, context->event_data + *offset, *size); + return tep_read_number(pevent, context->event_data + *offset, *size); } int common_lock_depth(struct scripting_context *context) @@ -99,24 +99,24 @@ raw_field_value(struct event_format *event, const char *name, void *data) struct format_field *field; unsigned long long val; - field = pevent_find_any_field(event, name); + field = tep_find_any_field(event, name); if (!field) return 0ULL; - pevent_read_number_field(field, data, &val); + tep_read_number_field(field, data, &val); return val; } unsigned long long read_size(struct event_format *event, void *ptr, int size) { - return pevent_read_number(event->pevent, ptr, size); + return tep_read_number(event->pevent, ptr, size); } void event_format__fprintf(struct event_format *event, int cpu, void *data, int size, FILE *fp) { - struct pevent_record record; + struct tep_record record; struct trace_seq s; memset(&record, 0, sizeof(record)); @@ -125,7 +125,7 @@ void event_format__fprintf(struct event_format *event, record.data = data; trace_seq_init(&s); - pevent_event_info(&s, event, &record); + tep_event_info(&s, event, &record); trace_seq_do_fprintf(&s, fp); trace_seq_destroy(&s); } @@ -136,7 +136,7 @@ void event_format__print(struct event_format *event, return event_format__fprintf(event, cpu, data, size, stdout); } -void parse_ftrace_printk(struct pevent *pevent, +void parse_ftrace_printk(struct tep_handle *pevent, char *file, unsigned int size __maybe_unused) { unsigned long long addr; @@ -157,11 +157,11 @@ void parse_ftrace_printk(struct pevent *pevent, /* fmt still has a space, skip it */ printk = strdup(fmt+1); line = strtok_r(NULL, "\n", &next); - pevent_register_print_string(pevent, printk, addr); + tep_register_print_string(pevent, printk, addr); } } -void parse_saved_cmdline(struct pevent *pevent, +void parse_saved_cmdline(struct tep_handle *pevent, char *file, unsigned int size __maybe_unused) { char *comm; @@ -172,24 +172,24 @@ void parse_saved_cmdline(struct pevent *pevent, line = strtok_r(file, "\n", &next); while (line) { sscanf(line, "%d %ms", &pid, &comm); - pevent_register_comm(pevent, comm, pid); + tep_register_comm(pevent, comm, pid); free(comm); line = strtok_r(NULL, "\n", &next); } } -int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size) +int parse_ftrace_file(struct tep_handle *pevent, char *buf, unsigned long size) { - return pevent_parse_event(pevent, buf, size, "ftrace"); + return tep_parse_event(pevent, buf, size, "ftrace"); } -int parse_event_file(struct pevent *pevent, +int parse_event_file(struct tep_handle *pevent, char *buf, unsigned long size, char *sys) { - return pevent_parse_event(pevent, buf, size, sys); + return tep_parse_event(pevent, buf, size, sys); } -struct event_format *trace_find_next_event(struct pevent *pevent, +struct event_format *trace_find_next_event(struct tep_handle *pevent, struct event_format *event) { static int idx; diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index 40b425949aa3..3dfc1db6b25b 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c @@ -96,7 +96,7 @@ static void skip(int size) }; } -static unsigned int read4(struct pevent *pevent) +static unsigned int read4(struct tep_handle *pevent) { unsigned int data; @@ -105,7 +105,7 @@ static unsigned int read4(struct pevent *pevent) return __data2host4(pevent, data); } -static unsigned long long read8(struct pevent *pevent) +static unsigned long long read8(struct tep_handle *pevent) { unsigned long long data; @@ -158,7 +158,7 @@ out: return str; } -static int read_proc_kallsyms(struct pevent *pevent) +static int read_proc_kallsyms(struct tep_handle *pevent) { unsigned int size; @@ -181,7 +181,7 @@ static int read_proc_kallsyms(struct pevent *pevent) return 0; } -static int read_ftrace_printk(struct pevent *pevent) +static int read_ftrace_printk(struct tep_handle *pevent) { unsigned int size; char *buf; @@ -208,7 +208,7 @@ static int read_ftrace_printk(struct pevent *pevent) return 0; } -static int read_header_files(struct pevent *pevent) +static int read_header_files(struct tep_handle *pevent) { unsigned long long size; char *header_page; @@ -235,13 +235,13 @@ static int read_header_files(struct pevent *pevent) return -1; } - if (!pevent_parse_header_page(pevent, header_page, size, - pevent_get_long_size(pevent))) { + if (!tep_parse_header_page(pevent, header_page, size, + tep_get_long_size(pevent))) { /* * The commit field in the page is of type long, * use that instead, since it represents the kernel. */ - pevent_set_long_size(pevent, pevent->header_page_size_size); + tep_set_long_size(pevent, pevent->header_page_size_size); } free(header_page); @@ -259,7 +259,7 @@ static int read_header_files(struct pevent *pevent) return ret; } -static int read_ftrace_file(struct pevent *pevent, unsigned long long size) +static int read_ftrace_file(struct tep_handle *pevent, unsigned long long size) { int ret; char *buf; @@ -284,8 +284,8 @@ out: return ret; } -static int read_event_file(struct pevent *pevent, char *sys, - unsigned long long size) +static int read_event_file(struct tep_handle *pevent, char *sys, + unsigned long long size) { int ret; char *buf; @@ -310,7 +310,7 @@ out: return ret; } -static int read_ftrace_files(struct pevent *pevent) +static int read_ftrace_files(struct tep_handle *pevent) { unsigned long long size; int count; @@ -328,7 +328,7 @@ static int read_ftrace_files(struct pevent *pevent) return 0; } -static int read_event_files(struct pevent *pevent) +static int read_event_files(struct tep_handle *pevent) { unsigned long long size; char *sys; @@ -356,7 +356,7 @@ static int read_event_files(struct pevent *pevent) return 0; } -static int read_saved_cmdline(struct pevent *pevent) +static int read_saved_cmdline(struct tep_handle *pevent) { unsigned long long size; char *buf; @@ -399,7 +399,7 @@ ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe) int host_bigendian; int file_long_size; int file_page_size; - struct pevent *pevent = NULL; + struct tep_handle *pevent = NULL; int err; repipe = __repipe; @@ -439,9 +439,9 @@ ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe) pevent = tevent->pevent; - pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT); - pevent_set_file_bigendian(pevent, file_bigendian); - pevent_set_host_bigendian(pevent, host_bigendian); + tep_set_flag(pevent, TEP_NSEC_OUTPUT); + tep_set_file_bigendian(pevent, file_bigendian); + tep_set_host_bigendian(pevent, host_bigendian); if (do_read(buf, 1) < 0) goto out; @@ -451,8 +451,8 @@ ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe) if (!file_page_size) goto out; - pevent_set_long_size(pevent, file_long_size); - pevent_set_page_size(pevent, file_page_size); + tep_set_long_size(pevent, file_long_size); + tep_set_page_size(pevent, file_page_size); err = read_header_files(pevent); if (err) @@ -479,9 +479,9 @@ ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe) repipe = false; if (show_funcs) { - pevent_print_funcs(pevent); + tep_print_funcs(pevent); } else if (show_printk) { - pevent_print_printk(pevent); + tep_print_printk(pevent); } pevent = NULL; diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c index b1e5c3a2b8e3..b749f812ac70 100644 --- a/tools/perf/util/trace-event-scripting.c +++ b/tools/perf/util/trace-event-scripting.c @@ -66,7 +66,7 @@ static int python_start_script_unsupported(const char *script __maybe_unused, return -1; } -static int python_generate_script_unsupported(struct pevent *pevent +static int python_generate_script_unsupported(struct tep_handle *pevent __maybe_unused, const char *outfile __maybe_unused) @@ -130,7 +130,7 @@ static int perl_start_script_unsupported(const char *script __maybe_unused, return -1; } -static int perl_generate_script_unsupported(struct pevent *pevent +static int perl_generate_script_unsupported(struct tep_handle *pevent __maybe_unused, const char *outfile __maybe_unused) { diff --git a/tools/perf/util/trace-event.c b/tools/perf/util/trace-event.c index 1aa368603268..58bb72f266f3 100644 --- a/tools/perf/util/trace-event.c +++ b/tools/perf/util/trace-event.c @@ -28,10 +28,10 @@ static bool tevent_initialized; int trace_event__init(struct trace_event *t) { - struct pevent *pevent = pevent_alloc(); + struct tep_handle *pevent = tep_alloc(); if (pevent) { - t->plugin_list = traceevent_load_plugins(pevent); + t->plugin_list = tep_load_plugins(pevent); t->pevent = pevent; } @@ -40,33 +40,33 @@ int trace_event__init(struct trace_event *t) static int trace_event__init2(void) { - int be = traceevent_host_bigendian(); - struct pevent *pevent; + int be = tep_host_bigendian(); + struct tep_handle *pevent; if (trace_event__init(&tevent)) return -1; pevent = tevent.pevent; - pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT); - pevent_set_file_bigendian(pevent, be); - pevent_set_host_bigendian(pevent, be); + tep_set_flag(pevent, TEP_NSEC_OUTPUT); + tep_set_file_bigendian(pevent, be); + tep_set_host_bigendian(pevent, be); tevent_initialized = true; return 0; } int trace_event__register_resolver(struct machine *machine, - pevent_func_resolver_t *func) + tep_func_resolver_t *func) { if (!tevent_initialized && trace_event__init2()) return -1; - return pevent_set_function_resolver(tevent.pevent, func, machine); + return tep_set_function_resolver(tevent.pevent, func, machine); } void trace_event__cleanup(struct trace_event *t) { - traceevent_unload_plugins(t->plugin_list, t->pevent); - pevent_free(t->pevent); + tep_unload_plugins(t->plugin_list, t->pevent); + tep_free(t->pevent); } /* @@ -76,7 +76,7 @@ static struct event_format* tp_format(const char *sys, const char *name) { char *tp_dir = get_events_file(sys); - struct pevent *pevent = tevent.pevent; + struct tep_handle *pevent = tevent.pevent; struct event_format *event = NULL; char path[PATH_MAX]; size_t size; @@ -93,7 +93,7 @@ tp_format(const char *sys, const char *name) if (err) return ERR_PTR(err); - pevent_parse_format(pevent, &event, data, size, sys); + tep_parse_format(pevent, &event, data, size, sys); free(data); return event; @@ -116,5 +116,5 @@ struct event_format *trace_event__tp_format_id(int id) if (!tevent_initialized && trace_event__init2()) return ERR_PTR(-ENOMEM); - return pevent_find_event(tevent.pevent, id); + return tep_find_event(tevent.pevent, id); } diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index dcbdb53dc702..40204ec3a7a2 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h @@ -13,14 +13,14 @@ struct thread; struct plugin_list; struct trace_event { - struct pevent *pevent; + struct tep_handle *pevent; struct plugin_list *plugin_list; }; int trace_event__init(struct trace_event *t); void trace_event__cleanup(struct trace_event *t); int trace_event__register_resolver(struct machine *machine, - pevent_func_resolver_t *func); + tep_func_resolver_t *func); struct event_format* trace_event__tp_format(const char *sys, const char *name); @@ -34,20 +34,20 @@ void event_format__fprintf(struct event_format *event, void event_format__print(struct event_format *event, int cpu, void *data, int size); -int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size); -int parse_event_file(struct pevent *pevent, +int parse_ftrace_file(struct tep_handle *pevent, char *buf, unsigned long size); +int parse_event_file(struct tep_handle *pevent, char *buf, unsigned long size, char *sys); unsigned long long raw_field_value(struct event_format *event, const char *name, void *data); -void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size); -void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size); -void parse_saved_cmdline(struct pevent *pevent, char *file, unsigned int size); +void parse_proc_kallsyms(struct tep_handle *pevent, char *file, unsigned int size); +void parse_ftrace_printk(struct tep_handle *pevent, char *file, unsigned int size); +void parse_saved_cmdline(struct tep_handle *pevent, char *file, unsigned int size); ssize_t trace_report(int fd, struct trace_event *tevent, bool repipe); -struct event_format *trace_find_next_event(struct pevent *pevent, +struct event_format *trace_find_next_event(struct tep_handle *pevent, struct event_format *event); unsigned long long read_size(struct event_format *event, void *ptr, int size); unsigned long long eval_flag(const char *flag); @@ -83,7 +83,7 @@ struct scripting_ops { void (*process_stat)(struct perf_stat_config *config, struct perf_evsel *evsel, u64 tstamp); void (*process_stat_interval)(u64 tstamp); - int (*generate_script) (struct pevent *pevent, const char *outfile); + int (*generate_script) (struct tep_handle *pevent, const char *outfile); }; extern unsigned int scripting_max_stack; @@ -94,7 +94,7 @@ void setup_perl_scripting(void); void setup_python_scripting(void); struct scripting_context { - struct pevent *pevent; + struct tep_handle *pevent; void *event_data; }; diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c index 538db4e5d1e6..6f318b15950e 100644 --- a/tools/perf/util/unwind-libdw.c +++ b/tools/perf/util/unwind-libdw.c @@ -77,7 +77,7 @@ static int entry(u64 ip, struct unwind_info *ui) if (__report_module(&al, ip, ui)) return -1; - e->ip = al.addr; + e->ip = ip; e->map = al.map; e->sym = al.sym; diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c index 6a11bc7e6b27..79f521a552cf 100644 --- a/tools/perf/util/unwind-libunwind-local.c +++ b/tools/perf/util/unwind-libunwind-local.c @@ -575,7 +575,7 @@ static int entry(u64 ip, struct thread *thread, struct addr_location al; e.sym = thread__find_symbol(thread, PERF_RECORD_MISC_USER, ip, &al); - e.ip = al.addr; + e.ip = ip; e.map = al.map; pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n", diff --git a/tools/perf/util/zlib.c b/tools/perf/util/zlib.c index a725b958cf31..902ce6384f57 100644 --- a/tools/perf/util/zlib.c +++ b/tools/perf/util/zlib.c @@ -5,6 +5,8 @@ #include <sys/stat.h> #include <sys/mman.h> #include <zlib.h> +#include <linux/compiler.h> +#include <unistd.h> #include "util/compress.h" #include "util/util.h" @@ -79,3 +81,19 @@ out_close: return ret == Z_STREAM_END ? 0 : -1; } + +bool gzip_is_compressed(const char *input) +{ + int fd = open(input, O_RDONLY); + const uint8_t magic[2] = { 0x1f, 0x8b }; + char buf[2] = { 0 }; + ssize_t rc; + + if (fd < 0) + return -1; + + rc = read(fd, buf, sizeof(buf)); + close(fd); + return rc == sizeof(buf) ? + memcmp(buf, magic, sizeof(buf)) == 0 : false; +} diff --git a/tools/power/cpupower/po/de.po b/tools/power/cpupower/po/de.po index 78c09e51663a..840c17cc450a 100644 --- a/tools/power/cpupower/po/de.po +++ b/tools/power/cpupower/po/de.po @@ -323,12 +323,12 @@ msgstr " Hardwarebedingte Grenzen der Taktfrequenz: " #: utils/cpufreq-info.c:256 #, c-format msgid " available frequency steps: " -msgstr " mögliche Taktfrequenzen: " +msgstr " mögliche Taktfrequenzen: " #: utils/cpufreq-info.c:269 #, c-format msgid " available cpufreq governors: " -msgstr " mögliche Regler: " +msgstr " mögliche Regler: " #: utils/cpufreq-info.c:280 #, c-format @@ -381,7 +381,7 @@ msgstr "Optionen:\n" msgid " -e, --debug Prints out debug information [default]\n" msgstr "" " -e, --debug Erzeugt detaillierte Informationen, hilfreich\n" -" zum Aufspüren von Fehlern\n" +" zum Aufspüren von Fehlern\n" #: utils/cpufreq-info.c:475 #, c-format @@ -424,7 +424,7 @@ msgstr " -p, --policy Findet die momentane Taktik heraus *\n" #: utils/cpufreq-info.c:482 #, c-format msgid " -g, --governors Determines available cpufreq governors *\n" -msgstr " -g, --governors Erzeugt eine Liste mit verfügbaren Reglern *\n" +msgstr " -g, --governors Erzeugt eine Liste mit verfügbaren Reglern *\n" #: utils/cpufreq-info.c:483 #, c-format @@ -450,7 +450,7 @@ msgstr "" #, c-format msgid " -s, --stats Shows cpufreq statistics if available\n" msgstr "" -" -s, --stats Zeigt, sofern möglich, Statistiken über cpufreq an.\n" +" -s, --stats Zeigt, sofern möglich, Statistiken über cpufreq an.\n" #: utils/cpufreq-info.c:487 #, c-format @@ -473,9 +473,9 @@ msgid "" "cpufreq\n" " interface in 2.4. and early 2.6. kernels\n" msgstr "" -" -o, --proc Erzeugt Informationen in einem ähnlichem Format zu " +" -o, --proc Erzeugt Informationen in einem ähnlichem Format zu " "dem\n" -" der /proc/cpufreq-Datei in 2.4. und frühen 2.6.\n" +" der /proc/cpufreq-Datei in 2.4. und frühen 2.6.\n" " Kernel-Versionen\n" #: utils/cpufreq-info.c:491 @@ -491,7 +491,7 @@ msgstr "" #: utils/cpufreq-info.c:492 utils/cpuidle-info.c:152 #, c-format msgid " -h, --help Prints out this screen\n" -msgstr " -h, --help Gibt diese Kurzübersicht aus\n" +msgstr " -h, --help Gibt diese Kurzübersicht aus\n" #: utils/cpufreq-info.c:495 #, c-format @@ -501,7 +501,7 @@ msgid "" msgstr "" "Sofern kein anderer Parameter als '-c, --cpu' angegeben wird, liefert " "dieses\n" -"Programm Informationen, die z.B. zum Berichten von Fehlern nützlich sind.\n" +"Programm Informationen, die z.B. zum Berichten von Fehlern nützlich sind.\n" #: utils/cpufreq-info.c:497 #, c-format @@ -557,7 +557,7 @@ msgid "" "select\n" msgstr "" " -d FREQ, --min FREQ neue minimale Taktfrequenz, die der Regler\n" -" auswählen darf\n" +" auswählen darf\n" #: utils/cpufreq-set.c:28 #, c-format @@ -566,7 +566,7 @@ msgid "" "select\n" msgstr "" " -u FREQ, --max FREQ neue maximale Taktfrequenz, die der Regler\n" -" auswählen darf\n" +" auswählen darf\n" #: utils/cpufreq-set.c:29 #, c-format @@ -579,20 +579,20 @@ msgid "" " -f FREQ, --freq FREQ specific frequency to be set. Requires userspace\n" " governor to be available and loaded\n" msgstr "" -" -f FREQ, --freq FREQ setze exakte Taktfrequenz. Benötigt den Regler\n" +" -f FREQ, --freq FREQ setze exakte Taktfrequenz. Benötigt den Regler\n" " 'userspace'.\n" #: utils/cpufreq-set.c:32 #, c-format msgid " -r, --related Switches all hardware-related CPUs\n" msgstr "" -" -r, --related Setze Werte für alle CPUs, deren Taktfrequenz\n" +" -r, --related Setze Werte für alle CPUs, deren Taktfrequenz\n" " hardwarebedingt identisch ist.\n" #: utils/cpufreq-set.c:33 utils/cpupower-set.c:28 utils/cpupower-info.c:27 #, c-format msgid " -h, --help Prints out this screen\n" -msgstr " -h, --help Gibt diese Kurzübersicht aus\n" +msgstr " -h, --help Gibt diese Kurzübersicht aus\n" #: utils/cpufreq-set.c:35 #, fuzzy, c-format @@ -618,8 +618,8 @@ msgstr "" " angenommen\n" "2. Der Parameter -f bzw. --freq kann mit keinem anderen als dem Parameter\n" " -c bzw. --cpu kombiniert werden\n" -"3. FREQuenzen können in Hz, kHz (Standard), MHz, GHz oder THz eingegeben\n" -" werden, indem der Wert und unmittelbar anschließend (ohne Leerzeichen!)\n" +"3. FREQuenzen können in Hz, kHz (Standard), MHz, GHz oder THz eingegeben\n" +" werden, indem der Wert und unmittelbar anschließend (ohne Leerzeichen!)\n" " die Einheit angegeben werden. (Bsp: 1GHz )\n" " (FREQuenz in kHz =^ MHz * 1000 =^ GHz * 1000000).\n" @@ -638,7 +638,7 @@ msgid "" msgstr "" "Beim Einstellen ist ein Fehler aufgetreten. Typische Fehlerquellen sind:\n" "- nicht ausreichende Rechte (Administrator)\n" -"- der Regler ist nicht verfügbar bzw. nicht geladen\n" +"- der Regler ist nicht verfügbar bzw. nicht geladen\n" "- die angegebene Taktik ist inkorrekt\n" "- eine spezifische Frequenz wurde angegeben, aber der Regler 'userspace'\n" " kann entweder hardwarebedingt nicht genutzt werden oder ist nicht geladen\n" @@ -821,7 +821,7 @@ msgstr "" #: utils/cpuidle-info.c:48 #, fuzzy, c-format msgid "Available idle states:" -msgstr " mögliche Taktfrequenzen: " +msgstr " mögliche Taktfrequenzen: " #: utils/cpuidle-info.c:71 #, c-format @@ -924,7 +924,7 @@ msgstr "Aufruf: cpufreq-info [Optionen]\n" msgid " -s, --silent Only show general C-state information\n" msgstr "" " -e, --debug Erzeugt detaillierte Informationen, hilfreich\n" -" zum Aufspüren von Fehlern\n" +" zum Aufspüren von Fehlern\n" #: utils/cpuidle-info.c:150 #, fuzzy, c-format @@ -933,9 +933,9 @@ msgid "" "acpi/processor/*/power\n" " interface in older kernels\n" msgstr "" -" -o, --proc Erzeugt Informationen in einem ähnlichem Format zu " +" -o, --proc Erzeugt Informationen in einem ähnlichem Format zu " "dem\n" -" der /proc/cpufreq-Datei in 2.4. und frühen 2.6.\n" +" der /proc/cpufreq-Datei in 2.4. und frühen 2.6.\n" " Kernel-Versionen\n" #: utils/cpuidle-info.c:209 @@ -949,7 +949,7 @@ msgstr "" #~ " -c CPU, --cpu CPU CPU number which information shall be determined " #~ "about\n" #~ msgstr "" -#~ " -c CPU, --cpu CPU Nummer der CPU, über die Informationen " +#~ " -c CPU, --cpu CPU Nummer der CPU, über die Informationen " #~ "herausgefunden werden sollen\n" #~ msgid "" diff --git a/tools/power/cpupower/po/fr.po b/tools/power/cpupower/po/fr.po index 245ad20a9bf9..b46ca2548f86 100644 --- a/tools/power/cpupower/po/fr.po +++ b/tools/power/cpupower/po/fr.po @@ -212,7 +212,7 @@ msgstr "" #: utils/cpupower.c:91 #, c-format msgid "Report errors and bugs to %s, please.\n" -msgstr "Veuillez rapportez les erreurs et les bogues à %s, s'il vous plait.\n" +msgstr "Veuillez rapportez les erreurs et les bogues à %s, s'il vous plait.\n" #: utils/cpupower.c:114 #, c-format @@ -227,14 +227,14 @@ msgstr "" #: utils/cpufreq-info.c:31 #, c-format msgid "Couldn't count the number of CPUs (%s: %s), assuming 1\n" -msgstr "Détermination du nombre de CPUs (%s : %s) impossible. Assume 1\n" +msgstr "Détermination du nombre de CPUs (%s : %s) impossible. Assume 1\n" #: utils/cpufreq-info.c:63 #, c-format msgid "" " minimum CPU frequency - maximum CPU frequency - governor\n" msgstr "" -" Fréquence CPU minimale - Fréquence CPU maximale - régulateur\n" +" Fréquence CPU minimale - Fréquence CPU maximale - régulateur\n" #: utils/cpufreq-info.c:151 #, c-format @@ -302,12 +302,12 @@ msgstr " pilote : %s\n" #: utils/cpufreq-info.c:219 #, fuzzy, c-format msgid " CPUs which run at the same hardware frequency: " -msgstr " CPUs qui doivent changer de fréquences en même temps : " +msgstr " CPUs qui doivent changer de fréquences en même temps : " #: utils/cpufreq-info.c:230 #, fuzzy, c-format msgid " CPUs which need to have their frequency coordinated by software: " -msgstr " CPUs qui doivent changer de fréquences en même temps : " +msgstr " CPUs qui doivent changer de fréquences en même temps : " #: utils/cpufreq-info.c:241 #, c-format @@ -317,22 +317,22 @@ msgstr "" #: utils/cpufreq-info.c:247 #, c-format msgid " hardware limits: " -msgstr " limitation matérielle : " +msgstr " limitation matérielle : " #: utils/cpufreq-info.c:256 #, c-format msgid " available frequency steps: " -msgstr " plage de fréquence : " +msgstr " plage de fréquence : " #: utils/cpufreq-info.c:269 #, c-format msgid " available cpufreq governors: " -msgstr " régulateurs disponibles : " +msgstr " régulateurs disponibles : " #: utils/cpufreq-info.c:280 #, c-format msgid " current policy: frequency should be within " -msgstr " tactique actuelle : la fréquence doit être comprise entre " +msgstr " tactique actuelle : la fréquence doit être comprise entre " #: utils/cpufreq-info.c:282 #, c-format @@ -345,18 +345,18 @@ msgid "" "The governor \"%s\" may decide which speed to use\n" " within this range.\n" msgstr "" -"Le régulateur \"%s\" est libre de choisir la vitesse\n" -" dans cette plage de fréquences.\n" +"Le régulateur \"%s\" est libre de choisir la vitesse\n" +" dans cette plage de fréquences.\n" #: utils/cpufreq-info.c:293 #, c-format msgid " current CPU frequency is " -msgstr " la fréquence actuelle de ce CPU est " +msgstr " la fréquence actuelle de ce CPU est " #: utils/cpufreq-info.c:296 #, c-format msgid " (asserted by call to hardware)" -msgstr " (vérifié par un appel direct du matériel)" +msgstr " (vérifié par un appel direct du matériel)" #: utils/cpufreq-info.c:304 #, c-format @@ -377,7 +377,7 @@ msgstr "Options :\n" #: utils/cpufreq-info.c:474 #, fuzzy, c-format msgid " -e, --debug Prints out debug information [default]\n" -msgstr " -e, --debug Afficher les informations de déboguage\n" +msgstr " -e, --debug Afficher les informations de déboguage\n" #: utils/cpufreq-info.c:475 #, c-format @@ -385,8 +385,8 @@ msgid "" " -f, --freq Get frequency the CPU currently runs at, according\n" " to the cpufreq core *\n" msgstr "" -" -f, --freq Obtenir la fréquence actuelle du CPU selon le point\n" -" de vue du coeur du système de cpufreq *\n" +" -f, --freq Obtenir la fréquence actuelle du CPU selon le point\n" +" de vue du coeur du système de cpufreq *\n" #: utils/cpufreq-info.c:477 #, c-format @@ -394,8 +394,8 @@ msgid "" " -w, --hwfreq Get frequency the CPU currently runs at, by reading\n" " it from hardware (only available to root) *\n" msgstr "" -" -w, --hwfreq Obtenir la fréquence actuelle du CPU directement par\n" -" le matériel (doit être root) *\n" +" -w, --hwfreq Obtenir la fréquence actuelle du CPU directement par\n" +" le matériel (doit être root) *\n" #: utils/cpufreq-info.c:479 #, c-format @@ -403,13 +403,13 @@ msgid "" " -l, --hwlimits Determine the minimum and maximum CPU frequency " "allowed *\n" msgstr "" -" -l, --hwlimits Affiche les fréquences minimales et maximales du CPU " +" -l, --hwlimits Affiche les fréquences minimales et maximales du CPU " "*\n" #: utils/cpufreq-info.c:480 #, c-format msgid " -d, --driver Determines the used cpufreq kernel driver *\n" -msgstr " -d, --driver Affiche le pilote cpufreq utilisé *\n" +msgstr " -d, --driver Affiche le pilote cpufreq utilisé *\n" #: utils/cpufreq-info.c:481 #, c-format @@ -420,7 +420,7 @@ msgstr " -p, --policy Affiche la tactique actuelle de cpufreq *\n" #, c-format msgid " -g, --governors Determines available cpufreq governors *\n" msgstr "" -" -g, --governors Affiche les régulateurs disponibles de cpufreq *\n" +" -g, --governors Affiche les régulateurs disponibles de cpufreq *\n" #: utils/cpufreq-info.c:483 #, fuzzy, c-format @@ -429,7 +429,7 @@ msgid "" "frequency *\n" msgstr "" " -a, --affected-cpus Affiche quels sont les CPUs qui doivent changer de\n" -" fréquences en même temps *\n" +" fréquences en même temps *\n" #: utils/cpufreq-info.c:484 #, fuzzy, c-format @@ -438,7 +438,7 @@ msgid "" " coordinated by software *\n" msgstr "" " -a, --affected-cpus Affiche quels sont les CPUs qui doivent changer de\n" -" fréquences en même temps *\n" +" fréquences en même temps *\n" #: utils/cpufreq-info.c:486 #, c-format @@ -453,7 +453,7 @@ msgid "" " -y, --latency Determines the maximum latency on CPU frequency " "changes *\n" msgstr "" -" -l, --hwlimits Affiche les fréquences minimales et maximales du CPU " +" -l, --hwlimits Affiche les fréquences minimales et maximales du CPU " "*\n" #: utils/cpufreq-info.c:488 @@ -469,7 +469,7 @@ msgid "" " interface in 2.4. and early 2.6. kernels\n" msgstr "" " -o, --proc Affiche les informations en utilisant l'interface\n" -" fournie par /proc/cpufreq, présente dans les " +" fournie par /proc/cpufreq, présente dans les " "versions\n" " 2.4 et les anciennes versions 2.6 du noyau\n" @@ -485,7 +485,7 @@ msgstr "" #: utils/cpufreq-info.c:492 utils/cpuidle-info.c:152 #, c-format msgid " -h, --help Prints out this screen\n" -msgstr " -h, --help affiche l'aide-mémoire\n" +msgstr " -h, --help affiche l'aide-mémoire\n" #: utils/cpufreq-info.c:495 #, c-format @@ -493,8 +493,8 @@ msgid "" "If no argument or only the -c, --cpu parameter is given, debug output about\n" "cpufreq is printed which is useful e.g. for reporting bugs.\n" msgstr "" -"Par défaut, les informations de déboguage seront affichées si aucun\n" -"argument, ou bien si seulement l'argument -c (--cpu) est donné, afin de\n" +"Par défaut, les informations de déboguage seront affichées si aucun\n" +"argument, ou bien si seulement l'argument -c (--cpu) est donné, afin de\n" "faciliter les rapports de bogues par exemple\n" #: utils/cpufreq-info.c:497 @@ -517,8 +517,8 @@ msgid "" "You can't specify more than one --cpu parameter and/or\n" "more than one output-specific argument\n" msgstr "" -"On ne peut indiquer plus d'un paramètre --cpu, tout comme l'on ne peut\n" -"spécifier plus d'un argument de formatage\n" +"On ne peut indiquer plus d'un paramètre --cpu, tout comme l'on ne peut\n" +"spécifier plus d'un argument de formatage\n" #: utils/cpufreq-info.c:600 utils/cpufreq-set.c:82 utils/cpupower-set.c:42 #: utils/cpupower-info.c:42 utils/cpuidle-info.c:213 @@ -529,7 +529,7 @@ msgstr "option invalide\n" #: utils/cpufreq-info.c:617 #, c-format msgid "couldn't analyze CPU %d as it doesn't seem to be present\n" -msgstr "analyse du CPU %d impossible puisqu'il ne semble pas être présent\n" +msgstr "analyse du CPU %d impossible puisqu'il ne semble pas être présent\n" #: utils/cpufreq-info.c:620 utils/cpupower-info.c:142 #, c-format @@ -547,8 +547,8 @@ msgid "" " -d FREQ, --min FREQ new minimum CPU frequency the governor may " "select\n" msgstr "" -" -d FREQ, --min FREQ nouvelle fréquence minimale du CPU à utiliser\n" -" par le régulateur\n" +" -d FREQ, --min FREQ nouvelle fréquence minimale du CPU à utiliser\n" +" par le régulateur\n" #: utils/cpufreq-set.c:28 #, c-format @@ -556,13 +556,13 @@ msgid "" " -u FREQ, --max FREQ new maximum CPU frequency the governor may " "select\n" msgstr "" -" -u FREQ, --max FREQ nouvelle fréquence maximale du CPU à utiliser\n" -" par le régulateur\n" +" -u FREQ, --max FREQ nouvelle fréquence maximale du CPU à utiliser\n" +" par le régulateur\n" #: utils/cpufreq-set.c:29 #, c-format msgid " -g GOV, --governor GOV new cpufreq governor\n" -msgstr " -g GOV, --governor GOV active le régulateur GOV\n" +msgstr " -g GOV, --governor GOV active le régulateur GOV\n" #: utils/cpufreq-set.c:30 #, c-format @@ -570,9 +570,9 @@ msgid "" " -f FREQ, --freq FREQ specific frequency to be set. Requires userspace\n" " governor to be available and loaded\n" msgstr "" -" -f FREQ, --freq FREQ fixe la fréquence du processeur à FREQ. Il faut\n" -" que le régulateur « userspace » soit disponible \n" -" et activé.\n" +" -f FREQ, --freq FREQ fixe la fréquence du processeur à FREQ. Il faut\n" +" que le régulateur « userspace » soit disponible \n" +" et activé.\n" #: utils/cpufreq-set.c:32 #, c-format @@ -582,7 +582,7 @@ msgstr "" #: utils/cpufreq-set.c:33 utils/cpupower-set.c:28 utils/cpupower-info.c:27 #, fuzzy, c-format msgid " -h, --help Prints out this screen\n" -msgstr " -h, --help affiche l'aide-mémoire\n" +msgstr " -h, --help affiche l'aide-mémoire\n" #: utils/cpufreq-set.c:35 #, fuzzy, c-format @@ -602,11 +602,11 @@ msgid "" " (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n" msgstr "" "Remarque :\n" -"1. Le CPU numéro 0 sera utilisé par défaut si -c (ou --cpu) est omis ;\n" -"2. l'argument -f FREQ (ou --freq FREQ) ne peut être utilisé qu'avec --cpu ;\n" -"3. on pourra préciser l'unité des fréquences en postfixant sans aucune " +"1. Le CPU numéro 0 sera utilisé par défaut si -c (ou --cpu) est omis ;\n" +"2. l'argument -f FREQ (ou --freq FREQ) ne peut être utilisé qu'avec --cpu ;\n" +"3. on pourra préciser l'unité des fréquences en postfixant sans aucune " "espace\n" -" les valeurs par hz, kHz (par défaut), MHz, GHz ou THz\n" +" les valeurs par hz, kHz (par défaut), MHz, GHz ou THz\n" " (kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n" #: utils/cpufreq-set.c:57 @@ -622,21 +622,21 @@ msgid "" "frequency\n" " or because the userspace governor isn't loaded?\n" msgstr "" -"En ajustant les nouveaux paramètres, une erreur est apparue. Les sources\n" +"En ajustant les nouveaux paramètres, une erreur est apparue. Les sources\n" "d'erreur typique sont :\n" -"- droit d'administration insuffisant (êtes-vous root ?) ;\n" -"- le régulateur choisi n'est pas disponible, ou bien n'est pas disponible " +"- droit d'administration insuffisant (êtes-vous root ?) ;\n" +"- le régulateur choisi n'est pas disponible, ou bien n'est pas disponible " "en\n" " tant que module noyau ;\n" "- la tactique n'est pas disponible ;\n" -"- vous voulez utiliser l'option -f/--freq, mais le régulateur « userspace »\n" -" n'est pas disponible, par exemple parce que le matériel ne le supporte\n" -" pas, ou bien n'est tout simplement pas chargé.\n" +"- vous voulez utiliser l'option -f/--freq, mais le régulateur « userspace »\n" +" n'est pas disponible, par exemple parce que le matériel ne le supporte\n" +" pas, ou bien n'est tout simplement pas chargé.\n" #: utils/cpufreq-set.c:170 #, c-format msgid "wrong, unknown or unhandled CPU?\n" -msgstr "CPU inconnu ou non supporté ?\n" +msgstr "CPU inconnu ou non supporté ?\n" #: utils/cpufreq-set.c:302 #, c-format @@ -653,7 +653,7 @@ msgid "" "At least one parameter out of -f/--freq, -d/--min, -u/--max, and\n" "-g/--governor must be passed\n" msgstr "" -"L'un de ces paramètres est obligatoire : -f/--freq, -d/--min, -u/--max et\n" +"L'un de ces paramètres est obligatoire : -f/--freq, -d/--min, -u/--max et\n" "-g/--governor\n" #: utils/cpufreq-set.c:347 @@ -810,7 +810,7 @@ msgstr "" #: utils/cpuidle-info.c:48 #, fuzzy, c-format msgid "Available idle states:" -msgstr " plage de fréquence : " +msgstr " plage de fréquence : " #: utils/cpuidle-info.c:71 #, c-format @@ -911,7 +911,7 @@ msgstr "Usage : cpufreq-info [options]\n" #: utils/cpuidle-info.c:149 #, fuzzy, c-format msgid " -s, --silent Only show general C-state information\n" -msgstr " -e, --debug Afficher les informations de déboguage\n" +msgstr " -e, --debug Afficher les informations de déboguage\n" #: utils/cpuidle-info.c:150 #, fuzzy, c-format @@ -921,7 +921,7 @@ msgid "" " interface in older kernels\n" msgstr "" " -o, --proc Affiche les informations en utilisant l'interface\n" -" fournie par /proc/cpufreq, présente dans les " +" fournie par /proc/cpufreq, présente dans les " "versions\n" " 2.4 et les anciennes versions 2.6 du noyau\n" @@ -929,19 +929,19 @@ msgstr "" #, fuzzy, c-format msgid "You can't specify more than one output-specific argument\n" msgstr "" -"On ne peut indiquer plus d'un paramètre --cpu, tout comme l'on ne peut\n" -"spécifier plus d'un argument de formatage\n" +"On ne peut indiquer plus d'un paramètre --cpu, tout comme l'on ne peut\n" +"spécifier plus d'un argument de formatage\n" #~ msgid "" #~ " -c CPU, --cpu CPU CPU number which information shall be determined " #~ "about\n" #~ msgstr "" -#~ " -c CPU, --cpu CPU Numéro du CPU pour lequel l'information sera " -#~ "affichée\n" +#~ " -c CPU, --cpu CPU Numéro du CPU pour lequel l'information sera " +#~ "affichée\n" #~ msgid "" #~ " -c CPU, --cpu CPU number of CPU where cpufreq settings shall be " #~ "modified\n" #~ msgstr "" -#~ " -c CPU, --cpu CPU numéro du CPU à prendre en compte pour les\n" +#~ " -c CPU, --cpu CPU numéro du CPU à prendre en compte pour les\n" #~ " changements\n" diff --git a/tools/testing/nvdimm/pmem-dax.c b/tools/testing/nvdimm/pmem-dax.c index b53596ad601b..2e7fd8227969 100644 --- a/tools/testing/nvdimm/pmem-dax.c +++ b/tools/testing/nvdimm/pmem-dax.c @@ -31,17 +31,21 @@ long __pmem_direct_access(struct pmem_device *pmem, pgoff_t pgoff, if (get_nfit_res(pmem->phys_addr + offset)) { struct page *page; - *kaddr = pmem->virt_addr + offset; + if (kaddr) + *kaddr = pmem->virt_addr + offset; page = vmalloc_to_page(pmem->virt_addr + offset); - *pfn = page_to_pfn_t(page); + if (pfn) + *pfn = page_to_pfn_t(page); pr_debug_ratelimited("%s: pmem: %p pgoff: %#lx pfn: %#lx\n", __func__, pmem, pgoff, page_to_pfn(page)); return 1; } - *kaddr = pmem->virt_addr + offset; - *pfn = phys_to_pfn_t(pmem->phys_addr + offset, pmem->pfn_flags); + if (kaddr) + *kaddr = pmem->virt_addr + offset; + if (pfn) + *pfn = phys_to_pfn_t(pmem->phys_addr + offset, pmem->pfn_flags); /* * If badblocks are present, limit known good range to the diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index e2926f72a821..cffc2c5a778d 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c @@ -142,6 +142,28 @@ static u32 handle[] = { static unsigned long dimm_fail_cmd_flags[NUM_DCR]; static int dimm_fail_cmd_code[NUM_DCR]; +static const struct nd_intel_smart smart_def = { + .flags = ND_INTEL_SMART_HEALTH_VALID + | ND_INTEL_SMART_SPARES_VALID + | ND_INTEL_SMART_ALARM_VALID + | ND_INTEL_SMART_USED_VALID + | ND_INTEL_SMART_SHUTDOWN_VALID + | ND_INTEL_SMART_MTEMP_VALID + | ND_INTEL_SMART_CTEMP_VALID, + .health = ND_INTEL_SMART_NON_CRITICAL_HEALTH, + .media_temperature = 23 * 16, + .ctrl_temperature = 25 * 16, + .pmic_temperature = 40 * 16, + .spares = 75, + .alarm_flags = ND_INTEL_SMART_SPARE_TRIP + | ND_INTEL_SMART_TEMP_TRIP, + .ait_status = 1, + .life_used = 5, + .shutdown_state = 0, + .vendor_size = 0, + .shutdown_count = 100, +}; + struct nfit_test_fw { enum intel_fw_update_state state; u32 context; @@ -752,15 +774,30 @@ static int nfit_test_cmd_smart_inject( if (buf_len != sizeof(*inj)) return -EINVAL; - if (inj->mtemp_enable) - smart->media_temperature = inj->media_temperature; - if (inj->spare_enable) - smart->spares = inj->spares; - if (inj->fatal_enable) - smart->health = ND_INTEL_SMART_FATAL_HEALTH; - if (inj->unsafe_shutdown_enable) { - smart->shutdown_state = 1; - smart->shutdown_count++; + if (inj->flags & ND_INTEL_SMART_INJECT_MTEMP) { + if (inj->mtemp_enable) + smart->media_temperature = inj->media_temperature; + else + smart->media_temperature = smart_def.media_temperature; + } + if (inj->flags & ND_INTEL_SMART_INJECT_SPARE) { + if (inj->spare_enable) + smart->spares = inj->spares; + else + smart->spares = smart_def.spares; + } + if (inj->flags & ND_INTEL_SMART_INJECT_FATAL) { + if (inj->fatal_enable) + smart->health = ND_INTEL_SMART_FATAL_HEALTH; + else + smart->health = ND_INTEL_SMART_NON_CRITICAL_HEALTH; + } + if (inj->flags & ND_INTEL_SMART_INJECT_SHUTDOWN) { + if (inj->unsafe_shutdown_enable) { + smart->shutdown_state = 1; + smart->shutdown_count++; + } else + smart->shutdown_state = 0; } inj->status = 0; smart_notify(bus_dev, dimm_dev, smart, thresh); @@ -884,6 +921,16 @@ static int nd_intel_test_cmd_set_lss_status(struct nfit_test *t, return 0; } +static int override_return_code(int dimm, unsigned int func, int rc) +{ + if ((1 << func) & dimm_fail_cmd_flags[dimm]) { + if (dimm_fail_cmd_code[dimm]) + return dimm_fail_cmd_code[dimm]; + return -EIO; + } + return rc; +} + static int get_dimm(struct nfit_mem *nfit_mem, unsigned int func) { int i; @@ -894,13 +941,6 @@ static int get_dimm(struct nfit_mem *nfit_mem, unsigned int func) break; if (i >= ARRAY_SIZE(handle)) return -ENXIO; - - if ((1 << func) & dimm_fail_cmd_flags[i]) { - if (dimm_fail_cmd_code[i]) - return dimm_fail_cmd_code[i]; - return -EIO; - } - return i; } @@ -939,48 +979,59 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, switch (func) { case ND_INTEL_ENABLE_LSS_STATUS: - return nd_intel_test_cmd_set_lss_status(t, + rc = nd_intel_test_cmd_set_lss_status(t, buf, buf_len); + break; case ND_INTEL_FW_GET_INFO: - return nd_intel_test_get_fw_info(t, buf, + rc = nd_intel_test_get_fw_info(t, buf, buf_len, i - t->dcr_idx); + break; case ND_INTEL_FW_START_UPDATE: - return nd_intel_test_start_update(t, buf, + rc = nd_intel_test_start_update(t, buf, buf_len, i - t->dcr_idx); + break; case ND_INTEL_FW_SEND_DATA: - return nd_intel_test_send_data(t, buf, + rc = nd_intel_test_send_data(t, buf, buf_len, i - t->dcr_idx); + break; case ND_INTEL_FW_FINISH_UPDATE: - return nd_intel_test_finish_fw(t, buf, + rc = nd_intel_test_finish_fw(t, buf, buf_len, i - t->dcr_idx); + break; case ND_INTEL_FW_FINISH_QUERY: - return nd_intel_test_finish_query(t, buf, + rc = nd_intel_test_finish_query(t, buf, buf_len, i - t->dcr_idx); + break; case ND_INTEL_SMART: - return nfit_test_cmd_smart(buf, buf_len, + rc = nfit_test_cmd_smart(buf, buf_len, &t->smart[i - t->dcr_idx]); + break; case ND_INTEL_SMART_THRESHOLD: - return nfit_test_cmd_smart_threshold(buf, + rc = nfit_test_cmd_smart_threshold(buf, buf_len, &t->smart_threshold[i - t->dcr_idx]); + break; case ND_INTEL_SMART_SET_THRESHOLD: - return nfit_test_cmd_smart_set_threshold(buf, + rc = nfit_test_cmd_smart_set_threshold(buf, buf_len, &t->smart_threshold[i - t->dcr_idx], &t->smart[i - t->dcr_idx], &t->pdev.dev, t->dimm_dev[i]); + break; case ND_INTEL_SMART_INJECT: - return nfit_test_cmd_smart_inject(buf, + rc = nfit_test_cmd_smart_inject(buf, buf_len, &t->smart_threshold[i - t->dcr_idx], &t->smart[i - t->dcr_idx], &t->pdev.dev, t->dimm_dev[i]); + break; default: return -ENOTTY; } + return override_return_code(i, func, rc); } if (!test_bit(cmd, &cmd_mask) @@ -1006,6 +1057,7 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, default: return -ENOTTY; } + return override_return_code(i, func, rc); } else { struct ars_state *ars_state = &t->ars_state; struct nd_cmd_pkg *call_pkg = buf; @@ -1302,29 +1354,9 @@ static void smart_init(struct nfit_test *t) .ctrl_temperature = 30 * 16, .spares = 5, }; - const struct nd_intel_smart smart_data = { - .flags = ND_INTEL_SMART_HEALTH_VALID - | ND_INTEL_SMART_SPARES_VALID - | ND_INTEL_SMART_ALARM_VALID - | ND_INTEL_SMART_USED_VALID - | ND_INTEL_SMART_SHUTDOWN_VALID - | ND_INTEL_SMART_MTEMP_VALID, - .health = ND_INTEL_SMART_NON_CRITICAL_HEALTH, - .media_temperature = 23 * 16, - .ctrl_temperature = 25 * 16, - .pmic_temperature = 40 * 16, - .spares = 75, - .alarm_flags = ND_INTEL_SMART_SPARE_TRIP - | ND_INTEL_SMART_TEMP_TRIP, - .ait_status = 1, - .life_used = 5, - .shutdown_state = 0, - .vendor_size = 0, - .shutdown_count = 100, - }; for (i = 0; i < t->num_dcr; i++) { - memcpy(&t->smart[i], &smart_data, sizeof(smart_data)); + memcpy(&t->smart[i], &smart_def, sizeof(smart_def)); memcpy(&t->smart_threshold[i], &smart_t_data, sizeof(smart_t_data)); } diff --git a/tools/testing/selftests/android/ion/ionapp_export.c b/tools/testing/selftests/android/ion/ionapp_export.c index a944e72621a9..b5fa0a2dc968 100644 --- a/tools/testing/selftests/android/ion/ionapp_export.c +++ b/tools/testing/selftests/android/ion/ionapp_export.c @@ -51,6 +51,7 @@ int main(int argc, char *argv[]) heap_size = 0; flags = 0; + heap_type = ION_HEAP_TYPE_SYSTEM; while ((opt = getopt(argc, argv, "hi:s:")) != -1) { switch (opt) { diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index a362e3d7abc6..fff7fb1285fc 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -22,7 +22,8 @@ $(TEST_CUSTOM_PROGS): $(OUTPUT)/%: %.c # Order correspond to 'make run_tests' order TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \ test_align test_verifier_log test_dev_cgroup test_tcpbpf_user \ - test_sock test_btf test_sockmap test_lirc_mode2_user get_cgroup_id_user + test_sock test_btf test_sockmap test_lirc_mode2_user get_cgroup_id_user \ + test_socket_cookie test_cgroup_storage test_select_reuseport TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o \ test_pkt_md_access.o test_xdp_redirect.o test_xdp_meta.o sockmap_parse_prog.o \ @@ -33,7 +34,8 @@ TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test test_btf_haskv.o test_btf_nokv.o test_sockmap_kern.o test_tunnel_kern.o \ test_get_stack_rawtp.o test_sockmap_kern.o test_sockhash_kern.o \ test_lwt_seg6local.o sendmsg4_prog.o sendmsg6_prog.o test_lirc_mode2_kern.o \ - get_cgroup_id_kern.o + get_cgroup_id_kern.o socket_cookie_prog.o test_select_reuseport_kern.o \ + test_skb_cgroup_id_kern.o # Order correspond to 'make run_tests' order TEST_PROGS := test_kmod.sh \ @@ -44,10 +46,11 @@ TEST_PROGS := test_kmod.sh \ test_sock_addr.sh \ test_tunnel.sh \ test_lwt_seg6local.sh \ - test_lirc_mode2.sh + test_lirc_mode2.sh \ + test_skb_cgroup_id.sh # Compile but not part of 'make run_tests' -TEST_GEN_PROGS_EXTENDED = test_libbpf_open test_sock_addr +TEST_GEN_PROGS_EXTENDED = test_libbpf_open test_sock_addr test_skb_cgroup_id_user include ../lib.mk @@ -58,11 +61,15 @@ $(TEST_GEN_PROGS): $(BPFOBJ) $(TEST_GEN_PROGS_EXTENDED): $(OUTPUT)/libbpf.a $(OUTPUT)/test_dev_cgroup: cgroup_helpers.c +$(OUTPUT)/test_skb_cgroup_id_user: cgroup_helpers.c $(OUTPUT)/test_sock: cgroup_helpers.c $(OUTPUT)/test_sock_addr: cgroup_helpers.c +$(OUTPUT)/test_socket_cookie: cgroup_helpers.c $(OUTPUT)/test_sockmap: cgroup_helpers.c +$(OUTPUT)/test_tcpbpf_user: cgroup_helpers.c $(OUTPUT)/test_progs: trace_helpers.c $(OUTPUT)/get_cgroup_id_user: cgroup_helpers.c +$(OUTPUT)/test_cgroup_storage: cgroup_helpers.c .PHONY: force diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h index 810de20e8e26..e4be7730222d 100644 --- a/tools/testing/selftests/bpf/bpf_helpers.h +++ b/tools/testing/selftests/bpf/bpf_helpers.h @@ -65,6 +65,8 @@ static int (*bpf_xdp_adjust_head)(void *ctx, int offset) = (void *) BPF_FUNC_xdp_adjust_head; static int (*bpf_xdp_adjust_meta)(void *ctx, int offset) = (void *) BPF_FUNC_xdp_adjust_meta; +static int (*bpf_get_socket_cookie)(void *ctx) = + (void *) BPF_FUNC_get_socket_cookie; static int (*bpf_setsockopt)(void *ctx, int level, int optname, void *optval, int optlen) = (void *) BPF_FUNC_setsockopt; @@ -109,6 +111,8 @@ static int (*bpf_xdp_adjust_tail)(void *ctx, int offset) = static int (*bpf_skb_get_xfrm_state)(void *ctx, int index, void *state, int size, int flags) = (void *) BPF_FUNC_skb_get_xfrm_state; +static int (*bpf_sk_select_reuseport)(void *ctx, void *map, void *key, __u32 flags) = + (void *) BPF_FUNC_sk_select_reuseport; static int (*bpf_get_stack)(void *ctx, void *buf, int size, int flags) = (void *) BPF_FUNC_get_stack; static int (*bpf_fib_lookup)(void *ctx, struct bpf_fib_lookup *params, @@ -133,6 +137,12 @@ static int (*bpf_rc_keydown)(void *ctx, unsigned int protocol, (void *) BPF_FUNC_rc_keydown; static unsigned long long (*bpf_get_current_cgroup_id)(void) = (void *) BPF_FUNC_get_current_cgroup_id; +static void *(*bpf_get_local_storage)(void *map, unsigned long long flags) = + (void *) BPF_FUNC_get_local_storage; +static unsigned long long (*bpf_skb_cgroup_id)(void *ctx) = + (void *) BPF_FUNC_skb_cgroup_id; +static unsigned long long (*bpf_skb_ancestor_cgroup_id)(void *ctx, int level) = + (void *) BPF_FUNC_skb_ancestor_cgroup_id; /* llvm builtin functions that eBPF C program may use to * emit BPF_LD_ABS and BPF_LD_IND instructions @@ -169,6 +179,8 @@ struct bpf_map_def { static int (*bpf_skb_load_bytes)(void *ctx, int off, void *to, int len) = (void *) BPF_FUNC_skb_load_bytes; +static int (*bpf_skb_load_bytes_relative)(void *ctx, int off, void *to, int len, __u32 start_header) = + (void *) BPF_FUNC_skb_load_bytes_relative; static int (*bpf_skb_store_bytes)(void *ctx, int off, void *from, int len, int flags) = (void *) BPF_FUNC_skb_store_bytes; static int (*bpf_l3_csum_replace)(void *ctx, int off, int from, int to, int flags) = diff --git a/tools/testing/selftests/bpf/bpf_util.h b/tools/testing/selftests/bpf/bpf_util.h index d0811b3d6a6f..315a44fa32af 100644 --- a/tools/testing/selftests/bpf/bpf_util.h +++ b/tools/testing/selftests/bpf/bpf_util.h @@ -44,4 +44,8 @@ static inline unsigned int bpf_num_possible_cpus(void) name[bpf_num_possible_cpus()] #define bpf_percpu(name, cpu) name[(cpu)].v +#ifndef ARRAY_SIZE +# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + #endif /* __BPF_UTIL__ */ diff --git a/tools/testing/selftests/bpf/cgroup_helpers.c b/tools/testing/selftests/bpf/cgroup_helpers.c index c87b4e052ce9..cf16948aad4a 100644 --- a/tools/testing/selftests/bpf/cgroup_helpers.c +++ b/tools/testing/selftests/bpf/cgroup_helpers.c @@ -118,7 +118,7 @@ static int join_cgroup_from_top(char *cgroup_path) * * On success, it returns 0, otherwise on failure it returns 1. */ -int join_cgroup(char *path) +int join_cgroup(const char *path) { char cgroup_path[PATH_MAX + 1]; @@ -158,7 +158,7 @@ void cleanup_cgroup_environment(void) * On success, it returns the file descriptor. On failure it returns 0. * If there is a failure, it prints the error to stderr. */ -int create_and_get_cgroup(char *path) +int create_and_get_cgroup(const char *path) { char cgroup_path[PATH_MAX + 1]; int fd; @@ -186,7 +186,7 @@ int create_and_get_cgroup(char *path) * which is an invalid cgroup id. * If there is a failure, it prints the error to stderr. */ -unsigned long long get_cgroup_id(char *path) +unsigned long long get_cgroup_id(const char *path) { int dirfd, err, flags, mount_id, fhsize; union { diff --git a/tools/testing/selftests/bpf/cgroup_helpers.h b/tools/testing/selftests/bpf/cgroup_helpers.h index 20a4a5dcd469..d64bb8957090 100644 --- a/tools/testing/selftests/bpf/cgroup_helpers.h +++ b/tools/testing/selftests/bpf/cgroup_helpers.h @@ -9,10 +9,10 @@ __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__) -int create_and_get_cgroup(char *path); -int join_cgroup(char *path); +int create_and_get_cgroup(const char *path); +int join_cgroup(const char *path); int setup_cgroup_environment(void); void cleanup_cgroup_environment(void); -unsigned long long get_cgroup_id(char *path); +unsigned long long get_cgroup_id(const char *path); #endif diff --git a/tools/testing/selftests/bpf/socket_cookie_prog.c b/tools/testing/selftests/bpf/socket_cookie_prog.c new file mode 100644 index 000000000000..9ff8ac4b0bf6 --- /dev/null +++ b/tools/testing/selftests/bpf/socket_cookie_prog.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Facebook + +#include <linux/bpf.h> +#include <sys/socket.h> + +#include "bpf_helpers.h" +#include "bpf_endian.h" + +struct bpf_map_def SEC("maps") socket_cookies = { + .type = BPF_MAP_TYPE_HASH, + .key_size = sizeof(__u64), + .value_size = sizeof(__u32), + .max_entries = 1 << 8, +}; + +SEC("cgroup/connect6") +int set_cookie(struct bpf_sock_addr *ctx) +{ + __u32 cookie_value = 0xFF; + __u64 cookie_key; + + if (ctx->family != AF_INET6 || ctx->user_family != AF_INET6) + return 1; + + cookie_key = bpf_get_socket_cookie(ctx); + if (bpf_map_update_elem(&socket_cookies, &cookie_key, &cookie_value, 0)) + return 0; + + return 1; +} + +SEC("sockops") +int update_cookie(struct bpf_sock_ops *ctx) +{ + __u32 new_cookie_value; + __u32 *cookie_value; + __u64 cookie_key; + + if (ctx->family != AF_INET6) + return 1; + + if (ctx->op != BPF_SOCK_OPS_TCP_CONNECT_CB) + return 1; + + cookie_key = bpf_get_socket_cookie(ctx); + + cookie_value = bpf_map_lookup_elem(&socket_cookies, &cookie_key); + if (!cookie_value) + return 1; + + new_cookie_value = (ctx->local_port << 8) | *cookie_value; + bpf_map_update_elem(&socket_cookies, &cookie_key, &new_cookie_value, 0); + + return 1; +} + +int _version SEC("version") = 1; + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/tcp_client.py b/tools/testing/selftests/bpf/tcp_client.py index 481dccdf140c..7f8200a8702b 100755 --- a/tools/testing/selftests/bpf/tcp_client.py +++ b/tools/testing/selftests/bpf/tcp_client.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # # SPDX-License-Identifier: GPL-2.0 # @@ -9,11 +9,11 @@ import subprocess import select def read(sock, n): - buf = '' + buf = b'' while len(buf) < n: rem = n - len(buf) try: s = sock.recv(rem) - except (socket.error), e: return '' + except (socket.error) as e: return b'' buf += s return buf @@ -22,7 +22,7 @@ def send(sock, s): count = 0 while count < total: try: n = sock.send(s) - except (socket.error), e: n = 0 + except (socket.error) as e: n = 0 if n == 0: return count; count += n @@ -39,10 +39,10 @@ try: except socket.error as e: sys.exit(1) -buf = '' +buf = b'' n = 0 while n < 1000: - buf += '+' + buf += b'+' n += 1 sock.settimeout(1); diff --git a/tools/testing/selftests/bpf/tcp_server.py b/tools/testing/selftests/bpf/tcp_server.py index bc454d7d0be2..b39903fca4c8 100755 --- a/tools/testing/selftests/bpf/tcp_server.py +++ b/tools/testing/selftests/bpf/tcp_server.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # # SPDX-License-Identifier: GPL-2.0 # @@ -9,11 +9,11 @@ import subprocess import select def read(sock, n): - buf = '' + buf = b'' while len(buf) < n: rem = n - len(buf) try: s = sock.recv(rem) - except (socket.error), e: return '' + except (socket.error) as e: return b'' buf += s return buf @@ -22,7 +22,7 @@ def send(sock, s): count = 0 while count < total: try: n = sock.send(s) - except (socket.error), e: n = 0 + except (socket.error) as e: n = 0 if n == 0: return count; count += n @@ -43,7 +43,7 @@ host = socket.gethostname() try: serverSocket.bind((host, 0)) except socket.error as msg: - print 'bind fails: ', msg + print('bind fails: ' + str(msg)) sn = serverSocket.getsockname() serverPort = sn[1] @@ -51,10 +51,10 @@ serverPort = sn[1] cmdStr = ("./tcp_client.py %d &") % (serverPort) os.system(cmdStr) -buf = '' +buf = b'' n = 0 while n < 500: - buf += '.' + buf += b'.' n += 1 serverSocket.listen(MAX_PORTS) @@ -79,5 +79,5 @@ while True: serverSocket.close() sys.exit(0) else: - print 'Select timeout!' + print('Select timeout!') sys.exit(1) diff --git a/tools/testing/selftests/bpf/test_align.c b/tools/testing/selftests/bpf/test_align.c index 6b1b302310fe..5f377ec53f2f 100644 --- a/tools/testing/selftests/bpf/test_align.c +++ b/tools/testing/selftests/bpf/test_align.c @@ -18,10 +18,7 @@ #include "../../../include/linux/filter.h" #include "bpf_rlimit.h" - -#ifndef ARRAY_SIZE -# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) -#endif +#include "bpf_util.h" #define MAX_INSNS 512 #define MAX_MATCHES 16 diff --git a/tools/testing/selftests/bpf/test_btf.c b/tools/testing/selftests/bpf/test_btf.c index ffdd27737c9e..6b5cfeb7a9cc 100644 --- a/tools/testing/selftests/bpf/test_btf.c +++ b/tools/testing/selftests/bpf/test_btf.c @@ -19,6 +19,7 @@ #include <bpf/btf.h> #include "bpf_rlimit.h" +#include "bpf_util.h" static uint32_t pass_cnt; static uint32_t error_cnt; @@ -93,10 +94,6 @@ static int __base_pr(const char *format, ...) #define MAX_NR_RAW_TYPES 1024 #define BTF_LOG_BUF_SIZE 65535 -#ifndef ARRAY_SIZE -# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) -#endif - static struct args { unsigned int raw_test_num; unsigned int file_test_num; @@ -131,6 +128,8 @@ struct btf_raw_test { __u32 max_entries; bool btf_load_err; bool map_create_err; + bool ordered_map; + bool lossless_map; int hdr_len_delta; int type_off_delta; int str_off_delta; @@ -2093,8 +2092,7 @@ struct pprint_mapv { } aenum; }; -static struct btf_raw_test pprint_test = { - .descr = "BTF pretty print test #1", +static struct btf_raw_test pprint_test_template = { .raw_types = { /* unsighed char */ /* [1] */ BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 8, 1), @@ -2146,8 +2144,6 @@ static struct btf_raw_test pprint_test = { }, .str_sec = "\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum", .str_sec_size = sizeof("\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum"), - .map_type = BPF_MAP_TYPE_ARRAY, - .map_name = "pprint_test", .key_size = sizeof(unsigned int), .value_size = sizeof(struct pprint_mapv), .key_type_id = 3, /* unsigned int */ @@ -2155,6 +2151,40 @@ static struct btf_raw_test pprint_test = { .max_entries = 128 * 1024, }; +static struct btf_pprint_test_meta { + const char *descr; + enum bpf_map_type map_type; + const char *map_name; + bool ordered_map; + bool lossless_map; +} pprint_tests_meta[] = { +{ + .descr = "BTF pretty print array", + .map_type = BPF_MAP_TYPE_ARRAY, + .map_name = "pprint_test_array", + .ordered_map = true, + .lossless_map = true, +}, + +{ + .descr = "BTF pretty print hash", + .map_type = BPF_MAP_TYPE_HASH, + .map_name = "pprint_test_hash", + .ordered_map = false, + .lossless_map = true, +}, + +{ + .descr = "BTF pretty print lru hash", + .map_type = BPF_MAP_TYPE_LRU_HASH, + .map_name = "pprint_test_lru_hash", + .ordered_map = false, + .lossless_map = false, +}, + +}; + + static void set_pprint_mapv(struct pprint_mapv *v, uint32_t i) { v->ui32 = i; @@ -2166,10 +2196,12 @@ static void set_pprint_mapv(struct pprint_mapv *v, uint32_t i) v->aenum = i & 0x03; } -static int test_pprint(void) +static int do_test_pprint(void) { - const struct btf_raw_test *test = &pprint_test; + const struct btf_raw_test *test = &pprint_test_template; struct bpf_create_map_attr create_attr = {}; + unsigned int key, nr_read_elems; + bool ordered_map, lossless_map; int map_fd = -1, btf_fd = -1; struct pprint_mapv mapv = {}; unsigned int raw_btf_size; @@ -2178,7 +2210,6 @@ static int test_pprint(void) char pin_path[255]; size_t line_len = 0; char *line = NULL; - unsigned int key; uint8_t *raw_btf; ssize_t nread; int err, ret; @@ -2251,14 +2282,18 @@ static int test_pprint(void) goto done; } - key = 0; + nr_read_elems = 0; + ordered_map = test->ordered_map; + lossless_map = test->lossless_map; do { ssize_t nexpected_line; + unsigned int next_key; - set_pprint_mapv(&mapv, key); + next_key = ordered_map ? nr_read_elems : atoi(line); + set_pprint_mapv(&mapv, next_key); nexpected_line = snprintf(expected_line, sizeof(expected_line), "%u: {%u,0,%d,0x%x,0x%x,0x%x,{%lu|[%u,%u,%u,%u,%u,%u,%u,%u]},%s}\n", - key, + next_key, mapv.ui32, mapv.si32, mapv.unused_bits2a, mapv.bits28, mapv.unused_bits2b, mapv.ui64, @@ -2281,11 +2316,12 @@ static int test_pprint(void) } nread = getline(&line, &line_len, pin_file); - } while (++key < test->max_entries && nread > 0); + } while (++nr_read_elems < test->max_entries && nread > 0); - if (CHECK(key < test->max_entries, - "Unexpected EOF. key:%u test->max_entries:%u", - key, test->max_entries)) { + if (lossless_map && + CHECK(nr_read_elems < test->max_entries, + "Unexpected EOF. nr_read_elems:%u test->max_entries:%u", + nr_read_elems, test->max_entries)) { err = -1; goto done; } @@ -2314,6 +2350,24 @@ done: return err; } +static int test_pprint(void) +{ + unsigned int i; + int err = 0; + + for (i = 0; i < ARRAY_SIZE(pprint_tests_meta); i++) { + pprint_test_template.descr = pprint_tests_meta[i].descr; + pprint_test_template.map_type = pprint_tests_meta[i].map_type; + pprint_test_template.map_name = pprint_tests_meta[i].map_name; + pprint_test_template.ordered_map = pprint_tests_meta[i].ordered_map; + pprint_test_template.lossless_map = pprint_tests_meta[i].lossless_map; + + err |= count_result(do_test_pprint()); + } + + return err; +} + static void usage(const char *cmd) { fprintf(stderr, "Usage: %s [-l] [[-r test_num (1 - %zu)] | [-g test_num (1 - %zu)] | [-f test_num (1 - %zu)] | [-p]]\n", @@ -2409,7 +2463,7 @@ int main(int argc, char **argv) err |= test_file(); if (args.pprint_test) - err |= count_result(test_pprint()); + err |= test_pprint(); if (args.raw_test || args.get_info_test || args.file_test || args.pprint_test) diff --git a/tools/testing/selftests/bpf/test_cgroup_storage.c b/tools/testing/selftests/bpf/test_cgroup_storage.c new file mode 100644 index 000000000000..4e196e3bfecf --- /dev/null +++ b/tools/testing/selftests/bpf/test_cgroup_storage.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <assert.h> +#include <bpf/bpf.h> +#include <linux/filter.h> +#include <stdio.h> +#include <stdlib.h> + +#include "bpf_rlimit.h" +#include "cgroup_helpers.h" + +char bpf_log_buf[BPF_LOG_BUF_SIZE]; + +#define TEST_CGROUP "/test-bpf-cgroup-storage-buf/" + +int main(int argc, char **argv) +{ + struct bpf_insn prog[] = { + BPF_LD_MAP_FD(BPF_REG_1, 0), /* map fd */ + BPF_MOV64_IMM(BPF_REG_2, 0), /* flags, not used */ + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_get_local_storage), + BPF_MOV64_IMM(BPF_REG_1, 1), + BPF_STX_XADD(BPF_DW, BPF_REG_0, BPF_REG_1, 0), + BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0), + BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0x1), + BPF_MOV64_REG(BPF_REG_0, BPF_REG_1), + BPF_EXIT_INSN(), + }; + size_t insns_cnt = sizeof(prog) / sizeof(struct bpf_insn); + int error = EXIT_FAILURE; + int map_fd, prog_fd, cgroup_fd; + struct bpf_cgroup_storage_key key; + unsigned long long value; + + map_fd = bpf_create_map(BPF_MAP_TYPE_CGROUP_STORAGE, sizeof(key), + sizeof(value), 0, 0); + if (map_fd < 0) { + printf("Failed to create map: %s\n", strerror(errno)); + goto out; + } + + prog[0].imm = map_fd; + prog_fd = bpf_load_program(BPF_PROG_TYPE_CGROUP_SKB, + prog, insns_cnt, "GPL", 0, + bpf_log_buf, BPF_LOG_BUF_SIZE); + if (prog_fd < 0) { + printf("Failed to load bpf program: %s\n", bpf_log_buf); + goto out; + } + + if (setup_cgroup_environment()) { + printf("Failed to setup cgroup environment\n"); + goto err; + } + + /* Create a cgroup, get fd, and join it */ + cgroup_fd = create_and_get_cgroup(TEST_CGROUP); + if (!cgroup_fd) { + printf("Failed to create test cgroup\n"); + goto err; + } + + if (join_cgroup(TEST_CGROUP)) { + printf("Failed to join cgroup\n"); + goto err; + } + + /* Attach the bpf program */ + if (bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_INET_EGRESS, 0)) { + printf("Failed to attach bpf program\n"); + goto err; + } + + if (bpf_map_get_next_key(map_fd, NULL, &key)) { + printf("Failed to get the first key in cgroup storage\n"); + goto err; + } + + if (bpf_map_lookup_elem(map_fd, &key, &value)) { + printf("Failed to lookup cgroup storage\n"); + goto err; + } + + /* Every second packet should be dropped */ + assert(system("ping localhost -c 1 -W 1 -q > /dev/null") == 0); + assert(system("ping localhost -c 1 -W 1 -q > /dev/null")); + assert(system("ping localhost -c 1 -W 1 -q > /dev/null") == 0); + + /* Check the counter in the cgroup local storage */ + if (bpf_map_lookup_elem(map_fd, &key, &value)) { + printf("Failed to lookup cgroup storage\n"); + goto err; + } + + if (value != 3) { + printf("Unexpected data in the cgroup storage: %llu\n", value); + goto err; + } + + /* Bump the counter in the cgroup local storage */ + value++; + if (bpf_map_update_elem(map_fd, &key, &value, 0)) { + printf("Failed to update the data in the cgroup storage\n"); + goto err; + } + + /* Every second packet should be dropped */ + assert(system("ping localhost -c 1 -W 1 -q > /dev/null") == 0); + assert(system("ping localhost -c 1 -W 1 -q > /dev/null")); + assert(system("ping localhost -c 1 -W 1 -q > /dev/null") == 0); + + /* Check the final value of the counter in the cgroup local storage */ + if (bpf_map_lookup_elem(map_fd, &key, &value)) { + printf("Failed to lookup the cgroup storage\n"); + goto err; + } + + if (value != 7) { + printf("Unexpected data in the cgroup storage: %llu\n", value); + goto err; + } + + error = 0; + printf("test_cgroup_storage:PASS\n"); + +err: + cleanup_cgroup_environment(); + +out: + return error; +} diff --git a/tools/testing/selftests/bpf/test_maps.c b/tools/testing/selftests/bpf/test_maps.c index 6c253343a6f9..6f54f84144a0 100644 --- a/tools/testing/selftests/bpf/test_maps.c +++ b/tools/testing/selftests/bpf/test_maps.c @@ -17,7 +17,8 @@ #include <stdlib.h> #include <sys/wait.h> - +#include <sys/socket.h> +#include <netinet/in.h> #include <linux/bpf.h> #include <bpf/bpf.h> @@ -26,8 +27,21 @@ #include "bpf_util.h" #include "bpf_rlimit.h" +#ifndef ENOTSUPP +#define ENOTSUPP 524 +#endif + static int map_flags; +#define CHECK(condition, tag, format...) ({ \ + int __ret = !!(condition); \ + if (__ret) { \ + printf("%s(%d):FAIL:%s ", __func__, __LINE__, tag); \ + printf(format); \ + exit(-1); \ + } \ +}) + static void test_hashmap(int task, void *data) { long long key, next_key, first_key, value; @@ -1150,6 +1164,250 @@ static void test_map_wronly(void) assert(bpf_map_get_next_key(fd, &key, &value) == -1 && errno == EPERM); } +static void prepare_reuseport_grp(int type, int map_fd, + __s64 *fds64, __u64 *sk_cookies, + unsigned int n) +{ + socklen_t optlen, addrlen; + struct sockaddr_in6 s6; + const __u32 index0 = 0; + const int optval = 1; + unsigned int i; + u64 sk_cookie; + __s64 fd64; + int err; + + s6.sin6_family = AF_INET6; + s6.sin6_addr = in6addr_any; + s6.sin6_port = 0; + addrlen = sizeof(s6); + optlen = sizeof(sk_cookie); + + for (i = 0; i < n; i++) { + fd64 = socket(AF_INET6, type, 0); + CHECK(fd64 == -1, "socket()", + "sock_type:%d fd64:%lld errno:%d\n", + type, fd64, errno); + + err = setsockopt(fd64, SOL_SOCKET, SO_REUSEPORT, + &optval, sizeof(optval)); + CHECK(err == -1, "setsockopt(SO_REUSEPORT)", + "err:%d errno:%d\n", err, errno); + + /* reuseport_array does not allow unbound sk */ + err = bpf_map_update_elem(map_fd, &index0, &fd64, + BPF_ANY); + CHECK(err != -1 || errno != EINVAL, + "reuseport array update unbound sk", + "sock_type:%d err:%d errno:%d\n", + type, err, errno); + + err = bind(fd64, (struct sockaddr *)&s6, sizeof(s6)); + CHECK(err == -1, "bind()", + "sock_type:%d err:%d errno:%d\n", type, err, errno); + + if (i == 0) { + err = getsockname(fd64, (struct sockaddr *)&s6, + &addrlen); + CHECK(err == -1, "getsockname()", + "sock_type:%d err:%d errno:%d\n", + type, err, errno); + } + + err = getsockopt(fd64, SOL_SOCKET, SO_COOKIE, &sk_cookie, + &optlen); + CHECK(err == -1, "getsockopt(SO_COOKIE)", + "sock_type:%d err:%d errno:%d\n", type, err, errno); + + if (type == SOCK_STREAM) { + /* + * reuseport_array does not allow + * non-listening tcp sk. + */ + err = bpf_map_update_elem(map_fd, &index0, &fd64, + BPF_ANY); + CHECK(err != -1 || errno != EINVAL, + "reuseport array update non-listening sk", + "sock_type:%d err:%d errno:%d\n", + type, err, errno); + err = listen(fd64, 0); + CHECK(err == -1, "listen()", + "sock_type:%d, err:%d errno:%d\n", + type, err, errno); + } + + fds64[i] = fd64; + sk_cookies[i] = sk_cookie; + } +} + +static void test_reuseport_array(void) +{ +#define REUSEPORT_FD_IDX(err, last) ({ (err) ? last : !last; }) + + const __u32 array_size = 4, index0 = 0, index3 = 3; + int types[2] = { SOCK_STREAM, SOCK_DGRAM }, type; + __u64 grpa_cookies[2], sk_cookie, map_cookie; + __s64 grpa_fds64[2] = { -1, -1 }, fd64 = -1; + const __u32 bad_index = array_size; + int map_fd, err, t, f; + __u32 fds_idx = 0; + int fd; + + map_fd = bpf_create_map(BPF_MAP_TYPE_REUSEPORT_SOCKARRAY, + sizeof(__u32), sizeof(__u64), array_size, 0); + CHECK(map_fd == -1, "reuseport array create", + "map_fd:%d, errno:%d\n", map_fd, errno); + + /* Test lookup/update/delete with invalid index */ + err = bpf_map_delete_elem(map_fd, &bad_index); + CHECK(err != -1 || errno != E2BIG, "reuseport array del >=max_entries", + "err:%d errno:%d\n", err, errno); + + err = bpf_map_update_elem(map_fd, &bad_index, &fd64, BPF_ANY); + CHECK(err != -1 || errno != E2BIG, + "reuseport array update >=max_entries", + "err:%d errno:%d\n", err, errno); + + err = bpf_map_lookup_elem(map_fd, &bad_index, &map_cookie); + CHECK(err != -1 || errno != ENOENT, + "reuseport array update >=max_entries", + "err:%d errno:%d\n", err, errno); + + /* Test lookup/delete non existence elem */ + err = bpf_map_lookup_elem(map_fd, &index3, &map_cookie); + CHECK(err != -1 || errno != ENOENT, + "reuseport array lookup not-exist elem", + "err:%d errno:%d\n", err, errno); + err = bpf_map_delete_elem(map_fd, &index3); + CHECK(err != -1 || errno != ENOENT, + "reuseport array del not-exist elem", + "err:%d errno:%d\n", err, errno); + + for (t = 0; t < ARRAY_SIZE(types); t++) { + type = types[t]; + + prepare_reuseport_grp(type, map_fd, grpa_fds64, + grpa_cookies, ARRAY_SIZE(grpa_fds64)); + + /* Test BPF_* update flags */ + /* BPF_EXIST failure case */ + err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx], + BPF_EXIST); + CHECK(err != -1 || errno != ENOENT, + "reuseport array update empty elem BPF_EXIST", + "sock_type:%d err:%d errno:%d\n", + type, err, errno); + fds_idx = REUSEPORT_FD_IDX(err, fds_idx); + + /* BPF_NOEXIST success case */ + err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx], + BPF_NOEXIST); + CHECK(err == -1, + "reuseport array update empty elem BPF_NOEXIST", + "sock_type:%d err:%d errno:%d\n", + type, err, errno); + fds_idx = REUSEPORT_FD_IDX(err, fds_idx); + + /* BPF_EXIST success case. */ + err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx], + BPF_EXIST); + CHECK(err == -1, + "reuseport array update same elem BPF_EXIST", + "sock_type:%d err:%d errno:%d\n", type, err, errno); + fds_idx = REUSEPORT_FD_IDX(err, fds_idx); + + /* BPF_NOEXIST failure case */ + err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx], + BPF_NOEXIST); + CHECK(err != -1 || errno != EEXIST, + "reuseport array update non-empty elem BPF_NOEXIST", + "sock_type:%d err:%d errno:%d\n", + type, err, errno); + fds_idx = REUSEPORT_FD_IDX(err, fds_idx); + + /* BPF_ANY case (always succeed) */ + err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx], + BPF_ANY); + CHECK(err == -1, + "reuseport array update same sk with BPF_ANY", + "sock_type:%d err:%d errno:%d\n", type, err, errno); + + fd64 = grpa_fds64[fds_idx]; + sk_cookie = grpa_cookies[fds_idx]; + + /* The same sk cannot be added to reuseport_array twice */ + err = bpf_map_update_elem(map_fd, &index3, &fd64, BPF_ANY); + CHECK(err != -1 || errno != EBUSY, + "reuseport array update same sk with same index", + "sock_type:%d err:%d errno:%d\n", + type, err, errno); + + err = bpf_map_update_elem(map_fd, &index0, &fd64, BPF_ANY); + CHECK(err != -1 || errno != EBUSY, + "reuseport array update same sk with different index", + "sock_type:%d err:%d errno:%d\n", + type, err, errno); + + /* Test delete elem */ + err = bpf_map_delete_elem(map_fd, &index3); + CHECK(err == -1, "reuseport array delete sk", + "sock_type:%d err:%d errno:%d\n", + type, err, errno); + + /* Add it back with BPF_NOEXIST */ + err = bpf_map_update_elem(map_fd, &index3, &fd64, BPF_NOEXIST); + CHECK(err == -1, + "reuseport array re-add with BPF_NOEXIST after del", + "sock_type:%d err:%d errno:%d\n", type, err, errno); + + /* Test cookie */ + err = bpf_map_lookup_elem(map_fd, &index3, &map_cookie); + CHECK(err == -1 || sk_cookie != map_cookie, + "reuseport array lookup re-added sk", + "sock_type:%d err:%d errno:%d sk_cookie:0x%llx map_cookie:0x%llxn", + type, err, errno, sk_cookie, map_cookie); + + /* Test elem removed by close() */ + for (f = 0; f < ARRAY_SIZE(grpa_fds64); f++) + close(grpa_fds64[f]); + err = bpf_map_lookup_elem(map_fd, &index3, &map_cookie); + CHECK(err != -1 || errno != ENOENT, + "reuseport array lookup after close()", + "sock_type:%d err:%d errno:%d\n", + type, err, errno); + } + + /* Test SOCK_RAW */ + fd64 = socket(AF_INET6, SOCK_RAW, IPPROTO_UDP); + CHECK(fd64 == -1, "socket(SOCK_RAW)", "err:%d errno:%d\n", + err, errno); + err = bpf_map_update_elem(map_fd, &index3, &fd64, BPF_NOEXIST); + CHECK(err != -1 || errno != ENOTSUPP, "reuseport array update SOCK_RAW", + "err:%d errno:%d\n", err, errno); + close(fd64); + + /* Close the 64 bit value map */ + close(map_fd); + + /* Test 32 bit fd */ + map_fd = bpf_create_map(BPF_MAP_TYPE_REUSEPORT_SOCKARRAY, + sizeof(__u32), sizeof(__u32), array_size, 0); + CHECK(map_fd == -1, "reuseport array create", + "map_fd:%d, errno:%d\n", map_fd, errno); + prepare_reuseport_grp(SOCK_STREAM, map_fd, &fd64, &sk_cookie, 1); + fd = fd64; + err = bpf_map_update_elem(map_fd, &index3, &fd, BPF_NOEXIST); + CHECK(err == -1, "reuseport array update 32 bit fd", + "err:%d errno:%d\n", err, errno); + err = bpf_map_lookup_elem(map_fd, &index3, &map_cookie); + CHECK(err != -1 || errno != ENOSPC, + "reuseport array lookup 32 bit fd", + "err:%d errno:%d\n", err, errno); + close(fd); + close(map_fd); +} + static void run_all_tests(void) { test_hashmap(0, NULL); @@ -1170,6 +1428,8 @@ static void run_all_tests(void) test_map_rdonly(); test_map_wronly(); + + test_reuseport_array(); } int main(void) diff --git a/tools/testing/selftests/bpf/test_offload.py b/tools/testing/selftests/bpf/test_offload.py index be800d0e7a84..d59642e70f56 100755 --- a/tools/testing/selftests/bpf/test_offload.py +++ b/tools/testing/selftests/bpf/test_offload.py @@ -158,8 +158,9 @@ def tool(name, args, flags, JSON=True, ns="", fail=True, include_stderr=False): else: return ret, out -def bpftool(args, JSON=True, ns="", fail=True): - return tool("bpftool", args, {"json":"-p"}, JSON=JSON, ns=ns, fail=fail) +def bpftool(args, JSON=True, ns="", fail=True, include_stderr=False): + return tool("bpftool", args, {"json":"-p"}, JSON=JSON, ns=ns, + fail=fail, include_stderr=include_stderr) def bpftool_prog_list(expected=None, ns=""): _, progs = bpftool("prog show", JSON=True, ns=ns, fail=True) @@ -201,6 +202,21 @@ def bpftool_map_list_wait(expected=0, n_retry=20): time.sleep(0.05) raise Exception("Time out waiting for map counts to stabilize want %d, have %d" % (expected, nmaps)) +def bpftool_prog_load(sample, file_name, maps=[], prog_type="xdp", dev=None, + fail=True, include_stderr=False): + args = "prog load %s %s" % (os.path.join(bpf_test_dir, sample), file_name) + if prog_type is not None: + args += " type " + prog_type + if dev is not None: + args += " dev " + dev + if len(maps): + args += " map " + " map ".join(maps) + + res = bpftool(args, fail=fail, include_stderr=include_stderr) + if res[0] == 0: + files.append(file_name) + return res + def ip(args, force=False, JSON=True, ns="", fail=True, include_stderr=False): if force: args = "-force " + args @@ -307,21 +323,25 @@ class NetdevSim: Class for netdevsim netdevice and its attributes. """ - def __init__(self): + def __init__(self, link=None): + self.link = link + self.dev = self._netdevsim_create() devs.append(self) self.ns = "" self.dfs_dir = '/sys/kernel/debug/netdevsim/%s' % (self.dev['ifname']) + self.sdev_dir = self.dfs_dir + '/sdev/' self.dfs_refresh() def __getitem__(self, key): return self.dev[key] def _netdevsim_create(self): + link = "" if self.link is None else "link " + self.link.dev['ifname'] _, old = ip("link show") - ip("link add sim%d type netdevsim") + ip("link add sim%d {link} type netdevsim".format(link=link)) _, new = ip("link show") for dev in new: @@ -339,13 +359,18 @@ class NetdevSim: self.dfs = DebugfsDir(self.dfs_dir) return self.dfs + def dfs_read(self, f): + path = os.path.join(self.dfs_dir, f) + _, data = cmd('cat %s' % (path)) + return data.strip() + def dfs_num_bound_progs(self): - path = os.path.join(self.dfs_dir, "bpf_bound_progs") + path = os.path.join(self.sdev_dir, "bpf_bound_progs") _, progs = cmd('ls %s' % (path)) return len(progs.split()) def dfs_get_bound_progs(self, expected): - progs = DebugfsDir(os.path.join(self.dfs_dir, "bpf_bound_progs")) + progs = DebugfsDir(os.path.join(self.sdev_dir, "bpf_bound_progs")) if expected is not None: if len(progs) != expected: fail(True, "%d BPF programs bound, expected %d" % @@ -547,11 +572,11 @@ def check_extack(output, reference, args): if skip_extack: return lines = output.split("\n") - comp = len(lines) >= 2 and lines[1] == reference + comp = len(lines) >= 2 and lines[1] == 'Error: ' + reference fail(not comp, "Missing or incorrect netlink extack message") def check_extack_nsim(output, reference, args): - check_extack(output, "Error: netdevsim: " + reference, args) + check_extack(output, "netdevsim: " + reference, args) def check_no_extack(res, needle): fail((res[1] + res[2]).count(needle) or (res[1] + res[2]).count("Warning:"), @@ -654,7 +679,7 @@ try: ret, _, err = sim.cls_bpf_add_filter(obj, skip_sw=True, fail=False, include_stderr=True) fail(ret == 0, "TC filter loaded without enabling TC offloads") - check_extack(err, "Error: TC offload is disabled on net device.", args) + check_extack(err, "TC offload is disabled on net device.", args) sim.wait_for_flush() sim.set_ethtool_tc_offloads(True) @@ -694,7 +719,7 @@ try: skip_sw=True, fail=False, include_stderr=True) fail(ret == 0, "Offloaded a filter to chain other than 0") - check_extack(err, "Error: Driver supports only offload of chain 0.", args) + check_extack(err, "Driver supports only offload of chain 0.", args) sim.tc_flush_filters() start_test("Test TC replace...") @@ -814,24 +839,20 @@ try: "Device parameters reported for non-offloaded program") start_test("Test XDP prog replace with bad flags...") - ret, _, err = sim.set_xdp(obj, "offload", force=True, + ret, _, err = sim.set_xdp(obj, "generic", force=True, fail=False, include_stderr=True) fail(ret == 0, "Replaced XDP program with a program in different mode") - check_extack_nsim(err, "program loaded with different flags.", args) + fail(err.count("File exists") != 1, "Replaced driver XDP with generic") ret, _, err = sim.set_xdp(obj, "", force=True, fail=False, include_stderr=True) fail(ret == 0, "Replaced XDP program with a program in different mode") - check_extack_nsim(err, "program loaded with different flags.", args) + check_extack(err, "program loaded with different flags.", args) start_test("Test XDP prog remove with bad flags...") - ret, _, err = sim.unset_xdp("offload", force=True, - fail=False, include_stderr=True) - fail(ret == 0, "Removed program with a bad mode mode") - check_extack_nsim(err, "program loaded with different flags.", args) ret, _, err = sim.unset_xdp("", force=True, fail=False, include_stderr=True) - fail(ret == 0, "Removed program with a bad mode mode") - check_extack_nsim(err, "program loaded with different flags.", args) + fail(ret == 0, "Removed program with a bad mode") + check_extack(err, "program loaded with different flags.", args) start_test("Test MTU restrictions...") ret, _ = sim.set_mtu(9000, fail=False) @@ -846,6 +867,25 @@ try: sim.set_mtu(1500) sim.wait_for_flush() + start_test("Test non-offload XDP attaching to HW...") + bpftool_prog_load("sample_ret0.o", "/sys/fs/bpf/nooffload") + nooffload = bpf_pinned("/sys/fs/bpf/nooffload") + ret, _, err = sim.set_xdp(nooffload, "offload", + fail=False, include_stderr=True) + fail(ret == 0, "attached non-offloaded XDP program to HW") + check_extack_nsim(err, "xdpoffload of non-bound program.", args) + rm("/sys/fs/bpf/nooffload") + + start_test("Test offload XDP attaching to drv...") + bpftool_prog_load("sample_ret0.o", "/sys/fs/bpf/offload", + dev=sim['ifname']) + offload = bpf_pinned("/sys/fs/bpf/offload") + ret, _, err = sim.set_xdp(offload, "drv", fail=False, include_stderr=True) + fail(ret == 0, "attached offloaded XDP program to drv") + check_extack(err, "using device-bound program without HW_MODE flag is not supported.", args) + rm("/sys/fs/bpf/offload") + sim.wait_for_flush() + start_test("Test XDP offload...") _, _, err = sim.set_xdp(obj, "offload", verbose=True, include_stderr=True) ipl = sim.ip_link_show(xdp=True) @@ -891,6 +931,60 @@ try: rm(pin_file) bpftool_prog_list_wait(expected=0) + start_test("Test multi-attachment XDP - attach...") + sim.set_xdp(obj, "offload") + xdp = sim.ip_link_show(xdp=True)["xdp"] + offloaded = sim.dfs_read("bpf_offloaded_id") + fail("prog" not in xdp, "Base program not reported in single program mode") + fail(len(ipl["xdp"]["attached"]) != 1, + "Wrong attached program count with one program") + + sim.set_xdp(obj, "") + two_xdps = sim.ip_link_show(xdp=True)["xdp"] + offloaded2 = sim.dfs_read("bpf_offloaded_id") + + fail(two_xdps["mode"] != 4, "Bad mode reported with multiple programs") + fail("prog" in two_xdps, "Base program reported in multi program mode") + fail(xdp["attached"][0] not in two_xdps["attached"], + "Offload program not reported after driver activated") + fail(len(two_xdps["attached"]) != 2, + "Wrong attached program count with two programs") + fail(two_xdps["attached"][0]["prog"]["id"] == + two_xdps["attached"][1]["prog"]["id"], + "offloaded and drv programs have the same id") + fail(offloaded != offloaded2, + "offload ID changed after loading driver program") + + start_test("Test multi-attachment XDP - replace...") + ret, _, err = sim.set_xdp(obj, "offload", fail=False, include_stderr=True) + fail(err.count("busy") != 1, "Replaced one of programs without -force") + + start_test("Test multi-attachment XDP - detach...") + ret, _, err = sim.unset_xdp("drv", force=True, + fail=False, include_stderr=True) + fail(ret == 0, "Removed program with a bad mode") + check_extack(err, "program loaded with different flags.", args) + + sim.unset_xdp("offload") + xdp = sim.ip_link_show(xdp=True)["xdp"] + offloaded = sim.dfs_read("bpf_offloaded_id") + + fail(xdp["mode"] != 1, "Bad mode reported after multiple programs") + fail("prog" not in xdp, + "Base program not reported after multi program mode") + fail(xdp["attached"][0] not in two_xdps["attached"], + "Offload program not reported after driver activated") + fail(len(ipl["xdp"]["attached"]) != 1, + "Wrong attached program count with remaining programs") + fail(offloaded != "0", "offload ID reported with only driver program left") + + start_test("Test multi-attachment XDP - device remove...") + sim.set_xdp(obj, "offload") + sim.remove() + + sim = NetdevSim() + sim.set_ethtool_tc_offloads(True) + start_test("Test mixing of TC and XDP...") sim.tc_add_ingress() sim.set_xdp(obj, "offload") @@ -1085,6 +1179,106 @@ try: fail(ret == 0, "netdevsim didn't refuse to create a map with offload disabled") + sim.remove() + + start_test("Test multi-dev ASIC program reuse...") + simA = NetdevSim() + simB1 = NetdevSim() + simB2 = NetdevSim(link=simB1) + simB3 = NetdevSim(link=simB1) + sims = (simA, simB1, simB2, simB3) + simB = (simB1, simB2, simB3) + + bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimA", + dev=simA['ifname']) + progA = bpf_pinned("/sys/fs/bpf/nsimA") + bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimB", + dev=simB1['ifname']) + progB = bpf_pinned("/sys/fs/bpf/nsimB") + + simA.set_xdp(progA, "offload", JSON=False) + for d in simB: + d.set_xdp(progB, "offload", JSON=False) + + start_test("Test multi-dev ASIC cross-dev replace...") + ret, _ = simA.set_xdp(progB, "offload", force=True, JSON=False, fail=False) + fail(ret == 0, "cross-ASIC program allowed") + for d in simB: + ret, _ = d.set_xdp(progA, "offload", force=True, JSON=False, fail=False) + fail(ret == 0, "cross-ASIC program allowed") + + start_test("Test multi-dev ASIC cross-dev install...") + for d in sims: + d.unset_xdp("offload") + + ret, _, err = simA.set_xdp(progB, "offload", force=True, JSON=False, + fail=False, include_stderr=True) + fail(ret == 0, "cross-ASIC program allowed") + check_extack_nsim(err, "program bound to different dev.", args) + for d in simB: + ret, _, err = d.set_xdp(progA, "offload", force=True, JSON=False, + fail=False, include_stderr=True) + fail(ret == 0, "cross-ASIC program allowed") + check_extack_nsim(err, "program bound to different dev.", args) + + start_test("Test multi-dev ASIC cross-dev map reuse...") + + mapA = bpftool("prog show %s" % (progA))[1]["map_ids"][0] + mapB = bpftool("prog show %s" % (progB))[1]["map_ids"][0] + + ret, _ = bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimB_", + dev=simB3['ifname'], + maps=["idx 0 id %d" % (mapB)], + fail=False) + fail(ret != 0, "couldn't reuse a map on the same ASIC") + rm("/sys/fs/bpf/nsimB_") + + ret, _, err = bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimA_", + dev=simA['ifname'], + maps=["idx 0 id %d" % (mapB)], + fail=False, include_stderr=True) + fail(ret == 0, "could reuse a map on a different ASIC") + fail(err.count("offload device mismatch between prog and map") == 0, + "error message missing for cross-ASIC map") + + ret, _, err = bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimB_", + dev=simB1['ifname'], + maps=["idx 0 id %d" % (mapA)], + fail=False, include_stderr=True) + fail(ret == 0, "could reuse a map on a different ASIC") + fail(err.count("offload device mismatch between prog and map") == 0, + "error message missing for cross-ASIC map") + + start_test("Test multi-dev ASIC cross-dev destruction...") + bpftool_prog_list_wait(expected=2) + + simA.remove() + bpftool_prog_list_wait(expected=1) + + ifnameB = bpftool("prog show %s" % (progB))[1]["dev"]["ifname"] + fail(ifnameB != simB1['ifname'], "program not bound to originial device") + simB1.remove() + bpftool_prog_list_wait(expected=1) + + start_test("Test multi-dev ASIC cross-dev destruction - move...") + ifnameB = bpftool("prog show %s" % (progB))[1]["dev"]["ifname"] + fail(ifnameB not in (simB2['ifname'], simB3['ifname']), + "program not bound to remaining devices") + + simB2.remove() + ifnameB = bpftool("prog show %s" % (progB))[1]["dev"]["ifname"] + fail(ifnameB != simB3['ifname'], "program not bound to remaining device") + + simB3.remove() + bpftool_prog_list_wait(expected=0) + + start_test("Test multi-dev ASIC cross-dev destruction - orphaned...") + ret, out = bpftool("prog show %s" % (progB), fail=False) + fail(ret == 0, "got information about orphaned program") + fail("error" not in out, "no error reported for get info on orphaned") + fail(out["error"] != "can't get prog info: No such device", + "wrong error for get info on orphaned") + print("%s: OK" % (os.path.basename(__file__))) finally: diff --git a/tools/testing/selftests/bpf/test_select_reuseport.c b/tools/testing/selftests/bpf/test_select_reuseport.c new file mode 100644 index 000000000000..75646d9b34aa --- /dev/null +++ b/tools/testing/selftests/bpf/test_select_reuseport.c @@ -0,0 +1,688 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2018 Facebook */ + +#include <stdlib.h> +#include <unistd.h> +#include <stdbool.h> +#include <string.h> +#include <errno.h> +#include <assert.h> +#include <fcntl.h> +#include <linux/bpf.h> +#include <linux/err.h> +#include <linux/types.h> +#include <linux/if_ether.h> +#include <sys/types.h> +#include <sys/epoll.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <bpf/bpf.h> +#include <bpf/libbpf.h> +#include "bpf_rlimit.h" +#include "bpf_util.h" +#include "test_select_reuseport_common.h" + +#define MIN_TCPHDR_LEN 20 +#define UDPHDR_LEN 8 + +#define TCP_SYNCOOKIE_SYSCTL "/proc/sys/net/ipv4/tcp_syncookies" +#define TCP_FO_SYSCTL "/proc/sys/net/ipv4/tcp_fastopen" +#define REUSEPORT_ARRAY_SIZE 32 + +static int result_map, tmp_index_ovr_map, linum_map, data_check_map; +static enum result expected_results[NR_RESULTS]; +static int sk_fds[REUSEPORT_ARRAY_SIZE]; +static int reuseport_array, outer_map; +static int select_by_skb_data_prog; +static int saved_tcp_syncookie; +static struct bpf_object *obj; +static int saved_tcp_fo; +static __u32 index_zero; +static int epfd; + +static union sa46 { + struct sockaddr_in6 v6; + struct sockaddr_in v4; + sa_family_t family; +} srv_sa; + +#define CHECK(condition, tag, format...) ({ \ + int __ret = !!(condition); \ + if (__ret) { \ + printf("%s(%d):FAIL:%s ", __func__, __LINE__, tag); \ + printf(format); \ + exit(-1); \ + } \ +}) + +static void create_maps(void) +{ + struct bpf_create_map_attr attr = {}; + + /* Creating reuseport_array */ + attr.name = "reuseport_array"; + attr.map_type = BPF_MAP_TYPE_REUSEPORT_SOCKARRAY; + attr.key_size = sizeof(__u32); + attr.value_size = sizeof(__u32); + attr.max_entries = REUSEPORT_ARRAY_SIZE; + + reuseport_array = bpf_create_map_xattr(&attr); + CHECK(reuseport_array == -1, "creating reuseport_array", + "reuseport_array:%d errno:%d\n", reuseport_array, errno); + + /* Creating outer_map */ + attr.name = "outer_map"; + attr.map_type = BPF_MAP_TYPE_ARRAY_OF_MAPS; + attr.key_size = sizeof(__u32); + attr.value_size = sizeof(__u32); + attr.max_entries = 1; + attr.inner_map_fd = reuseport_array; + outer_map = bpf_create_map_xattr(&attr); + CHECK(outer_map == -1, "creating outer_map", + "outer_map:%d errno:%d\n", outer_map, errno); +} + +static void prepare_bpf_obj(void) +{ + struct bpf_program *prog; + struct bpf_map *map; + int err; + struct bpf_object_open_attr attr = { + .file = "test_select_reuseport_kern.o", + .prog_type = BPF_PROG_TYPE_SK_REUSEPORT, + }; + + obj = bpf_object__open_xattr(&attr); + CHECK(IS_ERR_OR_NULL(obj), "open test_select_reuseport_kern.o", + "obj:%p PTR_ERR(obj):%ld\n", obj, PTR_ERR(obj)); + + prog = bpf_program__next(NULL, obj); + CHECK(!prog, "get first bpf_program", "!prog\n"); + bpf_program__set_type(prog, attr.prog_type); + + map = bpf_object__find_map_by_name(obj, "outer_map"); + CHECK(!map, "find outer_map", "!map\n"); + err = bpf_map__reuse_fd(map, outer_map); + CHECK(err, "reuse outer_map", "err:%d\n", err); + + err = bpf_object__load(obj); + CHECK(err, "load bpf_object", "err:%d\n", err); + + select_by_skb_data_prog = bpf_program__fd(prog); + CHECK(select_by_skb_data_prog == -1, "get prog fd", + "select_by_skb_data_prog:%d\n", select_by_skb_data_prog); + + map = bpf_object__find_map_by_name(obj, "result_map"); + CHECK(!map, "find result_map", "!map\n"); + result_map = bpf_map__fd(map); + CHECK(result_map == -1, "get result_map fd", + "result_map:%d\n", result_map); + + map = bpf_object__find_map_by_name(obj, "tmp_index_ovr_map"); + CHECK(!map, "find tmp_index_ovr_map", "!map\n"); + tmp_index_ovr_map = bpf_map__fd(map); + CHECK(tmp_index_ovr_map == -1, "get tmp_index_ovr_map fd", + "tmp_index_ovr_map:%d\n", tmp_index_ovr_map); + + map = bpf_object__find_map_by_name(obj, "linum_map"); + CHECK(!map, "find linum_map", "!map\n"); + linum_map = bpf_map__fd(map); + CHECK(linum_map == -1, "get linum_map fd", + "linum_map:%d\n", linum_map); + + map = bpf_object__find_map_by_name(obj, "data_check_map"); + CHECK(!map, "find data_check_map", "!map\n"); + data_check_map = bpf_map__fd(map); + CHECK(data_check_map == -1, "get data_check_map fd", + "data_check_map:%d\n", data_check_map); +} + +static void sa46_init_loopback(union sa46 *sa, sa_family_t family) +{ + memset(sa, 0, sizeof(*sa)); + sa->family = family; + if (sa->family == AF_INET6) + sa->v6.sin6_addr = in6addr_loopback; + else + sa->v4.sin_addr.s_addr = htonl(INADDR_LOOPBACK); +} + +static void sa46_init_inany(union sa46 *sa, sa_family_t family) +{ + memset(sa, 0, sizeof(*sa)); + sa->family = family; + if (sa->family == AF_INET6) + sa->v6.sin6_addr = in6addr_any; + else + sa->v4.sin_addr.s_addr = INADDR_ANY; +} + +static int read_int_sysctl(const char *sysctl) +{ + char buf[16]; + int fd, ret; + + fd = open(sysctl, 0); + CHECK(fd == -1, "open(sysctl)", "sysctl:%s fd:%d errno:%d\n", + sysctl, fd, errno); + + ret = read(fd, buf, sizeof(buf)); + CHECK(ret <= 0, "read(sysctl)", "sysctl:%s ret:%d errno:%d\n", + sysctl, ret, errno); + close(fd); + + return atoi(buf); +} + +static void write_int_sysctl(const char *sysctl, int v) +{ + int fd, ret, size; + char buf[16]; + + fd = open(sysctl, O_RDWR); + CHECK(fd == -1, "open(sysctl)", "sysctl:%s fd:%d errno:%d\n", + sysctl, fd, errno); + + size = snprintf(buf, sizeof(buf), "%d", v); + ret = write(fd, buf, size); + CHECK(ret != size, "write(sysctl)", + "sysctl:%s ret:%d size:%d errno:%d\n", sysctl, ret, size, errno); + close(fd); +} + +static void restore_sysctls(void) +{ + write_int_sysctl(TCP_FO_SYSCTL, saved_tcp_fo); + write_int_sysctl(TCP_SYNCOOKIE_SYSCTL, saved_tcp_syncookie); +} + +static void enable_fastopen(void) +{ + int fo; + + fo = read_int_sysctl(TCP_FO_SYSCTL); + write_int_sysctl(TCP_FO_SYSCTL, fo | 7); +} + +static void enable_syncookie(void) +{ + write_int_sysctl(TCP_SYNCOOKIE_SYSCTL, 2); +} + +static void disable_syncookie(void) +{ + write_int_sysctl(TCP_SYNCOOKIE_SYSCTL, 0); +} + +static __u32 get_linum(void) +{ + __u32 linum; + int err; + + err = bpf_map_lookup_elem(linum_map, &index_zero, &linum); + CHECK(err == -1, "lookup_elem(linum_map)", "err:%d errno:%d\n", + err, errno); + + return linum; +} + +static void check_data(int type, sa_family_t family, const struct cmd *cmd, + int cli_fd) +{ + struct data_check expected = {}, result; + union sa46 cli_sa; + socklen_t addrlen; + int err; + + addrlen = sizeof(cli_sa); + err = getsockname(cli_fd, (struct sockaddr *)&cli_sa, + &addrlen); + CHECK(err == -1, "getsockname(cli_fd)", "err:%d errno:%d\n", + err, errno); + + err = bpf_map_lookup_elem(data_check_map, &index_zero, &result); + CHECK(err == -1, "lookup_elem(data_check_map)", "err:%d errno:%d\n", + err, errno); + + if (type == SOCK_STREAM) { + expected.len = MIN_TCPHDR_LEN; + expected.ip_protocol = IPPROTO_TCP; + } else { + expected.len = UDPHDR_LEN; + expected.ip_protocol = IPPROTO_UDP; + } + + if (family == AF_INET6) { + expected.eth_protocol = htons(ETH_P_IPV6); + expected.bind_inany = !srv_sa.v6.sin6_addr.s6_addr32[3] && + !srv_sa.v6.sin6_addr.s6_addr32[2] && + !srv_sa.v6.sin6_addr.s6_addr32[1] && + !srv_sa.v6.sin6_addr.s6_addr32[0]; + + memcpy(&expected.skb_addrs[0], cli_sa.v6.sin6_addr.s6_addr32, + sizeof(cli_sa.v6.sin6_addr)); + memcpy(&expected.skb_addrs[4], &in6addr_loopback, + sizeof(in6addr_loopback)); + expected.skb_ports[0] = cli_sa.v6.sin6_port; + expected.skb_ports[1] = srv_sa.v6.sin6_port; + } else { + expected.eth_protocol = htons(ETH_P_IP); + expected.bind_inany = !srv_sa.v4.sin_addr.s_addr; + + expected.skb_addrs[0] = cli_sa.v4.sin_addr.s_addr; + expected.skb_addrs[1] = htonl(INADDR_LOOPBACK); + expected.skb_ports[0] = cli_sa.v4.sin_port; + expected.skb_ports[1] = srv_sa.v4.sin_port; + } + + if (memcmp(&result, &expected, offsetof(struct data_check, + equal_check_end))) { + printf("unexpected data_check\n"); + printf(" result: (0x%x, %u, %u)\n", + result.eth_protocol, result.ip_protocol, + result.bind_inany); + printf("expected: (0x%x, %u, %u)\n", + expected.eth_protocol, expected.ip_protocol, + expected.bind_inany); + CHECK(1, "data_check result != expected", + "bpf_prog_linum:%u\n", get_linum()); + } + + CHECK(!result.hash, "data_check result.hash empty", + "result.hash:%u", result.hash); + + expected.len += cmd ? sizeof(*cmd) : 0; + if (type == SOCK_STREAM) + CHECK(expected.len > result.len, "expected.len > result.len", + "expected.len:%u result.len:%u bpf_prog_linum:%u\n", + expected.len, result.len, get_linum()); + else + CHECK(expected.len != result.len, "expected.len != result.len", + "expected.len:%u result.len:%u bpf_prog_linum:%u\n", + expected.len, result.len, get_linum()); +} + +static void check_results(void) +{ + __u32 results[NR_RESULTS]; + __u32 i, broken = 0; + int err; + + for (i = 0; i < NR_RESULTS; i++) { + err = bpf_map_lookup_elem(result_map, &i, &results[i]); + CHECK(err == -1, "lookup_elem(result_map)", + "i:%u err:%d errno:%d\n", i, err, errno); + } + + for (i = 0; i < NR_RESULTS; i++) { + if (results[i] != expected_results[i]) { + broken = i; + break; + } + } + + if (i == NR_RESULTS) + return; + + printf("unexpected result\n"); + printf(" result: ["); + printf("%u", results[0]); + for (i = 1; i < NR_RESULTS; i++) + printf(", %u", results[i]); + printf("]\n"); + + printf("expected: ["); + printf("%u", expected_results[0]); + for (i = 1; i < NR_RESULTS; i++) + printf(", %u", expected_results[i]); + printf("]\n"); + + CHECK(expected_results[broken] != results[broken], + "unexpected result", + "expected_results[%u] != results[%u] bpf_prog_linum:%u\n", + broken, broken, get_linum()); +} + +static int send_data(int type, sa_family_t family, void *data, size_t len, + enum result expected) +{ + union sa46 cli_sa; + int fd, err; + + fd = socket(family, type, 0); + CHECK(fd == -1, "socket()", "fd:%d errno:%d\n", fd, errno); + + sa46_init_loopback(&cli_sa, family); + err = bind(fd, (struct sockaddr *)&cli_sa, sizeof(cli_sa)); + CHECK(fd == -1, "bind(cli_sa)", "err:%d errno:%d\n", err, errno); + + err = sendto(fd, data, len, MSG_FASTOPEN, (struct sockaddr *)&srv_sa, + sizeof(srv_sa)); + CHECK(err != len && expected >= PASS, + "sendto()", "family:%u err:%d errno:%d expected:%d\n", + family, err, errno, expected); + + return fd; +} + +static void do_test(int type, sa_family_t family, struct cmd *cmd, + enum result expected) +{ + int nev, srv_fd, cli_fd; + struct epoll_event ev; + struct cmd rcv_cmd; + ssize_t nread; + + cli_fd = send_data(type, family, cmd, cmd ? sizeof(*cmd) : 0, + expected); + nev = epoll_wait(epfd, &ev, 1, expected >= PASS ? 5 : 0); + CHECK((nev <= 0 && expected >= PASS) || + (nev > 0 && expected < PASS), + "nev <> expected", + "nev:%d expected:%d type:%d family:%d data:(%d, %d)\n", + nev, expected, type, family, + cmd ? cmd->reuseport_index : -1, + cmd ? cmd->pass_on_failure : -1); + check_results(); + check_data(type, family, cmd, cli_fd); + + if (expected < PASS) + return; + + CHECK(expected != PASS_ERR_SK_SELECT_REUSEPORT && + cmd->reuseport_index != ev.data.u32, + "check cmd->reuseport_index", + "cmd:(%u, %u) ev.data.u32:%u\n", + cmd->pass_on_failure, cmd->reuseport_index, ev.data.u32); + + srv_fd = sk_fds[ev.data.u32]; + if (type == SOCK_STREAM) { + int new_fd = accept(srv_fd, NULL, 0); + + CHECK(new_fd == -1, "accept(srv_fd)", + "ev.data.u32:%u new_fd:%d errno:%d\n", + ev.data.u32, new_fd, errno); + + nread = recv(new_fd, &rcv_cmd, sizeof(rcv_cmd), MSG_DONTWAIT); + CHECK(nread != sizeof(rcv_cmd), + "recv(new_fd)", + "ev.data.u32:%u nread:%zd sizeof(rcv_cmd):%zu errno:%d\n", + ev.data.u32, nread, sizeof(rcv_cmd), errno); + + close(new_fd); + } else { + nread = recv(srv_fd, &rcv_cmd, sizeof(rcv_cmd), MSG_DONTWAIT); + CHECK(nread != sizeof(rcv_cmd), + "recv(sk_fds)", + "ev.data.u32:%u nread:%zd sizeof(rcv_cmd):%zu errno:%d\n", + ev.data.u32, nread, sizeof(rcv_cmd), errno); + } + + close(cli_fd); +} + +static void test_err_inner_map(int type, sa_family_t family) +{ + struct cmd cmd = { + .reuseport_index = 0, + .pass_on_failure = 0, + }; + + printf("%s: ", __func__); + expected_results[DROP_ERR_INNER_MAP]++; + do_test(type, family, &cmd, DROP_ERR_INNER_MAP); + printf("OK\n"); +} + +static void test_err_skb_data(int type, sa_family_t family) +{ + printf("%s: ", __func__); + expected_results[DROP_ERR_SKB_DATA]++; + do_test(type, family, NULL, DROP_ERR_SKB_DATA); + printf("OK\n"); +} + +static void test_err_sk_select_port(int type, sa_family_t family) +{ + struct cmd cmd = { + .reuseport_index = REUSEPORT_ARRAY_SIZE, + .pass_on_failure = 0, + }; + + printf("%s: ", __func__); + expected_results[DROP_ERR_SK_SELECT_REUSEPORT]++; + do_test(type, family, &cmd, DROP_ERR_SK_SELECT_REUSEPORT); + printf("OK\n"); +} + +static void test_pass(int type, sa_family_t family) +{ + struct cmd cmd; + int i; + + printf("%s: ", __func__); + cmd.pass_on_failure = 0; + for (i = 0; i < REUSEPORT_ARRAY_SIZE; i++) { + expected_results[PASS]++; + cmd.reuseport_index = i; + do_test(type, family, &cmd, PASS); + } + printf("OK\n"); +} + +static void test_syncookie(int type, sa_family_t family) +{ + int err, tmp_index = 1; + struct cmd cmd = { + .reuseport_index = 0, + .pass_on_failure = 0, + }; + + if (type != SOCK_STREAM) + return; + + printf("%s: ", __func__); + /* + * +1 for TCP-SYN and + * +1 for the TCP-ACK (ack the syncookie) + */ + expected_results[PASS] += 2; + enable_syncookie(); + /* + * Simulate TCP-SYN and TCP-ACK are handled by two different sk: + * TCP-SYN: select sk_fds[tmp_index = 1] tmp_index is from the + * tmp_index_ovr_map + * TCP-ACK: select sk_fds[reuseport_index = 0] reuseport_index + * is from the cmd.reuseport_index + */ + err = bpf_map_update_elem(tmp_index_ovr_map, &index_zero, + &tmp_index, BPF_ANY); + CHECK(err == -1, "update_elem(tmp_index_ovr_map, 0, 1)", + "err:%d errno:%d\n", err, errno); + do_test(type, family, &cmd, PASS); + err = bpf_map_lookup_elem(tmp_index_ovr_map, &index_zero, + &tmp_index); + CHECK(err == -1 || tmp_index != -1, + "lookup_elem(tmp_index_ovr_map)", + "err:%d errno:%d tmp_index:%d\n", + err, errno, tmp_index); + disable_syncookie(); + printf("OK\n"); +} + +static void test_pass_on_err(int type, sa_family_t family) +{ + struct cmd cmd = { + .reuseport_index = REUSEPORT_ARRAY_SIZE, + .pass_on_failure = 1, + }; + + printf("%s: ", __func__); + expected_results[PASS_ERR_SK_SELECT_REUSEPORT] += 1; + do_test(type, family, &cmd, PASS_ERR_SK_SELECT_REUSEPORT); + printf("OK\n"); +} + +static void prepare_sk_fds(int type, sa_family_t family, bool inany) +{ + const int first = REUSEPORT_ARRAY_SIZE - 1; + int i, err, optval = 1; + struct epoll_event ev; + socklen_t addrlen; + + if (inany) + sa46_init_inany(&srv_sa, family); + else + sa46_init_loopback(&srv_sa, family); + addrlen = sizeof(srv_sa); + + /* + * The sk_fds[] is filled from the back such that the order + * is exactly opposite to the (struct sock_reuseport *)reuse->socks[]. + */ + for (i = first; i >= 0; i--) { + sk_fds[i] = socket(family, type, 0); + CHECK(sk_fds[i] == -1, "socket()", "sk_fds[%d]:%d errno:%d\n", + i, sk_fds[i], errno); + err = setsockopt(sk_fds[i], SOL_SOCKET, SO_REUSEPORT, + &optval, sizeof(optval)); + CHECK(err == -1, "setsockopt(SO_REUSEPORT)", + "sk_fds[%d] err:%d errno:%d\n", + i, err, errno); + + if (i == first) { + err = setsockopt(sk_fds[i], SOL_SOCKET, + SO_ATTACH_REUSEPORT_EBPF, + &select_by_skb_data_prog, + sizeof(select_by_skb_data_prog)); + CHECK(err == -1, "setsockopt(SO_ATTACH_REUEPORT_EBPF)", + "err:%d errno:%d\n", err, errno); + } + + err = bind(sk_fds[i], (struct sockaddr *)&srv_sa, addrlen); + CHECK(err == -1, "bind()", "sk_fds[%d] err:%d errno:%d\n", + i, err, errno); + + if (type == SOCK_STREAM) { + err = listen(sk_fds[i], 10); + CHECK(err == -1, "listen()", + "sk_fds[%d] err:%d errno:%d\n", + i, err, errno); + } + + err = bpf_map_update_elem(reuseport_array, &i, &sk_fds[i], + BPF_NOEXIST); + CHECK(err == -1, "update_elem(reuseport_array)", + "sk_fds[%d] err:%d errno:%d\n", i, err, errno); + + if (i == first) { + socklen_t addrlen = sizeof(srv_sa); + + err = getsockname(sk_fds[i], (struct sockaddr *)&srv_sa, + &addrlen); + CHECK(err == -1, "getsockname()", + "sk_fds[%d] err:%d errno:%d\n", i, err, errno); + } + } + + epfd = epoll_create(1); + CHECK(epfd == -1, "epoll_create(1)", + "epfd:%d errno:%d\n", epfd, errno); + + ev.events = EPOLLIN; + for (i = 0; i < REUSEPORT_ARRAY_SIZE; i++) { + ev.data.u32 = i; + err = epoll_ctl(epfd, EPOLL_CTL_ADD, sk_fds[i], &ev); + CHECK(err, "epoll_ctl(EPOLL_CTL_ADD)", "sk_fds[%d]\n", i); + } +} + +static void setup_per_test(int type, unsigned short family, bool inany) +{ + int ovr = -1, err; + + prepare_sk_fds(type, family, inany); + err = bpf_map_update_elem(tmp_index_ovr_map, &index_zero, &ovr, + BPF_ANY); + CHECK(err == -1, "update_elem(tmp_index_ovr_map, 0, -1)", + "err:%d errno:%d\n", err, errno); +} + +static void cleanup_per_test(void) +{ + int i, err; + + for (i = 0; i < REUSEPORT_ARRAY_SIZE; i++) + close(sk_fds[i]); + close(epfd); + + err = bpf_map_delete_elem(outer_map, &index_zero); + CHECK(err == -1, "delete_elem(outer_map)", + "err:%d errno:%d\n", err, errno); +} + +static void cleanup(void) +{ + close(outer_map); + close(reuseport_array); + bpf_object__close(obj); +} + +static void test_all(void) +{ + /* Extra SOCK_STREAM to test bind_inany==true */ + const int types[] = { SOCK_STREAM, SOCK_DGRAM, SOCK_STREAM }; + const char * const type_strings[] = { "TCP", "UDP", "TCP" }; + const char * const family_strings[] = { "IPv6", "IPv4" }; + const unsigned short families[] = { AF_INET6, AF_INET }; + const bool bind_inany[] = { false, false, true }; + int t, f, err; + + for (f = 0; f < ARRAY_SIZE(families); f++) { + unsigned short family = families[f]; + + for (t = 0; t < ARRAY_SIZE(types); t++) { + bool inany = bind_inany[t]; + int type = types[t]; + + printf("######## %s/%s %s ########\n", + family_strings[f], type_strings[t], + inany ? " INANY " : "LOOPBACK"); + + setup_per_test(type, family, inany); + + test_err_inner_map(type, family); + + /* Install reuseport_array to the outer_map */ + err = bpf_map_update_elem(outer_map, &index_zero, + &reuseport_array, BPF_ANY); + CHECK(err == -1, "update_elem(outer_map)", + "err:%d errno:%d\n", err, errno); + + test_err_skb_data(type, family); + test_err_sk_select_port(type, family); + test_pass(type, family); + test_syncookie(type, family); + test_pass_on_err(type, family); + + cleanup_per_test(); + printf("\n"); + } + } +} + +int main(int argc, const char **argv) +{ + create_maps(); + prepare_bpf_obj(); + saved_tcp_fo = read_int_sysctl(TCP_FO_SYSCTL); + saved_tcp_syncookie = read_int_sysctl(TCP_SYNCOOKIE_SYSCTL); + enable_fastopen(); + disable_syncookie(); + atexit(restore_sysctls); + + test_all(); + + cleanup(); + return 0; +} diff --git a/tools/testing/selftests/bpf/test_select_reuseport_common.h b/tools/testing/selftests/bpf/test_select_reuseport_common.h new file mode 100644 index 000000000000..08eb2a9f145f --- /dev/null +++ b/tools/testing/selftests/bpf/test_select_reuseport_common.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2018 Facebook */ + +#ifndef __TEST_SELECT_REUSEPORT_COMMON_H +#define __TEST_SELECT_REUSEPORT_COMMON_H + +#include <linux/types.h> + +enum result { + DROP_ERR_INNER_MAP, + DROP_ERR_SKB_DATA, + DROP_ERR_SK_SELECT_REUSEPORT, + DROP_MISC, + PASS, + PASS_ERR_SK_SELECT_REUSEPORT, + NR_RESULTS, +}; + +struct cmd { + __u32 reuseport_index; + __u32 pass_on_failure; +}; + +struct data_check { + __u32 ip_protocol; + __u32 skb_addrs[8]; + __u16 skb_ports[2]; + __u16 eth_protocol; + __u8 bind_inany; + __u8 equal_check_end[0]; + + __u32 len; + __u32 hash; +}; + +#endif diff --git a/tools/testing/selftests/bpf/test_select_reuseport_kern.c b/tools/testing/selftests/bpf/test_select_reuseport_kern.c new file mode 100644 index 000000000000..5b54ec637ada --- /dev/null +++ b/tools/testing/selftests/bpf/test_select_reuseport_kern.c @@ -0,0 +1,180 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2018 Facebook */ + +#include <stdlib.h> +#include <linux/in.h> +#include <linux/ip.h> +#include <linux/ipv6.h> +#include <linux/tcp.h> +#include <linux/udp.h> +#include <linux/bpf.h> +#include <linux/types.h> +#include <linux/if_ether.h> + +#include "bpf_endian.h" +#include "bpf_helpers.h" +#include "test_select_reuseport_common.h" + +int _version SEC("version") = 1; + +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif + +struct bpf_map_def SEC("maps") outer_map = { + .type = BPF_MAP_TYPE_ARRAY_OF_MAPS, + .key_size = sizeof(__u32), + .value_size = sizeof(__u32), + .max_entries = 1, +}; + +struct bpf_map_def SEC("maps") result_map = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(__u32), + .max_entries = NR_RESULTS, +}; + +struct bpf_map_def SEC("maps") tmp_index_ovr_map = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(int), + .max_entries = 1, +}; + +struct bpf_map_def SEC("maps") linum_map = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(__u32), + .max_entries = 1, +}; + +struct bpf_map_def SEC("maps") data_check_map = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(struct data_check), + .max_entries = 1, +}; + +#define GOTO_DONE(_result) ({ \ + result = (_result); \ + linum = __LINE__; \ + goto done; \ +}) + +SEC("select_by_skb_data") +int _select_by_skb_data(struct sk_reuseport_md *reuse_md) +{ + __u32 linum, index = 0, flags = 0, index_zero = 0; + __u32 *result_cnt, *linum_value; + struct data_check data_check = {}; + struct cmd *cmd, cmd_copy; + void *data, *data_end; + void *reuseport_array; + enum result result; + int *index_ovr; + int err; + + data = reuse_md->data; + data_end = reuse_md->data_end; + data_check.len = reuse_md->len; + data_check.eth_protocol = reuse_md->eth_protocol; + data_check.ip_protocol = reuse_md->ip_protocol; + data_check.hash = reuse_md->hash; + data_check.bind_inany = reuse_md->bind_inany; + if (data_check.eth_protocol == bpf_htons(ETH_P_IP)) { + if (bpf_skb_load_bytes_relative(reuse_md, + offsetof(struct iphdr, saddr), + data_check.skb_addrs, 8, + BPF_HDR_START_NET)) + GOTO_DONE(DROP_MISC); + } else { + if (bpf_skb_load_bytes_relative(reuse_md, + offsetof(struct ipv6hdr, saddr), + data_check.skb_addrs, 32, + BPF_HDR_START_NET)) + GOTO_DONE(DROP_MISC); + } + + /* + * The ip_protocol could be a compile time decision + * if the bpf_prog.o is dedicated to either TCP or + * UDP. + * + * Otherwise, reuse_md->ip_protocol or + * the protocol field in the iphdr can be used. + */ + if (data_check.ip_protocol == IPPROTO_TCP) { + struct tcphdr *th = data; + + if (th + 1 > data_end) + GOTO_DONE(DROP_MISC); + + data_check.skb_ports[0] = th->source; + data_check.skb_ports[1] = th->dest; + + if ((th->doff << 2) + sizeof(*cmd) > data_check.len) + GOTO_DONE(DROP_ERR_SKB_DATA); + if (bpf_skb_load_bytes(reuse_md, th->doff << 2, &cmd_copy, + sizeof(cmd_copy))) + GOTO_DONE(DROP_MISC); + cmd = &cmd_copy; + } else if (data_check.ip_protocol == IPPROTO_UDP) { + struct udphdr *uh = data; + + if (uh + 1 > data_end) + GOTO_DONE(DROP_MISC); + + data_check.skb_ports[0] = uh->source; + data_check.skb_ports[1] = uh->dest; + + if (sizeof(struct udphdr) + sizeof(*cmd) > data_check.len) + GOTO_DONE(DROP_ERR_SKB_DATA); + if (data + sizeof(struct udphdr) + sizeof(*cmd) > data_end) { + if (bpf_skb_load_bytes(reuse_md, sizeof(struct udphdr), + &cmd_copy, sizeof(cmd_copy))) + GOTO_DONE(DROP_MISC); + cmd = &cmd_copy; + } else { + cmd = data + sizeof(struct udphdr); + } + } else { + GOTO_DONE(DROP_MISC); + } + + reuseport_array = bpf_map_lookup_elem(&outer_map, &index_zero); + if (!reuseport_array) + GOTO_DONE(DROP_ERR_INNER_MAP); + + index = cmd->reuseport_index; + index_ovr = bpf_map_lookup_elem(&tmp_index_ovr_map, &index_zero); + if (!index_ovr) + GOTO_DONE(DROP_MISC); + + if (*index_ovr != -1) { + index = *index_ovr; + *index_ovr = -1; + } + err = bpf_sk_select_reuseport(reuse_md, reuseport_array, &index, + flags); + if (!err) + GOTO_DONE(PASS); + + if (cmd->pass_on_failure) + GOTO_DONE(PASS_ERR_SK_SELECT_REUSEPORT); + else + GOTO_DONE(DROP_ERR_SK_SELECT_REUSEPORT); + +done: + result_cnt = bpf_map_lookup_elem(&result_map, &result); + if (!result_cnt) + return SK_DROP; + + bpf_map_update_elem(&linum_map, &index_zero, &linum, BPF_ANY); + bpf_map_update_elem(&data_check_map, &index_zero, &data_check, BPF_ANY); + + (*result_cnt)++; + return result < PASS ? SK_DROP : SK_PASS; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_skb_cgroup_id.sh b/tools/testing/selftests/bpf/test_skb_cgroup_id.sh new file mode 100755 index 000000000000..42544a969abc --- /dev/null +++ b/tools/testing/selftests/bpf/test_skb_cgroup_id.sh @@ -0,0 +1,62 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# Copyright (c) 2018 Facebook + +set -eu + +wait_for_ip() +{ + local _i + echo -n "Wait for testing link-local IP to become available " + for _i in $(seq ${MAX_PING_TRIES}); do + echo -n "." + if ping -6 -q -c 1 -W 1 ff02::1%${TEST_IF} >/dev/null 2>&1; then + echo " OK" + return + fi + sleep 1 + done + echo 1>&2 "ERROR: Timeout waiting for test IP to become available." + exit 1 +} + +setup() +{ + # Create testing interfaces not to interfere with current environment. + ip link add dev ${TEST_IF} type veth peer name ${TEST_IF_PEER} + ip link set ${TEST_IF} up + ip link set ${TEST_IF_PEER} up + + wait_for_ip + + tc qdisc add dev ${TEST_IF} clsact + tc filter add dev ${TEST_IF} egress bpf obj ${BPF_PROG_OBJ} \ + sec ${BPF_PROG_SECTION} da + + BPF_PROG_ID=$(tc filter show dev ${TEST_IF} egress | \ + awk '/ id / {sub(/.* id /, "", $0); print($1)}') +} + +cleanup() +{ + ip link del ${TEST_IF} 2>/dev/null || : + ip link del ${TEST_IF_PEER} 2>/dev/null || : +} + +main() +{ + trap cleanup EXIT 2 3 6 15 + setup + ${PROG} ${TEST_IF} ${BPF_PROG_ID} +} + +DIR=$(dirname $0) +TEST_IF="test_cgid_1" +TEST_IF_PEER="test_cgid_2" +MAX_PING_TRIES=5 +BPF_PROG_OBJ="${DIR}/test_skb_cgroup_id_kern.o" +BPF_PROG_SECTION="cgroup_id_logger" +BPF_PROG_ID=0 +PROG="${DIR}/test_skb_cgroup_id_user" + +main diff --git a/tools/testing/selftests/bpf/test_skb_cgroup_id_kern.c b/tools/testing/selftests/bpf/test_skb_cgroup_id_kern.c new file mode 100644 index 000000000000..68cf9829f5a7 --- /dev/null +++ b/tools/testing/selftests/bpf/test_skb_cgroup_id_kern.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Facebook + +#include <linux/bpf.h> +#include <linux/pkt_cls.h> + +#include <string.h> + +#include "bpf_helpers.h" + +#define NUM_CGROUP_LEVELS 4 + +struct bpf_map_def SEC("maps") cgroup_ids = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(__u64), + .max_entries = NUM_CGROUP_LEVELS, +}; + +static __always_inline void log_nth_level(struct __sk_buff *skb, __u32 level) +{ + __u64 id; + + /* [1] &level passed to external function that may change it, it's + * incompatible with loop unroll. + */ + id = bpf_skb_ancestor_cgroup_id(skb, level); + bpf_map_update_elem(&cgroup_ids, &level, &id, 0); +} + +SEC("cgroup_id_logger") +int log_cgroup_id(struct __sk_buff *skb) +{ + /* Loop unroll can't be used here due to [1]. Unrolling manually. + * Number of calls should be in sync with NUM_CGROUP_LEVELS. + */ + log_nth_level(skb, 0); + log_nth_level(skb, 1); + log_nth_level(skb, 2); + log_nth_level(skb, 3); + + return TC_ACT_OK; +} + +int _version SEC("version") = 1; + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_skb_cgroup_id_user.c b/tools/testing/selftests/bpf/test_skb_cgroup_id_user.c new file mode 100644 index 000000000000..c121cc59f314 --- /dev/null +++ b/tools/testing/selftests/bpf/test_skb_cgroup_id_user.c @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Facebook + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <arpa/inet.h> +#include <net/if.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <sys/types.h> + + +#include <bpf/bpf.h> +#include <bpf/libbpf.h> + +#include "bpf_rlimit.h" +#include "cgroup_helpers.h" + +#define CGROUP_PATH "/skb_cgroup_test" +#define NUM_CGROUP_LEVELS 4 + +/* RFC 4291, Section 2.7.1 */ +#define LINKLOCAL_MULTICAST "ff02::1" + +static int mk_dst_addr(const char *ip, const char *iface, + struct sockaddr_in6 *dst) +{ + memset(dst, 0, sizeof(*dst)); + + dst->sin6_family = AF_INET6; + dst->sin6_port = htons(1025); + + if (inet_pton(AF_INET6, ip, &dst->sin6_addr) != 1) { + log_err("Invalid IPv6: %s", ip); + return -1; + } + + dst->sin6_scope_id = if_nametoindex(iface); + if (!dst->sin6_scope_id) { + log_err("Failed to get index of iface: %s", iface); + return -1; + } + + return 0; +} + +static int send_packet(const char *iface) +{ + struct sockaddr_in6 dst; + char msg[] = "msg"; + int err = 0; + int fd = -1; + + if (mk_dst_addr(LINKLOCAL_MULTICAST, iface, &dst)) + goto err; + + fd = socket(AF_INET6, SOCK_DGRAM, 0); + if (fd == -1) { + log_err("Failed to create UDP socket"); + goto err; + } + + if (sendto(fd, &msg, sizeof(msg), 0, (const struct sockaddr *)&dst, + sizeof(dst)) == -1) { + log_err("Failed to send datagram"); + goto err; + } + + goto out; +err: + err = -1; +out: + if (fd >= 0) + close(fd); + return err; +} + +int get_map_fd_by_prog_id(int prog_id) +{ + struct bpf_prog_info info = {}; + __u32 info_len = sizeof(info); + __u32 map_ids[1]; + int prog_fd = -1; + int map_fd = -1; + + prog_fd = bpf_prog_get_fd_by_id(prog_id); + if (prog_fd < 0) { + log_err("Failed to get fd by prog id %d", prog_id); + goto err; + } + + info.nr_map_ids = 1; + info.map_ids = (__u64) (unsigned long) map_ids; + + if (bpf_obj_get_info_by_fd(prog_fd, &info, &info_len)) { + log_err("Failed to get info by prog fd %d", prog_fd); + goto err; + } + + if (!info.nr_map_ids) { + log_err("No maps found for prog fd %d", prog_fd); + goto err; + } + + map_fd = bpf_map_get_fd_by_id(map_ids[0]); + if (map_fd < 0) + log_err("Failed to get fd by map id %d", map_ids[0]); +err: + if (prog_fd >= 0) + close(prog_fd); + return map_fd; +} + +int check_ancestor_cgroup_ids(int prog_id) +{ + __u64 actual_ids[NUM_CGROUP_LEVELS], expected_ids[NUM_CGROUP_LEVELS]; + __u32 level; + int err = 0; + int map_fd; + + expected_ids[0] = 0x100000001; /* root cgroup */ + expected_ids[1] = get_cgroup_id(""); + expected_ids[2] = get_cgroup_id(CGROUP_PATH); + expected_ids[3] = 0; /* non-existent cgroup */ + + map_fd = get_map_fd_by_prog_id(prog_id); + if (map_fd < 0) + goto err; + + for (level = 0; level < NUM_CGROUP_LEVELS; ++level) { + if (bpf_map_lookup_elem(map_fd, &level, &actual_ids[level])) { + log_err("Failed to lookup key %d", level); + goto err; + } + if (actual_ids[level] != expected_ids[level]) { + log_err("%llx (actual) != %llx (expected), level: %u\n", + actual_ids[level], expected_ids[level], level); + goto err; + } + } + + goto out; +err: + err = -1; +out: + if (map_fd >= 0) + close(map_fd); + return err; +} + +int main(int argc, char **argv) +{ + int cgfd = -1; + int err = 0; + + if (argc < 3) { + fprintf(stderr, "Usage: %s iface prog_id\n", argv[0]); + exit(EXIT_FAILURE); + } + + if (setup_cgroup_environment()) + goto err; + + cgfd = create_and_get_cgroup(CGROUP_PATH); + if (!cgfd) + goto err; + + if (join_cgroup(CGROUP_PATH)) + goto err; + + if (send_packet(argv[1])) + goto err; + + if (check_ancestor_cgroup_ids(atoi(argv[2]))) + goto err; + + goto out; +err: + err = -1; +out: + close(cgfd); + cleanup_cgroup_environment(); + printf("[%s]\n", err ? "FAIL" : "PASS"); + return err; +} diff --git a/tools/testing/selftests/bpf/test_sock.c b/tools/testing/selftests/bpf/test_sock.c index f4d99fabc56d..b8ebe2f58074 100644 --- a/tools/testing/selftests/bpf/test_sock.c +++ b/tools/testing/selftests/bpf/test_sock.c @@ -14,10 +14,7 @@ #include "cgroup_helpers.h" #include "bpf_rlimit.h" - -#ifndef ARRAY_SIZE -# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) -#endif +#include "bpf_util.h" #define CG_PATH "/foo" #define MAX_INSNS 512 diff --git a/tools/testing/selftests/bpf/test_sock_addr.c b/tools/testing/selftests/bpf/test_sock_addr.c index a5e76b9219b9..aeeb76a54d63 100644 --- a/tools/testing/selftests/bpf/test_sock_addr.c +++ b/tools/testing/selftests/bpf/test_sock_addr.c @@ -20,15 +20,12 @@ #include "cgroup_helpers.h" #include "bpf_rlimit.h" +#include "bpf_util.h" #ifndef ENOTSUPP # define ENOTSUPP 524 #endif -#ifndef ARRAY_SIZE -# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) -#endif - #define CG_PATH "/foo" #define CONNECT4_PROG_PATH "./connect4_prog.o" #define CONNECT6_PROG_PATH "./connect6_prog.o" @@ -998,8 +995,9 @@ int init_pktinfo(int domain, struct cmsghdr *cmsg) return 0; } -static int sendmsg_to_server(const struct sockaddr_storage *addr, - socklen_t addr_len, int set_cmsg, int *syscall_err) +static int sendmsg_to_server(int type, const struct sockaddr_storage *addr, + socklen_t addr_len, int set_cmsg, int flags, + int *syscall_err) { union { char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; @@ -1022,7 +1020,7 @@ static int sendmsg_to_server(const struct sockaddr_storage *addr, goto err; } - fd = socket(domain, SOCK_DGRAM, 0); + fd = socket(domain, type, 0); if (fd == -1) { log_err("Failed to create client socket"); goto err; @@ -1052,7 +1050,7 @@ static int sendmsg_to_server(const struct sockaddr_storage *addr, } } - if (sendmsg(fd, &hdr, 0) != sizeof(data)) { + if (sendmsg(fd, &hdr, flags) != sizeof(data)) { log_err("Fail to send message to server"); *syscall_err = errno; goto err; @@ -1066,6 +1064,15 @@ out: return fd; } +static int fastconnect_to_server(const struct sockaddr_storage *addr, + socklen_t addr_len) +{ + int sendmsg_err; + + return sendmsg_to_server(SOCK_STREAM, addr, addr_len, /*set_cmsg*/0, + MSG_FASTOPEN, &sendmsg_err); +} + static int recvmsg_from_client(int sockfd, struct sockaddr_storage *src_addr) { struct timeval tv; @@ -1185,6 +1192,20 @@ static int run_connect_test_case(const struct sock_addr_test *test) if (cmp_local_ip(clientfd, &expected_src_addr)) goto err; + if (test->type == SOCK_STREAM) { + /* Test TCP Fast Open scenario */ + clientfd = fastconnect_to_server(&requested_addr, addr_len); + if (clientfd == -1) + goto err; + + /* Make sure src and dst addrs were overridden properly */ + if (cmp_peer_addr(clientfd, &expected_addr)) + goto err; + + if (cmp_local_ip(clientfd, &expected_src_addr)) + goto err; + } + goto out; err: err = -1; @@ -1222,8 +1243,9 @@ static int run_sendmsg_test_case(const struct sock_addr_test *test) if (clientfd >= 0) close(clientfd); - clientfd = sendmsg_to_server(&requested_addr, addr_len, - set_cmsg, &err); + clientfd = sendmsg_to_server(test->type, &requested_addr, + addr_len, set_cmsg, /*flags*/0, + &err); if (err) goto out; else if (clientfd == -1) diff --git a/tools/testing/selftests/bpf/test_socket_cookie.c b/tools/testing/selftests/bpf/test_socket_cookie.c new file mode 100644 index 000000000000..68e108e4687a --- /dev/null +++ b/tools/testing/selftests/bpf/test_socket_cookie.c @@ -0,0 +1,225 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Facebook + +#include <string.h> +#include <unistd.h> + +#include <arpa/inet.h> +#include <netinet/in.h> +#include <sys/types.h> +#include <sys/socket.h> + +#include <bpf/bpf.h> +#include <bpf/libbpf.h> + +#include "bpf_rlimit.h" +#include "cgroup_helpers.h" + +#define CG_PATH "/foo" +#define SOCKET_COOKIE_PROG "./socket_cookie_prog.o" + +static int start_server(void) +{ + struct sockaddr_in6 addr; + int fd; + + fd = socket(AF_INET6, SOCK_STREAM, 0); + if (fd == -1) { + log_err("Failed to create server socket"); + goto out; + } + + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_addr = in6addr_loopback; + addr.sin6_port = 0; + + if (bind(fd, (const struct sockaddr *)&addr, sizeof(addr)) == -1) { + log_err("Failed to bind server socket"); + goto close_out; + } + + if (listen(fd, 128) == -1) { + log_err("Failed to listen on server socket"); + goto close_out; + } + + goto out; + +close_out: + close(fd); + fd = -1; +out: + return fd; +} + +static int connect_to_server(int server_fd) +{ + struct sockaddr_storage addr; + socklen_t len = sizeof(addr); + int fd; + + fd = socket(AF_INET6, SOCK_STREAM, 0); + if (fd == -1) { + log_err("Failed to create client socket"); + goto out; + } + + if (getsockname(server_fd, (struct sockaddr *)&addr, &len)) { + log_err("Failed to get server addr"); + goto close_out; + } + + if (connect(fd, (const struct sockaddr *)&addr, len) == -1) { + log_err("Fail to connect to server"); + goto close_out; + } + + goto out; + +close_out: + close(fd); + fd = -1; +out: + return fd; +} + +static int validate_map(struct bpf_map *map, int client_fd) +{ + __u32 cookie_expected_value; + struct sockaddr_in6 addr; + socklen_t len = sizeof(addr); + __u32 cookie_value; + __u64 cookie_key; + int err = 0; + int map_fd; + + if (!map) { + log_err("Map not found in BPF object"); + goto err; + } + + map_fd = bpf_map__fd(map); + + err = bpf_map_get_next_key(map_fd, NULL, &cookie_key); + if (err) { + log_err("Can't get cookie key from map"); + goto out; + } + + err = bpf_map_lookup_elem(map_fd, &cookie_key, &cookie_value); + if (err) { + log_err("Can't get cookie value from map"); + goto out; + } + + err = getsockname(client_fd, (struct sockaddr *)&addr, &len); + if (err) { + log_err("Can't get client local addr"); + goto out; + } + + cookie_expected_value = (ntohs(addr.sin6_port) << 8) | 0xFF; + if (cookie_value != cookie_expected_value) { + log_err("Unexpected value in map: %x != %x", cookie_value, + cookie_expected_value); + goto err; + } + + goto out; +err: + err = -1; +out: + return err; +} + +static int run_test(int cgfd) +{ + enum bpf_attach_type attach_type; + struct bpf_prog_load_attr attr; + struct bpf_program *prog; + struct bpf_object *pobj; + const char *prog_name; + int server_fd = -1; + int client_fd = -1; + int prog_fd = -1; + int err = 0; + + memset(&attr, 0, sizeof(attr)); + attr.file = SOCKET_COOKIE_PROG; + attr.prog_type = BPF_PROG_TYPE_UNSPEC; + + err = bpf_prog_load_xattr(&attr, &pobj, &prog_fd); + if (err) { + log_err("Failed to load %s", attr.file); + goto out; + } + + bpf_object__for_each_program(prog, pobj) { + prog_name = bpf_program__title(prog, /*needs_copy*/ false); + + if (strcmp(prog_name, "cgroup/connect6") == 0) { + attach_type = BPF_CGROUP_INET6_CONNECT; + } else if (strcmp(prog_name, "sockops") == 0) { + attach_type = BPF_CGROUP_SOCK_OPS; + } else { + log_err("Unexpected prog: %s", prog_name); + goto err; + } + + err = bpf_prog_attach(bpf_program__fd(prog), cgfd, attach_type, + BPF_F_ALLOW_OVERRIDE); + if (err) { + log_err("Failed to attach prog %s", prog_name); + goto out; + } + } + + server_fd = start_server(); + if (server_fd == -1) + goto err; + + client_fd = connect_to_server(server_fd); + if (client_fd == -1) + goto err; + + if (validate_map(bpf_map__next(NULL, pobj), client_fd)) + goto err; + + goto out; +err: + err = -1; +out: + close(client_fd); + close(server_fd); + bpf_object__close(pobj); + printf("%s\n", err ? "FAILED" : "PASSED"); + return err; +} + +int main(int argc, char **argv) +{ + int cgfd = -1; + int err = 0; + + if (setup_cgroup_environment()) + goto err; + + cgfd = create_and_get_cgroup(CG_PATH); + if (!cgfd) + goto err; + + if (join_cgroup(CG_PATH)) + goto err; + + if (run_test(cgfd)) + goto err; + + goto out; +err: + err = -1; +out: + close(cgfd); + cleanup_cgroup_environment(); + return err; +} diff --git a/tools/testing/selftests/bpf/test_tcpbpf.h b/tools/testing/selftests/bpf/test_tcpbpf.h index 2fe43289943c..7bcfa6207005 100644 --- a/tools/testing/selftests/bpf/test_tcpbpf.h +++ b/tools/testing/selftests/bpf/test_tcpbpf.h @@ -12,5 +12,6 @@ struct tcpbpf_globals { __u32 good_cb_test_rv; __u64 bytes_received; __u64 bytes_acked; + __u32 num_listen; }; #endif diff --git a/tools/testing/selftests/bpf/test_tcpbpf_kern.c b/tools/testing/selftests/bpf/test_tcpbpf_kern.c index 3e645ee41ed5..4b7fd540cea9 100644 --- a/tools/testing/selftests/bpf/test_tcpbpf_kern.c +++ b/tools/testing/selftests/bpf/test_tcpbpf_kern.c @@ -96,15 +96,22 @@ int bpf_testcb(struct bpf_sock_ops *skops) if (!gp) break; g = *gp; - g.total_retrans = skops->total_retrans; - g.data_segs_in = skops->data_segs_in; - g.data_segs_out = skops->data_segs_out; - g.bytes_received = skops->bytes_received; - g.bytes_acked = skops->bytes_acked; + if (skops->args[0] == BPF_TCP_LISTEN) { + g.num_listen++; + } else { + g.total_retrans = skops->total_retrans; + g.data_segs_in = skops->data_segs_in; + g.data_segs_out = skops->data_segs_out; + g.bytes_received = skops->bytes_received; + g.bytes_acked = skops->bytes_acked; + } bpf_map_update_elem(&global_map, &key, &g, BPF_ANY); } break; + case BPF_SOCK_OPS_TCP_LISTEN_CB: + bpf_sock_ops_cb_flags_set(skops, BPF_SOCK_OPS_STATE_CB_FLAG); + break; default: rv = -1; } diff --git a/tools/testing/selftests/bpf/test_tcpbpf_user.c b/tools/testing/selftests/bpf/test_tcpbpf_user.c index 84ab5163c828..a275c2971376 100644 --- a/tools/testing/selftests/bpf/test_tcpbpf_user.c +++ b/tools/testing/selftests/bpf/test_tcpbpf_user.c @@ -1,27 +1,59 @@ // SPDX-License-Identifier: GPL-2.0 +#include <inttypes.h> #include <stdio.h> #include <stdlib.h> -#include <stdio.h> #include <unistd.h> #include <errno.h> -#include <signal.h> #include <string.h> -#include <assert.h> -#include <linux/perf_event.h> -#include <linux/ptrace.h> #include <linux/bpf.h> -#include <sys/ioctl.h> -#include <sys/time.h> #include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> #include <bpf/bpf.h> #include <bpf/libbpf.h> -#include "bpf_util.h" + #include "bpf_rlimit.h" -#include <linux/perf_event.h> +#include "bpf_util.h" +#include "cgroup_helpers.h" + #include "test_tcpbpf.h" +#define EXPECT_EQ(expected, actual, fmt) \ + do { \ + if ((expected) != (actual)) { \ + printf(" Value of: " #actual "\n" \ + " Actual: %" fmt "\n" \ + " Expected: %" fmt "\n", \ + (actual), (expected)); \ + goto err; \ + } \ + } while (0) + +int verify_result(const struct tcpbpf_globals *result) +{ + __u32 expected_events; + + expected_events = ((1 << BPF_SOCK_OPS_TIMEOUT_INIT) | + (1 << BPF_SOCK_OPS_RWND_INIT) | + (1 << BPF_SOCK_OPS_TCP_CONNECT_CB) | + (1 << BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB) | + (1 << BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB) | + (1 << BPF_SOCK_OPS_NEEDS_ECN) | + (1 << BPF_SOCK_OPS_STATE_CB) | + (1 << BPF_SOCK_OPS_TCP_LISTEN_CB)); + + EXPECT_EQ(expected_events, result->event_map, "#" PRIx32); + EXPECT_EQ(501ULL, result->bytes_received, "llu"); + EXPECT_EQ(1002ULL, result->bytes_acked, "llu"); + EXPECT_EQ(1, result->data_segs_in, PRIu32); + EXPECT_EQ(1, result->data_segs_out, PRIu32); + EXPECT_EQ(0x80, result->bad_cb_test_rv, PRIu32); + EXPECT_EQ(0, result->good_cb_test_rv, PRIu32); + EXPECT_EQ(1, result->num_listen, PRIu32); + + return 0; +err: + return -1; +} + static int bpf_find_map(const char *test, struct bpf_object *obj, const char *name) { @@ -35,42 +67,28 @@ static int bpf_find_map(const char *test, struct bpf_object *obj, return bpf_map__fd(map); } -#define SYSTEM(CMD) \ - do { \ - if (system(CMD)) { \ - printf("system(%s) FAILS!\n", CMD); \ - } \ - } while (0) - int main(int argc, char **argv) { const char *file = "test_tcpbpf_kern.o"; struct tcpbpf_globals g = {0}; - int cg_fd, prog_fd, map_fd; - bool debug_flag = false; + const char *cg_path = "/foo"; int error = EXIT_FAILURE; struct bpf_object *obj; - char cmd[100], *dir; - struct stat buffer; + int prog_fd, map_fd; + int cg_fd = -1; __u32 key = 0; - int pid; int rv; - if (argc > 1 && strcmp(argv[1], "-d") == 0) - debug_flag = true; + if (setup_cgroup_environment()) + goto err; - dir = "/tmp/cgroupv2/foo"; + cg_fd = create_and_get_cgroup(cg_path); + if (!cg_fd) + goto err; - if (stat(dir, &buffer) != 0) { - SYSTEM("mkdir -p /tmp/cgroupv2"); - SYSTEM("mount -t cgroup2 none /tmp/cgroupv2"); - SYSTEM("mkdir -p /tmp/cgroupv2/foo"); - } - pid = (int) getpid(); - sprintf(cmd, "echo %d >> /tmp/cgroupv2/foo/cgroup.procs", pid); - SYSTEM(cmd); + if (join_cgroup(cg_path)) + goto err; - cg_fd = open(dir, O_DIRECTORY, O_RDONLY); if (bpf_prog_load(file, BPF_PROG_TYPE_SOCK_OPS, &obj, &prog_fd)) { printf("FAILED: load_bpf_file failed for: %s\n", file); goto err; @@ -83,7 +101,10 @@ int main(int argc, char **argv) goto err; } - SYSTEM("./tcp_server.py"); + if (system("./tcp_server.py")) { + printf("FAILED: TCP server\n"); + goto err; + } map_fd = bpf_find_map(__func__, obj, "global_map"); if (map_fd < 0) @@ -95,34 +116,16 @@ int main(int argc, char **argv) goto err; } - if (g.bytes_received != 501 || g.bytes_acked != 1002 || - g.data_segs_in != 1 || g.data_segs_out != 1 || - (g.event_map ^ 0x47e) != 0 || g.bad_cb_test_rv != 0x80 || - g.good_cb_test_rv != 0) { + if (verify_result(&g)) { printf("FAILED: Wrong stats\n"); - if (debug_flag) { - printf("\n"); - printf("bytes_received: %d (expecting 501)\n", - (int)g.bytes_received); - printf("bytes_acked: %d (expecting 1002)\n", - (int)g.bytes_acked); - printf("data_segs_in: %d (expecting 1)\n", - g.data_segs_in); - printf("data_segs_out: %d (expecting 1)\n", - g.data_segs_out); - printf("event_map: 0x%x (at least 0x47e)\n", - g.event_map); - printf("bad_cb_test_rv: 0x%x (expecting 0x80)\n", - g.bad_cb_test_rv); - printf("good_cb_test_rv:0x%x (expecting 0)\n", - g.good_cb_test_rv); - } goto err; } + printf("PASSED!\n"); error = 0; err: bpf_prog_detach(cg_fd, BPF_CGROUP_SOCK_OPS); + close(cg_fd); + cleanup_cgroup_environment(); return error; - } diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 41106d9d5cc7..67c412d19c09 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -42,15 +42,12 @@ #endif #include "bpf_rlimit.h" #include "bpf_rand.h" +#include "bpf_util.h" #include "../../../include/linux/filter.h" -#ifndef ARRAY_SIZE -# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) -#endif - #define MAX_INSNS BPF_MAXINSNS #define MAX_FIXUPS 8 -#define MAX_NR_MAPS 7 +#define MAX_NR_MAPS 8 #define POINTER_VALUE 0xcafe4all #define TEST_DATA_LEN 64 @@ -70,6 +67,7 @@ struct bpf_test { int fixup_prog1[MAX_FIXUPS]; int fixup_prog2[MAX_FIXUPS]; int fixup_map_in_map[MAX_FIXUPS]; + int fixup_cgroup_storage[MAX_FIXUPS]; const char *errstr; const char *errstr_unpriv; uint32_t retval; @@ -4631,6 +4629,121 @@ static struct bpf_test tests[] = { .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, }, { + "valid cgroup storage access", + .insns = { + BPF_MOV64_IMM(BPF_REG_2, 0), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_get_local_storage), + BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0), + BPF_MOV64_REG(BPF_REG_0, BPF_REG_1), + BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .fixup_cgroup_storage = { 1 }, + .result = ACCEPT, + .prog_type = BPF_PROG_TYPE_CGROUP_SKB, + }, + { + "invalid cgroup storage access 1", + .insns = { + BPF_MOV64_IMM(BPF_REG_2, 0), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_get_local_storage), + BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0), + BPF_MOV64_REG(BPF_REG_0, BPF_REG_1), + BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .fixup_map1 = { 1 }, + .result = REJECT, + .errstr = "cannot pass map_type 1 into func bpf_get_local_storage", + .prog_type = BPF_PROG_TYPE_CGROUP_SKB, + }, + { + "invalid cgroup storage access 2", + .insns = { + BPF_MOV64_IMM(BPF_REG_2, 0), + BPF_LD_MAP_FD(BPF_REG_1, 1), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_get_local_storage), + BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .result = REJECT, + .errstr = "fd 1 is not pointing to valid bpf_map", + .prog_type = BPF_PROG_TYPE_CGROUP_SKB, + }, + { + "invalid per-cgroup storage access 3", + .insns = { + BPF_MOV64_IMM(BPF_REG_2, 0), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_get_local_storage), + BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 256), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 1), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .fixup_cgroup_storage = { 1 }, + .result = REJECT, + .errstr = "invalid access to map value, value_size=64 off=256 size=4", + .prog_type = BPF_PROG_TYPE_CGROUP_SKB, + }, + { + "invalid cgroup storage access 4", + .insns = { + BPF_MOV64_IMM(BPF_REG_2, 0), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_get_local_storage), + BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, -2), + BPF_MOV64_REG(BPF_REG_0, BPF_REG_1), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 1), + BPF_EXIT_INSN(), + }, + .fixup_cgroup_storage = { 1 }, + .result = REJECT, + .errstr = "invalid access to map value, value_size=64 off=-2 size=4", + .prog_type = BPF_PROG_TYPE_CGROUP_SKB, + }, + { + "invalid cgroup storage access 5", + .insns = { + BPF_MOV64_IMM(BPF_REG_2, 7), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_get_local_storage), + BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0), + BPF_MOV64_REG(BPF_REG_0, BPF_REG_1), + BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .fixup_cgroup_storage = { 1 }, + .result = REJECT, + .errstr = "get_local_storage() doesn't support non-zero flags", + .prog_type = BPF_PROG_TYPE_CGROUP_SKB, + }, + { + "invalid cgroup storage access 6", + .insns = { + BPF_MOV64_REG(BPF_REG_2, BPF_REG_1), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_get_local_storage), + BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0), + BPF_MOV64_REG(BPF_REG_0, BPF_REG_1), + BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .fixup_cgroup_storage = { 1 }, + .result = REJECT, + .errstr = "get_local_storage() doesn't support non-zero flags", + .prog_type = BPF_PROG_TYPE_CGROUP_SKB, + }, + { "multiple registers share map_lookup_elem result", .insns = { BPF_MOV64_IMM(BPF_REG_1, 10), @@ -6997,7 +7110,7 @@ static struct bpf_test tests[] = { BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), - BPF_MOV64_REG(BPF_REG_0, 0), + BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, .fixup_map_in_map = { 3 }, @@ -7020,7 +7133,7 @@ static struct bpf_test tests[] = { BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8), BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), - BPF_MOV64_REG(BPF_REG_0, 0), + BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, .fixup_map_in_map = { 3 }, @@ -7042,7 +7155,7 @@ static struct bpf_test tests[] = { BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), - BPF_MOV64_REG(BPF_REG_0, 0), + BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), }, .fixup_map_in_map = { 3 }, @@ -12372,6 +12485,32 @@ static struct bpf_test tests[] = { .result = REJECT, .errstr = "variable ctx access var_off=(0x0; 0x4)", }, + { + "mov64 src == dst", + .insns = { + BPF_MOV64_IMM(BPF_REG_2, 0), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_2), + // Check bounds are OK + BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_2), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .result = ACCEPT, + }, + { + "mov64 src != dst", + .insns = { + BPF_MOV64_IMM(BPF_REG_3, 0), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_3), + // Check bounds are OK + BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_2), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .result = ACCEPT, + }, }; static int probe_filter_length(const struct bpf_insn *fp) @@ -12476,6 +12615,19 @@ static int create_map_in_map(void) return outer_map_fd; } +static int create_cgroup_storage(void) +{ + int fd; + + fd = bpf_create_map(BPF_MAP_TYPE_CGROUP_STORAGE, + sizeof(struct bpf_cgroup_storage_key), + TEST_DATA_LEN, 0, 0); + if (fd < 0) + printf("Failed to create array '%s'!\n", strerror(errno)); + + return fd; +} + static char bpf_vlog[UINT_MAX >> 8]; static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog, @@ -12488,6 +12640,7 @@ static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog, int *fixup_prog1 = test->fixup_prog1; int *fixup_prog2 = test->fixup_prog2; int *fixup_map_in_map = test->fixup_map_in_map; + int *fixup_cgroup_storage = test->fixup_cgroup_storage; if (test->fill_helper) test->fill_helper(test); @@ -12555,6 +12708,14 @@ static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog, fixup_map_in_map++; } while (*fixup_map_in_map); } + + if (*fixup_cgroup_storage) { + map_fds[7] = create_cgroup_storage(); + do { + prog[*fixup_cgroup_storage].imm = map_fds[7]; + fixup_cgroup_storage++; + } while (*fixup_cgroup_storage); + } } static void do_test_single(struct bpf_test *test, bool unpriv, diff --git a/tools/testing/selftests/bpf/trace_helpers.c b/tools/testing/selftests/bpf/trace_helpers.c index 3868dcb63420..cabe2a3a3b30 100644 --- a/tools/testing/selftests/bpf/trace_helpers.c +++ b/tools/testing/selftests/bpf/trace_helpers.c @@ -88,7 +88,7 @@ static int page_size; static int page_cnt = 8; static struct perf_event_mmap_page *header; -int perf_event_mmap(int fd) +int perf_event_mmap_header(int fd, struct perf_event_mmap_page **header) { void *base; int mmap_size; @@ -102,10 +102,15 @@ int perf_event_mmap(int fd) return -1; } - header = base; + *header = base; return 0; } +int perf_event_mmap(int fd) +{ + return perf_event_mmap_header(fd, &header); +} + static int perf_event_poll(int fd) { struct pollfd pfd = { .fd = fd, .events = POLLIN }; @@ -163,3 +168,42 @@ int perf_event_poller(int fd, perf_event_print_fn output_fn) return ret; } + +int perf_event_poller_multi(int *fds, struct perf_event_mmap_page **headers, + int num_fds, perf_event_print_fn output_fn) +{ + enum bpf_perf_event_ret ret; + struct pollfd *pfds; + void *buf = NULL; + size_t len = 0; + int i; + + pfds = calloc(num_fds, sizeof(*pfds)); + if (!pfds) + return LIBBPF_PERF_EVENT_ERROR; + + for (i = 0; i < num_fds; i++) { + pfds[i].fd = fds[i]; + pfds[i].events = POLLIN; + } + + for (;;) { + poll(pfds, num_fds, 1000); + for (i = 0; i < num_fds; i++) { + if (!pfds[i].revents) + continue; + + ret = bpf_perf_event_read_simple(headers[i], + page_cnt * page_size, + page_size, &buf, &len, + bpf_perf_event_print, + output_fn); + if (ret != LIBBPF_PERF_EVENT_CONT) + break; + } + } + free(buf); + free(pfds); + + return ret; +} diff --git a/tools/testing/selftests/bpf/trace_helpers.h b/tools/testing/selftests/bpf/trace_helpers.h index 3b4bcf7f5084..18924f23db1b 100644 --- a/tools/testing/selftests/bpf/trace_helpers.h +++ b/tools/testing/selftests/bpf/trace_helpers.h @@ -3,6 +3,7 @@ #define __TRACE_HELPER_H #include <libbpf.h> +#include <linux/perf_event.h> struct ksym { long addr; @@ -16,6 +17,9 @@ long ksym_get_addr(const char *name); typedef enum bpf_perf_event_ret (*perf_event_print_fn)(void *data, int size); int perf_event_mmap(int fd); +int perf_event_mmap_header(int fd, struct perf_event_mmap_page **header); /* return LIBBPF_PERF_EVENT_DONE or LIBBPF_PERF_EVENT_ERROR */ int perf_event_poller(int fd, perf_event_print_fn output_fn); +int perf_event_poller_multi(int *fds, struct perf_event_mmap_page **headers, + int num_fds, perf_event_print_fn output_fn); #endif diff --git a/tools/testing/selftests/cgroup/.gitignore b/tools/testing/selftests/cgroup/.gitignore new file mode 100644 index 000000000000..95eb3a53c381 --- /dev/null +++ b/tools/testing/selftests/cgroup/.gitignore @@ -0,0 +1 @@ +test_memcontrol diff --git a/tools/testing/selftests/cgroup/Makefile b/tools/testing/selftests/cgroup/Makefile index f7a31392eb2f..23fbaa4a9630 100644 --- a/tools/testing/selftests/cgroup/Makefile +++ b/tools/testing/selftests/cgroup/Makefile @@ -4,7 +4,9 @@ CFLAGS += -Wall all: TEST_GEN_PROGS = test_memcontrol +TEST_GEN_PROGS += test_core include ../lib.mk $(OUTPUT)/test_memcontrol: cgroup_util.c +$(OUTPUT)/test_core: cgroup_util.c diff --git a/tools/testing/selftests/cgroup/cgroup_util.c b/tools/testing/selftests/cgroup/cgroup_util.c index 1e9e3c470561..1c5d2b2a583b 100644 --- a/tools/testing/selftests/cgroup/cgroup_util.c +++ b/tools/testing/selftests/cgroup/cgroup_util.c @@ -229,6 +229,14 @@ retry: return ret; } +int cg_enter_current(const char *cgroup) +{ + char pidbuf[64]; + + snprintf(pidbuf, sizeof(pidbuf), "%d", getpid()); + return cg_write(cgroup, "cgroup.procs", pidbuf); +} + int cg_run(const char *cgroup, int (*fn)(const char *cgroup, void *arg), void *arg) diff --git a/tools/testing/selftests/cgroup/cgroup_util.h b/tools/testing/selftests/cgroup/cgroup_util.h index fe82a297d4e0..1ff6f9f1abdc 100644 --- a/tools/testing/selftests/cgroup/cgroup_util.h +++ b/tools/testing/selftests/cgroup/cgroup_util.h @@ -32,6 +32,7 @@ extern int cg_write(const char *cgroup, const char *control, char *buf); extern int cg_run(const char *cgroup, int (*fn)(const char *cgroup, void *arg), void *arg); +extern int cg_enter_current(const char *cgroup); extern int cg_run_nowait(const char *cgroup, int (*fn)(const char *cgroup, void *arg), void *arg); diff --git a/tools/testing/selftests/cgroup/test_core.c b/tools/testing/selftests/cgroup/test_core.c new file mode 100644 index 000000000000..be59f9c34ea2 --- /dev/null +++ b/tools/testing/selftests/cgroup/test_core.c @@ -0,0 +1,395 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#include <linux/limits.h> +#include <sys/types.h> +#include <unistd.h> +#include <stdio.h> +#include <errno.h> + +#include "../kselftest.h" +#include "cgroup_util.h" + +/* + * A(0) - B(0) - C(1) + * \ D(0) + * + * A, B and C's "populated" fields would be 1 while D's 0. + * test that after the one process in C is moved to root, + * A,B and C's "populated" fields would flip to "0" and file + * modified events will be generated on the + * "cgroup.events" files of both cgroups. + */ +static int test_cgcore_populated(const char *root) +{ + int ret = KSFT_FAIL; + char *cg_test_a = NULL, *cg_test_b = NULL; + char *cg_test_c = NULL, *cg_test_d = NULL; + + cg_test_a = cg_name(root, "cg_test_a"); + cg_test_b = cg_name(root, "cg_test_a/cg_test_b"); + cg_test_c = cg_name(root, "cg_test_a/cg_test_b/cg_test_c"); + cg_test_d = cg_name(root, "cg_test_a/cg_test_b/cg_test_d"); + + if (!cg_test_a || !cg_test_b || !cg_test_c || !cg_test_d) + goto cleanup; + + if (cg_create(cg_test_a)) + goto cleanup; + + if (cg_create(cg_test_b)) + goto cleanup; + + if (cg_create(cg_test_c)) + goto cleanup; + + if (cg_create(cg_test_d)) + goto cleanup; + + if (cg_enter_current(cg_test_c)) + goto cleanup; + + if (cg_read_strcmp(cg_test_a, "cgroup.events", "populated 1\n")) + goto cleanup; + + if (cg_read_strcmp(cg_test_b, "cgroup.events", "populated 1\n")) + goto cleanup; + + if (cg_read_strcmp(cg_test_c, "cgroup.events", "populated 1\n")) + goto cleanup; + + if (cg_read_strcmp(cg_test_d, "cgroup.events", "populated 0\n")) + goto cleanup; + + if (cg_enter_current(root)) + goto cleanup; + + if (cg_read_strcmp(cg_test_a, "cgroup.events", "populated 0\n")) + goto cleanup; + + if (cg_read_strcmp(cg_test_b, "cgroup.events", "populated 0\n")) + goto cleanup; + + if (cg_read_strcmp(cg_test_c, "cgroup.events", "populated 0\n")) + goto cleanup; + + if (cg_read_strcmp(cg_test_d, "cgroup.events", "populated 0\n")) + goto cleanup; + + ret = KSFT_PASS; + +cleanup: + if (cg_test_d) + cg_destroy(cg_test_d); + if (cg_test_c) + cg_destroy(cg_test_c); + if (cg_test_b) + cg_destroy(cg_test_b); + if (cg_test_a) + cg_destroy(cg_test_a); + free(cg_test_d); + free(cg_test_c); + free(cg_test_b); + free(cg_test_a); + return ret; +} + +/* + * A (domain threaded) - B (threaded) - C (domain) + * + * test that C can't be used until it is turned into a + * threaded cgroup. "cgroup.type" file will report "domain (invalid)" in + * these cases. Operations which fail due to invalid topology use + * EOPNOTSUPP as the errno. + */ +static int test_cgcore_invalid_domain(const char *root) +{ + int ret = KSFT_FAIL; + char *grandparent = NULL, *parent = NULL, *child = NULL; + + grandparent = cg_name(root, "cg_test_grandparent"); + parent = cg_name(root, "cg_test_grandparent/cg_test_parent"); + child = cg_name(root, "cg_test_grandparent/cg_test_parent/cg_test_child"); + if (!parent || !child || !grandparent) + goto cleanup; + + if (cg_create(grandparent)) + goto cleanup; + + if (cg_create(parent)) + goto cleanup; + + if (cg_create(child)) + goto cleanup; + + if (cg_write(parent, "cgroup.type", "threaded")) + goto cleanup; + + if (cg_read_strcmp(child, "cgroup.type", "domain invalid\n")) + goto cleanup; + + if (!cg_enter_current(child)) + goto cleanup; + + if (errno != EOPNOTSUPP) + goto cleanup; + + ret = KSFT_PASS; + +cleanup: + cg_enter_current(root); + if (child) + cg_destroy(child); + if (parent) + cg_destroy(parent); + if (grandparent) + cg_destroy(grandparent); + free(child); + free(parent); + free(grandparent); + return ret; +} + +/* + * Test that when a child becomes threaded + * the parent type becomes domain threaded. + */ +static int test_cgcore_parent_becomes_threaded(const char *root) +{ + int ret = KSFT_FAIL; + char *parent = NULL, *child = NULL; + + parent = cg_name(root, "cg_test_parent"); + child = cg_name(root, "cg_test_parent/cg_test_child"); + if (!parent || !child) + goto cleanup; + + if (cg_create(parent)) + goto cleanup; + + if (cg_create(child)) + goto cleanup; + + if (cg_write(child, "cgroup.type", "threaded")) + goto cleanup; + + if (cg_read_strcmp(parent, "cgroup.type", "domain threaded\n")) + goto cleanup; + + ret = KSFT_PASS; + +cleanup: + if (child) + cg_destroy(child); + if (parent) + cg_destroy(parent); + free(child); + free(parent); + return ret; + +} + +/* + * Test that there's no internal process constrain on threaded cgroups. + * You can add threads/processes on a parent with a controller enabled. + */ +static int test_cgcore_no_internal_process_constraint_on_threads(const char *root) +{ + int ret = KSFT_FAIL; + char *parent = NULL, *child = NULL; + + if (cg_read_strstr(root, "cgroup.controllers", "cpu") || + cg_read_strstr(root, "cgroup.subtree_control", "cpu")) { + ret = KSFT_SKIP; + goto cleanup; + } + + parent = cg_name(root, "cg_test_parent"); + child = cg_name(root, "cg_test_parent/cg_test_child"); + if (!parent || !child) + goto cleanup; + + if (cg_create(parent)) + goto cleanup; + + if (cg_create(child)) + goto cleanup; + + if (cg_write(parent, "cgroup.type", "threaded")) + goto cleanup; + + if (cg_write(child, "cgroup.type", "threaded")) + goto cleanup; + + if (cg_write(parent, "cgroup.subtree_control", "+cpu")) + goto cleanup; + + if (cg_enter_current(parent)) + goto cleanup; + + ret = KSFT_PASS; + +cleanup: + cg_enter_current(root); + cg_enter_current(root); + if (child) + cg_destroy(child); + if (parent) + cg_destroy(parent); + free(child); + free(parent); + return ret; +} + +/* + * Test that you can't enable a controller on a child if it's not enabled + * on the parent. + */ +static int test_cgcore_top_down_constraint_enable(const char *root) +{ + int ret = KSFT_FAIL; + char *parent = NULL, *child = NULL; + + parent = cg_name(root, "cg_test_parent"); + child = cg_name(root, "cg_test_parent/cg_test_child"); + if (!parent || !child) + goto cleanup; + + if (cg_create(parent)) + goto cleanup; + + if (cg_create(child)) + goto cleanup; + + if (!cg_write(child, "cgroup.subtree_control", "+memory")) + goto cleanup; + + ret = KSFT_PASS; + +cleanup: + if (child) + cg_destroy(child); + if (parent) + cg_destroy(parent); + free(child); + free(parent); + return ret; +} + +/* + * Test that you can't disable a controller on a parent + * if it's enabled in a child. + */ +static int test_cgcore_top_down_constraint_disable(const char *root) +{ + int ret = KSFT_FAIL; + char *parent = NULL, *child = NULL; + + parent = cg_name(root, "cg_test_parent"); + child = cg_name(root, "cg_test_parent/cg_test_child"); + if (!parent || !child) + goto cleanup; + + if (cg_create(parent)) + goto cleanup; + + if (cg_create(child)) + goto cleanup; + + if (cg_write(parent, "cgroup.subtree_control", "+memory")) + goto cleanup; + + if (cg_write(child, "cgroup.subtree_control", "+memory")) + goto cleanup; + + if (!cg_write(parent, "cgroup.subtree_control", "-memory")) + goto cleanup; + + ret = KSFT_PASS; + +cleanup: + if (child) + cg_destroy(child); + if (parent) + cg_destroy(parent); + free(child); + free(parent); + return ret; +} + +/* + * Test internal process constraint. + * You can't add a pid to a domain parent if a controller is enabled. + */ +static int test_cgcore_internal_process_constraint(const char *root) +{ + int ret = KSFT_FAIL; + char *parent = NULL, *child = NULL; + + parent = cg_name(root, "cg_test_parent"); + child = cg_name(root, "cg_test_parent/cg_test_child"); + if (!parent || !child) + goto cleanup; + + if (cg_create(parent)) + goto cleanup; + + if (cg_create(child)) + goto cleanup; + + if (cg_write(parent, "cgroup.subtree_control", "+memory")) + goto cleanup; + + if (!cg_enter_current(parent)) + goto cleanup; + + ret = KSFT_PASS; + +cleanup: + if (child) + cg_destroy(child); + if (parent) + cg_destroy(parent); + free(child); + free(parent); + return ret; +} + +#define T(x) { x, #x } +struct corecg_test { + int (*fn)(const char *root); + const char *name; +} tests[] = { + T(test_cgcore_internal_process_constraint), + T(test_cgcore_top_down_constraint_enable), + T(test_cgcore_top_down_constraint_disable), + T(test_cgcore_no_internal_process_constraint_on_threads), + T(test_cgcore_parent_becomes_threaded), + T(test_cgcore_invalid_domain), + T(test_cgcore_populated), +}; +#undef T + +int main(int argc, char *argv[]) +{ + char root[PATH_MAX]; + int i, ret = EXIT_SUCCESS; + + if (cg_find_unified_root(root, sizeof(root))) + ksft_exit_skip("cgroup v2 isn't mounted\n"); + for (i = 0; i < ARRAY_SIZE(tests); i++) { + switch (tests[i].fn(root)) { + case KSFT_PASS: + ksft_test_result_pass("%s\n", tests[i].name); + break; + case KSFT_SKIP: + ksft_test_result_skip("%s\n", tests[i].name); + break; + default: + ret = EXIT_FAILURE; + ksft_test_result_fail("%s\n", tests[i].name); + break; + } + } + + return ret; +} diff --git a/tools/testing/selftests/drivers/net/mlxsw/mirror_gre.sh b/tools/testing/selftests/drivers/net/mlxsw/mirror_gre.sh new file mode 100755 index 000000000000..76f1ab4898d9 --- /dev/null +++ b/tools/testing/selftests/drivers/net/mlxsw/mirror_gre.sh @@ -0,0 +1,217 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +# This test uses standard topology for testing gretap. See +# ../../../net/forwarding/mirror_gre_topo_lib.sh for more details. +# +# Test offloading various features of offloading gretap mirrors specific to +# mlxsw. + +lib_dir=$(dirname $0)/../../../net/forwarding + +NUM_NETIFS=6 +source $lib_dir/lib.sh +source $lib_dir/mirror_lib.sh +source $lib_dir/mirror_gre_lib.sh +source $lib_dir/mirror_gre_topo_lib.sh + +setup_keyful() +{ + tunnel_create gt6-key ip6gretap 2001:db8:3::1 2001:db8:3::2 \ + ttl 100 tos inherit allow-localremote \ + key 1234 + + tunnel_create h3-gt6-key ip6gretap 2001:db8:3::2 2001:db8:3::1 \ + key 1234 + ip link set h3-gt6-key vrf v$h3 + matchall_sink_create h3-gt6-key + + ip address add dev $swp3 2001:db8:3::1/64 + ip address add dev $h3 2001:db8:3::2/64 +} + +cleanup_keyful() +{ + ip address del dev $h3 2001:db8:3::2/64 + ip address del dev $swp3 2001:db8:3::1/64 + + tunnel_destroy h3-gt6-key + tunnel_destroy gt6-key +} + +setup_soft() +{ + # Set up a topology for testing underlay routes that point at an + # unsupported soft device. + + tunnel_create gt6-soft ip6gretap 2001:db8:4::1 2001:db8:4::2 \ + ttl 100 tos inherit allow-localremote + + tunnel_create h3-gt6-soft ip6gretap 2001:db8:4::2 2001:db8:4::1 + ip link set h3-gt6-soft vrf v$h3 + matchall_sink_create h3-gt6-soft + + ip link add name v1 type veth peer name v2 + ip link set dev v1 up + ip address add dev v1 2001:db8:4::1/64 + + ip link set dev v2 vrf v$h3 + ip link set dev v2 up + ip address add dev v2 2001:db8:4::2/64 +} + +cleanup_soft() +{ + ip link del dev v1 + + tunnel_destroy h3-gt6-soft + tunnel_destroy gt6-soft +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + swp1=${NETIFS[p2]} + + swp2=${NETIFS[p3]} + h2=${NETIFS[p4]} + + swp3=${NETIFS[p5]} + h3=${NETIFS[p6]} + + vrf_prepare + mirror_gre_topo_create + + ip address add dev $swp3 2001:db8:2::1/64 + ip address add dev $h3 2001:db8:2::2/64 + + ip address add dev $swp3 192.0.2.129/28 + ip address add dev $h3 192.0.2.130/28 + + setup_keyful + setup_soft +} + +cleanup() +{ + pre_cleanup + + cleanup_soft + cleanup_keyful + + ip address del dev $h3 2001:db8:2::2/64 + ip address del dev $swp3 2001:db8:2::1/64 + + ip address del dev $h3 192.0.2.130/28 + ip address del dev $swp3 192.0.2.129/28 + + mirror_gre_topo_destroy + vrf_cleanup +} + +test_span_gre_ttl_inherit() +{ + local tundev=$1; shift + local type=$1; shift + local what=$1; shift + + RET=0 + + ip link set dev $tundev type $type ttl inherit + mirror_install $swp1 ingress $tundev "matchall $tcflags" + fail_test_span_gre_dir $tundev ingress + + ip link set dev $tundev type $type ttl 100 + + quick_test_span_gre_dir $tundev ingress + mirror_uninstall $swp1 ingress + + log_test "$what: no offload on TTL of inherit ($tcflags)" +} + +test_span_gre_tos_fixed() +{ + local tundev=$1; shift + local type=$1; shift + local what=$1; shift + + RET=0 + + ip link set dev $tundev type $type tos 0x10 + mirror_install $swp1 ingress $tundev "matchall $tcflags" + fail_test_span_gre_dir $tundev ingress + + ip link set dev $tundev type $type tos inherit + quick_test_span_gre_dir $tundev ingress + mirror_uninstall $swp1 ingress + + log_test "$what: no offload on a fixed TOS ($tcflags)" +} + +test_span_failable() +{ + local should_fail=$1; shift + local tundev=$1; shift + local what=$1; shift + + RET=0 + + mirror_install $swp1 ingress $tundev "matchall $tcflags" + if ((should_fail)); then + fail_test_span_gre_dir $tundev ingress + else + quick_test_span_gre_dir $tundev ingress + fi + mirror_uninstall $swp1 ingress + + log_test "$what: should_fail=$should_fail ($tcflags)" +} + +test_failable() +{ + local should_fail=$1; shift + + test_span_failable $should_fail gt6-key "mirror to keyful gretap" + test_span_failable $should_fail gt6-soft "mirror to gretap w/ soft underlay" +} + +test_sw() +{ + slow_path_trap_install $swp1 ingress + slow_path_trap_install $swp1 egress + + test_failable 0 + + slow_path_trap_uninstall $swp1 egress + slow_path_trap_uninstall $swp1 ingress +} + +test_hw() +{ + test_failable 1 + + test_span_gre_tos_fixed gt4 gretap "mirror to gretap" + test_span_gre_tos_fixed gt6 ip6gretap "mirror to ip6gretap" + + test_span_gre_ttl_inherit gt4 gretap "mirror to gretap" + test_span_gre_ttl_inherit gt6 ip6gretap "mirror to ip6gretap" +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +if ! tc_offload_check; then + check_err 1 "Could not test offloaded functionality" + log_test "mlxsw-specific tests for mirror to gretap" + exit +fi + +tcflags="skip_hw" +test_sw + +tcflags="skip_sw" +test_hw + +exit $EXIT_STATUS diff --git a/tools/testing/selftests/drivers/net/mlxsw/mirror_gre_scale.sh b/tools/testing/selftests/drivers/net/mlxsw/mirror_gre_scale.sh new file mode 100644 index 000000000000..6f3a70df63bc --- /dev/null +++ b/tools/testing/selftests/drivers/net/mlxsw/mirror_gre_scale.sh @@ -0,0 +1,197 @@ +# SPDX-License-Identifier: GPL-2.0 + +# Test offloading a number of mirrors-to-gretap. The test creates a number of +# tunnels. Then it adds one flower mirror for each of the tunnels, matching a +# given host IP. Then it generates traffic at each of the host IPs and checks +# that the traffic has been mirrored at the appropriate tunnel. +# +# +--------------------------+ +--------------------------+ +# | H1 | | H2 | +# | + $h1 | | $h2 + | +# | | 2001:db8:1:X::1/64 | | 2001:db8:1:X::2/64 | | +# +-----|--------------------+ +--------------------|-----+ +# | | +# +-----|-------------------------------------------------------------|-----+ +# | SW o--> mirrors | | +# | +---|-------------------------------------------------------------|---+ | +# | | + $swp1 BR $swp2 + | | +# | +---------------------------------------------------------------------+ | +# | | +# | + $swp3 + gt6-<X> (ip6gretap) | +# | | 2001:db8:2:X::1/64 : loc=2001:db8:2:X::1 | +# | | : rem=2001:db8:2:X::2 | +# | | : ttl=100 | +# | | : tos=inherit | +# | | : | +# +-----|--------------------------------:----------------------------------+ +# | : +# +-----|--------------------------------:----------------------------------+ +# | H3 + $h3 + h3-gt6-<X> (ip6gretap) | +# | 2001:db8:2:X::2/64 loc=2001:db8:2:X::2 | +# | rem=2001:db8:2:X::1 | +# | ttl=100 | +# | tos=inherit | +# | | +# +-------------------------------------------------------------------------+ + +source ../../../../net/forwarding/mirror_lib.sh + +MIRROR_NUM_NETIFS=6 + +mirror_gre_ipv6_addr() +{ + local net=$1; shift + local num=$1; shift + + printf "2001:db8:%x:%x" $net $num +} + +mirror_gre_tunnels_create() +{ + local count=$1; shift + local should_fail=$1; shift + + MIRROR_GRE_BATCH_FILE="$(mktemp)" + for ((i=0; i < count; ++i)); do + local match_dip=$(mirror_gre_ipv6_addr 1 $i)::2 + local htun=h3-gt6-$i + local tun=gt6-$i + + ((mirror_gre_tunnels++)) + + ip address add dev $h1 $(mirror_gre_ipv6_addr 1 $i)::1/64 + ip address add dev $h2 $(mirror_gre_ipv6_addr 1 $i)::2/64 + + ip address add dev $swp3 $(mirror_gre_ipv6_addr 2 $i)::1/64 + ip address add dev $h3 $(mirror_gre_ipv6_addr 2 $i)::2/64 + + tunnel_create $tun ip6gretap \ + $(mirror_gre_ipv6_addr 2 $i)::1 \ + $(mirror_gre_ipv6_addr 2 $i)::2 \ + ttl 100 tos inherit allow-localremote + + tunnel_create $htun ip6gretap \ + $(mirror_gre_ipv6_addr 2 $i)::2 \ + $(mirror_gre_ipv6_addr 2 $i)::1 + ip link set $htun vrf v$h3 + matchall_sink_create $htun + + cat >> $MIRROR_GRE_BATCH_FILE <<-EOF + filter add dev $swp1 ingress pref 1000 \ + protocol ipv6 \ + flower $tcflags dst_ip $match_dip \ + action mirred egress mirror dev $tun + EOF + done + + tc -b $MIRROR_GRE_BATCH_FILE + check_err_fail $should_fail $? "Mirror rule insertion" +} + +mirror_gre_tunnels_destroy() +{ + local count=$1; shift + + for ((i=0; i < count; ++i)); do + local htun=h3-gt6-$i + local tun=gt6-$i + + ip address del dev $h3 $(mirror_gre_ipv6_addr 2 $i)::2/64 + ip address del dev $swp3 $(mirror_gre_ipv6_addr 2 $i)::1/64 + + ip address del dev $h2 $(mirror_gre_ipv6_addr 1 $i)::2/64 + ip address del dev $h1 $(mirror_gre_ipv6_addr 1 $i)::1/64 + + tunnel_destroy $htun + tunnel_destroy $tun + done +} + +__mirror_gre_test() +{ + local count=$1; shift + local should_fail=$1; shift + + mirror_gre_tunnels_create $count $should_fail + if ((should_fail)); then + return + fi + + sleep 5 + + for ((i = 0; i < count; ++i)); do + local dip=$(mirror_gre_ipv6_addr 1 $i)::2 + local htun=h3-gt6-$i + local message + + icmp6_capture_install $htun + mirror_test v$h1 "" $dip $htun 100 10 + icmp6_capture_uninstall $htun + done +} + +mirror_gre_test() +{ + local count=$1; shift + local should_fail=$1; shift + + if ! tc_offload_check $TC_FLOWER_NUM_NETIFS; then + check_err 1 "Could not test offloaded functionality" + return + fi + + tcflags="skip_sw" + __mirror_gre_test $count $should_fail +} + +mirror_gre_setup_prepare() +{ + h1=${NETIFS[p1]} + swp1=${NETIFS[p2]} + + swp2=${NETIFS[p3]} + h2=${NETIFS[p4]} + + swp3=${NETIFS[p5]} + h3=${NETIFS[p6]} + + mirror_gre_tunnels=0 + + vrf_prepare + + simple_if_init $h1 + simple_if_init $h2 + simple_if_init $h3 + + ip link add name br1 type bridge vlan_filtering 1 + ip link set dev br1 up + + ip link set dev $swp1 master br1 + ip link set dev $swp1 up + tc qdisc add dev $swp1 clsact + + ip link set dev $swp2 master br1 + ip link set dev $swp2 up + + ip link set dev $swp3 up +} + +mirror_gre_cleanup() +{ + mirror_gre_tunnels_destroy $mirror_gre_tunnels + + ip link set dev $swp3 down + + ip link set dev $swp2 down + + tc qdisc del dev $swp1 clsact + ip link set dev $swp1 down + + ip link del dev br1 + + simple_if_fini $h3 + simple_if_fini $h2 + simple_if_fini $h1 + + vrf_cleanup +} diff --git a/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_bridge.sh b/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_bridge.sh new file mode 100755 index 000000000000..1ca631d5aaba --- /dev/null +++ b/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_bridge.sh @@ -0,0 +1,189 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +# Test for DSCP prioritization and rewrite. Packets ingress $swp1 with a DSCP +# tag and are prioritized according to the map at $swp1. They egress $swp2 and +# the DSCP value is updated to match the map at that interface. The updated DSCP +# tag is verified at $h2. +# +# ICMP responses are produced with the same DSCP tag that arrived at $h2. They +# go through prioritization at $swp2 and DSCP retagging at $swp1. The tag is +# verified at $h1--it should match the original tag. +# +# +----------------------+ +----------------------+ +# | H1 | | H2 | +# | + $h1 | | $h2 + | +# | | 192.0.2.1/28 | | 192.0.2.2/28 | | +# +----|-----------------+ +----------------|-----+ +# | | +# +----|----------------------------------------------------------------|-----+ +# | SW | | | +# | +-|----------------------------------------------------------------|-+ | +# | | + $swp1 BR $swp2 + | | +# | | APP=0,5,10 .. 7,5,17 APP=0,5,20 .. 7,5,27 | | +# | +--------------------------------------------------------------------+ | +# +---------------------------------------------------------------------------+ + +ALL_TESTS=" + ping_ipv4 + test_dscp +" + +lib_dir=$(dirname $0)/../../../net/forwarding + +NUM_NETIFS=4 +source $lib_dir/lib.sh + +h1_create() +{ + local dscp; + + simple_if_init $h1 192.0.2.1/28 + tc qdisc add dev $h1 clsact + dscp_capture_install $h1 10 +} + +h1_destroy() +{ + dscp_capture_uninstall $h1 10 + tc qdisc del dev $h1 clsact + simple_if_fini $h1 192.0.2.1/28 +} + +h2_create() +{ + simple_if_init $h2 192.0.2.2/28 + tc qdisc add dev $h2 clsact + dscp_capture_install $h2 20 +} + +h2_destroy() +{ + dscp_capture_uninstall $h2 20 + tc qdisc del dev $h2 clsact + simple_if_fini $h2 192.0.2.2/28 +} + +dscp_map() +{ + local base=$1; shift + + for prio in {0..7}; do + echo app=$prio,5,$((base + prio)) + done +} + +switch_create() +{ + ip link add name br1 type bridge vlan_filtering 1 + ip link set dev br1 up + ip link set dev $swp1 master br1 + ip link set dev $swp1 up + ip link set dev $swp2 master br1 + ip link set dev $swp2 up + + lldptool -T -i $swp1 -V APP $(dscp_map 10) >/dev/null + lldptool -T -i $swp2 -V APP $(dscp_map 20) >/dev/null + lldpad_app_wait_set $swp1 + lldpad_app_wait_set $swp2 +} + +switch_destroy() +{ + lldptool -T -i $swp2 -V APP -d $(dscp_map 20) >/dev/null + lldptool -T -i $swp1 -V APP -d $(dscp_map 10) >/dev/null + lldpad_app_wait_del + + ip link set dev $swp2 nomaster + ip link set dev $swp1 nomaster + ip link del dev br1 +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + swp1=${NETIFS[p2]} + + swp2=${NETIFS[p3]} + h2=${NETIFS[p4]} + + vrf_prepare + + h1_create + h2_create + switch_create +} + +cleanup() +{ + pre_cleanup + + switch_destroy + h2_destroy + h1_destroy + + vrf_cleanup +} + +ping_ipv4() +{ + ping_test $h1 192.0.2.2 +} + +dscp_ping_test() +{ + local vrf_name=$1; shift + local sip=$1; shift + local dip=$1; shift + local prio=$1; shift + local dev_10=$1; shift + local dev_20=$1; shift + + local dscp_10=$(((prio + 10) << 2)) + local dscp_20=$(((prio + 20) << 2)) + + RET=0 + + local -A t0s + eval "t0s=($(dscp_fetch_stats $dev_10 10) + $(dscp_fetch_stats $dev_20 20))" + + ip vrf exec $vrf_name \ + ${PING} -Q $dscp_10 ${sip:+-I $sip} $dip \ + -c 10 -i 0.1 -w 2 &> /dev/null + + local -A t1s + eval "t1s=($(dscp_fetch_stats $dev_10 10) + $(dscp_fetch_stats $dev_20 20))" + + for key in ${!t0s[@]}; do + local expect + if ((key == prio+10 || key == prio+20)); then + expect=10 + else + expect=0 + fi + + local delta=$((t1s[$key] - t0s[$key])) + ((expect == delta)) + check_err $? "DSCP $key: Expected to capture $expect packets, got $delta." + done + + log_test "DSCP rewrite: $dscp_10-(prio $prio)-$dscp_20" +} + +test_dscp() +{ + for prio in {0..7}; do + dscp_ping_test v$h1 192.0.2.1 192.0.2.2 $prio $h1 $h2 + done +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +tests_run + +exit $EXIT_STATUS diff --git a/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_router.sh b/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_router.sh new file mode 100755 index 000000000000..281d90766e12 --- /dev/null +++ b/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_router.sh @@ -0,0 +1,233 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +# Test for DSCP prioritization in the router. +# +# With ip_forward_update_priority disabled, the packets are expected to keep +# their DSCP (which in this test uses only values 0..7) intact as they are +# forwarded by the switch. That is verified at $h2. ICMP responses are formed +# with the same DSCP as the requests, and likewise pass through the switch +# intact, which is verified at $h1. +# +# With ip_forward_update_priority enabled, router reprioritizes the packets +# according to the table in reprioritize(). Thus, say, DSCP 7 maps to priority +# 4, which on egress maps back to DSCP 4. The response packet then gets +# reprioritized to 6, getting DSCP 6 on egress. +# +# +----------------------+ +----------------------+ +# | H1 | | H2 | +# | + $h1 | | $h2 + | +# | | 192.0.2.1/28 | | 192.0.2.18/28 | | +# +----|-----------------+ +----------------|-----+ +# | | +# +----|----------------------------------------------------------------|-----+ +# | SW | | | +# | + $swp1 $swp2 + | +# | 192.0.2.2/28 192.0.2.17/28 | +# | APP=0,5,0 .. 7,5,7 APP=0,5,0 .. 7,5,7 | +# +---------------------------------------------------------------------------+ + +ALL_TESTS=" + ping_ipv4 + test_update + test_no_update +" + +lib_dir=$(dirname $0)/../../../net/forwarding + +NUM_NETIFS=4 +source $lib_dir/lib.sh + +reprioritize() +{ + local in=$1; shift + + # This is based on rt_tos2priority in include/net/route.h. Assuming 1:1 + # mapping between priorities and TOS, it yields a new priority for a + # packet with ingress priority of $in. + local -a reprio=(0 0 2 2 6 6 4 4) + + echo ${reprio[$in]} +} + +h1_create() +{ + local dscp; + + simple_if_init $h1 192.0.2.1/28 + tc qdisc add dev $h1 clsact + dscp_capture_install $h1 0 + ip route add vrf v$h1 192.0.2.16/28 via 192.0.2.2 +} + +h1_destroy() +{ + ip route del vrf v$h1 192.0.2.16/28 via 192.0.2.2 + dscp_capture_uninstall $h1 0 + tc qdisc del dev $h1 clsact + simple_if_fini $h1 192.0.2.1/28 +} + +h2_create() +{ + simple_if_init $h2 192.0.2.18/28 + tc qdisc add dev $h2 clsact + dscp_capture_install $h2 0 + ip route add vrf v$h2 192.0.2.0/28 via 192.0.2.17 +} + +h2_destroy() +{ + ip route del vrf v$h2 192.0.2.0/28 via 192.0.2.17 + dscp_capture_uninstall $h2 0 + tc qdisc del dev $h2 clsact + simple_if_fini $h2 192.0.2.18/28 +} + +dscp_map() +{ + local base=$1; shift + + for prio in {0..7}; do + echo app=$prio,5,$((base + prio)) + done +} + +switch_create() +{ + simple_if_init $swp1 192.0.2.2/28 + __simple_if_init $swp2 v$swp1 192.0.2.17/28 + + lldptool -T -i $swp1 -V APP $(dscp_map 0) >/dev/null + lldptool -T -i $swp2 -V APP $(dscp_map 0) >/dev/null + lldpad_app_wait_set $swp1 + lldpad_app_wait_set $swp2 +} + +switch_destroy() +{ + lldptool -T -i $swp2 -V APP -d $(dscp_map 0) >/dev/null + lldptool -T -i $swp1 -V APP -d $(dscp_map 0) >/dev/null + lldpad_app_wait_del + + __simple_if_fini $swp2 192.0.2.17/28 + simple_if_fini $swp1 192.0.2.2/28 +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + swp1=${NETIFS[p2]} + + swp2=${NETIFS[p3]} + h2=${NETIFS[p4]} + + vrf_prepare + + sysctl_set net.ipv4.ip_forward_update_priority 1 + h1_create + h2_create + switch_create +} + +cleanup() +{ + pre_cleanup + + switch_destroy + h2_destroy + h1_destroy + sysctl_restore net.ipv4.ip_forward_update_priority + + vrf_cleanup +} + +ping_ipv4() +{ + ping_test $h1 192.0.2.18 +} + +dscp_ping_test() +{ + local vrf_name=$1; shift + local sip=$1; shift + local dip=$1; shift + local prio=$1; shift + local reprio=$1; shift + local dev1=$1; shift + local dev2=$1; shift + + local prio2=$($reprio $prio) # ICMP Request egress prio + local prio3=$($reprio $prio2) # ICMP Response egress prio + + local dscp=$((prio << 2)) # ICMP Request ingress DSCP + local dscp2=$((prio2 << 2)) # ICMP Request egress DSCP + local dscp3=$((prio3 << 2)) # ICMP Response egress DSCP + + RET=0 + + eval "local -A dev1_t0s=($(dscp_fetch_stats $dev1 0))" + eval "local -A dev2_t0s=($(dscp_fetch_stats $dev2 0))" + + ip vrf exec $vrf_name \ + ${PING} -Q $dscp ${sip:+-I $sip} $dip \ + -c 10 -i 0.1 -w 2 &> /dev/null + + eval "local -A dev1_t1s=($(dscp_fetch_stats $dev1 0))" + eval "local -A dev2_t1s=($(dscp_fetch_stats $dev2 0))" + + for i in {0..7}; do + local dscpi=$((i << 2)) + local expect2=0 + local expect3=0 + + if ((i == prio2)); then + expect2=10 + fi + if ((i == prio3)); then + expect3=10 + fi + + local delta=$((dev2_t1s[$i] - dev2_t0s[$i])) + ((expect2 == delta)) + check_err $? "DSCP $dscpi@$dev2: Expected to capture $expect2 packets, got $delta." + + delta=$((dev1_t1s[$i] - dev1_t0s[$i])) + ((expect3 == delta)) + check_err $? "DSCP $dscpi@$dev1: Expected to capture $expect3 packets, got $delta." + done + + log_test "DSCP rewrite: $dscp-(prio $prio2)-$dscp2-(prio $prio3)-$dscp3" +} + +__test_update() +{ + local update=$1; shift + local reprio=$1; shift + + sysctl_restore net.ipv4.ip_forward_update_priority + sysctl_set net.ipv4.ip_forward_update_priority $update + + for prio in {0..7}; do + dscp_ping_test v$h1 192.0.2.1 192.0.2.18 $prio $reprio $h1 $h2 + done +} + +test_update() +{ + __test_update 1 reprioritize +} + +test_no_update() +{ + __test_update 0 echo +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +tests_run + +exit $EXIT_STATUS diff --git a/tools/testing/selftests/drivers/net/mlxsw/router_scale.sh b/tools/testing/selftests/drivers/net/mlxsw/router_scale.sh new file mode 100644 index 000000000000..d231649b4f01 --- /dev/null +++ b/tools/testing/selftests/drivers/net/mlxsw/router_scale.sh @@ -0,0 +1,167 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +ROUTER_NUM_NETIFS=4 + +router_h1_create() +{ + simple_if_init $h1 192.0.1.1/24 + ip route add 193.0.0.0/8 via 192.0.1.2 dev $h1 +} + +router_h1_destroy() +{ + ip route del 193.0.0.0/8 via 192.0.1.2 dev $h1 + simple_if_fini $h1 192.0.1.1/24 +} + +router_h2_create() +{ + simple_if_init $h2 192.0.2.1/24 + tc qdisc add dev $h2 handle ffff: ingress +} + +router_h2_destroy() +{ + tc qdisc del dev $h2 handle ffff: ingress + simple_if_fini $h2 192.0.2.1/24 +} + +router_create() +{ + ip link set dev $rp1 up + ip link set dev $rp2 up + + ip address add 192.0.1.2/24 dev $rp1 + ip address add 192.0.2.2/24 dev $rp2 +} + +router_destroy() +{ + ip address del 192.0.2.2/24 dev $rp2 + ip address del 192.0.1.2/24 dev $rp1 + + ip link set dev $rp2 down + ip link set dev $rp1 down +} + +router_setup_prepare() +{ + h1=${NETIFS[p1]} + rp1=${NETIFS[p2]} + + rp2=${NETIFS[p3]} + h2=${NETIFS[p4]} + + h1mac=$(mac_get $h1) + rp1mac=$(mac_get $rp1) + + vrf_prepare + + router_h1_create + router_h2_create + + router_create +} + +router_offload_validate() +{ + local route_count=$1 + local offloaded_count + + offloaded_count=$(ip route | grep -o 'offload' | wc -l) + [[ $offloaded_count -ge $route_count ]] +} + +router_routes_create() +{ + local route_count=$1 + local count=0 + + ROUTE_FILE="$(mktemp)" + + for i in {0..255} + do + for j in {0..255} + do + for k in {0..255} + do + if [[ $count -eq $route_count ]]; then + break 3 + fi + + echo route add 193.${i}.${j}.${k}/32 via \ + 192.0.2.1 dev $rp2 >> $ROUTE_FILE + ((count++)) + done + done + done + + ip -b $ROUTE_FILE &> /dev/null +} + +router_routes_destroy() +{ + if [[ -v ROUTE_FILE ]]; then + rm -f $ROUTE_FILE + fi +} + +router_test() +{ + local route_count=$1 + local should_fail=$2 + local count=0 + + RET=0 + + router_routes_create $route_count + + router_offload_validate $route_count + check_err_fail $should_fail $? "Offload of $route_count routes" + if [[ $RET -ne 0 ]] || [[ $should_fail -eq 1 ]]; then + return + fi + + tc filter add dev $h2 ingress protocol ip pref 1 flower \ + skip_sw dst_ip 193.0.0.0/8 action drop + + for i in {0..255} + do + for j in {0..255} + do + for k in {0..255} + do + if [[ $count -eq $route_count ]]; then + break 3 + fi + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $rp1mac \ + -A 192.0.1.1 -B 193.${i}.${j}.${k} \ + -t ip -q + ((count++)) + done + done + done + + tc_check_packets "dev $h2 ingress" 1 $route_count + check_err $? "Offload mismatch" + + tc filter del dev $h2 ingress protocol ip pref 1 flower \ + skip_sw dst_ip 193.0.0.0/8 action drop + + router_routes_destroy +} + +router_cleanup() +{ + pre_cleanup + + router_routes_destroy + router_destroy + + router_h2_destroy + router_h1_destroy + + vrf_cleanup +} diff --git a/tools/testing/selftests/drivers/net/mlxsw/spectrum-2/tc_flower.sh b/tools/testing/selftests/drivers/net/mlxsw/spectrum-2/tc_flower.sh new file mode 100755 index 000000000000..3b75180f455d --- /dev/null +++ b/tools/testing/selftests/drivers/net/mlxsw/spectrum-2/tc_flower.sh @@ -0,0 +1,366 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +# This test is for checking the A-TCAM and C-TCAM operation in Spectrum-2. +# It tries to exercise as many code paths in the eRP state machine as +# possible. + +lib_dir=$(dirname $0)/../../../../net/forwarding + +ALL_TESTS="single_mask_test identical_filters_test two_masks_test \ + multiple_masks_test ctcam_edge_cases_test" +NUM_NETIFS=2 +source $lib_dir/tc_common.sh +source $lib_dir/lib.sh + +tcflags="skip_hw" + +h1_create() +{ + simple_if_init $h1 192.0.2.1/24 198.51.100.1/24 +} + +h1_destroy() +{ + simple_if_fini $h1 192.0.2.1/24 198.51.100.1/24 +} + +h2_create() +{ + simple_if_init $h2 192.0.2.2/24 198.51.100.2/24 + tc qdisc add dev $h2 clsact +} + +h2_destroy() +{ + tc qdisc del dev $h2 clsact + simple_if_fini $h2 192.0.2.2/24 198.51.100.2/24 +} + +single_mask_test() +{ + # When only a single mask is required, the device uses the master + # mask and not the eRP table. Verify that under this mode the right + # filter is matched + + RET=0 + + tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \ + $tcflags dst_ip 192.0.2.2 action drop + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 101 1 + check_err $? "Single filter - did not match" + + tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \ + $tcflags dst_ip 198.51.100.2 action drop + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 101 2 + check_err $? "Two filters - did not match highest priority" + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 198.51.100.1 -B 198.51.100.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 102 1 + check_err $? "Two filters - did not match lowest priority" + + tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 198.51.100.1 -B 198.51.100.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 102 2 + check_err $? "Single filter - did not match after delete" + + tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower + + log_test "single mask test ($tcflags)" +} + +identical_filters_test() +{ + # When two filters that only differ in their priority are used, + # one needs to be inserted into the C-TCAM. This test verifies + # that filters are correctly spilled to C-TCAM and that the right + # filter is matched + + RET=0 + + tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \ + $tcflags dst_ip 192.0.2.2 action drop + tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \ + $tcflags dst_ip 192.0.2.2 action drop + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 101 1 + check_err $? "Did not match A-TCAM filter" + + tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 102 1 + check_err $? "Did not match C-TCAM filter after A-TCAM delete" + + tc filter add dev $h2 ingress protocol ip pref 3 handle 103 flower \ + $tcflags dst_ip 192.0.2.2 action drop + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 102 2 + check_err $? "Did not match C-TCAM filter after A-TCAM add" + + tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 103 1 + check_err $? "Did not match A-TCAM filter after C-TCAM delete" + + tc filter del dev $h2 ingress protocol ip pref 3 handle 103 flower + + log_test "identical filters test ($tcflags)" +} + +two_masks_test() +{ + # When more than one mask is required, the eRP table is used. This + # test verifies that the eRP table is correctly allocated and used + + RET=0 + + tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \ + $tcflags dst_ip 192.0.2.2 action drop + tc filter add dev $h2 ingress protocol ip pref 3 handle 103 flower \ + $tcflags dst_ip 192.0.0.0/16 action drop + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 101 1 + check_err $? "Two filters - did not match highest priority" + + tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 103 1 + check_err $? "Single filter - did not match" + + tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \ + $tcflags dst_ip 192.0.2.0/24 action drop + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 102 1 + check_err $? "Two filters - did not match highest priority after add" + + tc filter del dev $h2 ingress protocol ip pref 3 handle 103 flower + tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower + + log_test "two masks test ($tcflags)" +} + +multiple_masks_test() +{ + # The number of masks in a region is limited. Once the maximum + # number of masks has been reached filters that require new + # masks are spilled to the C-TCAM. This test verifies that + # spillage is performed correctly and that the right filter is + # matched + + local index + + RET=0 + + NUM_MASKS=32 + BASE_INDEX=100 + + for i in $(eval echo {1..$NUM_MASKS}); do + index=$((BASE_INDEX - i)) + + tc filter add dev $h2 ingress protocol ip pref $index \ + handle $index \ + flower $tcflags dst_ip 192.0.2.2/${i} src_ip 192.0.2.1 \ + action drop + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 \ + -B 192.0.2.2 -t ip -q + + tc_check_packets "dev $h2 ingress" $index 1 + check_err $? "$i filters - did not match highest priority (add)" + done + + for i in $(eval echo {$NUM_MASKS..1}); do + index=$((BASE_INDEX - i)) + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 \ + -B 192.0.2.2 -t ip -q + + tc_check_packets "dev $h2 ingress" $index 2 + check_err $? "$i filters - did not match highest priority (del)" + + tc filter del dev $h2 ingress protocol ip pref $index \ + handle $index flower + done + + log_test "multiple masks test ($tcflags)" +} + +ctcam_two_atcam_masks_test() +{ + RET=0 + + # First case: C-TCAM is disabled when there are two A-TCAM masks. + # We push a filter into the C-TCAM by using two identical filters + # as in identical_filters_test() + + # Filter goes into A-TCAM + tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \ + $tcflags dst_ip 192.0.2.2 action drop + # Filter goes into C-TCAM + tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \ + $tcflags dst_ip 192.0.2.2 action drop + # Filter goes into A-TCAM + tc filter add dev $h2 ingress protocol ip pref 3 handle 103 flower \ + $tcflags dst_ip 192.0.2.0/24 action drop + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 101 1 + check_err $? "Did not match A-TCAM filter" + + # Delete both A-TCAM and C-TCAM filters and make sure the remaining + # A-TCAM filter still works + tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower + tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 103 1 + check_err $? "Did not match A-TCAM filter" + + tc filter del dev $h2 ingress protocol ip pref 3 handle 103 flower + + log_test "ctcam with two atcam masks test ($tcflags)" +} + +ctcam_one_atcam_mask_test() +{ + RET=0 + + # Second case: C-TCAM is disabled when there is one A-TCAM mask. + # The test is similar to identical_filters_test() + + # Filter goes into A-TCAM + tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \ + $tcflags dst_ip 192.0.2.2 action drop + # Filter goes into C-TCAM + tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \ + $tcflags dst_ip 192.0.2.2 action drop + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 101 1 + check_err $? "Did not match C-TCAM filter" + + tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 102 1 + check_err $? "Did not match A-TCAM filter" + + tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower + + log_test "ctcam with one atcam mask test ($tcflags)" +} + +ctcam_no_atcam_masks_test() +{ + RET=0 + + # Third case: C-TCAM is disabled when there are no A-TCAM masks + # This test exercises the code path that transitions the eRP table + # to its initial state after deleting the last C-TCAM mask + + # Filter goes into A-TCAM + tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \ + $tcflags dst_ip 192.0.2.2 action drop + # Filter goes into C-TCAM + tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \ + $tcflags dst_ip 192.0.2.2 action drop + + tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower + tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower + + log_test "ctcam with no atcam masks test ($tcflags)" +} + +ctcam_edge_cases_test() +{ + # When the C-TCAM is disabled after deleting the last C-TCAM + # mask, we want to make sure the eRP state machine is put in + # the correct state + + ctcam_two_atcam_masks_test + ctcam_one_atcam_mask_test + ctcam_no_atcam_masks_test +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + h2=${NETIFS[p2]} + h1mac=$(mac_get $h1) + h2mac=$(mac_get $h2) + + vrf_prepare + + h1_create + h2_create +} + +cleanup() +{ + pre_cleanup + + h2_destroy + h1_destroy + + vrf_cleanup +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +tests_run + +if ! tc_offload_check; then + check_err 1 "Could not test offloaded functionality" + log_test "mlxsw-specific tests for tc flower" + exit +else + tcflags="skip_sw" + tests_run +fi + +exit $EXIT_STATUS diff --git a/tools/testing/selftests/drivers/net/mlxsw/spectrum/devlink_lib_spectrum.sh b/tools/testing/selftests/drivers/net/mlxsw/spectrum/devlink_lib_spectrum.sh new file mode 100644 index 000000000000..73035e25085d --- /dev/null +++ b/tools/testing/selftests/drivers/net/mlxsw/spectrum/devlink_lib_spectrum.sh @@ -0,0 +1,119 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +source "../../../../net/forwarding/devlink_lib.sh" + +if [ "$DEVLINK_VIDDID" != "15b3:cb84" ]; then + echo "SKIP: test is tailored for Mellanox Spectrum" + exit 1 +fi + +# Needed for returning to default +declare -A KVD_DEFAULTS + +KVD_CHILDREN="linear hash_single hash_double" +KVDL_CHILDREN="singles chunks large_chunks" + +devlink_sp_resource_minimize() +{ + local size + local i + + for i in $KVD_CHILDREN; do + size=$(devlink_resource_get kvd "$i" | jq '.["size_min"]') + devlink_resource_size_set "$size" kvd "$i" + done + + for i in $KVDL_CHILDREN; do + size=$(devlink_resource_get kvd linear "$i" | \ + jq '.["size_min"]') + devlink_resource_size_set "$size" kvd linear "$i" + done +} + +devlink_sp_size_kvd_to_default() +{ + local need_reload=0 + local i + + for i in $KVD_CHILDREN; do + local size=$(echo "${KVD_DEFAULTS[kvd_$i]}" | jq '.["size"]') + current_size=$(devlink_resource_size_get kvd "$i") + + if [ "$size" -ne "$current_size" ]; then + devlink_resource_size_set "$size" kvd "$i" + need_reload=1 + fi + done + + for i in $KVDL_CHILDREN; do + local size=$(echo "${KVD_DEFAULTS[kvd_linear_$i]}" | \ + jq '.["size"]') + current_size=$(devlink_resource_size_get kvd linear "$i") + + if [ "$size" -ne "$current_size" ]; then + devlink_resource_size_set "$size" kvd linear "$i" + need_reload=1 + fi + done + + if [ "$need_reload" -ne "0" ]; then + devlink_reload + fi +} + +devlink_sp_read_kvd_defaults() +{ + local key + local i + + KVD_DEFAULTS[kvd]=$(devlink_resource_get "kvd") + for i in $KVD_CHILDREN; do + key=kvd_$i + KVD_DEFAULTS[$key]=$(devlink_resource_get kvd "$i") + done + + for i in $KVDL_CHILDREN; do + key=kvd_linear_$i + KVD_DEFAULTS[$key]=$(devlink_resource_get kvd linear "$i") + done +} + +KVD_PROFILES="default scale ipv4_max" + +devlink_sp_resource_kvd_profile_set() +{ + local profile=$1 + + case "$profile" in + scale) + devlink_resource_size_set 64000 kvd linear + devlink_resource_size_set 15616 kvd linear singles + devlink_resource_size_set 32000 kvd linear chunks + devlink_resource_size_set 16384 kvd linear large_chunks + devlink_resource_size_set 128000 kvd hash_single + devlink_resource_size_set 48000 kvd hash_double + devlink_reload + ;; + ipv4_max) + devlink_resource_size_set 64000 kvd linear + devlink_resource_size_set 15616 kvd linear singles + devlink_resource_size_set 32000 kvd linear chunks + devlink_resource_size_set 16384 kvd linear large_chunks + devlink_resource_size_set 144000 kvd hash_single + devlink_resource_size_set 32768 kvd hash_double + devlink_reload + ;; + default) + devlink_resource_size_set 98304 kvd linear + devlink_resource_size_set 16384 kvd linear singles + devlink_resource_size_set 49152 kvd linear chunks + devlink_resource_size_set 32768 kvd linear large_chunks + devlink_resource_size_set 87040 kvd hash_single + devlink_resource_size_set 60416 kvd hash_double + devlink_reload + ;; + *) + check_err 1 "Unknown profile $profile" + esac +} diff --git a/tools/testing/selftests/drivers/net/mlxsw/spectrum/devlink_resources.sh b/tools/testing/selftests/drivers/net/mlxsw/spectrum/devlink_resources.sh new file mode 100755 index 000000000000..b1fe960e398a --- /dev/null +++ b/tools/testing/selftests/drivers/net/mlxsw/spectrum/devlink_resources.sh @@ -0,0 +1,117 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +NUM_NETIFS=1 +source devlink_lib_spectrum.sh + +setup_prepare() +{ + devlink_sp_read_kvd_defaults +} + +cleanup() +{ + pre_cleanup + devlink_sp_size_kvd_to_default +} + +trap cleanup EXIT + +setup_prepare + +profiles_test() +{ + local i + + log_info "Running profile tests" + + for i in $KVD_PROFILES; do + RET=0 + devlink_sp_resource_kvd_profile_set $i + log_test "'$i' profile" + done + + # Default is explicitly tested at end to ensure it's actually applied + RET=0 + devlink_sp_resource_kvd_profile_set "default" + log_test "'default' profile" +} + +resources_min_test() +{ + local size + local i + local j + + log_info "Running KVD-minimum tests" + + for i in $KVD_CHILDREN; do + RET=0 + size=$(devlink_resource_get kvd "$i" | jq '.["size_min"]') + devlink_resource_size_set "$size" kvd "$i" + + # In case of linear, need to minimize sub-resources as well + if [[ "$i" == "linear" ]]; then + for j in $KVDL_CHILDREN; do + devlink_resource_size_set 0 kvd linear "$j" + done + fi + + devlink_reload + devlink_sp_size_kvd_to_default + log_test "'$i' minimize [$size]" + done +} + +resources_max_test() +{ + local min_size + local size + local i + local j + + log_info "Running KVD-maximum tests" + for i in $KVD_CHILDREN; do + RET=0 + devlink_sp_resource_minimize + + # Calculate the maximum possible size for the given partition + size=$(devlink_resource_size_get kvd) + for j in $KVD_CHILDREN; do + if [ "$i" != "$j" ]; then + min_size=$(devlink_resource_get kvd "$j" | \ + jq '.["size_min"]') + size=$((size - min_size)) + fi + done + + # Test almost maximum size + devlink_resource_size_set "$((size - 128))" kvd "$i" + devlink_reload + log_test "'$i' almost maximize [$((size - 128))]" + + # Test above maximum size + devlink resource set "$DEVLINK_DEV" \ + path "kvd/$i" size $((size + 128)) &> /dev/null + check_fail $? "Set kvd/$i to size $((size + 128)) should fail" + log_test "'$i' Overflow rejection [$((size + 128))]" + + # Test maximum size + if [ "$i" == "hash_single" ] || [ "$i" == "hash_double" ]; then + echo "SKIP: Observed problem with exact max $i" + continue + fi + + devlink_resource_size_set "$size" kvd "$i" + devlink_reload + log_test "'$i' maximize [$size]" + + devlink_sp_size_kvd_to_default + done +} + +profiles_test +resources_min_test +resources_max_test + +exit "$RET" diff --git a/tools/testing/selftests/drivers/net/mlxsw/spectrum/mirror_gre_scale.sh b/tools/testing/selftests/drivers/net/mlxsw/spectrum/mirror_gre_scale.sh new file mode 100644 index 000000000000..8d2186c7c62b --- /dev/null +++ b/tools/testing/selftests/drivers/net/mlxsw/spectrum/mirror_gre_scale.sh @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0 +source ../mirror_gre_scale.sh + +mirror_gre_get_target() +{ + local should_fail=$1; shift + + if ((! should_fail)); then + echo 3 + else + echo 4 + fi +} diff --git a/tools/testing/selftests/drivers/net/mlxsw/spectrum/resource_scale.sh b/tools/testing/selftests/drivers/net/mlxsw/spectrum/resource_scale.sh new file mode 100755 index 000000000000..a0a80e1a69e8 --- /dev/null +++ b/tools/testing/selftests/drivers/net/mlxsw/spectrum/resource_scale.sh @@ -0,0 +1,55 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +NUM_NETIFS=6 +source ../../../../net/forwarding/lib.sh +source ../../../../net/forwarding/tc_common.sh +source devlink_lib_spectrum.sh + +current_test="" + +cleanup() +{ + pre_cleanup + if [ ! -z $current_test ]; then + ${current_test}_cleanup + fi + devlink_sp_size_kvd_to_default +} + +devlink_sp_read_kvd_defaults +trap cleanup EXIT + +ALL_TESTS="router tc_flower mirror_gre" +for current_test in ${TESTS:-$ALL_TESTS}; do + source ${current_test}_scale.sh + + num_netifs_var=${current_test^^}_NUM_NETIFS + num_netifs=${!num_netifs_var:-$NUM_NETIFS} + + for profile in $KVD_PROFILES; do + RET=0 + devlink_sp_resource_kvd_profile_set $profile + if [[ $RET -gt 0 ]]; then + log_test "'$current_test' [$profile] setting" + continue + fi + + for should_fail in 0 1; do + RET=0 + target=$(${current_test}_get_target "$should_fail") + ${current_test}_setup_prepare + setup_wait $num_netifs + ${current_test}_test "$target" "$should_fail" + ${current_test}_cleanup + if [[ "$should_fail" -eq 0 ]]; then + log_test "'$current_test' [$profile] $target" + else + log_test "'$current_test' [$profile] overflow $target" + fi + done + done +done +current_test="" + +exit "$RET" diff --git a/tools/testing/selftests/drivers/net/mlxsw/spectrum/router_scale.sh b/tools/testing/selftests/drivers/net/mlxsw/spectrum/router_scale.sh new file mode 100644 index 000000000000..21c4697d5bab --- /dev/null +++ b/tools/testing/selftests/drivers/net/mlxsw/spectrum/router_scale.sh @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0 +source ../router_scale.sh + +router_get_target() +{ + local should_fail=$1 + local target + + target=$(devlink_resource_size_get kvd hash_single) + + if [[ $should_fail -eq 0 ]]; then + target=$((target * 85 / 100)) + else + target=$((target + 1)) + fi + + echo $target +} diff --git a/tools/testing/selftests/drivers/net/mlxsw/spectrum/tc_flower_scale.sh b/tools/testing/selftests/drivers/net/mlxsw/spectrum/tc_flower_scale.sh new file mode 100644 index 000000000000..f9bfd8937765 --- /dev/null +++ b/tools/testing/selftests/drivers/net/mlxsw/spectrum/tc_flower_scale.sh @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0 +source ../tc_flower_scale.sh + +tc_flower_get_target() +{ + local should_fail=$1; shift + + # 6144 (6x1024) is the theoretical maximum. + # One bank of 512 rules is taken by the 18-byte MC router rule. + # One rule is the ACL catch-all. + # 6144 - 512 - 1 = 5631 + local target=5631 + + if ((! should_fail)); then + echo $target + else + echo $((target + 1)) + fi +} diff --git a/tools/testing/selftests/drivers/net/mlxsw/tc_flower_scale.sh b/tools/testing/selftests/drivers/net/mlxsw/tc_flower_scale.sh new file mode 100644 index 000000000000..a6d733d2a4b4 --- /dev/null +++ b/tools/testing/selftests/drivers/net/mlxsw/tc_flower_scale.sh @@ -0,0 +1,134 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +# Test for resource limit of offloaded flower rules. The test adds a given +# number of flower matches for different IPv6 addresses, then generates traffic, +# and ensures each was hit exactly once. This file contains functions to set up +# a testing topology and run the test, and is meant to be sourced from a test +# script that calls the testing routine with a given number of rules. + +TC_FLOWER_NUM_NETIFS=2 + +tc_flower_h1_create() +{ + simple_if_init $h1 + tc qdisc add dev $h1 clsact +} + +tc_flower_h1_destroy() +{ + tc qdisc del dev $h1 clsact + simple_if_fini $h1 +} + +tc_flower_h2_create() +{ + simple_if_init $h2 + tc qdisc add dev $h2 clsact +} + +tc_flower_h2_destroy() +{ + tc qdisc del dev $h2 clsact + simple_if_fini $h2 +} + +tc_flower_setup_prepare() +{ + h1=${NETIFS[p1]} + h2=${NETIFS[p2]} + + vrf_prepare + + tc_flower_h1_create + tc_flower_h2_create +} + +tc_flower_cleanup() +{ + pre_cleanup + + tc_flower_h2_destroy + tc_flower_h1_destroy + + vrf_cleanup + + if [[ -v TC_FLOWER_BATCH_FILE ]]; then + rm -f $TC_FLOWER_BATCH_FILE + fi +} + +tc_flower_addr() +{ + local num=$1; shift + + printf "2001:db8:1::%x" $num +} + +tc_flower_rules_create() +{ + local count=$1; shift + local should_fail=$1; shift + + TC_FLOWER_BATCH_FILE="$(mktemp)" + + for ((i = 0; i < count; ++i)); do + cat >> $TC_FLOWER_BATCH_FILE <<-EOF + filter add dev $h2 ingress \ + prot ipv6 \ + pref 1000 \ + flower $tcflags dst_ip $(tc_flower_addr $i) \ + action drop + EOF + done + + tc -b $TC_FLOWER_BATCH_FILE + check_err_fail $should_fail $? "Rule insertion" +} + +__tc_flower_test() +{ + local count=$1; shift + local should_fail=$1; shift + local last=$((count - 1)) + + tc_flower_rules_create $count $should_fail + + for ((i = 0; i < count; ++i)); do + $MZ $h1 -q -c 1 -t ip -p 20 -b bc -6 \ + -A 2001:db8:2::1 \ + -B $(tc_flower_addr $i) + done + + MISMATCHES=$( + tc -j -s filter show dev $h2 ingress | + jq -r '[ .[] | select(.kind == "flower") | .options | + values as $rule | .actions[].stats.packets | + select(. != 1) | "\(.) on \($rule.keys.dst_ip)" ] | + join(", ")' + ) + + test -z "$MISMATCHES" + check_err $? "Expected to capture 1 packet for each IP, but got $MISMATCHES" +} + +tc_flower_test() +{ + local count=$1; shift + local should_fail=$1; shift + + # We use lower 16 bits of IPv6 address for match. Also there are only 16 + # bits of rule priority space. + if ((count > 65536)); then + check_err 1 "Invalid count of $count. At most 65536 rules supported" + return + fi + + if ! tc_offload_check $TC_FLOWER_NUM_NETIFS; then + check_err 1 "Could not test offloaded functionality" + return + fi + + tcflags="skip_sw" + __tc_flower_test $count $should_fail +} diff --git a/tools/testing/selftests/drivers/usb/usbip/usbip_test.sh b/tools/testing/selftests/drivers/usb/usbip/usbip_test.sh index 1893d0f59ad7..a72df93cf1f8 100755 --- a/tools/testing/selftests/drivers/usb/usbip/usbip_test.sh +++ b/tools/testing/selftests/drivers/usb/usbip/usbip_test.sh @@ -46,7 +46,6 @@ if ! /sbin/modprobe -q -n usbip_host; then fi if /sbin/modprobe -q usbip_host; then - /sbin/modprobe -q -r test_bitmap echo "usbip_test: module usbip_host is loaded [OK]" else echo "usbip_test: module usbip_host failed to load [FAIL]" @@ -56,7 +55,6 @@ fi echo "Load vhci_hcd module" if /sbin/modprobe -q vhci_hcd; then - /sbin/modprobe -q -r test_bitmap echo "usbip_test: module vhci_hcd is loaded [OK]" else echo "usbip_test: module vhci_hcd failed to load [FAIL]" diff --git a/tools/testing/selftests/ftrace/config b/tools/testing/selftests/ftrace/config index b01924c71c09..07db5ab09cc7 100644 --- a/tools/testing/selftests/ftrace/config +++ b/tools/testing/selftests/ftrace/config @@ -4,3 +4,6 @@ CONFIG_FUNCTION_PROFILER=y CONFIG_TRACER_SNAPSHOT=y CONFIG_STACK_TRACER=y CONFIG_HIST_TRIGGERS=y +CONFIG_PREEMPT_TRACER=y +CONFIG_IRQSOFF_TRACER=y +CONFIG_PREEMPTIRQ_DELAY_TEST=m diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc index a0002563e9ee..1ad70cdaf442 100644 --- a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc +++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc @@ -9,28 +9,22 @@ echo > kprobe_events case `uname -m` in x86_64) - ARG2=%si - OFFS=8 + ARG1=%di ;; i[3456]86) - ARG2=%cx - OFFS=4 + ARG1=%ax ;; aarch64) - ARG2=%x1 - OFFS=8 + ARG1=%x0 ;; arm*) - ARG2=%r1 - OFFS=4 + ARG1=%r0 ;; ppc64*) - ARG2=%r4 - OFFS=8 + ARG1=%r3 ;; ppc*) - ARG2=%r4 - OFFS=4 + ARG1=%r3 ;; *) echo "Please implement other architecture here" @@ -38,17 +32,17 @@ ppc*) esac : "Test get argument (1)" -echo "p:testprobe create_trace_kprobe arg1=+0(+0(${ARG2})):string" > kprobe_events +echo "p:testprobe tracefs_create_dir arg1=+0(${ARG1}):string" > kprobe_events echo 1 > events/kprobes/testprobe/enable -! echo test >> kprobe_events -tail -n 1 trace | grep -qe "testprobe.* arg1=\"test\"" +echo "p:test _do_fork" >> kprobe_events +grep -qe "testprobe.* arg1=\"test\"" trace echo 0 > events/kprobes/testprobe/enable : "Test get argument (2)" -echo "p:testprobe create_trace_kprobe arg1=+0(+0(${ARG2})):string arg2=+0(+${OFFS}(${ARG2})):string" > kprobe_events +echo "p:testprobe tracefs_create_dir arg1=+0(${ARG1}):string arg2=+0(${ARG1}):string" > kprobe_events echo 1 > events/kprobes/testprobe/enable -! echo test1 test2 >> kprobe_events -tail -n 1 trace | grep -qe "testprobe.* arg1=\"test1\" arg2=\"test2\"" +echo "p:test _do_fork" >> kprobe_events +grep -qe "testprobe.* arg1=\"test\" arg2=\"test\"" trace echo 0 > events/enable echo > kprobe_events diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/probepoint.tc b/tools/testing/selftests/ftrace/test.d/kprobe/probepoint.tc index 4fda01a08da4..519d2763f5d2 100644 --- a/tools/testing/selftests/ftrace/test.d/kprobe/probepoint.tc +++ b/tools/testing/selftests/ftrace/test.d/kprobe/probepoint.tc @@ -4,7 +4,7 @@ [ -f kprobe_events ] || exit_unsupported # this is configurable -TARGET_FUNC=create_trace_kprobe +TARGET_FUNC=tracefs_create_dir dec_addr() { # hexaddr printf "%d" "0x"`echo $1 | tail -c 8` diff --git a/tools/testing/selftests/ftrace/test.d/preemptirq/irqsoff_tracer.tc b/tools/testing/selftests/ftrace/test.d/preemptirq/irqsoff_tracer.tc new file mode 100644 index 000000000000..cbd174334a48 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/preemptirq/irqsoff_tracer.tc @@ -0,0 +1,73 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# description: test for the preemptirqsoff tracer + +MOD=preemptirq_delay_test + +fail() { + reset_tracer + rmmod $MOD || true + exit_fail +} + +unsup() { #msg + reset_tracer + rmmod $MOD || true + echo $1 + exit_unsupported +} + +modprobe $MOD || unsup "$MOD module not available" +rmmod $MOD + +grep -q "preemptoff" available_tracers || unsup "preemptoff tracer not enabled" +grep -q "irqsoff" available_tracers || unsup "irqsoff tracer not enabled" + +reset_tracer + +# Simulate preemptoff section for half a second couple of times +echo preemptoff > current_tracer +sleep 1 +modprobe $MOD test_mode=preempt delay=500000 || fail +rmmod $MOD || fail +modprobe $MOD test_mode=preempt delay=500000 || fail +rmmod $MOD || fail +modprobe $MOD test_mode=preempt delay=500000 || fail +rmmod $MOD || fail + +cat trace + +# Confirm which tracer +grep -q "tracer: preemptoff" trace || fail + +# Check the end of the section +egrep -q "5.....us : <stack trace>" trace || fail + +# Check for 500ms of latency +egrep -q "latency: 5..... us" trace || fail + +reset_tracer + +# Simulate irqsoff section for half a second couple of times +echo irqsoff > current_tracer +sleep 1 +modprobe $MOD test_mode=irq delay=500000 || fail +rmmod $MOD || fail +modprobe $MOD test_mode=irq delay=500000 || fail +rmmod $MOD || fail +modprobe $MOD test_mode=irq delay=500000 || fail +rmmod $MOD || fail + +cat trace + +# Confirm which tracer +grep -q "tracer: irqsoff" trace || fail + +# Check the end of the section +egrep -q "5.....us : <stack trace>" trace || fail + +# Check for 500ms of latency +egrep -q "latency: 5..... us" trace || fail + +reset_tracer +exit 0 diff --git a/tools/testing/selftests/gpio/gpio-mockup-chardev.c b/tools/testing/selftests/gpio/gpio-mockup-chardev.c index 667e916fa7cc..f8d468f54e98 100644 --- a/tools/testing/selftests/gpio/gpio-mockup-chardev.c +++ b/tools/testing/selftests/gpio/gpio-mockup-chardev.c @@ -225,10 +225,10 @@ int gpio_pin_test(struct gpiochip_info *cinfo, int line, int flag, int value) if (flag & GPIOHANDLE_REQUEST_ACTIVE_LOW) debugfs_value = !debugfs_value; - if (!(debugfs_dir == OUT && value == debugfs_value)) + if (!(debugfs_dir == OUT && value == debugfs_value)) { errno = -EINVAL; - ret = -errno; - + ret = -errno; + } } gpiotools_release_linehandle(fd); diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore index 63fc1ab9248f..4202139d81d9 100644 --- a/tools/testing/selftests/kvm/.gitignore +++ b/tools/testing/selftests/kvm/.gitignore @@ -1,3 +1,5 @@ +cr4_cpuid_sync_test set_sregs_test sync_regs_test vmx_tsc_adjust_test +state_test diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index d9d00319b07c..03b0f551bedf 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -9,13 +9,18 @@ LIBKVM_x86_64 = lib/x86.c lib/vmx.c TEST_GEN_PROGS_x86_64 = set_sregs_test TEST_GEN_PROGS_x86_64 += sync_regs_test TEST_GEN_PROGS_x86_64 += vmx_tsc_adjust_test +TEST_GEN_PROGS_x86_64 += cr4_cpuid_sync_test +TEST_GEN_PROGS_x86_64 += state_test +TEST_GEN_PROGS_x86_64 += dirty_log_test TEST_GEN_PROGS += $(TEST_GEN_PROGS_$(UNAME_M)) LIBKVM += $(LIBKVM_$(UNAME_M)) INSTALL_HDR_PATH = $(top_srcdir)/usr LINUX_HDR_PATH = $(INSTALL_HDR_PATH)/include/ -CFLAGS += -O2 -g -std=gnu99 -I$(LINUX_HDR_PATH) -Iinclude -I$(<D) -I.. +LINUX_TOOL_INCLUDE = $(top_srcdir)tools/include +CFLAGS += -O2 -g -std=gnu99 -I$(LINUX_TOOL_INCLUDE) -I$(LINUX_HDR_PATH) -Iinclude -I$(<D) -I.. +LDFLAGS += -lpthread # After inclusion, $(OUTPUT) is defined and # $(TEST_GEN_PROGS) starts with $(OUTPUT)/ diff --git a/tools/testing/selftests/kvm/cr4_cpuid_sync_test.c b/tools/testing/selftests/kvm/cr4_cpuid_sync_test.c new file mode 100644 index 000000000000..11ec358bf969 --- /dev/null +++ b/tools/testing/selftests/kvm/cr4_cpuid_sync_test.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * CR4 and CPUID sync test + * + * Copyright 2018, Red Hat, Inc. and/or its affiliates. + * + * Author: + * Wei Huang <wei@redhat.com> + */ + +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> + +#include "test_util.h" + +#include "kvm_util.h" +#include "x86.h" + +#define X86_FEATURE_XSAVE (1<<26) +#define X86_FEATURE_OSXSAVE (1<<27) +#define VCPU_ID 1 + +static inline bool cr4_cpuid_is_sync(void) +{ + int func, subfunc; + uint32_t eax, ebx, ecx, edx; + uint64_t cr4; + + func = 0x1; + subfunc = 0x0; + __asm__ __volatile__("cpuid" + : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) + : "a"(func), "c"(subfunc)); + + cr4 = get_cr4(); + + return (!!(ecx & X86_FEATURE_OSXSAVE)) == (!!(cr4 & X86_CR4_OSXSAVE)); +} + +static void guest_code(void) +{ + uint64_t cr4; + + /* turn on CR4.OSXSAVE */ + cr4 = get_cr4(); + cr4 |= X86_CR4_OSXSAVE; + set_cr4(cr4); + + /* verify CR4.OSXSAVE == CPUID.OSXSAVE */ + GUEST_ASSERT(cr4_cpuid_is_sync()); + + /* notify hypervisor to change CR4 */ + GUEST_SYNC(0); + + /* check again */ + GUEST_ASSERT(cr4_cpuid_is_sync()); + + GUEST_DONE(); +} + +int main(int argc, char *argv[]) +{ + struct kvm_run *run; + struct kvm_vm *vm; + struct kvm_sregs sregs; + struct kvm_cpuid_entry2 *entry; + int rc; + + entry = kvm_get_supported_cpuid_entry(1); + if (!(entry->ecx & X86_FEATURE_XSAVE)) { + printf("XSAVE feature not supported, skipping test\n"); + return 0; + } + + /* Tell stdout not to buffer its content */ + setbuf(stdout, NULL); + + /* Create VM */ + vm = vm_create_default(VCPU_ID, 0, guest_code); + vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); + run = vcpu_state(vm, VCPU_ID); + + while (1) { + rc = _vcpu_run(vm, VCPU_ID); + + if (run->exit_reason == KVM_EXIT_IO) { + switch (run->io.port) { + case GUEST_PORT_SYNC: + /* emulate hypervisor clearing CR4.OSXSAVE */ + vcpu_sregs_get(vm, VCPU_ID, &sregs); + sregs.cr4 &= ~X86_CR4_OSXSAVE; + vcpu_sregs_set(vm, VCPU_ID, &sregs); + break; + case GUEST_PORT_ABORT: + TEST_ASSERT(false, "Guest CR4 bit (OSXSAVE) unsynchronized with CPUID bit."); + break; + case GUEST_PORT_DONE: + goto done; + default: + TEST_ASSERT(false, "Unknown port 0x%x.", + run->io.port); + } + } + } + + kvm_vm_free(vm); + +done: + return 0; +} diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c new file mode 100644 index 000000000000..0c2cdc105f96 --- /dev/null +++ b/tools/testing/selftests/kvm/dirty_log_test.c @@ -0,0 +1,308 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * KVM dirty page logging test + * + * Copyright (C) 2018, Red Hat, Inc. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <time.h> +#include <pthread.h> +#include <linux/bitmap.h> +#include <linux/bitops.h> + +#include "test_util.h" +#include "kvm_util.h" + +#define DEBUG printf + +#define VCPU_ID 1 +/* The memory slot index to track dirty pages */ +#define TEST_MEM_SLOT_INDEX 1 +/* + * GPA offset of the testing memory slot. Must be bigger than the + * default vm mem slot, which is DEFAULT_GUEST_PHY_PAGES. + */ +#define TEST_MEM_OFFSET (1ULL << 30) /* 1G */ +/* Size of the testing memory slot */ +#define TEST_MEM_PAGES (1ULL << 18) /* 1G for 4K pages */ +/* How many pages to dirty for each guest loop */ +#define TEST_PAGES_PER_LOOP 1024 +/* How many host loops to run (one KVM_GET_DIRTY_LOG for each loop) */ +#define TEST_HOST_LOOP_N 32 +/* Interval for each host loop (ms) */ +#define TEST_HOST_LOOP_INTERVAL 10 + +/* + * Guest variables. We use these variables to share data between host + * and guest. There are two copies of the variables, one in host memory + * (which is unused) and one in guest memory. When the host wants to + * access these variables, it needs to call addr_gva2hva() to access the + * guest copy. + */ +uint64_t guest_random_array[TEST_PAGES_PER_LOOP]; +uint64_t guest_iteration; +uint64_t guest_page_size; + +/* + * Writes to the first byte of a random page within the testing memory + * region continuously. + */ +void guest_code(void) +{ + int i = 0; + uint64_t volatile *array = guest_random_array; + uint64_t volatile *guest_addr; + + while (true) { + for (i = 0; i < TEST_PAGES_PER_LOOP; i++) { + /* + * Write to the first 8 bytes of a random page + * on the testing memory region. + */ + guest_addr = (uint64_t *) + (TEST_MEM_OFFSET + + (array[i] % TEST_MEM_PAGES) * guest_page_size); + *guest_addr = guest_iteration; + } + /* Tell the host that we need more random numbers */ + GUEST_SYNC(1); + } +} + +/* + * Host variables. These variables should only be used by the host + * rather than the guest. + */ +bool host_quit; + +/* Points to the test VM memory region on which we track dirty logs */ +void *host_test_mem; + +/* For statistics only */ +uint64_t host_dirty_count; +uint64_t host_clear_count; +uint64_t host_track_next_count; + +/* + * We use this bitmap to track some pages that should have its dirty + * bit set in the _next_ iteration. For example, if we detected the + * page value changed to current iteration but at the same time the + * page bit is cleared in the latest bitmap, then the system must + * report that write in the next get dirty log call. + */ +unsigned long *host_bmap_track; + +void generate_random_array(uint64_t *guest_array, uint64_t size) +{ + uint64_t i; + + for (i = 0; i < size; i++) { + guest_array[i] = random(); + } +} + +void *vcpu_worker(void *data) +{ + int ret; + uint64_t loops, *guest_array, pages_count = 0; + struct kvm_vm *vm = data; + struct kvm_run *run; + struct guest_args args; + + run = vcpu_state(vm, VCPU_ID); + + /* Retrieve the guest random array pointer and cache it */ + guest_array = addr_gva2hva(vm, (vm_vaddr_t)guest_random_array); + + DEBUG("VCPU starts\n"); + + generate_random_array(guest_array, TEST_PAGES_PER_LOOP); + + while (!READ_ONCE(host_quit)) { + /* Let the guest to dirty these random pages */ + ret = _vcpu_run(vm, VCPU_ID); + guest_args_read(vm, VCPU_ID, &args); + if (run->exit_reason == KVM_EXIT_IO && + args.port == GUEST_PORT_SYNC) { + pages_count += TEST_PAGES_PER_LOOP; + generate_random_array(guest_array, TEST_PAGES_PER_LOOP); + } else { + TEST_ASSERT(false, + "Invalid guest sync status: " + "exit_reason=%s\n", + exit_reason_str(run->exit_reason)); + } + } + + DEBUG("VCPU exits, dirtied %"PRIu64" pages\n", pages_count); + + return NULL; +} + +void vm_dirty_log_verify(unsigned long *bmap, uint64_t iteration) +{ + uint64_t page; + uint64_t volatile *value_ptr; + + for (page = 0; page < TEST_MEM_PAGES; page++) { + value_ptr = host_test_mem + page * getpagesize(); + + /* If this is a special page that we were tracking... */ + if (test_and_clear_bit(page, host_bmap_track)) { + host_track_next_count++; + TEST_ASSERT(test_bit(page, bmap), + "Page %"PRIu64" should have its dirty bit " + "set in this iteration but it is missing", + page); + } + + if (test_bit(page, bmap)) { + host_dirty_count++; + /* + * If the bit is set, the value written onto + * the corresponding page should be either the + * previous iteration number or the current one. + */ + TEST_ASSERT(*value_ptr == iteration || + *value_ptr == iteration - 1, + "Set page %"PRIu64" value %"PRIu64 + " incorrect (iteration=%"PRIu64")", + page, *value_ptr, iteration); + } else { + host_clear_count++; + /* + * If cleared, the value written can be any + * value smaller or equals to the iteration + * number. Note that the value can be exactly + * (iteration-1) if that write can happen + * like this: + * + * (1) increase loop count to "iteration-1" + * (2) write to page P happens (with value + * "iteration-1") + * (3) get dirty log for "iteration-1"; we'll + * see that page P bit is set (dirtied), + * and not set the bit in host_bmap_track + * (4) increase loop count to "iteration" + * (which is current iteration) + * (5) get dirty log for current iteration, + * we'll see that page P is cleared, with + * value "iteration-1". + */ + TEST_ASSERT(*value_ptr <= iteration, + "Clear page %"PRIu64" value %"PRIu64 + " incorrect (iteration=%"PRIu64")", + page, *value_ptr, iteration); + if (*value_ptr == iteration) { + /* + * This page is _just_ modified; it + * should report its dirtyness in the + * next run + */ + set_bit(page, host_bmap_track); + } + } + } +} + +void help(char *name) +{ + puts(""); + printf("usage: %s [-i iterations] [-I interval] [-h]\n", name); + puts(""); + printf(" -i: specify iteration counts (default: %"PRIu64")\n", + TEST_HOST_LOOP_N); + printf(" -I: specify interval in ms (default: %"PRIu64" ms)\n", + TEST_HOST_LOOP_INTERVAL); + puts(""); + exit(0); +} + +int main(int argc, char *argv[]) +{ + pthread_t vcpu_thread; + struct kvm_vm *vm; + uint64_t volatile *psize, *iteration; + unsigned long *bmap, iterations = TEST_HOST_LOOP_N, + interval = TEST_HOST_LOOP_INTERVAL; + int opt; + + while ((opt = getopt(argc, argv, "hi:I:")) != -1) { + switch (opt) { + case 'i': + iterations = strtol(optarg, NULL, 10); + break; + case 'I': + interval = strtol(optarg, NULL, 10); + break; + case 'h': + default: + help(argv[0]); + break; + } + } + + TEST_ASSERT(iterations > 2, "Iteration must be bigger than zero\n"); + TEST_ASSERT(interval > 0, "Interval must be bigger than zero"); + + DEBUG("Test iterations: %"PRIu64", interval: %"PRIu64" (ms)\n", + iterations, interval); + + srandom(time(0)); + + bmap = bitmap_alloc(TEST_MEM_PAGES); + host_bmap_track = bitmap_alloc(TEST_MEM_PAGES); + + vm = vm_create_default(VCPU_ID, TEST_MEM_PAGES, guest_code); + + /* Add an extra memory slot for testing dirty logging */ + vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, + TEST_MEM_OFFSET, + TEST_MEM_SLOT_INDEX, + TEST_MEM_PAGES, + KVM_MEM_LOG_DIRTY_PAGES); + /* Cache the HVA pointer of the region */ + host_test_mem = addr_gpa2hva(vm, (vm_paddr_t)TEST_MEM_OFFSET); + + /* Do 1:1 mapping for the dirty track memory slot */ + virt_map(vm, TEST_MEM_OFFSET, TEST_MEM_OFFSET, + TEST_MEM_PAGES * getpagesize(), 0); + + vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); + + /* Tell the guest about the page size on the system */ + psize = addr_gva2hva(vm, (vm_vaddr_t)&guest_page_size); + *psize = getpagesize(); + + /* Start the iterations */ + iteration = addr_gva2hva(vm, (vm_vaddr_t)&guest_iteration); + *iteration = 1; + + /* Start dirtying pages */ + pthread_create(&vcpu_thread, NULL, vcpu_worker, vm); + + while (*iteration < iterations) { + /* Give the vcpu thread some time to dirty some pages */ + usleep(interval * 1000); + kvm_vm_get_dirty_log(vm, TEST_MEM_SLOT_INDEX, bmap); + vm_dirty_log_verify(bmap, *iteration); + (*iteration)++; + } + + /* Tell the vcpu thread to quit */ + host_quit = true; + pthread_join(vcpu_thread, NULL); + + DEBUG("Total bits checked: dirty (%"PRIu64"), clear (%"PRIu64"), " + "track_next (%"PRIu64")\n", host_dirty_count, host_clear_count, + host_track_next_count); + + free(bmap); + free(host_bmap_track); + kvm_vm_free(vm); + + return 0; +} diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h index 637b7017b6ee..bb5a25fb82c6 100644 --- a/tools/testing/selftests/kvm/include/kvm_util.h +++ b/tools/testing/selftests/kvm/include/kvm_util.h @@ -53,6 +53,9 @@ int kvm_check_cap(long cap); struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm); void kvm_vm_free(struct kvm_vm *vmp); +void kvm_vm_restart(struct kvm_vm *vmp, int perm); +void kvm_vm_release(struct kvm_vm *vmp); +void kvm_vm_get_dirty_log(struct kvm_vm *vm, int slot, void *log); int kvm_memcmp_hva_gva(void *hva, struct kvm_vm *vm, const vm_vaddr_t gva, size_t len); @@ -75,9 +78,11 @@ void vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, unsigned long ioctl, void *arg); void vm_ioctl(struct kvm_vm *vm, unsigned long ioctl, void *arg); void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags); -void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid); +void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid, int pgd_memslot, int gdt_memslot); vm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min, uint32_t data_memslot, uint32_t pgd_memslot); +void virt_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, + size_t size, uint32_t pgd_memslot); void *addr_gpa2hva(struct kvm_vm *vm, vm_paddr_t gpa); void *addr_gva2hva(struct kvm_vm *vm, vm_vaddr_t gva); vm_paddr_t addr_hva2gpa(struct kvm_vm *vm, void *hva); @@ -125,7 +130,8 @@ kvm_get_supported_cpuid_entry(uint32_t function) return kvm_get_supported_cpuid_index(function, 0); } -struct kvm_vm *vm_create_default(uint32_t vcpuid, void *guest_code); +struct kvm_vm *vm_create_default(uint32_t vcpuid, uint64_t extra_mem_size, + void *guest_code); void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code); typedef void (*vmx_guest_code_t)(vm_vaddr_t vmxon_vaddr, @@ -142,4 +148,43 @@ allocate_kvm_dirty_log(struct kvm_userspace_memory_region *region); int vm_create_device(struct kvm_vm *vm, struct kvm_create_device *cd); +#define GUEST_PORT_SYNC 0x1000 +#define GUEST_PORT_ABORT 0x1001 +#define GUEST_PORT_DONE 0x1002 + +static inline void __exit_to_l0(uint16_t port, uint64_t arg0, uint64_t arg1) +{ + __asm__ __volatile__("in %[port], %%al" + : + : [port]"d"(port), "D"(arg0), "S"(arg1) + : "rax"); +} + +/* + * Allows to pass three arguments to the host: port is 16bit wide, + * arg0 & arg1 are 64bit wide + */ +#define GUEST_SYNC_ARGS(_port, _arg0, _arg1) \ + __exit_to_l0(_port, (uint64_t) (_arg0), (uint64_t) (_arg1)) + +#define GUEST_ASSERT(_condition) do { \ + if (!(_condition)) \ + GUEST_SYNC_ARGS(GUEST_PORT_ABORT, \ + "Failed guest assert: " \ + #_condition, __LINE__); \ + } while (0) + +#define GUEST_SYNC(stage) GUEST_SYNC_ARGS(GUEST_PORT_SYNC, "hello", stage) + +#define GUEST_DONE() GUEST_SYNC_ARGS(GUEST_PORT_DONE, 0, 0) + +struct guest_args { + uint64_t arg0; + uint64_t arg1; + uint16_t port; +} __attribute__ ((packed)); + +void guest_args_read(struct kvm_vm *vm, uint32_t vcpu_id, + struct guest_args *args); + #endif /* SELFTEST_KVM_UTIL_H */ diff --git a/tools/testing/selftests/kvm/include/test_util.h b/tools/testing/selftests/kvm/include/test_util.h index ac53730b30aa..73c3933436ec 100644 --- a/tools/testing/selftests/kvm/include/test_util.h +++ b/tools/testing/selftests/kvm/include/test_util.h @@ -28,8 +28,6 @@ int test_seq_read(const char *path, char **bufp, size_t *sizep); void test_assert(bool exp, const char *exp_str, const char *file, unsigned int line, const char *fmt, ...); -#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) - #define TEST_ASSERT(e, fmt, ...) \ test_assert((e), #e, __FILE__, __LINE__, fmt, ##__VA_ARGS__) diff --git a/tools/testing/selftests/kvm/include/vmx.h b/tools/testing/selftests/kvm/include/vmx.h index 6ed8499807fd..b9ffe1024d3a 100644 --- a/tools/testing/selftests/kvm/include/vmx.h +++ b/tools/testing/selftests/kvm/include/vmx.h @@ -380,6 +380,30 @@ static inline int vmptrld(uint64_t vmcs_pa) return ret; } +static inline int vmptrst(uint64_t *value) +{ + uint64_t tmp; + uint8_t ret; + + __asm__ __volatile__("vmptrst %[value]; setna %[ret]" + : [value]"=m"(tmp), [ret]"=rm"(ret) + : : "cc", "memory"); + + *value = tmp; + return ret; +} + +/* + * A wrapper around vmptrst that ignores errors and returns zero if the + * vmptrst instruction fails. + */ +static inline uint64_t vmptrstz(void) +{ + uint64_t value = 0; + vmptrst(&value); + return value; +} + /* * No guest state (e.g. GPRs) is established by this vmlaunch. */ @@ -444,6 +468,15 @@ static inline int vmresume(void) return ret; } +static inline void vmcall(void) +{ + /* Currently, L1 destroys our GPRs during vmexits. */ + __asm__ __volatile__("push %%rbp; vmcall; pop %%rbp" : : : + "rax", "rbx", "rcx", "rdx", + "rsi", "rdi", "r8", "r9", "r10", "r11", "r12", + "r13", "r14", "r15"); +} + static inline int vmread(uint64_t encoding, uint64_t *value) { uint64_t tmp; @@ -486,9 +519,34 @@ static inline uint32_t vmcs_revision(void) return rdmsr(MSR_IA32_VMX_BASIC); } -void prepare_for_vmx_operation(void); -void prepare_vmcs(void *guest_rip, void *guest_rsp); -struct kvm_vm *vm_create_default_vmx(uint32_t vcpuid, - vmx_guest_code_t guest_code); +struct vmx_pages { + void *vmxon_hva; + uint64_t vmxon_gpa; + void *vmxon; + + void *vmcs_hva; + uint64_t vmcs_gpa; + void *vmcs; + + void *msr_hva; + uint64_t msr_gpa; + void *msr; + + void *shadow_vmcs_hva; + uint64_t shadow_vmcs_gpa; + void *shadow_vmcs; + + void *vmread_hva; + uint64_t vmread_gpa; + void *vmread; + + void *vmwrite_hva; + uint64_t vmwrite_gpa; + void *vmwrite; +}; + +struct vmx_pages *vcpu_alloc_vmx(struct kvm_vm *vm, vm_vaddr_t *p_vmx_gva); +bool prepare_for_vmx_operation(struct vmx_pages *vmx); +void prepare_vmcs(struct vmx_pages *vmx, void *guest_rip, void *guest_rsp); #endif /* !SELFTEST_KVM_VMX_H */ diff --git a/tools/testing/selftests/kvm/include/x86.h b/tools/testing/selftests/kvm/include/x86.h index 4a5b2c4c1a0f..42c3596815b8 100644 --- a/tools/testing/selftests/kvm/include/x86.h +++ b/tools/testing/selftests/kvm/include/x86.h @@ -59,8 +59,8 @@ enum x86_register { struct desc64 { uint16_t limit0; uint16_t base0; - unsigned base1:8, type:5, dpl:2, p:1; - unsigned limit1:4, zero0:3, g:1, base2:8; + unsigned base1:8, s:1, type:4, dpl:2, p:1; + unsigned limit1:4, avl:1, l:1, db:1, g:1, base2:8; uint32_t base3; uint32_t zero1; } __attribute__((packed)); @@ -303,6 +303,10 @@ static inline unsigned long get_xmm(int n) return 0; } +struct kvm_x86_state; +struct kvm_x86_state *vcpu_save_state(struct kvm_vm *vm, uint32_t vcpuid); +void vcpu_load_state(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_x86_state *state); + /* * Basic CPU control in CR0 */ diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 37e2a787d2fc..e9ba389c48db 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -14,6 +14,7 @@ #include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> +#include <linux/kernel.h> #define KVM_DEV_PATH "/dev/kvm" @@ -62,6 +63,18 @@ int kvm_check_cap(long cap) return ret; } +static void vm_open(struct kvm_vm *vm, int perm) +{ + vm->kvm_fd = open(KVM_DEV_PATH, perm); + if (vm->kvm_fd < 0) + exit(KSFT_SKIP); + + /* Create VM. */ + vm->fd = ioctl(vm->kvm_fd, KVM_CREATE_VM, NULL); + TEST_ASSERT(vm->fd >= 0, "KVM_CREATE_VM ioctl failed, " + "rc: %i errno: %i", vm->fd, errno); +} + /* VM Create * * Input Args: @@ -90,16 +103,7 @@ struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm) TEST_ASSERT(vm != NULL, "Insufficent Memory"); vm->mode = mode; - kvm_fd = open(KVM_DEV_PATH, perm); - if (kvm_fd < 0) - exit(KSFT_SKIP); - - /* Create VM. */ - vm->fd = ioctl(kvm_fd, KVM_CREATE_VM, NULL); - TEST_ASSERT(vm->fd >= 0, "KVM_CREATE_VM ioctl failed, " - "rc: %i errno: %i", vm->fd, errno); - - close(kvm_fd); + vm_open(vm, perm); /* Setup mode specific traits. */ switch (vm->mode) { @@ -132,6 +136,49 @@ struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm) return vm; } +/* VM Restart + * + * Input Args: + * vm - VM that has been released before + * perm - permission + * + * Output Args: None + * + * Reopens the file descriptors associated to the VM and reinstates the + * global state, such as the irqchip and the memory regions that are mapped + * into the guest. + */ +void kvm_vm_restart(struct kvm_vm *vmp, int perm) +{ + struct userspace_mem_region *region; + + vm_open(vmp, perm); + if (vmp->has_irqchip) + vm_create_irqchip(vmp); + + for (region = vmp->userspace_mem_region_head; region; + region = region->next) { + int ret = ioctl(vmp->fd, KVM_SET_USER_MEMORY_REGION, ®ion->region); + TEST_ASSERT(ret == 0, "KVM_SET_USER_MEMORY_REGION IOCTL failed,\n" + " rc: %i errno: %i\n" + " slot: %u flags: 0x%x\n" + " guest_phys_addr: 0x%lx size: 0x%lx", + ret, errno, region->region.slot, region->region.flags, + region->region.guest_phys_addr, + region->region.memory_size); + } +} + +void kvm_vm_get_dirty_log(struct kvm_vm *vm, int slot, void *log) +{ + struct kvm_dirty_log args = { .dirty_bitmap = log, .slot = slot }; + int ret; + + ret = ioctl(vm->fd, KVM_GET_DIRTY_LOG, &args); + TEST_ASSERT(ret == 0, "%s: KVM_GET_DIRTY_LOG failed: %s", + strerror(-ret)); +} + /* Userspace Memory Region Find * * Input Args: @@ -238,8 +285,12 @@ struct vcpu *vcpu_find(struct kvm_vm *vm, static void vm_vcpu_rm(struct kvm_vm *vm, uint32_t vcpuid) { struct vcpu *vcpu = vcpu_find(vm, vcpuid); + int ret; - int ret = close(vcpu->fd); + ret = munmap(vcpu->state, sizeof(*vcpu->state)); + TEST_ASSERT(ret == 0, "munmap of VCPU fd failed, rc: %i " + "errno: %i", ret, errno); + close(vcpu->fd); TEST_ASSERT(ret == 0, "Close of VCPU fd failed, rc: %i " "errno: %i", ret, errno); @@ -252,6 +303,23 @@ static void vm_vcpu_rm(struct kvm_vm *vm, uint32_t vcpuid) free(vcpu); } +void kvm_vm_release(struct kvm_vm *vmp) +{ + int ret; + + /* Free VCPUs. */ + while (vmp->vcpu_head) + vm_vcpu_rm(vmp, vmp->vcpu_head->id); + + /* Close file descriptor for the VM. */ + ret = close(vmp->fd); + TEST_ASSERT(ret == 0, "Close of vm fd failed,\n" + " vmp->fd: %i rc: %i errno: %i", vmp->fd, ret, errno); + + close(vmp->kvm_fd); + TEST_ASSERT(ret == 0, "Close of /dev/kvm fd failed,\n" + " vmp->kvm_fd: %i rc: %i errno: %i", vmp->kvm_fd, ret, errno); +} /* Destroys and frees the VM pointed to by vmp. */ @@ -282,18 +350,11 @@ void kvm_vm_free(struct kvm_vm *vmp) free(region); } - /* Free VCPUs. */ - while (vmp->vcpu_head) - vm_vcpu_rm(vmp, vmp->vcpu_head->id); - /* Free sparsebit arrays. */ sparsebit_free(&vmp->vpages_valid); sparsebit_free(&vmp->vpages_mapped); - /* Close file descriptor for the VM. */ - ret = close(vmp->fd); - TEST_ASSERT(ret == 0, "Close of vm fd failed,\n" - " vmp->fd: %i rc: %i errno: %i", vmp->fd, ret, errno); + kvm_vm_release(vmp); /* Free the structure describing the VM. */ free(vmp); @@ -701,7 +762,7 @@ static int vcpu_mmap_sz(void) * Creates and adds to the VM specified by vm and virtual CPU with * the ID given by vcpuid. */ -void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid) +void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid, int pgd_memslot, int gdt_memslot) { struct vcpu *vcpu; @@ -736,7 +797,7 @@ void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid) vcpu->next = vm->vcpu_head; vm->vcpu_head = vcpu; - vcpu_setup(vm, vcpuid); + vcpu_setup(vm, vcpuid, pgd_memslot, gdt_memslot); } /* VM Virtual Address Unused Gap @@ -873,6 +934,39 @@ vm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min, return vaddr_start; } +/* + * Map a range of VM virtual address to the VM's physical address + * + * Input Args: + * vm - Virtual Machine + * vaddr - Virtuall address to map + * paddr - VM Physical Address + * size - The size of the range to map + * pgd_memslot - Memory region slot for new virtual translation tables + * + * Output Args: None + * + * Return: None + * + * Within the VM given by vm, creates a virtual translation for the + * page range starting at vaddr to the page range starting at paddr. + */ +void virt_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, + size_t size, uint32_t pgd_memslot) +{ + size_t page_size = vm->page_size; + size_t npages = size / page_size; + + TEST_ASSERT(vaddr + size > vaddr, "Vaddr overflow"); + TEST_ASSERT(paddr + size > paddr, "Paddr overflow"); + + while (npages--) { + virt_pg_map(vm, vaddr, paddr, pgd_memslot); + vaddr += page_size; + paddr += page_size; + } +} + /* Address VM Physical to Host Virtual * * Input Args: @@ -957,6 +1051,8 @@ void vm_create_irqchip(struct kvm_vm *vm) ret = ioctl(vm->fd, KVM_CREATE_IRQCHIP, 0); TEST_ASSERT(ret == 0, "KVM_CREATE_IRQCHIP IOCTL failed, " "rc: %i errno: %i", ret, errno); + + vm->has_irqchip = true; } /* VM VCPU State @@ -1484,3 +1580,17 @@ void *addr_gva2hva(struct kvm_vm *vm, vm_vaddr_t gva) { return addr_gpa2hva(vm, addr_gva2gpa(vm, gva)); } + +void guest_args_read(struct kvm_vm *vm, uint32_t vcpu_id, + struct guest_args *args) +{ + struct kvm_run *run = vcpu_state(vm, vcpu_id); + struct kvm_regs regs; + + memset(®s, 0, sizeof(regs)); + vcpu_regs_get(vm, vcpu_id, ®s); + + args->port = run->io.port; + args->arg0 = regs.rdi; + args->arg1 = regs.rsi; +} diff --git a/tools/testing/selftests/kvm/lib/kvm_util_internal.h b/tools/testing/selftests/kvm/lib/kvm_util_internal.h index a0bd1980c81c..542ed606b338 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util_internal.h +++ b/tools/testing/selftests/kvm/lib/kvm_util_internal.h @@ -43,6 +43,7 @@ struct vcpu { struct kvm_vm { int mode; + int kvm_fd; int fd; unsigned int page_size; unsigned int page_shift; @@ -51,13 +52,17 @@ struct kvm_vm { struct userspace_mem_region *userspace_mem_region_head; struct sparsebit *vpages_valid; struct sparsebit *vpages_mapped; + + bool has_irqchip; bool pgd_created; vm_paddr_t pgd; + vm_vaddr_t gdt; + vm_vaddr_t tss; }; struct vcpu *vcpu_find(struct kvm_vm *vm, uint32_t vcpuid); -void vcpu_setup(struct kvm_vm *vm, int vcpuid); +void vcpu_setup(struct kvm_vm *vm, int vcpuid, int pgd_memslot, int gdt_memslot); void virt_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent); void regs_dump(FILE *stream, struct kvm_regs *regs, uint8_t indent); diff --git a/tools/testing/selftests/kvm/lib/vmx.c b/tools/testing/selftests/kvm/lib/vmx.c index 0231bc0aae7b..b987c3c970eb 100644 --- a/tools/testing/selftests/kvm/lib/vmx.c +++ b/tools/testing/selftests/kvm/lib/vmx.c @@ -13,47 +13,60 @@ #include "x86.h" #include "vmx.h" -/* Create a default VM for VMX tests. +/* Allocate memory regions for nested VMX tests. * * Input Args: - * vcpuid - The id of the single VCPU to add to the VM. - * guest_code - The vCPU's entry point + * vm - The VM to allocate guest-virtual addresses in. * - * Output Args: None + * Output Args: + * p_vmx_gva - The guest virtual address for the struct vmx_pages. * * Return: - * Pointer to opaque structure that describes the created VM. + * Pointer to structure with the addresses of the VMX areas. */ -struct kvm_vm * -vm_create_default_vmx(uint32_t vcpuid, vmx_guest_code_t guest_code) +struct vmx_pages * +vcpu_alloc_vmx(struct kvm_vm *vm, vm_vaddr_t *p_vmx_gva) { - struct kvm_cpuid2 *cpuid; - struct kvm_vm *vm; - vm_vaddr_t vmxon_vaddr; - vm_paddr_t vmxon_paddr; - vm_vaddr_t vmcs_vaddr; - vm_paddr_t vmcs_paddr; - - vm = vm_create_default(vcpuid, (void *) guest_code); - - /* Enable nesting in CPUID */ - vcpu_set_cpuid(vm, vcpuid, kvm_get_supported_cpuid()); + vm_vaddr_t vmx_gva = vm_vaddr_alloc(vm, getpagesize(), 0x10000, 0, 0); + struct vmx_pages *vmx = addr_gva2hva(vm, vmx_gva); /* Setup of a region of guest memory for the vmxon region. */ - vmxon_vaddr = vm_vaddr_alloc(vm, getpagesize(), 0, 0, 0); - vmxon_paddr = addr_gva2gpa(vm, vmxon_vaddr); + vmx->vmxon = (void *)vm_vaddr_alloc(vm, getpagesize(), 0x10000, 0, 0); + vmx->vmxon_hva = addr_gva2hva(vm, (uintptr_t)vmx->vmxon); + vmx->vmxon_gpa = addr_gva2gpa(vm, (uintptr_t)vmx->vmxon); /* Setup of a region of guest memory for a vmcs. */ - vmcs_vaddr = vm_vaddr_alloc(vm, getpagesize(), 0, 0, 0); - vmcs_paddr = addr_gva2gpa(vm, vmcs_vaddr); + vmx->vmcs = (void *)vm_vaddr_alloc(vm, getpagesize(), 0x10000, 0, 0); + vmx->vmcs_hva = addr_gva2hva(vm, (uintptr_t)vmx->vmcs); + vmx->vmcs_gpa = addr_gva2gpa(vm, (uintptr_t)vmx->vmcs); + + /* Setup of a region of guest memory for the MSR bitmap. */ + vmx->msr = (void *)vm_vaddr_alloc(vm, getpagesize(), 0x10000, 0, 0); + vmx->msr_hva = addr_gva2hva(vm, (uintptr_t)vmx->msr); + vmx->msr_gpa = addr_gva2gpa(vm, (uintptr_t)vmx->msr); + memset(vmx->msr_hva, 0, getpagesize()); - vcpu_args_set(vm, vcpuid, 4, vmxon_vaddr, vmxon_paddr, vmcs_vaddr, - vmcs_paddr); + /* Setup of a region of guest memory for the shadow VMCS. */ + vmx->shadow_vmcs = (void *)vm_vaddr_alloc(vm, getpagesize(), 0x10000, 0, 0); + vmx->shadow_vmcs_hva = addr_gva2hva(vm, (uintptr_t)vmx->shadow_vmcs); + vmx->shadow_vmcs_gpa = addr_gva2gpa(vm, (uintptr_t)vmx->shadow_vmcs); - return vm; + /* Setup of a region of guest memory for the VMREAD and VMWRITE bitmaps. */ + vmx->vmread = (void *)vm_vaddr_alloc(vm, getpagesize(), 0x10000, 0, 0); + vmx->vmread_hva = addr_gva2hva(vm, (uintptr_t)vmx->vmread); + vmx->vmread_gpa = addr_gva2gpa(vm, (uintptr_t)vmx->vmread); + memset(vmx->vmread_hva, 0, getpagesize()); + + vmx->vmwrite = (void *)vm_vaddr_alloc(vm, getpagesize(), 0x10000, 0, 0); + vmx->vmwrite_hva = addr_gva2hva(vm, (uintptr_t)vmx->vmwrite); + vmx->vmwrite_gpa = addr_gva2gpa(vm, (uintptr_t)vmx->vmwrite); + memset(vmx->vmwrite_hva, 0, getpagesize()); + + *p_vmx_gva = vmx_gva; + return vmx; } -void prepare_for_vmx_operation(void) +bool prepare_for_vmx_operation(struct vmx_pages *vmx) { uint64_t feature_control; uint64_t required; @@ -88,18 +101,42 @@ void prepare_for_vmx_operation(void) feature_control = rdmsr(MSR_IA32_FEATURE_CONTROL); if ((feature_control & required) != required) wrmsr(MSR_IA32_FEATURE_CONTROL, feature_control | required); + + /* Enter VMX root operation. */ + *(uint32_t *)(vmx->vmxon) = vmcs_revision(); + if (vmxon(vmx->vmxon_gpa)) + return false; + + /* Load a VMCS. */ + *(uint32_t *)(vmx->vmcs) = vmcs_revision(); + if (vmclear(vmx->vmcs_gpa)) + return false; + + if (vmptrld(vmx->vmcs_gpa)) + return false; + + /* Setup shadow VMCS, do not load it yet. */ + *(uint32_t *)(vmx->shadow_vmcs) = vmcs_revision() | 0x80000000ul; + if (vmclear(vmx->shadow_vmcs_gpa)) + return false; + + return true; } /* * Initialize the control fields to the most basic settings possible. */ -static inline void init_vmcs_control_fields(void) +static inline void init_vmcs_control_fields(struct vmx_pages *vmx) { vmwrite(VIRTUAL_PROCESSOR_ID, 0); vmwrite(POSTED_INTR_NV, 0); - vmwrite(PIN_BASED_VM_EXEC_CONTROL, rdmsr(MSR_IA32_VMX_PINBASED_CTLS)); - vmwrite(CPU_BASED_VM_EXEC_CONTROL, rdmsr(MSR_IA32_VMX_PROCBASED_CTLS)); + vmwrite(PIN_BASED_VM_EXEC_CONTROL, rdmsr(MSR_IA32_VMX_TRUE_PINBASED_CTLS)); + if (!vmwrite(SECONDARY_VM_EXEC_CONTROL, 0)) + vmwrite(CPU_BASED_VM_EXEC_CONTROL, + rdmsr(MSR_IA32_VMX_TRUE_PROCBASED_CTLS) | CPU_BASED_ACTIVATE_SECONDARY_CONTROLS); + else + vmwrite(CPU_BASED_VM_EXEC_CONTROL, rdmsr(MSR_IA32_VMX_TRUE_PROCBASED_CTLS)); vmwrite(EXCEPTION_BITMAP, 0); vmwrite(PAGE_FAULT_ERROR_CODE_MASK, 0); vmwrite(PAGE_FAULT_ERROR_CODE_MATCH, -1); /* Never match */ @@ -113,12 +150,15 @@ static inline void init_vmcs_control_fields(void) vmwrite(VM_ENTRY_MSR_LOAD_COUNT, 0); vmwrite(VM_ENTRY_INTR_INFO_FIELD, 0); vmwrite(TPR_THRESHOLD, 0); - vmwrite(SECONDARY_VM_EXEC_CONTROL, 0); vmwrite(CR0_GUEST_HOST_MASK, 0); vmwrite(CR4_GUEST_HOST_MASK, 0); vmwrite(CR0_READ_SHADOW, get_cr0()); vmwrite(CR4_READ_SHADOW, get_cr4()); + + vmwrite(MSR_BITMAP, vmx->msr_gpa); + vmwrite(VMREAD_BITMAP, vmx->vmread_gpa); + vmwrite(VMWRITE_BITMAP, vmx->vmwrite_gpa); } /* @@ -235,9 +275,9 @@ static inline void init_vmcs_guest_state(void *rip, void *rsp) vmwrite(GUEST_SYSENTER_EIP, vmreadz(HOST_IA32_SYSENTER_EIP)); } -void prepare_vmcs(void *guest_rip, void *guest_rsp) +void prepare_vmcs(struct vmx_pages *vmx, void *guest_rip, void *guest_rsp) { - init_vmcs_control_fields(); + init_vmcs_control_fields(vmx); init_vmcs_host_state(); init_vmcs_guest_state(guest_rip, guest_rsp); } diff --git a/tools/testing/selftests/kvm/lib/x86.c b/tools/testing/selftests/kvm/lib/x86.c index 2f17675f4275..a3122f1949a8 100644 --- a/tools/testing/selftests/kvm/lib/x86.c +++ b/tools/testing/selftests/kvm/lib/x86.c @@ -239,25 +239,6 @@ void virt_pgd_alloc(struct kvm_vm *vm, uint32_t pgd_memslot) vm_paddr_t paddr = vm_phy_page_alloc(vm, KVM_GUEST_PAGE_TABLE_MIN_PADDR, pgd_memslot); vm->pgd = paddr; - - /* Set pointer to pgd tables in all the VCPUs that - * have already been created. Future VCPUs will have - * the value set as each one is created. - */ - for (struct vcpu *vcpu = vm->vcpu_head; vcpu; - vcpu = vcpu->next) { - struct kvm_sregs sregs; - - /* Obtain the current system register settings */ - vcpu_sregs_get(vm, vcpu->id, &sregs); - - /* Set and store the pointer to the start of the - * pgd tables. - */ - sregs.cr3 = vm->pgd; - vcpu_sregs_set(vm, vcpu->id, &sregs); - } - vm->pgd_created = true; } } @@ -460,9 +441,32 @@ static void kvm_seg_set_unusable(struct kvm_segment *segp) segp->unusable = true; } +static void kvm_seg_fill_gdt_64bit(struct kvm_vm *vm, struct kvm_segment *segp) +{ + void *gdt = addr_gva2hva(vm, vm->gdt); + struct desc64 *desc = gdt + (segp->selector >> 3) * 8; + + desc->limit0 = segp->limit & 0xFFFF; + desc->base0 = segp->base & 0xFFFF; + desc->base1 = segp->base >> 16; + desc->s = segp->s; + desc->type = segp->type; + desc->dpl = segp->dpl; + desc->p = segp->present; + desc->limit1 = segp->limit >> 16; + desc->l = segp->l; + desc->db = segp->db; + desc->g = segp->g; + desc->base2 = segp->base >> 24; + if (!segp->s) + desc->base3 = segp->base >> 32; +} + + /* Set Long Mode Flat Kernel Code Segment * * Input Args: + * vm - VM whose GDT is being filled, or NULL to only write segp * selector - selector value * * Output Args: @@ -473,7 +477,7 @@ static void kvm_seg_set_unusable(struct kvm_segment *segp) * Sets up the KVM segment pointed to by segp, to be a code segment * with the selector value given by selector. */ -static void kvm_seg_set_kernel_code_64bit(uint16_t selector, +static void kvm_seg_set_kernel_code_64bit(struct kvm_vm *vm, uint16_t selector, struct kvm_segment *segp) { memset(segp, 0, sizeof(*segp)); @@ -486,11 +490,14 @@ static void kvm_seg_set_kernel_code_64bit(uint16_t selector, segp->g = true; segp->l = true; segp->present = 1; + if (vm) + kvm_seg_fill_gdt_64bit(vm, segp); } /* Set Long Mode Flat Kernel Data Segment * * Input Args: + * vm - VM whose GDT is being filled, or NULL to only write segp * selector - selector value * * Output Args: @@ -501,7 +508,7 @@ static void kvm_seg_set_kernel_code_64bit(uint16_t selector, * Sets up the KVM segment pointed to by segp, to be a data segment * with the selector value given by selector. */ -static void kvm_seg_set_kernel_data_64bit(uint16_t selector, +static void kvm_seg_set_kernel_data_64bit(struct kvm_vm *vm, uint16_t selector, struct kvm_segment *segp) { memset(segp, 0, sizeof(*segp)); @@ -513,6 +520,8 @@ static void kvm_seg_set_kernel_data_64bit(uint16_t selector, */ segp->g = true; segp->present = true; + if (vm) + kvm_seg_fill_gdt_64bit(vm, segp); } /* Address Guest Virtual to Guest Physical @@ -575,13 +584,45 @@ unmapped_gva: "gva: 0x%lx", gva); } -void vcpu_setup(struct kvm_vm *vm, int vcpuid) +static void kvm_setup_gdt(struct kvm_vm *vm, struct kvm_dtable *dt, int gdt_memslot, + int pgd_memslot) +{ + if (!vm->gdt) + vm->gdt = vm_vaddr_alloc(vm, getpagesize(), + KVM_UTIL_MIN_VADDR, gdt_memslot, pgd_memslot); + + dt->base = vm->gdt; + dt->limit = getpagesize(); +} + +static void kvm_setup_tss_64bit(struct kvm_vm *vm, struct kvm_segment *segp, + int selector, int gdt_memslot, + int pgd_memslot) +{ + if (!vm->tss) + vm->tss = vm_vaddr_alloc(vm, getpagesize(), + KVM_UTIL_MIN_VADDR, gdt_memslot, pgd_memslot); + + memset(segp, 0, sizeof(*segp)); + segp->base = vm->tss; + segp->limit = 0x67; + segp->selector = selector; + segp->type = 0xb; + segp->present = 1; + kvm_seg_fill_gdt_64bit(vm, segp); +} + +void vcpu_setup(struct kvm_vm *vm, int vcpuid, int pgd_memslot, int gdt_memslot) { struct kvm_sregs sregs; /* Set mode specific system register values. */ vcpu_sregs_get(vm, vcpuid, &sregs); + sregs.idt.limit = 0; + + kvm_setup_gdt(vm, &sregs.gdt, gdt_memslot, pgd_memslot); + switch (vm->mode) { case VM_MODE_FLAT48PG: sregs.cr0 = X86_CR0_PE | X86_CR0_NE | X86_CR0_PG; @@ -589,30 +630,18 @@ void vcpu_setup(struct kvm_vm *vm, int vcpuid) sregs.efer |= (EFER_LME | EFER_LMA | EFER_NX); kvm_seg_set_unusable(&sregs.ldt); - kvm_seg_set_kernel_code_64bit(0x8, &sregs.cs); - kvm_seg_set_kernel_data_64bit(0x10, &sregs.ds); - kvm_seg_set_kernel_data_64bit(0x10, &sregs.es); + kvm_seg_set_kernel_code_64bit(vm, 0x8, &sregs.cs); + kvm_seg_set_kernel_data_64bit(vm, 0x10, &sregs.ds); + kvm_seg_set_kernel_data_64bit(vm, 0x10, &sregs.es); + kvm_setup_tss_64bit(vm, &sregs.tr, 0x18, gdt_memslot, pgd_memslot); break; default: TEST_ASSERT(false, "Unknown guest mode, mode: 0x%x", vm->mode); } - vcpu_sregs_set(vm, vcpuid, &sregs); - - /* If virtual translation table have been setup, set system register - * to point to the tables. It's okay if they haven't been setup yet, - * in that the code that sets up the virtual translation tables, will - * go back through any VCPUs that have already been created and set - * their values. - */ - if (vm->pgd_created) { - struct kvm_sregs sregs; - - vcpu_sregs_get(vm, vcpuid, &sregs); - sregs.cr3 = vm->pgd; - vcpu_sregs_set(vm, vcpuid, &sregs); - } + sregs.cr3 = vm->pgd; + vcpu_sregs_set(vm, vcpuid, &sregs); } /* Adds a vCPU with reasonable defaults (i.e., a stack) * @@ -629,7 +658,7 @@ void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code) DEFAULT_GUEST_STACK_VADDR_MIN, 0, 0); /* Create VCPU */ - vm_vcpu_add(vm, vcpuid); + vm_vcpu_add(vm, vcpuid, 0, 0); /* Setup guest general purpose registers */ vcpu_regs_get(vm, vcpuid, ®s); @@ -673,6 +702,9 @@ void vcpu_set_cpuid(struct kvm_vm *vm, * * Input Args: * vcpuid - The id of the single VCPU to add to the VM. + * extra_mem_pages - The size of extra memories to add (this will + * decide how much extra space we will need to + * setup the page tables using mem slot 0) * guest_code - The vCPU's entry point * * Output Args: None @@ -680,12 +712,23 @@ void vcpu_set_cpuid(struct kvm_vm *vm, * Return: * Pointer to opaque structure that describes the created VM. */ -struct kvm_vm *vm_create_default(uint32_t vcpuid, void *guest_code) +struct kvm_vm *vm_create_default(uint32_t vcpuid, uint64_t extra_mem_pages, + void *guest_code) { struct kvm_vm *vm; + /* + * For x86 the maximum page table size for a memory region + * will be when only 4K pages are used. In that case the + * total extra size for page tables (for extra N pages) will + * be: N/512+N/512^2+N/512^3+... which is definitely smaller + * than N/512*2. + */ + uint64_t extra_pg_pages = extra_mem_pages / 512 * 2; /* Create VM */ - vm = vm_create(VM_MODE_FLAT48PG, DEFAULT_GUEST_PHY_PAGES, O_RDWR); + vm = vm_create(VM_MODE_FLAT48PG, + DEFAULT_GUEST_PHY_PAGES + extra_pg_pages, + O_RDWR); /* Setup guest code */ kvm_vm_elf_load(vm, program_invocation_name, 0, 0); @@ -698,3 +741,148 @@ struct kvm_vm *vm_create_default(uint32_t vcpuid, void *guest_code) return vm; } + +struct kvm_x86_state { + struct kvm_vcpu_events events; + struct kvm_mp_state mp_state; + struct kvm_regs regs; + struct kvm_xsave xsave; + struct kvm_xcrs xcrs; + struct kvm_sregs sregs; + struct kvm_debugregs debugregs; + union { + struct kvm_nested_state nested; + char nested_[16384]; + }; + struct kvm_msrs msrs; +}; + +static int kvm_get_num_msrs(struct kvm_vm *vm) +{ + struct kvm_msr_list nmsrs; + int r; + + nmsrs.nmsrs = 0; + r = ioctl(vm->kvm_fd, KVM_GET_MSR_INDEX_LIST, &nmsrs); + TEST_ASSERT(r == -1 && errno == E2BIG, "Unexpected result from KVM_GET_MSR_INDEX_LIST probe, r: %i", + r); + + return nmsrs.nmsrs; +} + +struct kvm_x86_state *vcpu_save_state(struct kvm_vm *vm, uint32_t vcpuid) +{ + struct vcpu *vcpu = vcpu_find(vm, vcpuid); + struct kvm_msr_list *list; + struct kvm_x86_state *state; + int nmsrs, r, i; + static int nested_size = -1; + + if (nested_size == -1) { + nested_size = kvm_check_cap(KVM_CAP_NESTED_STATE); + TEST_ASSERT(nested_size <= sizeof(state->nested_), + "Nested state size too big, %i > %zi", + nested_size, sizeof(state->nested_)); + } + + nmsrs = kvm_get_num_msrs(vm); + list = malloc(sizeof(*list) + nmsrs * sizeof(list->indices[0])); + list->nmsrs = nmsrs; + r = ioctl(vm->kvm_fd, KVM_GET_MSR_INDEX_LIST, list); + TEST_ASSERT(r == 0, "Unexpected result from KVM_GET_MSR_INDEX_LIST, r: %i", + r); + + state = malloc(sizeof(*state) + nmsrs * sizeof(state->msrs.entries[0])); + r = ioctl(vcpu->fd, KVM_GET_VCPU_EVENTS, &state->events); + TEST_ASSERT(r == 0, "Unexpected result from KVM_GET_VCPU_EVENTS, r: %i", + r); + + r = ioctl(vcpu->fd, KVM_GET_MP_STATE, &state->mp_state); + TEST_ASSERT(r == 0, "Unexpected result from KVM_GET_MP_STATE, r: %i", + r); + + r = ioctl(vcpu->fd, KVM_GET_REGS, &state->regs); + TEST_ASSERT(r == 0, "Unexpected result from KVM_GET_REGS, r: %i", + r); + + r = ioctl(vcpu->fd, KVM_GET_XSAVE, &state->xsave); + TEST_ASSERT(r == 0, "Unexpected result from KVM_GET_XSAVE, r: %i", + r); + + r = ioctl(vcpu->fd, KVM_GET_XCRS, &state->xcrs); + TEST_ASSERT(r == 0, "Unexpected result from KVM_GET_XCRS, r: %i", + r); + + r = ioctl(vcpu->fd, KVM_GET_SREGS, &state->sregs); + TEST_ASSERT(r == 0, "Unexpected result from KVM_GET_SREGS, r: %i", + r); + + if (nested_size) { + state->nested.size = sizeof(state->nested_); + r = ioctl(vcpu->fd, KVM_GET_NESTED_STATE, &state->nested); + TEST_ASSERT(r == 0, "Unexpected result from KVM_GET_NESTED_STATE, r: %i", + r); + TEST_ASSERT(state->nested.size <= nested_size, + "Nested state size too big, %i (KVM_CHECK_CAP gave %i)", + state->nested.size, nested_size); + } else + state->nested.size = 0; + + state->msrs.nmsrs = nmsrs; + for (i = 0; i < nmsrs; i++) + state->msrs.entries[i].index = list->indices[i]; + r = ioctl(vcpu->fd, KVM_GET_MSRS, &state->msrs); + TEST_ASSERT(r == nmsrs, "Unexpected result from KVM_GET_MSRS, r: %i (failed at %x)", + r, r == nmsrs ? -1 : list->indices[r]); + + r = ioctl(vcpu->fd, KVM_GET_DEBUGREGS, &state->debugregs); + TEST_ASSERT(r == 0, "Unexpected result from KVM_GET_DEBUGREGS, r: %i", + r); + + free(list); + return state; +} + +void vcpu_load_state(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_x86_state *state) +{ + struct vcpu *vcpu = vcpu_find(vm, vcpuid); + int r; + + if (state->nested.size) { + r = ioctl(vcpu->fd, KVM_SET_NESTED_STATE, &state->nested); + TEST_ASSERT(r == 0, "Unexpected result from KVM_SET_NESTED_STATE, r: %i", + r); + } + + r = ioctl(vcpu->fd, KVM_SET_XSAVE, &state->xsave); + TEST_ASSERT(r == 0, "Unexpected result from KVM_SET_XSAVE, r: %i", + r); + + r = ioctl(vcpu->fd, KVM_SET_XCRS, &state->xcrs); + TEST_ASSERT(r == 0, "Unexpected result from KVM_SET_XCRS, r: %i", + r); + + r = ioctl(vcpu->fd, KVM_SET_SREGS, &state->sregs); + TEST_ASSERT(r == 0, "Unexpected result from KVM_SET_SREGS, r: %i", + r); + + r = ioctl(vcpu->fd, KVM_SET_MSRS, &state->msrs); + TEST_ASSERT(r == state->msrs.nmsrs, "Unexpected result from KVM_SET_MSRS, r: %i (failed at %x)", + r, r == state->msrs.nmsrs ? -1 : state->msrs.entries[r].index); + + r = ioctl(vcpu->fd, KVM_SET_VCPU_EVENTS, &state->events); + TEST_ASSERT(r == 0, "Unexpected result from KVM_SET_VCPU_EVENTS, r: %i", + r); + + r = ioctl(vcpu->fd, KVM_SET_MP_STATE, &state->mp_state); + TEST_ASSERT(r == 0, "Unexpected result from KVM_SET_MP_STATE, r: %i", + r); + + r = ioctl(vcpu->fd, KVM_SET_DEBUGREGS, &state->debugregs); + TEST_ASSERT(r == 0, "Unexpected result from KVM_SET_DEBUGREGS, r: %i", + r); + + r = ioctl(vcpu->fd, KVM_SET_REGS, &state->regs); + TEST_ASSERT(r == 0, "Unexpected result from KVM_SET_REGS, r: %i", + r); +} diff --git a/tools/testing/selftests/kvm/set_sregs_test.c b/tools/testing/selftests/kvm/set_sregs_test.c index 090fd3f19352..881419d5746e 100644 --- a/tools/testing/selftests/kvm/set_sregs_test.c +++ b/tools/testing/selftests/kvm/set_sregs_test.c @@ -36,7 +36,7 @@ int main(int argc, char *argv[]) setbuf(stdout, NULL); /* Create VM */ - vm = vm_create_default(VCPU_ID, NULL); + vm = vm_create_default(VCPU_ID, 0, NULL); vcpu_sregs_get(vm, VCPU_ID, &sregs); sregs.apic_base = 1 << 10; diff --git a/tools/testing/selftests/kvm/state_test.c b/tools/testing/selftests/kvm/state_test.c new file mode 100644 index 000000000000..900e3e9dfb9f --- /dev/null +++ b/tools/testing/selftests/kvm/state_test.c @@ -0,0 +1,196 @@ +/* + * KVM_GET/SET_* tests + * + * Copyright (C) 2018, Red Hat, Inc. + * + * This work is licensed under the terms of the GNU GPL, version 2. + * + * Tests for vCPU state save/restore, including nested guest state. + */ +#define _GNU_SOURCE /* for program_invocation_short_name */ +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> + +#include "test_util.h" + +#include "kvm_util.h" +#include "x86.h" +#include "vmx.h" + +#define VCPU_ID 5 + +static bool have_nested_state; + +void l2_guest_code(void) +{ + GUEST_SYNC(5); + + /* Exit to L1 */ + vmcall(); + + /* L1 has now set up a shadow VMCS for us. */ + GUEST_ASSERT(vmreadz(GUEST_RIP) == 0xc0ffee); + GUEST_SYNC(9); + GUEST_ASSERT(vmreadz(GUEST_RIP) == 0xc0ffee); + GUEST_ASSERT(!vmwrite(GUEST_RIP, 0xc0fffee)); + GUEST_SYNC(10); + GUEST_ASSERT(vmreadz(GUEST_RIP) == 0xc0fffee); + GUEST_ASSERT(!vmwrite(GUEST_RIP, 0xc0ffffee)); + GUEST_SYNC(11); + + /* Done, exit to L1 and never come back. */ + vmcall(); +} + +void l1_guest_code(struct vmx_pages *vmx_pages) +{ +#define L2_GUEST_STACK_SIZE 64 + unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE]; + + GUEST_ASSERT(vmx_pages->vmcs_gpa); + GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); + GUEST_ASSERT(vmptrstz() == vmx_pages->vmcs_gpa); + + GUEST_SYNC(3); + GUEST_ASSERT(vmptrstz() == vmx_pages->vmcs_gpa); + + prepare_vmcs(vmx_pages, l2_guest_code, + &l2_guest_stack[L2_GUEST_STACK_SIZE]); + + GUEST_SYNC(4); + GUEST_ASSERT(vmptrstz() == vmx_pages->vmcs_gpa); + GUEST_ASSERT(!vmlaunch()); + GUEST_ASSERT(vmptrstz() == vmx_pages->vmcs_gpa); + GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL); + + /* Check that the launched state is preserved. */ + GUEST_ASSERT(vmlaunch()); + + GUEST_ASSERT(!vmresume()); + GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL); + + GUEST_SYNC(6); + GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL); + + GUEST_ASSERT(!vmresume()); + GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL); + + vmwrite(GUEST_RIP, vmreadz(GUEST_RIP) + 3); + + vmwrite(SECONDARY_VM_EXEC_CONTROL, SECONDARY_EXEC_SHADOW_VMCS); + vmwrite(VMCS_LINK_POINTER, vmx_pages->shadow_vmcs_gpa); + + GUEST_ASSERT(!vmptrld(vmx_pages->shadow_vmcs_gpa)); + GUEST_ASSERT(vmlaunch()); + GUEST_SYNC(7); + GUEST_ASSERT(vmlaunch()); + GUEST_ASSERT(vmresume()); + + vmwrite(GUEST_RIP, 0xc0ffee); + GUEST_SYNC(8); + GUEST_ASSERT(vmreadz(GUEST_RIP) == 0xc0ffee); + + GUEST_ASSERT(!vmptrld(vmx_pages->vmcs_gpa)); + GUEST_ASSERT(!vmresume()); + GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL); + + GUEST_ASSERT(!vmptrld(vmx_pages->shadow_vmcs_gpa)); + GUEST_ASSERT(vmreadz(GUEST_RIP) == 0xc0ffffee); + GUEST_ASSERT(vmlaunch()); + GUEST_ASSERT(vmresume()); + GUEST_SYNC(12); + GUEST_ASSERT(vmreadz(GUEST_RIP) == 0xc0ffffee); + GUEST_ASSERT(vmlaunch()); + GUEST_ASSERT(vmresume()); +} + +void guest_code(struct vmx_pages *vmx_pages) +{ + GUEST_SYNC(1); + GUEST_SYNC(2); + + if (vmx_pages) + l1_guest_code(vmx_pages); + + GUEST_DONE(); +} + +int main(int argc, char *argv[]) +{ + struct vmx_pages *vmx_pages = NULL; + vm_vaddr_t vmx_pages_gva = 0; + + struct kvm_regs regs1, regs2; + struct kvm_vm *vm; + struct kvm_run *run; + struct kvm_x86_state *state; + int stage; + + struct kvm_cpuid_entry2 *entry = kvm_get_supported_cpuid_entry(1); + + /* Create VM */ + vm = vm_create_default(VCPU_ID, 0, guest_code); + vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); + run = vcpu_state(vm, VCPU_ID); + + vcpu_regs_get(vm, VCPU_ID, ®s1); + + if (kvm_check_cap(KVM_CAP_NESTED_STATE)) { + vmx_pages = vcpu_alloc_vmx(vm, &vmx_pages_gva); + vcpu_args_set(vm, VCPU_ID, 1, vmx_pages_gva); + } else { + printf("will skip nested state checks\n"); + vcpu_args_set(vm, VCPU_ID, 1, 0); + } + + for (stage = 1;; stage++) { + _vcpu_run(vm, VCPU_ID); + TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, + "Unexpected exit reason: %u (%s),\n", + run->exit_reason, + exit_reason_str(run->exit_reason)); + + memset(®s1, 0, sizeof(regs1)); + vcpu_regs_get(vm, VCPU_ID, ®s1); + switch (run->io.port) { + case GUEST_PORT_ABORT: + TEST_ASSERT(false, "%s at %s:%d", (const char *) regs1.rdi, + __FILE__, regs1.rsi); + /* NOT REACHED */ + case GUEST_PORT_SYNC: + break; + case GUEST_PORT_DONE: + goto done; + default: + TEST_ASSERT(false, "Unknown port 0x%x.", run->io.port); + } + + /* PORT_SYNC is handled here. */ + TEST_ASSERT(!strcmp((const char *)regs1.rdi, "hello") && + regs1.rsi == stage, "Unexpected register values vmexit #%lx, got %lx", + stage, (ulong) regs1.rsi); + + state = vcpu_save_state(vm, VCPU_ID); + kvm_vm_release(vm); + + /* Restore state in a new VM. */ + kvm_vm_restart(vm, O_RDWR); + vm_vcpu_add(vm, VCPU_ID, 0, 0); + vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); + vcpu_load_state(vm, VCPU_ID, state); + run = vcpu_state(vm, VCPU_ID); + free(state); + + memset(®s2, 0, sizeof(regs2)); + vcpu_regs_get(vm, VCPU_ID, ®s2); + TEST_ASSERT(!memcmp(®s1, ®s2, sizeof(regs2)), + "Unexpected register values after vcpu_load_state; rdi: %lx rsi: %lx", + (ulong) regs2.rdi, (ulong) regs2.rsi); + } + +done: + kvm_vm_free(vm); +} diff --git a/tools/testing/selftests/kvm/sync_regs_test.c b/tools/testing/selftests/kvm/sync_regs_test.c index eae1ece3c31b..213343e5dff9 100644 --- a/tools/testing/selftests/kvm/sync_regs_test.c +++ b/tools/testing/selftests/kvm/sync_regs_test.c @@ -22,28 +22,11 @@ #include "x86.h" #define VCPU_ID 5 -#define PORT_HOST_SYNC 0x1000 - -static void __exit_to_l0(uint16_t port, uint64_t arg0, uint64_t arg1) -{ - __asm__ __volatile__("in %[port], %%al" - : - : [port]"d"(port), "D"(arg0), "S"(arg1) - : "rax"); -} - -#define exit_to_l0(_port, _arg0, _arg1) \ - __exit_to_l0(_port, (uint64_t) (_arg0), (uint64_t) (_arg1)) - -#define GUEST_ASSERT(_condition) do { \ - if (!(_condition)) \ - exit_to_l0(PORT_ABORT, "Failed guest assert: " #_condition, 0);\ -} while (0) void guest_code(void) { for (;;) { - exit_to_l0(PORT_HOST_SYNC, "hello", 0); + GUEST_SYNC(0); asm volatile ("inc %r11"); } } @@ -111,7 +94,7 @@ int main(int argc, char *argv[]) } /* Create VM */ - vm = vm_create_default(VCPU_ID, guest_code); + vm = vm_create_default(VCPU_ID, 0, guest_code); run = vcpu_state(vm, VCPU_ID); diff --git a/tools/testing/selftests/kvm/vmx_tsc_adjust_test.c b/tools/testing/selftests/kvm/vmx_tsc_adjust_test.c index d7cb7944a42e..49bcc68b0235 100644 --- a/tools/testing/selftests/kvm/vmx_tsc_adjust_test.c +++ b/tools/testing/selftests/kvm/vmx_tsc_adjust_test.c @@ -46,11 +46,6 @@ enum { PORT_DONE, }; -struct vmx_page { - vm_vaddr_t virt; - vm_paddr_t phys; -}; - enum { VMXON_PAGE = 0, VMCS_PAGE, @@ -67,30 +62,12 @@ struct kvm_single_msr { /* The virtual machine object. */ static struct kvm_vm *vm; -/* Array of vmx_page descriptors that is shared with the guest. */ -struct vmx_page *vmx_pages; - -#define exit_to_l0(_port, _arg) do_exit_to_l0(_port, (unsigned long) (_arg)) -static void do_exit_to_l0(uint16_t port, unsigned long arg) -{ - __asm__ __volatile__("in %[port], %%al" - : - : [port]"d"(port), "D"(arg) - : "rax"); -} - - -#define GUEST_ASSERT(_condition) do { \ - if (!(_condition)) \ - exit_to_l0(PORT_ABORT, "Failed guest assert: " #_condition); \ -} while (0) - static void check_ia32_tsc_adjust(int64_t max) { int64_t adjust; adjust = rdmsr(MSR_IA32_TSC_ADJUST); - exit_to_l0(PORT_REPORT, adjust); + GUEST_SYNC(adjust); GUEST_ASSERT(adjust <= max); } @@ -105,7 +82,7 @@ static void l2_guest_code(void) __asm__ __volatile__("vmcall"); } -static void l1_guest_code(struct vmx_page *vmx_pages) +static void l1_guest_code(struct vmx_pages *vmx_pages) { #define L2_GUEST_STACK_SIZE 64 unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE]; @@ -116,23 +93,14 @@ static void l1_guest_code(struct vmx_page *vmx_pages) wrmsr(MSR_IA32_TSC, rdtsc() - TSC_ADJUST_VALUE); check_ia32_tsc_adjust(-1 * TSC_ADJUST_VALUE); - prepare_for_vmx_operation(); - - /* Enter VMX root operation. */ - *(uint32_t *)vmx_pages[VMXON_PAGE].virt = vmcs_revision(); - GUEST_ASSERT(!vmxon(vmx_pages[VMXON_PAGE].phys)); - - /* Load a VMCS. */ - *(uint32_t *)vmx_pages[VMCS_PAGE].virt = vmcs_revision(); - GUEST_ASSERT(!vmclear(vmx_pages[VMCS_PAGE].phys)); - GUEST_ASSERT(!vmptrld(vmx_pages[VMCS_PAGE].phys)); + GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); /* Prepare the VMCS for L2 execution. */ - prepare_vmcs(l2_guest_code, &l2_guest_stack[L2_GUEST_STACK_SIZE]); + prepare_vmcs(vmx_pages, l2_guest_code, + &l2_guest_stack[L2_GUEST_STACK_SIZE]); control = vmreadz(CPU_BASED_VM_EXEC_CONTROL); control |= CPU_BASED_USE_MSR_BITMAPS | CPU_BASED_USE_TSC_OFFSETING; vmwrite(CPU_BASED_VM_EXEC_CONTROL, control); - vmwrite(MSR_BITMAP, vmx_pages[MSR_BITMAP_PAGE].phys); vmwrite(TSC_OFFSET, TSC_OFFSET_VALUE); /* Jump into L2. First, test failure to load guest CR3. */ @@ -149,34 +117,7 @@ static void l1_guest_code(struct vmx_page *vmx_pages) check_ia32_tsc_adjust(-2 * TSC_ADJUST_VALUE); - exit_to_l0(PORT_DONE, 0); -} - -static void allocate_vmx_page(struct vmx_page *page) -{ - vm_vaddr_t virt; - - virt = vm_vaddr_alloc(vm, PAGE_SIZE, 0, 0, 0); - memset(addr_gva2hva(vm, virt), 0, PAGE_SIZE); - - page->virt = virt; - page->phys = addr_gva2gpa(vm, virt); -} - -static vm_vaddr_t allocate_vmx_pages(void) -{ - vm_vaddr_t vmx_pages_vaddr; - int i; - - vmx_pages_vaddr = vm_vaddr_alloc( - vm, sizeof(struct vmx_page) * NUM_VMX_PAGES, 0, 0, 0); - - vmx_pages = (void *) addr_gva2hva(vm, vmx_pages_vaddr); - - for (i = 0; i < NUM_VMX_PAGES; i++) - allocate_vmx_page(&vmx_pages[i]); - - return vmx_pages_vaddr; + GUEST_DONE(); } void report(int64_t val) @@ -187,7 +128,8 @@ void report(int64_t val) int main(int argc, char *argv[]) { - vm_vaddr_t vmx_pages_vaddr; + struct vmx_pages *vmx_pages; + vm_vaddr_t vmx_pages_gva; struct kvm_cpuid_entry2 *entry = kvm_get_supported_cpuid_entry(1); if (!(entry->ecx & CPUID_VMX)) { @@ -195,35 +137,35 @@ int main(int argc, char *argv[]) exit(KSFT_SKIP); } - vm = vm_create_default_vmx(VCPU_ID, (void *) l1_guest_code); + vm = vm_create_default(VCPU_ID, 0, (void *) l1_guest_code); + vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); /* Allocate VMX pages and shared descriptors (vmx_pages). */ - vmx_pages_vaddr = allocate_vmx_pages(); - vcpu_args_set(vm, VCPU_ID, 1, vmx_pages_vaddr); + vmx_pages = vcpu_alloc_vmx(vm, &vmx_pages_gva); + vcpu_args_set(vm, VCPU_ID, 1, vmx_pages_gva); for (;;) { volatile struct kvm_run *run = vcpu_state(vm, VCPU_ID); - struct kvm_regs regs; + struct guest_args args; vcpu_run(vm, VCPU_ID); + guest_args_read(vm, VCPU_ID, &args); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, - "Got exit_reason other than KVM_EXIT_IO: %u (%s),\n", + "Got exit_reason other than KVM_EXIT_IO: %u (%s)\n", run->exit_reason, exit_reason_str(run->exit_reason)); - vcpu_regs_get(vm, VCPU_ID, ®s); - - switch (run->io.port) { - case PORT_ABORT: - TEST_ASSERT(false, "%s", (const char *) regs.rdi); + switch (args.port) { + case GUEST_PORT_ABORT: + TEST_ASSERT(false, "%s", (const char *) args.arg0); /* NOT REACHED */ - case PORT_REPORT: - report(regs.rdi); + case GUEST_PORT_SYNC: + report(args.arg1); break; - case PORT_DONE: + case GUEST_PORT_DONE: goto done; default: - TEST_ASSERT(false, "Unknown port 0x%x.", run->io.port); + TEST_ASSERT(false, "Unknown port 0x%x.", args.port); } } diff --git a/tools/testing/selftests/mount/config b/tools/testing/selftests/mount/config index b5d881e48548..416bd53ce982 100644 --- a/tools/testing/selftests/mount/config +++ b/tools/testing/selftests/mount/config @@ -1,2 +1 @@ CONFIG_USER_NS=y -CONFIG_DEVPTS_MULTIPLE_INSTANCES=y diff --git a/tools/testing/selftests/net/.gitignore b/tools/testing/selftests/net/.gitignore index 1a0ac3a29ec5..78b24cf76f40 100644 --- a/tools/testing/selftests/net/.gitignore +++ b/tools/testing/selftests/net/.gitignore @@ -13,3 +13,4 @@ udpgso udpgso_bench_rx udpgso_bench_tx tcp_inq +tls diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile index 663e11e85727..9cca68e440a0 100644 --- a/tools/testing/selftests/net/Makefile +++ b/tools/testing/selftests/net/Makefile @@ -13,7 +13,7 @@ TEST_GEN_FILES += psock_fanout psock_tpacket msg_zerocopy TEST_GEN_FILES += tcp_mmap tcp_inq psock_snd TEST_GEN_FILES += udpgso udpgso_bench_tx udpgso_bench_rx TEST_GEN_PROGS = reuseport_bpf reuseport_bpf_cpu reuseport_bpf_numa -TEST_GEN_PROGS += reuseport_dualstack reuseaddr_conflict +TEST_GEN_PROGS += reuseport_dualstack reuseaddr_conflict tls include ../lib.mk diff --git a/tools/testing/selftests/net/forwarding/README b/tools/testing/selftests/net/forwarding/README index 4a0964c42860..b8a2af8fcfb7 100644 --- a/tools/testing/selftests/net/forwarding/README +++ b/tools/testing/selftests/net/forwarding/README @@ -46,6 +46,8 @@ Guidelines for Writing Tests o Where possible, reuse an existing topology for different tests instead of recreating the same topology. +o Tests that use anything but the most trivial topologies should include + an ASCII art showing the topology. o Where possible, IPv6 and IPv4 addresses shall conform to RFC 3849 and RFC 5737, respectively. o Where possible, tests shall be written so that they can be reused by diff --git a/tools/testing/selftests/net/forwarding/bridge_port_isolation.sh b/tools/testing/selftests/net/forwarding/bridge_port_isolation.sh new file mode 100755 index 000000000000..a43b4645c4de --- /dev/null +++ b/tools/testing/selftests/net/forwarding/bridge_port_isolation.sh @@ -0,0 +1,151 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +ALL_TESTS="ping_ipv4 ping_ipv6 flooding" +NUM_NETIFS=6 +CHECK_TC="yes" +source lib.sh + +h1_create() +{ + simple_if_init $h1 192.0.2.1/24 2001:db8:1::1/64 +} + +h1_destroy() +{ + simple_if_fini $h1 192.0.2.1/24 2001:db8:1::1/64 +} + +h2_create() +{ + simple_if_init $h2 192.0.2.2/24 2001:db8:1::2/64 +} + +h2_destroy() +{ + simple_if_fini $h2 192.0.2.2/24 2001:db8:1::2/64 +} + +h3_create() +{ + simple_if_init $h3 192.0.2.3/24 2001:db8:1::3/64 +} + +h3_destroy() +{ + simple_if_fini $h3 192.0.2.3/24 2001:db8:1::3/64 +} + +switch_create() +{ + ip link add dev br0 type bridge + + ip link set dev $swp1 master br0 + ip link set dev $swp2 master br0 + ip link set dev $swp3 master br0 + + ip link set dev $swp1 type bridge_slave isolated on + check_err $? "Can't set isolation on port $swp1" + ip link set dev $swp2 type bridge_slave isolated on + check_err $? "Can't set isolation on port $swp2" + ip link set dev $swp3 type bridge_slave isolated off + check_err $? "Can't disable isolation on port $swp3" + + ip link set dev br0 up + ip link set dev $swp1 up + ip link set dev $swp2 up + ip link set dev $swp3 up +} + +switch_destroy() +{ + ip link set dev $swp3 down + ip link set dev $swp2 down + ip link set dev $swp1 down + + ip link del dev br0 +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + swp1=${NETIFS[p2]} + + swp2=${NETIFS[p3]} + h2=${NETIFS[p4]} + + swp3=${NETIFS[p5]} + h3=${NETIFS[p6]} + + vrf_prepare + + h1_create + h2_create + h3_create + + switch_create +} + +cleanup() +{ + pre_cleanup + + switch_destroy + + h3_destroy + h2_destroy + h1_destroy + + vrf_cleanup +} + +ping_ipv4() +{ + RET=0 + ping_do $h1 192.0.2.2 + check_fail $? "Ping worked when it should not have" + + RET=0 + ping_do $h3 192.0.2.2 + check_err $? "Ping didn't work when it should have" + + log_test "Isolated port ping" +} + +ping_ipv6() +{ + RET=0 + ping6_do $h1 2001:db8:1::2 + check_fail $? "Ping6 worked when it should not have" + + RET=0 + ping6_do $h3 2001:db8:1::2 + check_err $? "Ping6 didn't work when it should have" + + log_test "Isolated port ping6" +} + +flooding() +{ + local mac=de:ad:be:ef:13:37 + local ip=192.0.2.100 + + RET=0 + flood_test_do false $mac $ip $h1 $h2 + check_err $? "Packet was flooded when it should not have been" + + RET=0 + flood_test_do true $mac $ip $h3 $h2 + check_err $? "Packet was not flooded when it should have been" + + log_test "Isolated port flooding" +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +tests_run + +exit $EXIT_STATUS diff --git a/tools/testing/selftests/net/forwarding/devlink_lib.sh b/tools/testing/selftests/net/forwarding/devlink_lib.sh new file mode 100644 index 000000000000..5ab1e5f43022 --- /dev/null +++ b/tools/testing/selftests/net/forwarding/devlink_lib.sh @@ -0,0 +1,108 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +############################################################################## +# Source library + +relative_path="${BASH_SOURCE%/*}" +if [[ "$relative_path" == "${BASH_SOURCE}" ]]; then + relative_path="." +fi + +source "$relative_path/lib.sh" + +############################################################################## +# Defines + +DEVLINK_DEV=$(devlink port show | grep "${NETIFS[p1]}" | \ + grep -v "${NETIFS[p1]}[0-9]" | cut -d" " -f1 | \ + rev | cut -d"/" -f2- | rev) +if [ -z "$DEVLINK_DEV" ]; then + echo "SKIP: ${NETIFS[p1]} has no devlink device registered for it" + exit 1 +fi +if [[ "$(echo $DEVLINK_DEV | grep -c pci)" -eq 0 ]]; then + echo "SKIP: devlink device's bus is not PCI" + exit 1 +fi + +DEVLINK_VIDDID=$(lspci -s $(echo $DEVLINK_DEV | cut -d"/" -f2) \ + -n | cut -d" " -f3) + +############################################################################## +# Sanity checks + +devlink -j resource show "$DEVLINK_DEV" &> /dev/null +if [ $? -ne 0 ]; then + echo "SKIP: iproute2 too old, missing devlink resource support" + exit 1 +fi + +############################################################################## +# Devlink helpers + +devlink_resource_names_to_path() +{ + local resource + local path="" + + for resource in "${@}"; do + if [ "$path" == "" ]; then + path="$resource" + else + path="${path}/$resource" + fi + done + + echo "$path" +} + +devlink_resource_get() +{ + local name=$1 + local resource_name=.[][\"$DEVLINK_DEV\"] + + resource_name="$resource_name | .[] | select (.name == \"$name\")" + + shift + for resource in "${@}"; do + resource_name="${resource_name} | .[\"resources\"][] | \ + select (.name == \"$resource\")" + done + + devlink -j resource show "$DEVLINK_DEV" | jq "$resource_name" +} + +devlink_resource_size_get() +{ + local size=$(devlink_resource_get "$@" | jq '.["size_new"]') + + if [ "$size" == "null" ]; then + devlink_resource_get "$@" | jq '.["size"]' + else + echo "$size" + fi +} + +devlink_resource_size_set() +{ + local new_size=$1 + local path + + shift + path=$(devlink_resource_names_to_path "$@") + devlink resource set "$DEVLINK_DEV" path "$path" size "$new_size" + check_err $? "Failed setting path $path to size $size" +} + +devlink_reload() +{ + local still_pending + + devlink dev reload "$DEVLINK_DEV" &> /dev/null + check_err $? "Failed reload" + + still_pending=$(devlink resource show "$DEVLINK_DEV" | \ + grep -c "size_new") + check_err $still_pending "Failed reload - There are still unset sizes" +} diff --git a/tools/testing/selftests/net/forwarding/gre_multipath.sh b/tools/testing/selftests/net/forwarding/gre_multipath.sh new file mode 100755 index 000000000000..cca2baa03fb8 --- /dev/null +++ b/tools/testing/selftests/net/forwarding/gre_multipath.sh @@ -0,0 +1,253 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +# Test traffic distribution when a wECMP route forwards traffic to two GRE +# tunnels. +# +# +-------------------------+ +# | H1 | +# | $h1 + | +# | 192.0.2.1/28 | | +# +-------------------|-----+ +# | +# +-------------------|------------------------+ +# | SW1 | | +# | $ol1 + | +# | 192.0.2.2/28 | +# | | +# | + g1a (gre) + g1b (gre) | +# | loc=192.0.2.65 loc=192.0.2.81 | +# | rem=192.0.2.66 --. rem=192.0.2.82 --. | +# | tos=inherit | tos=inherit | | +# | .------------------' | | +# | | .------------------' | +# | v v | +# | + $ul1.111 (vlan) + $ul1.222 (vlan) | +# | | 192.0.2.129/28 | 192.0.2.145/28 | +# | \ / | +# | \________________/ | +# | | | +# | + $ul1 | +# +------------|-------------------------------+ +# | +# +------------|-------------------------------+ +# | SW2 + $ul2 | +# | _______|________ | +# | / \ | +# | / \ | +# | + $ul2.111 (vlan) + $ul2.222 (vlan) | +# | ^ 192.0.2.130/28 ^ 192.0.2.146/28 | +# | | | | +# | | '------------------. | +# | '------------------. | | +# | + g2a (gre) | + g2b (gre) | | +# | loc=192.0.2.66 | loc=192.0.2.82 | | +# | rem=192.0.2.65 --' rem=192.0.2.81 --' | +# | tos=inherit tos=inherit | +# | | +# | $ol2 + | +# | 192.0.2.17/28 | | +# +-------------------|------------------------+ +# | +# +-------------------|-----+ +# | H2 | | +# | $h2 + | +# | 192.0.2.18/28 | +# +-------------------------+ + +ALL_TESTS=" + ping_ipv4 + multipath_ipv4 +" + +NUM_NETIFS=6 +source lib.sh + +h1_create() +{ + simple_if_init $h1 192.0.2.1/28 2001:db8:1::1/64 + ip route add vrf v$h1 192.0.2.16/28 via 192.0.2.2 +} + +h1_destroy() +{ + ip route del vrf v$h1 192.0.2.16/28 via 192.0.2.2 + simple_if_fini $h1 192.0.2.1/28 +} + +sw1_create() +{ + simple_if_init $ol1 192.0.2.2/28 + __simple_if_init $ul1 v$ol1 + vlan_create $ul1 111 v$ol1 192.0.2.129/28 + vlan_create $ul1 222 v$ol1 192.0.2.145/28 + + tunnel_create g1a gre 192.0.2.65 192.0.2.66 tos inherit dev v$ol1 + __simple_if_init g1a v$ol1 192.0.2.65/32 + ip route add vrf v$ol1 192.0.2.66/32 via 192.0.2.130 + + tunnel_create g1b gre 192.0.2.81 192.0.2.82 tos inherit dev v$ol1 + __simple_if_init g1b v$ol1 192.0.2.81/32 + ip route add vrf v$ol1 192.0.2.82/32 via 192.0.2.146 + + ip route add vrf v$ol1 192.0.2.16/28 \ + nexthop dev g1a \ + nexthop dev g1b + + tc qdisc add dev $ul1 clsact + tc filter add dev $ul1 egress pref 111 prot ipv4 \ + flower dst_ip 192.0.2.66 action pass + tc filter add dev $ul1 egress pref 222 prot ipv4 \ + flower dst_ip 192.0.2.82 action pass +} + +sw1_destroy() +{ + tc qdisc del dev $ul1 clsact + + ip route del vrf v$ol1 192.0.2.16/28 + + ip route del vrf v$ol1 192.0.2.82/32 via 192.0.2.146 + __simple_if_fini g1b 192.0.2.81/32 + tunnel_destroy g1b + + ip route del vrf v$ol1 192.0.2.66/32 via 192.0.2.130 + __simple_if_fini g1a 192.0.2.65/32 + tunnel_destroy g1a + + vlan_destroy $ul1 222 + vlan_destroy $ul1 111 + __simple_if_fini $ul1 + simple_if_fini $ol1 192.0.2.2/28 +} + +sw2_create() +{ + simple_if_init $ol2 192.0.2.17/28 + __simple_if_init $ul2 v$ol2 + vlan_create $ul2 111 v$ol2 192.0.2.130/28 + vlan_create $ul2 222 v$ol2 192.0.2.146/28 + + tunnel_create g2a gre 192.0.2.66 192.0.2.65 tos inherit dev v$ol2 + __simple_if_init g2a v$ol2 192.0.2.66/32 + ip route add vrf v$ol2 192.0.2.65/32 via 192.0.2.129 + + tunnel_create g2b gre 192.0.2.82 192.0.2.81 tos inherit dev v$ol2 + __simple_if_init g2b v$ol2 192.0.2.82/32 + ip route add vrf v$ol2 192.0.2.81/32 via 192.0.2.145 + + ip route add vrf v$ol2 192.0.2.0/28 \ + nexthop dev g2a \ + nexthop dev g2b +} + +sw2_destroy() +{ + ip route del vrf v$ol2 192.0.2.0/28 + + ip route del vrf v$ol2 192.0.2.81/32 via 192.0.2.145 + __simple_if_fini g2b 192.0.2.82/32 + tunnel_destroy g2b + + ip route del vrf v$ol2 192.0.2.65/32 via 192.0.2.129 + __simple_if_fini g2a 192.0.2.66/32 + tunnel_destroy g2a + + vlan_destroy $ul2 222 + vlan_destroy $ul2 111 + __simple_if_fini $ul2 + simple_if_fini $ol2 192.0.2.17/28 +} + +h2_create() +{ + simple_if_init $h2 192.0.2.18/28 + ip route add vrf v$h2 192.0.2.0/28 via 192.0.2.17 +} + +h2_destroy() +{ + ip route del vrf v$h2 192.0.2.0/28 via 192.0.2.17 + simple_if_fini $h2 192.0.2.18/28 +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + ol1=${NETIFS[p2]} + + ul1=${NETIFS[p3]} + ul2=${NETIFS[p4]} + + ol2=${NETIFS[p5]} + h2=${NETIFS[p6]} + + vrf_prepare + h1_create + sw1_create + sw2_create + h2_create +} + +cleanup() +{ + pre_cleanup + + h2_destroy + sw2_destroy + sw1_destroy + h1_destroy + vrf_cleanup +} + +multipath4_test() +{ + local what=$1; shift + local weight1=$1; shift + local weight2=$1; shift + + sysctl_set net.ipv4.fib_multipath_hash_policy 1 + ip route replace vrf v$ol1 192.0.2.16/28 \ + nexthop dev g1a weight $weight1 \ + nexthop dev g1b weight $weight2 + + local t0_111=$(tc_rule_stats_get $ul1 111 egress) + local t0_222=$(tc_rule_stats_get $ul1 222 egress) + + ip vrf exec v$h1 \ + $MZ $h1 -q -p 64 -A 192.0.2.1 -B 192.0.2.18 \ + -d 1msec -t udp "sp=1024,dp=0-32768" + + local t1_111=$(tc_rule_stats_get $ul1 111 egress) + local t1_222=$(tc_rule_stats_get $ul1 222 egress) + + local d111=$((t1_111 - t0_111)) + local d222=$((t1_222 - t0_222)) + multipath_eval "$what" $weight1 $weight2 $d111 $d222 + + ip route replace vrf v$ol1 192.0.2.16/28 \ + nexthop dev g1a \ + nexthop dev g1b + sysctl_restore net.ipv4.fib_multipath_hash_policy +} + +ping_ipv4() +{ + ping_test $h1 192.0.2.18 +} + +multipath_ipv4() +{ + log_info "Running IPv4 multipath tests" + multipath4_test "ECMP" 1 1 + multipath4_test "Weighted MP 2:1" 2 1 + multipath4_test "Weighted MP 11:45" 11 45 +} + +trap cleanup EXIT + +setup_prepare +setup_wait +tests_run + +exit $EXIT_STATUS diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index 7b18a53aa556..ca53b539aa2d 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -8,14 +8,21 @@ PING=${PING:=ping} PING6=${PING6:=ping6} MZ=${MZ:=mausezahn} +ARPING=${ARPING:=arping} +TEAMD=${TEAMD:=teamd} WAIT_TIME=${WAIT_TIME:=5} PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no} PAUSE_ON_CLEANUP=${PAUSE_ON_CLEANUP:=no} NETIF_TYPE=${NETIF_TYPE:=veth} NETIF_CREATE=${NETIF_CREATE:=yes} -if [[ -f forwarding.config ]]; then - source forwarding.config +relative_path="${BASH_SOURCE%/*}" +if [[ "$relative_path" == "${BASH_SOURCE}" ]]; then + relative_path="." +fi + +if [[ -f $relative_path/forwarding.config ]]; then + source "$relative_path/forwarding.config" fi ############################################################################## @@ -28,7 +35,10 @@ check_tc_version() echo "SKIP: iproute2 too old; tc is missing JSON support" exit 1 fi +} +check_tc_shblock_support() +{ tc filter help 2>&1 | grep block &> /dev/null if [[ $? -ne 0 ]]; then echo "SKIP: iproute2 too old; tc is missing shared block support" @@ -36,6 +46,15 @@ check_tc_version() fi } +check_tc_chain_support() +{ + tc help 2>&1|grep chain &> /dev/null + if [[ $? -ne 0 ]]; then + echo "SKIP: iproute2 too old; tc is missing chain support" + exit 1 + fi +} + if [[ "$(id -u)" -ne 0 ]]; then echo "SKIP: need root privileges" exit 0 @@ -45,15 +64,18 @@ if [[ "$CHECK_TC" = "yes" ]]; then check_tc_version fi -if [[ ! -x "$(command -v jq)" ]]; then - echo "SKIP: jq not installed" - exit 1 -fi +require_command() +{ + local cmd=$1; shift -if [[ ! -x "$(command -v $MZ)" ]]; then - echo "SKIP: $MZ not installed" - exit 1 -fi + if [[ ! -x "$(command -v "$cmd")" ]]; then + echo "SKIP: $cmd not installed" + exit 1 + fi +} + +require_command jq +require_command $MZ if [[ ! -v NUM_NETIFS ]]; then echo "SKIP: importer does not define \"NUM_NETIFS\"" @@ -151,6 +173,19 @@ check_fail() fi } +check_err_fail() +{ + local should_fail=$1; shift + local err=$1; shift + local what=$1; shift + + if ((should_fail)); then + check_fail $err "$what succeeded, but should have failed" + else + check_err $err "$what failed" + fi +} + log_test() { local test_name=$1 @@ -185,24 +220,54 @@ log_info() echo "INFO: $msg" } +setup_wait_dev() +{ + local dev=$1; shift + + while true; do + ip link show dev $dev up \ + | grep 'state UP' &> /dev/null + if [[ $? -ne 0 ]]; then + sleep 1 + else + break + fi + done +} + setup_wait() { - for i in $(eval echo {1..$NUM_NETIFS}); do - while true; do - ip link show dev ${NETIFS[p$i]} up \ - | grep 'state UP' &> /dev/null - if [[ $? -ne 0 ]]; then - sleep 1 - else - break - fi - done + local num_netifs=${1:-$NUM_NETIFS} + + for ((i = 1; i <= num_netifs; ++i)); do + setup_wait_dev ${NETIFS[p$i]} done # Make sure links are ready. sleep $WAIT_TIME } +lldpad_app_wait_set() +{ + local dev=$1; shift + + while lldptool -t -i $dev -V APP -c app | grep -q pending; do + echo "$dev: waiting for lldpad to push pending APP updates" + sleep 5 + done +} + +lldpad_app_wait_del() +{ + # Give lldpad a chance to push down the changes. If the device is downed + # too soon, the updates will be left pending. However, they will have + # been struck off the lldpad's DB already, so we won't be able to tell + # they are pending. Then on next test iteration this would cause + # weirdness as newly-added APP rules conflict with the old ones, + # sometimes getting stuck in an "unknown" state. + sleep 5 +} + pre_cleanup() { if [ "${PAUSE_ON_CLEANUP}" = "yes" ]; then @@ -287,6 +352,29 @@ __addr_add_del() done } +__simple_if_init() +{ + local if_name=$1; shift + local vrf_name=$1; shift + local addrs=("${@}") + + ip link set dev $if_name master $vrf_name + ip link set dev $if_name up + + __addr_add_del $if_name add "${addrs[@]}" +} + +__simple_if_fini() +{ + local if_name=$1; shift + local addrs=("${@}") + + __addr_add_del $if_name del "${addrs[@]}" + + ip link set dev $if_name down + ip link set dev $if_name nomaster +} + simple_if_init() { local if_name=$1 @@ -298,11 +386,8 @@ simple_if_init() array=("${@}") vrf_create $vrf_name - ip link set dev $if_name master $vrf_name ip link set dev $vrf_name up - ip link set dev $if_name up - - __addr_add_del $if_name add "${array[@]}" + __simple_if_init $if_name $vrf_name "${array[@]}" } simple_if_fini() @@ -315,9 +400,7 @@ simple_if_fini() vrf_name=v$if_name array=("${@}") - __addr_add_del $if_name del "${array[@]}" - - ip link set dev $if_name down + __simple_if_fini $if_name "${array[@]}" vrf_destroy $vrf_name } @@ -365,6 +448,28 @@ vlan_destroy() ip link del dev $name } +team_create() +{ + local if_name=$1; shift + local mode=$1; shift + + require_command $TEAMD + $TEAMD -t $if_name -d -c '{"runner": {"name": "'$mode'"}}' + for slave in "$@"; do + ip link set dev $slave down + ip link set dev $slave master $if_name + ip link set dev $slave up + done + ip link set dev $if_name up +} + +team_destroy() +{ + local if_name=$1; shift + + $TEAMD -t $if_name -k +} + master_name_get() { local if_name=$1 @@ -383,9 +488,10 @@ tc_rule_stats_get() { local dev=$1; shift local pref=$1; shift + local dir=$1; shift - tc -j -s filter show dev $dev ingress pref $pref | - jq '.[1].options.actions[].stats.packets' + tc -j -s filter show dev $dev ${dir:-ingress} pref $pref \ + | jq '.[1].options.actions[].stats.packets' } mac_get() @@ -437,7 +543,9 @@ forwarding_restore() tc_offload_check() { - for i in $(eval echo {1..$NUM_NETIFS}); do + local num_netifs=${1:-$NUM_NETIFS} + + for ((i = 1; i <= num_netifs; ++i)); do ethtool -k ${NETIFS[p$i]} \ | grep "hw-tc-offload: on" &> /dev/null if [[ $? -ne 0 ]]; then @@ -453,9 +561,15 @@ trap_install() local dev=$1; shift local direction=$1; shift - # For slow-path testing, we need to install a trap to get to - # slow path the packets that would otherwise be switched in HW. - tc filter add dev $dev $direction pref 1 flower skip_sw action trap + # Some devices may not support or need in-hardware trapping of traffic + # (e.g. the veth pairs that this library creates for non-existent + # loopbacks). Use continue instead, so that there is a filter in there + # (some tests check counters), and so that other filters are still + # processed. + tc filter add dev $dev $direction pref 1 \ + flower skip_sw action trap 2>/dev/null \ + || tc filter add dev $dev $direction pref 1 \ + flower action continue } trap_uninstall() @@ -463,11 +577,13 @@ trap_uninstall() local dev=$1; shift local direction=$1; shift - tc filter del dev $dev $direction pref 1 flower skip_sw + tc filter del dev $dev $direction pref 1 flower } slow_path_trap_install() { + # For slow-path testing, we need to install a trap to get to + # slow path the packets that would otherwise be switched in HW. if [ "${tcflags/skip_hw}" != "$tcflags" ]; then trap_install "$@" fi @@ -537,6 +653,48 @@ vlan_capture_uninstall() __vlan_capture_add_del del 100 "$@" } +__dscp_capture_add_del() +{ + local add_del=$1; shift + local dev=$1; shift + local base=$1; shift + local dscp; + + for prio in {0..7}; do + dscp=$((base + prio)) + __icmp_capture_add_del $add_del $((dscp + 100)) "" $dev \ + "skip_hw ip_tos $((dscp << 2))" + done +} + +dscp_capture_install() +{ + local dev=$1; shift + local base=$1; shift + + __dscp_capture_add_del add $dev $base +} + +dscp_capture_uninstall() +{ + local dev=$1; shift + local base=$1; shift + + __dscp_capture_add_del del $dev $base +} + +dscp_fetch_stats() +{ + local dev=$1; shift + local base=$1; shift + + for prio in {0..7}; do + local dscp=$((base + prio)) + local t=$(tc_rule_stats_get $dev $((dscp + 100))) + echo "[$dscp]=$t " + done +} + matchall_sink_create() { local dev=$1; shift @@ -557,33 +715,86 @@ tests_run() done } +multipath_eval() +{ + local desc="$1" + local weight_rp12=$2 + local weight_rp13=$3 + local packets_rp12=$4 + local packets_rp13=$5 + local weights_ratio packets_ratio diff + + RET=0 + + if [[ "$weight_rp12" -gt "$weight_rp13" ]]; then + weights_ratio=$(echo "scale=2; $weight_rp12 / $weight_rp13" \ + | bc -l) + else + weights_ratio=$(echo "scale=2; $weight_rp13 / $weight_rp12" \ + | bc -l) + fi + + if [[ "$packets_rp12" -eq "0" || "$packets_rp13" -eq "0" ]]; then + check_err 1 "Packet difference is 0" + log_test "Multipath" + log_info "Expected ratio $weights_ratio" + return + fi + + if [[ "$weight_rp12" -gt "$weight_rp13" ]]; then + packets_ratio=$(echo "scale=2; $packets_rp12 / $packets_rp13" \ + | bc -l) + else + packets_ratio=$(echo "scale=2; $packets_rp13 / $packets_rp12" \ + | bc -l) + fi + + diff=$(echo $weights_ratio - $packets_ratio | bc -l) + diff=${diff#-} + + test "$(echo "$diff / $weights_ratio > 0.15" | bc -l)" -eq 0 + check_err $? "Too large discrepancy between expected and measured ratios" + log_test "$desc" + log_info "Expected ratio $weights_ratio Measured ratio $packets_ratio" +} + ############################################################################## # Tests -ping_test() +ping_do() { local if_name=$1 local dip=$2 local vrf_name - RET=0 - vrf_name=$(master_name_get $if_name) ip vrf exec $vrf_name $PING $dip -c 10 -i 0.1 -w 2 &> /dev/null +} + +ping_test() +{ + RET=0 + + ping_do $1 $2 check_err $? log_test "ping" } -ping6_test() +ping6_do() { local if_name=$1 local dip=$2 local vrf_name - RET=0 - vrf_name=$(master_name_get $if_name) ip vrf exec $vrf_name $PING6 $dip -c 10 -i 0.1 -w 2 &> /dev/null +} + +ping6_test() +{ + RET=0 + + ping6_do $1 $2 check_err $? log_test "ping6" } diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d.sh b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d.sh new file mode 100755 index 000000000000..c5095da7f6bf --- /dev/null +++ b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d.sh @@ -0,0 +1,132 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +# Test for "tc action mirred egress mirror" when the underlay route points at a +# bridge device without vlan filtering (802.1d). +# +# This test uses standard topology for testing mirror-to-gretap. See +# mirror_gre_topo_lib.sh for more details. The full topology is as follows: +# +# +---------------------+ +---------------------+ +# | H1 | | H2 | +# | + $h1 | | $h2 + | +# | | 192.0.2.1/28 | | 192.0.2.2/28 | | +# +-----|---------------+ +---------------|-----+ +# | | +# +-----|-------------------------------------------------------------|-----+ +# | SW o---> mirror | | +# | +---|-------------------------------------------------------------|---+ | +# | | + $swp1 + br1 (802.1q bridge) $swp2 + | | +# | +---------------------------------------------------------------------+ | +# | | +# | +---------------------------------------------------------------------+ | +# | | + br2 (802.1d bridge) | | +# | | 192.0.2.129/28 | | +# | | + $swp3 2001:db8:2::1/64 | | +# | +---|-----------------------------------------------------------------+ | +# | | ^ ^ | +# | | + gt6 (ip6gretap) | + gt4 (gretap) | | +# | | : loc=2001:db8:2::1 | : loc=192.0.2.129 | | +# | | : rem=2001:db8:2::2 -+ : rem=192.0.2.130 -+ | +# | | : ttl=100 : ttl=100 | +# | | : tos=inherit : tos=inherit | +# +-----|---------------------:----------------------:----------------------+ +# | : : +# +-----|---------------------:----------------------:----------------------+ +# | H3 + $h3 + h3-gt6(ip6gretap) + h3-gt4 (gretap) | +# | 192.0.2.130/28 loc=2001:db8:2::2 loc=192.0.2.130 | +# | 2001:db8:2::2/64 rem=2001:db8:2::1 rem=192.0.2.129 | +# | ttl=100 ttl=100 | +# | tos=inherit tos=inherit | +# +-------------------------------------------------------------------------+ + +ALL_TESTS=" + test_gretap + test_ip6gretap +" + +NUM_NETIFS=6 +source lib.sh +source mirror_lib.sh +source mirror_gre_lib.sh +source mirror_gre_topo_lib.sh + +setup_prepare() +{ + h1=${NETIFS[p1]} + swp1=${NETIFS[p2]} + + swp2=${NETIFS[p3]} + h2=${NETIFS[p4]} + + swp3=${NETIFS[p5]} + h3=${NETIFS[p6]} + + vrf_prepare + mirror_gre_topo_create + + ip link add name br2 type bridge vlan_filtering 0 + ip link set dev br2 up + + ip link set dev $swp3 master br2 + ip route add 192.0.2.130/32 dev br2 + ip -6 route add 2001:db8:2::2/128 dev br2 + + ip address add dev br2 192.0.2.129/28 + ip address add dev br2 2001:db8:2::1/64 + + ip address add dev $h3 192.0.2.130/28 + ip address add dev $h3 2001:db8:2::2/64 +} + +cleanup() +{ + pre_cleanup + + ip address del dev $h3 2001:db8:2::2/64 + ip address del dev $h3 192.0.2.130/28 + ip link del dev br2 + + mirror_gre_topo_destroy + vrf_cleanup +} + +test_gretap() +{ + full_test_span_gre_dir gt4 ingress 8 0 "mirror to gretap" + full_test_span_gre_dir gt4 egress 0 8 "mirror to gretap" +} + +test_ip6gretap() +{ + full_test_span_gre_dir gt6 ingress 8 0 "mirror to ip6gretap" + full_test_span_gre_dir gt6 egress 0 8 "mirror to ip6gretap" +} + +test_all() +{ + slow_path_trap_install $swp1 ingress + slow_path_trap_install $swp1 egress + + tests_run + + slow_path_trap_uninstall $swp1 egress + slow_path_trap_uninstall $swp1 ingress +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +tcflags="skip_hw" +test_all + +if ! tc_offload_check; then + echo "WARN: Could not test offloaded functionality" +else + tcflags="skip_sw" + test_all +fi + +exit $EXIT_STATUS diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d_vlan.sh b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d_vlan.sh index 3bb4c2ba7b14..197e769c2ed1 100755 --- a/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d_vlan.sh +++ b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d_vlan.sh @@ -74,12 +74,14 @@ test_vlan_match() test_gretap() { - test_vlan_match gt4 'vlan_id 555 vlan_ethtype ip' "mirror to gretap" + test_vlan_match gt4 'skip_hw vlan_id 555 vlan_ethtype ip' \ + "mirror to gretap" } test_ip6gretap() { - test_vlan_match gt6 'vlan_id 555 vlan_ethtype ipv6' "mirror to ip6gretap" + test_vlan_match gt6 'skip_hw vlan_id 555 vlan_ethtype ip' \ + "mirror to ip6gretap" } test_gretap_stp() diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q.sh b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q.sh new file mode 100755 index 000000000000..a3402cd8d5b6 --- /dev/null +++ b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q.sh @@ -0,0 +1,126 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +# Test for "tc action mirred egress mirror" when the underlay route points at a +# bridge device with vlan filtering (802.1q). +# +# This test uses standard topology for testing mirror-to-gretap. See +# mirror_gre_topo_lib.sh for more details. The full topology is as follows: +# +# +---------------------+ +---------------------+ +# | H1 | | H2 | +# | + $h1 | | $h2 + | +# | | 192.0.2.1/28 | | 192.0.2.2/28 | | +# +-----|---------------+ +---------------|-----+ +# | | +# +-----|---------------------------------------------------------------|-----+ +# | SW o---> mirror | | +# | +---|---------------------------------------------------------------|---+ | +# | | + $swp1 + br1 (802.1q bridge) $swp2 + | | +# | | 192.0.2.129/28 | | +# | | + $swp3 2001:db8:2::1/64 | | +# | | | vid555 vid555[pvid,untagged] | | +# | +---|-------------------------------------------------------------------+ | +# | | ^ ^ | +# | | + gt6 (ip6gretap) | + gt4 (gretap) | | +# | | : loc=2001:db8:2::1 | : loc=192.0.2.129 | | +# | | : rem=2001:db8:2::2 -+ : rem=192.0.2.130 -+ | +# | | : ttl=100 : ttl=100 | +# | | : tos=inherit : tos=inherit | +# +-----|---------------------:------------------------:----------------------+ +# | : : +# +-----|---------------------:------------------------:----------------------+ +# | H3 + $h3 + h3-gt6(ip6gretap) + h3-gt4 (gretap) | +# | | loc=2001:db8:2::2 loc=192.0.2.130 | +# | + $h3.555 rem=2001:db8:2::1 rem=192.0.2.129 | +# | 192.0.2.130/28 ttl=100 ttl=100 | +# | 2001:db8:2::2/64 tos=inherit tos=inherit | +# +---------------------------------------------------------------------------+ + +ALL_TESTS=" + test_gretap + test_ip6gretap +" + +NUM_NETIFS=6 +source lib.sh +source mirror_lib.sh +source mirror_gre_lib.sh +source mirror_gre_topo_lib.sh + +setup_prepare() +{ + h1=${NETIFS[p1]} + swp1=${NETIFS[p2]} + + swp2=${NETIFS[p3]} + h2=${NETIFS[p4]} + + swp3=${NETIFS[p5]} + h3=${NETIFS[p6]} + + vrf_prepare + mirror_gre_topo_create + + ip link set dev $swp3 master br1 + bridge vlan add dev br1 vid 555 pvid untagged self + ip address add dev br1 192.0.2.129/28 + ip address add dev br1 2001:db8:2::1/64 + + ip -4 route add 192.0.2.130/32 dev br1 + ip -6 route add 2001:db8:2::2/128 dev br1 + + vlan_create $h3 555 v$h3 192.0.2.130/28 2001:db8:2::2/64 + bridge vlan add dev $swp3 vid 555 +} + +cleanup() +{ + pre_cleanup + + ip link set dev $swp3 nomaster + vlan_destroy $h3 555 + + mirror_gre_topo_destroy + vrf_cleanup +} + +test_gretap() +{ + full_test_span_gre_dir gt4 ingress 8 0 "mirror to gretap" + full_test_span_gre_dir gt4 egress 0 8 "mirror to gretap" +} + +test_ip6gretap() +{ + full_test_span_gre_dir gt6 ingress 8 0 "mirror to ip6gretap" + full_test_span_gre_dir gt6 egress 0 8 "mirror to ip6gretap" +} + +tests() +{ + slow_path_trap_install $swp1 ingress + slow_path_trap_install $swp1 egress + + tests_run + + slow_path_trap_uninstall $swp1 egress + slow_path_trap_uninstall $swp1 ingress +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +tcflags="skip_hw" +tests + +if ! tc_offload_check; then + echo "WARN: Could not test offloaded functionality" +else + tcflags="skip_sw" + tests +fi + +exit $EXIT_STATUS diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q_lag.sh b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q_lag.sh new file mode 100755 index 000000000000..61844caf671e --- /dev/null +++ b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q_lag.sh @@ -0,0 +1,283 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +# Test for "tc action mirred egress mirror" when the underlay route points at a +# bridge device with vlan filtering (802.1q), and the egress device is a team +# device. +# +# +----------------------+ +----------------------+ +# | H1 | | H2 | +# | + $h1.333 | | $h1.555 + | +# | | 192.0.2.1/28 | | 192.0.2.18/28 | | +# +-----|----------------+ +----------------|-----+ +# | $h1 | +# +--------------------------------+------------------------------+ +# | +# +--------------------------------------|------------------------------------+ +# | SW o---> mirror | +# | | | +# | +--------------------------------+------------------------------+ | +# | | $swp1 | | +# | + $swp1.333 $swp1.555 + | +# | 192.0.2.2/28 192.0.2.17/28 | +# | | +# | +-----------------------------------------------------------------------+ | +# | | BR1 (802.1q) | | +# | | + lag (team) 192.0.2.129/28 | | +# | | / \ 2001:db8:2::1/64 | | +# | +---/---\---------------------------------------------------------------+ | +# | / \ ^ | +# | | \ + gt4 (gretap) | | +# | | \ loc=192.0.2.129 | | +# | | \ rem=192.0.2.130 -+ | +# | | \ ttl=100 | +# | | \ tos=inherit | +# | | \ | +# | | \_________________________________ | +# | | \ | +# | + $swp3 + $swp4 | +# +---|------------------------------------------------|----------------------+ +# | | +# +---|----------------------+ +---|----------------------+ +# | + $h3 H3 | | + $h4 H4 | +# | 192.0.2.130/28 | | 192.0.2.130/28 | +# | 2001:db8:2::2/64 | | 2001:db8:2::2/64 | +# +--------------------------+ +--------------------------+ + +ALL_TESTS=" + test_mirror_gretap_first + test_mirror_gretap_second +" + +NUM_NETIFS=6 +source lib.sh +source mirror_lib.sh +source mirror_gre_lib.sh + +require_command $ARPING + +vlan_host_create() +{ + local if_name=$1; shift + local vid=$1; shift + local vrf_name=$1; shift + local ips=("${@}") + + vrf_create $vrf_name + ip link set dev $vrf_name up + vlan_create $if_name $vid $vrf_name "${ips[@]}" +} + +vlan_host_destroy() +{ + local if_name=$1; shift + local vid=$1; shift + local vrf_name=$1; shift + + vlan_destroy $if_name $vid + ip link set dev $vrf_name down + vrf_destroy $vrf_name +} + +h1_create() +{ + vlan_host_create $h1 333 vrf-h1 192.0.2.1/28 + ip -4 route add 192.0.2.16/28 vrf vrf-h1 nexthop via 192.0.2.2 +} + +h1_destroy() +{ + ip -4 route del 192.0.2.16/28 vrf vrf-h1 + vlan_host_destroy $h1 333 vrf-h1 +} + +h2_create() +{ + vlan_host_create $h1 555 vrf-h2 192.0.2.18/28 + ip -4 route add 192.0.2.0/28 vrf vrf-h2 nexthop via 192.0.2.17 +} + +h2_destroy() +{ + ip -4 route del 192.0.2.0/28 vrf vrf-h2 + vlan_host_destroy $h1 555 vrf-h2 +} + +h3_create() +{ + simple_if_init $h3 192.0.2.130/28 + tc qdisc add dev $h3 clsact +} + +h3_destroy() +{ + tc qdisc del dev $h3 clsact + simple_if_fini $h3 192.0.2.130/28 +} + +h4_create() +{ + simple_if_init $h4 192.0.2.130/28 + tc qdisc add dev $h4 clsact +} + +h4_destroy() +{ + tc qdisc del dev $h4 clsact + simple_if_fini $h4 192.0.2.130/28 +} + +switch_create() +{ + ip link set dev $swp1 up + tc qdisc add dev $swp1 clsact + vlan_create $swp1 333 "" 192.0.2.2/28 + vlan_create $swp1 555 "" 192.0.2.17/28 + + tunnel_create gt4 gretap 192.0.2.129 192.0.2.130 \ + ttl 100 tos inherit + + ip link set dev $swp3 up + ip link set dev $swp4 up + + ip link add name br1 type bridge vlan_filtering 1 + ip link set dev br1 up + __addr_add_del br1 add 192.0.2.129/32 + ip -4 route add 192.0.2.130/32 dev br1 + + team_create lag loadbalance $swp3 $swp4 + ip link set dev lag master br1 +} + +switch_destroy() +{ + ip link set dev lag nomaster + team_destroy lag + + ip -4 route del 192.0.2.130/32 dev br1 + __addr_add_del br1 del 192.0.2.129/32 + ip link set dev br1 down + ip link del dev br1 + + ip link set dev $swp4 down + ip link set dev $swp3 down + + tunnel_destroy gt4 + + vlan_destroy $swp1 555 + vlan_destroy $swp1 333 + tc qdisc del dev $swp1 clsact + ip link set dev $swp1 down +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + swp1=${NETIFS[p2]} + + swp3=${NETIFS[p3]} + h3=${NETIFS[p4]} + + swp4=${NETIFS[p5]} + h4=${NETIFS[p6]} + + vrf_prepare + + ip link set dev $h1 up + h1_create + h2_create + h3_create + h4_create + switch_create + + trap_install $h3 ingress + trap_install $h4 ingress +} + +cleanup() +{ + pre_cleanup + + trap_uninstall $h4 ingress + trap_uninstall $h3 ingress + + switch_destroy + h4_destroy + h3_destroy + h2_destroy + h1_destroy + ip link set dev $h1 down + + vrf_cleanup +} + +test_lag_slave() +{ + local host_dev=$1; shift + local up_dev=$1; shift + local down_dev=$1; shift + local what=$1; shift + + RET=0 + + mirror_install $swp1 ingress gt4 \ + "proto 802.1q flower vlan_id 333 $tcflags" + + # Test connectivity through $up_dev when $down_dev is set down. + ip link set dev $down_dev down + setup_wait_dev $up_dev + setup_wait_dev $host_dev + $ARPING -I br1 192.0.2.130 -qfc 1 + sleep 2 + mirror_test vrf-h1 192.0.2.1 192.0.2.18 $host_dev 1 10 + + # Test lack of connectivity when both slaves are down. + ip link set dev $up_dev down + sleep 2 + mirror_test vrf-h1 192.0.2.1 192.0.2.18 $h3 1 0 + mirror_test vrf-h1 192.0.2.1 192.0.2.18 $h4 1 0 + + ip link set dev $up_dev up + ip link set dev $down_dev up + mirror_uninstall $swp1 ingress + + log_test "$what ($tcflags)" +} + +test_mirror_gretap_first() +{ + test_lag_slave $h3 $swp3 $swp4 "mirror to gretap: LAG first slave" +} + +test_mirror_gretap_second() +{ + test_lag_slave $h4 $swp4 $swp3 "mirror to gretap: LAG second slave" +} + +test_all() +{ + slow_path_trap_install $swp1 ingress + slow_path_trap_install $swp1 egress + + tests_run + + slow_path_trap_uninstall $swp1 egress + slow_path_trap_uninstall $swp1 ingress +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +tcflags="skip_hw" +test_all + +if ! tc_offload_check; then + echo "WARN: Could not test offloaded functionality" +else + tcflags="skip_sw" + test_all +fi + +exit $EXIT_STATUS diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_changes.sh b/tools/testing/selftests/net/forwarding/mirror_gre_changes.sh index aa29d46186a8..135902aa8b11 100755 --- a/tools/testing/selftests/net/forwarding/mirror_gre_changes.sh +++ b/tools/testing/selftests/net/forwarding/mirror_gre_changes.sh @@ -122,15 +122,8 @@ test_span_gre_egress_up() # After setting the device up, wait for neighbor to get resolved so that # we can expect mirroring to work. ip link set dev $swp3 up - while true; do - ip neigh sh dev $swp3 $remote_ip nud reachable | - grep -q ^ - if [[ $? -ne 0 ]]; then - sleep 1 - else - break - fi - done + setup_wait_dev $swp3 + ping -c 1 -I $swp3 $remote_ip &>/dev/null quick_test_span_gre_dir $tundev ingress mirror_uninstall $swp1 ingress diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_lag_lacp.sh b/tools/testing/selftests/net/forwarding/mirror_gre_lag_lacp.sh new file mode 100755 index 000000000000..9edf4cb104a8 --- /dev/null +++ b/tools/testing/selftests/net/forwarding/mirror_gre_lag_lacp.sh @@ -0,0 +1,285 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +# Test for "tc action mirred egress mirror" when the underlay route points at a +# team device. +# +# +----------------------+ +----------------------+ +# | H1 | | H2 | +# | + $h1.333 | | $h1.555 + | +# | | 192.0.2.1/28 | | 192.0.2.18/28 | | +# +----|-----------------+ +----------------|-----+ +# | $h1 | +# +---------------------------------+------------------------------+ +# | +# +--------------------------------------|------------------------------------+ +# | SW o---> mirror | +# | | | +# | +----------------------------------+------------------------------+ | +# | | $swp1 | | +# | + $swp1.333 $swp1.555 + | +# | 192.0.2.2/28 192.0.2.17/28 | +# | | +# | | +# | + gt4 (gretap) ,-> + lag1 (team) | +# | loc=192.0.2.129 | | 192.0.2.129/28 | +# | rem=192.0.2.130 --' | | +# | ttl=100 | | +# | tos=inherit | | +# | _____________________|______________________ | +# | / \ | +# | / \ | +# | + $swp3 + $swp4 | +# +---|------------------------------------------------|----------------------+ +# | | +# +---|------------------------------------------------|----------------------+ +# | + $h3 + $h4 H3 | +# | \ / | +# | \____________________________________________/ | +# | | | +# | + lag2 (team) | +# | 192.0.2.130/28 | +# | | +# +---------------------------------------------------------------------------+ + +ALL_TESTS=" + test_mirror_gretap_first + test_mirror_gretap_second +" + +NUM_NETIFS=6 +source lib.sh +source mirror_lib.sh +source mirror_gre_lib.sh + +require_command $ARPING + +vlan_host_create() +{ + local if_name=$1; shift + local vid=$1; shift + local vrf_name=$1; shift + local ips=("${@}") + + vrf_create $vrf_name + ip link set dev $vrf_name up + vlan_create $if_name $vid $vrf_name "${ips[@]}" +} + +vlan_host_destroy() +{ + local if_name=$1; shift + local vid=$1; shift + local vrf_name=$1; shift + + vlan_destroy $if_name $vid + ip link set dev $vrf_name down + vrf_destroy $vrf_name +} + +h1_create() +{ + vlan_host_create $h1 333 vrf-h1 192.0.2.1/28 + ip -4 route add 192.0.2.16/28 vrf vrf-h1 nexthop via 192.0.2.2 +} + +h1_destroy() +{ + ip -4 route del 192.0.2.16/28 vrf vrf-h1 + vlan_host_destroy $h1 333 vrf-h1 +} + +h2_create() +{ + vlan_host_create $h1 555 vrf-h2 192.0.2.18/28 + ip -4 route add 192.0.2.0/28 vrf vrf-h2 nexthop via 192.0.2.17 +} + +h2_destroy() +{ + ip -4 route del 192.0.2.0/28 vrf vrf-h2 + vlan_host_destroy $h1 555 vrf-h2 +} + +h3_create_team() +{ + team_create lag2 lacp $h3 $h4 + __simple_if_init lag2 vrf-h3 192.0.2.130/32 + ip -4 route add vrf vrf-h3 192.0.2.129/32 dev lag2 +} + +h3_destroy_team() +{ + ip -4 route del vrf vrf-h3 192.0.2.129/32 dev lag2 + __simple_if_fini lag2 192.0.2.130/32 + team_destroy lag2 + + ip link set dev $h3 down + ip link set dev $h4 down +} + +h3_create() +{ + vrf_create vrf-h3 + ip link set dev vrf-h3 up + tc qdisc add dev $h3 clsact + tc qdisc add dev $h4 clsact + h3_create_team +} + +h3_destroy() +{ + h3_destroy_team + tc qdisc del dev $h4 clsact + tc qdisc del dev $h3 clsact + ip link set dev vrf-h3 down + vrf_destroy vrf-h3 +} + +switch_create() +{ + ip link set dev $swp1 up + tc qdisc add dev $swp1 clsact + vlan_create $swp1 333 "" 192.0.2.2/28 + vlan_create $swp1 555 "" 192.0.2.17/28 + + tunnel_create gt4 gretap 192.0.2.129 192.0.2.130 \ + ttl 100 tos inherit + + ip link set dev $swp3 up + ip link set dev $swp4 up + team_create lag1 lacp $swp3 $swp4 + __addr_add_del lag1 add 192.0.2.129/32 + ip -4 route add 192.0.2.130/32 dev lag1 +} + +switch_destroy() +{ + ip -4 route del 192.0.2.130/32 dev lag1 + __addr_add_del lag1 del 192.0.2.129/32 + team_destroy lag1 + + ip link set dev $swp4 down + ip link set dev $swp3 down + + tunnel_destroy gt4 + + vlan_destroy $swp1 555 + vlan_destroy $swp1 333 + tc qdisc del dev $swp1 clsact + ip link set dev $swp1 down +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + swp1=${NETIFS[p2]} + + swp3=${NETIFS[p3]} + h3=${NETIFS[p4]} + + swp4=${NETIFS[p5]} + h4=${NETIFS[p6]} + + vrf_prepare + + ip link set dev $h1 up + h1_create + h2_create + h3_create + switch_create + + trap_install $h3 ingress + trap_install $h4 ingress +} + +cleanup() +{ + pre_cleanup + + trap_uninstall $h4 ingress + trap_uninstall $h3 ingress + + switch_destroy + h3_destroy + h2_destroy + h1_destroy + ip link set dev $h1 down + + vrf_cleanup +} + +test_lag_slave() +{ + local up_dev=$1; shift + local down_dev=$1; shift + local what=$1; shift + + RET=0 + + mirror_install $swp1 ingress gt4 \ + "proto 802.1q flower vlan_id 333 $tcflags" + + # Move $down_dev away from the team. That will prompt change in + # txability of the connected device, without changing its upness. The + # driver should notice the txability change and move the traffic to the + # other slave. + ip link set dev $down_dev nomaster + sleep 2 + mirror_test vrf-h1 192.0.2.1 192.0.2.18 $up_dev 1 10 + + # Test lack of connectivity when neither slave is txable. + ip link set dev $up_dev nomaster + sleep 2 + mirror_test vrf-h1 192.0.2.1 192.0.2.18 $h3 1 0 + mirror_test vrf-h1 192.0.2.1 192.0.2.18 $h4 1 0 + mirror_uninstall $swp1 ingress + + # Recreate H3's team device, because mlxsw, which this test is + # predominantly mean to test, requires a bottom-up construction and + # doesn't allow enslavement to a device that already has an upper. + h3_destroy_team + h3_create_team + # Wait for ${h,swp}{3,4}. + setup_wait + + log_test "$what ($tcflags)" +} + +test_mirror_gretap_first() +{ + test_lag_slave $h3 $h4 "mirror to gretap: LAG first slave" +} + +test_mirror_gretap_second() +{ + test_lag_slave $h4 $h3 "mirror to gretap: LAG second slave" +} + +test_all() +{ + slow_path_trap_install $swp1 ingress + slow_path_trap_install $swp1 egress + + tests_run + + slow_path_trap_uninstall $swp1 egress + slow_path_trap_uninstall $swp1 ingress +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +tcflags="skip_hw" +test_all + +if ! tc_offload_check; then + echo "WARN: Could not test offloaded functionality" +else + tcflags="skip_sw" + test_all +fi + +exit $EXIT_STATUS diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_lib.sh b/tools/testing/selftests/net/forwarding/mirror_gre_lib.sh index 619b469365be..fac486178ef7 100644 --- a/tools/testing/selftests/net/forwarding/mirror_gre_lib.sh +++ b/tools/testing/selftests/net/forwarding/mirror_gre_lib.sh @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -source mirror_lib.sh +source "$relative_path/mirror_lib.sh" quick_test_span_gre_dir_ips() { @@ -62,7 +62,7 @@ full_test_span_gre_dir_vlan_ips() "$backward_type" "$ip1" "$ip2" tc filter add dev $h3 ingress pref 77 prot 802.1q \ - flower $vlan_match ip_proto 0x2f \ + flower $vlan_match \ action pass mirror_test v$h1 $ip1 $ip2 $h3 77 10 tc filter del dev $h3 ingress pref 77 diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_nh.sh b/tools/testing/selftests/net/forwarding/mirror_gre_nh.sh index 8fa681eb90e7..6f9ef1820e93 100755 --- a/tools/testing/selftests/net/forwarding/mirror_gre_nh.sh +++ b/tools/testing/selftests/net/forwarding/mirror_gre_nh.sh @@ -35,6 +35,8 @@ setup_prepare() vrf_prepare mirror_gre_topo_create + sysctl_set net.ipv4.conf.v$h3.rp_filter 0 + ip address add dev $swp3 192.0.2.161/28 ip address add dev $h3 192.0.2.162/28 ip address add dev gt4 192.0.2.129/32 @@ -61,6 +63,8 @@ cleanup() ip address del dev $h3 192.0.2.162/28 ip address del dev $swp3 192.0.2.161/28 + sysctl_restore net.ipv4.conf.v$h3.rp_filter 0 + mirror_gre_topo_destroy vrf_cleanup diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_topo_lib.sh b/tools/testing/selftests/net/forwarding/mirror_gre_topo_lib.sh index 253419564708..39c03e2867f4 100644 --- a/tools/testing/selftests/net/forwarding/mirror_gre_topo_lib.sh +++ b/tools/testing/selftests/net/forwarding/mirror_gre_topo_lib.sh @@ -33,7 +33,7 @@ # | | # +-------------------------------------------------------------------------+ -source mirror_topo_lib.sh +source "$relative_path/mirror_topo_lib.sh" mirror_gre_topo_h3_create() { diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_vlan_bridge_1q.sh b/tools/testing/selftests/net/forwarding/mirror_gre_vlan_bridge_1q.sh index 5dbc7a08f4bd..204b25f13934 100755 --- a/tools/testing/selftests/net/forwarding/mirror_gre_vlan_bridge_1q.sh +++ b/tools/testing/selftests/net/forwarding/mirror_gre_vlan_bridge_1q.sh @@ -28,6 +28,8 @@ source mirror_lib.sh source mirror_gre_lib.sh source mirror_gre_topo_lib.sh +require_command $ARPING + setup_prepare() { h1=${NETIFS[p1]} @@ -39,6 +41,12 @@ setup_prepare() swp3=${NETIFS[p5]} h3=${NETIFS[p6]} + # gt4's remote address is at $h3.555, not $h3. Thus the packets arriving + # directly to $h3 for test_gretap_untagged_egress() are rejected by + # rp_filter and the test spuriously fails. + sysctl_set net.ipv4.conf.all.rp_filter 0 + sysctl_set net.ipv4.conf.$h3.rp_filter 0 + vrf_prepare mirror_gre_topo_create @@ -65,6 +73,9 @@ cleanup() mirror_gre_topo_destroy vrf_cleanup + + sysctl_restore net.ipv4.conf.$h3.rp_filter + sysctl_restore net.ipv4.conf.all.rp_filter } test_vlan_match() @@ -79,12 +90,14 @@ test_vlan_match() test_gretap() { - test_vlan_match gt4 'vlan_id 555 vlan_ethtype ip' "mirror to gretap" + test_vlan_match gt4 'skip_hw vlan_id 555 vlan_ethtype ip' \ + "mirror to gretap" } test_ip6gretap() { - test_vlan_match gt6 'vlan_id 555 vlan_ethtype ipv6' "mirror to ip6gretap" + test_vlan_match gt6 'skip_hw vlan_id 555 vlan_ethtype ip' \ + "mirror to ip6gretap" } test_span_gre_forbidden_cpu() @@ -138,7 +151,7 @@ test_span_gre_forbidden_egress() bridge vlan add dev $swp3 vid 555 # Re-prime FDB - arping -I br1.555 192.0.2.130 -fqc 1 + $ARPING -I br1.555 192.0.2.130 -fqc 1 sleep 1 quick_test_span_gre_dir $tundev ingress @@ -212,7 +225,7 @@ test_span_gre_fdb_roaming() bridge fdb del dev $swp2 $h3mac vlan 555 master # Re-prime FDB - arping -I br1.555 192.0.2.130 -fqc 1 + $ARPING -I br1.555 192.0.2.130 -fqc 1 sleep 1 quick_test_span_gre_dir $tundev ingress diff --git a/tools/testing/selftests/net/forwarding/mirror_lib.sh b/tools/testing/selftests/net/forwarding/mirror_lib.sh index d36dc26c6c51..07991e1025c7 100644 --- a/tools/testing/selftests/net/forwarding/mirror_lib.sh +++ b/tools/testing/selftests/net/forwarding/mirror_lib.sh @@ -105,7 +105,7 @@ do_test_span_vlan_dir_ips() # Install the capture as skip_hw to avoid double-counting of packets. # The traffic is meant for local box anyway, so will be trapped to # kernel. - vlan_capture_install $dev "skip_hw vlan_id $vid" + vlan_capture_install $dev "skip_hw vlan_id $vid vlan_ethtype ip" mirror_test v$h1 $ip1 $ip2 $dev 100 $expect mirror_test v$h2 $ip2 $ip1 $dev 100 $expect vlan_capture_uninstall $dev diff --git a/tools/testing/selftests/net/forwarding/router_bridge.sh b/tools/testing/selftests/net/forwarding/router_bridge.sh new file mode 100755 index 000000000000..ebc596a272f7 --- /dev/null +++ b/tools/testing/selftests/net/forwarding/router_bridge.sh @@ -0,0 +1,113 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +ALL_TESTS=" + ping_ipv4 + ping_ipv6 +" +NUM_NETIFS=4 +source lib.sh + +h1_create() +{ + simple_if_init $h1 192.0.2.1/28 2001:db8:1::1/64 + ip -4 route add 192.0.2.128/28 vrf v$h1 nexthop via 192.0.2.2 + ip -6 route add 2001:db8:2::/64 vrf v$h1 nexthop via 2001:db8:1::2 +} + +h1_destroy() +{ + ip -6 route del 2001:db8:2::/64 vrf v$h1 + ip -4 route del 192.0.2.128/28 vrf v$h1 + simple_if_fini $h1 192.0.2.1/28 2001:db8:1::1/64 +} + +h2_create() +{ + simple_if_init $h2 192.0.2.130/28 2001:db8:2::2/64 + ip -4 route add 192.0.2.0/28 vrf v$h2 nexthop via 192.0.2.129 + ip -6 route add 2001:db8:1::/64 vrf v$h2 nexthop via 2001:db8:2::1 +} + +h2_destroy() +{ + ip -6 route del 2001:db8:1::/64 vrf v$h2 + ip -4 route del 192.0.2.0/28 vrf v$h2 + simple_if_fini $h2 192.0.2.130/28 2001:db8:2::2/64 +} + +router_create() +{ + ip link add name br1 type bridge vlan_filtering 1 + ip link set dev br1 up + + ip link set dev $swp1 master br1 + ip link set dev $swp1 up + __addr_add_del br1 add 192.0.2.2/28 2001:db8:1::2/64 + + ip link set dev $swp2 up + __addr_add_del $swp2 add 192.0.2.129/28 2001:db8:2::1/64 +} + +router_destroy() +{ + __addr_add_del $swp2 del 192.0.2.129/28 2001:db8:2::1/64 + ip link set dev $swp2 down + + __addr_add_del br1 del 192.0.2.2/28 2001:db8:1::2/64 + ip link set dev $swp1 down + ip link set dev $swp1 nomaster + + ip link del dev br1 +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + swp1=${NETIFS[p2]} + + swp2=${NETIFS[p3]} + h2=${NETIFS[p4]} + + vrf_prepare + + h1_create + h2_create + + router_create + + forwarding_enable +} + +cleanup() +{ + pre_cleanup + + forwarding_restore + + router_destroy + + h2_destroy + h1_destroy + + vrf_cleanup +} + +ping_ipv4() +{ + ping_test $h1 192.0.2.130 +} + +ping_ipv6() +{ + ping6_test $h1 2001:db8:2::2 +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +tests_run + +exit $EXIT_STATUS diff --git a/tools/testing/selftests/net/forwarding/router_bridge_vlan.sh b/tools/testing/selftests/net/forwarding/router_bridge_vlan.sh new file mode 100755 index 000000000000..fef88eb4b873 --- /dev/null +++ b/tools/testing/selftests/net/forwarding/router_bridge_vlan.sh @@ -0,0 +1,132 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +ALL_TESTS=" + ping_ipv4 + ping_ipv6 + vlan +" +NUM_NETIFS=4 +source lib.sh + +h1_create() +{ + simple_if_init $h1 + vlan_create $h1 555 v$h1 192.0.2.1/28 2001:db8:1::1/64 + ip -4 route add 192.0.2.128/28 vrf v$h1 nexthop via 192.0.2.2 + ip -6 route add 2001:db8:2::/64 vrf v$h1 nexthop via 2001:db8:1::2 +} + +h1_destroy() +{ + ip -6 route del 2001:db8:2::/64 vrf v$h1 + ip -4 route del 192.0.2.128/28 vrf v$h1 + vlan_destroy $h1 555 + simple_if_fini $h1 +} + +h2_create() +{ + simple_if_init $h2 192.0.2.130/28 2001:db8:2::2/64 + ip -4 route add 192.0.2.0/28 vrf v$h2 nexthop via 192.0.2.129 + ip -6 route add 2001:db8:1::/64 vrf v$h2 nexthop via 2001:db8:2::1 +} + +h2_destroy() +{ + ip -6 route del 2001:db8:1::/64 vrf v$h2 + ip -4 route del 192.0.2.0/28 vrf v$h2 + simple_if_fini $h2 192.0.2.130/28 +} + +router_create() +{ + ip link add name br1 type bridge vlan_filtering 1 + ip link set dev br1 up + + ip link set dev $swp1 master br1 + ip link set dev $swp1 up + + bridge vlan add dev br1 vid 555 self pvid untagged + bridge vlan add dev $swp1 vid 555 + + __addr_add_del br1 add 192.0.2.2/28 2001:db8:1::2/64 + + ip link set dev $swp2 up + __addr_add_del $swp2 add 192.0.2.129/28 2001:db8:2::1/64 +} + +router_destroy() +{ + __addr_add_del $swp2 del 192.0.2.129/28 2001:db8:2::1/64 + ip link set dev $swp2 down + + __addr_add_del br1 del 192.0.2.2/28 2001:db8:1::2/64 + ip link set dev $swp1 down + ip link set dev $swp1 nomaster + + ip link del dev br1 +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + swp1=${NETIFS[p2]} + + swp2=${NETIFS[p3]} + h2=${NETIFS[p4]} + + vrf_prepare + + h1_create + h2_create + + router_create + + forwarding_enable +} + +cleanup() +{ + pre_cleanup + + forwarding_restore + + router_destroy + + h2_destroy + h1_destroy + + vrf_cleanup +} + +vlan() +{ + RET=0 + + bridge vlan add dev br1 vid 333 self + check_err $? "Can't add a non-PVID VLAN" + bridge vlan del dev br1 vid 333 self + check_err $? "Can't remove a non-PVID VLAN" + + log_test "vlan" +} + +ping_ipv4() +{ + ping_test $h1 192.0.2.130 +} + +ping_ipv6() +{ + ping6_test $h1 2001:db8:2::2 +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +tests_run + +exit $EXIT_STATUS diff --git a/tools/testing/selftests/net/forwarding/router_broadcast.sh b/tools/testing/selftests/net/forwarding/router_broadcast.sh new file mode 100755 index 000000000000..7bd2ebb6e9de --- /dev/null +++ b/tools/testing/selftests/net/forwarding/router_broadcast.sh @@ -0,0 +1,233 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +ALL_TESTS="ping_ipv4" +NUM_NETIFS=6 +source lib.sh + +h1_create() +{ + vrf_create "vrf-h1" + ip link set dev $h1 master vrf-h1 + + ip link set dev vrf-h1 up + ip link set dev $h1 up + + ip address add 192.0.2.2/24 dev $h1 + + ip route add 198.51.100.0/24 vrf vrf-h1 nexthop via 192.0.2.1 + ip route add 198.51.200.0/24 vrf vrf-h1 nexthop via 192.0.2.1 +} + +h1_destroy() +{ + ip route del 198.51.200.0/24 vrf vrf-h1 + ip route del 198.51.100.0/24 vrf vrf-h1 + + ip address del 192.0.2.2/24 dev $h1 + + ip link set dev $h1 down + vrf_destroy "vrf-h1" +} + +h2_create() +{ + vrf_create "vrf-h2" + ip link set dev $h2 master vrf-h2 + + ip link set dev vrf-h2 up + ip link set dev $h2 up + + ip address add 198.51.100.2/24 dev $h2 + + ip route add 192.0.2.0/24 vrf vrf-h2 nexthop via 198.51.100.1 + ip route add 198.51.200.0/24 vrf vrf-h2 nexthop via 198.51.100.1 +} + +h2_destroy() +{ + ip route del 198.51.200.0/24 vrf vrf-h2 + ip route del 192.0.2.0/24 vrf vrf-h2 + + ip address del 198.51.100.2/24 dev $h2 + + ip link set dev $h2 down + vrf_destroy "vrf-h2" +} + +h3_create() +{ + vrf_create "vrf-h3" + ip link set dev $h3 master vrf-h3 + + ip link set dev vrf-h3 up + ip link set dev $h3 up + + ip address add 198.51.200.2/24 dev $h3 + + ip route add 192.0.2.0/24 vrf vrf-h3 nexthop via 198.51.200.1 + ip route add 198.51.100.0/24 vrf vrf-h3 nexthop via 198.51.200.1 +} + +h3_destroy() +{ + ip route del 198.51.100.0/24 vrf vrf-h3 + ip route del 192.0.2.0/24 vrf vrf-h3 + + ip address del 198.51.200.2/24 dev $h3 + + ip link set dev $h3 down + vrf_destroy "vrf-h3" +} + +router_create() +{ + ip link set dev $rp1 up + ip link set dev $rp2 up + ip link set dev $rp3 up + + ip address add 192.0.2.1/24 dev $rp1 + + ip address add 198.51.100.1/24 dev $rp2 + ip address add 198.51.200.1/24 dev $rp3 +} + +router_destroy() +{ + ip address del 198.51.200.1/24 dev $rp3 + ip address del 198.51.100.1/24 dev $rp2 + + ip address del 192.0.2.1/24 dev $rp1 + + ip link set dev $rp3 down + ip link set dev $rp2 down + ip link set dev $rp1 down +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + rp1=${NETIFS[p2]} + + rp2=${NETIFS[p3]} + h2=${NETIFS[p4]} + + rp3=${NETIFS[p5]} + h3=${NETIFS[p6]} + + vrf_prepare + + h1_create + h2_create + h3_create + + router_create + + forwarding_enable +} + +cleanup() +{ + pre_cleanup + + forwarding_restore + + router_destroy + + h3_destroy + h2_destroy + h1_destroy + + vrf_cleanup +} + +bc_forwarding_disable() +{ + sysctl_set net.ipv4.conf.all.bc_forwarding 0 + sysctl_set net.ipv4.conf.$rp1.bc_forwarding 0 +} + +bc_forwarding_enable() +{ + sysctl_set net.ipv4.conf.all.bc_forwarding 1 + sysctl_set net.ipv4.conf.$rp1.bc_forwarding 1 +} + +bc_forwarding_restore() +{ + sysctl_restore net.ipv4.conf.$rp1.bc_forwarding + sysctl_restore net.ipv4.conf.all.bc_forwarding +} + +ping_test_from() +{ + local oif=$1 + local dip=$2 + local from=$3 + local fail=${4:-0} + + RET=0 + + log_info "ping $dip, expected reply from $from" + ip vrf exec $(master_name_get $oif) \ + $PING -I $oif $dip -c 10 -i 0.1 -w 2 -b 2>&1 | grep $from &> /dev/null + check_err_fail $fail $? +} + +ping_ipv4() +{ + sysctl_set net.ipv4.icmp_echo_ignore_broadcasts 0 + + bc_forwarding_disable + log_info "bc_forwarding disabled on r1 =>" + ping_test_from $h1 198.51.100.255 192.0.2.1 + log_test "h1 -> net2: reply from r1 (not forwarding)" + ping_test_from $h1 198.51.200.255 192.0.2.1 + log_test "h1 -> net3: reply from r1 (not forwarding)" + ping_test_from $h1 192.0.2.255 192.0.2.1 + log_test "h1 -> net1: reply from r1 (not dropping)" + ping_test_from $h1 255.255.255.255 192.0.2.1 + log_test "h1 -> 255.255.255.255: reply from r1 (not forwarding)" + + ping_test_from $h2 192.0.2.255 198.51.100.1 + log_test "h2 -> net1: reply from r1 (not forwarding)" + ping_test_from $h2 198.51.200.255 198.51.100.1 + log_test "h2 -> net3: reply from r1 (not forwarding)" + ping_test_from $h2 198.51.100.255 198.51.100.1 + log_test "h2 -> net2: reply from r1 (not dropping)" + ping_test_from $h2 255.255.255.255 198.51.100.1 + log_test "h2 -> 255.255.255.255: reply from r1 (not forwarding)" + bc_forwarding_restore + + bc_forwarding_enable + log_info "bc_forwarding enabled on r1 =>" + ping_test_from $h1 198.51.100.255 198.51.100.2 + log_test "h1 -> net2: reply from h2 (forwarding)" + ping_test_from $h1 198.51.200.255 198.51.200.2 + log_test "h1 -> net3: reply from h3 (forwarding)" + ping_test_from $h1 192.0.2.255 192.0.2.1 1 + log_test "h1 -> net1: no reply (dropping)" + ping_test_from $h1 255.255.255.255 192.0.2.1 + log_test "h1 -> 255.255.255.255: reply from r1 (not forwarding)" + + ping_test_from $h2 192.0.2.255 192.0.2.2 + log_test "h2 -> net1: reply from h1 (forwarding)" + ping_test_from $h2 198.51.200.255 198.51.200.2 + log_test "h2 -> net3: reply from h3 (forwarding)" + ping_test_from $h2 198.51.100.255 198.51.100.1 1 + log_test "h2 -> net2: no reply (dropping)" + ping_test_from $h2 255.255.255.255 198.51.100.1 + log_test "h2 -> 255.255.255.255: reply from r1 (not forwarding)" + bc_forwarding_restore + + sysctl_restore net.ipv4.icmp_echo_ignore_broadcasts +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +tests_run + +exit $EXIT_STATUS diff --git a/tools/testing/selftests/net/forwarding/router_multipath.sh b/tools/testing/selftests/net/forwarding/router_multipath.sh index 8b6d0fb6d604..79a209927962 100755 --- a/tools/testing/selftests/net/forwarding/router_multipath.sh +++ b/tools/testing/selftests/net/forwarding/router_multipath.sh @@ -159,45 +159,6 @@ router2_destroy() vrf_destroy "vrf-r2" } -multipath_eval() -{ - local desc="$1" - local weight_rp12=$2 - local weight_rp13=$3 - local packets_rp12=$4 - local packets_rp13=$5 - local weights_ratio packets_ratio diff - - RET=0 - - if [[ "$packets_rp12" -eq "0" || "$packets_rp13" -eq "0" ]]; then - check_err 1 "Packet difference is 0" - log_test "Multipath" - log_info "Expected ratio $weights_ratio" - return - fi - - if [[ "$weight_rp12" -gt "$weight_rp13" ]]; then - weights_ratio=$(echo "scale=2; $weight_rp12 / $weight_rp13" \ - | bc -l) - packets_ratio=$(echo "scale=2; $packets_rp12 / $packets_rp13" \ - | bc -l) - else - weights_ratio=$(echo "scale=2; $weight_rp13 / $weight_rp12" | \ - bc -l) - packets_ratio=$(echo "scale=2; $packets_rp13 / $packets_rp12" | \ - bc -l) - fi - - diff=$(echo $weights_ratio - $packets_ratio | bc -l) - diff=${diff#-} - - test "$(echo "$diff / $weights_ratio > 0.15" | bc -l)" -eq 0 - check_err $? "Too large discrepancy between expected and measured ratios" - log_test "$desc" - log_info "Expected ratio $weights_ratio Measured ratio $packets_ratio" -} - multipath4_test() { local desc="$1" diff --git a/tools/testing/selftests/net/forwarding/tc_chains.sh b/tools/testing/selftests/net/forwarding/tc_chains.sh index d2c783e94df3..2934fb5ed2a2 100755 --- a/tools/testing/selftests/net/forwarding/tc_chains.sh +++ b/tools/testing/selftests/net/forwarding/tc_chains.sh @@ -1,7 +1,8 @@ #!/bin/bash # SPDX-License-Identifier: GPL-2.0 -ALL_TESTS="unreachable_chain_test gact_goto_chain_test" +ALL_TESTS="unreachable_chain_test gact_goto_chain_test create_destroy_chain \ + template_filter_fits" NUM_NETIFS=2 source tc_common.sh source lib.sh @@ -80,6 +81,87 @@ gact_goto_chain_test() log_test "gact goto chain ($tcflags)" } +create_destroy_chain() +{ + RET=0 + + tc chain add dev $h2 ingress + check_err $? "Failed to create default chain" + + output="$(tc -j chain get dev $h2 ingress)" + check_err $? "Failed to get default chain" + + echo $output | jq -e ".[] | select(.chain == 0)" &> /dev/null + check_err $? "Unexpected output for default chain" + + tc chain add dev $h2 ingress chain 1 + check_err $? "Failed to create chain 1" + + output="$(tc -j chain get dev $h2 ingress chain 1)" + check_err $? "Failed to get chain 1" + + echo $output | jq -e ".[] | select(.chain == 1)" &> /dev/null + check_err $? "Unexpected output for chain 1" + + output="$(tc -j chain show dev $h2 ingress)" + check_err $? "Failed to dump chains" + + echo $output | jq -e ".[] | select(.chain == 0)" &> /dev/null + check_err $? "Can't find default chain in dump" + + echo $output | jq -e ".[] | select(.chain == 1)" &> /dev/null + check_err $? "Can't find chain 1 in dump" + + tc chain del dev $h2 ingress + check_err $? "Failed to destroy default chain" + + tc chain del dev $h2 ingress chain 1 + check_err $? "Failed to destroy chain 1" + + log_test "create destroy chain" +} + +template_filter_fits() +{ + RET=0 + + tc chain add dev $h2 ingress protocol ip \ + flower dst_mac 00:00:00:00:00:00/FF:FF:FF:FF:FF:FF &> /dev/null + tc chain add dev $h2 ingress chain 1 protocol ip \ + flower src_mac 00:00:00:00:00:00/FF:FF:FF:FF:FF:FF &> /dev/null + + tc filter add dev $h2 ingress protocol ip pref 1 handle 1101 \ + flower dst_mac $h2mac action drop + check_err $? "Failed to insert filter which fits template" + + tc filter add dev $h2 ingress protocol ip pref 1 handle 1102 \ + flower src_mac $h2mac action drop &> /dev/null + check_fail $? "Incorrectly succeded to insert filter which does not template" + + tc filter add dev $h2 ingress chain 1 protocol ip pref 1 handle 1101 \ + flower src_mac $h2mac action drop + check_err $? "Failed to insert filter which fits template" + + tc filter add dev $h2 ingress chain 1 protocol ip pref 1 handle 1102 \ + flower dst_mac $h2mac action drop &> /dev/null + check_fail $? "Incorrectly succeded to insert filter which does not template" + + tc filter del dev $h2 ingress chain 1 protocol ip pref 1 handle 1102 \ + flower &> /dev/null + tc filter del dev $h2 ingress chain 1 protocol ip pref 1 handle 1101 \ + flower &> /dev/null + + tc filter del dev $h2 ingress protocol ip pref 1 handle 1102 \ + flower &> /dev/null + tc filter del dev $h2 ingress protocol ip pref 1 handle 1101 \ + flower &> /dev/null + + tc chain del dev $h2 ingress chain 1 + tc chain del dev $h2 ingress + + log_test "template filter fits" +} + setup_prepare() { h1=${NETIFS[p1]} @@ -103,6 +185,8 @@ cleanup() vrf_cleanup } +check_tc_chain_support + trap cleanup EXIT setup_prepare diff --git a/tools/testing/selftests/net/forwarding/tc_shblocks.sh b/tools/testing/selftests/net/forwarding/tc_shblocks.sh index b5b917203815..9826a446e2c0 100755 --- a/tools/testing/selftests/net/forwarding/tc_shblocks.sh +++ b/tools/testing/selftests/net/forwarding/tc_shblocks.sh @@ -105,6 +105,8 @@ cleanup() ip link set $swp2 address $swp2origmac } +check_tc_shblock_support + trap cleanup EXIT setup_prepare diff --git a/tools/testing/selftests/net/ip6_gre_headroom.sh b/tools/testing/selftests/net/ip6_gre_headroom.sh new file mode 100755 index 000000000000..5b41e8bb6e2d --- /dev/null +++ b/tools/testing/selftests/net/ip6_gre_headroom.sh @@ -0,0 +1,65 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Test that enough headroom is reserved for the first packet passing through an +# IPv6 GRE-like netdevice. + +setup_prepare() +{ + ip link add h1 type veth peer name swp1 + ip link add h3 type veth peer name swp3 + + ip link set dev h1 up + ip address add 192.0.2.1/28 dev h1 + + ip link add dev vh3 type vrf table 20 + ip link set dev h3 master vh3 + ip link set dev vh3 up + ip link set dev h3 up + + ip link set dev swp3 up + ip address add dev swp3 2001:db8:2::1/64 + ip address add dev swp3 2001:db8:2::3/64 + + ip link set dev swp1 up + tc qdisc add dev swp1 clsact + + ip link add name er6 type ip6erspan \ + local 2001:db8:2::1 remote 2001:db8:2::2 oseq okey 123 + ip link set dev er6 up + + ip link add name gt6 type ip6gretap \ + local 2001:db8:2::3 remote 2001:db8:2::4 + ip link set dev gt6 up + + sleep 1 +} + +cleanup() +{ + ip link del dev gt6 + ip link del dev er6 + ip link del dev swp1 + ip link del dev swp3 + ip link del dev vh3 +} + +test_headroom() +{ + local type=$1; shift + local tundev=$1; shift + + tc filter add dev swp1 ingress pref 1000 matchall skip_hw \ + action mirred egress mirror dev $tundev + ping -I h1 192.0.2.2 -c 1 -w 2 &> /dev/null + tc filter del dev swp1 ingress pref 1000 + + # If it doesn't panic, it passes. + printf "TEST: %-60s [PASS]\n" "$type headroom" +} + +trap cleanup EXIT + +setup_prepare +test_headroom ip6gretap gt6 +test_headroom ip6erspan er6 diff --git a/tools/testing/selftests/net/rtnetlink.sh b/tools/testing/selftests/net/rtnetlink.sh index 0d7a44fa30af..08c341b49760 100755 --- a/tools/testing/selftests/net/rtnetlink.sh +++ b/tools/testing/selftests/net/rtnetlink.sh @@ -525,18 +525,21 @@ kci_test_macsec() #------------------------------------------------------------------- kci_test_ipsec() { - srcip="14.0.0.52" - dstip="14.0.0.70" + ret=0 algo="aead rfc4106(gcm(aes)) 0x3132333435363738393031323334353664636261 128" + srcip=192.168.123.1 + dstip=192.168.123.2 + spi=7 + + ip addr add $srcip dev $devdummy # flush to be sure there's nothing configured ip x s flush ; ip x p flush check_err $? # start the monitor in the background - tmpfile=`mktemp ipsectestXXX` - ip x m > $tmpfile & - mpid=$! + tmpfile=`mktemp /var/run/ipsectestXXX` + mpid=`(ip x m > $tmpfile & echo $!) 2>/dev/null` sleep 0.2 ipsecid="proto esp src $srcip dst $dstip spi 0x07" @@ -599,6 +602,7 @@ kci_test_ipsec() check_err $? ip x p flush check_err $? + ip addr del $srcip/32 dev $devdummy if [ $ret -ne 0 ]; then echo "FAIL: ipsec" @@ -607,6 +611,119 @@ kci_test_ipsec() echo "PASS: ipsec" } +#------------------------------------------------------------------- +# Example commands +# ip x s add proto esp src 14.0.0.52 dst 14.0.0.70 \ +# spi 0x07 mode transport reqid 0x07 replay-window 32 \ +# aead 'rfc4106(gcm(aes))' 1234567890123456dcba 128 \ +# sel src 14.0.0.52/24 dst 14.0.0.70/24 +# offload dev sim1 dir out +# ip x p add dir out src 14.0.0.52/24 dst 14.0.0.70/24 \ +# tmpl proto esp src 14.0.0.52 dst 14.0.0.70 \ +# spi 0x07 mode transport reqid 0x07 +# +#------------------------------------------------------------------- +kci_test_ipsec_offload() +{ + ret=0 + algo="aead rfc4106(gcm(aes)) 0x3132333435363738393031323334353664636261 128" + srcip=192.168.123.3 + dstip=192.168.123.4 + dev=simx1 + sysfsd=/sys/kernel/debug/netdevsim/$dev + sysfsf=$sysfsd/ipsec + + # setup netdevsim since dummydev doesn't have offload support + modprobe netdevsim + check_err $? + if [ $ret -ne 0 ]; then + echo "FAIL: ipsec_offload can't load netdevsim" + return 1 + fi + + ip link add $dev type netdevsim + ip addr add $srcip dev $dev + ip link set $dev up + if [ ! -d $sysfsd ] ; then + echo "FAIL: ipsec_offload can't create device $dev" + return 1 + fi + if [ ! -f $sysfsf ] ; then + echo "FAIL: ipsec_offload netdevsim doesn't support IPsec offload" + return 1 + fi + + # flush to be sure there's nothing configured + ip x s flush ; ip x p flush + + # create offloaded SAs, both in and out + ip x p add dir out src $srcip/24 dst $dstip/24 \ + tmpl proto esp src $srcip dst $dstip spi 9 \ + mode transport reqid 42 + check_err $? + ip x p add dir out src $dstip/24 dst $srcip/24 \ + tmpl proto esp src $dstip dst $srcip spi 9 \ + mode transport reqid 42 + check_err $? + + ip x s add proto esp src $srcip dst $dstip spi 9 \ + mode transport reqid 42 $algo sel src $srcip/24 dst $dstip/24 \ + offload dev $dev dir out + check_err $? + ip x s add proto esp src $dstip dst $srcip spi 9 \ + mode transport reqid 42 $algo sel src $dstip/24 dst $srcip/24 \ + offload dev $dev dir in + check_err $? + if [ $ret -ne 0 ]; then + echo "FAIL: ipsec_offload can't create SA" + return 1 + fi + + # does offload show up in ip output + lines=`ip x s list | grep -c "crypto offload parameters: dev $dev dir"` + if [ $lines -ne 2 ] ; then + echo "FAIL: ipsec_offload SA offload missing from list output" + check_err 1 + fi + + # use ping to exercise the Tx path + ping -I $dev -c 3 -W 1 -i 0 $dstip >/dev/null + + # does driver have correct offload info + diff $sysfsf - << EOF +SA count=2 tx=3 +sa[0] tx ipaddr=0x00000000 00000000 00000000 00000000 +sa[0] spi=0x00000009 proto=0x32 salt=0x61626364 crypt=1 +sa[0] key=0x34333231 38373635 32313039 36353433 +sa[1] rx ipaddr=0x00000000 00000000 00000000 037ba8c0 +sa[1] spi=0x00000009 proto=0x32 salt=0x61626364 crypt=1 +sa[1] key=0x34333231 38373635 32313039 36353433 +EOF + if [ $? -ne 0 ] ; then + echo "FAIL: ipsec_offload incorrect driver data" + check_err 1 + fi + + # does offload get removed from driver + ip x s flush + ip x p flush + lines=`grep -c "SA count=0" $sysfsf` + if [ $lines -ne 1 ] ; then + echo "FAIL: ipsec_offload SA not removed from driver" + check_err 1 + fi + + # clean up any leftovers + ip link del $dev + rmmod netdevsim + + if [ $ret -ne 0 ]; then + echo "FAIL: ipsec_offload" + return 1 + fi + echo "PASS: ipsec_offload" +} + kci_test_gretap() { testns="testns" @@ -861,6 +978,7 @@ kci_test_rtnl() kci_test_encap kci_test_macsec kci_test_ipsec + kci_test_ipsec_offload kci_del_dummy } diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c new file mode 100644 index 000000000000..b3ebf2646e52 --- /dev/null +++ b/tools/testing/selftests/net/tls.c @@ -0,0 +1,692 @@ +// SPDX-License-Identifier: GPL-2.0 + +#define _GNU_SOURCE + +#include <arpa/inet.h> +#include <errno.h> +#include <error.h> +#include <fcntl.h> +#include <poll.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <linux/tls.h> +#include <linux/tcp.h> +#include <linux/socket.h> + +#include <sys/types.h> +#include <sys/sendfile.h> +#include <sys/socket.h> +#include <sys/stat.h> + +#include "../kselftest_harness.h" + +#define TLS_PAYLOAD_MAX_LEN 16384 +#define SOL_TLS 282 + +FIXTURE(tls) +{ + int fd, cfd; + bool notls; +}; + +FIXTURE_SETUP(tls) +{ + struct tls12_crypto_info_aes_gcm_128 tls12; + struct sockaddr_in addr; + socklen_t len; + int sfd, ret; + + self->notls = false; + len = sizeof(addr); + + memset(&tls12, 0, sizeof(tls12)); + tls12.info.version = TLS_1_2_VERSION; + tls12.info.cipher_type = TLS_CIPHER_AES_GCM_128; + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = 0; + + self->fd = socket(AF_INET, SOCK_STREAM, 0); + sfd = socket(AF_INET, SOCK_STREAM, 0); + + ret = bind(sfd, &addr, sizeof(addr)); + ASSERT_EQ(ret, 0); + ret = listen(sfd, 10); + ASSERT_EQ(ret, 0); + + ret = getsockname(sfd, &addr, &len); + ASSERT_EQ(ret, 0); + + ret = connect(self->fd, &addr, sizeof(addr)); + ASSERT_EQ(ret, 0); + + ret = setsockopt(self->fd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls")); + if (ret != 0) { + self->notls = true; + printf("Failure setting TCP_ULP, testing without tls\n"); + } + + if (!self->notls) { + ret = setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, + sizeof(tls12)); + ASSERT_EQ(ret, 0); + } + + self->cfd = accept(sfd, &addr, &len); + ASSERT_GE(self->cfd, 0); + + if (!self->notls) { + ret = setsockopt(self->cfd, IPPROTO_TCP, TCP_ULP, "tls", + sizeof("tls")); + ASSERT_EQ(ret, 0); + + ret = setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12, + sizeof(tls12)); + ASSERT_EQ(ret, 0); + } + + close(sfd); +} + +FIXTURE_TEARDOWN(tls) +{ + close(self->fd); + close(self->cfd); +} + +TEST_F(tls, sendfile) +{ + int filefd = open("/proc/self/exe", O_RDONLY); + struct stat st; + + EXPECT_GE(filefd, 0); + fstat(filefd, &st); + EXPECT_GE(sendfile(self->fd, filefd, 0, st.st_size), 0); +} + +TEST_F(tls, send_then_sendfile) +{ + int filefd = open("/proc/self/exe", O_RDONLY); + char const *test_str = "test_send"; + int to_send = strlen(test_str) + 1; + char recv_buf[10]; + struct stat st; + char *buf; + + EXPECT_GE(filefd, 0); + fstat(filefd, &st); + buf = (char *)malloc(st.st_size); + + EXPECT_EQ(send(self->fd, test_str, to_send, 0), to_send); + EXPECT_EQ(recv(self->cfd, recv_buf, to_send, 0), to_send); + EXPECT_EQ(memcmp(test_str, recv_buf, to_send), 0); + + EXPECT_GE(sendfile(self->fd, filefd, 0, st.st_size), 0); + EXPECT_EQ(recv(self->cfd, buf, st.st_size, 0), st.st_size); +} + +TEST_F(tls, recv_max) +{ + unsigned int send_len = TLS_PAYLOAD_MAX_LEN; + char recv_mem[TLS_PAYLOAD_MAX_LEN]; + char buf[TLS_PAYLOAD_MAX_LEN]; + + EXPECT_GE(send(self->fd, buf, send_len, 0), 0); + EXPECT_NE(recv(self->cfd, recv_mem, send_len, 0), -1); + EXPECT_EQ(memcmp(buf, recv_mem, send_len), 0); +} + +TEST_F(tls, recv_small) +{ + char const *test_str = "test_read"; + int send_len = 10; + char buf[10]; + + send_len = strlen(test_str) + 1; + EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len); + EXPECT_NE(recv(self->cfd, buf, send_len, 0), -1); + EXPECT_EQ(memcmp(buf, test_str, send_len), 0); +} + +TEST_F(tls, msg_more) +{ + char const *test_str = "test_read"; + int send_len = 10; + char buf[10 * 2]; + + EXPECT_EQ(send(self->fd, test_str, send_len, MSG_MORE), send_len); + EXPECT_EQ(recv(self->cfd, buf, send_len, MSG_DONTWAIT), -1); + EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len); + EXPECT_EQ(recv(self->cfd, buf, send_len * 2, MSG_DONTWAIT), + send_len * 2); + EXPECT_EQ(memcmp(buf, test_str, send_len), 0); +} + +TEST_F(tls, sendmsg_single) +{ + struct msghdr msg; + + char const *test_str = "test_sendmsg"; + size_t send_len = 13; + struct iovec vec; + char buf[13]; + + vec.iov_base = (char *)test_str; + vec.iov_len = send_len; + memset(&msg, 0, sizeof(struct msghdr)); + msg.msg_iov = &vec; + msg.msg_iovlen = 1; + EXPECT_EQ(sendmsg(self->fd, &msg, 0), send_len); + EXPECT_EQ(recv(self->cfd, buf, send_len, 0), send_len); + EXPECT_EQ(memcmp(buf, test_str, send_len), 0); +} + +TEST_F(tls, sendmsg_large) +{ + void *mem = malloc(16384); + size_t send_len = 16384; + size_t sends = 128; + struct msghdr msg; + size_t recvs = 0; + size_t sent = 0; + + memset(&msg, 0, sizeof(struct msghdr)); + while (sent++ < sends) { + struct iovec vec = { (void *)mem, send_len }; + + msg.msg_iov = &vec; + msg.msg_iovlen = 1; + EXPECT_EQ(sendmsg(self->cfd, &msg, 0), send_len); + } + + while (recvs++ < sends) + EXPECT_NE(recv(self->fd, mem, send_len, 0), -1); + + free(mem); +} + +TEST_F(tls, sendmsg_multiple) +{ + char const *test_str = "test_sendmsg_multiple"; + struct iovec vec[5]; + char *test_strs[5]; + struct msghdr msg; + int total_len = 0; + int len_cmp = 0; + int iov_len = 5; + char *buf; + int i; + + memset(&msg, 0, sizeof(struct msghdr)); + for (i = 0; i < iov_len; i++) { + test_strs[i] = (char *)malloc(strlen(test_str) + 1); + snprintf(test_strs[i], strlen(test_str) + 1, "%s", test_str); + vec[i].iov_base = (void *)test_strs[i]; + vec[i].iov_len = strlen(test_strs[i]) + 1; + total_len += vec[i].iov_len; + } + msg.msg_iov = vec; + msg.msg_iovlen = iov_len; + + EXPECT_EQ(sendmsg(self->cfd, &msg, 0), total_len); + buf = malloc(total_len); + EXPECT_NE(recv(self->fd, buf, total_len, 0), -1); + for (i = 0; i < iov_len; i++) { + EXPECT_EQ(memcmp(test_strs[i], buf + len_cmp, + strlen(test_strs[i])), + 0); + len_cmp += strlen(buf + len_cmp) + 1; + } + for (i = 0; i < iov_len; i++) + free(test_strs[i]); + free(buf); +} + +TEST_F(tls, sendmsg_multiple_stress) +{ + char const *test_str = "abcdefghijklmno"; + struct iovec vec[1024]; + char *test_strs[1024]; + int iov_len = 1024; + int total_len = 0; + char buf[1 << 14]; + struct msghdr msg; + int len_cmp = 0; + int i; + + memset(&msg, 0, sizeof(struct msghdr)); + for (i = 0; i < iov_len; i++) { + test_strs[i] = (char *)malloc(strlen(test_str) + 1); + snprintf(test_strs[i], strlen(test_str) + 1, "%s", test_str); + vec[i].iov_base = (void *)test_strs[i]; + vec[i].iov_len = strlen(test_strs[i]) + 1; + total_len += vec[i].iov_len; + } + msg.msg_iov = vec; + msg.msg_iovlen = iov_len; + + EXPECT_EQ(sendmsg(self->fd, &msg, 0), total_len); + EXPECT_NE(recv(self->cfd, buf, total_len, 0), -1); + + for (i = 0; i < iov_len; i++) + len_cmp += strlen(buf + len_cmp) + 1; + + for (i = 0; i < iov_len; i++) + free(test_strs[i]); +} + +TEST_F(tls, splice_from_pipe) +{ + int send_len = TLS_PAYLOAD_MAX_LEN; + char mem_send[TLS_PAYLOAD_MAX_LEN]; + char mem_recv[TLS_PAYLOAD_MAX_LEN]; + int p[2]; + + ASSERT_GE(pipe(p), 0); + EXPECT_GE(write(p[1], mem_send, send_len), 0); + EXPECT_GE(splice(p[0], NULL, self->fd, NULL, send_len, 0), 0); + EXPECT_GE(recv(self->cfd, mem_recv, send_len, 0), 0); + EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0); +} + +TEST_F(tls, splice_from_pipe2) +{ + int send_len = 16000; + char mem_send[16000]; + char mem_recv[16000]; + int p2[2]; + int p[2]; + + ASSERT_GE(pipe(p), 0); + ASSERT_GE(pipe(p2), 0); + EXPECT_GE(write(p[1], mem_send, 8000), 0); + EXPECT_GE(splice(p[0], NULL, self->fd, NULL, 8000, 0), 0); + EXPECT_GE(write(p2[1], mem_send + 8000, 8000), 0); + EXPECT_GE(splice(p2[0], NULL, self->fd, NULL, 8000, 0), 0); + EXPECT_GE(recv(self->cfd, mem_recv, send_len, 0), 0); + EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0); +} + +TEST_F(tls, send_and_splice) +{ + int send_len = TLS_PAYLOAD_MAX_LEN; + char mem_send[TLS_PAYLOAD_MAX_LEN]; + char mem_recv[TLS_PAYLOAD_MAX_LEN]; + char const *test_str = "test_read"; + int send_len2 = 10; + char buf[10]; + int p[2]; + + ASSERT_GE(pipe(p), 0); + EXPECT_EQ(send(self->fd, test_str, send_len2, 0), send_len2); + EXPECT_NE(recv(self->cfd, buf, send_len2, 0), -1); + EXPECT_EQ(memcmp(test_str, buf, send_len2), 0); + + EXPECT_GE(write(p[1], mem_send, send_len), send_len); + EXPECT_GE(splice(p[0], NULL, self->fd, NULL, send_len, 0), send_len); + + EXPECT_GE(recv(self->cfd, mem_recv, send_len, 0), 0); + EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0); +} + +TEST_F(tls, splice_to_pipe) +{ + int send_len = TLS_PAYLOAD_MAX_LEN; + char mem_send[TLS_PAYLOAD_MAX_LEN]; + char mem_recv[TLS_PAYLOAD_MAX_LEN]; + int p[2]; + + ASSERT_GE(pipe(p), 0); + EXPECT_GE(send(self->fd, mem_send, send_len, 0), 0); + EXPECT_GE(splice(self->cfd, NULL, p[1], NULL, send_len, 0), 0); + EXPECT_GE(read(p[0], mem_recv, send_len), 0); + EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0); +} + +TEST_F(tls, recvmsg_single) +{ + char const *test_str = "test_recvmsg_single"; + int send_len = strlen(test_str) + 1; + char buf[20]; + struct msghdr hdr; + struct iovec vec; + + memset(&hdr, 0, sizeof(hdr)); + EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len); + vec.iov_base = (char *)buf; + vec.iov_len = send_len; + hdr.msg_iovlen = 1; + hdr.msg_iov = &vec; + EXPECT_NE(recvmsg(self->cfd, &hdr, 0), -1); + EXPECT_EQ(memcmp(test_str, buf, send_len), 0); +} + +TEST_F(tls, recvmsg_single_max) +{ + int send_len = TLS_PAYLOAD_MAX_LEN; + char send_mem[TLS_PAYLOAD_MAX_LEN]; + char recv_mem[TLS_PAYLOAD_MAX_LEN]; + struct iovec vec; + struct msghdr hdr; + + EXPECT_EQ(send(self->fd, send_mem, send_len, 0), send_len); + vec.iov_base = (char *)recv_mem; + vec.iov_len = TLS_PAYLOAD_MAX_LEN; + + hdr.msg_iovlen = 1; + hdr.msg_iov = &vec; + EXPECT_NE(recvmsg(self->cfd, &hdr, 0), -1); + EXPECT_EQ(memcmp(send_mem, recv_mem, send_len), 0); +} + +TEST_F(tls, recvmsg_multiple) +{ + unsigned int msg_iovlen = 1024; + unsigned int len_compared = 0; + struct iovec vec[1024]; + char *iov_base[1024]; + unsigned int iov_len = 16; + int send_len = 1 << 14; + char buf[1 << 14]; + struct msghdr hdr; + int i; + + EXPECT_EQ(send(self->fd, buf, send_len, 0), send_len); + for (i = 0; i < msg_iovlen; i++) { + iov_base[i] = (char *)malloc(iov_len); + vec[i].iov_base = iov_base[i]; + vec[i].iov_len = iov_len; + } + + hdr.msg_iovlen = msg_iovlen; + hdr.msg_iov = vec; + EXPECT_NE(recvmsg(self->cfd, &hdr, 0), -1); + for (i = 0; i < msg_iovlen; i++) + len_compared += iov_len; + + for (i = 0; i < msg_iovlen; i++) + free(iov_base[i]); +} + +TEST_F(tls, single_send_multiple_recv) +{ + unsigned int total_len = TLS_PAYLOAD_MAX_LEN * 2; + unsigned int send_len = TLS_PAYLOAD_MAX_LEN; + char send_mem[TLS_PAYLOAD_MAX_LEN * 2]; + char recv_mem[TLS_PAYLOAD_MAX_LEN * 2]; + + EXPECT_GE(send(self->fd, send_mem, total_len, 0), 0); + memset(recv_mem, 0, total_len); + + EXPECT_NE(recv(self->cfd, recv_mem, send_len, 0), -1); + EXPECT_NE(recv(self->cfd, recv_mem + send_len, send_len, 0), -1); + EXPECT_EQ(memcmp(send_mem, recv_mem, total_len), 0); +} + +TEST_F(tls, multiple_send_single_recv) +{ + unsigned int total_len = 2 * 10; + unsigned int send_len = 10; + char recv_mem[2 * 10]; + char send_mem[10]; + + EXPECT_GE(send(self->fd, send_mem, send_len, 0), 0); + EXPECT_GE(send(self->fd, send_mem, send_len, 0), 0); + memset(recv_mem, 0, total_len); + EXPECT_EQ(recv(self->cfd, recv_mem, total_len, 0), total_len); + + EXPECT_EQ(memcmp(send_mem, recv_mem, send_len), 0); + EXPECT_EQ(memcmp(send_mem, recv_mem + send_len, send_len), 0); +} + +TEST_F(tls, recv_partial) +{ + char const *test_str = "test_read_partial"; + char const *test_str_first = "test_read"; + char const *test_str_second = "_partial"; + int send_len = strlen(test_str) + 1; + char recv_mem[18]; + + memset(recv_mem, 0, sizeof(recv_mem)); + EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len); + EXPECT_NE(recv(self->cfd, recv_mem, strlen(test_str_first), 0), -1); + EXPECT_EQ(memcmp(test_str_first, recv_mem, strlen(test_str_first)), 0); + memset(recv_mem, 0, sizeof(recv_mem)); + EXPECT_NE(recv(self->cfd, recv_mem, strlen(test_str_second), 0), -1); + EXPECT_EQ(memcmp(test_str_second, recv_mem, strlen(test_str_second)), + 0); +} + +TEST_F(tls, recv_nonblock) +{ + char buf[4096]; + bool err; + + EXPECT_EQ(recv(self->cfd, buf, sizeof(buf), MSG_DONTWAIT), -1); + err = (errno == EAGAIN || errno == EWOULDBLOCK); + EXPECT_EQ(err, true); +} + +TEST_F(tls, recv_peek) +{ + char const *test_str = "test_read_peek"; + int send_len = strlen(test_str) + 1; + char buf[15]; + + EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len); + EXPECT_NE(recv(self->cfd, buf, send_len, MSG_PEEK), -1); + EXPECT_EQ(memcmp(test_str, buf, send_len), 0); + memset(buf, 0, sizeof(buf)); + EXPECT_NE(recv(self->cfd, buf, send_len, 0), -1); + EXPECT_EQ(memcmp(test_str, buf, send_len), 0); +} + +TEST_F(tls, recv_peek_multiple) +{ + char const *test_str = "test_read_peek"; + int send_len = strlen(test_str) + 1; + unsigned int num_peeks = 100; + char buf[15]; + int i; + + EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len); + for (i = 0; i < num_peeks; i++) { + EXPECT_NE(recv(self->cfd, buf, send_len, MSG_PEEK), -1); + EXPECT_EQ(memcmp(test_str, buf, send_len), 0); + memset(buf, 0, sizeof(buf)); + } + EXPECT_NE(recv(self->cfd, buf, send_len, 0), -1); + EXPECT_EQ(memcmp(test_str, buf, send_len), 0); +} + +TEST_F(tls, pollin) +{ + char const *test_str = "test_poll"; + struct pollfd fd = { 0, 0, 0 }; + char buf[10]; + int send_len = 10; + + EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len); + fd.fd = self->cfd; + fd.events = POLLIN; + + EXPECT_EQ(poll(&fd, 1, 20), 1); + EXPECT_EQ(fd.revents & POLLIN, 1); + EXPECT_EQ(recv(self->cfd, buf, send_len, 0), send_len); + /* Test timing out */ + EXPECT_EQ(poll(&fd, 1, 20), 0); +} + +TEST_F(tls, poll_wait) +{ + char const *test_str = "test_poll_wait"; + int send_len = strlen(test_str) + 1; + struct pollfd fd = { 0, 0, 0 }; + char recv_mem[15]; + + fd.fd = self->cfd; + fd.events = POLLIN; + EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len); + /* Set timeout to inf. secs */ + EXPECT_EQ(poll(&fd, 1, -1), 1); + EXPECT_EQ(fd.revents & POLLIN, 1); + EXPECT_EQ(recv(self->cfd, recv_mem, send_len, 0), send_len); +} + +TEST_F(tls, blocking) +{ + size_t data = 100000; + int res = fork(); + + EXPECT_NE(res, -1); + + if (res) { + /* parent */ + size_t left = data; + char buf[16384]; + int status; + int pid2; + + while (left) { + int res = send(self->fd, buf, + left > 16384 ? 16384 : left, 0); + + EXPECT_GE(res, 0); + left -= res; + } + + pid2 = wait(&status); + EXPECT_EQ(status, 0); + EXPECT_EQ(res, pid2); + } else { + /* child */ + size_t left = data; + char buf[16384]; + + while (left) { + int res = recv(self->cfd, buf, + left > 16384 ? 16384 : left, 0); + + EXPECT_GE(res, 0); + left -= res; + } + } +} + +TEST_F(tls, nonblocking) +{ + size_t data = 100000; + int sendbuf = 100; + int flags; + int res; + + flags = fcntl(self->fd, F_GETFL, 0); + fcntl(self->fd, F_SETFL, flags | O_NONBLOCK); + fcntl(self->cfd, F_SETFL, flags | O_NONBLOCK); + + /* Ensure nonblocking behavior by imposing a small send + * buffer. + */ + EXPECT_EQ(setsockopt(self->fd, SOL_SOCKET, SO_SNDBUF, + &sendbuf, sizeof(sendbuf)), 0); + + res = fork(); + EXPECT_NE(res, -1); + + if (res) { + /* parent */ + bool eagain = false; + size_t left = data; + char buf[16384]; + int status; + int pid2; + + while (left) { + int res = send(self->fd, buf, + left > 16384 ? 16384 : left, 0); + + if (res == -1 && errno == EAGAIN) { + eagain = true; + usleep(10000); + continue; + } + EXPECT_GE(res, 0); + left -= res; + } + + EXPECT_TRUE(eagain); + pid2 = wait(&status); + + EXPECT_EQ(status, 0); + EXPECT_EQ(res, pid2); + } else { + /* child */ + bool eagain = false; + size_t left = data; + char buf[16384]; + + while (left) { + int res = recv(self->cfd, buf, + left > 16384 ? 16384 : left, 0); + + if (res == -1 && errno == EAGAIN) { + eagain = true; + usleep(10000); + continue; + } + EXPECT_GE(res, 0); + left -= res; + } + EXPECT_TRUE(eagain); + } +} + +TEST_F(tls, control_msg) +{ + if (self->notls) + return; + + char cbuf[CMSG_SPACE(sizeof(char))]; + char const *test_str = "test_read"; + int cmsg_len = sizeof(char); + char record_type = 100; + struct cmsghdr *cmsg; + struct msghdr msg; + int send_len = 10; + struct iovec vec; + char buf[10]; + + vec.iov_base = (char *)test_str; + vec.iov_len = 10; + memset(&msg, 0, sizeof(struct msghdr)); + msg.msg_iov = &vec; + msg.msg_iovlen = 1; + msg.msg_control = cbuf; + msg.msg_controllen = sizeof(cbuf); + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_TLS; + /* test sending non-record types. */ + cmsg->cmsg_type = TLS_SET_RECORD_TYPE; + cmsg->cmsg_len = CMSG_LEN(cmsg_len); + *CMSG_DATA(cmsg) = record_type; + msg.msg_controllen = cmsg->cmsg_len; + + EXPECT_EQ(sendmsg(self->fd, &msg, 0), send_len); + /* Should fail because we didn't provide a control message */ + EXPECT_EQ(recv(self->cfd, buf, send_len, 0), -1); + + vec.iov_base = buf; + EXPECT_EQ(recvmsg(self->cfd, &msg, 0), send_len); + cmsg = CMSG_FIRSTHDR(&msg); + EXPECT_NE(cmsg, NULL); + EXPECT_EQ(cmsg->cmsg_level, SOL_TLS); + EXPECT_EQ(cmsg->cmsg_type, TLS_GET_RECORD_TYPE); + record_type = *((unsigned char *)CMSG_DATA(cmsg)); + EXPECT_EQ(record_type, 100); + EXPECT_EQ(memcmp(buf, test_str, send_len), 0); +} + +TEST_HARNESS_MAIN diff --git a/tools/testing/selftests/powerpc/alignment/.gitignore b/tools/testing/selftests/powerpc/alignment/.gitignore index 9d383073b7ad..6d4fd014511c 100644 --- a/tools/testing/selftests/powerpc/alignment/.gitignore +++ b/tools/testing/selftests/powerpc/alignment/.gitignore @@ -1,6 +1,2 @@ -copy_unaligned copy_first_unaligned -paste_unaligned -paste_last_unaligned -copy_paste_unaligned_common alignment_handler diff --git a/tools/testing/selftests/powerpc/alignment/Makefile b/tools/testing/selftests/powerpc/alignment/Makefile index 083a48a008b4..93baacab7693 100644 --- a/tools/testing/selftests/powerpc/alignment/Makefile +++ b/tools/testing/selftests/powerpc/alignment/Makefile @@ -1,6 +1,5 @@ -TEST_GEN_PROGS := copy_unaligned copy_first_unaligned paste_unaligned \ - paste_last_unaligned alignment_handler +TEST_GEN_PROGS := copy_first_unaligned alignment_handler include ../../lib.mk -$(TEST_GEN_PROGS): ../harness.c ../utils.c copy_paste_unaligned_common.c +$(TEST_GEN_PROGS): ../harness.c ../utils.c diff --git a/tools/testing/selftests/powerpc/alignment/alignment_handler.c b/tools/testing/selftests/powerpc/alignment/alignment_handler.c index 0f2698f9fd6d..169a8b9719fb 100644 --- a/tools/testing/selftests/powerpc/alignment/alignment_handler.c +++ b/tools/testing/selftests/powerpc/alignment/alignment_handler.c @@ -40,6 +40,7 @@ #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> +#include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -48,6 +49,8 @@ #include <setjmp.h> #include <signal.h> +#include <asm/cputable.h> + #include "utils.h" int bufsize; @@ -191,7 +194,7 @@ int test_memcmp(void *s1, void *s2, int n, int offset, char *test_name) */ int do_test(char *test_name, void (*test_func)(char *, char *)) { - int offset, width, fd, rc = 0, r; + int offset, width, fd, rc, r; void *mem0, *mem1, *ci0, *ci1; printf("\tDoing %s:\t", test_name); @@ -199,8 +202,8 @@ int do_test(char *test_name, void (*test_func)(char *, char *)) fd = open("/dev/fb0", O_RDWR); if (fd < 0) { printf("\n"); - perror("Can't open /dev/fb0"); - SKIP_IF(1); + perror("Can't open /dev/fb0 now?"); + return 1; } ci0 = mmap(NULL, bufsize, PROT_WRITE, MAP_SHARED, @@ -226,6 +229,7 @@ int do_test(char *test_name, void (*test_func)(char *, char *)) return rc; } + rc = 0; /* offset = 0 no alignment fault, so skip */ for (offset = 1; offset < 16; offset++) { width = 16; /* vsx == 16 bytes */ @@ -244,32 +248,51 @@ int do_test(char *test_name, void (*test_func)(char *, char *)) r |= test_memcpy(mem1, mem0, width, offset, test_func); if (r && !debug) { printf("FAILED: Got signal"); + rc = 1; break; } r |= test_memcmp(mem1, ci1, width, offset, test_name); - rc |= r; if (r && !debug) { printf("FAILED: Wrong Data"); + rc = 1; break; } } - if (!r) + + if (rc == 0) printf("PASSED"); + printf("\n"); munmap(ci0, bufsize); munmap(ci1, bufsize); free(mem0); free(mem1); + close(fd); return rc; } +static bool can_open_fb0(void) +{ + int fd; + + fd = open("/dev/fb0", O_RDWR); + if (fd < 0) + return false; + + close(fd); + return true; +} + int test_alignment_handler_vsx_206(void) { int rc = 0; + SKIP_IF(!can_open_fb0()); + SKIP_IF(!have_hwcap(PPC_FEATURE_ARCH_2_06)); + printf("VSX: 2.06B\n"); LOAD_VSX_XFORM_TEST(lxvd2x); LOAD_VSX_XFORM_TEST(lxvw4x); @@ -285,6 +308,9 @@ int test_alignment_handler_vsx_207(void) { int rc = 0; + SKIP_IF(!can_open_fb0()); + SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_2_07)); + printf("VSX: 2.07B\n"); LOAD_VSX_XFORM_TEST(lxsspx); LOAD_VSX_XFORM_TEST(lxsiwax); @@ -298,6 +324,8 @@ int test_alignment_handler_vsx_300(void) { int rc = 0; + SKIP_IF(!can_open_fb0()); + SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_3_00)); printf("VSX: 3.00B\n"); LOAD_VMX_DFORM_TEST(lxsd); @@ -328,6 +356,8 @@ int test_alignment_handler_integer(void) { int rc = 0; + SKIP_IF(!can_open_fb0()); + printf("Integer\n"); LOAD_DFORM_TEST(lbz); LOAD_DFORM_TEST(lbzu); @@ -354,7 +384,6 @@ int test_alignment_handler_integer(void) LOAD_DFORM_TEST(ldu); LOAD_XFORM_TEST(ldx); LOAD_XFORM_TEST(ldux); - LOAD_XFORM_TEST(ldbrx); LOAD_DFORM_TEST(lmw); STORE_DFORM_TEST(stb); STORE_XFORM_TEST(stbx); @@ -374,8 +403,23 @@ int test_alignment_handler_integer(void) STORE_XFORM_TEST(stdx); STORE_DFORM_TEST(stdu); STORE_XFORM_TEST(stdux); - STORE_XFORM_TEST(stdbrx); STORE_DFORM_TEST(stmw); + + return rc; +} + +int test_alignment_handler_integer_206(void) +{ + int rc = 0; + + SKIP_IF(!can_open_fb0()); + SKIP_IF(!have_hwcap(PPC_FEATURE_ARCH_2_06)); + + printf("Integer: 2.06\n"); + + LOAD_XFORM_TEST(ldbrx); + STORE_XFORM_TEST(stdbrx); + return rc; } @@ -383,6 +427,9 @@ int test_alignment_handler_vmx(void) { int rc = 0; + SKIP_IF(!can_open_fb0()); + SKIP_IF(!have_hwcap(PPC_FEATURE_HAS_ALTIVEC)); + printf("VMX\n"); LOAD_VMX_XFORM_TEST(lvx); @@ -408,23 +455,19 @@ int test_alignment_handler_fp(void) { int rc = 0; + SKIP_IF(!can_open_fb0()); + printf("Floating point\n"); LOAD_FLOAT_DFORM_TEST(lfd); LOAD_FLOAT_XFORM_TEST(lfdx); - LOAD_FLOAT_DFORM_TEST(lfdp); - LOAD_FLOAT_XFORM_TEST(lfdpx); LOAD_FLOAT_DFORM_TEST(lfdu); LOAD_FLOAT_XFORM_TEST(lfdux); LOAD_FLOAT_DFORM_TEST(lfs); LOAD_FLOAT_XFORM_TEST(lfsx); LOAD_FLOAT_DFORM_TEST(lfsu); LOAD_FLOAT_XFORM_TEST(lfsux); - LOAD_FLOAT_XFORM_TEST(lfiwzx); - LOAD_FLOAT_XFORM_TEST(lfiwax); STORE_FLOAT_DFORM_TEST(stfd); STORE_FLOAT_XFORM_TEST(stfdx); - STORE_FLOAT_DFORM_TEST(stfdp); - STORE_FLOAT_XFORM_TEST(stfdpx); STORE_FLOAT_DFORM_TEST(stfdu); STORE_FLOAT_XFORM_TEST(stfdux); STORE_FLOAT_DFORM_TEST(stfs); @@ -436,6 +479,38 @@ int test_alignment_handler_fp(void) return rc; } +int test_alignment_handler_fp_205(void) +{ + int rc = 0; + + SKIP_IF(!can_open_fb0()); + SKIP_IF(!have_hwcap(PPC_FEATURE_ARCH_2_05)); + + printf("Floating point: 2.05\n"); + + LOAD_FLOAT_DFORM_TEST(lfdp); + LOAD_FLOAT_XFORM_TEST(lfdpx); + LOAD_FLOAT_XFORM_TEST(lfiwax); + STORE_FLOAT_DFORM_TEST(stfdp); + STORE_FLOAT_XFORM_TEST(stfdpx); + + return rc; +} + +int test_alignment_handler_fp_206(void) +{ + int rc = 0; + + SKIP_IF(!can_open_fb0()); + SKIP_IF(!have_hwcap(PPC_FEATURE_ARCH_2_06)); + + printf("Floating point: 2.06\n"); + + LOAD_FLOAT_XFORM_TEST(lfiwzx); + + return rc; +} + void usage(char *prog) { printf("Usage: %s [options]\n", prog); @@ -483,9 +558,15 @@ int main(int argc, char *argv[]) "test_alignment_handler_vsx_300"); rc |= test_harness(test_alignment_handler_integer, "test_alignment_handler_integer"); + rc |= test_harness(test_alignment_handler_integer_206, + "test_alignment_handler_integer_206"); rc |= test_harness(test_alignment_handler_vmx, "test_alignment_handler_vmx"); rc |= test_harness(test_alignment_handler_fp, "test_alignment_handler_fp"); + rc |= test_harness(test_alignment_handler_fp_205, + "test_alignment_handler_fp_205"); + rc |= test_harness(test_alignment_handler_fp_206, + "test_alignment_handler_fp_206"); return rc; } diff --git a/tools/testing/selftests/powerpc/alignment/copy_first_unaligned.c b/tools/testing/selftests/powerpc/alignment/copy_first_unaligned.c index 47b73b3a08bd..5a9589987702 100644 --- a/tools/testing/selftests/powerpc/alignment/copy_first_unaligned.c +++ b/tools/testing/selftests/powerpc/alignment/copy_first_unaligned.c @@ -11,15 +11,46 @@ * */ +#include <signal.h> #include <string.h> #include <unistd.h> #include "utils.h" #include "instructions.h" -#include "copy_paste_unaligned_common.h" unsigned int expected_instruction = PPC_INST_COPY_FIRST; unsigned int instruction_mask = 0xfc2007fe; +void signal_action_handler(int signal_num, siginfo_t *info, void *ptr) +{ + ucontext_t *ctx = ptr; +#ifdef __powerpc64__ + unsigned int *pc = (unsigned int *)ctx->uc_mcontext.gp_regs[PT_NIP]; +#else + unsigned int *pc = (unsigned int *)ctx->uc_mcontext.uc_regs->gregs[PT_NIP]; +#endif + + /* + * Check that the signal was on the correct instruction, using a + * mask because the compiler assigns the register at RB. + */ + if ((*pc & instruction_mask) == expected_instruction) + _exit(0); /* We hit the right instruction */ + + _exit(1); +} + +void setup_signal_handler(void) +{ + struct sigaction signal_action; + + memset(&signal_action, 0, sizeof(signal_action)); + signal_action.sa_sigaction = signal_action_handler; + signal_action.sa_flags = SA_SIGINFO; + sigaction(SIGBUS, &signal_action, NULL); +} + +char cacheline_buf[128] __cacheline_aligned; + int test_copy_first_unaligned(void) { /* Only run this test on a P9 or later */ diff --git a/tools/testing/selftests/powerpc/alignment/copy_paste_unaligned_common.c b/tools/testing/selftests/powerpc/alignment/copy_paste_unaligned_common.c deleted file mode 100644 index d35fa5f5d2d3..000000000000 --- a/tools/testing/selftests/powerpc/alignment/copy_paste_unaligned_common.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2016, Chris Smart, IBM Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Common code for copy, copy_first, paste and paste_last unaligned - * tests. - * - */ - -#include <signal.h> -#include <string.h> -#include <unistd.h> -#include "utils.h" -#include "instructions.h" -#include "copy_paste_unaligned_common.h" - -unsigned int expected_instruction; -unsigned int instruction_mask; - -char cacheline_buf[128] __cacheline_aligned; - -void signal_action_handler(int signal_num, siginfo_t *info, void *ptr) -{ - ucontext_t *ctx = ptr; -#if defined(__powerpc64__) - unsigned int *pc = (unsigned int *)ctx->uc_mcontext.gp_regs[PT_NIP]; -#else - unsigned int *pc = (unsigned int *)ctx->uc_mcontext.uc_regs->gregs[PT_NIP]; -#endif - - /* - * Check that the signal was on the correct instruction, using a - * mask because the compiler assigns the register at RB. - */ - if ((*pc & instruction_mask) == expected_instruction) - _exit(0); /* We hit the right instruction */ - - _exit(1); -} - -void setup_signal_handler(void) -{ - struct sigaction signal_action; - - memset(&signal_action, 0, sizeof(signal_action)); - signal_action.sa_sigaction = signal_action_handler; - signal_action.sa_flags = SA_SIGINFO; - sigaction(SIGBUS, &signal_action, NULL); -} diff --git a/tools/testing/selftests/powerpc/alignment/copy_paste_unaligned_common.h b/tools/testing/selftests/powerpc/alignment/copy_paste_unaligned_common.h deleted file mode 100644 index 053899fe506e..000000000000 --- a/tools/testing/selftests/powerpc/alignment/copy_paste_unaligned_common.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2016, Chris Smart, IBM Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Declarations for common code for copy, copy_first, paste and - * paste_last unaligned tests. - * - */ - -#ifndef _SELFTESTS_POWERPC_COPY_PASTE_H -#define _SELFTESTS_POWERPC_COPY_PASTE_H - -#include <signal.h> - -int main(int argc, char *argv[]); -void signal_action_handler(int signal_num, siginfo_t *info, void *ptr); -void setup_signal_handler(void); -extern char cacheline_buf[128] __cacheline_aligned; -extern unsigned int expected_instruction; -extern unsigned int instruction_mask; - -#endif /* _SELFTESTS_POWERPC_COPY_PASTE_H */ diff --git a/tools/testing/selftests/powerpc/alignment/copy_unaligned.c b/tools/testing/selftests/powerpc/alignment/copy_unaligned.c deleted file mode 100644 index 3a4e26461554..000000000000 --- a/tools/testing/selftests/powerpc/alignment/copy_unaligned.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2016, Chris Smart, IBM Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Calls to copy which are not 128-byte aligned should be caught - * and sent a SIGBUS. - * - */ - -#include <string.h> -#include <unistd.h> -#include "utils.h" -#include "instructions.h" -#include "copy_paste_unaligned_common.h" - -unsigned int expected_instruction = PPC_INST_COPY; -unsigned int instruction_mask = 0xfc0007fe; - -int test_copy_unaligned(void) -{ - /* Only run this test on a P9 or later */ - SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_3_00)); - - /* Register our signal handler with SIGBUS */ - setup_signal_handler(); - - /* +1 makes buf unaligned */ - copy(cacheline_buf+1); - - /* We should not get here */ - return 1; -} - -int main(int argc, char *argv[]) -{ - return test_harness(test_copy_unaligned, "test_copy_unaligned"); -} diff --git a/tools/testing/selftests/powerpc/alignment/paste_last_unaligned.c b/tools/testing/selftests/powerpc/alignment/paste_last_unaligned.c deleted file mode 100644 index 6e0ad045fcc3..000000000000 --- a/tools/testing/selftests/powerpc/alignment/paste_last_unaligned.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2016, Chris Smart, IBM Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Calls to paste_last which are not 128-byte aligned should be - * caught and sent a SIGBUS. - * - */ - -#include <string.h> -#include <unistd.h> -#include "utils.h" -#include "instructions.h" -#include "copy_paste_unaligned_common.h" - -unsigned int expected_instruction = PPC_INST_PASTE_LAST; -unsigned int instruction_mask = 0xfc2007ff; - -int test_paste_last_unaligned(void) -{ - /* Only run this test on a P9 or later */ - SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_3_00)); - - /* Register our signal handler with SIGBUS */ - setup_signal_handler(); - - copy(cacheline_buf); - - /* +1 makes buf unaligned */ - paste_last(cacheline_buf+1); - - /* We should not get here */ - return 1; -} - -int main(int argc, char *argv[]) -{ - return test_harness(test_paste_last_unaligned, "test_paste_last_unaligned"); -} diff --git a/tools/testing/selftests/powerpc/alignment/paste_unaligned.c b/tools/testing/selftests/powerpc/alignment/paste_unaligned.c deleted file mode 100644 index 6f982b45e4bd..000000000000 --- a/tools/testing/selftests/powerpc/alignment/paste_unaligned.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2016, Chris Smart, IBM Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Calls to paste which are not 128-byte aligned should be caught - * and sent a SIGBUS. - * - */ - -#include <string.h> -#include <unistd.h> -#include "utils.h" -#include "instructions.h" -#include "copy_paste_unaligned_common.h" - -unsigned int expected_instruction = PPC_INST_PASTE; -unsigned int instruction_mask = 0xfc0007fe; - -int test_paste_unaligned(void) -{ - /* Only run this test on a P9 or later */ - SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_3_00)); - - /* Register our signal handler with SIGBUS */ - setup_signal_handler(); - - copy(cacheline_buf); - - /* +1 makes buf unaligned */ - paste(cacheline_buf+1); - - /* We should not get here */ - return 1; -} - -int main(int argc, char *argv[]) -{ - return test_harness(test_paste_unaligned, "test_paste_unaligned"); -} diff --git a/tools/testing/selftests/powerpc/benchmarks/futex_bench.c b/tools/testing/selftests/powerpc/benchmarks/futex_bench.c index 2fc711d9150d..d58e4dc50fcd 100644 --- a/tools/testing/selftests/powerpc/benchmarks/futex_bench.c +++ b/tools/testing/selftests/powerpc/benchmarks/futex_bench.c @@ -38,5 +38,6 @@ int test_futex(void) int main(void) { + test_harness_set_timeout(300); return test_harness(test_futex, "futex_bench"); } diff --git a/tools/testing/selftests/powerpc/benchmarks/mmap_bench.c b/tools/testing/selftests/powerpc/benchmarks/mmap_bench.c index 7a0a462a2272..033de0560d99 100644 --- a/tools/testing/selftests/powerpc/benchmarks/mmap_bench.c +++ b/tools/testing/selftests/powerpc/benchmarks/mmap_bench.c @@ -84,5 +84,7 @@ int main(int argc, char *argv[]) exit(1); } } + + test_harness_set_timeout(300); return test_harness(test_mmap, "mmap_bench"); } diff --git a/tools/testing/selftests/powerpc/copyloops/.gitignore b/tools/testing/selftests/powerpc/copyloops/.gitignore index 25a192f62c4d..ce12cd0e2967 100644 --- a/tools/testing/selftests/powerpc/copyloops/.gitignore +++ b/tools/testing/selftests/powerpc/copyloops/.gitignore @@ -1,4 +1,13 @@ -copyuser_64 -copyuser_power7 -memcpy_64 -memcpy_power7 +copyuser_64_t0 +copyuser_64_t1 +copyuser_64_t2 +copyuser_power7_t0 +copyuser_power7_t1 +memcpy_64_t0 +memcpy_64_t1 +memcpy_64_t2 +memcpy_power7_t0 +memcpy_power7_t1 +copyuser_64_exc_t0 +copyuser_64_exc_t1 +copyuser_64_exc_t2 diff --git a/tools/testing/selftests/powerpc/copyloops/Makefile b/tools/testing/selftests/powerpc/copyloops/Makefile index eedce3366f64..1cf89a34d97c 100644 --- a/tools/testing/selftests/powerpc/copyloops/Makefile +++ b/tools/testing/selftests/powerpc/copyloops/Makefile @@ -4,18 +4,49 @@ CFLAGS += -m64 CFLAGS += -I$(CURDIR) CFLAGS += -D SELFTEST CFLAGS += -maltivec +CFLAGS += -mcpu=power4 # Use our CFLAGS for the implicit .S rule & set the asm machine type ASFLAGS = $(CFLAGS) -Wa,-mpower4 -TEST_GEN_PROGS := copyuser_64 copyuser_power7 memcpy_64 memcpy_power7 -EXTRA_SOURCES := validate.c ../harness.c +TEST_GEN_PROGS := copyuser_64_t0 copyuser_64_t1 copyuser_64_t2 \ + copyuser_p7_t0 copyuser_p7_t1 \ + memcpy_64_t0 memcpy_64_t1 memcpy_64_t2 \ + memcpy_p7_t0 memcpy_p7_t1 \ + copyuser_64_exc_t0 copyuser_64_exc_t1 copyuser_64_exc_t2 + +EXTRA_SOURCES := validate.c ../harness.c stubs.S include ../../lib.mk -$(OUTPUT)/copyuser_64: CPPFLAGS += -D COPY_LOOP=test___copy_tofrom_user_base -$(OUTPUT)/copyuser_power7: CPPFLAGS += -D COPY_LOOP=test___copy_tofrom_user_power7 -$(OUTPUT)/memcpy_64: CPPFLAGS += -D COPY_LOOP=test_memcpy -$(OUTPUT)/memcpy_power7: CPPFLAGS += -D COPY_LOOP=test_memcpy_power7 +$(OUTPUT)/copyuser_64_t%: copyuser_64.S $(EXTRA_SOURCES) + $(CC) $(CPPFLAGS) $(CFLAGS) \ + -D COPY_LOOP=test___copy_tofrom_user_base \ + -D SELFTEST_CASE=$(subst copyuser_64_t,,$(notdir $@)) \ + -o $@ $^ + +$(OUTPUT)/copyuser_p7_t%: copyuser_power7.S $(EXTRA_SOURCES) + $(CC) $(CPPFLAGS) $(CFLAGS) \ + -D COPY_LOOP=test___copy_tofrom_user_power7 \ + -D SELFTEST_CASE=$(subst copyuser_p7_t,,$(notdir $@)) \ + -o $@ $^ + +# Strictly speaking, we only need the memcpy_64 test cases for big-endian +$(OUTPUT)/memcpy_64_t%: memcpy_64.S $(EXTRA_SOURCES) + $(CC) $(CPPFLAGS) $(CFLAGS) \ + -D COPY_LOOP=test_memcpy \ + -D SELFTEST_CASE=$(subst memcpy_64_t,,$(notdir $@)) \ + -o $@ $^ + +$(OUTPUT)/memcpy_p7_t%: memcpy_power7.S $(EXTRA_SOURCES) + $(CC) $(CPPFLAGS) $(CFLAGS) \ + -D COPY_LOOP=test_memcpy_power7 \ + -D SELFTEST_CASE=$(subst memcpy_p7_t,,$(notdir $@)) \ + -o $@ $^ -$(TEST_GEN_PROGS): $(EXTRA_SOURCES) +$(OUTPUT)/copyuser_64_exc_t%: copyuser_64.S exc_validate.c ../harness.c \ + copy_tofrom_user_reference.S stubs.S + $(CC) $(CPPFLAGS) $(CFLAGS) \ + -D COPY_LOOP=test___copy_tofrom_user_base \ + -D SELFTEST_CASE=$(subst copyuser_64_exc_t,,$(notdir $@)) \ + -o $@ $^ diff --git a/tools/testing/selftests/powerpc/copyloops/asm/asm-compat.h b/tools/testing/selftests/powerpc/copyloops/asm/asm-compat.h new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/tools/testing/selftests/powerpc/copyloops/asm/asm-compat.h diff --git a/tools/testing/selftests/powerpc/copyloops/asm/feature-fixups.h b/tools/testing/selftests/powerpc/copyloops/asm/feature-fixups.h new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/tools/testing/selftests/powerpc/copyloops/asm/feature-fixups.h diff --git a/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h b/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h index 5ffe04d802c9..0605df807593 100644 --- a/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h +++ b/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h @@ -1,4 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __SELFTESTS_POWERPC_PPC_ASM_H +#define __SELFTESTS_POWERPC_PPC_ASM_H #include <ppc-asm.h> #define CONFIG_ALTIVEC @@ -26,34 +28,20 @@ #define PPC_MTOCRF(A, B) mtocrf A, B -#define EX_TABLE(x, y) +#define EX_TABLE(x, y) \ + .section __ex_table,"a"; \ + .8byte x, y; \ + .previous -FUNC_START(enter_vmx_usercopy) - li r3,1 - blr +#define BEGIN_FTR_SECTION .if test_feature +#define FTR_SECTION_ELSE .else +#define ALT_FTR_SECTION_END_IFCLR(x) .endif +#define ALT_FTR_SECTION_END_IFSET(x) .endif +#define ALT_FTR_SECTION_END(x, y) .endif +#define END_FTR_SECTION_IFCLR(x) .endif +#define END_FTR_SECTION_IFSET(x) .endif -FUNC_START(exit_vmx_usercopy) - li r3,0 - blr +/* Default to taking the first of any alternative feature sections */ +test_feature = 1 -FUNC_START(enter_vmx_copy) - li r3,1 - blr - -FUNC_START(exit_vmx_copy) - blr - -FUNC_START(memcpy_power7) - blr - -FUNC_START(__copy_tofrom_user_power7) - blr - -FUNC_START(__copy_tofrom_user_base) - blr - -#define BEGIN_FTR_SECTION -#define FTR_SECTION_ELSE -#define ALT_FTR_SECTION_END_IFCLR(x) -#define ALT_FTR_SECTION_END(x, y) -#define END_FTR_SECTION_IFCLR(x) +#endif /* __SELFTESTS_POWERPC_PPC_ASM_H */ diff --git a/tools/testing/selftests/powerpc/copyloops/copy_tofrom_user_reference.S b/tools/testing/selftests/powerpc/copyloops/copy_tofrom_user_reference.S new file mode 100644 index 000000000000..3363b86407d6 --- /dev/null +++ b/tools/testing/selftests/powerpc/copyloops/copy_tofrom_user_reference.S @@ -0,0 +1,24 @@ +#include <asm/ppc_asm.h> + +_GLOBAL(copy_tofrom_user_reference) + cmpdi r5,0 + beq 4f + + mtctr r5 + +1: lbz r6,0(r4) +2: stb r6,0(r3) + addi r3,r3,1 + addi r4,r4,1 + bdnz 1b + +3: mfctr r3 + blr + +4: mr r3,r5 + blr + +.section __ex_table,"a" + .llong 1b,3b + .llong 2b,3b +.text diff --git a/tools/testing/selftests/powerpc/copyloops/exc_validate.c b/tools/testing/selftests/powerpc/copyloops/exc_validate.c new file mode 100644 index 000000000000..c896ea9a763c --- /dev/null +++ b/tools/testing/selftests/powerpc/copyloops/exc_validate.c @@ -0,0 +1,124 @@ +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <signal.h> +#include <unistd.h> +#include <sys/mman.h> + +#include "utils.h" + +extern char __start___ex_table[]; +extern char __stop___ex_table[]; + +#if defined(__powerpc64__) +#define UCONTEXT_NIA(UC) (UC)->uc_mcontext.gp_regs[PT_NIP] +#elif defined(__powerpc__) +#define UCONTEXT_NIA(UC) (UC)->uc_mcontext.uc_regs->gregs[PT_NIP] +#else +#error implement UCONTEXT_NIA +#endif + +static void segv_handler(int signr, siginfo_t *info, void *ptr) +{ + ucontext_t *uc = (ucontext_t *)ptr; + unsigned long addr = (unsigned long)info->si_addr; + unsigned long *ip = &UCONTEXT_NIA(uc); + unsigned long *ex_p = (unsigned long *)__start___ex_table; + + while (ex_p < (unsigned long *)__stop___ex_table) { + unsigned long insn, fixup; + + insn = *ex_p++; + fixup = *ex_p++; + + if (insn == *ip) { + *ip = fixup; + return; + } + } + + printf("No exception table match for NIA %lx ADDR %lx\n", *ip, addr); + abort(); +} + +static void setup_segv_handler(void) +{ + struct sigaction action; + + memset(&action, 0, sizeof(action)); + action.sa_sigaction = segv_handler; + action.sa_flags = SA_SIGINFO; + sigaction(SIGSEGV, &action, NULL); +} + +unsigned long COPY_LOOP(void *to, const void *from, unsigned long size); +unsigned long test_copy_tofrom_user_reference(void *to, const void *from, unsigned long size); + +static int total_passed; +static int total_failed; + +static void do_one_test(char *dstp, char *srcp, unsigned long len) +{ + unsigned long got, expected; + + got = COPY_LOOP(dstp, srcp, len); + expected = test_copy_tofrom_user_reference(dstp, srcp, len); + + if (got != expected) { + total_failed++; + printf("FAIL from=%p to=%p len=%ld returned %ld, expected %ld\n", + srcp, dstp, len, got, expected); + //abort(); + } else + total_passed++; +} + +//#define MAX_LEN 512 +#define MAX_LEN 16 + +int test_copy_exception(void) +{ + int page_size; + static char *p, *q; + unsigned long src, dst, len; + + page_size = getpagesize(); + p = mmap(NULL, page_size * 2, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + + if (p == MAP_FAILED) { + perror("mmap"); + exit(1); + } + + memset(p, 0, page_size); + + setup_segv_handler(); + + if (mprotect(p + page_size, page_size, PROT_NONE)) { + perror("mprotect"); + exit(1); + } + + q = p + page_size - MAX_LEN; + + for (src = 0; src < MAX_LEN; src++) { + for (dst = 0; dst < MAX_LEN; dst++) { + for (len = 0; len < MAX_LEN+1; len++) { + // printf("from=%p to=%p len=%ld\n", q+dst, q+src, len); + do_one_test(q+dst, q+src, len); + } + } + } + + printf("Totals:\n"); + printf(" Pass: %d\n", total_passed); + printf(" Fail: %d\n", total_failed); + + return 0; +} + +int main(void) +{ + return test_harness(test_copy_exception, str(COPY_LOOP)); +} diff --git a/tools/testing/selftests/powerpc/copyloops/stubs.S b/tools/testing/selftests/powerpc/copyloops/stubs.S new file mode 100644 index 000000000000..ec8bcf2bf1c2 --- /dev/null +++ b/tools/testing/selftests/powerpc/copyloops/stubs.S @@ -0,0 +1,19 @@ +#include <asm/ppc_asm.h> + +FUNC_START(enter_vmx_usercopy) + li r3,1 + blr + +FUNC_START(exit_vmx_usercopy) + li r3,0 + blr + +FUNC_START(enter_vmx_ops) + li r3,1 + blr + +FUNC_START(exit_vmx_ops) + blr + +FUNC_START(__copy_tofrom_user_base) + blr diff --git a/tools/testing/selftests/powerpc/dscr/dscr_inherit_exec_test.c b/tools/testing/selftests/powerpc/dscr/dscr_inherit_exec_test.c index 08a8b95e3bc1..c8c240accc0c 100644 --- a/tools/testing/selftests/powerpc/dscr/dscr_inherit_exec_test.c +++ b/tools/testing/selftests/powerpc/dscr/dscr_inherit_exec_test.c @@ -5,8 +5,8 @@ * verifies that the child is using the changed DSCR using mfspr. * * When using the privilege state SPR, the instructions such as - * mfspr or mtspr are priviledged and the kernel emulates them - * for us. Instructions using problem state SPR can be exuecuted + * mfspr or mtspr are privileged and the kernel emulates them + * for us. Instructions using problem state SPR can be executed * directly without any emulation if the HW supports them. Else * they also get emulated by the kernel. * @@ -19,7 +19,7 @@ */ #include "dscr.h" -static char prog[LEN_MAX]; +static char *prog; static void do_exec(unsigned long parent_dscr) { @@ -104,6 +104,6 @@ int main(int argc, char *argv[]) exit(1); } - strncpy(prog, argv[0], strlen(argv[0])); + prog = argv[0]; return test_harness(dscr_inherit_exec, "dscr_inherit_exec_test"); } diff --git a/tools/testing/selftests/powerpc/harness.c b/tools/testing/selftests/powerpc/harness.c index 66d31de60b9a..9d7166dfad1e 100644 --- a/tools/testing/selftests/powerpc/harness.c +++ b/tools/testing/selftests/powerpc/harness.c @@ -85,13 +85,13 @@ wait: return status; } -static void alarm_handler(int signum) +static void sig_handler(int signum) { - /* Jut wake us up from waitpid */ + /* Just wake us up from waitpid */ } -static struct sigaction alarm_action = { - .sa_handler = alarm_handler, +static struct sigaction sig_action = { + .sa_handler = sig_handler, }; void test_harness_set_timeout(uint64_t time) @@ -106,8 +106,14 @@ int test_harness(int (test_function)(void), char *name) test_start(name); test_set_git_version(GIT_VERSION); - if (sigaction(SIGALRM, &alarm_action, NULL)) { - perror("sigaction"); + if (sigaction(SIGINT, &sig_action, NULL)) { + perror("sigaction (sigint)"); + test_error(name); + return 1; + } + + if (sigaction(SIGALRM, &sig_action, NULL)) { + perror("sigaction (sigalrm)"); test_error(name); return 1; } diff --git a/tools/testing/selftests/powerpc/include/utils.h b/tools/testing/selftests/powerpc/include/utils.h index 735815b3ad7f..c58c370828b4 100644 --- a/tools/testing/selftests/powerpc/include/utils.h +++ b/tools/testing/selftests/powerpc/include/utils.h @@ -48,6 +48,8 @@ static inline bool have_hwcap2(unsigned long ftr2) } #endif +bool is_ppc64le(void); + /* Yes, this is evil */ #define FAIL_IF(x) \ do { \ diff --git a/tools/testing/selftests/powerpc/pmu/ebb/instruction_count_test.c b/tools/testing/selftests/powerpc/pmu/ebb/instruction_count_test.c index ae9a79086111..35a3426e341c 100644 --- a/tools/testing/selftests/powerpc/pmu/ebb/instruction_count_test.c +++ b/tools/testing/selftests/powerpc/pmu/ebb/instruction_count_test.c @@ -162,5 +162,6 @@ int instruction_count(void) int main(void) { + test_harness_set_timeout(300); return test_harness(instruction_count, "instruction_count"); } diff --git a/tools/testing/selftests/powerpc/pmu/ebb/lost_exception_test.c b/tools/testing/selftests/powerpc/pmu/ebb/lost_exception_test.c index eb8acb78bc6c..2ed7ad33f7a3 100644 --- a/tools/testing/selftests/powerpc/pmu/ebb/lost_exception_test.c +++ b/tools/testing/selftests/powerpc/pmu/ebb/lost_exception_test.c @@ -98,5 +98,6 @@ static int lost_exception(void) int main(void) { + test_harness_set_timeout(300); return test_harness(lost_exception, "lost_exception"); } diff --git a/tools/testing/selftests/powerpc/primitives/asm/asm-const.h b/tools/testing/selftests/powerpc/primitives/asm/asm-const.h new file mode 120000 index 000000000000..18d8be13e67f --- /dev/null +++ b/tools/testing/selftests/powerpc/primitives/asm/asm-const.h @@ -0,0 +1 @@ +../../../../../../arch/powerpc/include/asm/asm-const.h
\ No newline at end of file diff --git a/tools/testing/selftests/powerpc/primitives/asm/feature-fixups.h b/tools/testing/selftests/powerpc/primitives/asm/feature-fixups.h new file mode 120000 index 000000000000..8dc6d4d46e8e --- /dev/null +++ b/tools/testing/selftests/powerpc/primitives/asm/feature-fixups.h @@ -0,0 +1 @@ +../../../../../../arch/powerpc/include/asm/feature-fixups.h
\ No newline at end of file diff --git a/tools/testing/selftests/powerpc/ptrace/core-pkey.c b/tools/testing/selftests/powerpc/ptrace/core-pkey.c index 36bc312b1f5c..e23e2e199eb4 100644 --- a/tools/testing/selftests/powerpc/ptrace/core-pkey.c +++ b/tools/testing/selftests/powerpc/ptrace/core-pkey.c @@ -140,6 +140,10 @@ static int child(struct shared_info *info) if (disable_execute) info->iamr |= 1ul << pkeyshift(pkey1); + else + info->iamr &= ~(1ul << pkeyshift(pkey1)); + + info->iamr &= ~(1ul << pkeyshift(pkey2) | 1ul << pkeyshift(pkey3)); info->uamor |= 3ul << pkeyshift(pkey1) | 3ul << pkeyshift(pkey2); diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-pkey.c b/tools/testing/selftests/powerpc/ptrace/ptrace-pkey.c index 5cf631f792cc..bdbbbe8431e0 100644 --- a/tools/testing/selftests/powerpc/ptrace/ptrace-pkey.c +++ b/tools/testing/selftests/powerpc/ptrace/ptrace-pkey.c @@ -104,6 +104,10 @@ static int child(struct shared_info *info) if (disable_execute) info->expected_iamr |= 1ul << pkeyshift(pkey1); + else + info->expected_iamr &= ~(1ul << pkeyshift(pkey1)); + + info->expected_iamr &= ~(1ul << pkeyshift(pkey2) | 1ul << pkeyshift(pkey3)); info->expected_uamor |= 3ul << pkeyshift(pkey1) | 3ul << pkeyshift(pkey2); diff --git a/tools/testing/selftests/powerpc/stringloops/Makefile b/tools/testing/selftests/powerpc/stringloops/Makefile index 1125e489055e..10b35c87a4f4 100644 --- a/tools/testing/selftests/powerpc/stringloops/Makefile +++ b/tools/testing/selftests/powerpc/stringloops/Makefile @@ -1,10 +1,33 @@ # SPDX-License-Identifier: GPL-2.0 # The loops are all 64-bit code -CFLAGS += -m64 CFLAGS += -I$(CURDIR) -TEST_GEN_PROGS := memcmp -EXTRA_SOURCES := memcmp_64.S ../harness.c +EXTRA_SOURCES := ../harness.c + +build_32bit = $(shell if ($(CC) $(CFLAGS) -m32 -o /dev/null memcmp.c >/dev/null 2>&1) then echo "1"; fi) + +TEST_GEN_PROGS := memcmp_64 strlen + +$(OUTPUT)/memcmp_64: memcmp.c +$(OUTPUT)/memcmp_64: CFLAGS += -m64 -maltivec + +ifeq ($(build_32bit),1) +$(OUTPUT)/memcmp_32: memcmp.c +$(OUTPUT)/memcmp_32: CFLAGS += -m32 + +TEST_GEN_PROGS += memcmp_32 +endif + +$(OUTPUT)/strlen: strlen.c string.c + +ifeq ($(build_32bit),1) +$(OUTPUT)/strlen_32: strlen.c +$(OUTPUT)/strlen_32: CFLAGS += -m32 + +TEST_GEN_PROGS += strlen_32 +endif + +ASFLAGS = $(CFLAGS) include ../../lib.mk diff --git a/tools/testing/selftests/powerpc/stringloops/asm/cache.h b/tools/testing/selftests/powerpc/stringloops/asm/cache.h new file mode 100644 index 000000000000..8a2840831122 --- /dev/null +++ b/tools/testing/selftests/powerpc/stringloops/asm/cache.h @@ -0,0 +1 @@ +#define IFETCH_ALIGN_BYTES 4 diff --git a/tools/testing/selftests/powerpc/stringloops/asm/ppc-opcode.h b/tools/testing/selftests/powerpc/stringloops/asm/ppc-opcode.h new file mode 100644 index 000000000000..9de413c0c2cb --- /dev/null +++ b/tools/testing/selftests/powerpc/stringloops/asm/ppc-opcode.h @@ -0,0 +1,39 @@ +/* + * Copyright 2009 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * provides masks and opcode images for use by code generation, emulation + * and for instructions that older assemblers might not know about + */ +#ifndef _ASM_POWERPC_PPC_OPCODE_H +#define _ASM_POWERPC_PPC_OPCODE_H + + +# define stringify_in_c(...) __VA_ARGS__ +# define ASM_CONST(x) x + + +#define PPC_INST_VCMPEQUD_RC 0x100000c7 +#define PPC_INST_VCMPEQUB_RC 0x10000006 + +#define __PPC_RC21 (0x1 << 10) + +/* macros to insert fields into opcodes */ +#define ___PPC_RA(a) (((a) & 0x1f) << 16) +#define ___PPC_RB(b) (((b) & 0x1f) << 11) +#define ___PPC_RS(s) (((s) & 0x1f) << 21) +#define ___PPC_RT(t) ___PPC_RS(t) + +#define VCMPEQUD_RC(vrt, vra, vrb) stringify_in_c(.long PPC_INST_VCMPEQUD_RC | \ + ___PPC_RT(vrt) | ___PPC_RA(vra) | \ + ___PPC_RB(vrb) | __PPC_RC21) + +#define VCMPEQUB_RC(vrt, vra, vrb) stringify_in_c(.long PPC_INST_VCMPEQUB_RC | \ + ___PPC_RT(vrt) | ___PPC_RA(vra) | \ + ___PPC_RB(vrb) | __PPC_RC21) + +#endif /* _ASM_POWERPC_PPC_OPCODE_H */ diff --git a/tools/testing/selftests/powerpc/stringloops/asm/ppc_asm.h b/tools/testing/selftests/powerpc/stringloops/asm/ppc_asm.h index 136242ec4b0e..d2c0a911f55e 100644 --- a/tools/testing/selftests/powerpc/stringloops/asm/ppc_asm.h +++ b/tools/testing/selftests/powerpc/stringloops/asm/ppc_asm.h @@ -1,4 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _PPC_ASM_H +#define __PPC_ASM_H #include <ppc-asm.h> #ifndef r1 @@ -6,3 +8,26 @@ #endif #define _GLOBAL(A) FUNC_START(test_ ## A) +#define _GLOBAL_TOC(A) FUNC_START(test_ ## A) + +#define CONFIG_ALTIVEC + +#define R14 r14 +#define R15 r15 +#define R16 r16 +#define R17 r17 +#define R18 r18 +#define R19 r19 +#define R20 r20 +#define R21 r21 +#define R22 r22 +#define R29 r29 +#define R30 r30 +#define R31 r31 + +#define STACKFRAMESIZE 256 +#define STK_REG(i) (112 + ((i)-14)*8) + +#define BEGIN_FTR_SECTION +#define END_FTR_SECTION_IFSET(val) +#endif diff --git a/tools/testing/selftests/powerpc/stringloops/memcmp.c b/tools/testing/selftests/powerpc/stringloops/memcmp.c index 8250db25b379..b1fa7546957f 100644 --- a/tools/testing/selftests/powerpc/stringloops/memcmp.c +++ b/tools/testing/selftests/powerpc/stringloops/memcmp.c @@ -2,20 +2,40 @@ #include <malloc.h> #include <stdlib.h> #include <string.h> +#include <time.h> #include "utils.h" #define SIZE 256 #define ITERATIONS 10000 +#define LARGE_SIZE (5 * 1024) +#define LARGE_ITERATIONS 1000 +#define LARGE_MAX_OFFSET 32 +#define LARGE_SIZE_START 4096 + +#define MAX_OFFSET_DIFF_S1_S2 48 + +int vmx_count; +int enter_vmx_ops(void) +{ + vmx_count++; + return 1; +} + +void exit_vmx_ops(void) +{ + vmx_count--; +} int test_memcmp(const void *s1, const void *s2, size_t n); /* test all offsets and lengths */ -static void test_one(char *s1, char *s2) +static void test_one(char *s1, char *s2, unsigned long max_offset, + unsigned long size_start, unsigned long max_size) { unsigned long offset, size; - for (offset = 0; offset < SIZE; offset++) { - for (size = 0; size < (SIZE-offset); size++) { + for (offset = 0; offset < max_offset; offset++) { + for (size = size_start; size < (max_size - offset); size++) { int x, y; unsigned long i; @@ -35,70 +55,105 @@ static void test_one(char *s1, char *s2) printf("\n"); abort(); } + + if (vmx_count != 0) { + printf("vmx enter/exit not paired.(offset:%ld size:%ld s1:%p s2:%p vc:%d\n", + offset, size, s1, s2, vmx_count); + printf("\n"); + abort(); + } } } } -static int testcase(void) +static int testcase(bool islarge) { char *s1; char *s2; unsigned long i; - s1 = memalign(128, SIZE); + unsigned long comp_size = (islarge ? LARGE_SIZE : SIZE); + unsigned long alloc_size = comp_size + MAX_OFFSET_DIFF_S1_S2; + int iterations = islarge ? LARGE_ITERATIONS : ITERATIONS; + + s1 = memalign(128, alloc_size); if (!s1) { perror("memalign"); exit(1); } - s2 = memalign(128, SIZE); + s2 = memalign(128, alloc_size); if (!s2) { perror("memalign"); exit(1); } - srandom(1); + srandom(time(0)); - for (i = 0; i < ITERATIONS; i++) { + for (i = 0; i < iterations; i++) { unsigned long j; unsigned long change; + char *rand_s1 = s1; + char *rand_s2 = s2; - for (j = 0; j < SIZE; j++) + for (j = 0; j < alloc_size; j++) s1[j] = random(); - memcpy(s2, s1, SIZE); + rand_s1 += random() % MAX_OFFSET_DIFF_S1_S2; + rand_s2 += random() % MAX_OFFSET_DIFF_S1_S2; + memcpy(rand_s2, rand_s1, comp_size); /* change one byte */ - change = random() % SIZE; - s2[change] = random() & 0xff; - - test_one(s1, s2); + change = random() % comp_size; + rand_s2[change] = random() & 0xff; + + if (islarge) + test_one(rand_s1, rand_s2, LARGE_MAX_OFFSET, + LARGE_SIZE_START, comp_size); + else + test_one(rand_s1, rand_s2, SIZE, 0, comp_size); } - srandom(1); + srandom(time(0)); - for (i = 0; i < ITERATIONS; i++) { + for (i = 0; i < iterations; i++) { unsigned long j; unsigned long change; + char *rand_s1 = s1; + char *rand_s2 = s2; - for (j = 0; j < SIZE; j++) + for (j = 0; j < alloc_size; j++) s1[j] = random(); - memcpy(s2, s1, SIZE); + rand_s1 += random() % MAX_OFFSET_DIFF_S1_S2; + rand_s2 += random() % MAX_OFFSET_DIFF_S1_S2; + memcpy(rand_s2, rand_s1, comp_size); /* change multiple bytes, 1/8 of total */ - for (j = 0; j < SIZE / 8; j++) { - change = random() % SIZE; + for (j = 0; j < comp_size / 8; j++) { + change = random() % comp_size; s2[change] = random() & 0xff; } - test_one(s1, s2); + if (islarge) + test_one(rand_s1, rand_s2, LARGE_MAX_OFFSET, + LARGE_SIZE_START, comp_size); + else + test_one(rand_s1, rand_s2, SIZE, 0, comp_size); } return 0; } +static int testcases(void) +{ + testcase(0); + testcase(1); + return 0; +} + int main(void) { - return test_harness(testcase, "memcmp"); + test_harness_set_timeout(300); + return test_harness(testcases, "memcmp"); } diff --git a/tools/testing/selftests/powerpc/stringloops/memcmp_32.S b/tools/testing/selftests/powerpc/stringloops/memcmp_32.S new file mode 120000 index 000000000000..056f2b3af789 --- /dev/null +++ b/tools/testing/selftests/powerpc/stringloops/memcmp_32.S @@ -0,0 +1 @@ +../../../../../arch/powerpc/lib/memcmp_32.S
\ No newline at end of file diff --git a/tools/testing/selftests/powerpc/stringloops/string.c b/tools/testing/selftests/powerpc/stringloops/string.c new file mode 100644 index 000000000000..45e7775415c7 --- /dev/null +++ b/tools/testing/selftests/powerpc/stringloops/string.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copied from linux/lib/string.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include <stddef.h> + +/** + * strlen - Find the length of a string + * @s: The string to be sized + */ +size_t test_strlen(const char *s) +{ + const char *sc; + + for (sc = s; *sc != '\0'; ++sc) + /* nothing */; + return sc - s; +} diff --git a/tools/testing/selftests/powerpc/stringloops/strlen.c b/tools/testing/selftests/powerpc/stringloops/strlen.c new file mode 100644 index 000000000000..9055ebc484d0 --- /dev/null +++ b/tools/testing/selftests/powerpc/stringloops/strlen.c @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <malloc.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include "utils.h" + +#define SIZE 256 +#define ITERATIONS 1000 +#define ITERATIONS_BENCH 100000 + +int test_strlen(const void *s); + +/* test all offsets and lengths */ +static void test_one(char *s) +{ + unsigned long offset; + + for (offset = 0; offset < SIZE; offset++) { + int x, y; + unsigned long i; + + y = strlen(s + offset); + x = test_strlen(s + offset); + + if (x != y) { + printf("strlen() returned %d, should have returned %d (%p offset %ld)\n", x, y, s, offset); + + for (i = offset; i < SIZE; i++) + printf("%02x ", s[i]); + printf("\n"); + } + } +} + +static void bench_test(char *s) +{ + struct timespec ts_start, ts_end; + int i; + + clock_gettime(CLOCK_MONOTONIC, &ts_start); + + for (i = 0; i < ITERATIONS_BENCH; i++) + test_strlen(s); + + clock_gettime(CLOCK_MONOTONIC, &ts_end); + + printf("len %3.3d : time = %.6f\n", test_strlen(s), ts_end.tv_sec - ts_start.tv_sec + (ts_end.tv_nsec - ts_start.tv_nsec) / 1e9); +} + +static int testcase(void) +{ + char *s; + unsigned long i; + + s = memalign(128, SIZE); + if (!s) { + perror("memalign"); + exit(1); + } + + srandom(1); + + memset(s, 0, SIZE); + for (i = 0; i < SIZE; i++) { + char c; + + do { + c = random() & 0x7f; + } while (!c); + s[i] = c; + test_one(s); + } + + for (i = 0; i < ITERATIONS; i++) { + unsigned long j; + + for (j = 0; j < SIZE; j++) { + char c; + + do { + c = random() & 0x7f; + } while (!c); + s[j] = c; + } + for (j = 0; j < sizeof(long); j++) { + s[SIZE - 1 - j] = 0; + test_one(s); + } + } + + for (i = 0; i < SIZE; i++) { + char c; + + do { + c = random() & 0x7f; + } while (!c); + s[i] = c; + } + + bench_test(s); + + s[16] = 0; + bench_test(s); + + s[8] = 0; + bench_test(s); + + s[4] = 0; + bench_test(s); + + s[3] = 0; + bench_test(s); + + s[2] = 0; + bench_test(s); + + s[1] = 0; + bench_test(s); + + return 0; +} + +int main(void) +{ + return test_harness(testcase, "strlen"); +} diff --git a/tools/testing/selftests/powerpc/stringloops/strlen_32.S b/tools/testing/selftests/powerpc/stringloops/strlen_32.S new file mode 120000 index 000000000000..72b13731b24c --- /dev/null +++ b/tools/testing/selftests/powerpc/stringloops/strlen_32.S @@ -0,0 +1 @@ +../../../../../arch/powerpc/lib/strlen_32.S
\ No newline at end of file diff --git a/tools/testing/selftests/powerpc/tm/tm-sigreturn.c b/tools/testing/selftests/powerpc/tm/tm-sigreturn.c index 85d63449243b..9a6017a1d769 100644 --- a/tools/testing/selftests/powerpc/tm/tm-sigreturn.c +++ b/tools/testing/selftests/powerpc/tm/tm-sigreturn.c @@ -55,6 +55,7 @@ int tm_sigreturn(void) uint64_t ret = 0; SKIP_IF(!have_htm()); + SKIP_IF(!is_ppc64le()); memset(&sa, 0, sizeof(sa)); sa.sa_handler = handler; diff --git a/tools/testing/selftests/powerpc/tm/tm-tar.c b/tools/testing/selftests/powerpc/tm/tm-tar.c index 2d2fcc2b7a60..f31fe5a28ddb 100644 --- a/tools/testing/selftests/powerpc/tm/tm-tar.c +++ b/tools/testing/selftests/powerpc/tm/tm-tar.c @@ -26,6 +26,7 @@ int test_tar(void) int i; SKIP_IF(!have_htm()); + SKIP_IF(!is_ppc64le()); for (i = 0; i < num_loops; i++) { diff --git a/tools/testing/selftests/powerpc/tm/tm-vmxcopy.c b/tools/testing/selftests/powerpc/tm/tm-vmxcopy.c index 0274de7b11f3..fe52811584ae 100644 --- a/tools/testing/selftests/powerpc/tm/tm-vmxcopy.c +++ b/tools/testing/selftests/powerpc/tm/tm-vmxcopy.c @@ -46,6 +46,7 @@ int test_vmxcopy() uint64_t aborted = 0; SKIP_IF(!have_htm()); + SKIP_IF(!is_ppc64le()); fd = mkstemp(tmpfile); assert(fd >= 0); diff --git a/tools/testing/selftests/powerpc/utils.c b/tools/testing/selftests/powerpc/utils.c index d46916867a6f..aa8fc1e6365b 100644 --- a/tools/testing/selftests/powerpc/utils.c +++ b/tools/testing/selftests/powerpc/utils.c @@ -11,8 +11,10 @@ #include <link.h> #include <sched.h> #include <stdio.h> +#include <string.h> #include <sys/stat.h> #include <sys/types.h> +#include <sys/utsname.h> #include <unistd.h> #include "utils.h" @@ -104,3 +106,18 @@ int pick_online_cpu(void) printf("No cpus in affinity mask?!\n"); return -1; } + +bool is_ppc64le(void) +{ + struct utsname uts; + int rc; + + errno = 0; + rc = uname(&uts); + if (rc) { + perror("uname"); + return false; + } + + return strcmp(uts.machine, "ppc64le") == 0; +} diff --git a/tools/testing/selftests/proc/.gitignore b/tools/testing/selftests/proc/.gitignore index 74e5912e9f2e..82121a81681f 100644 --- a/tools/testing/selftests/proc/.gitignore +++ b/tools/testing/selftests/proc/.gitignore @@ -9,3 +9,5 @@ /proc-uptime-001 /proc-uptime-002 /read +/self +/thread-self diff --git a/tools/testing/selftests/proc/Makefile b/tools/testing/selftests/proc/Makefile index db310eedc268..1c12c34cf85d 100644 --- a/tools/testing/selftests/proc/Makefile +++ b/tools/testing/selftests/proc/Makefile @@ -1,4 +1,5 @@ CFLAGS += -Wall -O2 -Wno-unused-function +CFLAGS += -D_GNU_SOURCE TEST_GEN_PROGS := TEST_GEN_PROGS += fd-001-lookup @@ -12,5 +13,7 @@ TEST_GEN_PROGS += proc-self-wchan TEST_GEN_PROGS += proc-uptime-001 TEST_GEN_PROGS += proc-uptime-002 TEST_GEN_PROGS += read +TEST_GEN_PROGS += self +TEST_GEN_PROGS += thread-self include ../lib.mk diff --git a/tools/testing/selftests/proc/proc.h b/tools/testing/selftests/proc/proc.h index 4e178166fd84..b7d57ea40237 100644 --- a/tools/testing/selftests/proc/proc.h +++ b/tools/testing/selftests/proc/proc.h @@ -6,6 +6,18 @@ #include <stdbool.h> #include <stdlib.h> #include <string.h> +#include <unistd.h> +#include <sys/syscall.h> + +static inline pid_t sys_getpid(void) +{ + return syscall(SYS_getpid); +} + +static inline pid_t sys_gettid(void) +{ + return syscall(SYS_gettid); +} static inline bool streq(const char *s1, const char *s2) { diff --git a/tools/testing/selftests/proc/self.c b/tools/testing/selftests/proc/self.c new file mode 100644 index 000000000000..21c15a1ffefb --- /dev/null +++ b/tools/testing/selftests/proc/self.c @@ -0,0 +1,39 @@ +/* + * Copyright © 2018 Alexey Dobriyan <adobriyan@gmail.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +// Test that /proc/self gives correct TGID. +#undef NDEBUG +#include <assert.h> +#include <stdio.h> +#include <unistd.h> + +#include "proc.h" + +int main(void) +{ + char buf1[64], buf2[64]; + pid_t pid; + ssize_t rv; + + pid = sys_getpid(); + snprintf(buf1, sizeof(buf1), "%u", pid); + + rv = readlink("/proc/self", buf2, sizeof(buf2)); + assert(rv == strlen(buf1)); + buf2[rv] = '\0'; + assert(streq(buf1, buf2)); + + return 0; +} diff --git a/tools/testing/selftests/proc/thread-self.c b/tools/testing/selftests/proc/thread-self.c new file mode 100644 index 000000000000..4b23b39b7ae0 --- /dev/null +++ b/tools/testing/selftests/proc/thread-self.c @@ -0,0 +1,64 @@ +/* + * Copyright © 2018 Alexey Dobriyan <adobriyan@gmail.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +// Test that /proc/thread-self gives correct TGID/PID. +#undef NDEBUG +#include <assert.h> +#include <sched.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/wait.h> + +#include "proc.h" + +int f(void *arg) +{ + char buf1[64], buf2[64]; + pid_t pid, tid; + ssize_t rv; + + pid = sys_getpid(); + tid = sys_gettid(); + snprintf(buf1, sizeof(buf1), "%u/task/%u", pid, tid); + + rv = readlink("/proc/thread-self", buf2, sizeof(buf2)); + assert(rv == strlen(buf1)); + buf2[rv] = '\0'; + assert(streq(buf1, buf2)); + + if (arg) + exit(0); + return 0; +} + +int main(void) +{ + const int PAGE_SIZE = sysconf(_SC_PAGESIZE); + pid_t pid; + void *stack; + + /* main thread */ + f((void *)0); + + stack = mmap(NULL, 2 * PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + assert(stack != MAP_FAILED); + /* side thread */ + pid = clone(f, stack + PAGE_SIZE, CLONE_THREAD|CLONE_SIGHAND|CLONE_VM, (void *)1); + assert(pid > 0); + pause(); + + return 0; +} diff --git a/tools/testing/selftests/rcutorture/bin/configinit.sh b/tools/testing/selftests/rcutorture/bin/configinit.sh index c15f270e121d..65541c21a544 100755 --- a/tools/testing/selftests/rcutorture/bin/configinit.sh +++ b/tools/testing/selftests/rcutorture/bin/configinit.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# Usage: configinit.sh config-spec-file [ build output dir ] +# Usage: configinit.sh config-spec-file build-output-dir results-dir # # Create a .config file from the spec file. Run from the kernel source tree. # Exits with 0 if all went well, with 1 if all went well but the config @@ -40,20 +40,18 @@ mkdir $T c=$1 buildloc=$2 +resdir=$3 builddir= -if test -n $buildloc +if echo $buildloc | grep -q '^O=' then - if echo $buildloc | grep -q '^O=' + builddir=`echo $buildloc | sed -e 's/^O=//'` + if test ! -d $builddir then - builddir=`echo $buildloc | sed -e 's/^O=//'` - if test ! -d $builddir - then - mkdir $builddir - fi - else - echo Bad build directory: \"$buildloc\" - exit 2 + mkdir $builddir fi +else + echo Bad build directory: \"$buildloc\" + exit 2 fi sed -e 's/^\(CONFIG[0-9A-Z_]*\)=.*$/grep -v "^# \1" |/' < $c > $T/u.sh @@ -61,12 +59,12 @@ sed -e 's/^\(CONFIG[0-9A-Z_]*=\).*$/grep -v \1 |/' < $c >> $T/u.sh grep '^grep' < $T/u.sh > $T/upd.sh echo "cat - $c" >> $T/upd.sh make mrproper -make $buildloc distclean > $builddir/Make.distclean 2>&1 -make $buildloc $TORTURE_DEFCONFIG > $builddir/Make.defconfig.out 2>&1 +make $buildloc distclean > $resdir/Make.distclean 2>&1 +make $buildloc $TORTURE_DEFCONFIG > $resdir/Make.defconfig.out 2>&1 mv $builddir/.config $builddir/.config.sav sh $T/upd.sh < $builddir/.config.sav > $builddir/.config cp $builddir/.config $builddir/.config.new -yes '' | make $buildloc oldconfig > $builddir/Make.oldconfig.out 2> $builddir/Make.oldconfig.err +yes '' | make $buildloc oldconfig > $resdir/Make.oldconfig.out 2> $resdir/Make.oldconfig.err # verify new config matches specification. configcheck.sh $builddir/.config $c diff --git a/tools/testing/selftests/rcutorture/bin/kvm-build.sh b/tools/testing/selftests/rcutorture/bin/kvm-build.sh index 34d126734cde..9115fcdb5617 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-build.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-build.sh @@ -2,7 +2,7 @@ # # Build a kvm-ready Linux kernel from the tree in the current directory. # -# Usage: kvm-build.sh config-template build-dir +# Usage: kvm-build.sh config-template build-dir resdir # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -29,6 +29,7 @@ then exit 1 fi builddir=${2} +resdir=${3} T=${TMPDIR-/tmp}/test-linux.sh.$$ trap 'rm -rf $T' 0 @@ -41,19 +42,19 @@ CONFIG_VIRTIO_PCI=y CONFIG_VIRTIO_CONSOLE=y ___EOF___ -configinit.sh $T/config O=$builddir +configinit.sh $T/config O=$builddir $resdir retval=$? if test $retval -gt 1 then exit 2 fi ncpus=`cpus2use.sh` -make O=$builddir -j$ncpus $TORTURE_KMAKE_ARG > $builddir/Make.out 2>&1 +make O=$builddir -j$ncpus $TORTURE_KMAKE_ARG > $resdir/Make.out 2>&1 retval=$? -if test $retval -ne 0 || grep "rcu[^/]*": < $builddir/Make.out | egrep -q "Stop|Error|error:|warning:" || egrep -q "Stop|Error|error:" < $builddir/Make.out +if test $retval -ne 0 || grep "rcu[^/]*": < $resdir/Make.out | egrep -q "Stop|Error|error:|warning:" || egrep -q "Stop|Error|error:" < $resdir/Make.out then echo Kernel build error - egrep "Stop|Error|error:|warning:" < $builddir/Make.out + egrep "Stop|Error|error:|warning:" < $resdir/Make.out echo Run aborted. exit 3 fi diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh index 477ecb1293ab..0fa8a61ccb7b 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh @@ -70,4 +70,5 @@ else else print_warning $nclosecalls "Reader Batch close calls in" $(($dur/60)) minute run: $i fi + echo $nclosecalls "Reader Batch close calls in" $(($dur/60)) minute run: $i > $i/console.log.rcu.diags fi diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh index c27e97824163..c9bab57a77eb 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh @@ -39,6 +39,7 @@ do head -1 $resdir/log fi TORTURE_SUITE="`cat $i/../TORTURE_SUITE`" + rm -f $i/console.log.*.diags kvm-recheck-${TORTURE_SUITE}.sh $i if test -f "$i/console.log" then diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh index c5b0f94341d9..f7247ee00514 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh @@ -98,14 +98,15 @@ then ln -s $base_resdir/.config $resdir # for kvm-recheck.sh # Arch-independent indicator touch $resdir/builtkernel -elif kvm-build.sh $T/Kc2 $builddir +elif kvm-build.sh $T/Kc2 $builddir $resdir then # Had to build a kernel for this test. QEMU="`identify_qemu $builddir/vmlinux`" BOOT_IMAGE="`identify_boot_image $QEMU`" - cp $builddir/Make*.out $resdir cp $builddir/vmlinux $resdir cp $builddir/.config $resdir + cp $builddir/Module.symvers $resdir > /dev/null || : + cp $builddir/System.map $resdir > /dev/null || : if test -n "$BOOT_IMAGE" then cp $builddir/$BOOT_IMAGE $resdir diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh index 56610dbbdf73..5a7a62d76a50 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm.sh @@ -347,7 +347,7 @@ function dump(first, pastlast, batchnum) print "needqemurun=" jn=1 for (j = first; j < pastlast; j++) { - builddir=KVM "/b" jn + builddir=KVM "/b1" cpusr[jn] = cpus[j]; if (cfrep[cf[j]] == "") { cfr[jn] = cf[j]; diff --git a/tools/testing/selftests/rcutorture/bin/parse-console.sh b/tools/testing/selftests/rcutorture/bin/parse-console.sh index 17293436f551..84933f6aed77 100755 --- a/tools/testing/selftests/rcutorture/bin/parse-console.sh +++ b/tools/testing/selftests/rcutorture/bin/parse-console.sh @@ -163,6 +163,13 @@ then print_warning Summary: $summary cat $T.diags >> $file.diags fi +for i in $file.*.diags +do + if test -f "$i" + then + cat $i >> $file.diags + fi +done if ! test -s $file.diags then rm -f $file.diags diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE03.boot b/tools/testing/selftests/rcutorture/configs/rcu/TREE03.boot index 5d2cc0bd50a0..5c3213cc3ad7 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE03.boot +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE03.boot @@ -1,5 +1,5 @@ -rcutorture.onoff_interval=1 rcutorture.onoff_holdoff=30 -rcutree.gp_preinit_delay=3 +rcutorture.onoff_interval=200 rcutorture.onoff_holdoff=30 +rcutree.gp_preinit_delay=12 rcutree.gp_init_delay=3 rcutree.gp_cleanup_delay=3 rcutree.kthread_prio=2 diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T.boot b/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T.boot deleted file mode 100644 index 883149b5f2d1..000000000000 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T.boot +++ /dev/null @@ -1 +0,0 @@ -rcutree.rcu_fanout_exact=1 diff --git a/tools/testing/selftests/rcutorture/configs/rcu/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/rcu/ver_functions.sh index 24ec91041957..7bab8246392b 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/ver_functions.sh +++ b/tools/testing/selftests/rcutorture/configs/rcu/ver_functions.sh @@ -39,7 +39,7 @@ rcutorture_param_onoff () { if ! bootparam_hotplug_cpu "$1" && configfrag_hotplug_cpu "$2" then echo CPU-hotplug kernel, adding rcutorture onoff. 1>&2 - echo rcutorture.onoff_interval=3 rcutorture.onoff_holdoff=30 + echo rcutorture.onoff_interval=1000 rcutorture.onoff_holdoff=30 fi } diff --git a/tools/testing/selftests/rseq/param_test.c b/tools/testing/selftests/rseq/param_test.c index 615252331813..642d4e12abea 100644 --- a/tools/testing/selftests/rseq/param_test.c +++ b/tools/testing/selftests/rseq/param_test.c @@ -90,6 +90,30 @@ unsigned int yield_mod_cnt, nr_abort; #error "Unsupported architecture" #endif +#elif defined(__s390__) + +#define RSEQ_INJECT_INPUT \ + , [loop_cnt_1]"m"(loop_cnt[1]) \ + , [loop_cnt_2]"m"(loop_cnt[2]) \ + , [loop_cnt_3]"m"(loop_cnt[3]) \ + , [loop_cnt_4]"m"(loop_cnt[4]) \ + , [loop_cnt_5]"m"(loop_cnt[5]) \ + , [loop_cnt_6]"m"(loop_cnt[6]) + +#define INJECT_ASM_REG "r12" + +#define RSEQ_INJECT_CLOBBER \ + , INJECT_ASM_REG + +#define RSEQ_INJECT_ASM(n) \ + "l %%" INJECT_ASM_REG ", %[loop_cnt_" #n "]\n\t" \ + "ltr %%" INJECT_ASM_REG ", %%" INJECT_ASM_REG "\n\t" \ + "je 333f\n\t" \ + "222:\n\t" \ + "ahi %%" INJECT_ASM_REG ", -1\n\t" \ + "jnz 222b\n\t" \ + "333:\n\t" + #elif defined(__ARMEL__) #define RSEQ_INJECT_INPUT \ @@ -114,6 +138,26 @@ unsigned int yield_mod_cnt, nr_abort; "bne 222b\n\t" \ "333:\n\t" +#elif defined(__AARCH64EL__) + +#define RSEQ_INJECT_INPUT \ + , [loop_cnt_1] "Qo" (loop_cnt[1]) \ + , [loop_cnt_2] "Qo" (loop_cnt[2]) \ + , [loop_cnt_3] "Qo" (loop_cnt[3]) \ + , [loop_cnt_4] "Qo" (loop_cnt[4]) \ + , [loop_cnt_5] "Qo" (loop_cnt[5]) \ + , [loop_cnt_6] "Qo" (loop_cnt[6]) + +#define INJECT_ASM_REG RSEQ_ASM_TMP_REG32 + +#define RSEQ_INJECT_ASM(n) \ + " ldr " INJECT_ASM_REG ", %[loop_cnt_" #n "]\n" \ + " cbz " INJECT_ASM_REG ", 333f\n" \ + "222:\n" \ + " sub " INJECT_ASM_REG ", " INJECT_ASM_REG ", #1\n" \ + " cbnz " INJECT_ASM_REG ", 222b\n" \ + "333:\n" + #elif __PPC__ #define RSEQ_INJECT_INPUT \ diff --git a/tools/testing/selftests/rseq/rseq-arm64.h b/tools/testing/selftests/rseq/rseq-arm64.h new file mode 100644 index 000000000000..954f34671ca6 --- /dev/null +++ b/tools/testing/selftests/rseq/rseq-arm64.h @@ -0,0 +1,594 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * rseq-arm64.h + * + * (C) Copyright 2016-2018 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com> + * (C) Copyright 2018 - Will Deacon <will.deacon@arm.com> + */ + +#define RSEQ_SIG 0xd428bc00 /* BRK #0x45E0 */ + +#define rseq_smp_mb() __asm__ __volatile__ ("dmb ish" ::: "memory") +#define rseq_smp_rmb() __asm__ __volatile__ ("dmb ishld" ::: "memory") +#define rseq_smp_wmb() __asm__ __volatile__ ("dmb ishst" ::: "memory") + +#define rseq_smp_load_acquire(p) \ +__extension__ ({ \ + __typeof(*p) ____p1; \ + switch (sizeof(*p)) { \ + case 1: \ + asm volatile ("ldarb %w0, %1" \ + : "=r" (*(__u8 *)p) \ + : "Q" (*p) : "memory"); \ + break; \ + case 2: \ + asm volatile ("ldarh %w0, %1" \ + : "=r" (*(__u16 *)p) \ + : "Q" (*p) : "memory"); \ + break; \ + case 4: \ + asm volatile ("ldar %w0, %1" \ + : "=r" (*(__u32 *)p) \ + : "Q" (*p) : "memory"); \ + break; \ + case 8: \ + asm volatile ("ldar %0, %1" \ + : "=r" (*(__u64 *)p) \ + : "Q" (*p) : "memory"); \ + break; \ + } \ + ____p1; \ +}) + +#define rseq_smp_acquire__after_ctrl_dep() rseq_smp_rmb() + +#define rseq_smp_store_release(p, v) \ +do { \ + switch (sizeof(*p)) { \ + case 1: \ + asm volatile ("stlrb %w1, %0" \ + : "=Q" (*p) \ + : "r" ((__u8)v) \ + : "memory"); \ + break; \ + case 2: \ + asm volatile ("stlrh %w1, %0" \ + : "=Q" (*p) \ + : "r" ((__u16)v) \ + : "memory"); \ + break; \ + case 4: \ + asm volatile ("stlr %w1, %0" \ + : "=Q" (*p) \ + : "r" ((__u32)v) \ + : "memory"); \ + break; \ + case 8: \ + asm volatile ("stlr %1, %0" \ + : "=Q" (*p) \ + : "r" ((__u64)v) \ + : "memory"); \ + break; \ + } \ +} while (0) + +#ifdef RSEQ_SKIP_FASTPATH +#include "rseq-skip.h" +#else /* !RSEQ_SKIP_FASTPATH */ + +#define RSEQ_ASM_TMP_REG32 "w15" +#define RSEQ_ASM_TMP_REG "x15" +#define RSEQ_ASM_TMP_REG_2 "x14" + +#define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, start_ip, \ + post_commit_offset, abort_ip) \ + " .pushsection __rseq_table, \"aw\"\n" \ + " .balign 32\n" \ + __rseq_str(label) ":\n" \ + " .long " __rseq_str(version) ", " __rseq_str(flags) "\n" \ + " .quad " __rseq_str(start_ip) ", " \ + __rseq_str(post_commit_offset) ", " \ + __rseq_str(abort_ip) "\n" \ + " .popsection\n" + +#define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \ + __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip, \ + (post_commit_ip - start_ip), abort_ip) + +#define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \ + RSEQ_INJECT_ASM(1) \ + " adrp " RSEQ_ASM_TMP_REG ", " __rseq_str(cs_label) "\n" \ + " add " RSEQ_ASM_TMP_REG ", " RSEQ_ASM_TMP_REG \ + ", :lo12:" __rseq_str(cs_label) "\n" \ + " str " RSEQ_ASM_TMP_REG ", %[" __rseq_str(rseq_cs) "]\n" \ + __rseq_str(label) ":\n" + +#define RSEQ_ASM_DEFINE_ABORT(label, abort_label) \ + " b 222f\n" \ + " .inst " __rseq_str(RSEQ_SIG) "\n" \ + __rseq_str(label) ":\n" \ + " b %l[" __rseq_str(abort_label) "]\n" \ + "222:\n" + +#define RSEQ_ASM_OP_STORE(value, var) \ + " str %[" __rseq_str(value) "], %[" __rseq_str(var) "]\n" + +#define RSEQ_ASM_OP_STORE_RELEASE(value, var) \ + " stlr %[" __rseq_str(value) "], %[" __rseq_str(var) "]\n" + +#define RSEQ_ASM_OP_FINAL_STORE(value, var, post_commit_label) \ + RSEQ_ASM_OP_STORE(value, var) \ + __rseq_str(post_commit_label) ":\n" + +#define RSEQ_ASM_OP_FINAL_STORE_RELEASE(value, var, post_commit_label) \ + RSEQ_ASM_OP_STORE_RELEASE(value, var) \ + __rseq_str(post_commit_label) ":\n" + +#define RSEQ_ASM_OP_CMPEQ(var, expect, label) \ + " ldr " RSEQ_ASM_TMP_REG ", %[" __rseq_str(var) "]\n" \ + " sub " RSEQ_ASM_TMP_REG ", " RSEQ_ASM_TMP_REG \ + ", %[" __rseq_str(expect) "]\n" \ + " cbnz " RSEQ_ASM_TMP_REG ", " __rseq_str(label) "\n" + +#define RSEQ_ASM_OP_CMPEQ32(var, expect, label) \ + " ldr " RSEQ_ASM_TMP_REG32 ", %[" __rseq_str(var) "]\n" \ + " sub " RSEQ_ASM_TMP_REG32 ", " RSEQ_ASM_TMP_REG32 \ + ", %w[" __rseq_str(expect) "]\n" \ + " cbnz " RSEQ_ASM_TMP_REG32 ", " __rseq_str(label) "\n" + +#define RSEQ_ASM_OP_CMPNE(var, expect, label) \ + " ldr " RSEQ_ASM_TMP_REG ", %[" __rseq_str(var) "]\n" \ + " sub " RSEQ_ASM_TMP_REG ", " RSEQ_ASM_TMP_REG \ + ", %[" __rseq_str(expect) "]\n" \ + " cbz " RSEQ_ASM_TMP_REG ", " __rseq_str(label) "\n" + +#define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \ + RSEQ_INJECT_ASM(2) \ + RSEQ_ASM_OP_CMPEQ32(current_cpu_id, cpu_id, label) + +#define RSEQ_ASM_OP_R_LOAD(var) \ + " ldr " RSEQ_ASM_TMP_REG ", %[" __rseq_str(var) "]\n" + +#define RSEQ_ASM_OP_R_STORE(var) \ + " str " RSEQ_ASM_TMP_REG ", %[" __rseq_str(var) "]\n" + +#define RSEQ_ASM_OP_R_LOAD_OFF(offset) \ + " ldr " RSEQ_ASM_TMP_REG ", [" RSEQ_ASM_TMP_REG \ + ", %[" __rseq_str(offset) "]]\n" + +#define RSEQ_ASM_OP_R_ADD(count) \ + " add " RSEQ_ASM_TMP_REG ", " RSEQ_ASM_TMP_REG \ + ", %[" __rseq_str(count) "]\n" + +#define RSEQ_ASM_OP_R_FINAL_STORE(var, post_commit_label) \ + " str " RSEQ_ASM_TMP_REG ", %[" __rseq_str(var) "]\n" \ + __rseq_str(post_commit_label) ":\n" + +#define RSEQ_ASM_OP_R_BAD_MEMCPY(dst, src, len) \ + " cbz %[" __rseq_str(len) "], 333f\n" \ + " mov " RSEQ_ASM_TMP_REG_2 ", %[" __rseq_str(len) "]\n" \ + "222: sub " RSEQ_ASM_TMP_REG_2 ", " RSEQ_ASM_TMP_REG_2 ", #1\n" \ + " ldrb " RSEQ_ASM_TMP_REG32 ", [%[" __rseq_str(src) "]" \ + ", " RSEQ_ASM_TMP_REG_2 "]\n" \ + " strb " RSEQ_ASM_TMP_REG32 ", [%[" __rseq_str(dst) "]" \ + ", " RSEQ_ASM_TMP_REG_2 "]\n" \ + " cbnz " RSEQ_ASM_TMP_REG_2 ", 222b\n" \ + "333:\n" + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu) +{ + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f) + RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail]) + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2]) +#endif + RSEQ_ASM_OP_FINAL_STORE(newv, v, 3) + RSEQ_INJECT_ASM(5) + RSEQ_ASM_DEFINE_ABORT(4, abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "Qo" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + [v] "Qo" (*v), + [expect] "r" (expect), + [newv] "r" (newv) + RSEQ_INJECT_INPUT + : "memory", RSEQ_ASM_TMP_REG + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +cmpfail: + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, + off_t voffp, intptr_t *load, int cpu) +{ + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f) + RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + RSEQ_ASM_OP_CMPNE(v, expectnot, %l[cmpfail]) + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + RSEQ_ASM_OP_CMPNE(v, expectnot, %l[error2]) +#endif + RSEQ_ASM_OP_R_LOAD(v) + RSEQ_ASM_OP_R_STORE(load) + RSEQ_ASM_OP_R_LOAD_OFF(voffp) + RSEQ_ASM_OP_R_FINAL_STORE(v, 3) + RSEQ_INJECT_ASM(5) + RSEQ_ASM_DEFINE_ABORT(4, abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "Qo" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + [v] "Qo" (*v), + [expectnot] "r" (expectnot), + [load] "Qo" (*load), + [voffp] "r" (voffp) + RSEQ_INJECT_INPUT + : "memory", RSEQ_ASM_TMP_REG + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +cmpfail: + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_addv(intptr_t *v, intptr_t count, int cpu) +{ + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f) + RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) +#endif + RSEQ_ASM_OP_R_LOAD(v) + RSEQ_ASM_OP_R_ADD(count) + RSEQ_ASM_OP_R_FINAL_STORE(v, 3) + RSEQ_INJECT_ASM(4) + RSEQ_ASM_DEFINE_ABORT(4, abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "Qo" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + [v] "Qo" (*v), + [count] "r" (count) + RSEQ_INJECT_INPUT + : "memory", RSEQ_ASM_TMP_REG + : abort +#ifdef RSEQ_COMPARE_TWICE + , error1 +#endif + ); + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect, + intptr_t *v2, intptr_t newv2, + intptr_t newv, int cpu) +{ + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f) + RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail]) + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2]) +#endif + RSEQ_ASM_OP_STORE(newv2, v2) + RSEQ_INJECT_ASM(5) + RSEQ_ASM_OP_FINAL_STORE(newv, v, 3) + RSEQ_INJECT_ASM(6) + RSEQ_ASM_DEFINE_ABORT(4, abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "Qo" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + [expect] "r" (expect), + [v] "Qo" (*v), + [newv] "r" (newv), + [v2] "Qo" (*v2), + [newv2] "r" (newv2) + RSEQ_INJECT_INPUT + : "memory", RSEQ_ASM_TMP_REG + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +cmpfail: + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect, + intptr_t *v2, intptr_t newv2, + intptr_t newv, int cpu) +{ + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f) + RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail]) + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2]) +#endif + RSEQ_ASM_OP_STORE(newv2, v2) + RSEQ_INJECT_ASM(5) + RSEQ_ASM_OP_FINAL_STORE_RELEASE(newv, v, 3) + RSEQ_INJECT_ASM(6) + RSEQ_ASM_DEFINE_ABORT(4, abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "Qo" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + [expect] "r" (expect), + [v] "Qo" (*v), + [newv] "r" (newv), + [v2] "Qo" (*v2), + [newv2] "r" (newv2) + RSEQ_INJECT_INPUT + : "memory", RSEQ_ASM_TMP_REG + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +cmpfail: + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect, + intptr_t *v2, intptr_t expect2, + intptr_t newv, int cpu) +{ + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f) + RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail]) + RSEQ_INJECT_ASM(4) + RSEQ_ASM_OP_CMPEQ(v2, expect2, %l[cmpfail]) + RSEQ_INJECT_ASM(5) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2]) + RSEQ_ASM_OP_CMPEQ(v2, expect2, %l[error3]) +#endif + RSEQ_ASM_OP_FINAL_STORE(newv, v, 3) + RSEQ_INJECT_ASM(6) + RSEQ_ASM_DEFINE_ABORT(4, abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "Qo" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + [v] "Qo" (*v), + [expect] "r" (expect), + [v2] "Qo" (*v2), + [expect2] "r" (expect2), + [newv] "r" (newv) + RSEQ_INJECT_INPUT + : "memory", RSEQ_ASM_TMP_REG + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2, error3 +#endif + ); + + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +cmpfail: + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +error3: + rseq_bug("2nd expected value comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect, + void *dst, void *src, size_t len, + intptr_t newv, int cpu) +{ + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f) + RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail]) + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2]) +#endif + RSEQ_ASM_OP_R_BAD_MEMCPY(dst, src, len) + RSEQ_INJECT_ASM(5) + RSEQ_ASM_OP_FINAL_STORE(newv, v, 3) + RSEQ_INJECT_ASM(6) + RSEQ_ASM_DEFINE_ABORT(4, abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "Qo" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + [expect] "r" (expect), + [v] "Qo" (*v), + [newv] "r" (newv), + [dst] "r" (dst), + [src] "r" (src), + [len] "r" (len) + RSEQ_INJECT_INPUT + : "memory", RSEQ_ASM_TMP_REG, RSEQ_ASM_TMP_REG_2 + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +cmpfail: + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect, + void *dst, void *src, size_t len, + intptr_t newv, int cpu) +{ + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f) + RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail]) + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2]) +#endif + RSEQ_ASM_OP_R_BAD_MEMCPY(dst, src, len) + RSEQ_INJECT_ASM(5) + RSEQ_ASM_OP_FINAL_STORE_RELEASE(newv, v, 3) + RSEQ_INJECT_ASM(6) + RSEQ_ASM_DEFINE_ABORT(4, abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "Qo" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + [expect] "r" (expect), + [v] "Qo" (*v), + [newv] "r" (newv), + [dst] "r" (dst), + [src] "r" (src), + [len] "r" (len) + RSEQ_INJECT_INPUT + : "memory", RSEQ_ASM_TMP_REG, RSEQ_ASM_TMP_REG_2 + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +cmpfail: + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif +} + +#endif /* !RSEQ_SKIP_FASTPATH */ diff --git a/tools/testing/selftests/rseq/rseq-s390.h b/tools/testing/selftests/rseq/rseq-s390.h new file mode 100644 index 000000000000..1069e85258ce --- /dev/null +++ b/tools/testing/selftests/rseq/rseq-s390.h @@ -0,0 +1,513 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ + +#define RSEQ_SIG 0x53053053 + +#define rseq_smp_mb() __asm__ __volatile__ ("bcr 15,0" ::: "memory") +#define rseq_smp_rmb() rseq_smp_mb() +#define rseq_smp_wmb() rseq_smp_mb() + +#define rseq_smp_load_acquire(p) \ +__extension__ ({ \ + __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \ + rseq_barrier(); \ + ____p1; \ +}) + +#define rseq_smp_acquire__after_ctrl_dep() rseq_smp_rmb() + +#define rseq_smp_store_release(p, v) \ +do { \ + rseq_barrier(); \ + RSEQ_WRITE_ONCE(*p, v); \ +} while (0) + +#ifdef RSEQ_SKIP_FASTPATH +#include "rseq-skip.h" +#else /* !RSEQ_SKIP_FASTPATH */ + +#ifdef __s390x__ + +#define LONG_L "lg" +#define LONG_S "stg" +#define LONG_LT_R "ltgr" +#define LONG_CMP "cg" +#define LONG_CMP_R "cgr" +#define LONG_ADDI "aghi" +#define LONG_ADD_R "agr" + +#define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \ + start_ip, post_commit_offset, abort_ip) \ + ".pushsection __rseq_table, \"aw\"\n\t" \ + ".balign 32\n\t" \ + __rseq_str(label) ":\n\t" \ + ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \ + ".quad " __rseq_str(start_ip) ", " __rseq_str(post_commit_offset) ", " __rseq_str(abort_ip) "\n\t" \ + ".popsection\n\t" + +#elif __s390__ + +#define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \ + start_ip, post_commit_offset, abort_ip) \ + ".pushsection __rseq_table, \"aw\"\n\t" \ + ".balign 32\n\t" \ + __rseq_str(label) ":\n\t" \ + ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \ + ".long 0x0, " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) "\n\t" \ + ".popsection\n\t" + +#define LONG_L "l" +#define LONG_S "st" +#define LONG_LT_R "ltr" +#define LONG_CMP "c" +#define LONG_CMP_R "cr" +#define LONG_ADDI "ahi" +#define LONG_ADD_R "ar" + +#endif + +#define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \ + __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip, \ + (post_commit_ip - start_ip), abort_ip) + +#define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \ + RSEQ_INJECT_ASM(1) \ + "larl %%r0, " __rseq_str(cs_label) "\n\t" \ + LONG_S " %%r0, %[" __rseq_str(rseq_cs) "]\n\t" \ + __rseq_str(label) ":\n\t" + +#define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \ + RSEQ_INJECT_ASM(2) \ + "c %[" __rseq_str(cpu_id) "], %[" __rseq_str(current_cpu_id) "]\n\t" \ + "jnz " __rseq_str(label) "\n\t" + +#define RSEQ_ASM_DEFINE_ABORT(label, teardown, abort_label) \ + ".pushsection __rseq_failure, \"ax\"\n\t" \ + ".long " __rseq_str(RSEQ_SIG) "\n\t" \ + __rseq_str(label) ":\n\t" \ + teardown \ + "j %l[" __rseq_str(abort_label) "]\n\t" \ + ".popsection\n\t" + +#define RSEQ_ASM_DEFINE_CMPFAIL(label, teardown, cmpfail_label) \ + ".pushsection __rseq_failure, \"ax\"\n\t" \ + __rseq_str(label) ":\n\t" \ + teardown \ + "j %l[" __rseq_str(cmpfail_label) "]\n\t" \ + ".popsection\n\t" + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu) +{ + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + LONG_CMP " %[expect], %[v]\n\t" + "jnz %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + LONG_CMP " %[expect], %[v]\n\t" + "jnz %l[error2]\n\t" +#endif + /* final store */ + LONG_S " %[newv], %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(5) + RSEQ_ASM_DEFINE_ABORT(4, "", abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv) + RSEQ_INJECT_INPUT + : "memory", "cc", "r0" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +cmpfail: + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif +} + +/* + * Compare @v against @expectnot. When it does _not_ match, load @v + * into @load, and store the content of *@v + voffp into @v. + */ +static inline __attribute__((always_inline)) +int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, + off_t voffp, intptr_t *load, int cpu) +{ + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + LONG_L " %%r1, %[v]\n\t" + LONG_CMP_R " %%r1, %[expectnot]\n\t" + "je %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + LONG_L " %%r1, %[v]\n\t" + LONG_CMP_R " %%r1, %[expectnot]\n\t" + "je %l[error2]\n\t" +#endif + LONG_S " %%r1, %[load]\n\t" + LONG_ADD_R " %%r1, %[voffp]\n\t" + LONG_L " %%r1, 0(%%r1)\n\t" + /* final store */ + LONG_S " %%r1, %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(5) + RSEQ_ASM_DEFINE_ABORT(4, "", abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* final store input */ + [v] "m" (*v), + [expectnot] "r" (expectnot), + [voffp] "r" (voffp), + [load] "m" (*load) + RSEQ_INJECT_INPUT + : "memory", "cc", "r0", "r1" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +cmpfail: + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_addv(intptr_t *v, intptr_t count, int cpu) +{ + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) +#endif + LONG_L " %%r0, %[v]\n\t" + LONG_ADD_R " %%r0, %[count]\n\t" + /* final store */ + LONG_S " %%r0, %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(4) + RSEQ_ASM_DEFINE_ABORT(4, "", abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* final store input */ + [v] "m" (*v), + [count] "r" (count) + RSEQ_INJECT_INPUT + : "memory", "cc", "r0" + RSEQ_INJECT_CLOBBER + : abort +#ifdef RSEQ_COMPARE_TWICE + , error1 +#endif + ); + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect, + intptr_t *v2, intptr_t newv2, + intptr_t newv, int cpu) +{ + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + LONG_CMP " %[expect], %[v]\n\t" + "jnz %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + LONG_CMP " %[expect], %[v]\n\t" + "jnz %l[error2]\n\t" +#endif + /* try store */ + LONG_S " %[newv2], %[v2]\n\t" + RSEQ_INJECT_ASM(5) + /* final store */ + LONG_S " %[newv], %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(6) + RSEQ_ASM_DEFINE_ABORT(4, "", abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* try store input */ + [v2] "m" (*v2), + [newv2] "r" (newv2), + /* final store input */ + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv) + RSEQ_INJECT_INPUT + : "memory", "cc", "r0" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +cmpfail: + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif +} + +/* s390 is TSO. */ +static inline __attribute__((always_inline)) +int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect, + intptr_t *v2, intptr_t newv2, + intptr_t newv, int cpu) +{ + return rseq_cmpeqv_trystorev_storev(v, expect, v2, newv2, newv, cpu); +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect, + intptr_t *v2, intptr_t expect2, + intptr_t newv, int cpu) +{ + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + LONG_CMP " %[expect], %[v]\n\t" + "jnz %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(4) + LONG_CMP " %[expect2], %[v2]\n\t" + "jnz %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(5) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + LONG_CMP " %[expect], %[v]\n\t" + "jnz %l[error2]\n\t" + LONG_CMP " %[expect2], %[v2]\n\t" + "jnz %l[error3]\n\t" +#endif + /* final store */ + LONG_S " %[newv], %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(6) + RSEQ_ASM_DEFINE_ABORT(4, "", abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* cmp2 input */ + [v2] "m" (*v2), + [expect2] "r" (expect2), + /* final store input */ + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv) + RSEQ_INJECT_INPUT + : "memory", "cc", "r0" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2, error3 +#endif + ); + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +cmpfail: + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("1st expected value comparison failed"); +error3: + rseq_bug("2nd expected value comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect, + void *dst, void *src, size_t len, + intptr_t newv, int cpu) +{ + uint64_t rseq_scratch[3]; + + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ + LONG_S " %[src], %[rseq_scratch0]\n\t" + LONG_S " %[dst], %[rseq_scratch1]\n\t" + LONG_S " %[len], %[rseq_scratch2]\n\t" + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + LONG_CMP " %[expect], %[v]\n\t" + "jnz 5f\n\t" + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 6f) + LONG_CMP " %[expect], %[v]\n\t" + "jnz 7f\n\t" +#endif + /* try memcpy */ + LONG_LT_R " %[len], %[len]\n\t" + "jz 333f\n\t" + "222:\n\t" + "ic %%r0,0(%[src])\n\t" + "stc %%r0,0(%[dst])\n\t" + LONG_ADDI " %[src], 1\n\t" + LONG_ADDI " %[dst], 1\n\t" + LONG_ADDI " %[len], -1\n\t" + "jnz 222b\n\t" + "333:\n\t" + RSEQ_INJECT_ASM(5) + /* final store */ + LONG_S " %[newv], %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(6) + /* teardown */ + LONG_L " %[len], %[rseq_scratch2]\n\t" + LONG_L " %[dst], %[rseq_scratch1]\n\t" + LONG_L " %[src], %[rseq_scratch0]\n\t" + RSEQ_ASM_DEFINE_ABORT(4, + LONG_L " %[len], %[rseq_scratch2]\n\t" + LONG_L " %[dst], %[rseq_scratch1]\n\t" + LONG_L " %[src], %[rseq_scratch0]\n\t", + abort) + RSEQ_ASM_DEFINE_CMPFAIL(5, + LONG_L " %[len], %[rseq_scratch2]\n\t" + LONG_L " %[dst], %[rseq_scratch1]\n\t" + LONG_L " %[src], %[rseq_scratch0]\n\t", + cmpfail) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_DEFINE_CMPFAIL(6, + LONG_L " %[len], %[rseq_scratch2]\n\t" + LONG_L " %[dst], %[rseq_scratch1]\n\t" + LONG_L " %[src], %[rseq_scratch0]\n\t", + error1) + RSEQ_ASM_DEFINE_CMPFAIL(7, + LONG_L " %[len], %[rseq_scratch2]\n\t" + LONG_L " %[dst], %[rseq_scratch1]\n\t" + LONG_L " %[src], %[rseq_scratch0]\n\t", + error2) +#endif + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* final store input */ + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv), + /* try memcpy input */ + [dst] "r" (dst), + [src] "r" (src), + [len] "r" (len), + [rseq_scratch0] "m" (rseq_scratch[0]), + [rseq_scratch1] "m" (rseq_scratch[1]), + [rseq_scratch2] "m" (rseq_scratch[2]) + RSEQ_INJECT_INPUT + : "memory", "cc", "r0" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +cmpfail: + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif +} + +/* s390 is TSO. */ +static inline __attribute__((always_inline)) +int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect, + void *dst, void *src, size_t len, + intptr_t newv, int cpu) +{ + return rseq_cmpeqv_trymemcpy_storev(v, expect, dst, src, len, + newv, cpu); +} +#endif /* !RSEQ_SKIP_FASTPATH */ diff --git a/tools/testing/selftests/rseq/rseq.h b/tools/testing/selftests/rseq/rseq.h index 86ce22417e0d..c72eb70f9b52 100644 --- a/tools/testing/selftests/rseq/rseq.h +++ b/tools/testing/selftests/rseq/rseq.h @@ -71,10 +71,14 @@ extern __thread volatile struct rseq __rseq_abi; #include <rseq-x86.h> #elif defined(__ARMEL__) #include <rseq-arm.h> +#elif defined (__AARCH64EL__) +#include <rseq-arm64.h> #elif defined(__PPC__) #include <rseq-ppc.h> #elif defined(__mips__) #include <rseq-mips.h> +#elif defined(__s390__) +#include <rseq-s390.h> #else #error unsupported target #endif diff --git a/tools/testing/selftests/tc-testing/README b/tools/testing/selftests/tc-testing/README index 3a0336782d2d..49a6f8c3fdae 100644 --- a/tools/testing/selftests/tc-testing/README +++ b/tools/testing/selftests/tc-testing/README @@ -17,6 +17,10 @@ REQUIREMENTS * The kernel must have veth support available, as a veth pair is created prior to running the tests. +* The kernel must have the appropriate infrastructure enabled to run all tdc + unit tests. See the config file in this directory for minimum required + features. As new tests will be added, config options list will be updated. + * All tc-related features being tested must be built in or available as modules. To check what is required in current setup run: ./tdc.py -c @@ -109,8 +113,8 @@ COMMAND LINE ARGUMENTS Run tdc.py -h to see the full list of available arguments. usage: tdc.py [-h] [-p PATH] [-D DIR [DIR ...]] [-f FILE [FILE ...]] - [-c [CATG [CATG ...]]] [-e ID [ID ...]] [-l] [-s] [-i] [-v] - [-d DEVICE] [-n NS] [-V] + [-c [CATG [CATG ...]]] [-e ID [ID ...]] [-l] [-s] [-i] [-v] [-N] + [-d DEVICE] [-P] [-n] [-V] Linux TC unit tests @@ -118,8 +122,10 @@ optional arguments: -h, --help show this help message and exit -p PATH, --path PATH The full path to the tc executable to use -v, --verbose Show the commands that are being run + -N, --notap Suppress tap results for command under test -d DEVICE, --device DEVICE Execute the test case in flower category + -P, --pause Pause execution just before post-suite stage selection: select which test cases: files plus directories; filtered by categories @@ -146,10 +152,10 @@ action: -i, --id Generate ID numbers for new test cases netns: - options for nsPlugin(run commands in net namespace) + options for nsPlugin (run commands in net namespace) - -n NS, --namespace NS - Run commands in namespace NS + -n, --namespace + Run commands in namespace as specified in tdc_config.py valgrind: options for valgrindPlugin (run command under test under Valgrind) diff --git a/tools/testing/selftests/tc-testing/config b/tools/testing/selftests/tc-testing/config new file mode 100644 index 000000000000..203302065458 --- /dev/null +++ b/tools/testing/selftests/tc-testing/config @@ -0,0 +1,48 @@ +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_INGRESS=m + +# +# Classification +# +CONFIG_NET_CLS=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_CLS_U32_PERF=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +CONFIG_NET_EMATCH_CMP=m +CONFIG_NET_EMATCH_NBYTE=m +CONFIG_NET_EMATCH_U32=m +CONFIG_NET_EMATCH_META=m +CONFIG_NET_EMATCH_TEXT=m +CONFIG_NET_EMATCH_IPSET=m +CONFIG_NET_EMATCH_IPT=m +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=m +CONFIG_NET_ACT_GACT=m +CONFIG_GACT_PROB=y +CONFIG_NET_ACT_MIRRED=m +CONFIG_NET_ACT_SAMPLE=m +CONFIG_NET_ACT_IPT=m +CONFIG_NET_ACT_NAT=m +CONFIG_NET_ACT_PEDIT=m +CONFIG_NET_ACT_SIMP=m +CONFIG_NET_ACT_SKBEDIT=m +CONFIG_NET_ACT_CSUM=m +CONFIG_NET_ACT_VLAN=m +CONFIG_NET_ACT_BPF=m +CONFIG_NET_ACT_CONNMARK=m +CONFIG_NET_ACT_SKBMOD=m +CONFIG_NET_ACT_IFE=m +CONFIG_NET_ACT_TUNNEL_KEY=m +CONFIG_NET_IFE_SKBMARK=m +CONFIG_NET_IFE_SKBPRIO=m +CONFIG_NET_IFE_SKBTCINDEX=m +CONFIG_NET_CLS_IND=y +CONFIG_NET_SCH_FIFO=y diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/connmark.json b/tools/testing/selftests/tc-testing/tc-tests/actions/connmark.json index 70952bd98ff9..13147a1f5731 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/connmark.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/connmark.json @@ -17,7 +17,7 @@ "cmdUnderTest": "$TC actions add action connmark", "expExitCode": "0", "verifyCmd": "$TC actions list action connmark", - "matchPattern": "action order [0-9]+: connmark zone 0 pipe", + "matchPattern": "action order [0-9]+: connmark zone 0 pipe", "matchCount": "1", "teardown": [ "$TC actions flush action connmark" @@ -41,7 +41,7 @@ "cmdUnderTest": "$TC actions add action connmark pass index 1", "expExitCode": "0", "verifyCmd": "$TC actions get action connmark index 1", - "matchPattern": "action order [0-9]+: connmark zone 0 pass.*index 1 ref", + "matchPattern": "action order [0-9]+: connmark zone 0 pass.*index 1 ref", "matchCount": "1", "teardown": [ "$TC actions flush action connmark" @@ -65,7 +65,7 @@ "cmdUnderTest": "$TC actions add action connmark drop index 100", "expExitCode": "0", "verifyCmd": "$TC actions get action connmark index 100", - "matchPattern": "action order [0-9]+: connmark zone 0 drop.*index 100 ref", + "matchPattern": "action order [0-9]+: connmark zone 0 drop.*index 100 ref", "matchCount": "1", "teardown": [ "$TC actions flush action connmark" @@ -89,7 +89,7 @@ "cmdUnderTest": "$TC actions add action connmark pipe index 455", "expExitCode": "0", "verifyCmd": "$TC actions get action connmark index 455", - "matchPattern": "action order [0-9]+: connmark zone 0 pipe.*index 455 ref", + "matchPattern": "action order [0-9]+: connmark zone 0 pipe.*index 455 ref", "matchCount": "1", "teardown": [ "$TC actions flush action connmark" @@ -113,7 +113,7 @@ "cmdUnderTest": "$TC actions add action connmark reclassify index 7", "expExitCode": "0", "verifyCmd": "$TC actions list action connmark", - "matchPattern": "action order [0-9]+: connmark zone 0 reclassify.*index 7 ref", + "matchPattern": "action order [0-9]+: connmark zone 0 reclassify.*index 7 ref", "matchCount": "1", "teardown": [ "$TC actions flush action connmark" @@ -137,7 +137,7 @@ "cmdUnderTest": "$TC actions add action connmark continue index 17", "expExitCode": "0", "verifyCmd": "$TC actions list action connmark", - "matchPattern": "action order [0-9]+: connmark zone 0 continue.*index 17 ref", + "matchPattern": "action order [0-9]+: connmark zone 0 continue.*index 17 ref", "matchCount": "1", "teardown": [ "$TC actions flush action connmark" @@ -161,7 +161,7 @@ "cmdUnderTest": "$TC actions add action connmark jump 10 index 17", "expExitCode": "0", "verifyCmd": "$TC actions list action connmark", - "matchPattern": "action order [0-9]+: connmark zone 0 jump 10.*index 17 ref", + "matchPattern": "action order [0-9]+: connmark zone 0 jump 10.*index 17 ref", "matchCount": "1", "teardown": [ "$TC actions flush action connmark" @@ -185,7 +185,7 @@ "cmdUnderTest": "$TC actions add action connmark zone 100 pipe index 1", "expExitCode": "0", "verifyCmd": "$TC actions get action connmark index 1", - "matchPattern": "action order [0-9]+: connmark zone 100 pipe.*index 1 ref", + "matchPattern": "action order [0-9]+: connmark zone 100 pipe.*index 1 ref", "matchCount": "1", "teardown": [ "$TC actions flush action connmark" @@ -209,7 +209,7 @@ "cmdUnderTest": "$TC actions add action connmark zone 65536 reclassify index 21", "expExitCode": "255", "verifyCmd": "$TC actions get action connmark index 1", - "matchPattern": "action order [0-9]+: connmark zone 65536 reclassify.*index 21 ref", + "matchPattern": "action order [0-9]+: connmark zone 65536 reclassify.*index 21 ref", "matchCount": "0", "teardown": [ "$TC actions flush action connmark" @@ -233,7 +233,7 @@ "cmdUnderTest": "$TC actions add action connmark zone 655 unsupp_arg pass index 2", "expExitCode": "255", "verifyCmd": "$TC actions get action connmark index 2", - "matchPattern": "action order [0-9]+: connmark zone 655 unsupp_arg pass.*index 2 ref", + "matchPattern": "action order [0-9]+: connmark zone 655 unsupp_arg pass.*index 2 ref", "matchCount": "0", "teardown": [ "$TC actions flush action connmark" @@ -258,7 +258,7 @@ "cmdUnderTest": "$TC actions replace action connmark zone 555 reclassify index 555", "expExitCode": "0", "verifyCmd": "$TC actions get action connmark index 555", - "matchPattern": "action order [0-9]+: connmark zone 555 reclassify.*index 555 ref", + "matchPattern": "action order [0-9]+: connmark zone 555 reclassify.*index 555 ref", "matchCount": "1", "teardown": [ "$TC actions flush action connmark" @@ -282,7 +282,7 @@ "cmdUnderTest": "$TC actions add action connmark zone 555 pipe index 5 cookie aabbccddeeff112233445566778800a1", "expExitCode": "0", "verifyCmd": "$TC actions get action connmark index 5", - "matchPattern": "action order [0-9]+: connmark zone 555 pipe.*index 5 ref.*cookie aabbccddeeff112233445566778800a1", + "matchPattern": "action order [0-9]+: connmark zone 555 pipe.*index 5 ref.*cookie aabbccddeeff112233445566778800a1", "matchCount": "1", "teardown": [ "$TC actions flush action connmark" diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/csum.json b/tools/testing/selftests/tc-testing/tc-tests/actions/csum.json index 3a2f51fc7fd4..a022792d392a 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/csum.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/csum.json @@ -336,6 +336,30 @@ ] }, { + "id": "b10b", + "name": "Add all 7 csum actions", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action csum icmp ip4h sctp igmp udplite udp tcp index 7", + "expExitCode": "0", + "verifyCmd": "$TC actions get action csum index 7", + "matchPattern": "action order [0-9]*: csum \\(iph, icmp, igmp, tcp, udp, udplite, sctp\\).*index 7 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action csum" + ] + }, + { "id": "ce92", "name": "Add csum udp action with cookie", "category": [ diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/mirred.json b/tools/testing/selftests/tc-testing/tc-tests/actions/mirred.json index 6e4edfae1799..db49fd0f8445 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/mirred.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/mirred.json @@ -44,7 +44,8 @@ "matchPattern": "action order [0-9]*: mirred \\(Egress Redirect to device lo\\).*index 2 ref", "matchCount": "1", "teardown": [ - "$TC actions flush action mirred" + "$TC actions flush action mirred", + "$TC actions flush action gact" ] }, { diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/nat.json b/tools/testing/selftests/tc-testing/tc-tests/actions/nat.json new file mode 100644 index 000000000000..0080dc2fd41c --- /dev/null +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/nat.json @@ -0,0 +1,593 @@ +[ + { + "id": "7565", + "name": "Add nat action on ingress with default control action", + "category": [ + "actions", + "nat" + ], + "setup": [ + [ + "$TC actions flush action nat", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action nat ingress 192.168.1.1 200.200.200.1", + "expExitCode": "0", + "verifyCmd": "$TC actions ls action nat", + "matchPattern": "action order [0-9]+: nat ingress 192.168.1.1/32 200.200.200.1 pass", + "matchCount": "1", + "teardown": [ + "$TC actions flush action nat" + ] + }, + { + "id": "fd79", + "name": "Add nat action on ingress with pipe control action", + "category": [ + "actions", + "nat" + ], + "setup": [ + [ + "$TC actions flush action nat", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action nat ingress 1.1.1.1 2.2.2.1 pipe index 77", + "expExitCode": "0", + "verifyCmd": "$TC actions get action nat index 77", + "matchPattern": "action order [0-9]+: nat ingress 1.1.1.1/32 2.2.2.1 pipe.*index 77 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action nat" + ] + }, + { + "id": "eab9", + "name": "Add nat action on ingress with continue control action", + "category": [ + "actions", + "nat" + ], + "setup": [ + [ + "$TC actions flush action nat", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action nat ingress 192.168.10.10 192.168.20.20 continue index 1000", + "expExitCode": "0", + "verifyCmd": "$TC actions get action nat index 1000", + "matchPattern": "action order [0-9]+: nat ingress 192.168.10.10/32 192.168.20.20 continue.*index 1000 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action nat" + ] + }, + { + "id": "c53a", + "name": "Add nat action on ingress with reclassify control action", + "category": [ + "actions", + "nat" + ], + "setup": [ + [ + "$TC actions flush action nat", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action nat ingress 192.168.10.10 192.168.20.20 reclassify index 1000", + "expExitCode": "0", + "verifyCmd": "$TC actions get action nat index 1000", + "matchPattern": "action order [0-9]+: nat ingress 192.168.10.10/32 192.168.20.20 reclassify.*index 1000 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action nat" + ] + }, + { + "id": "76c9", + "name": "Add nat action on ingress with jump control action", + "category": [ + "actions", + "nat" + ], + "setup": [ + [ + "$TC actions flush action nat", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action nat ingress 12.18.10.10 12.18.20.20 jump 10 index 22", + "expExitCode": "0", + "verifyCmd": "$TC actions get action nat index 22", + "matchPattern": "action order [0-9]+: nat ingress 12.18.10.10/32 12.18.20.20 jump 10.*index 22 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action nat" + ] + }, + { + "id": "24c6", + "name": "Add nat action on ingress with drop control action", + "category": [ + "actions", + "nat" + ], + "setup": [ + [ + "$TC actions flush action nat", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action nat ingress 1.18.1.1 1.18.2.2 drop index 722", + "expExitCode": "0", + "verifyCmd": "$TC actions get action nat index 722", + "matchPattern": "action order [0-9]+: nat ingress 1.18.1.1/32 1.18.2.2 drop.*index 722 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action nat" + ] + }, + { + "id": "2120", + "name": "Add nat action on ingress with maximum index value", + "category": [ + "actions", + "nat" + ], + "setup": [ + [ + "$TC actions flush action nat", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action nat ingress 1.18.1.1 1.18.2.2 index 4294967295", + "expExitCode": "0", + "verifyCmd": "$TC actions get action nat index 4294967295", + "matchPattern": "action order [0-9]+: nat ingress 1.18.1.1/32 1.18.2.2 pass.*index 4294967295 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action nat" + ] + }, + { + "id": "3e9d", + "name": "Add nat action on ingress with invalid index value", + "category": [ + "actions", + "nat" + ], + "setup": [ + [ + "$TC actions flush action nat", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action nat ingress 1.18.1.1 1.18.2.2 index 4294967295555", + "expExitCode": "255", + "verifyCmd": "$TC actions get action nat index 4294967295555", + "matchPattern": "action order [0-9]+: nat ingress 1.18.1.1/32 1.18.2.2 pass.*index 4294967295555 ref", + "matchCount": "0", + "teardown": [ + [ + "$TC actions flush action nat", + 0, + 1, + 255 + ] + ] + }, + { + "id": "f6c9", + "name": "Add nat action on ingress with invalid IP address", + "category": [ + "actions", + "nat" + ], + "setup": [ + [ + "$TC actions flush action nat", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action nat ingress 1.1.1.1 1.1888.2.2 index 7", + "expExitCode": "255", + "verifyCmd": "$TC actions get action nat index 7", + "matchPattern": "action order [0-9]+: nat ingress 1.1.1.1/32 1.1888.2.2 pass.*index 7 ref", + "matchCount": "0", + "teardown": [ + [ + "$TC actions flush action nat", + 0, + 1, + 255 + ] + ] + }, + { + "id": "be25", + "name": "Add nat action on ingress with invalid argument", + "category": [ + "actions", + "nat" + ], + "setup": [ + [ + "$TC actions flush action nat", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action nat ingress 1.1.1.1 1.18.2.2 another_arg index 12", + "expExitCode": "255", + "verifyCmd": "$TC actions get action nat index 12", + "matchPattern": "action order [0-9]+: nat ingress 1.1.1.1/32 1.18.2.2 pass.*another_arg.*index 12 ref", + "matchCount": "0", + "teardown": [ + [ + "$TC actions flush action nat", + 0, + 1, + 255 + ] + ] + }, + { + "id": "a7bd", + "name": "Add nat action on ingress with DEFAULT IP address", + "category": [ + "actions", + "nat" + ], + "setup": [ + [ + "$TC actions flush action nat", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action nat ingress default 10.10.10.1 index 12", + "expExitCode": "0", + "verifyCmd": "$TC actions get action nat index 12", + "matchPattern": "action order [0-9]+: nat ingress 0.0.0.0/32 10.10.10.1 pass.*index 12 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action nat" + ] + }, + { + "id": "ee1e", + "name": "Add nat action on ingress with ANY IP address", + "category": [ + "actions", + "nat" + ], + "setup": [ + [ + "$TC actions flush action nat", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action nat ingress any 10.10.10.1 index 12", + "expExitCode": "0", + "verifyCmd": "$TC actions get action nat index 12", + "matchPattern": "action order [0-9]+: nat ingress 0.0.0.0/32 10.10.10.1 pass.*index 12 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action nat" + ] + }, + { + "id": "1de8", + "name": "Add nat action on ingress with ALL IP address", + "category": [ + "actions", + "nat" + ], + "setup": [ + [ + "$TC actions flush action nat", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action nat ingress all 10.10.10.1 index 12", + "expExitCode": "0", + "verifyCmd": "$TC actions get action nat index 12", + "matchPattern": "action order [0-9]+: nat ingress 0.0.0.0/32 10.10.10.1 pass.*index 12 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action nat" + ] + }, + { + "id": "8dba", + "name": "Add nat action on egress with default control action", + "category": [ + "actions", + "nat" + ], + "setup": [ + [ + "$TC actions flush action nat", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action nat egress 10.10.10.1 20.20.20.1", + "expExitCode": "0", + "verifyCmd": "$TC actions ls action nat", + "matchPattern": "action order [0-9]+: nat egress 10.10.10.1/32 20.20.20.1 pass", + "matchCount": "1", + "teardown": [ + "$TC actions flush action nat" + ] + }, + { + "id": "19a7", + "name": "Add nat action on egress with pipe control action", + "category": [ + "actions", + "nat" + ], + "setup": [ + [ + "$TC actions flush action nat", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action nat egress 10.10.10.1 20.20.20.1 pipe", + "expExitCode": "0", + "verifyCmd": "$TC actions ls action nat", + "matchPattern": "action order [0-9]+: nat egress 10.10.10.1/32 20.20.20.1 pipe", + "matchCount": "1", + "teardown": [ + "$TC actions flush action nat" + ] + }, + { + "id": "f1d9", + "name": "Add nat action on egress with continue control action", + "category": [ + "actions", + "nat" + ], + "setup": [ + [ + "$TC actions flush action nat", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action nat egress 10.10.10.1 20.20.20.1 continue", + "expExitCode": "0", + "verifyCmd": "$TC actions ls action nat", + "matchPattern": "action order [0-9]+: nat egress 10.10.10.1/32 20.20.20.1 continue", + "matchCount": "1", + "teardown": [ + "$TC actions flush action nat" + ] + }, + { + "id": "6d4a", + "name": "Add nat action on egress with reclassify control action", + "category": [ + "actions", + "nat" + ], + "setup": [ + [ + "$TC actions flush action nat", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action nat egress 10.10.10.1 20.20.20.1 reclassify", + "expExitCode": "0", + "verifyCmd": "$TC actions ls action nat", + "matchPattern": "action order [0-9]+: nat egress 10.10.10.1/32 20.20.20.1 reclassify", + "matchCount": "1", + "teardown": [ + "$TC actions flush action nat" + ] + }, + { + "id": "b313", + "name": "Add nat action on egress with jump control action", + "category": [ + "actions", + "nat" + ], + "setup": [ + [ + "$TC actions flush action nat", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action nat egress 10.10.10.1 20.20.20.1 jump 777", + "expExitCode": "0", + "verifyCmd": "$TC actions ls action nat", + "matchPattern": "action order [0-9]+: nat egress 10.10.10.1/32 20.20.20.1 jump 777", + "matchCount": "1", + "teardown": [ + "$TC actions flush action nat" + ] + }, + { + "id": "d9fc", + "name": "Add nat action on egress with drop control action", + "category": [ + "actions", + "nat" + ], + "setup": [ + [ + "$TC actions flush action nat", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action nat egress 10.10.10.1 20.20.20.1 drop", + "expExitCode": "0", + "verifyCmd": "$TC actions ls action nat", + "matchPattern": "action order [0-9]+: nat egress 10.10.10.1/32 20.20.20.1 drop", + "matchCount": "1", + "teardown": [ + "$TC actions flush action nat" + ] + }, + { + "id": "a895", + "name": "Add nat action on egress with DEFAULT IP address", + "category": [ + "actions", + "nat" + ], + "setup": [ + [ + "$TC actions flush action nat", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action nat egress default 20.20.20.1 pipe index 10", + "expExitCode": "0", + "verifyCmd": "$TC actions get action nat index 10", + "matchPattern": "action order [0-9]+: nat egress 0.0.0.0/32 20.20.20.1 pipe.*index 10 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action nat" + ] + }, + { + "id": "2572", + "name": "Add nat action on egress with ANY IP address", + "category": [ + "actions", + "nat" + ], + "setup": [ + [ + "$TC actions flush action nat", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action nat egress any 20.20.20.1 pipe index 10", + "expExitCode": "0", + "verifyCmd": "$TC actions get action nat index 10", + "matchPattern": "action order [0-9]+: nat egress 0.0.0.0/32 20.20.20.1 pipe.*index 10 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action nat" + ] + }, + { + "id": "37f3", + "name": "Add nat action on egress with ALL IP address", + "category": [ + "actions", + "nat" + ], + "setup": [ + [ + "$TC actions flush action nat", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action nat egress all 20.20.20.1 pipe index 10", + "expExitCode": "0", + "verifyCmd": "$TC actions get action nat index 10", + "matchPattern": "action order [0-9]+: nat egress 0.0.0.0/32 20.20.20.1 pipe.*index 10 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action nat" + ] + }, + { + "id": "6054", + "name": "Add nat action on egress with cookie", + "category": [ + "actions", + "nat" + ], + "setup": [ + [ + "$TC actions flush action nat", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action nat egress all 20.20.20.1 pipe index 10 cookie aa1bc2d3eeff112233445566778800a1", + "expExitCode": "0", + "verifyCmd": "$TC actions get action nat index 10", + "matchPattern": "action order [0-9]+: nat egress 0.0.0.0/32 20.20.20.1 pipe.*index 10 ref.*cookie aa1bc2d3eeff112233445566778800a1", + "matchCount": "1", + "teardown": [ + "$TC actions flush action nat" + ] + }, + { + "id": "79d6", + "name": "Add nat action on ingress with cookie", + "category": [ + "actions", + "nat" + ], + "setup": [ + [ + "$TC actions flush action nat", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action nat ingress 192.168.1.1 10.10.10.1 reclassify index 1 cookie 112233445566778899aabbccddeeff11", + "expExitCode": "0", + "verifyCmd": "$TC actions get action nat index 1", + "matchPattern": "action order [0-9]+: nat ingress 192.168.1.1/32 10.10.10.1 reclassify.*index 1 ref.*cookie 112233445566778899aabbccddeeff11", + "matchCount": "1", + "teardown": [ + "$TC actions flush action nat" + ] + } +] diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/skbedit.json b/tools/testing/selftests/tc-testing/tc-tests/actions/skbedit.json index 37ecc2716fee..5aaf593b914a 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/skbedit.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/skbedit.json @@ -17,7 +17,7 @@ "cmdUnderTest": "$TC actions add action skbedit mark 1", "expExitCode": "0", "verifyCmd": "$TC actions list action skbedit", - "matchPattern": "action order [0-9]*: skbedit mark 1", + "matchPattern": "action order [0-9]*: skbedit mark 1", "matchCount": "1", "teardown": [ "$TC actions flush action skbedit" @@ -65,7 +65,7 @@ "cmdUnderTest": "$TC actions add action skbedit prio 99", "expExitCode": "0", "verifyCmd": "$TC actions list action skbedit", - "matchPattern": "action order [0-9]*: skbedit priority :99", + "matchPattern": "action order [0-9]*: skbedit priority :99", "matchCount": "1", "teardown": [ "$TC actions flush action skbedit" @@ -113,7 +113,7 @@ "cmdUnderTest": "$TC actions add action skbedit queue_mapping 909", "expExitCode": "0", "verifyCmd": "$TC actions list action skbedit", - "matchPattern": "action order [0-9]*: skbedit queue_mapping 909", + "matchPattern": "action order [0-9]*: skbedit queue_mapping 909", "matchCount": "1", "teardown": [ "$TC actions flush action skbedit" @@ -161,7 +161,7 @@ "cmdUnderTest": "$TC actions add action skbedit ptype host", "expExitCode": "0", "verifyCmd": "$TC actions list action skbedit", - "matchPattern": "action order [0-9]*: skbedit ptype host", + "matchPattern": "action order [0-9]*: skbedit ptype host", "matchCount": "1", "teardown": [ "$TC actions flush action skbedit" @@ -185,7 +185,7 @@ "cmdUnderTest": "$TC actions add action skbedit ptype otherhost", "expExitCode": "0", "verifyCmd": "$TC actions list action skbedit", - "matchPattern": "action order [0-9]*: skbedit ptype otherhost", + "matchPattern": "action order [0-9]*: skbedit ptype otherhost", "matchCount": "1", "teardown": [ "$TC actions flush action skbedit" @@ -233,7 +233,7 @@ "cmdUnderTest": "$TC actions add action skbedit ptype host pipe index 11", "expExitCode": "0", "verifyCmd": "$TC actions get action skbedit index 11", - "matchPattern": "action order [0-9]*: skbedit ptype host pipe.*index 11 ref", + "matchPattern": "action order [0-9]*: skbedit ptype host pipe.*index 11 ref", "matchCount": "1", "teardown": [ "$TC actions flush action skbedit" @@ -257,7 +257,7 @@ "cmdUnderTest": "$TC actions add action skbedit mark 56789 reclassify index 90", "expExitCode": "0", "verifyCmd": "$TC actions get action skbedit index 90", - "matchPattern": "action order [0-9]*: skbedit mark 56789 reclassify.*index 90 ref", + "matchPattern": "action order [0-9]*: skbedit mark 56789 reclassify.*index 90 ref", "matchCount": "1", "teardown": [ "$TC actions flush action skbedit" @@ -281,7 +281,7 @@ "cmdUnderTest": "$TC actions add action skbedit queue_mapping 3 pass index 271", "expExitCode": "0", "verifyCmd": "$TC actions get action skbedit index 271", - "matchPattern": "action order [0-9]*: skbedit queue_mapping 3 pass.*index 271 ref", + "matchPattern": "action order [0-9]*: skbedit queue_mapping 3 pass.*index 271 ref", "matchCount": "1", "teardown": [ "$TC actions flush action skbedit" @@ -305,7 +305,7 @@ "cmdUnderTest": "$TC actions add action skbedit queue_mapping 3 drop index 271", "expExitCode": "0", "verifyCmd": "$TC actions get action skbedit index 271", - "matchPattern": "action order [0-9]*: skbedit queue_mapping 3 drop.*index 271 ref", + "matchPattern": "action order [0-9]*: skbedit queue_mapping 3 drop.*index 271 ref", "matchCount": "1", "teardown": [ "$TC actions flush action skbedit" @@ -329,7 +329,7 @@ "cmdUnderTest": "$TC actions add action skbedit priority 8 jump 9 index 2", "expExitCode": "0", "verifyCmd": "$TC actions get action skbedit index 2", - "matchPattern": "action order [0-9]*: skbedit priority :8 jump 9.*index 2 ref", + "matchPattern": "action order [0-9]*: skbedit priority :8 jump 9.*index 2 ref", "matchCount": "1", "teardown": [ "$TC actions flush action skbedit" @@ -353,7 +353,7 @@ "cmdUnderTest": "$TC actions add action skbedit priority 16 continue index 32", "expExitCode": "0", "verifyCmd": "$TC actions get action skbedit index 32", - "matchPattern": "action order [0-9]*: skbedit priority :16 continue.*index 32 ref", + "matchPattern": "action order [0-9]*: skbedit priority :16 continue.*index 32 ref", "matchCount": "1", "teardown": [ "$TC actions flush action skbedit" @@ -377,7 +377,7 @@ "cmdUnderTest": "$TC actions add action skbedit priority 16 continue index 32 cookie deadbeef", "expExitCode": "0", "verifyCmd": "$TC actions get action skbedit index 32", - "matchPattern": "action order [0-9]*: skbedit priority :16 continue.*index 32 ref.*cookie deadbeef", + "matchPattern": "action order [0-9]*: skbedit priority :16 continue.*index 32 ref.*cookie deadbeef", "matchCount": "1", "teardown": [ "$TC actions flush action skbedit" @@ -405,7 +405,7 @@ "cmdUnderTest": "$TC actions list action skbedit", "expExitCode": "0", "verifyCmd": "$TC actions list action skbedit", - "matchPattern": "action order [0-9]*: skbedit", + "matchPattern": "action order [0-9]*: skbedit", "matchCount": "4", "teardown": [ "$TC actions flush action skbedit" diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/tunnel_key.json b/tools/testing/selftests/tc-testing/tc-tests/actions/tunnel_key.json new file mode 100644 index 000000000000..10b2d894e436 --- /dev/null +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/tunnel_key.json @@ -0,0 +1,917 @@ +[ + { + "id": "2b11", + "name": "Add tunnel_key set action with mandatory parameters", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 10.10.10.1 dst_ip 20.20.20.2 id 1", + "expExitCode": "0", + "verifyCmd": "$TC actions list action tunnel_key", + "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 10.10.10.1.*dst_ip 20.20.20.2.*key_id 1", + "matchCount": "1", + "teardown": [ + "$TC actions flush action tunnel_key" + ] + }, + { + "id": "dc6b", + "name": "Add tunnel_key set action with missing mandatory src_ip parameter", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action tunnel_key set dst_ip 20.20.20.2 id 100", + "expExitCode": "255", + "verifyCmd": "$TC actions list action tunnel_key", + "matchPattern": "action order [0-9]+: tunnel_key set.*dst_ip 20.20.20.2.*key_id 100", + "matchCount": "0", + "teardown": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ] + }, + { + "id": "7f25", + "name": "Add tunnel_key set action with missing mandatory dst_ip parameter", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 10.10.10.1 id 100", + "expExitCode": "255", + "verifyCmd": "$TC actions list action tunnel_key", + "matchPattern": "action order [0-9]+: tunnel_key set.*src_ip 10.10.10.1.*key_id 100", + "matchCount": "0", + "teardown": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ] + }, + { + "id": "ba4e", + "name": "Add tunnel_key set action with missing mandatory id parameter", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 10.10.10.1 dst_ip 20.20.20.2", + "expExitCode": "255", + "verifyCmd": "$TC actions list action tunnel_key", + "matchPattern": "action order [0-9]+: tunnel_key set.*src_ip 10.10.10.1.*dst_ip 20.20.20.2", + "matchCount": "0", + "teardown": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ] + }, + { + "id": "a5e0", + "name": "Add tunnel_key set action with invalid src_ip parameter", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 300.168.100.1 dst_ip 192.168.200.1 id 7 index 1", + "expExitCode": "1", + "verifyCmd": "$TC actions get action tunnel_key index 1", + "matchPattern": "action order [0-9]+: tunnel_key set.*src_ip 300.168.100.1.*dst_ip 192.168.200.1.*key_id 7.*index 1 ref", + "matchCount": "0", + "teardown": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ] + }, + { + "id": "eaa8", + "name": "Add tunnel_key set action with invalid dst_ip parameter", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 192.168.100.1 dst_ip 192.168.800.1 id 10 index 11", + "expExitCode": "1", + "verifyCmd": "$TC actions get action tunnel_key index 11", + "matchPattern": "action order [0-9]+: tunnel_key set.*src_ip 192.168.100.1.*dst_ip 192.168.800.1.*key_id 10.*index 11 ref", + "matchCount": "0", + "teardown": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ] + }, + { + "id": "3b09", + "name": "Add tunnel_key set action with invalid id parameter", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 112233445566778899 index 1", + "expExitCode": "255", + "verifyCmd": "$TC actions get action tunnel_key index 1", + "matchPattern": "action order [0-9]+: tunnel_key set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 112233445566778899.*index 1 ref", + "matchCount": "0", + "teardown": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ] + }, + { + "id": "9625", + "name": "Add tunnel_key set action with invalid dst_port parameter", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 11 dst_port 998877 index 1", + "expExitCode": "255", + "verifyCmd": "$TC actions get action tunnel_key index 1", + "matchPattern": "action order [0-9]+: tunnel_key set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 11.*dst_port 998877.*index 1 ref", + "matchCount": "0", + "teardown": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ] + }, + { + "id": "05af", + "name": "Add tunnel_key set action with optional dst_port parameter", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 192.168.100.1 dst_ip 192.168.200.1 id 789 dst_port 4000 index 10", + "expExitCode": "0", + "verifyCmd": "$TC actions get action tunnel_key index 10", + "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 192.168.100.1.*dst_ip 192.168.200.1.*key_id 789.*dst_port 4000.*index 10 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action tunnel_key" + ] + }, + { + "id": "da80", + "name": "Add tunnel_key set action with index at 32-bit maximum", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 11 index 4294967295", + "expExitCode": "0", + "verifyCmd": "$TC actions get action tunnel_key index 4294967295", + "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*id 11.*index 4294967295 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action tunnel_key" + ] + }, + { + "id": "d407", + "name": "Add tunnel_key set action with index exceeding 32-bit maximum", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 11 index 4294967295678", + "expExitCode": "255", + "verifyCmd": "$TC actions get action tunnel_key index 4294967295678", + "matchPattern": "action order [0-9]+: tunnel_key set.*index 4294967295678 ref", + "matchCount": "0", + "teardown": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ] + }, + { + "id": "5cba", + "name": "Add tunnel_key set action with id value at 32-bit maximum", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 4294967295 index 1", + "expExitCode": "0", + "verifyCmd": "$TC actions get action tunnel_key index 1", + "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 4294967295.*index 1", + "matchCount": "1", + "teardown": [ + "$TC actions flush action tunnel_key" + ] + }, + { + "id": "e84a", + "name": "Add tunnel_key set action with id value exceeding 32-bit maximum", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 42949672955 index 1", + "expExitCode": "255", + "verifyCmd": "$TC actions get action tunnel_key index 4294967295", + "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 42949672955.*index 1", + "matchCount": "0", + "teardown": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ] + }, + { + "id": "9c19", + "name": "Add tunnel_key set action with dst_port value at 16-bit maximum", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 429 dst_port 65535 index 1", + "expExitCode": "0", + "verifyCmd": "$TC actions get action tunnel_key index 1", + "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 429.*dst_port 65535.*index 1", + "matchCount": "1", + "teardown": [ + "$TC actions flush action tunnel_key" + ] + }, + { + "id": "3bd9", + "name": "Add tunnel_key set action with dst_port value exceeding 16-bit maximum", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 429 dst_port 65535789 index 1", + "expExitCode": "255", + "verifyCmd": "$TC actions get action tunnel_key index 1", + "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 429.*dst_port 65535789.*index 1", + "matchCount": "0", + "teardown": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ] + }, + { + "id": "68e2", + "name": "Add tunnel_key unset action", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action tunnel_key unset index 1", + "expExitCode": "0", + "verifyCmd": "$TC actions get action tunnel_key index 1", + "matchPattern": "action order [0-9]+: tunnel_key.*unset.*index 1 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action tunnel_key" + ] + }, + { + "id": "6192", + "name": "Add tunnel_key unset continue action", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action tunnel_key unset continue index 1", + "expExitCode": "0", + "verifyCmd": "$TC actions get action tunnel_key index 1", + "matchPattern": "action order [0-9]+: tunnel_key.*unset continue.*index 1 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action tunnel_key" + ] + }, + { + "id": "061d", + "name": "Add tunnel_key set continue action with cookie", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 192.168.10.1 dst_ip 192.168.20.2 id 123 continue index 1 cookie aa11bb22cc33dd44ee55ff66aa11b1b2", + "expExitCode": "0", + "verifyCmd": "$TC actions get action tunnel_key index 1", + "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 192.168.10.1.*dst_ip 192.168.20.2.*key_id 123.*csum continue.*index 1.*cookie aa11bb22cc33dd44ee55ff66aa11b1b2", + "matchCount": "1", + "teardown": [ + "$TC actions flush action tunnel_key" + ] + }, + { + "id": "8acb", + "name": "Add tunnel_key set continue action with invalid cookie", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 192.168.10.1 dst_ip 192.168.20.2 id 123 continue index 1 cookie aa11bb22cc33dd44ee55ff66aa11b1b2777888", + "expExitCode": "255", + "verifyCmd": "$TC actions get action tunnel_key index 1", + "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 192.168.10.1.*dst_ip 192.168.20.2.*key_id 123.*csum continue.*index 1.*cookie aa11bb22cc33dd44ee55ff66aa11b1b2777888", + "matchCount": "0", + "teardown": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ] + }, + { + "id": "a07e", + "name": "Add tunnel_key action with no set/unset command specified", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action tunnel_key src_ip 10.10.10.1 dst_ip 20.20.20.2 id 1", + "expExitCode": "255", + "verifyCmd": "$TC actions get action tunnel_key index 1", + "matchPattern": "action order [0-9]+: tunnel_key.*src_ip 10.10.10.1.*dst_ip 20.20.20.2.*key_id 1", + "matchCount": "0", + "teardown": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ] + }, + { + "id": "b227", + "name": "Add tunnel_key action with csum option", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 10.10.10.1 dst_ip 20.20.20.2 id 1 csum index 99", + "expExitCode": "0", + "verifyCmd": "$TC actions get action tunnel_key index 99", + "matchPattern": "action order [0-9]+: tunnel_key.*src_ip 10.10.10.1.*dst_ip 20.20.20.2.*key_id 1.*csum pipe.*index 99", + "matchCount": "1", + "teardown": [ + "$TC actions flush action tunnel_key" + ] + }, + { + "id": "58a7", + "name": "Add tunnel_key action with nocsum option", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 10.10.10.1 dst_ip 10.10.10.2 id 7823 nocsum index 234", + "expExitCode": "0", + "verifyCmd": "$TC actions get action tunnel_key index 234", + "matchPattern": "action order [0-9]+: tunnel_key.*src_ip 10.10.10.1.*dst_ip 10.10.10.2.*key_id 7823.*nocsum pipe.*index 234", + "matchCount": "1", + "teardown": [ + "$TC actions flush action tunnel_key" + ] + }, + { + "id": "2575", + "name": "Add tunnel_key action with not-supported parameter", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 10.10.10.1 dst_ip 10.10.10.2 id 7 foobar 999 index 4", + "expExitCode": "255", + "verifyCmd": "$TC actions get action tunnel_key index 4", + "matchPattern": "action order [0-9]+: tunnel_key.*src_ip 10.10.10.1.*dst_ip 10.10.10.2.*key_id 7.*foobar 999.*index 4", + "matchCount": "0", + "teardown": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ] + }, + { + "id": "7a88", + "name": "Add tunnel_key action with cookie parameter", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 10.10.10.1 dst_ip 10.10.10.2 id 7 index 4 cookie aa11bb22cc33dd44ee55ff66aa11b1b2", + "expExitCode": "0", + "verifyCmd": "$TC actions get action tunnel_key index 4", + "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 10.10.10.1.*dst_ip 10.10.10.2.*key_id 7.*dst_port 0.*csum pipe.*index 4 ref.*cookie aa11bb22cc33dd44ee55ff66aa11b1b2", + "matchCount": "1", + "teardown": [ + "$TC actions flush action tunnel_key" + ] + }, + { + "id": "4f20", + "name": "Add tunnel_key action with a single geneve option parameter", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 42 dst_port 6081 geneve_opts 0102:80:00880022 index 1", + "expExitCode": "0", + "verifyCmd": "$TC actions get action tunnel_key index 1", + "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 42.*dst_port 6081.*geneve_opt 0102:80:00880022.*index 1", + "matchCount": "1", + "teardown": [ + "$TC actions flush action tunnel_key" + ] + }, + { + "id": "e33d", + "name": "Add tunnel_key action with multiple geneve options parameter", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 42 dst_port 6081 geneve_opts 0102:80:00880022,0408:42:0040007611223344,0111:02:1020304011223344 index 1", + "expExitCode": "0", + "verifyCmd": "$TC actions get action tunnel_key index 1", + "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 42.*dst_port 6081.*geneve_opt 0102:80:00880022,0408:42:0040007611223344,0111:02:1020304011223344.*index 1", + "matchCount": "1", + "teardown": [ + "$TC actions flush action tunnel_key" + ] + }, + { + "id": "0778", + "name": "Add tunnel_key action with invalid class geneve option parameter", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 42 dst_port 6081 geneve_opts 824212:80:00880022 index 1", + "expExitCode": "255", + "verifyCmd": "$TC actions get action tunnel_key index 1", + "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 42.*dst_port 6081.*geneve_opt 824212:80:00880022.*index 1", + "matchCount": "0", + "teardown": [ + "$TC actions flush action tunnel_key" + ] + }, + { + "id": "4ae8", + "name": "Add tunnel_key action with invalid type geneve option parameter", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 42 dst_port 6081 geneve_opts 0102:4224:00880022 index 1", + "expExitCode": "255", + "verifyCmd": "$TC actions get action tunnel_key index 1", + "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 42.*dst_port 6081.*geneve_opt 0102:4224:00880022.*index 1", + "matchCount": "0", + "teardown": [ + "$TC actions flush action tunnel_key" + ] + }, + { + "id": "4039", + "name": "Add tunnel_key action with short data length geneve option parameter", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 42 dst_port 6081 geneve_opts 0102:80:4288 index 1", + "expExitCode": "255", + "verifyCmd": "$TC actions get action tunnel_key index 1", + "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 42.*dst_port 6081.*geneve_opt 0102:80:4288.*index 1", + "matchCount": "0", + "teardown": [ + "$TC actions flush action tunnel_key" + ] + }, + { + "id": "26a6", + "name": "Add tunnel_key action with non-multiple of 4 data length geneve option parameter", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 42 dst_port 6081 geneve_opts 0102:80:4288428822 index 1", + "expExitCode": "255", + "verifyCmd": "$TC actions get action tunnel_key index 1", + "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 42.*dst_port 6081.*geneve_opt 0102:80:4288428822.*index 1", + "matchCount": "0", + "teardown": [ + "$TC actions flush action tunnel_key" + ] + }, + { + "id": "f44d", + "name": "Add tunnel_key action with incomplete geneve options parameter", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 42 dst_port 6081 geneve_opts 0102:80:00880022,0408:42: index 1", + "expExitCode": "255", + "verifyCmd": "$TC actions get action tunnel_key index 1", + "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 42.*dst_port 6081.*geneve_opt 0102:80:00880022,0408:42:.*index 1", + "matchCount": "0", + "teardown": [ + "$TC actions flush action tunnel_key" + ] + }, + { + "id": "7afc", + "name": "Replace tunnel_key set action with all parameters", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ], + "$TC actions add action tunnel_key set src_ip 10.10.10.1 dst_ip 20.20.20.2 dst_port 3128 csum id 1 index 1" + ], + "cmdUnderTest": "$TC actions replace action tunnel_key set src_ip 11.11.11.1 dst_ip 21.21.21.2 dst_port 3129 nocsum id 11 index 1", + "expExitCode": "0", + "verifyCmd": "$TC actions get action tunnel_key index 1", + "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 11.11.11.1.*dst_ip 21.21.21.2.*key_id 11.*dst_port 3129.*nocsum pipe.*index 1", + "matchCount": "1", + "teardown": [ + "$TC actions flush action tunnel_key" + ] + }, + { + "id": "364d", + "name": "Replace tunnel_key set action with all parameters and cookie", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ], + "$TC actions add action tunnel_key set src_ip 10.10.10.1 dst_ip 20.20.20.2 dst_port 3128 nocsum id 1 index 1 cookie aabbccddeeff112233445566778800a" + ], + "cmdUnderTest": "$TC actions replace action tunnel_key set src_ip 11.11.11.1 dst_ip 21.21.21.2 dst_port 3129 id 11 csum reclassify index 1 cookie a1b1c1d1", + "expExitCode": "0", + "verifyCmd": "$TC actions get action tunnel_key index 1", + "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 11.11.11.1.*dst_ip 21.21.21.2.*key_id 11.*dst_port 3129.*csum reclassify.*index 1.*cookie a1b1c1d1", + "matchCount": "1", + "teardown": [ + "$TC actions flush action tunnel_key" + ] + }, + { + "id": "937c", + "name": "Fetch all existing tunnel_key actions", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ], + "$TC actions add action tunnel_key set src_ip 10.10.10.1 dst_ip 20.20.20.2 dst_port 3128 nocsum id 1 pipe index 1", + "$TC actions add action tunnel_key set src_ip 11.10.10.1 dst_ip 21.20.20.2 dst_port 3129 csum id 2 jump 10 index 2", + "$TC actions add action tunnel_key set src_ip 12.10.10.1 dst_ip 22.20.20.2 dst_port 3130 csum id 3 pass index 3", + "$TC actions add action tunnel_key set src_ip 13.10.10.1 dst_ip 23.20.20.2 dst_port 3131 nocsum id 4 continue index 4" + ], + "cmdUnderTest": "$TC actions list action tunnel_key", + "expExitCode": "0", + "verifyCmd": "$TC actions list action tunnel_key", + "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 10.10.10.1.*dst_ip 20.20.20.2.*key_id 1.*dst_port 3128.*nocsum pipe.*index 1.*set.*src_ip 11.10.10.1.*dst_ip 21.20.20.2.*key_id 2.*dst_port 3129.*csum jump 10.*index 2.*set.*src_ip 12.10.10.1.*dst_ip 22.20.20.2.*key_id 3.*dst_port 3130.*csum pass.*index 3.*set.*src_ip 13.10.10.1.*dst_ip 23.20.20.2.*key_id 4.*dst_port 3131.*nocsum continue.*index 4", + "matchCount": "1", + "teardown": [ + "$TC actions flush action tunnel_key" + ] + }, + { + "id": "6783", + "name": "Flush all existing tunnel_key actions", + "category": [ + "actions", + "tunnel_key" + ], + "setup": [ + [ + "$TC actions flush action tunnel_key", + 0, + 1, + 255 + ], + "$TC actions add action tunnel_key set src_ip 10.10.10.1 dst_ip 20.20.20.2 dst_port 3128 nocsum id 1 pipe index 1", + "$TC actions add action tunnel_key set src_ip 11.10.10.1 dst_ip 21.20.20.2 dst_port 3129 csum id 2 reclassify index 2", + "$TC actions add action tunnel_key set src_ip 12.10.10.1 dst_ip 22.20.20.2 dst_port 3130 csum id 3 pass index 3", + "$TC actions add action tunnel_key set src_ip 13.10.10.1 dst_ip 23.20.20.2 dst_port 3131 nocsum id 4 continue index 4" + ], + "cmdUnderTest": "$TC actions flush action tunnel_key", + "expExitCode": "0", + "verifyCmd": "$TC actions list action tunnel_key", + "matchPattern": "action order [0-9]+:.*", + "matchCount": "0", + "teardown": [ + "$TC actions flush action tunnel_key" + ] + } +] diff --git a/tools/testing/selftests/tc-testing/tc-tests/filters/fw.json b/tools/testing/selftests/tc-testing/tc-tests/filters/fw.json new file mode 100644 index 000000000000..3b97cfd7e0f8 --- /dev/null +++ b/tools/testing/selftests/tc-testing/tc-tests/filters/fw.json @@ -0,0 +1,1049 @@ +[ + { + "id": "901f", + "name": "Add fw filter with prio at 32-bit maxixum", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 65535 fw action ok", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 65535 protocol all fw", + "matchPattern": "pref 65535 fw.*handle 0x1.*gact action pass", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "51e2", + "name": "Add fw filter with prio exceeding 32-bit maxixum", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 65536 fw action ok", + "expExitCode": "255", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 65536 protocol all fw", + "matchPattern": "pref 65536 fw.*handle 0x1.*gact action pass", + "matchCount": "0", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "d987", + "name": "Add fw filter with action ok", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 1 fw action ok", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol all fw", + "matchPattern": "handle 0x1.*gact action pass", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "affe", + "name": "Add fw filter with action continue", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 1 fw action continue", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol all fw", + "matchPattern": "handle 0x1.*gact action continue", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "28bc", + "name": "Add fw filter with action pipe", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 1 fw action pipe", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol all fw", + "matchPattern": "handle 0x1.*gact action pipe", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "8da2", + "name": "Add fw filter with action drop", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 1 fw action drop", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 protocol all prio 1 fw", + "matchPattern": "handle 0x1.*gact action drop", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "9436", + "name": "Add fw filter with action reclassify", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 1 fw action reclassify", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol all fw", + "matchPattern": "handle 0x1.*gact action reclassify", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "95bb", + "name": "Add fw filter with action jump 10", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 1 fw action jump 10", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol all fw", + "matchPattern": "handle 0x1.*gact action jump 10", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "3d74", + "name": "Add fw filter with action goto chain 5", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 1 fw action goto chain 5", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol all fw", + "matchPattern": "handle 0x1.*gact action goto chain 5", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "eb8f", + "name": "Add fw filter with invalid action", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 1 fw action pump", + "expExitCode": "255", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol all fw", + "matchPattern": "handle 0x1.*gact action pump", + "matchCount": "0", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "6a79", + "name": "Add fw filter with missing mandatory action", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 1 fw", + "expExitCode": "2", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol all fw", + "matchPattern": "filter protocol all pref [0-9]+ fw.*handle 0x1", + "matchCount": "0", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "8298", + "name": "Add fw filter with cookie", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 2 fw action pipe cookie aa11bb22cc33dd44ee55ff66aa11b1b2", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 2 protocol all fw", + "matchPattern": "pref 2 fw.*handle 0x1.*gact action pipe.*cookie aa11bb22cc33dd44ee55ff66aa11b1b2", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "a88c", + "name": "Add fw filter with invalid cookie", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 2 fw action continue cookie aa11bb22cc33dd44ee55ff66aa11b1b2777888", + "expExitCode": "255", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 2 protocol all fw", + "matchPattern": "pref 2 fw.*handle 0x1.*gact action continue.*cookie aa11bb22cc33dd44ee55ff66aa11b1b2777888", + "matchCount": "0", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "10f6", + "name": "Add fw filter with handle in hex", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 0xa1b2ff prio 1 fw action ok", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 0xa1b2ff prio 1 protocol all fw", + "matchPattern": "fw.*handle 0xa1b2ff.*gact action pass", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "9d51", + "name": "Add fw filter with handle at 32-bit maximum", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 4294967295 prio 1 fw action ok", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 4294967295 prio 1 protocol all fw", + "matchPattern": "fw.*handle 0xffffffff.*gact action pass", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "d939", + "name": "Add fw filter with handle exceeding 32-bit maximum", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 4294967296 prio 1 fw action ok", + "expExitCode": "1", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 4294967296 prio 1 protocol all fw", + "matchPattern": "fw.*handle 0x.*gact action pass", + "matchCount": "0", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "658c", + "name": "Add fw filter with mask in hex", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 10/0xa1b2f prio 1 fw action ok", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 10 prio 1 protocol all fw", + "matchPattern": "fw.*handle 0xa/0xa1b2f", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "86be", + "name": "Add fw filter with mask at 32-bit maximum", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 10/4294967295 prio 1 fw action ok", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 10 prio 1 protocol all fw", + "matchPattern": "fw.*handle 0xa[^/]", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "e635", + "name": "Add fw filter with mask exceeding 32-bit maximum", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 10/4294967296 prio 1 fw action ok", + "expExitCode": "1", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 10 prio 1 protocol all fw", + "matchPattern": "fw.*handle 0xa", + "matchCount": "0", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "6cab", + "name": "Add fw filter with handle/mask in hex", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 0xa1b2cdff/0x1a2bffdc prio 1 fw action ok", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 0xa1b2cdff prio 1 protocol all fw", + "matchPattern": "fw.*handle 0xa1b2cdff/0x1a2bffdc", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "8700", + "name": "Add fw filter with handle/mask at 32-bit maximum", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 4294967295/4294967295 prio 1 fw action ok", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 0xffffffff prio 1 protocol all fw", + "matchPattern": "fw.*handle 0xffffffff[^/]", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "7d62", + "name": "Add fw filter with handle/mask exceeding 32-bit maximum", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 4294967296/4294967296 prio 1 fw action ok", + "expExitCode": "1", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 10 prio 1 protocol all fw", + "matchPattern": "fw.*handle", + "matchCount": "0", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "7b69", + "name": "Add fw filter with missing mandatory handle", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: prio 1 fw action ok", + "expExitCode": "2", + "verifyCmd": "$TC filter show dev $DEV1 parent ffff:", + "matchPattern": "filter protocol all.*fw.*handle.*gact action pass", + "matchCount": "0", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "d68b", + "name": "Add fw filter with invalid parent", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent aa11b1b2: handle 1 prio 1 fw action ok", + "expExitCode": "255", + "verifyCmd": "$TC filter dev $DEV1 parent aa11b1b2: handle 1 prio 1 protocol all fw", + "matchPattern": "filter protocol all pref 1 fw.*handle 0x1.*gact action pass", + "matchCount": "0", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "66e0", + "name": "Add fw filter with missing mandatory parent id", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 handle 1 prio 1 fw action ok", + "expExitCode": "2", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol all fw", + "matchPattern": "pref [0-9]+ fw.*handle 0x1.*gact action pass", + "matchCount": "0", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "0ff3", + "name": "Add fw filter with classid", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 1 fw classid 3 action ok", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol all fw", + "matchPattern": "fw.*handle 0x1 classid :3.*gact action pass", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "9849", + "name": "Add fw filter with classid at root", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 1 fw classid ffff:ffff action ok", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol all fw", + "matchPattern": "pref 1 fw.*handle 0x1 classid root.*gact action pass", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "b7ff", + "name": "Add fw filter with classid - keeps last 8 (hex) digits", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 1 fw classid 98765fedcb action ok", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol all fw", + "matchPattern": "fw.*handle 0x1 classid 765f:edcb.*gact action pass", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "2b18", + "name": "Add fw filter with invalid classid", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 1 fw classid 6789defg action ok", + "expExitCode": "1", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol all fw", + "matchPattern": "fw.*handle 0x1 classid 6789:defg.*gact action pass", + "matchCount": "0", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "fade", + "name": "Add fw filter with flowid", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 10 prio 1 fw flowid 1:10 action ok", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 10 prio 1 protocol all fw", + "matchPattern": "filter parent ffff: protocol all pref 1 fw.*handle 0xa classid 1:10.*gact action pass", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "33af", + "name": "Add fw filter with flowid then classid (same arg, takes second)", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 11 prio 1 fw flowid 10 classid 4 action ok", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 11 prio 1 protocol all fw", + "matchPattern": "filter parent ffff: protocol all pref 1 fw.*handle 0xb classid :4.*gact action pass", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "8a8c", + "name": "Add fw filter with classid then flowid (same arg, takes second)", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 11 prio 1 fw classid 4 flowid 10 action ok", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 11 prio 1 protocol all fw", + "matchPattern": "filter parent ffff: protocol all pref 1 fw.*handle 0xb classid :10.*gact action pass", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "b50d", + "name": "Add fw filter with handle val/mask and flowid 10:1000", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: prio 3 handle 10/0xff fw flowid 10:1000 action ok", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 10 prio 3 protocol all fw", + "matchPattern": "filter parent ffff: protocol all pref 3 fw.*handle 0xa/0xff classid 10:1000.*gact action pass", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "7207", + "name": "Add fw filter with protocol ip", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: protocol ip prio 1 handle 3 fw action ok", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 3 prio 1 protocol ip fw", + "matchPattern": "filter parent ffff: protocol ip pref 1 fw.*handle 0x3.*gact action pass.*index [0-9]+ ref [0-9]+ bind [0-9]+", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "306d", + "name": "Add fw filter with protocol ipv6", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: protocol ipv6 prio 2 handle 4 fw action ok", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 4 prio 2 protocol ipv6 fw", + "matchPattern": "filter parent ffff: protocol ipv6 pref 2 fw.*handle 0x4.*gact action pass.*index [0-9]+ ref [0-9]+ bind [0-9]+", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "9a78", + "name": "Add fw filter with protocol arp", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: protocol arp prio 5 handle 7 fw action drop", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 7 prio 5 protocol arp fw", + "matchPattern": "filter parent ffff: protocol arp pref 5 fw.*handle 0x7.*gact action drop.*index [0-9]+ ref [0-9]+ bind [0-9]+", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "1821", + "name": "Add fw filter with protocol 802_3", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: protocol 802_3 handle 1 prio 1 fw action ok", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol 802_3 fw", + "matchPattern": "filter parent ffff: protocol 802_3 pref 1 fw.*handle 0x1.*gact action pass", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "2260", + "name": "Add fw filter with invalid protocol", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: protocol igmp handle 1 prio 1 fw action ok", + "expExitCode": "255", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol igmp fw", + "matchPattern": "filter parent ffff: protocol igmp pref 1 fw.*handle 0x1.*gact action pass", + "matchCount": "0", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "09d7", + "name": "Add fw filters protocol 802_3 and ip with conflicting priorities", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress", + "$TC filter add dev $DEV1 parent ffff: protocol 802_3 prio 3 handle 7 fw action ok" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: protocol ip prio 3 handle 8 fw action ok", + "expExitCode": "2", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 8 prio 3 protocol ip fw", + "matchPattern": "filter parent ffff: protocol ip pref 3 fw.*handle 0x8", + "matchCount": "0", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "6973", + "name": "Add fw filters with same index, same action", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress", + "$TC filter add dev $DEV1 parent ffff: prio 6 handle 2 fw action continue index 5" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: prio 8 handle 4 fw action continue index 5", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 4 prio 8 protocol all fw", + "matchPattern": "filter parent ffff: protocol all pref 8 fw.*handle 0x4.*gact action continue.*index 5 ref 2 bind 2", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "fc06", + "name": "Add fw filters with action police", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: prio 3 handle 4 fw action police rate 1kbit burst 10k index 5", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 4 prio 3 protocol all fw", + "matchPattern": "filter parent ffff: protocol all pref 3 fw.*handle 0x4.*police 0x5 rate 1Kbit burst 10Kb mtu 2Kb action reclassify overhead 0b.*ref 1 bind 1", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "aac7", + "name": "Add fw filters with action police linklayer atm", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress" + ], + "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: prio 3 handle 4 fw action police rate 2mbit burst 200k linklayer atm index 8", + "expExitCode": "0", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 4 prio 3 protocol all fw", + "matchPattern": "filter parent ffff: protocol all pref 3 fw.*handle 0x4.*police 0x8 rate 2Mbit burst 200Kb mtu 2Kb action reclassify overhead 0b linklayer atm.*ref 1 bind 1", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "5339", + "name": "Del entire fw filter", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress", + "$TC filter add dev $DEV1 parent ffff: handle 5 prio 7 fw action pass", + "$TC filter add dev $DEV1 parent ffff: handle 3 prio 9 fw action pass" + ], + "cmdUnderTest": "$TC filter del dev $DEV1 parent ffff:", + "expExitCode": "0", + "verifyCmd": "$TC filter show dev $DEV1 parent ffff:", + "matchPattern": "protocol all pref.*handle.*gact action pass", + "matchCount": "0", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "0e99", + "name": "Del single fw filter x1", + "__comment__": "First of two tests to check that one filter is there and the other isn't", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress", + "$TC filter add dev $DEV1 parent ffff: handle 5 prio 7 fw action pass", + "$TC filter add dev $DEV1 parent ffff: handle 3 prio 9 fw action pass" + ], + "cmdUnderTest": "$TC filter del dev $DEV1 parent ffff: handle 3 prio 9 fw action pass", + "expExitCode": "0", + "verifyCmd": "$TC filter show dev $DEV1 parent ffff:", + "matchPattern": "protocol all pref 7.*handle 0x5.*gact action pass", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "f54c", + "name": "Del single fw filter x2", + "__comment__": "Second of two tests to check that one filter is there and the other isn't", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress", + "$TC filter add dev $DEV1 parent ffff: handle 5 prio 7 fw action pass", + "$TC filter add dev $DEV1 parent ffff: handle 3 prio 9 fw action pass" + ], + "cmdUnderTest": "$TC filter del dev $DEV1 parent ffff: handle 3 prio 9 fw action pass", + "expExitCode": "0", + "verifyCmd": "$TC filter show dev $DEV1 parent ffff:", + "matchPattern": "protocol all pref 9.*handle 0x3.*gact action pass", + "matchCount": "0", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "ba94", + "name": "Del fw filter by prio", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress", + "$TC filter add dev $DEV1 parent ffff: handle 1 prio 4 fw action ok", + "$TC filter add dev $DEV1 parent ffff: handle 2 prio 4 fw action ok" + ], + "cmdUnderTest": "$TC filter del dev $DEV1 parent ffff: prio 4", + "expExitCode": "0", + "verifyCmd": "$TC filter show dev $DEV1 parent ffff:", + "matchPattern": "pref 4 fw.*gact action pass", + "matchCount": "0", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "4acb", + "name": "Del fw filter by chain", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress", + "$TC filter add dev $DEV1 parent ffff: handle 4 prio 2 chain 13 fw action pipe", + "$TC filter add dev $DEV1 parent ffff: handle 3 prio 5 chain 13 fw action pipe" + ], + "cmdUnderTest": "$TC filter del dev $DEV1 parent ffff: chain 13", + "expExitCode": "0", + "verifyCmd": "$TC filter show dev $DEV1 parent ffff:", + "matchPattern": "fw chain 13 handle.*gact action pipe", + "matchCount": "0", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "3424", + "name": "Del fw filter by action (invalid)", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress", + "$TC filter add dev $DEV1 parent ffff: handle 2 prio 4 fw action drop" + ], + "cmdUnderTest": "$TC filter del dev $DEV1 parent ffff: fw action drop", + "expExitCode": "2", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 2 prio 4 protocol all fw", + "matchPattern": "handle 0x2.*gact action drop", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "da89", + "name": "Del fw filter by handle (invalid)", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress", + "$TC filter add dev $DEV1 parent ffff: handle 3 prio 4 fw action continue" + ], + "cmdUnderTest": "$TC filter del dev $DEV1 parent ffff: handle 3 fw", + "expExitCode": "2", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 3 prio 4 protocol all fw", + "matchPattern": "handle 0x3.*gact action continue", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "4d95", + "name": "Del fw filter by protocol (invalid)", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress", + "$TC filter add dev $DEV1 parent ffff: handle 4 prio 2 protocol arp fw action pipe" + ], + "cmdUnderTest": "$TC filter del dev $DEV1 parent ffff: protocol arp fw", + "expExitCode": "2", + "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 4 prio 2 protocol arp fw", + "matchPattern": "filter parent ffff: protocol arp.*handle 0x4.*gact action pipe", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "4736", + "name": "Del fw filter by flowid (invalid)", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress", + "$TC filter add dev $DEV1 parent ffff: handle 4 prio 2 fw action pipe flowid 45" + ], + "cmdUnderTest": "$TC filter del dev $DEV1 parent ffff: fw flowid 45", + "expExitCode": "2", + "verifyCmd": "$TC filter show dev $DEV1 parent ffff:", + "matchPattern": "handle 0x4.*gact action pipe", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "3dcb", + "name": "Replace fw filter action", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress", + "$TC filter add dev $DEV1 parent ffff: handle 1 prio 2 fw action ok" + ], + "cmdUnderTest": "$TC filter replace dev $DEV1 parent ffff: handle 1 prio 2 fw action pipe", + "expExitCode": "0", + "verifyCmd": "$TC filter show dev $DEV1 parent ffff:", + "matchPattern": "pref 2 fw.*handle 0x1.*gact action pipe", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "eb4d", + "name": "Replace fw filter classid", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress", + "$TC filter add dev $DEV1 parent ffff: handle 1 prio 2 fw action ok" + ], + "cmdUnderTest": "$TC filter replace dev $DEV1 parent ffff: handle 1 prio 2 fw action pipe classid 2", + "expExitCode": "0", + "verifyCmd": "$TC filter show dev $DEV1 parent ffff:", + "matchPattern": "pref 2 fw.*handle 0x1 classid :2.*gact action pipe", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + }, + { + "id": "67ec", + "name": "Replace fw filter index", + "category": [ + "filter", + "fw" + ], + "setup": [ + "$TC qdisc add dev $DEV1 ingress", + "$TC filter add dev $DEV1 parent ffff: handle 1 prio 2 fw action ok index 3" + ], + "cmdUnderTest": "$TC filter replace dev $DEV1 parent ffff: handle 1 prio 2 fw action ok index 16", + "expExitCode": "0", + "verifyCmd": "$TC filter show dev $DEV1 parent ffff:", + "matchPattern": "pref 2 fw.*handle 0x1.*gact action pass.*index 16", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DEV1 ingress" + ] + } +] diff --git a/tools/testing/selftests/tc-testing/tc-tests/filters/tests.json b/tools/testing/selftests/tc-testing/tc-tests/filters/tests.json index 5fa02d86b35f..99a5ffca1088 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/filters/tests.json +++ b/tools/testing/selftests/tc-testing/tc-tests/filters/tests.json @@ -12,8 +12,8 @@ "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: protocol ip prio 1 u32 match ip src 127.0.0.1/32 flowid 1:1 action ok", "expExitCode": "0", "verifyCmd": "$TC filter show dev $DEV1 parent ffff:", - "matchPattern": "match 7f000002/ffffffff at 12", - "matchCount": "0", + "matchPattern": "match 7f000001/ffffffff at 12", + "matchCount": "1", "teardown": [ "$TC qdisc del dev $DEV1 ingress" ] diff --git a/tools/testing/selftests/timers/raw_skew.c b/tools/testing/selftests/timers/raw_skew.c index ca6cd146aafe..dcf73c5dab6e 100644 --- a/tools/testing/selftests/timers/raw_skew.c +++ b/tools/testing/selftests/timers/raw_skew.c @@ -134,6 +134,11 @@ int main(int argv, char **argc) printf(" %lld.%i(act)", ppm/1000, abs((int)(ppm%1000))); if (llabs(eppm - ppm) > 1000) { + if (tx1.offset || tx2.offset || + tx1.freq != tx2.freq || tx1.tick != tx2.tick) { + printf(" [SKIP]\n"); + return ksft_exit_skip("The clock was adjusted externally. Shutdown NTPd or other time sync daemons\n"); + } printf(" [FAILED]\n"); return ksft_exit_fail(); } diff --git a/tools/testing/selftests/vDSO/Makefile b/tools/testing/selftests/vDSO/Makefile index f5d7a7851e21..9e03d61f52fd 100644 --- a/tools/testing/selftests/vDSO/Makefile +++ b/tools/testing/selftests/vDSO/Makefile @@ -1,6 +1,14 @@ # SPDX-License-Identifier: GPL-2.0 include ../lib.mk +uname_M := $(shell uname -m 2>/dev/null || echo not) +ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/x86/ -e s/x86_64/x86/) + +TEST_GEN_PROGS := $(OUTPUT)/vdso_test +ifeq ($(ARCH),x86) +TEST_GEN_PROGS += $(OUTPUT)/vdso_standalone_test_x86 +endif + ifndef CROSS_COMPILE CFLAGS := -std=gnu99 CFLAGS_vdso_standalone_test_x86 := -nostdlib -fno-asynchronous-unwind-tables -fno-stack-protector @@ -8,14 +16,11 @@ ifeq ($(CONFIG_X86_32),y) LDLIBS += -lgcc_s endif -TEST_PROGS := $(OUTPUT)/vdso_test $(OUTPUT)/vdso_standalone_test_x86 - -all: $(TEST_PROGS) +all: $(TEST_GEN_PROGS) $(OUTPUT)/vdso_test: parse_vdso.c vdso_test.c $(OUTPUT)/vdso_standalone_test_x86: vdso_standalone_test_x86.c parse_vdso.c $(CC) $(CFLAGS) $(CFLAGS_vdso_standalone_test_x86) \ vdso_standalone_test_x86.c parse_vdso.c \ -o $@ -EXTRA_CLEAN := $(TEST_PROGS) endif diff --git a/tools/testing/selftests/vDSO/vdso_test.c b/tools/testing/selftests/vDSO/vdso_test.c index 2df26bd0099c..eda53f833d8e 100644 --- a/tools/testing/selftests/vDSO/vdso_test.c +++ b/tools/testing/selftests/vDSO/vdso_test.c @@ -15,6 +15,8 @@ #include <sys/auxv.h> #include <sys/time.h> +#include "../kselftest.h" + extern void *vdso_sym(const char *version, const char *name); extern void vdso_init_from_sysinfo_ehdr(uintptr_t base); extern void vdso_init_from_auxv(void *auxv); @@ -37,7 +39,7 @@ int main(int argc, char **argv) unsigned long sysinfo_ehdr = getauxval(AT_SYSINFO_EHDR); if (!sysinfo_ehdr) { printf("AT_SYSINFO_EHDR is not present!\n"); - return 0; + return KSFT_SKIP; } vdso_init_from_sysinfo_ehdr(getauxval(AT_SYSINFO_EHDR)); @@ -48,7 +50,7 @@ int main(int argc, char **argv) if (!gtod) { printf("Could not find %s\n", name); - return 1; + return KSFT_SKIP; } struct timeval tv; @@ -59,6 +61,7 @@ int main(int argc, char **argv) (long long)tv.tv_sec, (long long)tv.tv_usec); } else { printf("%s failed\n", name); + return KSFT_FAIL; } return 0; diff --git a/tools/testing/selftests/vm/.gitignore b/tools/testing/selftests/vm/.gitignore index 342c7bc9dc8c..af5ff83f6d7f 100644 --- a/tools/testing/selftests/vm/.gitignore +++ b/tools/testing/selftests/vm/.gitignore @@ -1,6 +1,7 @@ hugepage-mmap hugepage-shm map_hugetlb +map_populate thuge-gen compaction_test mlock2-tests diff --git a/tools/testing/selftests/vm/Makefile b/tools/testing/selftests/vm/Makefile index fdefa2295ddc..9881876d2aa0 100644 --- a/tools/testing/selftests/vm/Makefile +++ b/tools/testing/selftests/vm/Makefile @@ -12,6 +12,7 @@ TEST_GEN_FILES += gup_benchmark TEST_GEN_FILES += hugepage-mmap TEST_GEN_FILES += hugepage-shm TEST_GEN_FILES += map_hugetlb +TEST_GEN_FILES += map_populate TEST_GEN_FILES += mlock-random-test TEST_GEN_FILES += mlock2-tests TEST_GEN_FILES += on-fault-limit diff --git a/tools/testing/selftests/vm/map_populate.c b/tools/testing/selftests/vm/map_populate.c new file mode 100644 index 000000000000..6b8aeaa0bf7a --- /dev/null +++ b/tools/testing/selftests/vm/map_populate.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 Dmitry Safonov, Arista Networks + * + * MAP_POPULATE | MAP_PRIVATE should COW VMA pages. + */ + +#define _GNU_SOURCE +#include <errno.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#ifndef MMAP_SZ +#define MMAP_SZ 4096 +#endif + +#define BUG_ON(condition, description) \ + do { \ + if (condition) { \ + fprintf(stderr, "[FAIL]\t%s:%d\t%s:%s\n", __func__, \ + __LINE__, (description), strerror(errno)); \ + exit(1); \ + } \ + } while (0) + +static int parent_f(int sock, unsigned long *smap, int child) +{ + int status, ret; + + ret = read(sock, &status, sizeof(int)); + BUG_ON(ret <= 0, "read(sock)"); + + *smap = 0x22222BAD; + ret = msync(smap, MMAP_SZ, MS_SYNC); + BUG_ON(ret, "msync()"); + + ret = write(sock, &status, sizeof(int)); + BUG_ON(ret <= 0, "write(sock)"); + + waitpid(child, &status, 0); + BUG_ON(!WIFEXITED(status), "child in unexpected state"); + + return WEXITSTATUS(status); +} + +static int child_f(int sock, unsigned long *smap, int fd) +{ + int ret, buf = 0; + + smap = mmap(0, MMAP_SZ, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_POPULATE, fd, 0); + BUG_ON(smap == MAP_FAILED, "mmap()"); + + BUG_ON(*smap != 0xdeadbabe, "MAP_PRIVATE | MAP_POPULATE changed file"); + + ret = write(sock, &buf, sizeof(int)); + BUG_ON(ret <= 0, "write(sock)"); + + ret = read(sock, &buf, sizeof(int)); + BUG_ON(ret <= 0, "read(sock)"); + + BUG_ON(*smap == 0x22222BAD, "MAP_POPULATE didn't COW private page"); + BUG_ON(*smap != 0xdeadbabe, "mapping was corrupted"); + + return 0; +} + +int main(int argc, char **argv) +{ + int sock[2], child, ret; + FILE *ftmp; + unsigned long *smap; + + ftmp = tmpfile(); + BUG_ON(ftmp == 0, "tmpfile()"); + + ret = ftruncate(fileno(ftmp), MMAP_SZ); + BUG_ON(ret, "ftruncate()"); + + smap = mmap(0, MMAP_SZ, PROT_READ | PROT_WRITE, + MAP_SHARED, fileno(ftmp), 0); + BUG_ON(smap == MAP_FAILED, "mmap()"); + + *smap = 0xdeadbabe; + /* Probably unnecessary, but let it be. */ + ret = msync(smap, MMAP_SZ, MS_SYNC); + BUG_ON(ret, "msync()"); + + ret = socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sock); + BUG_ON(ret, "socketpair()"); + + child = fork(); + BUG_ON(child == -1, "fork()"); + + if (child) { + ret = close(sock[0]); + BUG_ON(ret, "close()"); + + return parent_f(sock[1], smap, child); + } + + ret = close(sock[1]); + BUG_ON(ret, "close()"); + + return child_f(sock[0], smap, fileno(ftmp)); +} diff --git a/tools/testing/selftests/vm/run_vmtests b/tools/testing/selftests/vm/run_vmtests index 88cbe5575f0c..584a91ae4a8f 100755 --- a/tools/testing/selftests/vm/run_vmtests +++ b/tools/testing/selftests/vm/run_vmtests @@ -168,6 +168,17 @@ else fi echo "--------------------" +echo "running map_populate" +echo "--------------------" +./map_populate +if [ $? -ne 0 ]; then + echo "[FAIL]" + exitcode=1 +else + echo "[PASS]" +fi + +echo "--------------------" echo "running mlock2-tests" echo "--------------------" ./mlock2-tests diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c index cce853dca691..30cb0a0713ff 100644 --- a/tools/vm/page-types.c +++ b/tools/vm/page-types.c @@ -75,8 +75,11 @@ #define KPF_BYTES 8 #define PROC_KPAGEFLAGS "/proc/kpageflags" +#define PROC_KPAGECOUNT "/proc/kpagecount" #define PROC_KPAGECGROUP "/proc/kpagecgroup" +#define SYS_KERNEL_MM_PAGE_IDLE "/sys/kernel/mm/page_idle/bitmap" + /* [32-] kernel hacking assistances */ #define KPF_RESERVED 32 #define KPF_MLOCKED 33 @@ -168,11 +171,13 @@ static const char * const debugfs_known_mountpoints[] = { static int opt_raw; /* for kernel developers */ static int opt_list; /* list pages (in ranges) */ +static int opt_mark_idle; /* set accessed bit */ static int opt_no_summary; /* don't show summary */ static pid_t opt_pid; /* process to walk */ const char *opt_file; /* file or directory path */ static uint64_t opt_cgroup; /* cgroup inode */ static int opt_list_cgroup;/* list page cgroup */ +static int opt_list_mapcnt;/* list page map count */ static const char *opt_kpageflags;/* kpageflags file to parse */ #define MAX_ADDR_RANGES 1024 @@ -194,7 +199,9 @@ static int page_size; static int pagemap_fd; static int kpageflags_fd; +static int kpagecount_fd = -1; static int kpagecgroup_fd = -1; +static int page_idle_fd = -1; static int opt_hwpoison; static int opt_unpoison; @@ -298,6 +305,15 @@ static unsigned long kpagecgroup_read(uint64_t *buf, return do_u64_read(kpagecgroup_fd, opt_kpageflags, buf, index, pages); } +static unsigned long kpagecount_read(uint64_t *buf, + unsigned long index, + unsigned long pages) +{ + return kpagecount_fd < 0 ? pages : + do_u64_read(kpagecount_fd, PROC_KPAGECOUNT, + buf, index, pages); +} + static unsigned long pagemap_read(uint64_t *buf, unsigned long index, unsigned long pages) @@ -370,16 +386,18 @@ static char *page_flag_longname(uint64_t flags) */ static void show_page_range(unsigned long voffset, unsigned long offset, - unsigned long size, uint64_t flags, uint64_t cgroup) + unsigned long size, uint64_t flags, + uint64_t cgroup, uint64_t mapcnt) { static uint64_t flags0; static uint64_t cgroup0; + static uint64_t mapcnt0; static unsigned long voff; static unsigned long index; static unsigned long count; - if (flags == flags0 && cgroup == cgroup0 && offset == index + count && - size && voffset == voff + count) { + if (flags == flags0 && cgroup == cgroup0 && mapcnt == mapcnt0 && + offset == index + count && size && voffset == voff + count) { count += size; return; } @@ -391,12 +409,15 @@ static void show_page_range(unsigned long voffset, unsigned long offset, printf("%lu\t", voff); if (opt_list_cgroup) printf("@%llu\t", (unsigned long long)cgroup0); + if (opt_list_mapcnt) + printf("%lu\t", mapcnt0); printf("%lx\t%lx\t%s\n", index, count, page_flag_name(flags0)); } flags0 = flags; - cgroup0= cgroup; + cgroup0 = cgroup; + mapcnt0 = mapcnt; index = offset; voff = voffset; count = size; @@ -404,11 +425,11 @@ static void show_page_range(unsigned long voffset, unsigned long offset, static void flush_page_range(void) { - show_page_range(0, 0, 0, 0, 0); + show_page_range(0, 0, 0, 0, 0, 0); } static void show_page(unsigned long voffset, unsigned long offset, - uint64_t flags, uint64_t cgroup) + uint64_t flags, uint64_t cgroup, uint64_t mapcnt) { if (opt_pid) printf("%lx\t", voffset); @@ -416,6 +437,9 @@ static void show_page(unsigned long voffset, unsigned long offset, printf("%lu\t", voffset); if (opt_list_cgroup) printf("@%llu\t", (unsigned long long)cgroup); + if (opt_list_mapcnt) + printf("%lu\t", mapcnt); + printf("%lx\t%s\n", offset, page_flag_name(flags)); } @@ -567,6 +591,30 @@ static int unpoison_page(unsigned long offset) return 0; } +static int mark_page_idle(unsigned long offset) +{ + static unsigned long off; + static uint64_t buf; + int len; + + if ((offset / 64 == off / 64) || buf == 0) { + buf |= 1UL << (offset % 64); + off = offset; + return 0; + } + + len = pwrite(page_idle_fd, &buf, 8, 8 * (off / 64)); + if (len < 0) { + perror("mark page idle"); + return len; + } + + buf = 1UL << (offset % 64); + off = offset; + + return 0; +} + /* * page frame walker */ @@ -599,7 +647,8 @@ static size_t hash_slot(uint64_t flags) } static void add_page(unsigned long voffset, unsigned long offset, - uint64_t flags, uint64_t cgroup, uint64_t pme) + uint64_t flags, uint64_t cgroup, uint64_t mapcnt, + uint64_t pme) { flags = kpageflags_flags(flags, pme); @@ -614,10 +663,13 @@ static void add_page(unsigned long voffset, unsigned long offset, if (opt_unpoison) unpoison_page(offset); + if (opt_mark_idle) + mark_page_idle(offset); + if (opt_list == 1) - show_page_range(voffset, offset, 1, flags, cgroup); + show_page_range(voffset, offset, 1, flags, cgroup, mapcnt); else if (opt_list == 2) - show_page(voffset, offset, flags, cgroup); + show_page(voffset, offset, flags, cgroup, mapcnt); nr_pages[hash_slot(flags)]++; total_pages++; @@ -631,6 +683,7 @@ static void walk_pfn(unsigned long voffset, { uint64_t buf[KPAGEFLAGS_BATCH]; uint64_t cgi[KPAGEFLAGS_BATCH]; + uint64_t cnt[KPAGEFLAGS_BATCH]; unsigned long batch; unsigned long pages; unsigned long i; @@ -654,8 +707,12 @@ static void walk_pfn(unsigned long voffset, if (kpagecgroup_read(cgi, index, pages) != pages) fatal("kpagecgroup returned fewer pages than expected"); + if (kpagecount_read(cnt, index, batch) != pages) + fatal("kpagecount returned fewer pages than expected"); + for (i = 0; i < pages; i++) - add_page(voffset + i, index + i, buf[i], cgi[i], pme); + add_page(voffset + i, index + i, + buf[i], cgi[i], cnt[i], pme); index += pages; count -= pages; @@ -673,9 +730,10 @@ static void walk_swap(unsigned long voffset, uint64_t pme) return; if (opt_list == 1) - show_page_range(voffset, pagemap_swap_offset(pme), 1, flags, 0); + show_page_range(voffset, pagemap_swap_offset(pme), + 1, flags, 0, 0); else if (opt_list == 2) - show_page(voffset, pagemap_swap_offset(pme), flags, 0); + show_page(voffset, pagemap_swap_offset(pme), flags, 0, 0); nr_pages[hash_slot(flags)]++; total_pages++; @@ -756,6 +814,9 @@ static void walk_addr_ranges(void) else walk_task(opt_offset[i], opt_size[i]); + if (opt_mark_idle) + mark_page_idle(0); + close(kpageflags_fd); } @@ -786,9 +847,11 @@ static void usage(void) " -c|--cgroup path|@inode Walk pages within memory cgroup\n" " -p|--pid pid Walk process address space\n" " -f|--file filename Walk file address space\n" +" -i|--mark-idle Mark pages idle\n" " -l|--list Show page details in ranges\n" " -L|--list-each Show page details one by one\n" " -C|--list-cgroup Show cgroup inode for pages\n" +" -M|--list-mapcnt Show page map count\n" " -N|--no-summary Don't show summary info\n" " -X|--hwpoison hwpoison pages\n" " -x|--unpoison unpoison pages\n" @@ -925,6 +988,7 @@ static void walk_file(const char *name, const struct stat *st) uint8_t vec[PAGEMAP_BATCH]; uint64_t buf[PAGEMAP_BATCH], flags; uint64_t cgroup = 0; + uint64_t mapcnt = 0; unsigned long nr_pages, pfn, i; off_t off, end = st->st_size; int fd; @@ -984,13 +1048,15 @@ got_sigbus: continue; if (!kpagecgroup_read(&cgroup, pfn, 1)) fatal("kpagecgroup_read failed"); + if (!kpagecount_read(&mapcnt, pfn, 1)) + fatal("kpagecount_read failed"); if (first && opt_list) { first = 0; flush_page_range(); show_file(name, st); } add_page(off / page_size + i, pfn, - flags, cgroup, buf[i]); + flags, cgroup, mapcnt, buf[i]); } } @@ -1190,9 +1256,11 @@ static const struct option opts[] = { { "bits" , 1, NULL, 'b' }, { "cgroup" , 1, NULL, 'c' }, { "describe" , 1, NULL, 'd' }, + { "mark-idle" , 0, NULL, 'i' }, { "list" , 0, NULL, 'l' }, { "list-each" , 0, NULL, 'L' }, { "list-cgroup", 0, NULL, 'C' }, + { "list-mapcnt", 0, NULL, 'M' }, { "no-summary", 0, NULL, 'N' }, { "hwpoison" , 0, NULL, 'X' }, { "unpoison" , 0, NULL, 'x' }, @@ -1208,7 +1276,8 @@ int main(int argc, char *argv[]) page_size = getpagesize(); while ((c = getopt_long(argc, argv, - "rp:f:a:b:d:c:ClLNXxF:h", opts, NULL)) != -1) { + "rp:f:a:b:d:c:CilLMNXxF:h", + opts, NULL)) != -1) { switch (c) { case 'r': opt_raw = 1; @@ -1234,12 +1303,18 @@ int main(int argc, char *argv[]) case 'd': describe_flags(optarg); exit(0); + case 'i': + opt_mark_idle = 1; + break; case 'l': opt_list = 1; break; case 'L': opt_list = 2; break; + case 'M': + opt_list_mapcnt = 1; + break; case 'N': opt_no_summary = 1; break; @@ -1269,12 +1344,21 @@ int main(int argc, char *argv[]) if (opt_cgroup || opt_list_cgroup) kpagecgroup_fd = checked_open(PROC_KPAGECGROUP, O_RDONLY); + if (opt_list && opt_list_mapcnt) + kpagecount_fd = checked_open(PROC_KPAGECOUNT, O_RDONLY); + + if (opt_mark_idle && opt_file) + page_idle_fd = checked_open(SYS_KERNEL_MM_PAGE_IDLE, O_RDWR); + if (opt_list && opt_pid) printf("voffset\t"); if (opt_list && opt_file) printf("foffset\t"); if (opt_list && opt_list_cgroup) printf("cgroup\t"); + if (opt_list && opt_list_mapcnt) + printf("map-cnt\t"); + if (opt_list == 1) printf("offset\tlen\tflags\n"); if (opt_list == 2) @@ -1296,5 +1380,11 @@ int main(int argc, char *argv[]) show_summary(); + if (opt_list_mapcnt) + close(kpagecount_fd); + + if (page_idle_fd >= 0) + close(page_idle_fd); + return 0; } |