From 8665bd53f2f2e27e5511d90428cb3f60e6d0ce15 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 18 May 2024 20:50:12 +0200 Subject: Merging upstream version 6.8.9. Signed-off-by: Daniel Baumann --- tools/arch/x86/include/asm/cpufeatures.h | 10 +- tools/arch/x86/include/asm/msr-index.h | 8 + tools/arch/x86/include/uapi/asm/kvm.h | 3 + tools/arch/x86/lib/memcpy_64.S | 4 +- tools/arch/x86/lib/memset_64.S | 4 +- tools/bpf/bpftool/Documentation/bpftool.rst | 2 +- tools/bpf/bpftool/feature.c | 4 - tools/bpf/bpftool/link.c | 105 +- tools/bpf/bpftool/prog.c | 14 +- tools/build/Makefile.feature | 1 + tools/build/feature/Makefile | 4 + tools/build/feature/test-dwarf_getcfi.c | 9 + tools/cgroup/Makefile | 11 - tools/cgroup/cgroup_event_listener.c | 83 - tools/counter/Build | 1 + tools/counter/Makefile | 12 +- tools/counter/counter_watch_events.c | 406 ++ tools/crypto/tcrypt/tcrypt_speed_compare.py | 190 + tools/iio/iio_event_monitor.c | 2 + tools/iio/iio_utils.c | 2 +- tools/include/asm-generic/unaligned.h | 24 +- tools/include/linux/rwsem.h | 4 + tools/include/linux/spinlock.h | 1 + tools/include/nolibc/arch-mips.h | 11 +- tools/include/nolibc/arch.h | 4 +- tools/include/nolibc/stdio.h | 4 +- tools/include/nolibc/sys.h | 38 + tools/include/nolibc/types.h | 25 +- tools/include/perf/arm_pmuv3.h | 43 +- tools/include/uapi/asm-generic/unistd.h | 15 +- tools/include/uapi/drm/drm.h | 72 +- tools/include/uapi/drm/i915_drm.h | 12 +- tools/include/uapi/linux/bpf.h | 40 +- tools/include/uapi/linux/fcntl.h | 3 + tools/include/uapi/linux/fs.h | 1 + tools/include/uapi/linux/if_xdp.h | 61 +- tools/include/uapi/linux/kvm.h | 140 +- tools/include/uapi/linux/mount.h | 70 + tools/include/uapi/linux/netdev.h | 80 +- tools/include/uapi/linux/perf_event.h | 13 + tools/include/uapi/linux/pkt_cls.h | 47 - tools/include/uapi/linux/pkt_sched.h | 109 - tools/include/uapi/linux/stat.h | 1 + tools/include/uapi/sound/asound.h | 7 +- tools/lib/api/fs/fs.c | 80 +- tools/lib/api/io.h | 11 +- tools/lib/bpf/bpf_core_read.h | 32 + tools/lib/bpf/bpf_helpers.h | 3 + tools/lib/bpf/elf.c | 5 +- tools/lib/bpf/libbpf.c | 726 ++- tools/lib/bpf/libbpf.map | 3 + tools/lib/bpf/libbpf_internal.h | 17 +- tools/lib/bpf/libbpf_version.h | 2 +- tools/lib/bpf/linker.c | 27 +- tools/lib/perf/Documentation/examples/sampling.c | 2 +- tools/lib/perf/Documentation/libperf-sampling.txt | 2 +- tools/lib/perf/Documentation/libperf.txt | 4 +- tools/lib/perf/cpumap.c | 65 +- tools/lib/perf/evlist.c | 24 +- tools/lib/perf/evsel.c | 2 +- tools/lib/perf/include/internal/evlist.h | 4 +- tools/lib/perf/include/internal/mmap.h | 3 +- tools/lib/perf/include/perf/cpumap.h | 40 +- tools/lib/perf/libperf.map | 6 +- tools/lib/perf/mmap.c | 20 +- tools/lib/perf/tests/test-cpumap.c | 4 +- tools/lib/perf/tests/test-evlist.c | 6 +- tools/lib/perf/tests/test-evsel.c | 2 +- tools/net/ynl/Makefile | 2 + tools/net/ynl/generated/.gitignore | 2 + tools/net/ynl/generated/devlink-user.c | 6864 -------------------- tools/net/ynl/generated/devlink-user.h | 5255 --------------- tools/net/ynl/generated/ethtool-user.c | 6370 ------------------ tools/net/ynl/generated/ethtool-user.h | 5535 ---------------- tools/net/ynl/generated/fou-user.c | 330 - tools/net/ynl/generated/fou-user.h | 343 - tools/net/ynl/generated/handshake-user.c | 332 - tools/net/ynl/generated/handshake-user.h | 145 - tools/net/ynl/generated/netdev-user.c | 225 - tools/net/ynl/generated/netdev-user.h | 90 - tools/net/ynl/generated/nfsd-user.c | 203 - tools/net/ynl/generated/nfsd-user.h | 67 - tools/net/ynl/lib/nlspec.py | 55 + tools/net/ynl/lib/ynl-priv.h | 144 + tools/net/ynl/lib/ynl.c | 14 +- tools/net/ynl/lib/ynl.h | 149 +- tools/net/ynl/lib/ynl.py | 99 +- tools/net/ynl/samples/.gitignore | 1 + tools/net/ynl/samples/Makefile | 4 +- tools/net/ynl/samples/netdev.c | 10 +- tools/net/ynl/samples/page-pool.c | 147 + tools/net/ynl/ynl-gen-c.py | 272 +- tools/net/ynl/ynl-gen-rst.py | 417 ++ tools/net/ynl/ynl-regen.sh | 4 +- tools/objtool/check.c | 2 +- tools/perf/.gitignore | 4 + tools/perf/Documentation/itrace.txt | 1 + tools/perf/Documentation/perf-annotate.txt | 11 + tools/perf/Documentation/perf-config.txt | 4 +- tools/perf/Documentation/perf-intel-pt.txt | 2 +- tools/perf/Documentation/perf-list.txt | 16 +- tools/perf/Documentation/perf-lock.txt | 2 +- tools/perf/Documentation/perf-record.txt | 4 + tools/perf/Documentation/perf-report.txt | 3 + tools/perf/Documentation/perf-stat.txt | 52 +- tools/perf/Documentation/perf.txt | 3 + tools/perf/Makefile.config | 13 +- tools/perf/Makefile.perf | 23 +- tools/perf/arch/arm/util/cs-etm.c | 16 +- tools/perf/arch/arm64/util/arm-spe.c | 4 +- tools/perf/arch/arm64/util/header.c | 2 +- tools/perf/arch/loongarch/annotate/instructions.c | 6 +- .../perf/arch/mips/entry/syscalls/syscall_n64.tbl | 5 + tools/perf/arch/powerpc/entry/syscalls/syscall.tbl | 5 + tools/perf/arch/s390/entry/syscalls/syscall.tbl | 5 + tools/perf/arch/x86/entry/syscalls/syscall_64.tbl | 5 + tools/perf/arch/x86/tests/hybrid.c | 37 +- tools/perf/arch/x86/util/dwarf-regs.c | 38 + tools/perf/arch/x86/util/event.c | 103 +- tools/perf/arch/x86/util/intel-bts.c | 4 +- tools/perf/arch/x86/util/intel-pt.c | 10 +- tools/perf/bench/epoll-ctl.c | 2 +- tools/perf/bench/epoll-wait.c | 2 +- tools/perf/bench/futex-hash.c | 2 +- tools/perf/bench/futex-lock-pi.c | 2 +- tools/perf/bench/futex-requeue.c | 2 +- tools/perf/bench/futex-wake-parallel.c | 2 +- tools/perf/bench/futex-wake.c | 2 +- tools/perf/bench/sched-seccomp-notify.c | 2 +- tools/perf/builtin-annotate.c | 300 +- tools/perf/builtin-c2c.c | 2 +- tools/perf/builtin-ftrace.c | 2 +- tools/perf/builtin-inject.c | 6 + tools/perf/builtin-list.c | 211 +- tools/perf/builtin-lock.c | 4 +- tools/perf/builtin-record.c | 69 +- tools/perf/builtin-report.c | 113 +- tools/perf/builtin-stat.c | 15 +- tools/perf/builtin-top.c | 49 +- tools/perf/builtin-trace.c | 6 +- tools/perf/perf-archive.sh | 86 +- tools/perf/perf.c | 30 + .../arch/arm64/ampere/ampereonex/branch.json | 125 + .../arch/arm64/ampere/ampereonex/bus.json | 20 + .../arch/arm64/ampere/ampereonex/cache.json | 206 + .../arch/arm64/ampere/ampereonex/core-imp-def.json | 464 ++ .../arch/arm64/ampere/ampereonex/exception.json | 47 + .../arch/arm64/ampere/ampereonex/instruction.json | 128 + .../arch/arm64/ampere/ampereonex/intrinsic.json | 14 + .../arch/arm64/ampere/ampereonex/memory.json | 41 + .../arch/arm64/ampere/ampereonex/metrics.json | 442 ++ .../arch/arm64/ampere/ampereonex/mmu.json | 170 + .../arch/arm64/ampere/ampereonex/pipeline.json | 41 + .../arch/arm64/ampere/ampereonex/spe.json | 14 + tools/perf/pmu-events/arch/arm64/mapfile.csv | 1 + tools/perf/pmu-events/arch/powerpc/mapfile.csv | 3 +- tools/perf/pmu-events/arch/riscv/mapfile.csv | 2 + .../arch/riscv/starfive/dubhe-80/common.json | 172 + .../arch/riscv/starfive/dubhe-80/firmware.json | 68 + .../arch/riscv/thead/c900-legacy/cache.json | 67 + .../arch/riscv/thead/c900-legacy/firmware.json | 68 + .../arch/riscv/thead/c900-legacy/instruction.json | 72 + .../arch/riscv/thead/c900-legacy/microarch.json | 80 + .../pmu-events/arch/x86/alderlake/adl-metrics.json | 269 +- .../arch/x86/alderlaken/adln-metrics.json | 4 - tools/perf/pmu-events/arch/x86/amdzen4/cache.json | 56 + .../arch/x86/amdzen4/memory-controller.json | 101 + .../pmu-events/arch/x86/amdzen4/recommended.json | 84 + .../arch/x86/cascadelakex/clx-metrics.json | 6 + .../arch/x86/emeraldrapids/floating-point.json | 27 +- .../arch/x86/emeraldrapids/pipeline.json | 18 +- .../x86/emeraldrapids/uncore-interconnect.json | 8 +- .../arch/x86/emeraldrapids/uncore-io.json | 30 + .../pmu-events/arch/x86/icelakex/icx-metrics.json | 6 + tools/perf/pmu-events/arch/x86/icelakex/other.json | 2 +- .../pmu-events/arch/x86/icelakex/pipeline.json | 2 +- .../arch/x86/icelakex/uncore-interconnect.json | 6 +- tools/perf/pmu-events/arch/x86/mapfile.csv | 6 +- .../arch/x86/rocketlake/rkl-metrics.json | 2 +- .../arch/x86/sapphirerapids/floating-point.json | 27 +- .../arch/x86/sapphirerapids/pipeline.json | 2 +- .../arch/x86/sapphirerapids/spr-metrics.json | 31 +- .../x86/sapphirerapids/uncore-interconnect.json | 8 +- .../arch/x86/sapphirerapids/uncore-io.json | 30 + .../pmu-events/arch/x86/skylakex/skx-metrics.json | 6 + tools/perf/pmu-events/jevents.py | 8 +- tools/perf/scripts/python/arm-cs-trace-disasm.py | 30 +- tools/perf/scripts/python/compaction-times.py | 2 +- tools/perf/scripts/python/exported-sql-viewer.py | 4 +- tools/perf/tests/Build | 14 + tools/perf/tests/attr.c | 2 +- tools/perf/tests/attr/base-record | 2 +- tools/perf/tests/builtin-test.c | 17 +- tools/perf/tests/code-reading.c | 80 +- tools/perf/tests/cpumap.c | 2 +- tools/perf/tests/dso-data.c | 15 +- tools/perf/tests/keep-tracking.c | 2 +- tools/perf/tests/make | 2 +- tools/perf/tests/maps.c | 61 +- tools/perf/tests/mmap-basic.c | 2 +- tools/perf/tests/openat-syscall-all-cpus.c | 2 +- tools/perf/tests/parse-events.c | 260 +- tools/perf/tests/perf-time-to-tsc.c | 2 +- .../shell/coresight/memcpy_thread/memcpy_thread.c | 1 - .../shell/coresight/thread_loop/thread_loop.c | 1 - .../unroll_loop_thread/unroll_loop_thread.c | 1 - tools/perf/tests/shell/daemon.sh | 34 +- tools/perf/tests/shell/diff.sh | 108 + tools/perf/tests/shell/lib/perf_has_symbol.sh | 21 + tools/perf/tests/shell/lib/setup_python.sh | 16 + tools/perf/tests/shell/list.sh | 34 + tools/perf/tests/shell/pipe_test.sh | 9 +- .../tests/shell/record+probe_libc_inet_pton.sh | 5 +- tools/perf/tests/shell/record.sh | 38 +- tools/perf/tests/shell/record_offcpu.sh | 4 +- tools/perf/tests/shell/script.sh | 3 +- tools/perf/tests/shell/stat+json_output.sh | 16 +- tools/perf/tests/shell/stat_all_pmu.sh | 2 +- tools/perf/tests/shell/stat_metrics_values.sh | 14 +- tools/perf/tests/shell/test_arm_callgraph_fp.sh | 6 + tools/perf/tests/shell/test_brstack.sh | 6 + tools/perf/tests/shell/test_data_symbol.sh | 16 +- .../tests/shell/test_perf_data_converter_json.sh | 13 +- tools/perf/tests/sigtrap.c | 106 +- tools/perf/tests/sw-clock.c | 2 +- tools/perf/tests/switch-tracking.c | 2 +- tools/perf/tests/task-exit.c | 2 +- tools/perf/tests/tests.h | 1 + tools/perf/tests/topology.c | 2 +- tools/perf/tests/vmlinux-kallsyms.c | 181 +- tools/perf/trace/beauty/arch_errno_names.sh | 10 +- tools/perf/trace/beauty/beauty.h | 2 - tools/perf/trace/beauty/prctl_option.sh | 4 +- tools/perf/trace/beauty/socket.sh | 4 +- tools/perf/trace/beauty/statx.c | 1 + tools/perf/ui/browsers/annotate.c | 106 +- tools/perf/ui/browsers/hists.c | 36 +- tools/perf/ui/browsers/hists.h | 2 - tools/perf/ui/browsers/scripts.c | 1 + tools/perf/ui/gtk/annotate.c | 6 +- tools/perf/ui/gtk/gtk.h | 2 - tools/perf/ui/tui/setup.c | 22 + tools/perf/util/Build | 2 + tools/perf/util/annotate-data.c | 405 ++ tools/perf/util/annotate-data.h | 143 + tools/perf/util/annotate.c | 690 +- tools/perf/util/annotate.h | 144 +- tools/perf/util/auxtrace.c | 7 +- tools/perf/util/auxtrace.h | 3 + tools/perf/util/block-info.c | 10 +- tools/perf/util/block-info.h | 3 +- tools/perf/util/block-range.c | 7 +- tools/perf/util/bpf-event.c | 3 + tools/perf/util/bpf_counter.c | 2 +- tools/perf/util/bpf_lock_contention.c | 2 +- tools/perf/util/bpf_skel/lock_contention.bpf.c | 5 +- tools/perf/util/compress.h | 7 +- tools/perf/util/cpumap.c | 2 +- tools/perf/util/cputopo.c | 2 +- tools/perf/util/cs-etm.c | 21 +- tools/perf/util/debug.c | 22 +- tools/perf/util/debug.h | 1 + tools/perf/util/debuginfo.c | 205 + tools/perf/util/debuginfo.h | 64 + tools/perf/util/dso.c | 4 + tools/perf/util/dso.h | 2 + tools/perf/util/dwarf-aux.c | 249 +- tools/perf/util/dwarf-aux.h | 51 +- tools/perf/util/dwarf-regs.c | 34 + tools/perf/util/env.c | 32 + tools/perf/util/env.h | 13 + tools/perf/util/event.c | 4 +- tools/perf/util/evlist.c | 19 +- tools/perf/util/evsel.c | 55 +- tools/perf/util/evsel.h | 4 +- tools/perf/util/header.c | 26 +- tools/perf/util/hist.c | 4 +- tools/perf/util/hist.h | 28 +- tools/perf/util/include/dwarf-regs.h | 19 + tools/perf/util/include/linux/linkage.h | 4 + tools/perf/util/machine.c | 75 +- tools/perf/util/map.c | 20 +- tools/perf/util/map.h | 83 +- tools/perf/util/maps.c | 528 +- tools/perf/util/maps.h | 48 +- tools/perf/util/metricgroup.c | 2 +- tools/perf/util/mmap.c | 5 +- tools/perf/util/mmap.h | 1 - tools/perf/util/parse-branch-options.c | 1 + tools/perf/util/parse-events.c | 52 +- tools/perf/util/perf_api_probe.c | 4 +- tools/perf/util/perf_event_attr_fprintf.c | 1 + tools/perf/util/pmu.c | 8 +- tools/perf/util/pmu.h | 3 +- tools/perf/util/print-events.c | 2 +- tools/perf/util/probe-event.c | 40 +- tools/perf/util/probe-finder.c | 201 +- tools/perf/util/probe-finder.h | 19 +- tools/perf/util/record.c | 4 +- tools/perf/util/s390-cpumcf-kernel.h | 2 + tools/perf/util/s390-sample-raw.c | 114 +- tools/perf/util/sample.h | 1 + .../perf/util/scripting-engines/trace-event-perl.c | 3 + .../util/scripting-engines/trace-event-python.c | 17 +- tools/perf/util/session.c | 20 +- tools/perf/util/sort.c | 216 +- tools/perf/util/sort.h | 7 + tools/perf/util/stat-display.c | 2 +- tools/perf/util/stat.c | 4 +- tools/perf/util/stat.h | 1 - tools/perf/util/symbol-elf.c | 6 +- tools/perf/util/symbol-minimal.c | 10 +- tools/perf/util/symbol.c | 306 +- tools/perf/util/symbol.h | 1 - tools/perf/util/symbol_conf.h | 6 +- tools/perf/util/synthetic-events.c | 122 +- tools/perf/util/thread.c | 42 +- tools/perf/util/thread.h | 14 + tools/perf/util/top.c | 9 +- tools/perf/util/top.h | 1 - tools/perf/util/unwind-libunwind-local.c | 34 +- tools/perf/util/vdso.c | 35 +- tools/perf/util/zstd.c | 63 +- tools/power/cpupower/bench/Makefile | 2 +- .../x86_energy_perf_policy.c | 1 + tools/testing/cxl/Kbuild | 4 + tools/testing/cxl/test/Kbuild | 2 + tools/testing/cxl/test/cxl.c | 67 +- tools/testing/cxl/test/mem.c | 163 +- tools/testing/cxl/test/mock.c | 14 + tools/testing/cxl/test/mock.h | 1 + tools/testing/ktest/ktest.pl | 1 + tools/testing/kunit/kunit_tool_test.py | 16 + .../kunit/test_data/test_parse_attributes.log | 9 + tools/testing/memblock/linux/mmzone.h | 6 +- tools/testing/nvdimm/Kbuild | 2 + tools/testing/nvdimm/test/Kbuild | 1 + tools/testing/radix-tree/linux.c | 45 +- tools/testing/radix-tree/linux/maple_tree.h | 2 +- tools/testing/radix-tree/maple.c | 396 +- tools/testing/selftests/Makefile | 4 + tools/testing/selftests/alsa/mixer-test.c | 2 +- tools/testing/selftests/arm64/abi/tpidr2.c | 18 +- tools/testing/selftests/arm64/fp/sve-test.S | 10 + tools/testing/selftests/arm64/fp/vec-syscfg.c | 14 +- tools/testing/selftests/arm64/fp/za-test.S | 6 + tools/testing/selftests/arm64/fp/zt-test.S | 5 + tools/testing/selftests/bpf/Makefile | 15 +- tools/testing/selftests/bpf/README.rst | 2 +- .../testing/selftests/bpf/benchs/bench_htab_mem.c | 1 + tools/testing/selftests/bpf/bpf_experimental.h | 220 +- tools/testing/selftests/bpf/bpf_kfuncs.h | 10 + tools/testing/selftests/bpf/cgroup_helpers.c | 114 +- tools/testing/selftests/bpf/cgroup_helpers.h | 5 +- tools/testing/selftests/bpf/config | 3 +- tools/testing/selftests/bpf/config.aarch64 | 18 +- tools/testing/selftests/bpf/config.s390x | 10 - tools/testing/selftests/bpf/config.vm | 12 + tools/testing/selftests/bpf/config.x86_64 | 13 - .../selftests/bpf/map_tests/map_percpu_stats.c | 39 +- tools/testing/selftests/bpf/network_helpers.h | 43 + tools/testing/selftests/bpf/prog_tests/align.c | 42 +- tools/testing/selftests/bpf/prog_tests/bind_perm.c | 6 +- tools/testing/selftests/bpf/prog_tests/bpf_iter.c | 85 +- .../testing/selftests/bpf/prog_tests/bpf_obj_id.c | 204 +- .../testing/selftests/bpf/prog_tests/bpf_tcp_ca.c | 48 +- .../selftests/bpf/prog_tests/bpf_verif_scale.c | 2 +- .../selftests/bpf/prog_tests/cgroup1_hierarchy.c | 158 + .../testing/selftests/bpf/prog_tests/cgroup_v1v2.c | 2 +- .../selftests/bpf/prog_tests/cgrp_local_storage.c | 98 +- tools/testing/selftests/bpf/prog_tests/cpumask.c | 1 + .../selftests/bpf/prog_tests/fexit_bpf2bpf.c | 30 +- .../selftests/bpf/prog_tests/fill_link_info.c | 242 +- tools/testing/selftests/bpf/prog_tests/fs_kfuncs.c | 142 + .../bpf/prog_tests/global_func_dead_code.c | 60 + tools/testing/selftests/bpf/prog_tests/iters.c | 1 + .../selftests/bpf/prog_tests/kprobe_multi_test.c | 31 +- .../testing/selftests/bpf/prog_tests/libbpf_str.c | 2 +- .../selftests/bpf/prog_tests/local_kptr_stash.c | 56 + tools/testing/selftests/bpf/prog_tests/log_buf.c | 4 +- tools/testing/selftests/bpf/prog_tests/log_fixup.c | 4 +- tools/testing/selftests/bpf/prog_tests/map_btf.c | 98 + .../testing/selftests/bpf/prog_tests/map_in_map.c | 141 + .../selftests/bpf/prog_tests/read_vsyscall.c | 57 + .../selftests/bpf/prog_tests/recursive_attach.c | 151 + .../testing/selftests/bpf/prog_tests/reg_bounds.c | 2131 ++++++ .../selftests/bpf/prog_tests/sock_iter_batch.c | 135 + .../selftests/bpf/prog_tests/sockmap_basic.c | 214 +- tools/testing/selftests/bpf/prog_tests/spin_lock.c | 14 +- tools/testing/selftests/bpf/prog_tests/syscall.c | 30 +- .../testing/selftests/bpf/prog_tests/test_bpf_ma.c | 20 +- .../selftests/bpf/prog_tests/test_global_funcs.c | 119 + .../testing/selftests/bpf/prog_tests/test_tunnel.c | 162 +- tools/testing/selftests/bpf/prog_tests/timer.c | 35 +- .../selftests/bpf/prog_tests/uprobe_multi_test.c | 177 +- tools/testing/selftests/bpf/prog_tests/verifier.c | 6 + .../selftests/bpf/prog_tests/verify_pkcs7_sig.c | 165 +- tools/testing/selftests/bpf/prog_tests/vmlinux.c | 16 +- .../bpf/prog_tests/xdp_context_test_run.c | 4 +- .../selftests/bpf/prog_tests/xdp_metadata.c | 165 +- .../selftests/bpf/progs/access_map_in_map.c | 93 + .../bpf/progs/bpf_iter_bpf_percpu_hash_map.c | 2 +- .../selftests/bpf/progs/bpf_iter_task_vmas.c | 2 +- tools/testing/selftests/bpf/progs/bpf_iter_tasks.c | 2 +- .../selftests/bpf/progs/bpf_iter_test_kern4.c | 2 +- tools/testing/selftests/bpf/progs/bpf_misc.h | 1 + .../testing/selftests/bpf/progs/bpf_tracing_net.h | 4 + .../bpf/progs/cgroup_getset_retval_setsockopt.c | 2 +- .../selftests/bpf/progs/cgrp_kfunc_failure.c | 2 +- .../selftests/bpf/progs/cgrp_ls_recursion.c | 84 +- .../selftests/bpf/progs/cgrp_ls_sleepable.c | 63 +- tools/testing/selftests/bpf/progs/cgrp_ls_tp_btf.c | 82 +- tools/testing/selftests/bpf/progs/cpumask_common.h | 1 + .../testing/selftests/bpf/progs/cpumask_success.c | 45 +- tools/testing/selftests/bpf/progs/exceptions.c | 20 +- .../selftests/bpf/progs/exceptions_assert.c | 92 +- .../testing/selftests/bpf/progs/exceptions_fail.c | 2 +- .../testing/selftests/bpf/progs/fentry_recursive.c | 14 + .../selftests/bpf/progs/fentry_recursive_target.c | 25 + .../bpf/progs/freplace_dead_global_func.c | 11 + .../selftests/bpf/progs/freplace_unreliable_prog.c | 20 + tools/testing/selftests/bpf/progs/iters.c | 26 +- tools/testing/selftests/bpf/progs/iters_task.c | 12 +- tools/testing/selftests/bpf/progs/iters_task_vma.c | 3 +- tools/testing/selftests/bpf/progs/linked_funcs1.c | 2 +- tools/testing/selftests/bpf/progs/linked_funcs2.c | 2 +- tools/testing/selftests/bpf/progs/linked_list.c | 2 +- .../testing/selftests/bpf/progs/local_kptr_stash.c | 124 + tools/testing/selftests/bpf/progs/local_storage.c | 2 +- tools/testing/selftests/bpf/progs/lsm.c | 2 +- tools/testing/selftests/bpf/progs/map_in_map_btf.c | 73 + tools/testing/selftests/bpf/progs/normal_map_btf.c | 56 + .../selftests/bpf/progs/percpu_alloc_fail.c | 18 + tools/testing/selftests/bpf/progs/profiler.inc.h | 68 +- tools/testing/selftests/bpf/progs/read_vsyscall.c | 45 + .../selftests/bpf/progs/refcounted_kptr_fail.c | 19 + .../testing/selftests/bpf/progs/sock_iter_batch.c | 91 + .../testing/selftests/bpf/progs/sockopt_inherit.c | 2 +- tools/testing/selftests/bpf/progs/sockopt_multi.c | 2 +- .../selftests/bpf/progs/sockopt_qos_to_cc.c | 2 +- tools/testing/selftests/bpf/progs/syscall.c | 96 +- .../selftests/bpf/progs/task_kfunc_failure.c | 2 +- tools/testing/selftests/bpf/progs/test_bpf_ma.c | 92 +- .../selftests/bpf/progs/test_cgroup1_hierarchy.c | 71 + .../selftests/bpf/progs/test_core_reloc_kernel.c | 2 +- .../selftests/bpf/progs/test_core_reloc_module.c | 8 +- .../selftests/bpf/progs/test_fill_link_info.c | 6 + tools/testing/selftests/bpf/progs/test_fsverity.c | 48 + tools/testing/selftests/bpf/progs/test_get_xattr.c | 37 + .../selftests/bpf/progs/test_global_func12.c | 4 +- .../selftests/bpf/progs/test_global_func15.c | 34 +- .../selftests/bpf/progs/test_global_func5.c | 2 +- .../bpf/progs/test_global_func_ctx_args.c | 49 + tools/testing/selftests/bpf/progs/test_jhash.h | 31 + .../selftests/bpf/progs/test_sig_in_xattr.c | 83 + .../selftests/bpf/progs/test_skc_to_unix_sock.c | 2 +- .../testing/selftests/bpf/progs/test_tunnel_kern.c | 138 +- .../selftests/bpf/progs/test_verify_pkcs7_sig.c | 8 +- .../selftests/bpf/progs/test_xdp_do_redirect.c | 2 +- tools/testing/selftests/bpf/progs/timer.c | 34 +- tools/testing/selftests/bpf/progs/timer_failure.c | 37 +- .../selftests/bpf/progs/user_ringbuf_fail.c | 2 +- .../selftests/bpf/progs/verifier_bitfield_write.c | 100 + .../testing/selftests/bpf/progs/verifier_bounds.c | 64 + .../bpf/progs/verifier_btf_unreliable_prog.c | 20 + .../bpf/progs/verifier_cgroup_inv_retcode.c | 8 +- .../bpf/progs/verifier_direct_packet_access.c | 2 +- .../selftests/bpf/progs/verifier_global_subprogs.c | 350 + tools/testing/selftests/bpf/progs/verifier_gotol.c | 19 + .../bpf/progs/verifier_helper_value_access.c | 45 +- .../testing/selftests/bpf/progs/verifier_int_ptr.c | 2 +- .../bpf/progs/verifier_iterating_callbacks.c | 70 + .../bpf/progs/verifier_netfilter_retcode.c | 2 +- .../selftests/bpf/progs/verifier_raw_stack.c | 2 +- .../selftests/bpf/progs/verifier_spill_fill.c | 287 + .../selftests/bpf/progs/verifier_stack_ptr.c | 4 +- .../bpf/progs/verifier_subprog_precision.c | 141 +- .../bpf/progs/verifier_value_illegal_alu.c | 19 + .../testing/selftests/bpf/progs/verifier_var_off.c | 29 + .../testing/selftests/bpf/progs/xdp_hw_metadata.c | 38 +- tools/testing/selftests/bpf/progs/xdp_metadata.c | 36 +- tools/testing/selftests/bpf/test_loader.c | 44 +- tools/testing/selftests/bpf/test_maps.c | 17 +- tools/testing/selftests/bpf/test_maps.h | 5 + tools/testing/selftests/bpf/test_offload.py | 15 +- tools/testing/selftests/bpf/test_sock_addr.c | 2 +- tools/testing/selftests/bpf/test_tunnel.sh | 92 - tools/testing/selftests/bpf/test_verifier.c | 2 +- tools/testing/selftests/bpf/testing_helpers.c | 4 +- tools/testing/selftests/bpf/testing_helpers.h | 3 + tools/testing/selftests/bpf/verifier/precise.c | 38 +- tools/testing/selftests/bpf/verify_sig_setup.sh | 25 + tools/testing/selftests/bpf/veristat.c | 89 +- tools/testing/selftests/bpf/vmtest.sh | 4 +- tools/testing/selftests/bpf/xdp_hw_metadata.c | 265 +- tools/testing/selftests/bpf/xdp_metadata.h | 34 +- tools/testing/selftests/bpf/xsk.c | 3 + tools/testing/selftests/bpf/xsk.h | 1 + .../selftests/breakpoints/breakpoint_test.c | 4 +- .../breakpoints/step_after_suspend_test.c | 2 +- tools/testing/selftests/capabilities/test_execve.c | 6 +- tools/testing/selftests/cgroup/test_cpuset_prs.sh | 222 +- tools/testing/selftests/cgroup/test_freezer.c | 2 +- tools/testing/selftests/cgroup/test_zswap.c | 74 +- tools/testing/selftests/damon/Makefile | 3 + tools/testing/selftests/damon/_damon_sysfs.py | 322 + tools/testing/selftests/damon/access_memory.c | 41 + tools/testing/selftests/damon/sysfs.sh | 27 + .../sysfs_update_schemes_tried_regions_hang.py | 33 + ..._update_schemes_tried_regions_wss_estimation.py | 55 + tools/testing/selftests/drivers/net/bonding/config | 8 + .../selftests/drivers/net/mlxsw/pci_reset.sh | 58 + .../testing/selftests/drivers/net/mlxsw/qos_pfc.sh | 1 - .../testing/selftests/drivers/net/netdevsim/config | 10 + .../drivers/net/netdevsim/ethtool-common.sh | 1 + .../selftests/drivers/net/netdevsim/ethtool-fec.sh | 18 +- .../drivers/net/netdevsim/udp_tunnel_nic.sh | 1 + .../selftests/filesystems/overlayfs/.gitignore | 2 + .../selftests/filesystems/overlayfs/Makefile | 7 + .../selftests/filesystems/overlayfs/dev_in_maps.c | 182 + .../testing/selftests/filesystems/overlayfs/log.h | 26 + .../selftests/filesystems/statmount/.gitignore | 2 + .../selftests/filesystems/statmount/Makefile | 6 + .../filesystems/statmount/statmount_test.c | 612 ++ .../test.d/00basic/ringbuffer_subbuf_size.tc | 95 + .../ftrace/test.d/00basic/test_ownership.tc | 114 + .../ftrace/test.d/00basic/trace_marker.tc | 82 + .../ftrace/test.d/event/subsystem-enable.tc | 6 +- tools/testing/selftests/hid/config | 1 - tools/testing/selftests/hid/tests/base.py | 7 +- tools/testing/selftests/hid/tests/test_mouse.py | 14 +- tools/testing/selftests/hid/tests/test_tablet.py | 764 ++- .../selftests/hid/tests/test_wacom_generic.py | 282 +- tools/testing/selftests/hid/vmtest.sh | 46 +- tools/testing/selftests/iommu/config | 2 + tools/testing/selftests/iommu/iommufd.c | 230 +- tools/testing/selftests/iommu/iommufd_utils.h | 94 +- tools/testing/selftests/kselftest.h | 33 +- tools/testing/selftests/kselftest/runner.sh | 38 +- tools/testing/selftests/kvm/Makefile | 9 +- tools/testing/selftests/kvm/aarch64/arch_timer.c | 12 +- tools/testing/selftests/kvm/aarch64/hypercalls.c | 16 +- .../selftests/kvm/aarch64/page_fault_test.c | 8 +- tools/testing/selftests/kvm/aarch64/smccc_filter.c | 2 +- .../selftests/kvm/aarch64/vpmu_counter_access.c | 17 +- tools/testing/selftests/kvm/demand_paging_test.c | 4 +- tools/testing/selftests/kvm/dirty_log_perf_test.c | 4 +- tools/testing/selftests/kvm/dirty_log_test.c | 56 +- tools/testing/selftests/kvm/get-reg-list.c | 2 +- tools/testing/selftests/kvm/guest_memfd_test.c | 198 + tools/testing/selftests/kvm/guest_print_test.c | 8 +- .../testing/selftests/kvm/hardware_disable_test.c | 6 +- .../selftests/kvm/include/aarch64/processor.h | 4 +- tools/testing/selftests/kvm/include/guest_modes.h | 4 +- .../testing/selftests/kvm/include/kvm_util_base.h | 217 +- .../selftests/kvm/include/riscv/processor.h | 62 +- tools/testing/selftests/kvm/include/test_util.h | 9 +- tools/testing/selftests/kvm/include/ucall_common.h | 18 +- .../selftests/kvm/include/x86_64/processor.h | 17 + tools/testing/selftests/kvm/kvm_create_max_vcpus.c | 2 +- tools/testing/selftests/kvm/kvm_page_table_test.c | 6 +- .../testing/selftests/kvm/lib/aarch64/processor.c | 71 +- tools/testing/selftests/kvm/lib/aarch64/vgic.c | 4 +- tools/testing/selftests/kvm/lib/elf.c | 2 +- tools/testing/selftests/kvm/lib/guest_modes.c | 50 +- tools/testing/selftests/kvm/lib/kvm_util.c | 244 +- tools/testing/selftests/kvm/lib/memstress.c | 5 +- tools/testing/selftests/kvm/lib/riscv/processor.c | 51 +- tools/testing/selftests/kvm/lib/riscv/ucall.c | 26 - tools/testing/selftests/kvm/lib/s390x/processor.c | 2 +- tools/testing/selftests/kvm/lib/test_util.c | 25 + tools/testing/selftests/kvm/lib/userfaultfd_util.c | 2 +- tools/testing/selftests/kvm/lib/x86_64/processor.c | 21 +- tools/testing/selftests/kvm/lib/x86_64/vmx.c | 6 +- .../kvm/memslot_modification_stress_test.c | 2 +- tools/testing/selftests/kvm/memslot_perf_test.c | 6 +- tools/testing/selftests/kvm/riscv/get-reg-list.c | 698 +- tools/testing/selftests/kvm/rseq_test.c | 4 +- tools/testing/selftests/kvm/s390x/cmma_test.c | 11 +- tools/testing/selftests/kvm/s390x/resets.c | 4 +- tools/testing/selftests/kvm/s390x/sync_regs_test.c | 20 +- .../testing/selftests/kvm/set_memory_region_test.c | 177 +- tools/testing/selftests/kvm/steal_time.c | 99 + .../selftests/kvm/system_counter_offset_test.c | 2 +- tools/testing/selftests/kvm/x86_64/amx_test.c | 6 +- tools/testing/selftests/kvm/x86_64/cpuid_test.c | 4 +- .../kvm/x86_64/dirty_log_page_splitting_test.c | 21 +- .../testing/selftests/kvm/x86_64/flds_emulation.h | 2 +- tools/testing/selftests/kvm/x86_64/hyperv_clock.c | 7 +- tools/testing/selftests/kvm/x86_64/hyperv_evmcs.c | 5 +- .../kvm/x86_64/hyperv_extended_hypercalls.c | 2 + .../testing/selftests/kvm/x86_64/hyperv_features.c | 21 +- tools/testing/selftests/kvm/x86_64/hyperv_ipi.c | 4 +- .../testing/selftests/kvm/x86_64/hyperv_svm_test.c | 1 + .../selftests/kvm/x86_64/hyperv_tlb_flush.c | 4 +- .../testing/selftests/kvm/x86_64/kvm_clock_test.c | 42 +- .../selftests/kvm/x86_64/mmio_warning_test.c | 121 - .../selftests/kvm/x86_64/monitor_mwait_test.c | 6 +- .../selftests/kvm/x86_64/nx_huge_pages_test.c | 6 +- .../selftests/kvm/x86_64/platform_info_test.c | 2 +- .../selftests/kvm/x86_64/pmu_event_filter_test.c | 2 +- .../kvm/x86_64/private_mem_conversions_test.c | 482 ++ .../kvm/x86_64/private_mem_kvm_exits_test.c | 120 + .../selftests/kvm/x86_64/sev_migrate_tests.c | 28 +- .../kvm/x86_64/smaller_maxphyaddr_emulation_test.c | 4 +- .../kvm/x86_64/svm_nested_soft_inject_test.c | 4 +- .../testing/selftests/kvm/x86_64/sync_regs_test.c | 10 +- .../selftests/kvm/x86_64/ucna_injection_test.c | 10 +- .../selftests/kvm/x86_64/userspace_io_test.c | 2 +- .../selftests/kvm/x86_64/vmx_apic_access_test.c | 2 +- .../selftests/kvm/x86_64/vmx_dirty_log_test.c | 16 +- .../vmx_exception_with_invalid_guest_state.c | 2 +- .../kvm/x86_64/vmx_nested_tsc_scaling_test.c | 19 +- .../selftests/kvm/x86_64/vmx_pmu_caps_test.c | 2 +- .../kvm/x86_64/vmx_set_nested_state_test.c | 16 +- .../testing/selftests/kvm/x86_64/xapic_ipi_test.c | 8 +- .../testing/selftests/kvm/x86_64/xcr0_cpuid_test.c | 10 +- tools/testing/selftests/kvm/x86_64/xss_msr_test.c | 2 +- tools/testing/selftests/landlock/fs_test.c | 80 +- tools/testing/selftests/landlock/net_test.c | 59 +- tools/testing/selftests/livepatch/functions.sh | 37 +- tools/testing/selftests/lsm/.gitignore | 1 + tools/testing/selftests/lsm/Makefile | 17 + tools/testing/selftests/lsm/common.c | 89 + tools/testing/selftests/lsm/common.h | 33 + tools/testing/selftests/lsm/config | 3 + .../testing/selftests/lsm/lsm_get_self_attr_test.c | 275 + .../testing/selftests/lsm/lsm_list_modules_test.c | 137 + .../testing/selftests/lsm/lsm_set_self_attr_test.c | 74 + tools/testing/selftests/mm/Makefile | 4 +- tools/testing/selftests/mm/compaction_test.c | 91 +- tools/testing/selftests/mm/cow.c | 183 +- tools/testing/selftests/mm/hugepage-mmap.c | 23 +- tools/testing/selftests/mm/hugepage-mremap.c | 87 +- tools/testing/selftests/mm/khugepaged.c | 410 +- tools/testing/selftests/mm/mremap_test.c | 27 +- tools/testing/selftests/mm/run_vmtests.sh | 55 +- tools/testing/selftests/mm/thp_settings.c | 349 + tools/testing/selftests/mm/thp_settings.h | 80 + tools/testing/selftests/mm/thuge-gen.c | 3 +- tools/testing/selftests/mm/uffd-common.c | 39 +- tools/testing/selftests/mm/uffd-common.h | 9 + tools/testing/selftests/mm/uffd-stress.c | 5 +- tools/testing/selftests/mm/uffd-unit-tests.c | 209 + tools/testing/selftests/mm/vm_util.c | 80 +- tools/testing/selftests/mm/vm_util.h | 2 +- tools/testing/selftests/net/Makefile | 5 +- .../selftests/net/arp_ndisc_evict_nocarrier.sh | 46 +- .../selftests/net/arp_ndisc_untracked_subnets.sh | 18 +- tools/testing/selftests/net/cmsg_ipv6.sh | 10 +- tools/testing/selftests/net/cmsg_sender.c | 50 +- tools/testing/selftests/net/cmsg_so_mark.sh | 7 +- tools/testing/selftests/net/cmsg_time.sh | 7 +- tools/testing/selftests/net/config | 6 +- tools/testing/selftests/net/drop_monitor_tests.sh | 21 +- tools/testing/selftests/net/fcnal-test.sh | 30 +- tools/testing/selftests/net/fdb_flush.sh | 11 +- tools/testing/selftests/net/fib-onlink-tests.sh | 9 +- .../selftests/net/fib_nexthop_multiprefix.sh | 98 +- tools/testing/selftests/net/fib_nexthop_nongw.sh | 34 +- tools/testing/selftests/net/fib_nexthops.sh | 142 +- tools/testing/selftests/net/fib_rule_tests.sh | 36 +- tools/testing/selftests/net/fib_tests.sh | 184 +- tools/testing/selftests/net/forwarding/Makefile | 3 +- .../testing/selftests/net/forwarding/bridge_mdb.sh | 191 +- .../testing/selftests/net/forwarding/ethtool_mm.sh | 48 +- .../selftests/net/forwarding/ethtool_rmon.sh | 143 + tools/testing/selftests/net/forwarding/lib.sh | 70 +- tools/testing/selftests/net/fq_band_pktlimit.sh | 57 + tools/testing/selftests/net/gre_gso.sh | 18 +- tools/testing/selftests/net/gro.c | 93 +- tools/testing/selftests/net/gro.sh | 9 +- tools/testing/selftests/net/icmp.sh | 10 +- tools/testing/selftests/net/icmp_redirect.sh | 182 +- .../testing/selftests/net/io_uring_zerocopy_tx.sh | 9 +- tools/testing/selftests/net/ioam6.sh | 281 +- tools/testing/selftests/net/ioam6_parser.c | 95 +- tools/testing/selftests/net/ip_local_port_range.c | 16 + tools/testing/selftests/net/l2tp.sh | 130 +- tools/testing/selftests/net/lib.sh | 96 + tools/testing/selftests/net/mptcp/diag.sh | 50 +- tools/testing/selftests/net/mptcp/mptcp_connect.sh | 187 +- tools/testing/selftests/net/mptcp/mptcp_join.sh | 183 +- tools/testing/selftests/net/mptcp/mptcp_lib.sh | 51 + tools/testing/selftests/net/mptcp/mptcp_sockopt.sh | 31 +- tools/testing/selftests/net/mptcp/simult_flows.sh | 19 +- tools/testing/selftests/net/mptcp/userspace_pm.sh | 12 +- tools/testing/selftests/net/msg_zerocopy.sh | 9 +- .../selftests/net/ndisc_unsolicited_na_test.sh | 19 +- tools/testing/selftests/net/net_helper.sh | 25 + tools/testing/selftests/net/netns-name.sh | 44 +- tools/testing/selftests/net/pmtu.sh | 4 +- tools/testing/selftests/net/reuseaddr_conflict.c | 2 +- tools/testing/selftests/net/rtnetlink.sh | 66 +- tools/testing/selftests/net/sctp_vrf.sh | 12 +- tools/testing/selftests/net/settings | 2 +- tools/testing/selftests/net/setup_loopback.sh | 8 +- tools/testing/selftests/net/setup_veth.sh | 9 +- tools/testing/selftests/net/so_txtime.sh | 29 +- .../selftests/net/srv6_end_dt46_l3vpn_test.sh | 51 +- .../selftests/net/srv6_end_dt4_l3vpn_test.sh | 48 +- .../selftests/net/srv6_end_dt6_l3vpn_test.sh | 46 +- .../selftests/net/stress_reuseport_listen.sh | 6 +- tools/testing/selftests/net/tcp_ao/.gitignore | 2 + tools/testing/selftests/net/tcp_ao/Makefile | 56 + tools/testing/selftests/net/tcp_ao/bench-lookups.c | 360 + tools/testing/selftests/net/tcp_ao/config | 10 + tools/testing/selftests/net/tcp_ao/connect-deny.c | 264 + tools/testing/selftests/net/tcp_ao/connect.c | 90 + tools/testing/selftests/net/tcp_ao/icmps-accept.c | 1 + tools/testing/selftests/net/tcp_ao/icmps-discard.c | 449 ++ .../testing/selftests/net/tcp_ao/key-management.c | 1186 ++++ tools/testing/selftests/net/tcp_ao/lib/aolib.h | 605 ++ tools/testing/selftests/net/tcp_ao/lib/kconfig.c | 148 + tools/testing/selftests/net/tcp_ao/lib/netlink.c | 413 ++ tools/testing/selftests/net/tcp_ao/lib/proc.c | 273 + tools/testing/selftests/net/tcp_ao/lib/repair.c | 254 + tools/testing/selftests/net/tcp_ao/lib/setup.c | 361 + tools/testing/selftests/net/tcp_ao/lib/sock.c | 596 ++ tools/testing/selftests/net/tcp_ao/lib/utils.c | 30 + tools/testing/selftests/net/tcp_ao/restore.c | 236 + tools/testing/selftests/net/tcp_ao/rst.c | 460 ++ tools/testing/selftests/net/tcp_ao/self-connect.c | 197 + tools/testing/selftests/net/tcp_ao/seq-ext.c | 245 + .../selftests/net/tcp_ao/setsockopt-closed.c | 835 +++ tools/testing/selftests/net/tcp_ao/settings | 1 + tools/testing/selftests/net/tcp_ao/unsigned-md5.c | 741 +++ .../selftests/net/test_bridge_neigh_suppress.sh | 331 +- tools/testing/selftests/net/test_vxlan_mdb.sh | 608 +- .../selftests/net/test_vxlan_nolocalbypass.sh | 48 +- .../testing/selftests/net/test_vxlan_under_vrf.sh | 70 +- .../selftests/net/test_vxlan_vnifiltering.sh | 154 +- tools/testing/selftests/net/tls.c | 63 +- tools/testing/selftests/net/toeplitz.sh | 14 +- tools/testing/selftests/net/traceroute.sh | 82 +- tools/testing/selftests/net/udpgro.sh | 13 +- tools/testing/selftests/net/udpgro_bench.sh | 5 +- tools/testing/selftests/net/udpgro_frglist.sh | 5 +- tools/testing/selftests/net/udpgro_fwd.sh | 10 +- tools/testing/selftests/net/udpgso.c | 2 +- tools/testing/selftests/net/veth.sh | 14 + tools/testing/selftests/net/vrf-xfrm-tests.sh | 77 +- tools/testing/selftests/net/vrf_route_leaking.sh | 201 +- .../testing/selftests/net/vrf_strict_mode_test.sh | 47 +- tools/testing/selftests/net/xfrm_policy.sh | 138 +- tools/testing/selftests/netfilter/.gitignore | 2 + tools/testing/selftests/netfilter/Makefile | 6 +- .../selftests/netfilter/bridge_netfilter.sh | 188 + .../selftests/netfilter/conntrack_dump_flush.c | 471 ++ tools/testing/selftests/nolibc/.gitignore | 1 + tools/testing/selftests/nolibc/Makefile | 65 +- tools/testing/selftests/nolibc/nolibc-test.c | 47 +- tools/testing/selftests/nolibc/run-tests.sh | 169 + tools/testing/selftests/powerpc/Makefile | 2 + tools/testing/selftests/powerpc/math/fpu.h | 25 + tools/testing/selftests/powerpc/math/fpu_asm.S | 48 +- tools/testing/selftests/powerpc/math/fpu_preempt.c | 21 +- tools/testing/selftests/powerpc/math/fpu_signal.c | 16 +- tools/testing/selftests/powerpc/math/fpu_syscall.c | 8 +- .../selftests/powerpc/papr_sysparm/.gitignore | 1 + .../selftests/powerpc/papr_sysparm/Makefile | 12 + .../selftests/powerpc/papr_sysparm/papr_sysparm.c | 196 + .../testing/selftests/powerpc/papr_vpd/.gitignore | 1 + tools/testing/selftests/powerpc/papr_vpd/Makefile | 12 + .../testing/selftests/powerpc/papr_vpd/papr_vpd.c | 352 + tools/testing/selftests/prctl/set-process-name.c | 32 + tools/testing/selftests/rcutorture/bin/mkinitrd.sh | 5 +- .../selftests/rcutorture/configs/rcu/TREE07.boot | 3 + tools/testing/selftests/riscv/hwprobe/Makefile | 5 +- tools/testing/selftests/riscv/hwprobe/cbo.c | 2 +- tools/testing/selftests/riscv/hwprobe/hwprobe.c | 2 +- tools/testing/selftests/riscv/hwprobe/hwprobe.h | 12 +- tools/testing/selftests/riscv/hwprobe/which-cpus.c | 154 + .../selftests/riscv/vector/vstate_exec_nolibc.c | 3 + .../testing/selftests/riscv/vector/vstate_prctl.c | 10 +- .../testing/selftests/rseq/basic_percpu_ops_test.c | 14 +- tools/testing/selftests/rseq/param_test.c | 22 +- tools/testing/selftests/run_kselftest.sh | 10 +- tools/testing/selftests/sched/cs_prctl_test.c | 2 +- .../testing/selftests/seccomp/seccomp_benchmark.c | 104 +- tools/testing/selftests/seccomp/seccomp_bpf.c | 41 +- tools/testing/selftests/sgx/Makefile | 12 +- tools/testing/selftests/sgx/defines.h | 2 + tools/testing/selftests/sgx/test_encl.c | 59 +- tools/testing/selftests/sgx/test_encl.lds | 4 + tools/testing/selftests/sgx/test_encl_bootstrap.S | 28 +- tools/testing/selftests/sysctl/sysctl.sh | 146 +- tools/testing/selftests/tc-testing/Makefile | 29 +- tools/testing/selftests/tc-testing/README | 2 - tools/testing/selftests/tc-testing/config | 1 - .../tc-testing/plugin-lib/buildebpfPlugin.py | 67 - .../selftests/tc-testing/plugin-lib/nsPlugin.py | 210 +- .../selftests/tc-testing/tc-tests/actions/bpf.json | 14 +- .../selftests/tc-testing/tc-tests/actions/xt.json | 243 - .../selftests/tc-testing/tc-tests/filters/bpf.json | 10 +- .../tc-testing/tc-tests/filters/concurrency.json | 177 - .../tc-testing/tc-tests/filters/flower.json | 275 + .../tc-testing/tc-tests/filters/matchall.json | 23 + .../tc-testing/tc-tests/filters/tests.json | 129 - .../selftests/tc-testing/tc-tests/filters/u32.json | 57 + tools/testing/selftests/tc-testing/tdc.py | 14 +- tools/testing/selftests/tc-testing/tdc.sh | 68 +- tools/testing/selftests/timers/posix_timers.c | 105 +- tools/testing/selftests/vDSO/vdso_test_abi.c | 72 +- tools/testing/selftests/x86/lam.c | 4 +- tools/testing/vsock/vsock_test.c | 175 + tools/thermal/tmon/tui.c | 2 +- 807 files changed, 40911 insertions(+), 35109 deletions(-) create mode 100644 tools/build/feature/test-dwarf_getcfi.c delete mode 100644 tools/cgroup/Makefile delete mode 100644 tools/cgroup/cgroup_event_listener.c create mode 100644 tools/counter/counter_watch_events.c create mode 100755 tools/crypto/tcrypt/tcrypt_speed_compare.py create mode 100644 tools/net/ynl/generated/.gitignore delete mode 100644 tools/net/ynl/generated/devlink-user.c delete mode 100644 tools/net/ynl/generated/devlink-user.h delete mode 100644 tools/net/ynl/generated/ethtool-user.c delete mode 100644 tools/net/ynl/generated/ethtool-user.h delete mode 100644 tools/net/ynl/generated/fou-user.c delete mode 100644 tools/net/ynl/generated/fou-user.h delete mode 100644 tools/net/ynl/generated/handshake-user.c delete mode 100644 tools/net/ynl/generated/handshake-user.h delete mode 100644 tools/net/ynl/generated/netdev-user.c delete mode 100644 tools/net/ynl/generated/netdev-user.h delete mode 100644 tools/net/ynl/generated/nfsd-user.c delete mode 100644 tools/net/ynl/generated/nfsd-user.h create mode 100644 tools/net/ynl/lib/ynl-priv.h create mode 100644 tools/net/ynl/samples/page-pool.c create mode 100755 tools/net/ynl/ynl-gen-rst.py mode change 100644 => 100755 tools/perf/perf-archive.sh create mode 100644 tools/perf/pmu-events/arch/arm64/ampere/ampereonex/branch.json create mode 100644 tools/perf/pmu-events/arch/arm64/ampere/ampereonex/bus.json create mode 100644 tools/perf/pmu-events/arch/arm64/ampere/ampereonex/cache.json create mode 100644 tools/perf/pmu-events/arch/arm64/ampere/ampereonex/core-imp-def.json create mode 100644 tools/perf/pmu-events/arch/arm64/ampere/ampereonex/exception.json create mode 100644 tools/perf/pmu-events/arch/arm64/ampere/ampereonex/instruction.json create mode 100644 tools/perf/pmu-events/arch/arm64/ampere/ampereonex/intrinsic.json create mode 100644 tools/perf/pmu-events/arch/arm64/ampere/ampereonex/memory.json create mode 100644 tools/perf/pmu-events/arch/arm64/ampere/ampereonex/metrics.json create mode 100644 tools/perf/pmu-events/arch/arm64/ampere/ampereonex/mmu.json create mode 100644 tools/perf/pmu-events/arch/arm64/ampere/ampereonex/pipeline.json create mode 100644 tools/perf/pmu-events/arch/arm64/ampere/ampereonex/spe.json create mode 100644 tools/perf/pmu-events/arch/riscv/starfive/dubhe-80/common.json create mode 100644 tools/perf/pmu-events/arch/riscv/starfive/dubhe-80/firmware.json create mode 100644 tools/perf/pmu-events/arch/riscv/thead/c900-legacy/cache.json create mode 100644 tools/perf/pmu-events/arch/riscv/thead/c900-legacy/firmware.json create mode 100644 tools/perf/pmu-events/arch/riscv/thead/c900-legacy/instruction.json create mode 100644 tools/perf/pmu-events/arch/riscv/thead/c900-legacy/microarch.json create mode 100644 tools/perf/pmu-events/arch/x86/amdzen4/memory-controller.json create mode 100755 tools/perf/tests/shell/diff.sh create mode 100644 tools/perf/tests/shell/lib/perf_has_symbol.sh create mode 100644 tools/perf/tests/shell/lib/setup_python.sh create mode 100755 tools/perf/tests/shell/list.sh create mode 100644 tools/perf/util/annotate-data.c create mode 100644 tools/perf/util/annotate-data.h create mode 100644 tools/perf/util/debuginfo.c create mode 100644 tools/perf/util/debuginfo.h create mode 100644 tools/testing/kunit/test_data/test_parse_attributes.log create mode 100644 tools/testing/selftests/bpf/config.vm create mode 100644 tools/testing/selftests/bpf/prog_tests/cgroup1_hierarchy.c create mode 100644 tools/testing/selftests/bpf/prog_tests/fs_kfuncs.c create mode 100644 tools/testing/selftests/bpf/prog_tests/global_func_dead_code.c create mode 100644 tools/testing/selftests/bpf/prog_tests/map_btf.c create mode 100644 tools/testing/selftests/bpf/prog_tests/map_in_map.c create mode 100644 tools/testing/selftests/bpf/prog_tests/read_vsyscall.c create mode 100644 tools/testing/selftests/bpf/prog_tests/recursive_attach.c create mode 100644 tools/testing/selftests/bpf/prog_tests/reg_bounds.c create mode 100644 tools/testing/selftests/bpf/prog_tests/sock_iter_batch.c create mode 100644 tools/testing/selftests/bpf/progs/access_map_in_map.c create mode 100644 tools/testing/selftests/bpf/progs/fentry_recursive.c create mode 100644 tools/testing/selftests/bpf/progs/fentry_recursive_target.c create mode 100644 tools/testing/selftests/bpf/progs/freplace_dead_global_func.c create mode 100644 tools/testing/selftests/bpf/progs/freplace_unreliable_prog.c create mode 100644 tools/testing/selftests/bpf/progs/map_in_map_btf.c create mode 100644 tools/testing/selftests/bpf/progs/normal_map_btf.c create mode 100644 tools/testing/selftests/bpf/progs/read_vsyscall.c create mode 100644 tools/testing/selftests/bpf/progs/sock_iter_batch.c create mode 100644 tools/testing/selftests/bpf/progs/test_cgroup1_hierarchy.c create mode 100644 tools/testing/selftests/bpf/progs/test_fsverity.c create mode 100644 tools/testing/selftests/bpf/progs/test_get_xattr.c create mode 100644 tools/testing/selftests/bpf/progs/test_sig_in_xattr.c create mode 100644 tools/testing/selftests/bpf/progs/verifier_bitfield_write.c create mode 100644 tools/testing/selftests/bpf/progs/verifier_btf_unreliable_prog.c create mode 100644 tools/testing/selftests/bpf/progs/verifier_global_subprogs.c create mode 100644 tools/testing/selftests/damon/_damon_sysfs.py create mode 100644 tools/testing/selftests/damon/access_memory.c create mode 100644 tools/testing/selftests/damon/sysfs_update_schemes_tried_regions_hang.py create mode 100644 tools/testing/selftests/damon/sysfs_update_schemes_tried_regions_wss_estimation.py create mode 100755 tools/testing/selftests/drivers/net/mlxsw/pci_reset.sh create mode 100644 tools/testing/selftests/drivers/net/netdevsim/config create mode 100644 tools/testing/selftests/filesystems/overlayfs/.gitignore create mode 100644 tools/testing/selftests/filesystems/overlayfs/Makefile create mode 100644 tools/testing/selftests/filesystems/overlayfs/dev_in_maps.c create mode 100644 tools/testing/selftests/filesystems/overlayfs/log.h create mode 100644 tools/testing/selftests/filesystems/statmount/.gitignore create mode 100644 tools/testing/selftests/filesystems/statmount/Makefile create mode 100644 tools/testing/selftests/filesystems/statmount/statmount_test.c create mode 100644 tools/testing/selftests/ftrace/test.d/00basic/ringbuffer_subbuf_size.tc create mode 100644 tools/testing/selftests/ftrace/test.d/00basic/test_ownership.tc create mode 100644 tools/testing/selftests/ftrace/test.d/00basic/trace_marker.tc create mode 100644 tools/testing/selftests/kvm/guest_memfd_test.c delete mode 100644 tools/testing/selftests/kvm/x86_64/mmio_warning_test.c create mode 100644 tools/testing/selftests/kvm/x86_64/private_mem_conversions_test.c create mode 100644 tools/testing/selftests/kvm/x86_64/private_mem_kvm_exits_test.c create mode 100644 tools/testing/selftests/lsm/.gitignore create mode 100644 tools/testing/selftests/lsm/Makefile create mode 100644 tools/testing/selftests/lsm/common.c create mode 100644 tools/testing/selftests/lsm/common.h create mode 100644 tools/testing/selftests/lsm/config create mode 100644 tools/testing/selftests/lsm/lsm_get_self_attr_test.c create mode 100644 tools/testing/selftests/lsm/lsm_list_modules_test.c create mode 100644 tools/testing/selftests/lsm/lsm_set_self_attr_test.c create mode 100644 tools/testing/selftests/mm/thp_settings.c create mode 100644 tools/testing/selftests/mm/thp_settings.h create mode 100755 tools/testing/selftests/net/forwarding/ethtool_rmon.sh mode change 100755 => 100644 tools/testing/selftests/net/forwarding/lib.sh create mode 100755 tools/testing/selftests/net/fq_band_pktlimit.sh create mode 100644 tools/testing/selftests/net/lib.sh create mode 100644 tools/testing/selftests/net/net_helper.sh mode change 100755 => 100644 tools/testing/selftests/net/setup_loopback.sh create mode 100644 tools/testing/selftests/net/tcp_ao/.gitignore create mode 100644 tools/testing/selftests/net/tcp_ao/Makefile create mode 100644 tools/testing/selftests/net/tcp_ao/bench-lookups.c create mode 100644 tools/testing/selftests/net/tcp_ao/config create mode 100644 tools/testing/selftests/net/tcp_ao/connect-deny.c create mode 100644 tools/testing/selftests/net/tcp_ao/connect.c create mode 120000 tools/testing/selftests/net/tcp_ao/icmps-accept.c create mode 100644 tools/testing/selftests/net/tcp_ao/icmps-discard.c create mode 100644 tools/testing/selftests/net/tcp_ao/key-management.c create mode 100644 tools/testing/selftests/net/tcp_ao/lib/aolib.h create mode 100644 tools/testing/selftests/net/tcp_ao/lib/kconfig.c create mode 100644 tools/testing/selftests/net/tcp_ao/lib/netlink.c create mode 100644 tools/testing/selftests/net/tcp_ao/lib/proc.c create mode 100644 tools/testing/selftests/net/tcp_ao/lib/repair.c create mode 100644 tools/testing/selftests/net/tcp_ao/lib/setup.c create mode 100644 tools/testing/selftests/net/tcp_ao/lib/sock.c create mode 100644 tools/testing/selftests/net/tcp_ao/lib/utils.c create mode 100644 tools/testing/selftests/net/tcp_ao/restore.c create mode 100644 tools/testing/selftests/net/tcp_ao/rst.c create mode 100644 tools/testing/selftests/net/tcp_ao/self-connect.c create mode 100644 tools/testing/selftests/net/tcp_ao/seq-ext.c create mode 100644 tools/testing/selftests/net/tcp_ao/setsockopt-closed.c create mode 100644 tools/testing/selftests/net/tcp_ao/settings create mode 100644 tools/testing/selftests/net/tcp_ao/unsigned-md5.c create mode 100644 tools/testing/selftests/netfilter/bridge_netfilter.sh create mode 100644 tools/testing/selftests/netfilter/conntrack_dump_flush.c create mode 100755 tools/testing/selftests/nolibc/run-tests.sh create mode 100644 tools/testing/selftests/powerpc/math/fpu.h create mode 100644 tools/testing/selftests/powerpc/papr_sysparm/.gitignore create mode 100644 tools/testing/selftests/powerpc/papr_sysparm/Makefile create mode 100644 tools/testing/selftests/powerpc/papr_sysparm/papr_sysparm.c create mode 100644 tools/testing/selftests/powerpc/papr_vpd/.gitignore create mode 100644 tools/testing/selftests/powerpc/papr_vpd/Makefile create mode 100644 tools/testing/selftests/powerpc/papr_vpd/papr_vpd.c create mode 100644 tools/testing/selftests/riscv/hwprobe/which-cpus.c delete mode 100644 tools/testing/selftests/tc-testing/plugin-lib/buildebpfPlugin.py delete mode 100644 tools/testing/selftests/tc-testing/tc-tests/actions/xt.json delete mode 100644 tools/testing/selftests/tc-testing/tc-tests/filters/concurrency.json create mode 100644 tools/testing/selftests/tc-testing/tc-tests/filters/flower.json delete mode 100644 tools/testing/selftests/tc-testing/tc-tests/filters/tests.json (limited to 'tools') diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h index 4af140cf57..29cb275a21 100644 --- a/tools/arch/x86/include/asm/cpufeatures.h +++ b/tools/arch/x86/include/asm/cpufeatures.h @@ -198,6 +198,7 @@ #define X86_FEATURE_CAT_L3 ( 7*32+ 4) /* Cache Allocation Technology L3 */ #define X86_FEATURE_CAT_L2 ( 7*32+ 5) /* Cache Allocation Technology L2 */ #define X86_FEATURE_CDP_L3 ( 7*32+ 6) /* Code and Data Prioritization L3 */ +#define X86_FEATURE_TDX_HOST_PLATFORM ( 7*32+ 7) /* Platform supports being a TDX host */ #define X86_FEATURE_HW_PSTATE ( 7*32+ 8) /* AMD HW-PState */ #define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */ #define X86_FEATURE_XCOMPACTED ( 7*32+10) /* "" Use compacted XSTATE (XSAVES or XSAVEC) */ @@ -218,7 +219,7 @@ #define X86_FEATURE_IBRS ( 7*32+25) /* Indirect Branch Restricted Speculation */ #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 based on Zen microarchitecture */ +#define X86_FEATURE_ZEN ( 7*32+28) /* "" Generic flag for all Zen and newer */ #define X86_FEATURE_L1TF_PTEINV ( 7*32+29) /* "" L1TF workaround PTE inversion */ #define X86_FEATURE_IBRS_ENHANCED ( 7*32+30) /* Enhanced IBRS */ #define X86_FEATURE_MSR_IA32_FEAT_CTL ( 7*32+31) /* "" MSR IA32_FEAT_CTL configured */ @@ -308,10 +309,14 @@ #define X86_FEATURE_SMBA (11*32+21) /* "" Slow Memory Bandwidth Allocation */ #define X86_FEATURE_BMEC (11*32+22) /* "" Bandwidth Monitoring Event Configuration */ #define X86_FEATURE_USER_SHSTK (11*32+23) /* Shadow stack support for user mode applications */ - #define X86_FEATURE_SRSO (11*32+24) /* "" AMD BTB untrain RETs */ #define X86_FEATURE_SRSO_ALIAS (11*32+25) /* "" AMD BTB untrain RETs through aliasing */ #define X86_FEATURE_IBPB_ON_VMEXIT (11*32+26) /* "" Issue an IBPB only on VMEXIT */ +#define X86_FEATURE_APIC_MSRS_FENCE (11*32+27) /* "" IA32_TSC_DEADLINE and X2APIC MSRs need fencing */ +#define X86_FEATURE_ZEN2 (11*32+28) /* "" CPU based on Zen2 microarchitecture */ +#define X86_FEATURE_ZEN3 (11*32+29) /* "" CPU based on Zen3 microarchitecture */ +#define X86_FEATURE_ZEN4 (11*32+30) /* "" CPU based on Zen4 microarchitecture */ +#define X86_FEATURE_ZEN1 (11*32+31) /* "" CPU based on Zen1 microarchitecture */ /* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */ #define X86_FEATURE_AVX_VNNI (12*32+ 4) /* AVX VNNI instructions */ @@ -495,6 +500,7 @@ #define X86_BUG_EIBRS_PBRSB X86_BUG(28) /* EIBRS is vulnerable to Post Barrier RSB Predictions */ #define X86_BUG_SMT_RSB X86_BUG(29) /* CPU is vulnerable to Cross-Thread Return Address Predictions */ #define X86_BUG_GDS X86_BUG(30) /* CPU is affected by Gather Data Sampling */ +#define X86_BUG_TDX_PW_MCE X86_BUG(31) /* CPU may incur #MC if non-TD software does partial write to TDX private memory */ /* BUG word 2 */ #define X86_BUG_SRSO X86_BUG(1*32 + 0) /* AMD SRSO bug */ diff --git a/tools/arch/x86/include/asm/msr-index.h b/tools/arch/x86/include/asm/msr-index.h index 1d51e1850e..f1bd7b91b3 100644 --- a/tools/arch/x86/include/asm/msr-index.h +++ b/tools/arch/x86/include/asm/msr-index.h @@ -237,6 +237,11 @@ #define LBR_INFO_CYCLES 0xffff #define LBR_INFO_BR_TYPE_OFFSET 56 #define LBR_INFO_BR_TYPE (0xfull << LBR_INFO_BR_TYPE_OFFSET) +#define LBR_INFO_BR_CNTR_OFFSET 32 +#define LBR_INFO_BR_CNTR_NUM 4 +#define LBR_INFO_BR_CNTR_BITS 2 +#define LBR_INFO_BR_CNTR_MASK GENMASK_ULL(LBR_INFO_BR_CNTR_BITS - 1, 0) +#define LBR_INFO_BR_CNTR_FULL_MASK GENMASK_ULL(LBR_INFO_BR_CNTR_NUM * LBR_INFO_BR_CNTR_BITS - 1, 0) #define MSR_ARCH_LBR_CTL 0x000014ce #define ARCH_LBR_CTL_LBREN BIT(0) @@ -536,6 +541,9 @@ #define MSR_RELOAD_PMC0 0x000014c1 #define MSR_RELOAD_FIXED_CTR0 0x00001309 +/* KeyID partitioning between MKTME and TDX */ +#define MSR_IA32_MKTME_KEYID_PARTITIONING 0x00000087 + /* * AMD64 MSRs. Not complete. See the architecture manual for a more * complete list. diff --git a/tools/arch/x86/include/uapi/asm/kvm.h b/tools/arch/x86/include/uapi/asm/kvm.h index 1a6a1f9879..a448d0964f 100644 --- a/tools/arch/x86/include/uapi/asm/kvm.h +++ b/tools/arch/x86/include/uapi/asm/kvm.h @@ -562,4 +562,7 @@ struct kvm_pmu_event_filter { /* x86-specific KVM_EXIT_HYPERCALL flags. */ #define KVM_EXIT_HYPERCALL_LONG_MODE BIT(0) +#define KVM_X86_DEFAULT_VM 0 +#define KVM_X86_SW_PROTECTED_VM 1 + #endif /* _ASM_X86_KVM_H */ diff --git a/tools/arch/x86/lib/memcpy_64.S b/tools/arch/x86/lib/memcpy_64.S index d055b82d22..59cf6f9065 100644 --- a/tools/arch/x86/lib/memcpy_64.S +++ b/tools/arch/x86/lib/memcpy_64.S @@ -1,11 +1,11 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* Copyright 2002 Andi Kleen */ +#include #include #include #include #include -#include .section .noinstr.text, "ax" @@ -39,7 +39,7 @@ SYM_TYPED_FUNC_START(__memcpy) SYM_FUNC_END(__memcpy) EXPORT_SYMBOL(__memcpy) -SYM_FUNC_ALIAS(memcpy, __memcpy) +SYM_FUNC_ALIAS_MEMFUNC(memcpy, __memcpy) EXPORT_SYMBOL(memcpy) SYM_FUNC_START_LOCAL(memcpy_orig) diff --git a/tools/arch/x86/lib/memset_64.S b/tools/arch/x86/lib/memset_64.S index 7c59a704c4..0199d56cb4 100644 --- a/tools/arch/x86/lib/memset_64.S +++ b/tools/arch/x86/lib/memset_64.S @@ -1,10 +1,10 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* Copyright 2002 Andi Kleen, SuSE Labs */ +#include #include #include #include -#include .section .noinstr.text, "ax" @@ -40,7 +40,7 @@ SYM_FUNC_START(__memset) SYM_FUNC_END(__memset) EXPORT_SYMBOL(__memset) -SYM_FUNC_ALIAS(memset, __memset) +SYM_FUNC_ALIAS_MEMFUNC(memset, __memset) EXPORT_SYMBOL(memset) SYM_FUNC_START_LOCAL(memset_orig) diff --git a/tools/bpf/bpftool/Documentation/bpftool.rst b/tools/bpf/bpftool/Documentation/bpftool.rst index 6965c94dfd..09e4f2ff56 100644 --- a/tools/bpf/bpftool/Documentation/bpftool.rst +++ b/tools/bpf/bpftool/Documentation/bpftool.rst @@ -20,7 +20,7 @@ SYNOPSIS **bpftool** **version** - *OBJECT* := { **map** | **program** | **link** | **cgroup** | **perf** | **net** | **feature** | + *OBJECT* := { **map** | **prog** | **link** | **cgroup** | **perf** | **net** | **feature** | **btf** | **gen** | **struct_ops** | **iter** } *OPTIONS* := { { **-V** | **--version** } | |COMMON_OPTIONS| } diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c index edda4fc2c4..708733b0ea 100644 --- a/tools/bpf/bpftool/feature.c +++ b/tools/bpf/bpftool/feature.c @@ -426,10 +426,6 @@ static void probe_kernel_image_config(const char *define_prefix) { "CONFIG_BPF_STREAM_PARSER", }, /* xt_bpf module for passing BPF programs to netfilter */ { "CONFIG_NETFILTER_XT_MATCH_BPF", }, - /* bpfilter back-end for iptables */ - { "CONFIG_BPFILTER", }, - /* bpftilter module with "user mode helper" */ - { "CONFIG_BPFILTER_UMH", }, /* test_bpf module for BPF tests */ { "CONFIG_TEST_BPF", }, diff --git a/tools/bpf/bpftool/link.c b/tools/bpf/bpftool/link.c index a1528cde81..35b6859dd7 100644 --- a/tools/bpf/bpftool/link.c +++ b/tools/bpf/bpftool/link.c @@ -294,6 +294,37 @@ show_kprobe_multi_json(struct bpf_link_info *info, json_writer_t *wtr) jsonw_end_array(json_wtr); } +static __u64 *u64_to_arr(__u64 val) +{ + return (__u64 *) u64_to_ptr(val); +} + +static void +show_uprobe_multi_json(struct bpf_link_info *info, json_writer_t *wtr) +{ + __u32 i; + + jsonw_bool_field(json_wtr, "retprobe", + info->uprobe_multi.flags & BPF_F_UPROBE_MULTI_RETURN); + jsonw_string_field(json_wtr, "path", (char *) u64_to_ptr(info->uprobe_multi.path)); + jsonw_uint_field(json_wtr, "func_cnt", info->uprobe_multi.count); + jsonw_int_field(json_wtr, "pid", (int) info->uprobe_multi.pid); + jsonw_name(json_wtr, "funcs"); + jsonw_start_array(json_wtr); + + for (i = 0; i < info->uprobe_multi.count; i++) { + jsonw_start_object(json_wtr); + jsonw_uint_field(json_wtr, "offset", + u64_to_arr(info->uprobe_multi.offsets)[i]); + jsonw_uint_field(json_wtr, "ref_ctr_offset", + u64_to_arr(info->uprobe_multi.ref_ctr_offsets)[i]); + jsonw_uint_field(json_wtr, "cookie", + u64_to_arr(info->uprobe_multi.cookies)[i]); + jsonw_end_object(json_wtr); + } + jsonw_end_array(json_wtr); +} + static void show_perf_event_kprobe_json(struct bpf_link_info *info, json_writer_t *wtr) { @@ -465,6 +496,9 @@ static int show_link_close_json(int fd, struct bpf_link_info *info) case BPF_LINK_TYPE_KPROBE_MULTI: show_kprobe_multi_json(info, json_wtr); break; + case BPF_LINK_TYPE_UPROBE_MULTI: + show_uprobe_multi_json(info, json_wtr); + break; case BPF_LINK_TYPE_PERF_EVENT: switch (info->perf_event.type) { case BPF_PERF_EVENT_EVENT: @@ -674,6 +708,33 @@ static void show_kprobe_multi_plain(struct bpf_link_info *info) } } +static void show_uprobe_multi_plain(struct bpf_link_info *info) +{ + __u32 i; + + if (!info->uprobe_multi.count) + return; + + if (info->uprobe_multi.flags & BPF_F_UPROBE_MULTI_RETURN) + printf("\n\turetprobe.multi "); + else + printf("\n\tuprobe.multi "); + + printf("path %s ", (char *) u64_to_ptr(info->uprobe_multi.path)); + printf("func_cnt %u ", info->uprobe_multi.count); + + if (info->uprobe_multi.pid) + printf("pid %d ", info->uprobe_multi.pid); + + printf("\n\t%-16s %-16s %-16s", "offset", "ref_ctr_offset", "cookies"); + for (i = 0; i < info->uprobe_multi.count; i++) { + printf("\n\t0x%-16llx 0x%-16llx 0x%-16llx", + u64_to_arr(info->uprobe_multi.offsets)[i], + u64_to_arr(info->uprobe_multi.ref_ctr_offsets)[i], + u64_to_arr(info->uprobe_multi.cookies)[i]); + } +} + static void show_perf_event_kprobe_plain(struct bpf_link_info *info) { const char *buf; @@ -807,6 +868,9 @@ static int show_link_close_plain(int fd, struct bpf_link_info *info) case BPF_LINK_TYPE_KPROBE_MULTI: show_kprobe_multi_plain(info); break; + case BPF_LINK_TYPE_UPROBE_MULTI: + show_uprobe_multi_plain(info); + break; case BPF_LINK_TYPE_PERF_EVENT: switch (info->perf_event.type) { case BPF_PERF_EVENT_EVENT: @@ -846,8 +910,10 @@ static int show_link_close_plain(int fd, struct bpf_link_info *info) static int do_show_link(int fd) { + __u64 *ref_ctr_offsets = NULL, *offsets = NULL, *cookies = NULL; struct bpf_link_info info; __u32 len = sizeof(info); + char path_buf[PATH_MAX]; __u64 *addrs = NULL; char buf[PATH_MAX]; int count; @@ -889,6 +955,39 @@ again: goto again; } } + if (info.type == BPF_LINK_TYPE_UPROBE_MULTI && + !info.uprobe_multi.offsets) { + count = info.uprobe_multi.count; + if (count) { + offsets = calloc(count, sizeof(__u64)); + if (!offsets) { + p_err("mem alloc failed"); + close(fd); + return -ENOMEM; + } + info.uprobe_multi.offsets = ptr_to_u64(offsets); + ref_ctr_offsets = calloc(count, sizeof(__u64)); + if (!ref_ctr_offsets) { + p_err("mem alloc failed"); + free(offsets); + close(fd); + return -ENOMEM; + } + info.uprobe_multi.ref_ctr_offsets = ptr_to_u64(ref_ctr_offsets); + cookies = calloc(count, sizeof(__u64)); + if (!cookies) { + p_err("mem alloc failed"); + free(ref_ctr_offsets); + free(offsets); + close(fd); + return -ENOMEM; + } + info.uprobe_multi.cookies = ptr_to_u64(cookies); + info.uprobe_multi.path = ptr_to_u64(path_buf); + info.uprobe_multi.path_size = sizeof(path_buf); + goto again; + } + } if (info.type == BPF_LINK_TYPE_PERF_EVENT) { switch (info.perf_event.type) { case BPF_PERF_EVENT_TRACEPOINT: @@ -924,8 +1023,10 @@ again: else show_link_close_plain(fd, &info); - if (addrs) - free(addrs); + free(ref_ctr_offsets); + free(cookies); + free(offsets); + free(addrs); close(fd); return 0; } diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c index 865bfa869a..9cb42a3366 100644 --- a/tools/bpf/bpftool/prog.c +++ b/tools/bpf/bpftool/prog.c @@ -442,7 +442,7 @@ static void print_prog_header_json(struct bpf_prog_info *info, int fd) jsonw_uint_field(json_wtr, "recursion_misses", info->recursion_misses); } -static void print_prog_json(struct bpf_prog_info *info, int fd) +static void print_prog_json(struct bpf_prog_info *info, int fd, bool orphaned) { char *memlock; @@ -461,6 +461,7 @@ static void print_prog_json(struct bpf_prog_info *info, int fd) jsonw_uint_field(json_wtr, "uid", info->created_by_uid); } + jsonw_bool_field(json_wtr, "orphaned", orphaned); jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len); if (info->jited_prog_len) { @@ -527,7 +528,7 @@ static void print_prog_header_plain(struct bpf_prog_info *info, int fd) printf("\n"); } -static void print_prog_plain(struct bpf_prog_info *info, int fd) +static void print_prog_plain(struct bpf_prog_info *info, int fd, bool orphaned) { char *memlock; @@ -554,6 +555,9 @@ static void print_prog_plain(struct bpf_prog_info *info, int fd) printf(" memlock %sB", memlock); free(memlock); + if (orphaned) + printf(" orphaned"); + if (info->nr_map_ids) show_prog_maps(fd, info->nr_map_ids); @@ -581,15 +585,15 @@ static int show_prog(int fd) int err; err = bpf_prog_get_info_by_fd(fd, &info, &len); - if (err) { + if (err && err != -ENODEV) { p_err("can't get prog info: %s", strerror(errno)); return -1; } if (json_output) - print_prog_json(&info, fd); + print_prog_json(&info, fd, err == -ENODEV); else - print_prog_plain(&info, fd); + print_prog_plain(&info, fd, err == -ENODEV); return 0; } diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature index 934e2777a2..64df118376 100644 --- a/tools/build/Makefile.feature +++ b/tools/build/Makefile.feature @@ -32,6 +32,7 @@ FEATURE_TESTS_BASIC := \ backtrace \ dwarf \ dwarf_getlocations \ + dwarf_getcfi \ eventfd \ fortify-source \ get_current_dir_name \ diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile index dad79ede4e..37722e509e 100644 --- a/tools/build/feature/Makefile +++ b/tools/build/feature/Makefile @@ -7,6 +7,7 @@ FILES= \ test-bionic.bin \ test-dwarf.bin \ test-dwarf_getlocations.bin \ + test-dwarf_getcfi.bin \ test-eventfd.bin \ test-fortify-source.bin \ test-get_current_dir_name.bin \ @@ -154,6 +155,9 @@ $(OUTPUT)test-dwarf.bin: $(OUTPUT)test-dwarf_getlocations.bin: $(BUILD) $(DWARFLIBS) +$(OUTPUT)test-dwarf_getcfi.bin: + $(BUILD) $(DWARFLIBS) + $(OUTPUT)test-libelf-getphdrnum.bin: $(BUILD) -lelf diff --git a/tools/build/feature/test-dwarf_getcfi.c b/tools/build/feature/test-dwarf_getcfi.c new file mode 100644 index 0000000000..50e7d7cb7b --- /dev/null +++ b/tools/build/feature/test-dwarf_getcfi.c @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include + +int main(void) +{ + Dwarf *dwarf = NULL; + return dwarf_getcfi(dwarf) == NULL; +} diff --git a/tools/cgroup/Makefile b/tools/cgroup/Makefile deleted file mode 100644 index ffca068e4a..0000000000 --- a/tools/cgroup/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# Makefile for cgroup tools - -CFLAGS = -Wall -Wextra - -all: cgroup_event_listener -%: %.c - $(CC) $(CFLAGS) -o $@ $^ - -clean: - $(RM) cgroup_event_listener diff --git a/tools/cgroup/cgroup_event_listener.c b/tools/cgroup/cgroup_event_listener.c deleted file mode 100644 index 3d70dc831a..0000000000 --- a/tools/cgroup/cgroup_event_listener.c +++ /dev/null @@ -1,83 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * cgroup_event_listener.c - Simple listener of cgroup events - * - * Copyright (C) Kirill A. Shutemov - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define USAGE_STR "Usage: cgroup_event_listener " - -int main(int argc, char **argv) -{ - int efd = -1; - int cfd = -1; - int event_control = -1; - char event_control_path[PATH_MAX]; - char line[LINE_MAX]; - int ret; - - if (argc != 3) - errx(1, "%s", USAGE_STR); - - cfd = open(argv[1], O_RDONLY); - if (cfd == -1) - err(1, "Cannot open %s", argv[1]); - - ret = snprintf(event_control_path, PATH_MAX, "%s/cgroup.event_control", - dirname(argv[1])); - if (ret >= PATH_MAX) - errx(1, "Path to cgroup.event_control is too long"); - - event_control = open(event_control_path, O_WRONLY); - if (event_control == -1) - err(1, "Cannot open %s", event_control_path); - - efd = eventfd(0, 0); - if (efd == -1) - err(1, "eventfd() failed"); - - ret = snprintf(line, LINE_MAX, "%d %d %s", efd, cfd, argv[2]); - if (ret >= LINE_MAX) - errx(1, "Arguments string is too long"); - - ret = write(event_control, line, strlen(line) + 1); - if (ret == -1) - err(1, "Cannot write to cgroup.event_control"); - - while (1) { - uint64_t result; - - ret = read(efd, &result, sizeof(result)); - if (ret == -1) { - if (errno == EINTR) - continue; - err(1, "Cannot read from eventfd"); - } - assert(ret == sizeof(result)); - - ret = access(event_control_path, W_OK); - if ((ret == -1) && (errno == ENOENT)) { - puts("The cgroup seems to have removed."); - break; - } - - if (ret == -1) - err(1, "cgroup.event_control is not accessible any more"); - - printf("%s %s: crossed\n", argv[1], argv[2]); - } - - return 0; -} diff --git a/tools/counter/Build b/tools/counter/Build index 33f4a51d71..4bbadb7ec9 100644 --- a/tools/counter/Build +++ b/tools/counter/Build @@ -1 +1,2 @@ counter_example-y += counter_example.o +counter_watch_events-y += counter_watch_events.o diff --git a/tools/counter/Makefile b/tools/counter/Makefile index b2c2946f44..d82d35a520 100644 --- a/tools/counter/Makefile +++ b/tools/counter/Makefile @@ -12,9 +12,10 @@ endif # (this improves performance and avoids hard-to-debug behaviour); MAKEFLAGS += -r -override CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include +override CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include \ + -I$(srctree)/tools/include -ALL_TARGETS := counter_example +ALL_TARGETS := counter_example counter_watch_events ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS)) all: $(ALL_PROGRAMS) @@ -37,12 +38,19 @@ $(COUNTER_EXAMPLE): prepare FORCE $(OUTPUT)counter_example: $(COUNTER_EXAMPLE) $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ +COUNTER_WATCH_EVENTS := $(OUTPUT)counter_watch_events.o +$(COUNTER_WATCH_EVENTS): prepare FORCE + $(Q)$(MAKE) $(build)=counter_watch_events +$(OUTPUT)counter_watch_events: $(COUNTER_WATCH_EVENTS) + $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ + clean: rm -f $(ALL_PROGRAMS) rm -rf $(OUTPUT)include/linux/counter.h rm -df $(OUTPUT)include/linux rm -df $(OUTPUT)include find $(or $(OUTPUT),.) -name '*.o' -delete -o -name '\.*.d' -delete + find $(or $(OUTPUT),.) -name '\.*.o.cmd' -delete install: $(ALL_PROGRAMS) install -d -m 755 $(DESTDIR)$(bindir); \ diff --git a/tools/counter/counter_watch_events.c b/tools/counter/counter_watch_events.c new file mode 100644 index 0000000000..107631e0f2 --- /dev/null +++ b/tools/counter/counter_watch_events.c @@ -0,0 +1,406 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Counter Watch Events - Test various counter watch events in a userspace application + * + * Copyright (C) STMicroelectronics 2023 - All Rights Reserved + * Author: Fabrice Gasnier . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct counter_watch simple_watch[] = { + { + /* Component data: Count 0 count */ + .component.type = COUNTER_COMPONENT_COUNT, + .component.scope = COUNTER_SCOPE_COUNT, + .component.parent = 0, + /* Event type: overflow or underflow */ + .event = COUNTER_EVENT_OVERFLOW_UNDERFLOW, + /* Device event channel 0 */ + .channel = 0, + }, +}; + +static const char * const counter_event_type_name[] = { + "COUNTER_EVENT_OVERFLOW", + "COUNTER_EVENT_UNDERFLOW", + "COUNTER_EVENT_OVERFLOW_UNDERFLOW", + "COUNTER_EVENT_THRESHOLD", + "COUNTER_EVENT_INDEX", + "COUNTER_EVENT_CHANGE_OF_STATE", + "COUNTER_EVENT_CAPTURE", +}; + +static const char * const counter_component_type_name[] = { + "COUNTER_COMPONENT_NONE", + "COUNTER_COMPONENT_SIGNAL", + "COUNTER_COMPONENT_COUNT", + "COUNTER_COMPONENT_FUNCTION", + "COUNTER_COMPONENT_SYNAPSE_ACTION", + "COUNTER_COMPONENT_EXTENSION", +}; + +static const char * const counter_scope_name[] = { + "COUNTER_SCOPE_DEVICE", + "COUNTER_SCOPE_SIGNAL", + "COUNTER_SCOPE_COUNT", +}; + +static void print_watch(struct counter_watch *watch, int nwatch) +{ + int i; + + /* prints the watch array in C-like structure */ + printf("watch[%d] = {\n", nwatch); + for (i = 0; i < nwatch; i++) { + printf(" [%d] =\t{\n" + "\t\t.component.type = %s\n" + "\t\t.component.scope = %s\n" + "\t\t.component.parent = %d\n" + "\t\t.component.id = %d\n" + "\t\t.event = %s\n" + "\t\t.channel = %d\n" + "\t},\n", + i, + counter_component_type_name[watch[i].component.type], + counter_scope_name[watch[i].component.scope], + watch[i].component.parent, + watch[i].component.id, + counter_event_type_name[watch[i].event], + watch[i].channel); + } + printf("};\n"); +} + +static void print_usage(void) +{ + fprintf(stderr, "Usage:\n\n" + "counter_watch_events [options] [-w ]\n" + "counter_watch_events [options] [-w ] [-w ]...\n" + "\n" + "When no --watch option has been provided, simple watch example is used:\n" + "counter_watch_events [options] -w comp_count,scope_count,evt_ovf_udf\n" + "\n" + "Test various watch events for given counter device.\n" + "\n" + "Options:\n" + " -d, --debug Prints debug information\n" + " -h, --help Prints usage\n" + " -n, --device-num Use /dev/counter [default: /dev/counter0]\n" + " -l, --loop Loop for events [default: 0 (forever)]\n" + " -w, --watch comma-separated list of watch options\n" + "\n" + "Watch options:\n" + " scope_device (COUNTER_SCOPE_DEVICE) [default: scope_device]\n" + " scope_signal (COUNTER_SCOPE_SIGNAL)\n" + " scope_count (COUNTER_SCOPE_COUNT)\n" + "\n" + " comp_none (COUNTER_COMPONENT_NONE) [default: comp_none]\n" + " comp_signal (COUNTER_COMPONENT_SIGNAL)\n" + " comp_count (COUNTER_COMPONENT_COUNT)\n" + " comp_function (COUNTER_COMPONENT_FUNCTION)\n" + " comp_synapse_action (COUNTER_COMPONENT_SYNAPSE_ACTION)\n" + " comp_extension (COUNTER_COMPONENT_EXTENSION)\n" + "\n" + " evt_ovf (COUNTER_EVENT_OVERFLOW) [default: evt_ovf]\n" + " evt_udf (COUNTER_EVENT_UNDERFLOW)\n" + " evt_ovf_udf (COUNTER_EVENT_OVERFLOW_UNDERFLOW)\n" + " evt_threshold (COUNTER_EVENT_THRESHOLD)\n" + " evt_index (COUNTER_EVENT_INDEX)\n" + " evt_change_of_state (COUNTER_EVENT_CHANGE_OF_STATE)\n" + " evt_capture (COUNTER_EVENT_CAPTURE)\n" + "\n" + " chan= channel for this watch [default: 0]\n" + " id= component id for this watch [default: 0]\n" + " parent= component parent for this watch [default: 0]\n" + "\n" + "Example with two watched events:\n\n" + "counter_watch_events -d \\\n" + "\t-w comp_count,scope_count,evt_ovf_udf \\\n" + "\t-w comp_extension,scope_count,evt_capture,id=7,chan=3\n" + ); +} + +static const struct option longopts[] = { + { "debug", no_argument, 0, 'd' }, + { "help", no_argument, 0, 'h' }, + { "device-num", required_argument, 0, 'n' }, + { "loop", required_argument, 0, 'l' }, + { "watch", required_argument, 0, 'w' }, + { }, +}; + +/* counter watch subopts */ +enum { + WATCH_SCOPE_DEVICE, + WATCH_SCOPE_SIGNAL, + WATCH_SCOPE_COUNT, + WATCH_COMPONENT_NONE, + WATCH_COMPONENT_SIGNAL, + WATCH_COMPONENT_COUNT, + WATCH_COMPONENT_FUNCTION, + WATCH_COMPONENT_SYNAPSE_ACTION, + WATCH_COMPONENT_EXTENSION, + WATCH_EVENT_OVERFLOW, + WATCH_EVENT_UNDERFLOW, + WATCH_EVENT_OVERFLOW_UNDERFLOW, + WATCH_EVENT_THRESHOLD, + WATCH_EVENT_INDEX, + WATCH_EVENT_CHANGE_OF_STATE, + WATCH_EVENT_CAPTURE, + WATCH_CHANNEL, + WATCH_ID, + WATCH_PARENT, + WATCH_SUBOPTS_MAX, +}; + +static char * const counter_watch_subopts[WATCH_SUBOPTS_MAX + 1] = { + /* component.scope */ + [WATCH_SCOPE_DEVICE] = "scope_device", + [WATCH_SCOPE_SIGNAL] = "scope_signal", + [WATCH_SCOPE_COUNT] = "scope_count", + /* component.type */ + [WATCH_COMPONENT_NONE] = "comp_none", + [WATCH_COMPONENT_SIGNAL] = "comp_signal", + [WATCH_COMPONENT_COUNT] = "comp_count", + [WATCH_COMPONENT_FUNCTION] = "comp_function", + [WATCH_COMPONENT_SYNAPSE_ACTION] = "comp_synapse_action", + [WATCH_COMPONENT_EXTENSION] = "comp_extension", + /* event */ + [WATCH_EVENT_OVERFLOW] = "evt_ovf", + [WATCH_EVENT_UNDERFLOW] = "evt_udf", + [WATCH_EVENT_OVERFLOW_UNDERFLOW] = "evt_ovf_udf", + [WATCH_EVENT_THRESHOLD] = "evt_threshold", + [WATCH_EVENT_INDEX] = "evt_index", + [WATCH_EVENT_CHANGE_OF_STATE] = "evt_change_of_state", + [WATCH_EVENT_CAPTURE] = "evt_capture", + /* channel, id, parent */ + [WATCH_CHANNEL] = "chan", + [WATCH_ID] = "id", + [WATCH_PARENT] = "parent", + /* Empty entry ends the opts array */ + NULL +}; + +int main(int argc, char **argv) +{ + int c, fd, i, ret, rc = 0, debug = 0, loop = 0, dev_num = 0, nwatch = 0; + struct counter_event event_data; + char *device_name = NULL, *subopts, *value; + struct counter_watch *watches; + + /* + * 1st pass: + * - list watch events number to allocate the watch array. + * - parse normal options (other than watch options) + */ + while ((c = getopt_long(argc, argv, "dhn:l:w:", longopts, NULL)) != -1) { + switch (c) { + case 'd': + debug = 1; + break; + case 'h': + print_usage(); + return EXIT_SUCCESS; + case 'n': + dev_num = strtoul(optarg, NULL, 10); + if (errno) { + perror("strtol failed: --device-num \n"); + return EXIT_FAILURE; + } + break; + case 'l': + loop = strtol(optarg, NULL, 10); + if (errno) { + perror("strtol failed: --loop \n"); + return EXIT_FAILURE; + } + break; + case 'w': + nwatch++; + break; + default: + return EXIT_FAILURE; + } + } + + if (nwatch) { + watches = calloc(nwatch, sizeof(*watches)); + if (!watches) { + perror("Error allocating watches\n"); + return EXIT_FAILURE; + } + } else { + /* default to simple watch example */ + watches = simple_watch; + nwatch = ARRAY_SIZE(simple_watch); + } + + /* 2nd pass: parse watch sub-options to fill in watch array */ + optind = 1; + i = 0; + while ((c = getopt_long(argc, argv, "dhn:l:w:", longopts, NULL)) != -1) { + switch (c) { + case 'w': + subopts = optarg; + while (*subopts != '\0') { + ret = getsubopt(&subopts, counter_watch_subopts, &value); + switch (ret) { + case WATCH_SCOPE_DEVICE: + case WATCH_SCOPE_SIGNAL: + case WATCH_SCOPE_COUNT: + /* match with counter_scope */ + watches[i].component.scope = ret; + break; + case WATCH_COMPONENT_NONE: + case WATCH_COMPONENT_SIGNAL: + case WATCH_COMPONENT_COUNT: + case WATCH_COMPONENT_FUNCTION: + case WATCH_COMPONENT_SYNAPSE_ACTION: + case WATCH_COMPONENT_EXTENSION: + /* match counter_component_type: subtract enum value */ + ret -= WATCH_COMPONENT_NONE; + watches[i].component.type = ret; + break; + case WATCH_EVENT_OVERFLOW: + case WATCH_EVENT_UNDERFLOW: + case WATCH_EVENT_OVERFLOW_UNDERFLOW: + case WATCH_EVENT_THRESHOLD: + case WATCH_EVENT_INDEX: + case WATCH_EVENT_CHANGE_OF_STATE: + case WATCH_EVENT_CAPTURE: + /* match counter_event_type: subtract enum value */ + ret -= WATCH_EVENT_OVERFLOW; + watches[i].event = ret; + break; + case WATCH_CHANNEL: + if (!value) { + fprintf(stderr, "Invalid chan=\n"); + rc = EXIT_FAILURE; + goto err_free_watches; + } + watches[i].channel = strtoul(value, NULL, 10); + if (errno) { + perror("strtoul failed: chan=\n"); + rc = EXIT_FAILURE; + goto err_free_watches; + } + break; + case WATCH_ID: + if (!value) { + fprintf(stderr, "Invalid id=\n"); + rc = EXIT_FAILURE; + goto err_free_watches; + } + watches[i].component.id = strtoul(value, NULL, 10); + if (errno) { + perror("strtoul failed: id=\n"); + rc = EXIT_FAILURE; + goto err_free_watches; + } + break; + case WATCH_PARENT: + if (!value) { + fprintf(stderr, "Invalid parent=\n"); + rc = EXIT_FAILURE; + goto err_free_watches; + } + watches[i].component.parent = strtoul(value, NULL, 10); + if (errno) { + perror("strtoul failed: parent=\n"); + rc = EXIT_FAILURE; + goto err_free_watches; + } + break; + default: + fprintf(stderr, "Unknown suboption '%s'\n", value); + rc = EXIT_FAILURE; + goto err_free_watches; + } + } + i++; + break; + } + } + + if (debug) + print_watch(watches, nwatch); + + ret = asprintf(&device_name, "/dev/counter%d", dev_num); + if (ret < 0) { + fprintf(stderr, "asprintf failed\n"); + rc = EXIT_FAILURE; + goto err_free_watches; + } + + if (debug) + printf("Opening %s\n", device_name); + + fd = open(device_name, O_RDWR); + if (fd == -1) { + fprintf(stderr, "Unable to open %s: %s\n", device_name, strerror(errno)); + free(device_name); + rc = EXIT_FAILURE; + goto err_free_watches; + } + free(device_name); + + for (i = 0; i < nwatch; i++) { + ret = ioctl(fd, COUNTER_ADD_WATCH_IOCTL, watches + i); + if (ret == -1) { + fprintf(stderr, "Error adding watches[%d]: %s\n", i, + strerror(errno)); + rc = EXIT_FAILURE; + goto err_close; + } + } + + ret = ioctl(fd, COUNTER_ENABLE_EVENTS_IOCTL); + if (ret == -1) { + perror("Error enabling events"); + rc = EXIT_FAILURE; + goto err_close; + } + + for (i = 0; loop <= 0 || i < loop; i++) { + ret = read(fd, &event_data, sizeof(event_data)); + if (ret == -1) { + perror("Failed to read event data"); + rc = EXIT_FAILURE; + goto err_close; + } + + if (ret != sizeof(event_data)) { + fprintf(stderr, "Failed to read event data (got: %d)\n", ret); + rc = EXIT_FAILURE; + goto err_close; + } + + printf("Timestamp: %llu\tData: %llu\t event: %s\tch: %d\n", + event_data.timestamp, event_data.value, + counter_event_type_name[event_data.watch.event], + event_data.watch.channel); + + if (event_data.status) { + fprintf(stderr, "Error %d: %s\n", event_data.status, + strerror(event_data.status)); + } + } + +err_close: + close(fd); +err_free_watches: + if (watches != simple_watch) + free(watches); + + return rc; +} diff --git a/tools/crypto/tcrypt/tcrypt_speed_compare.py b/tools/crypto/tcrypt/tcrypt_speed_compare.py new file mode 100755 index 0000000000..f3f5783cdc --- /dev/null +++ b/tools/crypto/tcrypt/tcrypt_speed_compare.py @@ -0,0 +1,190 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) xFusion Digital Technologies Co., Ltd., 2023 +# +# Author: Wang Jinchao +# +""" +A tool for comparing tcrypt speed test logs. + +Please note that for such a comparison, stability depends +on whether we allow frequency to float or pin the frequency. + +Both support tests for operations within one second and +cycles of operation. +For example, use it in the bash script below. + +```bash +#!/bin/bash + +# log file prefix +seq_num=0 + +# When sec=0, it will perform cycle tests; +# otherwise, it indicates the duration of a single test +sec=0 +num_mb=8 +mode=211 + +# base speed test +lsmod | grep pcrypt && modprobe -r pcrypt +dmesg -C +modprobe tcrypt alg="pcrypt(rfc4106(gcm(aes)))" type=3 +modprobe tcrypt mode=${mode} sec=${sec} num_mb=${num_mb} +dmesg > ${seq_num}_base_dmesg.log + +# new speed test +lsmod | grep pcrypt && modprobe -r pcrypt +dmesg -C +modprobe tcrypt alg="pcrypt(rfc4106(gcm(aes)))" type=3 +modprobe tcrypt mode=${mode} sec=${sec} num_mb=${num_mb} +dmesg > ${seq_num}_new_dmesg.log +lsmod | grep pcrypt && modprobe -r pcrypt + +tools/crypto/tcrypt/tcrypt_speed_compare.py \ + ${seq_num}_base_dmesg.log \ + ${seq_num}_new_dmesg.log \ + >${seq_num}_compare.log +grep 'average' -A2 -B0 --group-separator="" ${seq_num}_compare.log +``` +""" + +import sys +import re + + +def parse_title(line): + pattern = r'tcrypt: testing speed of (.*?) (encryption|decryption)' + match = re.search(pattern, line) + if match: + alg = match.group(1) + op = match.group(2) + return alg, op + else: + return "", "" + + +def parse_item(line): + pattern_operations = r'\((\d+) bit key, (\d+) byte blocks\): (\d+) operations' + pattern_cycles = r'\((\d+) bit key, (\d+) byte blocks\): 1 operation in (\d+) cycles' + match = re.search(pattern_operations, line) + if match: + res = { + "bit_key": int(match.group(1)), + "byte_blocks": int(match.group(2)), + "operations": int(match.group(3)), + } + return res + + match = re.search(pattern_cycles, line) + if match: + res = { + "bit_key": int(match.group(1)), + "byte_blocks": int(match.group(2)), + "cycles": int(match.group(3)), + } + return res + + return None + + +def parse(filepath): + result = {} + alg, op = "", "" + with open(filepath, 'r') as file: + for line in file: + if not line: + continue + _alg, _op = parse_title(line) + if _alg: + alg, op = _alg, _op + if alg not in result: + result[alg] = {} + if op not in result[alg]: + result[alg][op] = [] + continue + parsed_result = parse_item(line) + if parsed_result: + result[alg][op].append(parsed_result) + return result + + +def merge(base, new): + merged = {} + for alg in base.keys(): + merged[alg] = {} + for op in base[alg].keys(): + if op not in merged[alg]: + merged[alg][op] = [] + for index in range(len(base[alg][op])): + merged_item = { + "bit_key": base[alg][op][index]["bit_key"], + "byte_blocks": base[alg][op][index]["byte_blocks"], + } + if "operations" in base[alg][op][index].keys(): + merged_item["base_ops"] = base[alg][op][index]["operations"] + merged_item["new_ops"] = new[alg][op][index]["operations"] + else: + merged_item["base_cycles"] = base[alg][op][index]["cycles"] + merged_item["new_cycles"] = new[alg][op][index]["cycles"] + + merged[alg][op].append(merged_item) + return merged + + +def format(merged): + for alg in merged.keys(): + for op in merged[alg].keys(): + base_sum = 0 + new_sum = 0 + differ_sum = 0 + differ_cnt = 0 + print() + hlen = 80 + print("="*hlen) + print(f"{alg}") + print(f"{' '*(len(alg)//3) + op}") + print("-"*hlen) + key = "" + if "base_ops" in merged[alg][op][0]: + key = "ops" + print(f"bit key | byte blocks | base ops | new ops | differ(%)") + else: + key = "cycles" + print(f"bit key | byte blocks | base cycles | new cycles | differ(%)") + for index in range(len(merged[alg][op])): + item = merged[alg][op][index] + base_cnt = item[f"base_{key}"] + new_cnt = item[f"new_{key}"] + base_sum += base_cnt + new_sum += new_cnt + differ = round((new_cnt - base_cnt)*100/base_cnt, 2) + differ_sum += differ + differ_cnt += 1 + bit_key = item["bit_key"] + byte_blocks = item["byte_blocks"] + print( + f"{bit_key:<7} | {byte_blocks:<11} | {base_cnt:<11} | {new_cnt:<11} | {differ:<8}") + average_speed_up = "{:.2f}".format(differ_sum/differ_cnt) + ops_total_speed_up = "{:.2f}".format( + (base_sum - new_sum) * 100 / base_sum) + print('-'*hlen) + print(f"average differ(%s) | total_differ(%)") + print('-'*hlen) + print(f"{average_speed_up:<21} | {ops_total_speed_up:<10}") + print('='*hlen) + + +def main(base_log, new_log): + base = parse(base_log) + new = parse(new_log) + merged = merge(base, new) + format(merged) + + +if __name__ == "__main__": + if len(sys.argv) != 3: + print(f"usage: {sys.argv[0]} base_log new_log") + exit(-1) + main(sys.argv[1], sys.argv[2]) diff --git a/tools/iio/iio_event_monitor.c b/tools/iio/iio_event_monitor.c index 2eaaa7123b..8073c9e4fe 100644 --- a/tools/iio/iio_event_monitor.c +++ b/tools/iio/iio_event_monitor.c @@ -105,6 +105,8 @@ 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_UVA] = "uva", + [IIO_MOD_LIGHT_UVB] = "uvb", [IIO_MOD_LIGHT_DUV] = "duv", [IIO_MOD_QUATERNION] = "quaternion", [IIO_MOD_TEMP_AMBIENT] = "ambient", diff --git a/tools/iio/iio_utils.c b/tools/iio/iio_utils.c index 6a00a6eeca..c5c5082cb2 100644 --- a/tools/iio/iio_utils.c +++ b/tools/iio/iio_utils.c @@ -376,7 +376,7 @@ int build_channel_array(const char *device_dir, int buffer_idx, goto error_close_dir; } - seekdir(dp, 0); + rewinddir(dp); while (ent = readdir(dp), ent) { if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), "_en") == 0) { diff --git a/tools/include/asm-generic/unaligned.h b/tools/include/asm-generic/unaligned.h index 2fd551915c..cdd2fd0780 100644 --- a/tools/include/asm-generic/unaligned.h +++ b/tools/include/asm-generic/unaligned.h @@ -105,9 +105,9 @@ static inline u32 get_unaligned_le24(const void *p) static inline void __put_unaligned_be24(const u32 val, u8 *p) { - *p++ = val >> 16; - *p++ = val >> 8; - *p++ = val; + *p++ = (val >> 16) & 0xff; + *p++ = (val >> 8) & 0xff; + *p++ = val & 0xff; } static inline void put_unaligned_be24(const u32 val, void *p) @@ -117,9 +117,9 @@ static inline void put_unaligned_be24(const u32 val, void *p) static inline void __put_unaligned_le24(const u32 val, u8 *p) { - *p++ = val; - *p++ = val >> 8; - *p++ = val >> 16; + *p++ = val & 0xff; + *p++ = (val >> 8) & 0xff; + *p++ = (val >> 16) & 0xff; } static inline void put_unaligned_le24(const u32 val, void *p) @@ -129,12 +129,12 @@ static inline void put_unaligned_le24(const u32 val, void *p) static inline void __put_unaligned_be48(const u64 val, u8 *p) { - *p++ = val >> 40; - *p++ = val >> 32; - *p++ = val >> 24; - *p++ = val >> 16; - *p++ = val >> 8; - *p++ = val; + *p++ = (val >> 40) & 0xff; + *p++ = (val >> 32) & 0xff; + *p++ = (val >> 24) & 0xff; + *p++ = (val >> 16) & 0xff; + *p++ = (val >> 8) & 0xff; + *p++ = val & 0xff; } static inline void put_unaligned_be48(const u64 val, void *p) diff --git a/tools/include/linux/rwsem.h b/tools/include/linux/rwsem.h index 83971b3cbf..f8bffd4a98 100644 --- a/tools/include/linux/rwsem.h +++ b/tools/include/linux/rwsem.h @@ -37,4 +37,8 @@ static inline int up_write(struct rw_semaphore *sem) { return pthread_rwlock_unlock(&sem->lock); } + +#define down_read_nested(sem, subclass) down_read(sem) +#define down_write_nested(sem, subclass) down_write(sem) + #endif /* _TOOLS_RWSEM_H */ diff --git a/tools/include/linux/spinlock.h b/tools/include/linux/spinlock.h index 622266b197..a6cdf25b6b 100644 --- a/tools/include/linux/spinlock.h +++ b/tools/include/linux/spinlock.h @@ -11,6 +11,7 @@ #define spin_lock_init(x) pthread_mutex_init(x, NULL) #define spin_lock(x) pthread_mutex_lock(x) +#define spin_lock_nested(x, subclass) pthread_mutex_lock(x) #define spin_unlock(x) pthread_mutex_unlock(x) #define spin_lock_bh(x) pthread_mutex_lock(x) #define spin_unlock_bh(x) pthread_mutex_unlock(x) diff --git a/tools/include/nolibc/arch-mips.h b/tools/include/nolibc/arch-mips.h index 4ab6fa54be..62cc50ef32 100644 --- a/tools/include/nolibc/arch-mips.h +++ b/tools/include/nolibc/arch-mips.h @@ -10,6 +10,10 @@ #include "compiler.h" #include "crt.h" +#if !defined(_ABIO32) +#error Unsupported MIPS ABI +#endif + /* Syscalls for MIPS ABI O32 : * - WARNING! there's always a delayed slot! * - WARNING again, the syntax is different, registers take a '$' and numbers @@ -180,8 +184,13 @@ void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_ __asm__ volatile ( ".set push\n" ".set noreorder\n" - ".option pic0\n" + "bal 1f\n" /* prime $ra for .cpload */ + "nop\n" + "1:\n" + ".cpload $ra\n" "move $a0, $sp\n" /* save stack pointer to $a0, as arg1 of _start_c */ + "addiu $sp, $sp, -4\n" /* space for .cprestore to store $gp */ + ".cprestore 0\n" "li $t0, -8\n" "and $sp, $sp, $t0\n" /* $sp must be 8-byte aligned */ "addiu $sp, $sp, -16\n" /* the callee expects to save a0..a3 there */ diff --git a/tools/include/nolibc/arch.h b/tools/include/nolibc/arch.h index e276fb0680..c8f4e5d3ad 100644 --- a/tools/include/nolibc/arch.h +++ b/tools/include/nolibc/arch.h @@ -23,7 +23,7 @@ #include "arch-arm.h" #elif defined(__aarch64__) #include "arch-aarch64.h" -#elif defined(__mips__) && defined(_ABIO32) +#elif defined(__mips__) #include "arch-mips.h" #elif defined(__powerpc__) #include "arch-powerpc.h" @@ -33,6 +33,8 @@ #include "arch-s390.h" #elif defined(__loongarch__) #include "arch-loongarch.h" +#else +#error Unsupported Architecture #endif #endif /* _NOLIBC_ARCH_H */ diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index d7ef439739..16cd4d8072 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -212,7 +212,7 @@ char *fgets(char *s, int size, FILE *stream) * - %s * - unknown modifiers are ignored. */ -static __attribute__((unused)) +static __attribute__((unused, format(printf, 2, 0))) int vfprintf(FILE *stream, const char *fmt, va_list args) { char escape, lpref, c; @@ -318,7 +318,7 @@ int vfprintf(FILE *stream, const char *fmt, va_list args) return written; } -static __attribute__((unused)) +static __attribute__((unused, format(printf, 1, 0))) int vprintf(const char *fmt, va_list args) { return vfprintf(stdout, fmt, args); diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h index 2f359cb03d..dda9dffd1d 100644 --- a/tools/include/nolibc/sys.h +++ b/tools/include/nolibc/sys.h @@ -21,6 +21,7 @@ #include /* for O_* and AT_* */ #include /* for statx() */ #include +#include #include "arch.h" #include "errno.h" @@ -898,6 +899,43 @@ int reboot(int cmd) } +/* + * int getrlimit(int resource, struct rlimit *rlim); + * int setrlimit(int resource, const struct rlimit *rlim); + */ + +static __attribute__((unused)) +int sys_prlimit64(pid_t pid, int resource, + const struct rlimit64 *new_limit, struct rlimit64 *old_limit) +{ + return my_syscall4(__NR_prlimit64, pid, resource, new_limit, old_limit); +} + +static __attribute__((unused)) +int getrlimit(int resource, struct rlimit *rlim) +{ + struct rlimit64 rlim64; + int ret; + + ret = __sysret(sys_prlimit64(0, resource, NULL, &rlim64)); + rlim->rlim_cur = rlim64.rlim_cur; + rlim->rlim_max = rlim64.rlim_max; + + return ret; +} + +static __attribute__((unused)) +int setrlimit(int resource, const struct rlimit *rlim) +{ + struct rlimit64 rlim64 = { + .rlim_cur = rlim->rlim_cur, + .rlim_max = rlim->rlim_max, + }; + + return __sysret(sys_prlimit64(0, resource, &rlim64, NULL)); +} + + /* * int sched_yield(void); */ diff --git a/tools/include/nolibc/types.h b/tools/include/nolibc/types.h index 8cfc4c860f..b26a5d0c41 100644 --- a/tools/include/nolibc/types.h +++ b/tools/include/nolibc/types.h @@ -12,6 +12,8 @@ #include /* for LINUX_REBOOT_* */ #include #include +#include +#include /* Only the generic macros and types may be defined here. The arch-specific @@ -108,9 +110,6 @@ #define WTERMSIG(status) ((status) & 0x7f) #define WIFSIGNALED(status) ((status) - 1 < 0xff) -/* waitpid() flags */ -#define WNOHANG 1 - /* standard exit() codes */ #define EXIT_SUCCESS 0 #define EXIT_FAILURE 1 @@ -180,26 +179,6 @@ struct linux_dirent64 { char d_name[]; }; -/* needed by wait4() */ -struct rusage { - struct timeval ru_utime; - struct timeval ru_stime; - long ru_maxrss; - long ru_ixrss; - long ru_idrss; - long ru_isrss; - long ru_minflt; - long ru_majflt; - long ru_nswap; - long ru_inblock; - long ru_oublock; - long ru_msgsnd; - long ru_msgrcv; - long ru_nsignals; - long ru_nvcsw; - long ru_nivcsw; -}; - /* The format of the struct as returned by the libc to the application, which * significantly differs from the format returned by the stat() syscall flavours. */ diff --git a/tools/include/perf/arm_pmuv3.h b/tools/include/perf/arm_pmuv3.h index e822d49fb5..1e397d5538 100644 --- a/tools/include/perf/arm_pmuv3.h +++ b/tools/include/perf/arm_pmuv3.h @@ -218,45 +218,54 @@ #define ARMV8_PMU_PMCR_DP (1 << 5) /* Disable CCNT if non-invasive debug*/ #define ARMV8_PMU_PMCR_LC (1 << 6) /* Overflow on 64 bit cycle counter */ #define ARMV8_PMU_PMCR_LP (1 << 7) /* Long event counter enable */ -#define ARMV8_PMU_PMCR_N_SHIFT 11 /* Number of counters supported */ -#define ARMV8_PMU_PMCR_N_MASK 0x1f -#define ARMV8_PMU_PMCR_MASK 0xff /* Mask for writable bits */ +#define ARMV8_PMU_PMCR_N GENMASK(15, 11) /* Number of counters supported */ +/* Mask for writable bits */ +#define ARMV8_PMU_PMCR_MASK (ARMV8_PMU_PMCR_E | ARMV8_PMU_PMCR_P | \ + ARMV8_PMU_PMCR_C | ARMV8_PMU_PMCR_D | \ + ARMV8_PMU_PMCR_X | ARMV8_PMU_PMCR_DP | \ + ARMV8_PMU_PMCR_LC | ARMV8_PMU_PMCR_LP) /* * PMOVSR: counters overflow flag status reg */ -#define ARMV8_PMU_OVSR_MASK 0xffffffff /* Mask for writable bits */ -#define ARMV8_PMU_OVERFLOWED_MASK ARMV8_PMU_OVSR_MASK +#define ARMV8_PMU_OVSR_P GENMASK(30, 0) +#define ARMV8_PMU_OVSR_C BIT(31) +/* Mask for writable bits is both P and C fields */ +#define ARMV8_PMU_OVERFLOWED_MASK (ARMV8_PMU_OVSR_P | ARMV8_PMU_OVSR_C) /* * PMXEVTYPER: Event selection reg */ -#define ARMV8_PMU_EVTYPE_MASK 0xc800ffff /* Mask for writable bits */ -#define ARMV8_PMU_EVTYPE_EVENT 0xffff /* Mask for EVENT bits */ +#define ARMV8_PMU_EVTYPE_EVENT GENMASK(15, 0) /* Mask for EVENT bits */ +#define ARMV8_PMU_EVTYPE_TH GENMASK(43, 32) +#define ARMV8_PMU_EVTYPE_TC GENMASK(63, 61) /* * Event filters for PMUv3 */ -#define ARMV8_PMU_EXCLUDE_EL1 (1U << 31) -#define ARMV8_PMU_EXCLUDE_EL0 (1U << 30) -#define ARMV8_PMU_INCLUDE_EL2 (1U << 27) +#define ARMV8_PMU_EXCLUDE_EL1 (1U << 31) +#define ARMV8_PMU_EXCLUDE_EL0 (1U << 30) +#define ARMV8_PMU_EXCLUDE_NS_EL1 (1U << 29) +#define ARMV8_PMU_EXCLUDE_NS_EL0 (1U << 28) +#define ARMV8_PMU_INCLUDE_EL2 (1U << 27) +#define ARMV8_PMU_EXCLUDE_EL3 (1U << 26) /* * PMUSERENR: user enable reg */ -#define ARMV8_PMU_USERENR_MASK 0xf /* Mask for writable bits */ #define ARMV8_PMU_USERENR_EN (1 << 0) /* PMU regs can be accessed at EL0 */ #define ARMV8_PMU_USERENR_SW (1 << 1) /* PMSWINC can be written at EL0 */ #define ARMV8_PMU_USERENR_CR (1 << 2) /* Cycle counter can be read at EL0 */ #define ARMV8_PMU_USERENR_ER (1 << 3) /* Event counter can be read at EL0 */ +/* Mask for writable bits */ +#define ARMV8_PMU_USERENR_MASK (ARMV8_PMU_USERENR_EN | ARMV8_PMU_USERENR_SW | \ + ARMV8_PMU_USERENR_CR | ARMV8_PMU_USERENR_ER) /* PMMIR_EL1.SLOTS mask */ -#define ARMV8_PMU_SLOTS_MASK 0xff - -#define ARMV8_PMU_BUS_SLOTS_SHIFT 8 -#define ARMV8_PMU_BUS_SLOTS_MASK 0xff -#define ARMV8_PMU_BUS_WIDTH_SHIFT 16 -#define ARMV8_PMU_BUS_WIDTH_MASK 0xf +#define ARMV8_PMU_SLOTS GENMASK(7, 0) +#define ARMV8_PMU_BUS_SLOTS GENMASK(15, 8) +#define ARMV8_PMU_BUS_WIDTH GENMASK(19, 16) +#define ARMV8_PMU_THWIDTH GENMASK(23, 20) /* * This code is really good diff --git a/tools/include/uapi/asm-generic/unistd.h b/tools/include/uapi/asm-generic/unistd.h index 756b013fb8..75f00965ab 100644 --- a/tools/include/uapi/asm-generic/unistd.h +++ b/tools/include/uapi/asm-generic/unistd.h @@ -829,8 +829,21 @@ __SYSCALL(__NR_futex_wait, sys_futex_wait) #define __NR_futex_requeue 456 __SYSCALL(__NR_futex_requeue, sys_futex_requeue) +#define __NR_statmount 457 +__SYSCALL(__NR_statmount, sys_statmount) + +#define __NR_listmount 458 +__SYSCALL(__NR_listmount, sys_listmount) + +#define __NR_lsm_get_self_attr 459 +__SYSCALL(__NR_lsm_get_self_attr, sys_lsm_get_self_attr) +#define __NR_lsm_set_self_attr 460 +__SYSCALL(__NR_lsm_set_self_attr, sys_lsm_set_self_attr) +#define __NR_lsm_list_modules 461 +__SYSCALL(__NR_lsm_list_modules, sys_lsm_list_modules) + #undef __NR_syscalls -#define __NR_syscalls 457 +#define __NR_syscalls 462 /* * 32 bit systems traditionally used different diff --git a/tools/include/uapi/drm/drm.h b/tools/include/uapi/drm/drm.h index de723566c5..16122819ed 100644 --- a/tools/include/uapi/drm/drm.h +++ b/tools/include/uapi/drm/drm.h @@ -713,7 +713,8 @@ struct drm_gem_open { /** * DRM_CAP_ASYNC_PAGE_FLIP * - * If set to 1, the driver supports &DRM_MODE_PAGE_FLIP_ASYNC. + * If set to 1, the driver supports &DRM_MODE_PAGE_FLIP_ASYNC for legacy + * page-flips. */ #define DRM_CAP_ASYNC_PAGE_FLIP 0x7 /** @@ -773,6 +774,13 @@ struct drm_gem_open { * :ref:`drm_sync_objects`. */ #define DRM_CAP_SYNCOBJ_TIMELINE 0x14 +/** + * DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP + * + * If set to 1, the driver supports &DRM_MODE_PAGE_FLIP_ASYNC for atomic + * commits. + */ +#define DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP 0x15 /* DRM_IOCTL_GET_CAP ioctl argument type */ struct drm_get_cap { @@ -842,6 +850,31 @@ struct drm_get_cap { */ #define DRM_CLIENT_CAP_WRITEBACK_CONNECTORS 5 +/** + * DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT + * + * Drivers for para-virtualized hardware (e.g. vmwgfx, qxl, virtio and + * virtualbox) have additional restrictions for cursor planes (thus + * making cursor planes on those drivers not truly universal,) e.g. + * they need cursor planes to act like one would expect from a mouse + * cursor and have correctly set hotspot properties. + * If this client cap is not set the DRM core will hide cursor plane on + * those virtualized drivers because not setting it implies that the + * client is not capable of dealing with those extra restictions. + * Clients which do set cursor hotspot and treat the cursor plane + * like a mouse cursor should set this property. + * The client must enable &DRM_CLIENT_CAP_ATOMIC first. + * + * Setting this property on drivers which do not special case + * cursor planes (i.e. non-virtualized drivers) will return + * EOPNOTSUPP, which can be used by userspace to gauge + * requirements of the hardware/drivers they're running on. + * + * This capability is always supported for atomic-capable virtualized + * drivers starting from kernel version 6.6. + */ +#define DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT 6 + /* DRM_IOCTL_SET_CLIENT_CAP ioctl argument type */ struct drm_set_client_cap { __u64 capability; @@ -893,6 +926,7 @@ struct drm_syncobj_transfer { #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL (1 << 0) #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT (1 << 1) #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE (1 << 2) /* wait for time point to become available */ +#define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE (1 << 3) /* set fence deadline to deadline_nsec */ struct drm_syncobj_wait { __u64 handles; /* absolute timeout */ @@ -901,6 +935,14 @@ struct drm_syncobj_wait { __u32 flags; __u32 first_signaled; /* only valid when not waiting all */ __u32 pad; + /** + * @deadline_nsec - fence deadline hint + * + * Deadline hint, in absolute CLOCK_MONOTONIC, to set on backing + * fence(s) if the DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE flag is + * set. + */ + __u64 deadline_nsec; }; struct drm_syncobj_timeline_wait { @@ -913,6 +955,14 @@ struct drm_syncobj_timeline_wait { __u32 flags; __u32 first_signaled; /* only valid when not waiting all */ __u32 pad; + /** + * @deadline_nsec - fence deadline hint + * + * Deadline hint, in absolute CLOCK_MONOTONIC, to set on backing + * fence(s) if the DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE flag is + * set. + */ + __u64 deadline_nsec; }; /** @@ -1218,6 +1268,26 @@ extern "C" { #define DRM_IOCTL_SYNCOBJ_EVENTFD DRM_IOWR(0xCF, struct drm_syncobj_eventfd) +/** + * DRM_IOCTL_MODE_CLOSEFB - Close a framebuffer. + * + * This closes a framebuffer previously added via ADDFB/ADDFB2. The IOCTL + * argument is a framebuffer object ID. + * + * This IOCTL is similar to &DRM_IOCTL_MODE_RMFB, except it doesn't disable + * planes and CRTCs. As long as the framebuffer is used by a plane, it's kept + * alive. When the plane no longer uses the framebuffer (because the + * framebuffer is replaced with another one, or the plane is disabled), the + * framebuffer is cleaned up. + * + * This is useful to implement flicker-free transitions between two processes. + * + * Depending on the threat model, user-space may want to ensure that the + * framebuffer doesn't expose any sensitive user information: closed + * framebuffers attached to a plane can be read back by the next DRM master. + */ +#define DRM_IOCTL_MODE_CLOSEFB DRM_IOWR(0xD0, struct drm_mode_closefb) + /* * Device specific ioctls should only be in their respective headers * The device specific ioctl range is from 0x40 to 0x9f. diff --git a/tools/include/uapi/drm/i915_drm.h b/tools/include/uapi/drm/i915_drm.h index 218edb0a96..fd4f9574d1 100644 --- a/tools/include/uapi/drm/i915_drm.h +++ b/tools/include/uapi/drm/i915_drm.h @@ -693,7 +693,7 @@ typedef struct drm_i915_irq_wait { #define I915_PARAM_HAS_EXEC_FENCE 44 /* Query whether DRM_I915_GEM_EXECBUFFER2 supports the ability to capture - * user specified bufffers for post-mortem debugging of GPU hangs. See + * user-specified buffers for post-mortem debugging of GPU hangs. See * EXEC_OBJECT_CAPTURE. */ #define I915_PARAM_HAS_EXEC_CAPTURE 45 @@ -1606,7 +1606,7 @@ struct drm_i915_gem_busy { * is accurate. * * The returned dword is split into two fields to indicate both - * the engine classess on which the object is being read, and the + * the engine classes on which the object is being read, and the * engine class on which it is currently being written (if any). * * The low word (bits 0:15) indicate if the object is being written @@ -1815,7 +1815,7 @@ struct drm_i915_gem_madvise { __u32 handle; /* Advice: either the buffer will be needed again in the near future, - * or wont be and could be discarded under memory pressure. + * or won't be and could be discarded under memory pressure. */ __u32 madv; @@ -3246,7 +3246,7 @@ struct drm_i915_query_topology_info { * // enough to hold our array of engines. The kernel will fill out the * // item.length for us, which is the number of bytes we need. * // - * // Alternatively a large buffer can be allocated straight away enabling + * // Alternatively a large buffer can be allocated straightaway enabling * // querying in one pass, in which case item.length should contain the * // length of the provided buffer. * err = ioctl(fd, DRM_IOCTL_I915_QUERY, &query); @@ -3256,7 +3256,7 @@ struct drm_i915_query_topology_info { * // Now that we allocated the required number of bytes, we call the ioctl * // again, this time with the data_ptr pointing to our newly allocated * // blob, which the kernel can then populate with info on all engines. - * item.data_ptr = (uintptr_t)&info, + * item.data_ptr = (uintptr_t)&info; * * err = ioctl(fd, DRM_IOCTL_I915_QUERY, &query); * if (err) ... @@ -3286,7 +3286,7 @@ struct drm_i915_query_topology_info { /** * struct drm_i915_engine_info * - * Describes one engine and it's capabilities as known to the driver. + * Describes one engine and its capabilities as known to the driver. */ struct drm_i915_engine_info { /** @engine: Engine class and instance. */ diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index bda948a685..7f24d898ef 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -1074,9 +1074,11 @@ enum bpf_link_type { BPF_LINK_TYPE_TCX = 11, BPF_LINK_TYPE_UPROBE_MULTI = 12, BPF_LINK_TYPE_NETKIT = 13, - MAX_BPF_LINK_TYPE, + __MAX_BPF_LINK_TYPE, }; +#define MAX_BPF_LINK_TYPE __MAX_BPF_LINK_TYPE + enum bpf_perf_event_type { BPF_PERF_EVENT_UNSPEC = 0, BPF_PERF_EVENT_UPROBE = 1, @@ -1200,6 +1202,9 @@ enum bpf_perf_event_type { */ #define BPF_F_XDP_DEV_BOUND_ONLY (1U << 6) +/* The verifier internal test flag. Behavior is undefined */ +#define BPF_F_TEST_REG_INVARIANTS (1U << 7) + /* link_create.kprobe_multi.flags used in LINK_CREATE command for * BPF_TRACE_KPROBE_MULTI attach type to create return probe. */ @@ -6559,6 +6564,16 @@ struct bpf_link_info { __u32 flags; __u64 missed; } kprobe_multi; + struct { + __aligned_u64 path; + __aligned_u64 offsets; + __aligned_u64 ref_ctr_offsets; + __aligned_u64 cookies; + __u32 path_size; /* in/out: real path size on success, including zero byte */ + __u32 count; /* in/out: uprobe_multi offsets/ref_ctr_offsets/cookies count */ + __u32 flags; + __u32 pid; + } uprobe_multi; struct { __u32 type; /* enum bpf_perf_event_type */ __u32 :32; @@ -7154,40 +7169,31 @@ struct bpf_spin_lock { }; struct bpf_timer { - __u64 :64; - __u64 :64; + __u64 __opaque[2]; } __attribute__((aligned(8))); struct bpf_dynptr { - __u64 :64; - __u64 :64; + __u64 __opaque[2]; } __attribute__((aligned(8))); struct bpf_list_head { - __u64 :64; - __u64 :64; + __u64 __opaque[2]; } __attribute__((aligned(8))); struct bpf_list_node { - __u64 :64; - __u64 :64; - __u64 :64; + __u64 __opaque[3]; } __attribute__((aligned(8))); struct bpf_rb_root { - __u64 :64; - __u64 :64; + __u64 __opaque[2]; } __attribute__((aligned(8))); struct bpf_rb_node { - __u64 :64; - __u64 :64; - __u64 :64; - __u64 :64; + __u64 __opaque[4]; } __attribute__((aligned(8))); struct bpf_refcount { - __u32 :32; + __u32 __opaque[1]; } __attribute__((aligned(4))); struct bpf_sysctl { diff --git a/tools/include/uapi/linux/fcntl.h b/tools/include/uapi/linux/fcntl.h index 6c80f96049..282e90aeb1 100644 --- a/tools/include/uapi/linux/fcntl.h +++ b/tools/include/uapi/linux/fcntl.h @@ -116,5 +116,8 @@ #define AT_HANDLE_FID AT_REMOVEDIR /* file handle is needed to compare object identity and may not be usable to open_by_handle_at(2) */ +#if defined(__KERNEL__) +#define AT_GETATTR_NOSEC 0x80000000 +#endif #endif /* _UAPI_LINUX_FCNTL_H */ diff --git a/tools/include/uapi/linux/fs.h b/tools/include/uapi/linux/fs.h index da43810b74..48ad69f772 100644 --- a/tools/include/uapi/linux/fs.h +++ b/tools/include/uapi/linux/fs.h @@ -316,6 +316,7 @@ typedef int __bitwise __kernel_rwf_t; #define PAGE_IS_SWAPPED (1 << 4) #define PAGE_IS_PFNZERO (1 << 5) #define PAGE_IS_HUGE (1 << 6) +#define PAGE_IS_SOFT_DIRTY (1 << 7) /* * struct page_region - Page region with flags diff --git a/tools/include/uapi/linux/if_xdp.h b/tools/include/uapi/linux/if_xdp.h index 73a47da885..638c606dfa 100644 --- a/tools/include/uapi/linux/if_xdp.h +++ b/tools/include/uapi/linux/if_xdp.h @@ -26,14 +26,20 @@ */ #define XDP_USE_NEED_WAKEUP (1 << 3) /* By setting this option, userspace application indicates that it can - * handle multiple descriptors per packet thus enabling xsk core to split + * handle multiple descriptors per packet thus enabling AF_XDP to split * multi-buffer XDP frames into multiple Rx descriptors. Without this set - * such frames will be dropped by xsk. + * such frames will be dropped. */ -#define XDP_USE_SG (1 << 4) +#define XDP_USE_SG (1 << 4) /* Flags for xsk_umem_config flags */ -#define XDP_UMEM_UNALIGNED_CHUNK_FLAG (1 << 0) +#define XDP_UMEM_UNALIGNED_CHUNK_FLAG (1 << 0) + +/* Force checksum calculation in software. Can be used for testing or + * working around potential HW issues. This option causes performance + * degradation and only works in XDP_COPY mode. + */ +#define XDP_UMEM_TX_SW_CSUM (1 << 1) struct sockaddr_xdp { __u16 sxdp_family; @@ -76,6 +82,7 @@ struct xdp_umem_reg { __u32 chunk_size; __u32 headroom; __u32 flags; + __u32 tx_metadata_len; }; struct xdp_statistics { @@ -105,6 +112,41 @@ struct xdp_options { #define XSK_UNALIGNED_BUF_ADDR_MASK \ ((1ULL << XSK_UNALIGNED_BUF_OFFSET_SHIFT) - 1) +/* Request transmit timestamp. Upon completion, put it into tx_timestamp + * field of union xsk_tx_metadata. + */ +#define XDP_TXMD_FLAGS_TIMESTAMP (1 << 0) + +/* Request transmit checksum offload. Checksum start position and offset + * are communicated via csum_start and csum_offset fields of union + * xsk_tx_metadata. + */ +#define XDP_TXMD_FLAGS_CHECKSUM (1 << 1) + +/* AF_XDP offloads request. 'request' union member is consumed by the driver + * when the packet is being transmitted. 'completion' union member is + * filled by the driver when the transmit completion arrives. + */ +struct xsk_tx_metadata { + __u64 flags; + + union { + struct { + /* XDP_TXMD_FLAGS_CHECKSUM */ + + /* Offset from desc->addr where checksumming should start. */ + __u16 csum_start; + /* Offset from csum_start where checksum should be stored. */ + __u16 csum_offset; + } request; + + struct { + /* XDP_TXMD_FLAGS_TIMESTAMP */ + __u64 tx_timestamp; + } completion; + }; +}; + /* Rx/Tx descriptor */ struct xdp_desc { __u64 addr; @@ -112,9 +154,16 @@ struct xdp_desc { __u32 options; }; -/* Flag indicating packet constitutes of multiple buffers*/ +/* UMEM descriptor is __u64 */ + +/* Flag indicating that the packet continues with the buffer pointed out by the + * next frame in the ring. The end of the packet is signalled by setting this + * bit to zero. For single buffer packets, every descriptor has 'options' set + * to 0 and this maintains backward compatibility. + */ #define XDP_PKT_CONTD (1 << 0) -/* UMEM descriptor is __u64 */ +/* TX packet carries valid metadata. */ +#define XDP_TX_METADATA (1 << 1) #endif /* _LINUX_IF_XDP_H */ diff --git a/tools/include/uapi/linux/kvm.h b/tools/include/uapi/linux/kvm.h index 211b86de35..c330853648 100644 --- a/tools/include/uapi/linux/kvm.h +++ b/tools/include/uapi/linux/kvm.h @@ -16,76 +16,6 @@ #define KVM_API_VERSION 12 -/* *** Deprecated interfaces *** */ - -#define KVM_TRC_SHIFT 16 - -#define KVM_TRC_ENTRYEXIT (1 << KVM_TRC_SHIFT) -#define KVM_TRC_HANDLER (1 << (KVM_TRC_SHIFT + 1)) - -#define KVM_TRC_VMENTRY (KVM_TRC_ENTRYEXIT + 0x01) -#define KVM_TRC_VMEXIT (KVM_TRC_ENTRYEXIT + 0x02) -#define KVM_TRC_PAGE_FAULT (KVM_TRC_HANDLER + 0x01) - -#define KVM_TRC_HEAD_SIZE 12 -#define KVM_TRC_CYCLE_SIZE 8 -#define KVM_TRC_EXTRA_MAX 7 - -#define KVM_TRC_INJ_VIRQ (KVM_TRC_HANDLER + 0x02) -#define KVM_TRC_REDELIVER_EVT (KVM_TRC_HANDLER + 0x03) -#define KVM_TRC_PEND_INTR (KVM_TRC_HANDLER + 0x04) -#define KVM_TRC_IO_READ (KVM_TRC_HANDLER + 0x05) -#define KVM_TRC_IO_WRITE (KVM_TRC_HANDLER + 0x06) -#define KVM_TRC_CR_READ (KVM_TRC_HANDLER + 0x07) -#define KVM_TRC_CR_WRITE (KVM_TRC_HANDLER + 0x08) -#define KVM_TRC_DR_READ (KVM_TRC_HANDLER + 0x09) -#define KVM_TRC_DR_WRITE (KVM_TRC_HANDLER + 0x0A) -#define KVM_TRC_MSR_READ (KVM_TRC_HANDLER + 0x0B) -#define KVM_TRC_MSR_WRITE (KVM_TRC_HANDLER + 0x0C) -#define KVM_TRC_CPUID (KVM_TRC_HANDLER + 0x0D) -#define KVM_TRC_INTR (KVM_TRC_HANDLER + 0x0E) -#define KVM_TRC_NMI (KVM_TRC_HANDLER + 0x0F) -#define KVM_TRC_VMMCALL (KVM_TRC_HANDLER + 0x10) -#define KVM_TRC_HLT (KVM_TRC_HANDLER + 0x11) -#define KVM_TRC_CLTS (KVM_TRC_HANDLER + 0x12) -#define KVM_TRC_LMSW (KVM_TRC_HANDLER + 0x13) -#define KVM_TRC_APIC_ACCESS (KVM_TRC_HANDLER + 0x14) -#define KVM_TRC_TDP_FAULT (KVM_TRC_HANDLER + 0x15) -#define KVM_TRC_GTLB_WRITE (KVM_TRC_HANDLER + 0x16) -#define KVM_TRC_STLB_WRITE (KVM_TRC_HANDLER + 0x17) -#define KVM_TRC_STLB_INVAL (KVM_TRC_HANDLER + 0x18) -#define KVM_TRC_PPC_INSTR (KVM_TRC_HANDLER + 0x19) - -struct kvm_user_trace_setup { - __u32 buf_size; - __u32 buf_nr; -}; - -#define __KVM_DEPRECATED_MAIN_W_0x06 \ - _IOW(KVMIO, 0x06, struct kvm_user_trace_setup) -#define __KVM_DEPRECATED_MAIN_0x07 _IO(KVMIO, 0x07) -#define __KVM_DEPRECATED_MAIN_0x08 _IO(KVMIO, 0x08) - -#define __KVM_DEPRECATED_VM_R_0x70 _IOR(KVMIO, 0x70, struct kvm_assigned_irq) - -struct kvm_breakpoint { - __u32 enabled; - __u32 padding; - __u64 address; -}; - -struct kvm_debug_guest { - __u32 enabled; - __u32 pad; - struct kvm_breakpoint breakpoints[4]; - __u32 singlestep; -}; - -#define __KVM_DEPRECATED_VCPU_W_0x87 _IOW(KVMIO, 0x87, struct kvm_debug_guest) - -/* *** End of deprecated interfaces *** */ - - /* for KVM_SET_USER_MEMORY_REGION */ struct kvm_userspace_memory_region { __u32 slot; @@ -95,6 +25,19 @@ struct kvm_userspace_memory_region { __u64 userspace_addr; /* start of the userspace allocated memory */ }; +/* for KVM_SET_USER_MEMORY_REGION2 */ +struct kvm_userspace_memory_region2 { + __u32 slot; + __u32 flags; + __u64 guest_phys_addr; + __u64 memory_size; + __u64 userspace_addr; + __u64 guest_memfd_offset; + __u32 guest_memfd; + __u32 pad1; + __u64 pad2[14]; +}; + /* * The bit 0 ~ bit 15 of kvm_userspace_memory_region::flags are visible for * userspace, other bits are reserved for kvm internal use which are defined @@ -102,6 +45,7 @@ struct kvm_userspace_memory_region { */ #define KVM_MEM_LOG_DIRTY_PAGES (1UL << 0) #define KVM_MEM_READONLY (1UL << 1) +#define KVM_MEM_GUEST_MEMFD (1UL << 2) /* for KVM_IRQ_LINE */ struct kvm_irq_level { @@ -265,6 +209,7 @@ struct kvm_xen_exit { #define KVM_EXIT_RISCV_CSR 36 #define KVM_EXIT_NOTIFY 37 #define KVM_EXIT_LOONGARCH_IOCSR 38 +#define KVM_EXIT_MEMORY_FAULT 39 /* For KVM_EXIT_INTERNAL_ERROR */ /* Emulate instruction failed. */ @@ -518,6 +463,13 @@ struct kvm_run { #define KVM_NOTIFY_CONTEXT_INVALID (1 << 0) __u32 flags; } notify; + /* KVM_EXIT_MEMORY_FAULT */ + struct { +#define KVM_MEMORY_EXIT_FLAG_PRIVATE (1ULL << 3) + __u64 flags; + __u64 gpa; + __u64 size; + } memory_fault; /* Fix the size of the union. */ char padding[256]; }; @@ -945,9 +897,6 @@ struct kvm_ppc_resize_hpt { */ #define KVM_GET_VCPU_MMAP_SIZE _IO(KVMIO, 0x04) /* in bytes */ #define KVM_GET_SUPPORTED_CPUID _IOWR(KVMIO, 0x05, struct kvm_cpuid2) -#define KVM_TRACE_ENABLE __KVM_DEPRECATED_MAIN_W_0x06 -#define KVM_TRACE_PAUSE __KVM_DEPRECATED_MAIN_0x07 -#define KVM_TRACE_DISABLE __KVM_DEPRECATED_MAIN_0x08 #define KVM_GET_EMULATED_CPUID _IOWR(KVMIO, 0x09, struct kvm_cpuid2) #define KVM_GET_MSR_FEATURE_INDEX_LIST _IOWR(KVMIO, 0x0a, struct kvm_msr_list) @@ -1201,6 +1150,11 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_ARM_EAGER_SPLIT_CHUNK_SIZE 228 #define KVM_CAP_ARM_SUPPORTED_BLOCK_SIZES 229 #define KVM_CAP_ARM_SUPPORTED_REG_MASK_RANGES 230 +#define KVM_CAP_USER_MEMORY2 231 +#define KVM_CAP_MEMORY_FAULT_INFO 232 +#define KVM_CAP_MEMORY_ATTRIBUTES 233 +#define KVM_CAP_GUEST_MEMFD 234 +#define KVM_CAP_VM_TYPES 235 #ifdef KVM_CAP_IRQ_ROUTING @@ -1291,6 +1245,7 @@ struct kvm_x86_mce { #define KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL (1 << 4) #define KVM_XEN_HVM_CONFIG_EVTCHN_SEND (1 << 5) #define KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG (1 << 6) +#define KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE (1 << 7) struct kvm_xen_hvm_config { __u32 flags; @@ -1483,6 +1438,8 @@ struct kvm_vfio_spapr_tce { struct kvm_userspace_memory_region) #define KVM_SET_TSS_ADDR _IO(KVMIO, 0x47) #define KVM_SET_IDENTITY_MAP_ADDR _IOW(KVMIO, 0x48, __u64) +#define KVM_SET_USER_MEMORY_REGION2 _IOW(KVMIO, 0x49, \ + struct kvm_userspace_memory_region2) /* enable ucontrol for s390 */ struct kvm_s390_ucas_mapping { @@ -1507,20 +1464,8 @@ struct kvm_s390_ucas_mapping { _IOW(KVMIO, 0x67, struct kvm_coalesced_mmio_zone) #define KVM_UNREGISTER_COALESCED_MMIO \ _IOW(KVMIO, 0x68, struct kvm_coalesced_mmio_zone) -#define KVM_ASSIGN_PCI_DEVICE _IOR(KVMIO, 0x69, \ - struct kvm_assigned_pci_dev) #define KVM_SET_GSI_ROUTING _IOW(KVMIO, 0x6a, struct kvm_irq_routing) -/* deprecated, replaced by KVM_ASSIGN_DEV_IRQ */ -#define KVM_ASSIGN_IRQ __KVM_DEPRECATED_VM_R_0x70 -#define KVM_ASSIGN_DEV_IRQ _IOW(KVMIO, 0x70, struct kvm_assigned_irq) #define KVM_REINJECT_CONTROL _IO(KVMIO, 0x71) -#define KVM_DEASSIGN_PCI_DEVICE _IOW(KVMIO, 0x72, \ - struct kvm_assigned_pci_dev) -#define KVM_ASSIGN_SET_MSIX_NR _IOW(KVMIO, 0x73, \ - struct kvm_assigned_msix_nr) -#define KVM_ASSIGN_SET_MSIX_ENTRY _IOW(KVMIO, 0x74, \ - struct kvm_assigned_msix_entry) -#define KVM_DEASSIGN_DEV_IRQ _IOW(KVMIO, 0x75, struct kvm_assigned_irq) #define KVM_IRQFD _IOW(KVMIO, 0x76, struct kvm_irqfd) #define KVM_CREATE_PIT2 _IOW(KVMIO, 0x77, struct kvm_pit_config) #define KVM_SET_BOOT_CPU_ID _IO(KVMIO, 0x78) @@ -1537,9 +1482,6 @@ struct kvm_s390_ucas_mapping { * KVM_CAP_VM_TSC_CONTROL to set defaults for a VM */ #define KVM_SET_TSC_KHZ _IO(KVMIO, 0xa2) #define KVM_GET_TSC_KHZ _IO(KVMIO, 0xa3) -/* Available with KVM_CAP_PCI_2_3 */ -#define KVM_ASSIGN_SET_INTX_MASK _IOW(KVMIO, 0xa4, \ - struct kvm_assigned_pci_dev) /* Available with KVM_CAP_SIGNAL_MSI */ #define KVM_SIGNAL_MSI _IOW(KVMIO, 0xa5, struct kvm_msi) /* Available with KVM_CAP_PPC_GET_SMMU_INFO */ @@ -1592,8 +1534,6 @@ struct kvm_s390_ucas_mapping { #define KVM_SET_SREGS _IOW(KVMIO, 0x84, struct kvm_sregs) #define KVM_TRANSLATE _IOWR(KVMIO, 0x85, struct kvm_translation) #define KVM_INTERRUPT _IOW(KVMIO, 0x86, struct kvm_interrupt) -/* KVM_DEBUG_GUEST is no longer supported, use KVM_SET_GUEST_DEBUG instead */ -#define KVM_DEBUG_GUEST __KVM_DEPRECATED_VCPU_W_0x87 #define KVM_GET_MSRS _IOWR(KVMIO, 0x88, struct kvm_msrs) #define KVM_SET_MSRS _IOW(KVMIO, 0x89, struct kvm_msrs) #define KVM_SET_CPUID _IOW(KVMIO, 0x8a, struct kvm_cpuid) @@ -2267,4 +2207,24 @@ struct kvm_s390_zpci_op { /* flags for kvm_s390_zpci_op->u.reg_aen.flags */ #define KVM_S390_ZPCIOP_REGAEN_HOST (1 << 0) +/* Available with KVM_CAP_MEMORY_ATTRIBUTES */ +#define KVM_SET_MEMORY_ATTRIBUTES _IOW(KVMIO, 0xd2, struct kvm_memory_attributes) + +struct kvm_memory_attributes { + __u64 address; + __u64 size; + __u64 attributes; + __u64 flags; +}; + +#define KVM_MEMORY_ATTRIBUTE_PRIVATE (1ULL << 3) + +#define KVM_CREATE_GUEST_MEMFD _IOWR(KVMIO, 0xd4, struct kvm_create_guest_memfd) + +struct kvm_create_guest_memfd { + __u64 size; + __u64 flags; + __u64 reserved[6]; +}; + #endif /* __LINUX_KVM_H */ diff --git a/tools/include/uapi/linux/mount.h b/tools/include/uapi/linux/mount.h index bb242fdcfe..ad5478dbad 100644 --- a/tools/include/uapi/linux/mount.h +++ b/tools/include/uapi/linux/mount.h @@ -138,4 +138,74 @@ struct mount_attr { /* List of all mount_attr versions. */ #define MOUNT_ATTR_SIZE_VER0 32 /* sizeof first published struct */ + +/* + * Structure for getting mount/superblock/filesystem info with statmount(2). + * + * The interface is similar to statx(2): individual fields or groups can be + * selected with the @mask argument of statmount(). Kernel will set the @mask + * field according to the supported fields. + * + * If string fields are selected, then the caller needs to pass a buffer that + * has space after the fixed part of the structure. Nul terminated strings are + * copied there and offsets relative to @str are stored in the relevant fields. + * If the buffer is too small, then EOVERFLOW is returned. The actually used + * size is returned in @size. + */ +struct statmount { + __u32 size; /* Total size, including strings */ + __u32 __spare1; + __u64 mask; /* What results were written */ + __u32 sb_dev_major; /* Device ID */ + __u32 sb_dev_minor; + __u64 sb_magic; /* ..._SUPER_MAGIC */ + __u32 sb_flags; /* SB_{RDONLY,SYNCHRONOUS,DIRSYNC,LAZYTIME} */ + __u32 fs_type; /* [str] Filesystem type */ + __u64 mnt_id; /* Unique ID of mount */ + __u64 mnt_parent_id; /* Unique ID of parent (for root == mnt_id) */ + __u32 mnt_id_old; /* Reused IDs used in proc/.../mountinfo */ + __u32 mnt_parent_id_old; + __u64 mnt_attr; /* MOUNT_ATTR_... */ + __u64 mnt_propagation; /* MS_{SHARED,SLAVE,PRIVATE,UNBINDABLE} */ + __u64 mnt_peer_group; /* ID of shared peer group */ + __u64 mnt_master; /* Mount receives propagation from this ID */ + __u64 propagate_from; /* Propagation from in current namespace */ + __u32 mnt_root; /* [str] Root of mount relative to root of fs */ + __u32 mnt_point; /* [str] Mountpoint relative to current root */ + __u64 __spare2[50]; + char str[]; /* Variable size part containing strings */ +}; + +/* + * Structure for passing mount ID and miscellaneous parameters to statmount(2) + * and listmount(2). + * + * For statmount(2) @param represents the request mask. + * For listmount(2) @param represents the last listed mount id (or zero). + */ +struct mnt_id_req { + __u32 size; + __u32 spare; + __u64 mnt_id; + __u64 param; +}; + +/* List of all mnt_id_req versions. */ +#define MNT_ID_REQ_SIZE_VER0 24 /* sizeof first published struct */ + +/* + * @mask bits for statmount(2) + */ +#define STATMOUNT_SB_BASIC 0x00000001U /* Want/got sb_... */ +#define STATMOUNT_MNT_BASIC 0x00000002U /* Want/got mnt_... */ +#define STATMOUNT_PROPAGATE_FROM 0x00000004U /* Want/got propagate_from */ +#define STATMOUNT_MNT_ROOT 0x00000008U /* Want/got mnt_root */ +#define STATMOUNT_MNT_POINT 0x00000010U /* Want/got mnt_point */ +#define STATMOUNT_FS_TYPE 0x00000020U /* Want/got fs_type */ + +/* + * Special @mnt_id values that can be passed to listmount + */ +#define LSMT_ROOT 0xffffffffffffffff /* root mount */ + #endif /* _UAPI_LINUX_MOUNT_H */ diff --git a/tools/include/uapi/linux/netdev.h b/tools/include/uapi/linux/netdev.h index 2943a151d4..93cb411adf 100644 --- a/tools/include/uapi/linux/netdev.h +++ b/tools/include/uapi/linux/netdev.h @@ -44,13 +44,30 @@ enum netdev_xdp_act { * timestamp via bpf_xdp_metadata_rx_timestamp(). * @NETDEV_XDP_RX_METADATA_HASH: Device is capable of exposing receive packet * hash via bpf_xdp_metadata_rx_hash(). + * @NETDEV_XDP_RX_METADATA_VLAN_TAG: Device is capable of exposing receive + * packet VLAN tag via bpf_xdp_metadata_rx_vlan_tag(). */ enum netdev_xdp_rx_metadata { NETDEV_XDP_RX_METADATA_TIMESTAMP = 1, NETDEV_XDP_RX_METADATA_HASH = 2, + NETDEV_XDP_RX_METADATA_VLAN_TAG = 4, +}; - /* private: */ - NETDEV_XDP_RX_METADATA_MASK = 3, +/** + * enum netdev_xsk_flags + * @NETDEV_XSK_FLAGS_TX_TIMESTAMP: HW timestamping egress packets is supported + * by the driver. + * @NETDEV_XSK_FLAGS_TX_CHECKSUM: L3 checksum HW offload is supported by the + * driver. + */ +enum netdev_xsk_flags { + NETDEV_XSK_FLAGS_TX_TIMESTAMP = 1, + NETDEV_XSK_FLAGS_TX_CHECKSUM = 2, +}; + +enum netdev_queue_type { + NETDEV_QUEUE_TYPE_RX, + NETDEV_QUEUE_TYPE_TX, }; enum { @@ -59,21 +76,80 @@ enum { NETDEV_A_DEV_XDP_FEATURES, NETDEV_A_DEV_XDP_ZC_MAX_SEGS, NETDEV_A_DEV_XDP_RX_METADATA_FEATURES, + NETDEV_A_DEV_XSK_FEATURES, __NETDEV_A_DEV_MAX, NETDEV_A_DEV_MAX = (__NETDEV_A_DEV_MAX - 1) }; +enum { + NETDEV_A_PAGE_POOL_ID = 1, + NETDEV_A_PAGE_POOL_IFINDEX, + NETDEV_A_PAGE_POOL_NAPI_ID, + NETDEV_A_PAGE_POOL_INFLIGHT, + NETDEV_A_PAGE_POOL_INFLIGHT_MEM, + NETDEV_A_PAGE_POOL_DETACH_TIME, + + __NETDEV_A_PAGE_POOL_MAX, + NETDEV_A_PAGE_POOL_MAX = (__NETDEV_A_PAGE_POOL_MAX - 1) +}; + +enum { + NETDEV_A_PAGE_POOL_STATS_INFO = 1, + NETDEV_A_PAGE_POOL_STATS_ALLOC_FAST = 8, + NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW, + NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW_HIGH_ORDER, + NETDEV_A_PAGE_POOL_STATS_ALLOC_EMPTY, + NETDEV_A_PAGE_POOL_STATS_ALLOC_REFILL, + NETDEV_A_PAGE_POOL_STATS_ALLOC_WAIVE, + NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHED, + NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHE_FULL, + NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING, + NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING_FULL, + NETDEV_A_PAGE_POOL_STATS_RECYCLE_RELEASED_REFCNT, + + __NETDEV_A_PAGE_POOL_STATS_MAX, + NETDEV_A_PAGE_POOL_STATS_MAX = (__NETDEV_A_PAGE_POOL_STATS_MAX - 1) +}; + +enum { + NETDEV_A_NAPI_IFINDEX = 1, + NETDEV_A_NAPI_ID, + NETDEV_A_NAPI_IRQ, + NETDEV_A_NAPI_PID, + + __NETDEV_A_NAPI_MAX, + NETDEV_A_NAPI_MAX = (__NETDEV_A_NAPI_MAX - 1) +}; + +enum { + NETDEV_A_QUEUE_ID = 1, + NETDEV_A_QUEUE_IFINDEX, + NETDEV_A_QUEUE_TYPE, + NETDEV_A_QUEUE_NAPI_ID, + + __NETDEV_A_QUEUE_MAX, + NETDEV_A_QUEUE_MAX = (__NETDEV_A_QUEUE_MAX - 1) +}; + enum { NETDEV_CMD_DEV_GET = 1, NETDEV_CMD_DEV_ADD_NTF, NETDEV_CMD_DEV_DEL_NTF, NETDEV_CMD_DEV_CHANGE_NTF, + NETDEV_CMD_PAGE_POOL_GET, + NETDEV_CMD_PAGE_POOL_ADD_NTF, + NETDEV_CMD_PAGE_POOL_DEL_NTF, + NETDEV_CMD_PAGE_POOL_CHANGE_NTF, + NETDEV_CMD_PAGE_POOL_STATS_GET, + NETDEV_CMD_QUEUE_GET, + NETDEV_CMD_NAPI_GET, __NETDEV_CMD_MAX, NETDEV_CMD_MAX = (__NETDEV_CMD_MAX - 1) }; #define NETDEV_MCGRP_MGMT "mgmt" +#define NETDEV_MCGRP_PAGE_POOL "page-pool" #endif /* _UAPI_LINUX_NETDEV_H */ diff --git a/tools/include/uapi/linux/perf_event.h b/tools/include/uapi/linux/perf_event.h index 39c6a250dd..3a64499b0f 100644 --- a/tools/include/uapi/linux/perf_event.h +++ b/tools/include/uapi/linux/perf_event.h @@ -204,6 +204,8 @@ enum perf_branch_sample_type_shift { PERF_SAMPLE_BRANCH_PRIV_SAVE_SHIFT = 18, /* save privilege mode */ + PERF_SAMPLE_BRANCH_COUNTERS_SHIFT = 19, /* save occurrences of events on a branch */ + PERF_SAMPLE_BRANCH_MAX_SHIFT /* non-ABI */ }; @@ -235,6 +237,8 @@ enum perf_branch_sample_type { PERF_SAMPLE_BRANCH_PRIV_SAVE = 1U << PERF_SAMPLE_BRANCH_PRIV_SAVE_SHIFT, + PERF_SAMPLE_BRANCH_COUNTERS = 1U << PERF_SAMPLE_BRANCH_COUNTERS_SHIFT, + PERF_SAMPLE_BRANCH_MAX = 1U << PERF_SAMPLE_BRANCH_MAX_SHIFT, }; @@ -982,6 +986,12 @@ enum perf_event_type { * { u64 nr; * { u64 hw_idx; } && PERF_SAMPLE_BRANCH_HW_INDEX * { u64 from, to, flags } lbr[nr]; + * # + * # The format of the counters is decided by the + * # "branch_counter_nr" and "branch_counter_width", + * # which are defined in the ABI. + * # + * { u64 counters; } cntr[nr] && PERF_SAMPLE_BRANCH_COUNTERS * } && PERF_SAMPLE_BRANCH_STACK * * { u64 abi; # enum perf_sample_regs_abi @@ -1427,6 +1437,9 @@ struct perf_branch_entry { reserved:31; }; +/* Size of used info bits in struct perf_branch_entry */ +#define PERF_BRANCH_ENTRY_INFO_BITS_MAX 33 + union perf_sample_weight { __u64 full; #if defined(__LITTLE_ENDIAN_BITFIELD) diff --git a/tools/include/uapi/linux/pkt_cls.h b/tools/include/uapi/linux/pkt_cls.h index 3faee0199a..bd4b227ab4 100644 --- a/tools/include/uapi/linux/pkt_cls.h +++ b/tools/include/uapi/linux/pkt_cls.h @@ -204,37 +204,6 @@ struct tc_u32_pcnt { #define TC_U32_MAXDEPTH 8 - -/* RSVP filter */ - -enum { - TCA_RSVP_UNSPEC, - TCA_RSVP_CLASSID, - TCA_RSVP_DST, - TCA_RSVP_SRC, - TCA_RSVP_PINFO, - TCA_RSVP_POLICE, - TCA_RSVP_ACT, - __TCA_RSVP_MAX -}; - -#define TCA_RSVP_MAX (__TCA_RSVP_MAX - 1 ) - -struct tc_rsvp_gpi { - __u32 key; - __u32 mask; - int offset; -}; - -struct tc_rsvp_pinfo { - struct tc_rsvp_gpi dpi; - struct tc_rsvp_gpi spi; - __u8 protocol; - __u8 tunnelid; - __u8 tunnelhdr; - __u8 pad; -}; - /* ROUTE filter */ enum { @@ -265,22 +234,6 @@ enum { #define TCA_FW_MAX (__TCA_FW_MAX - 1) -/* TC index filter */ - -enum { - TCA_TCINDEX_UNSPEC, - TCA_TCINDEX_HASH, - TCA_TCINDEX_MASK, - TCA_TCINDEX_SHIFT, - TCA_TCINDEX_FALL_THROUGH, - TCA_TCINDEX_CLASSID, - TCA_TCINDEX_POLICE, - TCA_TCINDEX_ACT, - __TCA_TCINDEX_MAX -}; - -#define TCA_TCINDEX_MAX (__TCA_TCINDEX_MAX - 1) - /* Flow filter */ enum { diff --git a/tools/include/uapi/linux/pkt_sched.h b/tools/include/uapi/linux/pkt_sched.h index 5c903abc9f..587481a194 100644 --- a/tools/include/uapi/linux/pkt_sched.h +++ b/tools/include/uapi/linux/pkt_sched.h @@ -457,115 +457,6 @@ enum { #define TCA_HFSC_MAX (__TCA_HFSC_MAX - 1) - -/* CBQ section */ - -#define TC_CBQ_MAXPRIO 8 -#define TC_CBQ_MAXLEVEL 8 -#define TC_CBQ_DEF_EWMA 5 - -struct tc_cbq_lssopt { - unsigned char change; - unsigned char flags; -#define TCF_CBQ_LSS_BOUNDED 1 -#define TCF_CBQ_LSS_ISOLATED 2 - unsigned char ewma_log; - unsigned char level; -#define TCF_CBQ_LSS_FLAGS 1 -#define TCF_CBQ_LSS_EWMA 2 -#define TCF_CBQ_LSS_MAXIDLE 4 -#define TCF_CBQ_LSS_MINIDLE 8 -#define TCF_CBQ_LSS_OFFTIME 0x10 -#define TCF_CBQ_LSS_AVPKT 0x20 - __u32 maxidle; - __u32 minidle; - __u32 offtime; - __u32 avpkt; -}; - -struct tc_cbq_wrropt { - unsigned char flags; - unsigned char priority; - unsigned char cpriority; - unsigned char __reserved; - __u32 allot; - __u32 weight; -}; - -struct tc_cbq_ovl { - unsigned char strategy; -#define TC_CBQ_OVL_CLASSIC 0 -#define TC_CBQ_OVL_DELAY 1 -#define TC_CBQ_OVL_LOWPRIO 2 -#define TC_CBQ_OVL_DROP 3 -#define TC_CBQ_OVL_RCLASSIC 4 - unsigned char priority2; - __u16 pad; - __u32 penalty; -}; - -struct tc_cbq_police { - unsigned char police; - unsigned char __res1; - unsigned short __res2; -}; - -struct tc_cbq_fopt { - __u32 split; - __u32 defmap; - __u32 defchange; -}; - -struct tc_cbq_xstats { - __u32 borrows; - __u32 overactions; - __s32 avgidle; - __s32 undertime; -}; - -enum { - TCA_CBQ_UNSPEC, - TCA_CBQ_LSSOPT, - TCA_CBQ_WRROPT, - TCA_CBQ_FOPT, - TCA_CBQ_OVL_STRATEGY, - TCA_CBQ_RATE, - TCA_CBQ_RTAB, - TCA_CBQ_POLICE, - __TCA_CBQ_MAX, -}; - -#define TCA_CBQ_MAX (__TCA_CBQ_MAX - 1) - -/* dsmark section */ - -enum { - TCA_DSMARK_UNSPEC, - TCA_DSMARK_INDICES, - TCA_DSMARK_DEFAULT_INDEX, - TCA_DSMARK_SET_TC_INDEX, - TCA_DSMARK_MASK, - TCA_DSMARK_VALUE, - __TCA_DSMARK_MAX, -}; - -#define TCA_DSMARK_MAX (__TCA_DSMARK_MAX - 1) - -/* ATM section */ - -enum { - TCA_ATM_UNSPEC, - TCA_ATM_FD, /* file/socket descriptor */ - TCA_ATM_PTR, /* pointer to descriptor - later */ - TCA_ATM_HDR, /* LL header */ - TCA_ATM_EXCESS, /* excess traffic class (0 for CLP) */ - TCA_ATM_ADDR, /* PVC address (for output only) */ - TCA_ATM_STATE, /* VC state (ATM_VS_*; for output only) */ - __TCA_ATM_MAX, -}; - -#define TCA_ATM_MAX (__TCA_ATM_MAX - 1) - /* Network emulator */ enum { diff --git a/tools/include/uapi/linux/stat.h b/tools/include/uapi/linux/stat.h index 7cab2c65d3..2f2ee82d55 100644 --- a/tools/include/uapi/linux/stat.h +++ b/tools/include/uapi/linux/stat.h @@ -154,6 +154,7 @@ struct statx { #define STATX_BTIME 0x00000800U /* Want/got stx_btime */ #define STATX_MNT_ID 0x00001000U /* Got stx_mnt_id */ #define STATX_DIOALIGN 0x00002000U /* Want/got direct I/O alignment info */ +#define STATX_MNT_ID_UNIQUE 0x00004000U /* Want/got extended stx_mount_id */ #define STATX__RESERVED 0x80000000U /* Reserved for future struct statx expansion */ diff --git a/tools/include/uapi/sound/asound.h b/tools/include/uapi/sound/asound.h index f9939da411..d5b9cfbd9c 100644 --- a/tools/include/uapi/sound/asound.h +++ b/tools/include/uapi/sound/asound.h @@ -142,7 +142,7 @@ struct snd_hwdep_dsp_image { * * *****************************************************************************/ -#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 15) +#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 16) typedef unsigned long snd_pcm_uframes_t; typedef signed long snd_pcm_sframes_t; @@ -267,7 +267,10 @@ typedef int __bitwise snd_pcm_format_t; typedef int __bitwise snd_pcm_subformat_t; #define SNDRV_PCM_SUBFORMAT_STD ((__force snd_pcm_subformat_t) 0) -#define SNDRV_PCM_SUBFORMAT_LAST SNDRV_PCM_SUBFORMAT_STD +#define SNDRV_PCM_SUBFORMAT_MSBITS_MAX ((__force snd_pcm_subformat_t) 1) +#define SNDRV_PCM_SUBFORMAT_MSBITS_20 ((__force snd_pcm_subformat_t) 2) +#define SNDRV_PCM_SUBFORMAT_MSBITS_24 ((__force snd_pcm_subformat_t) 3) +#define SNDRV_PCM_SUBFORMAT_LAST SNDRV_PCM_SUBFORMAT_MSBITS_24 #define SNDRV_PCM_INFO_MMAP 0x00000001 /* hardware supports mmap */ #define SNDRV_PCM_INFO_MMAP_VALID 0x00000002 /* period data are valid during transfer */ diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c index 5cb0eeec2c..337fde770e 100644 --- a/tools/lib/api/fs/fs.c +++ b/tools/lib/api/fs/fs.c @@ -16,6 +16,7 @@ #include #include "fs.h" +#include "../io.h" #include "debug-internal.h" #define _STR(x) #x @@ -344,53 +345,24 @@ int filename__read_ull(const char *filename, unsigned long long *value) return filename__read_ull_base(filename, value, 0); } -#define STRERR_BUFSIZE 128 /* For the buffer size of strerror_r */ - int filename__read_str(const char *filename, char **buf, size_t *sizep) { - size_t size = 0, alloc_size = 0; - void *bf = NULL, *nbf; - int fd, n, err = 0; - char sbuf[STRERR_BUFSIZE]; + struct io io; + char bf[128]; + int err; - fd = open(filename, O_RDONLY); - if (fd < 0) + io.fd = open(filename, O_RDONLY); + if (io.fd < 0) return -errno; - - do { - if (size == alloc_size) { - alloc_size += BUFSIZ; - nbf = realloc(bf, alloc_size); - if (!nbf) { - err = -ENOMEM; - break; - } - - bf = nbf; - } - - n = read(fd, bf + size, alloc_size - size); - if (n < 0) { - if (size) { - pr_warn("read failed %d: %s\n", errno, - strerror_r(errno, sbuf, sizeof(sbuf))); - err = 0; - } else - err = -errno; - - break; - } - - size += n; - } while (n > 0); - - if (!err) { - *sizep = size; - *buf = bf; + io__init(&io, io.fd, bf, sizeof(bf)); + *buf = NULL; + err = io__getdelim(&io, buf, sizep, /*delim=*/-1); + if (err < 0) { + free(*buf); + *buf = NULL; } else - free(bf); - - close(fd); + err = 0; + close(io.fd); return err; } @@ -475,15 +447,22 @@ int sysfs__read_str(const char *entry, char **buf, size_t *sizep) int sysfs__read_bool(const char *entry, bool *value) { - char *buf; - size_t size; - int ret; + struct io io; + char bf[16]; + int ret = 0; + char path[PATH_MAX]; + const char *sysfs = sysfs__mountpoint(); + + if (!sysfs) + return -1; - ret = sysfs__read_str(entry, &buf, &size); - if (ret < 0) - return ret; + snprintf(path, sizeof(path), "%s/%s", sysfs, entry); + io.fd = open(path, O_RDONLY); + if (io.fd < 0) + return -errno; - switch (buf[0]) { + io__init(&io, io.fd, bf, sizeof(bf)); + switch (io__get_char(&io)) { case '1': case 'y': case 'Y': @@ -497,8 +476,7 @@ int sysfs__read_bool(const char *entry, bool *value) default: ret = -1; } - - free(buf); + close(io.fd); return ret; } diff --git a/tools/lib/api/io.h b/tools/lib/api/io.h index 2a7fe97588..84adf81020 100644 --- a/tools/lib/api/io.h +++ b/tools/lib/api/io.h @@ -141,8 +141,8 @@ static inline int io__get_dec(struct io *io, __u64 *dec) } } -/* Read up to and including the first newline following the pattern of getline. */ -static inline ssize_t io__getline(struct io *io, char **line_out, size_t *line_len_out) +/* Read up to and including the first delim. */ +static inline ssize_t io__getdelim(struct io *io, char **line_out, size_t *line_len_out, int delim) { char buf[128]; int buf_pos = 0; @@ -152,7 +152,7 @@ static inline ssize_t io__getline(struct io *io, char **line_out, size_t *line_l /* TODO: reuse previously allocated memory. */ free(*line_out); - while (ch != '\n') { + while (ch != delim) { ch = io__get_char(io); if (ch < 0) @@ -185,4 +185,9 @@ err_out: return -ENOMEM; } +static inline ssize_t io__getline(struct io *io, char **line_out, size_t *line_len_out) +{ + return io__getdelim(io, line_out, line_len_out, /*delim=*/'\n'); +} + #endif /* __API_IO__ */ diff --git a/tools/lib/bpf/bpf_core_read.h b/tools/lib/bpf/bpf_core_read.h index 1ac57bb7ac..7325a12692 100644 --- a/tools/lib/bpf/bpf_core_read.h +++ b/tools/lib/bpf/bpf_core_read.h @@ -111,6 +111,38 @@ enum bpf_enum_value_kind { val; \ }) +/* + * Write to a bitfield, identified by s->field. + * This is the inverse of BPF_CORE_WRITE_BITFIELD(). + */ +#define BPF_CORE_WRITE_BITFIELD(s, field, new_val) ({ \ + void *p = (void *)s + __CORE_RELO(s, field, BYTE_OFFSET); \ + unsigned int byte_size = __CORE_RELO(s, field, BYTE_SIZE); \ + unsigned int lshift = __CORE_RELO(s, field, LSHIFT_U64); \ + unsigned int rshift = __CORE_RELO(s, field, RSHIFT_U64); \ + unsigned long long mask, val, nval = new_val; \ + unsigned int rpad = rshift - lshift; \ + \ + asm volatile("" : "+r"(p)); \ + \ + switch (byte_size) { \ + case 1: val = *(unsigned char *)p; break; \ + case 2: val = *(unsigned short *)p; break; \ + case 4: val = *(unsigned int *)p; break; \ + case 8: val = *(unsigned long long *)p; break; \ + } \ + \ + mask = (~0ULL << rshift) >> lshift; \ + val = (val & ~mask) | ((nval << rpad) & mask); \ + \ + switch (byte_size) { \ + case 1: *(unsigned char *)p = val; break; \ + case 2: *(unsigned short *)p = val; break; \ + case 4: *(unsigned int *)p = val; break; \ + case 8: *(unsigned long long *)p = val; break; \ + } \ +}) + #define ___bpf_field_ref1(field) (field) #define ___bpf_field_ref2(type, field) (((typeof(type) *)0)->field) #define ___bpf_field_ref(args...) \ diff --git a/tools/lib/bpf/bpf_helpers.h b/tools/lib/bpf/bpf_helpers.h index 77ceea575d..2324cc42b0 100644 --- a/tools/lib/bpf/bpf_helpers.h +++ b/tools/lib/bpf/bpf_helpers.h @@ -188,6 +188,9 @@ enum libbpf_tristate { !!sym; \ }) +#define __arg_ctx __attribute__((btf_decl_tag("arg:ctx"))) +#define __arg_nonnull __attribute((btf_decl_tag("arg:nonnull"))) + #ifndef ___bpf_concat #define ___bpf_concat(a, b) a ## b #endif diff --git a/tools/lib/bpf/elf.c b/tools/lib/bpf/elf.c index 2a62bf411b..b02faec748 100644 --- a/tools/lib/bpf/elf.c +++ b/tools/lib/bpf/elf.c @@ -407,7 +407,8 @@ static int symbol_cmp(const void *a, const void *b) * size, that needs to be released by the caller. */ int elf_resolve_syms_offsets(const char *binary_path, int cnt, - const char **syms, unsigned long **poffsets) + const char **syms, unsigned long **poffsets, + int st_type) { int sh_types[2] = { SHT_DYNSYM, SHT_SYMTAB }; int err = 0, i, cnt_done = 0; @@ -438,7 +439,7 @@ int elf_resolve_syms_offsets(const char *binary_path, int cnt, struct elf_sym_iter iter; struct elf_sym *sym; - err = elf_sym_iter_new(&iter, elf_fd.elf, binary_path, sh_types[i], STT_FUNC); + err = elf_sym_iter_new(&iter, elf_fd.elf, binary_path, sh_types[i], st_type); if (err == -ENOENT) continue; if (err) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index ca83af916c..92bca96587 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -1504,6 +1505,16 @@ static Elf64_Sym *find_elf_var_sym(const struct bpf_object *obj, const char *nam return ERR_PTR(-ENOENT); } +static int create_placeholder_fd(void) +{ + int fd; + + fd = ensure_good_fd(memfd_create("libbpf-placeholder-fd", MFD_CLOEXEC)); + if (fd < 0) + return -errno; + return fd; +} + static struct bpf_map *bpf_object__add_map(struct bpf_object *obj) { struct bpf_map *map; @@ -1516,7 +1527,21 @@ static struct bpf_map *bpf_object__add_map(struct bpf_object *obj) map = &obj->maps[obj->nr_maps++]; map->obj = obj; - map->fd = -1; + /* Preallocate map FD without actually creating BPF map just yet. + * These map FD "placeholders" will be reused later without changing + * FD value when map is actually created in the kernel. + * + * This is useful to be able to perform BPF program relocations + * without having to create BPF maps before that step. This allows us + * to finalize and load BTF very late in BPF object's loading phase, + * right before BPF maps have to be created and BPF programs have to + * be loaded. By having these map FD placeholders we can perform all + * the sanitizations, relocations, and any other adjustments before we + * start creating actual BPF kernel objects (BTF, maps, progs). + */ + map->fd = create_placeholder_fd(); + if (map->fd < 0) + return ERR_PTR(map->fd); map->inner_map_fd = -1; map->autocreate = true; @@ -2608,7 +2633,9 @@ static int bpf_object__init_user_btf_map(struct bpf_object *obj, map->inner_map = calloc(1, sizeof(*map->inner_map)); if (!map->inner_map) return -ENOMEM; - map->inner_map->fd = -1; + map->inner_map->fd = create_placeholder_fd(); + if (map->inner_map->fd < 0) + return map->inner_map->fd; map->inner_map->sec_idx = sec_idx; map->inner_map->name = malloc(strlen(map_name) + sizeof(".inner") + 1); if (!map->inner_map->name) @@ -3055,9 +3082,15 @@ static bool prog_needs_vmlinux_btf(struct bpf_program *prog) return false; } +static bool map_needs_vmlinux_btf(struct bpf_map *map) +{ + return bpf_map__is_struct_ops(map); +} + static bool obj_needs_vmlinux_btf(const struct bpf_object *obj) { struct bpf_program *prog; + struct bpf_map *map; int i; /* CO-RE relocations need kernel BTF, only when btf_custom_path @@ -3082,6 +3115,11 @@ static bool obj_needs_vmlinux_btf(const struct bpf_object *obj) return true; } + bpf_object__for_each_map(map, obj) { + if (map_needs_vmlinux_btf(map)) + return true; + } + return false; } @@ -3156,86 +3194,6 @@ static int bpf_object__sanitize_and_load_btf(struct bpf_object *obj) } } - if (!kernel_supports(obj, FEAT_BTF_DECL_TAG)) - goto skip_exception_cb; - for (i = 0; i < obj->nr_programs; i++) { - struct bpf_program *prog = &obj->programs[i]; - int j, k, n; - - if (prog_is_subprog(obj, prog)) - continue; - n = btf__type_cnt(obj->btf); - for (j = 1; j < n; j++) { - const char *str = "exception_callback:", *name; - size_t len = strlen(str); - struct btf_type *t; - - t = btf_type_by_id(obj->btf, j); - if (!btf_is_decl_tag(t) || btf_decl_tag(t)->component_idx != -1) - continue; - - name = btf__str_by_offset(obj->btf, t->name_off); - if (strncmp(name, str, len)) - continue; - - t = btf_type_by_id(obj->btf, t->type); - if (!btf_is_func(t) || btf_func_linkage(t) != BTF_FUNC_GLOBAL) { - pr_warn("prog '%s': exception_callback: decl tag not applied to the main program\n", - prog->name); - return -EINVAL; - } - if (strcmp(prog->name, btf__str_by_offset(obj->btf, t->name_off))) - continue; - /* Multiple callbacks are specified for the same prog, - * the verifier will eventually return an error for this - * case, hence simply skip appending a subprog. - */ - if (prog->exception_cb_idx >= 0) { - prog->exception_cb_idx = -1; - break; - } - - name += len; - if (str_is_empty(name)) { - pr_warn("prog '%s': exception_callback: decl tag contains empty value\n", - prog->name); - return -EINVAL; - } - - for (k = 0; k < obj->nr_programs; k++) { - struct bpf_program *subprog = &obj->programs[k]; - - if (!prog_is_subprog(obj, subprog)) - continue; - if (strcmp(name, subprog->name)) - continue; - /* Enforce non-hidden, as from verifier point of - * view it expects global functions, whereas the - * mark_btf_static fixes up linkage as static. - */ - if (!subprog->sym_global || subprog->mark_btf_static) { - pr_warn("prog '%s': exception callback %s must be a global non-hidden function\n", - prog->name, subprog->name); - return -EINVAL; - } - /* Let's see if we already saw a static exception callback with the same name */ - if (prog->exception_cb_idx >= 0) { - pr_warn("prog '%s': multiple subprogs with same name as exception callback '%s'\n", - prog->name, subprog->name); - return -EINVAL; - } - prog->exception_cb_idx = k; - break; - } - - if (prog->exception_cb_idx >= 0) - continue; - pr_warn("prog '%s': cannot find exception callback '%s'\n", prog->name, name); - return -ENOENT; - } - } -skip_exception_cb: - sanitize = btf_needs_sanitization(obj); if (sanitize) { const void *raw_data; @@ -4539,14 +4497,12 @@ int bpf_map__reuse_fd(struct bpf_map *map, int fd) goto err_free_new_name; } - err = zclose(map->fd); - if (err) { - err = -errno; - goto err_close_new_fd; - } + err = reuse_fd(map->fd, new_fd); + if (err) + goto err_free_new_name; + free(map->name); - map->fd = new_fd; map->name = new_name; map->def.type = info.type; map->def.key_size = info.key_size; @@ -4560,8 +4516,6 @@ int bpf_map__reuse_fd(struct bpf_map *map, int fd) return 0; -err_close_new_fd: - close(new_fd); err_free_new_name: free(new_name); return libbpf_err(err); @@ -5190,12 +5144,17 @@ bpf_object__populate_internal_map(struct bpf_object *obj, struct bpf_map *map) static void bpf_map__destroy(struct bpf_map *map); +static bool map_is_created(const struct bpf_map *map) +{ + return map->obj->loaded || map->reused; +} + static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map, bool is_inner) { LIBBPF_OPTS(bpf_map_create_opts, create_attr); struct bpf_map_def *def = &map->def; const char *map_name = NULL; - int err = 0; + int err = 0, map_fd; if (kernel_supports(obj, FEAT_PROG_NAME)) map_name = map->name; @@ -5224,7 +5183,7 @@ static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map, b map->name, err); return err; } - map->inner_map_fd = bpf_map__fd(map->inner_map); + map->inner_map_fd = map->inner_map->fd; } if (map->inner_map_fd >= 0) create_attr.inner_map_fd = map->inner_map_fd; @@ -5257,17 +5216,19 @@ static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map, b bpf_gen__map_create(obj->gen_loader, def->type, map_name, def->key_size, def->value_size, def->max_entries, &create_attr, is_inner ? -1 : map - obj->maps); - /* Pretend to have valid FD to pass various fd >= 0 checks. - * This fd == 0 will not be used with any syscall and will be reset to -1 eventually. + /* We keep pretenting we have valid FD to pass various fd >= 0 + * checks by just keeping original placeholder FDs in place. + * See bpf_object__add_map() comment. + * This placeholder fd will not be used with any syscall and + * will be reset to -1 eventually. */ - map->fd = 0; + map_fd = map->fd; } else { - map->fd = bpf_map_create(def->type, map_name, - def->key_size, def->value_size, - def->max_entries, &create_attr); + map_fd = bpf_map_create(def->type, map_name, + def->key_size, def->value_size, + def->max_entries, &create_attr); } - if (map->fd < 0 && (create_attr.btf_key_type_id || - create_attr.btf_value_type_id)) { + if (map_fd < 0 && (create_attr.btf_key_type_id || create_attr.btf_value_type_id)) { char *cp, errmsg[STRERR_BUFSIZE]; err = -errno; @@ -5279,13 +5240,11 @@ static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map, b create_attr.btf_value_type_id = 0; map->btf_key_type_id = 0; map->btf_value_type_id = 0; - map->fd = bpf_map_create(def->type, map_name, - def->key_size, def->value_size, - def->max_entries, &create_attr); + map_fd = bpf_map_create(def->type, map_name, + def->key_size, def->value_size, + def->max_entries, &create_attr); } - err = map->fd < 0 ? -errno : 0; - if (bpf_map_type__is_map_in_map(def->type) && map->inner_map) { if (obj->gen_loader) map->inner_map->fd = -1; @@ -5293,7 +5252,19 @@ static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map, b zfree(&map->inner_map); } - return err; + if (map_fd < 0) + return map_fd; + + /* obj->gen_loader case, prevent reuse_fd() from closing map_fd */ + if (map->fd == map_fd) + return 0; + + /* Keep placeholder FD value but now point it to the BPF map object. + * This way everything that relied on this map's FD (e.g., relocated + * ldimm64 instructions) will stay valid and won't need adjustments. + * map->fd stays valid but now point to what map_fd points to. + */ + return reuse_fd(map->fd, map_fd); } static int init_map_in_map_slots(struct bpf_object *obj, struct bpf_map *map) @@ -5307,7 +5278,7 @@ static int init_map_in_map_slots(struct bpf_object *obj, struct bpf_map *map) continue; targ_map = map->init_slots[i]; - fd = bpf_map__fd(targ_map); + fd = targ_map->fd; if (obj->gen_loader) { bpf_gen__populate_outer_map(obj->gen_loader, @@ -5377,10 +5348,8 @@ static int bpf_object_init_prog_arrays(struct bpf_object *obj) continue; err = init_prog_array_slots(obj, map); - if (err < 0) { - zclose(map->fd); + if (err < 0) return err; - } } return 0; } @@ -5458,7 +5427,7 @@ retry: } } - if (map->fd >= 0) { + if (map->reused) { pr_debug("map '%s': skipping creation (preset fd=%d)\n", map->name, map->fd); } else { @@ -5471,25 +5440,20 @@ retry: if (bpf_map__is_internal(map)) { err = bpf_object__populate_internal_map(obj, map); - if (err < 0) { - zclose(map->fd); + if (err < 0) goto err_out; - } } if (map->init_slots_sz && map->def.type != BPF_MAP_TYPE_PROG_ARRAY) { err = init_map_in_map_slots(obj, map); - if (err < 0) { - zclose(map->fd); + if (err < 0) goto err_out; - } } } if (map->pin_path && !map->pinned) { err = bpf_map__pin(map, NULL); if (err) { - zclose(map->fd); if (!retried && err == -EEXIST) { retried = true; goto retry; @@ -6222,7 +6186,7 @@ reloc_prog_func_and_line_info(const struct bpf_object *obj, int err; /* no .BTF.ext relocation if .BTF.ext is missing or kernel doesn't - * supprot func/line info + * support func/line info */ if (!obj->btf_ext || !kernel_supports(obj, FEAT_BTF_FUNC)) return 0; @@ -6622,8 +6586,471 @@ static void bpf_object__sort_relos(struct bpf_object *obj) } } -static int -bpf_object__relocate(struct bpf_object *obj, const char *targ_btf_path) +static int bpf_prog_assign_exc_cb(struct bpf_object *obj, struct bpf_program *prog) +{ + const char *str = "exception_callback:"; + size_t pfx_len = strlen(str); + int i, j, n; + + if (!obj->btf || !kernel_supports(obj, FEAT_BTF_DECL_TAG)) + return 0; + + n = btf__type_cnt(obj->btf); + for (i = 1; i < n; i++) { + const char *name; + struct btf_type *t; + + t = btf_type_by_id(obj->btf, i); + if (!btf_is_decl_tag(t) || btf_decl_tag(t)->component_idx != -1) + continue; + + name = btf__str_by_offset(obj->btf, t->name_off); + if (strncmp(name, str, pfx_len) != 0) + continue; + + t = btf_type_by_id(obj->btf, t->type); + if (!btf_is_func(t) || btf_func_linkage(t) != BTF_FUNC_GLOBAL) { + pr_warn("prog '%s': exception_callback: decl tag not applied to the main program\n", + prog->name); + return -EINVAL; + } + if (strcmp(prog->name, btf__str_by_offset(obj->btf, t->name_off)) != 0) + continue; + /* Multiple callbacks are specified for the same prog, + * the verifier will eventually return an error for this + * case, hence simply skip appending a subprog. + */ + if (prog->exception_cb_idx >= 0) { + prog->exception_cb_idx = -1; + break; + } + + name += pfx_len; + if (str_is_empty(name)) { + pr_warn("prog '%s': exception_callback: decl tag contains empty value\n", + prog->name); + return -EINVAL; + } + + for (j = 0; j < obj->nr_programs; j++) { + struct bpf_program *subprog = &obj->programs[j]; + + if (!prog_is_subprog(obj, subprog)) + continue; + if (strcmp(name, subprog->name) != 0) + continue; + /* Enforce non-hidden, as from verifier point of + * view it expects global functions, whereas the + * mark_btf_static fixes up linkage as static. + */ + if (!subprog->sym_global || subprog->mark_btf_static) { + pr_warn("prog '%s': exception callback %s must be a global non-hidden function\n", + prog->name, subprog->name); + return -EINVAL; + } + /* Let's see if we already saw a static exception callback with the same name */ + if (prog->exception_cb_idx >= 0) { + pr_warn("prog '%s': multiple subprogs with same name as exception callback '%s'\n", + prog->name, subprog->name); + return -EINVAL; + } + prog->exception_cb_idx = j; + break; + } + + if (prog->exception_cb_idx >= 0) + continue; + + pr_warn("prog '%s': cannot find exception callback '%s'\n", prog->name, name); + return -ENOENT; + } + + return 0; +} + +static struct { + enum bpf_prog_type prog_type; + const char *ctx_name; +} global_ctx_map[] = { + { BPF_PROG_TYPE_CGROUP_DEVICE, "bpf_cgroup_dev_ctx" }, + { BPF_PROG_TYPE_CGROUP_SKB, "__sk_buff" }, + { BPF_PROG_TYPE_CGROUP_SOCK, "bpf_sock" }, + { BPF_PROG_TYPE_CGROUP_SOCK_ADDR, "bpf_sock_addr" }, + { BPF_PROG_TYPE_CGROUP_SOCKOPT, "bpf_sockopt" }, + { BPF_PROG_TYPE_CGROUP_SYSCTL, "bpf_sysctl" }, + { BPF_PROG_TYPE_FLOW_DISSECTOR, "__sk_buff" }, + { BPF_PROG_TYPE_KPROBE, "bpf_user_pt_regs_t" }, + { BPF_PROG_TYPE_LWT_IN, "__sk_buff" }, + { BPF_PROG_TYPE_LWT_OUT, "__sk_buff" }, + { BPF_PROG_TYPE_LWT_SEG6LOCAL, "__sk_buff" }, + { BPF_PROG_TYPE_LWT_XMIT, "__sk_buff" }, + { BPF_PROG_TYPE_NETFILTER, "bpf_nf_ctx" }, + { BPF_PROG_TYPE_PERF_EVENT, "bpf_perf_event_data" }, + { BPF_PROG_TYPE_RAW_TRACEPOINT, "bpf_raw_tracepoint_args" }, + { BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE, "bpf_raw_tracepoint_args" }, + { BPF_PROG_TYPE_SCHED_ACT, "__sk_buff" }, + { BPF_PROG_TYPE_SCHED_CLS, "__sk_buff" }, + { BPF_PROG_TYPE_SK_LOOKUP, "bpf_sk_lookup" }, + { BPF_PROG_TYPE_SK_MSG, "sk_msg_md" }, + { BPF_PROG_TYPE_SK_REUSEPORT, "sk_reuseport_md" }, + { BPF_PROG_TYPE_SK_SKB, "__sk_buff" }, + { BPF_PROG_TYPE_SOCK_OPS, "bpf_sock_ops" }, + { BPF_PROG_TYPE_SOCKET_FILTER, "__sk_buff" }, + { BPF_PROG_TYPE_XDP, "xdp_md" }, + /* all other program types don't have "named" context structs */ +}; + +/* forward declarations for arch-specific underlying types of bpf_user_pt_regs_t typedef, + * for below __builtin_types_compatible_p() checks; + * with this approach we don't need any extra arch-specific #ifdef guards + */ +struct pt_regs; +struct user_pt_regs; +struct user_regs_struct; + +static bool need_func_arg_type_fixup(const struct btf *btf, const struct bpf_program *prog, + const char *subprog_name, int arg_idx, + int arg_type_id, const char *ctx_name) +{ + const struct btf_type *t; + const char *tname; + + /* check if existing parameter already matches verifier expectations */ + t = skip_mods_and_typedefs(btf, arg_type_id, NULL); + if (!btf_is_ptr(t)) + goto out_warn; + + /* typedef bpf_user_pt_regs_t is a special PITA case, valid for kprobe + * and perf_event programs, so check this case early on and forget + * about it for subsequent checks + */ + while (btf_is_mod(t)) + t = btf__type_by_id(btf, t->type); + if (btf_is_typedef(t) && + (prog->type == BPF_PROG_TYPE_KPROBE || prog->type == BPF_PROG_TYPE_PERF_EVENT)) { + tname = btf__str_by_offset(btf, t->name_off) ?: ""; + if (strcmp(tname, "bpf_user_pt_regs_t") == 0) + return false; /* canonical type for kprobe/perf_event */ + } + + /* now we can ignore typedefs moving forward */ + t = skip_mods_and_typedefs(btf, t->type, NULL); + + /* if it's `void *`, definitely fix up BTF info */ + if (btf_is_void(t)) + return true; + + /* if it's already proper canonical type, no need to fix up */ + tname = btf__str_by_offset(btf, t->name_off) ?: ""; + if (btf_is_struct(t) && strcmp(tname, ctx_name) == 0) + return false; + + /* special cases */ + switch (prog->type) { + case BPF_PROG_TYPE_KPROBE: + /* `struct pt_regs *` is expected, but we need to fix up */ + if (btf_is_struct(t) && strcmp(tname, "pt_regs") == 0) + return true; + break; + case BPF_PROG_TYPE_PERF_EVENT: + if (__builtin_types_compatible_p(bpf_user_pt_regs_t, struct pt_regs) && + btf_is_struct(t) && strcmp(tname, "pt_regs") == 0) + return true; + if (__builtin_types_compatible_p(bpf_user_pt_regs_t, struct user_pt_regs) && + btf_is_struct(t) && strcmp(tname, "user_pt_regs") == 0) + return true; + if (__builtin_types_compatible_p(bpf_user_pt_regs_t, struct user_regs_struct) && + btf_is_struct(t) && strcmp(tname, "user_regs_struct") == 0) + return true; + break; + case BPF_PROG_TYPE_RAW_TRACEPOINT: + case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE: + /* allow u64* as ctx */ + if (btf_is_int(t) && t->size == 8) + return true; + break; + default: + break; + } + +out_warn: + pr_warn("prog '%s': subprog '%s' arg#%d is expected to be of `struct %s *` type\n", + prog->name, subprog_name, arg_idx, ctx_name); + return false; +} + +static int clone_func_btf_info(struct btf *btf, int orig_fn_id, struct bpf_program *prog) +{ + int fn_id, fn_proto_id, ret_type_id, orig_proto_id; + int i, err, arg_cnt, fn_name_off, linkage; + struct btf_type *fn_t, *fn_proto_t, *t; + struct btf_param *p; + + /* caller already validated FUNC -> FUNC_PROTO validity */ + fn_t = btf_type_by_id(btf, orig_fn_id); + fn_proto_t = btf_type_by_id(btf, fn_t->type); + + /* Note that each btf__add_xxx() operation invalidates + * all btf_type and string pointers, so we need to be + * very careful when cloning BTF types. BTF type + * pointers have to be always refetched. And to avoid + * problems with invalidated string pointers, we + * add empty strings initially, then just fix up + * name_off offsets in place. Offsets are stable for + * existing strings, so that works out. + */ + fn_name_off = fn_t->name_off; /* we are about to invalidate fn_t */ + linkage = btf_func_linkage(fn_t); + orig_proto_id = fn_t->type; /* original FUNC_PROTO ID */ + ret_type_id = fn_proto_t->type; /* fn_proto_t will be invalidated */ + arg_cnt = btf_vlen(fn_proto_t); + + /* clone FUNC_PROTO and its params */ + fn_proto_id = btf__add_func_proto(btf, ret_type_id); + if (fn_proto_id < 0) + return -EINVAL; + + for (i = 0; i < arg_cnt; i++) { + int name_off; + + /* copy original parameter data */ + t = btf_type_by_id(btf, orig_proto_id); + p = &btf_params(t)[i]; + name_off = p->name_off; + + err = btf__add_func_param(btf, "", p->type); + if (err) + return err; + + fn_proto_t = btf_type_by_id(btf, fn_proto_id); + p = &btf_params(fn_proto_t)[i]; + p->name_off = name_off; /* use remembered str offset */ + } + + /* clone FUNC now, btf__add_func() enforces non-empty name, so use + * entry program's name as a placeholder, which we replace immediately + * with original name_off + */ + fn_id = btf__add_func(btf, prog->name, linkage, fn_proto_id); + if (fn_id < 0) + return -EINVAL; + + fn_t = btf_type_by_id(btf, fn_id); + fn_t->name_off = fn_name_off; /* reuse original string */ + + return fn_id; +} + +static int probe_kern_arg_ctx_tag(void) +{ + /* To minimize merge conflicts with BPF token series that refactors + * feature detection code a lot, we don't integrate + * probe_kern_arg_ctx_tag() into kernel_supports() feature-detection + * framework yet, doing our own caching internally. + * This will be cleaned up a bit later when bpf/bpf-next trees settle. + */ + static int cached_result = -1; + static const char strs[] = "\0a\0b\0arg:ctx\0"; + const __u32 types[] = { + /* [1] INT */ + BTF_TYPE_INT_ENC(1 /* "a" */, BTF_INT_SIGNED, 0, 32, 4), + /* [2] PTR -> VOID */ + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 0), + /* [3] FUNC_PROTO `int(void *a)` */ + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 1), 1), + BTF_PARAM_ENC(1 /* "a" */, 2), + /* [4] FUNC 'a' -> FUNC_PROTO (main prog) */ + BTF_TYPE_ENC(1 /* "a" */, BTF_INFO_ENC(BTF_KIND_FUNC, 0, BTF_FUNC_GLOBAL), 3), + /* [5] FUNC_PROTO `int(void *b __arg_ctx)` */ + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 1), 1), + BTF_PARAM_ENC(3 /* "b" */, 2), + /* [6] FUNC 'b' -> FUNC_PROTO (subprog) */ + BTF_TYPE_ENC(3 /* "b" */, BTF_INFO_ENC(BTF_KIND_FUNC, 0, BTF_FUNC_GLOBAL), 5), + /* [7] DECL_TAG 'arg:ctx' -> func 'b' arg 'b' */ + BTF_TYPE_DECL_TAG_ENC(5 /* "arg:ctx" */, 6, 0), + }; + const struct bpf_insn insns[] = { + /* main prog */ + BPF_CALL_REL(+1), + BPF_EXIT_INSN(), + /* global subprog */ + BPF_EMIT_CALL(BPF_FUNC_get_func_ip), /* needs PTR_TO_CTX */ + BPF_EXIT_INSN(), + }; + const struct bpf_func_info_min func_infos[] = { + { 0, 4 }, /* main prog -> FUNC 'a' */ + { 2, 6 }, /* subprog -> FUNC 'b' */ + }; + LIBBPF_OPTS(bpf_prog_load_opts, opts); + int prog_fd, btf_fd, insn_cnt = ARRAY_SIZE(insns); + + if (cached_result >= 0) + return cached_result; + + btf_fd = libbpf__load_raw_btf((char *)types, sizeof(types), strs, sizeof(strs)); + if (btf_fd < 0) + return 0; + + opts.prog_btf_fd = btf_fd; + opts.func_info = &func_infos; + opts.func_info_cnt = ARRAY_SIZE(func_infos); + opts.func_info_rec_size = sizeof(func_infos[0]); + + prog_fd = bpf_prog_load(BPF_PROG_TYPE_KPROBE, "det_arg_ctx", + "GPL", insns, insn_cnt, &opts); + close(btf_fd); + + cached_result = probe_fd(prog_fd); + return cached_result; +} + +/* Check if main program or global subprog's function prototype has `arg:ctx` + * argument tags, and, if necessary, substitute correct type to match what BPF + * verifier would expect, taking into account specific program type. This + * allows to support __arg_ctx tag transparently on old kernels that don't yet + * have a native support for it in the verifier, making user's life much + * easier. + */ +static int bpf_program_fixup_func_info(struct bpf_object *obj, struct bpf_program *prog) +{ + const char *ctx_name = NULL, *ctx_tag = "arg:ctx", *fn_name; + struct bpf_func_info_min *func_rec; + struct btf_type *fn_t, *fn_proto_t; + struct btf *btf = obj->btf; + const struct btf_type *t; + struct btf_param *p; + int ptr_id = 0, struct_id, tag_id, orig_fn_id; + int i, n, arg_idx, arg_cnt, err, rec_idx; + int *orig_ids; + + /* no .BTF.ext, no problem */ + if (!obj->btf_ext || !prog->func_info) + return 0; + + /* don't do any fix ups if kernel natively supports __arg_ctx */ + if (probe_kern_arg_ctx_tag() > 0) + return 0; + + /* some BPF program types just don't have named context structs, so + * this fallback mechanism doesn't work for them + */ + for (i = 0; i < ARRAY_SIZE(global_ctx_map); i++) { + if (global_ctx_map[i].prog_type != prog->type) + continue; + ctx_name = global_ctx_map[i].ctx_name; + break; + } + if (!ctx_name) + return 0; + + /* remember original func BTF IDs to detect if we already cloned them */ + orig_ids = calloc(prog->func_info_cnt, sizeof(*orig_ids)); + if (!orig_ids) + return -ENOMEM; + for (i = 0; i < prog->func_info_cnt; i++) { + func_rec = prog->func_info + prog->func_info_rec_size * i; + orig_ids[i] = func_rec->type_id; + } + + /* go through each DECL_TAG with "arg:ctx" and see if it points to one + * of our subprogs; if yes and subprog is global and needs adjustment, + * clone and adjust FUNC -> FUNC_PROTO combo + */ + for (i = 1, n = btf__type_cnt(btf); i < n; i++) { + /* only DECL_TAG with "arg:ctx" value are interesting */ + t = btf__type_by_id(btf, i); + if (!btf_is_decl_tag(t)) + continue; + if (strcmp(btf__str_by_offset(btf, t->name_off), ctx_tag) != 0) + continue; + + /* only global funcs need adjustment, if at all */ + orig_fn_id = t->type; + fn_t = btf_type_by_id(btf, orig_fn_id); + if (!btf_is_func(fn_t) || btf_func_linkage(fn_t) != BTF_FUNC_GLOBAL) + continue; + + /* sanity check FUNC -> FUNC_PROTO chain, just in case */ + fn_proto_t = btf_type_by_id(btf, fn_t->type); + if (!fn_proto_t || !btf_is_func_proto(fn_proto_t)) + continue; + + /* find corresponding func_info record */ + func_rec = NULL; + for (rec_idx = 0; rec_idx < prog->func_info_cnt; rec_idx++) { + if (orig_ids[rec_idx] == t->type) { + func_rec = prog->func_info + prog->func_info_rec_size * rec_idx; + break; + } + } + /* current main program doesn't call into this subprog */ + if (!func_rec) + continue; + + /* some more sanity checking of DECL_TAG */ + arg_cnt = btf_vlen(fn_proto_t); + arg_idx = btf_decl_tag(t)->component_idx; + if (arg_idx < 0 || arg_idx >= arg_cnt) + continue; + + /* check if we should fix up argument type */ + p = &btf_params(fn_proto_t)[arg_idx]; + fn_name = btf__str_by_offset(btf, fn_t->name_off) ?: ""; + if (!need_func_arg_type_fixup(btf, prog, fn_name, arg_idx, p->type, ctx_name)) + continue; + + /* clone fn/fn_proto, unless we already did it for another arg */ + if (func_rec->type_id == orig_fn_id) { + int fn_id; + + fn_id = clone_func_btf_info(btf, orig_fn_id, prog); + if (fn_id < 0) { + err = fn_id; + goto err_out; + } + + /* point func_info record to a cloned FUNC type */ + func_rec->type_id = fn_id; + } + + /* create PTR -> STRUCT type chain to mark PTR_TO_CTX argument; + * we do it just once per main BPF program, as all global + * funcs share the same program type, so need only PTR -> + * STRUCT type chain + */ + if (ptr_id == 0) { + struct_id = btf__add_struct(btf, ctx_name, 0); + ptr_id = btf__add_ptr(btf, struct_id); + if (ptr_id < 0 || struct_id < 0) { + err = -EINVAL; + goto err_out; + } + } + + /* for completeness, clone DECL_TAG and point it to cloned param */ + tag_id = btf__add_decl_tag(btf, ctx_tag, func_rec->type_id, arg_idx); + if (tag_id < 0) { + err = -EINVAL; + goto err_out; + } + + /* all the BTF manipulations invalidated pointers, refetch them */ + fn_t = btf_type_by_id(btf, func_rec->type_id); + fn_proto_t = btf_type_by_id(btf, fn_t->type); + + /* fix up type ID pointed to by param */ + p = &btf_params(fn_proto_t)[arg_idx]; + p->type = ptr_id; + } + + free(orig_ids); + return 0; +err_out: + free(orig_ids); + return err; +} + +static int bpf_object__relocate(struct bpf_object *obj, const char *targ_btf_path) { struct bpf_program *prog; size_t i, j; @@ -6682,6 +7109,9 @@ bpf_object__relocate(struct bpf_object *obj, const char *targ_btf_path) return err; } + err = bpf_prog_assign_exc_cb(obj, prog); + if (err) + return err; /* Now, also append exception callback if it has not been done already. */ if (prog->exception_cb_idx >= 0) { struct bpf_program *subprog = &obj->programs[prog->exception_cb_idx]; @@ -6701,19 +7131,28 @@ bpf_object__relocate(struct bpf_object *obj, const char *targ_btf_path) } } } - /* Process data relos for main programs */ for (i = 0; i < obj->nr_programs; i++) { prog = &obj->programs[i]; if (prog_is_subprog(obj, prog)) continue; if (!prog->autoload) continue; + + /* Process data relos for main programs */ err = bpf_object__relocate_data(obj, prog); if (err) { pr_warn("prog '%s': failed to relocate data references: %d\n", prog->name, err); return err; } + + /* Fix up .BTF.ext information, if necessary */ + err = bpf_program_fixup_func_info(obj, prog); + if (err) { + pr_warn("prog '%s': failed to perform .BTF.ext fix ups: %d\n", + prog->name, err); + return err; + } } return 0; @@ -7043,7 +7482,7 @@ static int bpf_object_load_prog(struct bpf_object *obj, struct bpf_program *prog load_attr.prog_ifindex = prog->prog_ifindex; /* specify func_info/line_info only if kernel supports them */ - btf_fd = bpf_object__btf_fd(obj); + btf_fd = btf__fd(obj->btf); if (btf_fd >= 0 && kernel_supports(obj, FEAT_BTF_FUNC)) { load_attr.prog_btf_fd = btf_fd; load_attr.func_info = prog->func_info; @@ -7128,7 +7567,7 @@ retry_load: if (map->libbpf_type != LIBBPF_MAP_RODATA) continue; - if (bpf_prog_bind_map(ret, bpf_map__fd(map), NULL)) { + if (bpf_prog_bind_map(ret, map->fd, NULL)) { cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg)); pr_warn("prog '%s': failed to bind map '%s': %s\n", prog->name, map->real_name, cp); @@ -8060,11 +8499,11 @@ static int bpf_object_load(struct bpf_object *obj, int extra_log_level, const ch err = bpf_object__probe_loading(obj); err = err ? : bpf_object__load_vmlinux_btf(obj, false); err = err ? : bpf_object__resolve_externs(obj, obj->kconfig); - err = err ? : bpf_object__sanitize_and_load_btf(obj); err = err ? : bpf_object__sanitize_maps(obj); err = err ? : bpf_object__init_kern_struct_ops_maps(obj); - err = err ? : bpf_object__create_maps(obj); err = err ? : bpf_object__relocate(obj, obj->btf_custom_path ? : target_btf_path); + err = err ? : bpf_object__sanitize_and_load_btf(obj); + err = err ? : bpf_object__create_maps(obj); err = err ? : bpf_object__load_progs(obj, extra_log_level); err = err ? : bpf_object_init_prog_arrays(obj); err = err ? : bpf_object_prepare_struct_ops(obj); @@ -8073,8 +8512,6 @@ static int bpf_object_load(struct bpf_object *obj, int extra_log_level, const ch /* reset FDs */ if (obj->btf) btf__set_fd(obj->btf, -1); - for (i = 0; i < obj->nr_maps; i++) - obj->maps[i].fd = -1; if (!err) err = bpf_gen__finish(obj->gen_loader, obj->nr_programs, obj->nr_maps); } @@ -9594,7 +10031,11 @@ int libbpf_attach_type_by_name(const char *name, int bpf_map__fd(const struct bpf_map *map) { - return map ? map->fd : libbpf_err(-EINVAL); + if (!map) + return libbpf_err(-EINVAL); + if (!map_is_created(map)) + return -1; + return map->fd; } static bool map_uses_real_name(const struct bpf_map *map) @@ -9630,7 +10071,7 @@ enum bpf_map_type bpf_map__type(const struct bpf_map *map) int bpf_map__set_type(struct bpf_map *map, enum bpf_map_type type) { - if (map->fd >= 0) + if (map_is_created(map)) return libbpf_err(-EBUSY); map->def.type = type; return 0; @@ -9643,7 +10084,7 @@ __u32 bpf_map__map_flags(const struct bpf_map *map) int bpf_map__set_map_flags(struct bpf_map *map, __u32 flags) { - if (map->fd >= 0) + if (map_is_created(map)) return libbpf_err(-EBUSY); map->def.map_flags = flags; return 0; @@ -9656,7 +10097,7 @@ __u64 bpf_map__map_extra(const struct bpf_map *map) int bpf_map__set_map_extra(struct bpf_map *map, __u64 map_extra) { - if (map->fd >= 0) + if (map_is_created(map)) return libbpf_err(-EBUSY); map->map_extra = map_extra; return 0; @@ -9669,7 +10110,7 @@ __u32 bpf_map__numa_node(const struct bpf_map *map) int bpf_map__set_numa_node(struct bpf_map *map, __u32 numa_node) { - if (map->fd >= 0) + if (map_is_created(map)) return libbpf_err(-EBUSY); map->numa_node = numa_node; return 0; @@ -9682,7 +10123,7 @@ __u32 bpf_map__key_size(const struct bpf_map *map) int bpf_map__set_key_size(struct bpf_map *map, __u32 size) { - if (map->fd >= 0) + if (map_is_created(map)) return libbpf_err(-EBUSY); map->def.key_size = size; return 0; @@ -9766,7 +10207,7 @@ static int map_btf_datasec_resize(struct bpf_map *map, __u32 size) int bpf_map__set_value_size(struct bpf_map *map, __u32 size) { - if (map->fd >= 0) + if (map->obj->loaded || map->reused) return libbpf_err(-EBUSY); if (map->mmaped) { @@ -9807,8 +10248,11 @@ __u32 bpf_map__btf_value_type_id(const struct bpf_map *map) int bpf_map__set_initial_value(struct bpf_map *map, const void *data, size_t size) { + if (map->obj->loaded || map->reused) + return libbpf_err(-EBUSY); + if (!map->mmaped || map->libbpf_type == LIBBPF_MAP_KCONFIG || - size != map->def.value_size || map->fd >= 0) + size != map->def.value_size) return libbpf_err(-EINVAL); memcpy(map->mmaped, data, size); @@ -9835,7 +10279,7 @@ __u32 bpf_map__ifindex(const struct bpf_map *map) int bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex) { - if (map->fd >= 0) + if (map_is_created(map)) return libbpf_err(-EBUSY); map->map_ifindex = ifindex; return 0; @@ -9940,7 +10384,7 @@ bpf_object__find_map_fd_by_name(const struct bpf_object *obj, const char *name) static int validate_map_op(const struct bpf_map *map, size_t key_sz, size_t value_sz, bool check_value_sz) { - if (map->fd <= 0) + if (!map_is_created(map)) /* map is not yet created */ return -ENOENT; if (map->def.key_size != key_sz) { @@ -11453,7 +11897,7 @@ bpf_program__attach_uprobe_multi(const struct bpf_program *prog, return libbpf_err_ptr(err); offsets = resolved_offsets; } else if (syms) { - err = elf_resolve_syms_offsets(path, cnt, syms, &resolved_offsets); + err = elf_resolve_syms_offsets(path, cnt, syms, &resolved_offsets, STT_FUNC); if (err < 0) return libbpf_err_ptr(err); offsets = resolved_offsets; @@ -12393,7 +12837,7 @@ int bpf_link__update_map(struct bpf_link *link, const struct bpf_map *map) __u32 zero = 0; int err; - if (!bpf_map__is_struct_ops(map) || map->fd < 0) + if (!bpf_map__is_struct_ops(map) || !map_is_created(map)) return -EINVAL; st_ops_link = container_of(link, struct bpf_link_struct_ops, link); @@ -13297,7 +13741,7 @@ int bpf_object__load_skeleton(struct bpf_object_skeleton *s) for (i = 0; i < s->map_cnt; i++) { struct bpf_map *map = *s->maps[i].map; size_t mmap_sz = bpf_map_mmap_sz(map->def.value_size, map->def.max_entries); - int prot, map_fd = bpf_map__fd(map); + int prot, map_fd = map->fd; void **mmaped = s->maps[i].mmaped; if (!mmaped) diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map index b52dc28dc8..91c5aef7da 100644 --- a/tools/lib/bpf/libbpf.map +++ b/tools/lib/bpf/libbpf.map @@ -409,3 +409,6 @@ LIBBPF_1.3.0 { ring__size; ring_buffer__ring; } LIBBPF_1.2.0; + +LIBBPF_1.4.0 { +} LIBBPF_1.3.0; diff --git a/tools/lib/bpf/libbpf_internal.h b/tools/lib/bpf/libbpf_internal.h index 57dec645d6..878a0d0b51 100644 --- a/tools/lib/bpf/libbpf_internal.h +++ b/tools/lib/bpf/libbpf_internal.h @@ -569,6 +569,20 @@ static inline int ensure_good_fd(int fd) return fd; } +/* Point *fixed_fd* to the same file that *tmp_fd* points to. + * Regardless of success, *tmp_fd* is closed. + * Whatever *fixed_fd* pointed to is closed silently. + */ +static inline int reuse_fd(int fixed_fd, int tmp_fd) +{ + int err; + + err = dup2(tmp_fd, fixed_fd); + err = err < 0 ? -errno : 0; + close(tmp_fd); /* clean up temporary FD */ + return err; +} + /* The following two functions are exposed to bpftool */ int bpf_core_add_cands(struct bpf_core_cand *local_cand, size_t local_essent_len, @@ -608,7 +622,8 @@ int elf_open(const char *binary_path, struct elf_fd *elf_fd); void elf_close(struct elf_fd *elf_fd); int elf_resolve_syms_offsets(const char *binary_path, int cnt, - const char **syms, unsigned long **poffsets); + const char **syms, unsigned long **poffsets, + int st_type); int elf_resolve_pattern_offsets(const char *binary_path, const char *pattern, unsigned long **poffsets, size_t *pcnt); diff --git a/tools/lib/bpf/libbpf_version.h b/tools/lib/bpf/libbpf_version.h index 290411ddb3..e783a47da8 100644 --- a/tools/lib/bpf/libbpf_version.h +++ b/tools/lib/bpf/libbpf_version.h @@ -4,6 +4,6 @@ #define __LIBBPF_VERSION_H #define LIBBPF_MAJOR_VERSION 1 -#define LIBBPF_MINOR_VERSION 3 +#define LIBBPF_MINOR_VERSION 4 #endif /* __LIBBPF_VERSION_H */ diff --git a/tools/lib/bpf/linker.c b/tools/lib/bpf/linker.c index 5ced96d99f..16bca56002 100644 --- a/tools/lib/bpf/linker.c +++ b/tools/lib/bpf/linker.c @@ -719,13 +719,28 @@ static int linker_sanity_check_elf(struct src_obj *obj) return -EINVAL; } - if (sec->shdr->sh_addralign && !is_pow_of_2(sec->shdr->sh_addralign)) + if (is_dwarf_sec_name(sec->sec_name)) + continue; + + if (sec->shdr->sh_addralign && !is_pow_of_2(sec->shdr->sh_addralign)) { + pr_warn("ELF section #%zu alignment %llu is non pow-of-2 alignment in %s\n", + sec->sec_idx, (long long unsigned)sec->shdr->sh_addralign, + obj->filename); return -EINVAL; - if (sec->shdr->sh_addralign != sec->data->d_align) + } + if (sec->shdr->sh_addralign != sec->data->d_align) { + pr_warn("ELF section #%zu has inconsistent alignment addr=%llu != d=%llu in %s\n", + sec->sec_idx, (long long unsigned)sec->shdr->sh_addralign, + (long long unsigned)sec->data->d_align, obj->filename); return -EINVAL; + } - if (sec->shdr->sh_size != sec->data->d_size) + if (sec->shdr->sh_size != sec->data->d_size) { + pr_warn("ELF section #%zu has inconsistent section size sh=%llu != d=%llu in %s\n", + sec->sec_idx, (long long unsigned)sec->shdr->sh_size, + (long long unsigned)sec->data->d_size, obj->filename); return -EINVAL; + } switch (sec->shdr->sh_type) { case SHT_SYMTAB: @@ -737,8 +752,12 @@ static int linker_sanity_check_elf(struct src_obj *obj) break; case SHT_PROGBITS: if (sec->shdr->sh_flags & SHF_EXECINSTR) { - if (sec->shdr->sh_size % sizeof(struct bpf_insn) != 0) + if (sec->shdr->sh_size % sizeof(struct bpf_insn) != 0) { + pr_warn("ELF section #%zu has unexpected size alignment %llu in %s\n", + sec->sec_idx, (long long unsigned)sec->shdr->sh_size, + obj->filename); return -EINVAL; + } } break; case SHT_NOBITS: diff --git a/tools/lib/perf/Documentation/examples/sampling.c b/tools/lib/perf/Documentation/examples/sampling.c index 8e1a926a9c..bc142f0664 100644 --- a/tools/lib/perf/Documentation/examples/sampling.c +++ b/tools/lib/perf/Documentation/examples/sampling.c @@ -39,7 +39,7 @@ int main(int argc, char **argv) libperf_init(libperf_print); - cpus = perf_cpu_map__new(NULL); + cpus = perf_cpu_map__new_online_cpus(); if (!cpus) { fprintf(stderr, "failed to create cpus\n"); return -1; diff --git a/tools/lib/perf/Documentation/libperf-sampling.txt b/tools/lib/perf/Documentation/libperf-sampling.txt index d6ca24f6ef..2378980fab 100644 --- a/tools/lib/perf/Documentation/libperf-sampling.txt +++ b/tools/lib/perf/Documentation/libperf-sampling.txt @@ -97,7 +97,7 @@ In this case we will monitor all the available CPUs: [source,c] -- - 42 cpus = perf_cpu_map__new(NULL); + 42 cpus = perf_cpu_map__new_online_cpus(); 43 if (!cpus) { 44 fprintf(stderr, "failed to create cpus\n"); 45 return -1; diff --git a/tools/lib/perf/Documentation/libperf.txt b/tools/lib/perf/Documentation/libperf.txt index a8f1a23793..fcfb9499ef 100644 --- a/tools/lib/perf/Documentation/libperf.txt +++ b/tools/lib/perf/Documentation/libperf.txt @@ -37,7 +37,7 @@ SYNOPSIS struct perf_cpu_map; - struct perf_cpu_map *perf_cpu_map__dummy_new(void); + struct perf_cpu_map *perf_cpu_map__new_any_cpu(void); struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list); struct perf_cpu_map *perf_cpu_map__read(FILE *file); struct perf_cpu_map *perf_cpu_map__get(struct perf_cpu_map *map); @@ -46,7 +46,7 @@ SYNOPSIS void perf_cpu_map__put(struct perf_cpu_map *map); int perf_cpu_map__cpu(const struct perf_cpu_map *cpus, int idx); int perf_cpu_map__nr(const struct perf_cpu_map *cpus); - bool perf_cpu_map__empty(const struct perf_cpu_map *map); + bool perf_cpu_map__has_any_cpu_or_is_empty(const struct perf_cpu_map *map); int perf_cpu_map__max(struct perf_cpu_map *map); bool perf_cpu_map__has(const struct perf_cpu_map *map, int cpu); diff --git a/tools/lib/perf/cpumap.c b/tools/lib/perf/cpumap.c index 2a5a292173..4adcd7920d 100644 --- a/tools/lib/perf/cpumap.c +++ b/tools/lib/perf/cpumap.c @@ -9,6 +9,7 @@ #include #include #include +#include "internal.h" void perf_cpu_map__set_nr(struct perf_cpu_map *map, int nr_cpus) { @@ -27,7 +28,7 @@ struct perf_cpu_map *perf_cpu_map__alloc(int nr_cpus) return result; } -struct perf_cpu_map *perf_cpu_map__dummy_new(void) +struct perf_cpu_map *perf_cpu_map__new_any_cpu(void) { struct perf_cpu_map *cpus = perf_cpu_map__alloc(1); @@ -66,15 +67,21 @@ void perf_cpu_map__put(struct perf_cpu_map *map) } } -static struct perf_cpu_map *cpu_map__default_new(void) +static struct perf_cpu_map *cpu_map__new_sysconf(void) { struct perf_cpu_map *cpus; - int nr_cpus; + int nr_cpus, nr_cpus_conf; nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); if (nr_cpus < 0) return NULL; + nr_cpus_conf = sysconf(_SC_NPROCESSORS_CONF); + if (nr_cpus != nr_cpus_conf) { + pr_warning("Number of online CPUs (%d) differs from the number configured (%d) the CPU map will only cover the first %d CPUs.", + nr_cpus, nr_cpus_conf, nr_cpus); + } + cpus = perf_cpu_map__alloc(nr_cpus); if (cpus != NULL) { int i; @@ -86,9 +93,27 @@ static struct perf_cpu_map *cpu_map__default_new(void) return cpus; } -struct perf_cpu_map *perf_cpu_map__default_new(void) +static struct perf_cpu_map *cpu_map__new_sysfs_online(void) { - return cpu_map__default_new(); + struct perf_cpu_map *cpus = NULL; + FILE *onlnf; + + onlnf = fopen("/sys/devices/system/cpu/online", "r"); + if (onlnf) { + cpus = perf_cpu_map__read(onlnf); + fclose(onlnf); + } + return cpus; +} + +struct perf_cpu_map *perf_cpu_map__new_online_cpus(void) +{ + struct perf_cpu_map *cpus = cpu_map__new_sysfs_online(); + + if (cpus) + return cpus; + + return cpu_map__new_sysconf(); } @@ -180,27 +205,11 @@ struct perf_cpu_map *perf_cpu_map__read(FILE *file) if (nr_cpus > 0) cpus = cpu_map__trim_new(nr_cpus, tmp_cpus); - else - cpus = cpu_map__default_new(); out_free_tmp: free(tmp_cpus); return cpus; } -static struct perf_cpu_map *cpu_map__read_all_cpu_map(void) -{ - struct perf_cpu_map *cpus = NULL; - FILE *onlnf; - - onlnf = fopen("/sys/devices/system/cpu/online", "r"); - if (!onlnf) - return cpu_map__default_new(); - - cpus = perf_cpu_map__read(onlnf); - fclose(onlnf); - return cpus; -} - struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list) { struct perf_cpu_map *cpus = NULL; @@ -211,7 +220,7 @@ struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list) int max_entries = 0; if (!cpu_list) - return cpu_map__read_all_cpu_map(); + return perf_cpu_map__new_online_cpus(); /* * must handle the case of empty cpumap to cover @@ -268,10 +277,12 @@ struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list) if (nr_cpus > 0) cpus = cpu_map__trim_new(nr_cpus, tmp_cpus); - else if (*cpu_list != '\0') - cpus = cpu_map__default_new(); - else - cpus = perf_cpu_map__dummy_new(); + else if (*cpu_list != '\0') { + pr_warning("Unexpected characters at end of cpu list ('%s'), using online CPUs.", + cpu_list); + cpus = perf_cpu_map__new_online_cpus(); + } else + cpus = perf_cpu_map__new_any_cpu(); invalid: free(tmp_cpus); out: @@ -300,7 +311,7 @@ int perf_cpu_map__nr(const struct perf_cpu_map *cpus) return cpus ? __perf_cpu_map__nr(cpus) : 1; } -bool perf_cpu_map__empty(const struct perf_cpu_map *map) +bool perf_cpu_map__has_any_cpu_or_is_empty(const struct perf_cpu_map *map) { return map ? __perf_cpu_map__cpu(map, 0).cpu == -1 : true; } diff --git a/tools/lib/perf/evlist.c b/tools/lib/perf/evlist.c index 3acbbccc19..c6d67fc9e5 100644 --- a/tools/lib/perf/evlist.c +++ b/tools/lib/perf/evlist.c @@ -39,7 +39,7 @@ static void __perf_evlist__propagate_maps(struct perf_evlist *evlist, if (evsel->system_wide) { /* System wide: set the cpu map of the evsel to all online CPUs. */ perf_cpu_map__put(evsel->cpus); - evsel->cpus = perf_cpu_map__new(NULL); + evsel->cpus = perf_cpu_map__new_online_cpus(); } else if (evlist->has_user_cpus && evsel->is_pmu_core) { /* * User requested CPUs on a core PMU, ensure the requested CPUs @@ -248,10 +248,10 @@ u64 perf_evlist__read_format(struct perf_evlist *evlist) static void perf_evlist__id_hash(struct perf_evlist *evlist, struct perf_evsel *evsel, - int cpu, int thread, u64 id) + int cpu_map_idx, int thread, u64 id) { int hash; - struct perf_sample_id *sid = SID(evsel, cpu, thread); + struct perf_sample_id *sid = SID(evsel, cpu_map_idx, thread); sid->id = id; sid->evsel = evsel; @@ -269,21 +269,27 @@ void perf_evlist__reset_id_hash(struct perf_evlist *evlist) void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel, - int cpu, int thread, u64 id) + int cpu_map_idx, int thread, u64 id) { - perf_evlist__id_hash(evlist, evsel, cpu, thread, id); + if (!SID(evsel, cpu_map_idx, thread)) + return; + + perf_evlist__id_hash(evlist, evsel, cpu_map_idx, thread, id); evsel->id[evsel->ids++] = id; } int perf_evlist__id_add_fd(struct perf_evlist *evlist, struct perf_evsel *evsel, - int cpu, int thread, int fd) + int cpu_map_idx, int thread, int fd) { u64 read_data[4] = { 0, }; int id_idx = 1; /* The first entry is the counter value */ u64 id; int ret; + if (!SID(evsel, cpu_map_idx, thread)) + return -1; + ret = ioctl(fd, PERF_EVENT_IOC_ID, &id); if (!ret) goto add; @@ -312,7 +318,7 @@ int perf_evlist__id_add_fd(struct perf_evlist *evlist, id = read_data[id_idx]; add: - perf_evlist__id_add(evlist, evsel, cpu, thread, id); + perf_evlist__id_add(evlist, evsel, cpu_map_idx, thread, id); return 0; } @@ -619,7 +625,7 @@ static int perf_evlist__nr_mmaps(struct perf_evlist *evlist) /* One for each CPU */ nr_mmaps = perf_cpu_map__nr(evlist->all_cpus); - if (perf_cpu_map__empty(evlist->all_cpus)) { + if (perf_cpu_map__has_any_cpu_or_is_empty(evlist->all_cpus)) { /* Plus one for each thread */ nr_mmaps += perf_thread_map__nr(evlist->threads); /* Minus the per-thread CPU (-1) */ @@ -653,7 +659,7 @@ int perf_evlist__mmap_ops(struct perf_evlist *evlist, if (evlist->pollfd.entries == NULL && perf_evlist__alloc_pollfd(evlist) < 0) return -ENOMEM; - if (perf_cpu_map__empty(cpus)) + if (perf_cpu_map__has_any_cpu_or_is_empty(cpus)) return mmap_per_thread(evlist, ops, mp); return mmap_per_cpu(evlist, ops, mp); diff --git a/tools/lib/perf/evsel.c b/tools/lib/perf/evsel.c index 8b51b008a8..c071609532 100644 --- a/tools/lib/perf/evsel.c +++ b/tools/lib/perf/evsel.c @@ -120,7 +120,7 @@ int perf_evsel__open(struct perf_evsel *evsel, struct perf_cpu_map *cpus, static struct perf_cpu_map *empty_cpu_map; if (empty_cpu_map == NULL) { - empty_cpu_map = perf_cpu_map__dummy_new(); + empty_cpu_map = perf_cpu_map__new_any_cpu(); if (empty_cpu_map == NULL) return -ENOMEM; } diff --git a/tools/lib/perf/include/internal/evlist.h b/tools/lib/perf/include/internal/evlist.h index d86ffe8ed4..f43bdb9b62 100644 --- a/tools/lib/perf/include/internal/evlist.h +++ b/tools/lib/perf/include/internal/evlist.h @@ -126,11 +126,11 @@ u64 perf_evlist__read_format(struct perf_evlist *evlist); void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel, - int cpu, int thread, u64 id); + int cpu_map_idx, int thread, u64 id); int perf_evlist__id_add_fd(struct perf_evlist *evlist, struct perf_evsel *evsel, - int cpu, int thread, int fd); + int cpu_map_idx, int thread, int fd); void perf_evlist__reset_id_hash(struct perf_evlist *evlist); diff --git a/tools/lib/perf/include/internal/mmap.h b/tools/lib/perf/include/internal/mmap.h index 5a062af8e9..5f08cab61e 100644 --- a/tools/lib/perf/include/internal/mmap.h +++ b/tools/lib/perf/include/internal/mmap.h @@ -33,7 +33,8 @@ struct perf_mmap { bool overwrite; u64 flush; libperf_unmap_cb_t unmap_cb; - char event_copy[PERF_SAMPLE_MAX_SIZE] __aligned(8); + void *event_copy; + size_t event_copy_sz; struct perf_mmap *next; }; diff --git a/tools/lib/perf/include/perf/cpumap.h b/tools/lib/perf/include/perf/cpumap.h index e38d859a38..228c6c629b 100644 --- a/tools/lib/perf/include/perf/cpumap.h +++ b/tools/lib/perf/include/perf/cpumap.h @@ -19,10 +19,23 @@ struct perf_cache { struct perf_cpu_map; /** - * perf_cpu_map__dummy_new - a map with a singular "any CPU"/dummy -1 value. + * perf_cpu_map__new_any_cpu - a map with a singular "any CPU"/dummy -1 value. + */ +LIBPERF_API struct perf_cpu_map *perf_cpu_map__new_any_cpu(void); +/** + * perf_cpu_map__new_online_cpus - a map read from + * /sys/devices/system/cpu/online if + * available. If reading wasn't possible a map + * is created using the online processors + * assuming the first 'n' processors are all + * online. + */ +LIBPERF_API struct perf_cpu_map *perf_cpu_map__new_online_cpus(void); +/** + * perf_cpu_map__new - create a map from the given cpu_list such as "0-7". If no + * cpu_list argument is provided then + * perf_cpu_map__new_online_cpus is returned. */ -LIBPERF_API struct perf_cpu_map *perf_cpu_map__dummy_new(void); -LIBPERF_API struct perf_cpu_map *perf_cpu_map__default_new(void); LIBPERF_API struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list); LIBPERF_API struct perf_cpu_map *perf_cpu_map__read(FILE *file); LIBPERF_API struct perf_cpu_map *perf_cpu_map__get(struct perf_cpu_map *map); @@ -31,12 +44,23 @@ LIBPERF_API struct perf_cpu_map *perf_cpu_map__merge(struct perf_cpu_map *orig, LIBPERF_API struct perf_cpu_map *perf_cpu_map__intersect(struct perf_cpu_map *orig, struct perf_cpu_map *other); LIBPERF_API void perf_cpu_map__put(struct perf_cpu_map *map); +/** + * perf_cpu_map__cpu - get the CPU value at the given index. Returns -1 if index + * is invalid. + */ LIBPERF_API struct perf_cpu perf_cpu_map__cpu(const struct perf_cpu_map *cpus, int idx); +/** + * perf_cpu_map__nr - for an empty map returns 1, as perf_cpu_map__cpu returns a + * cpu of -1 for an invalid index, this makes an empty map + * look like it contains the "any CPU"/dummy value. Otherwise + * the result is the number CPUs in the map plus one if the + * "any CPU"/dummy value is present. + */ LIBPERF_API int perf_cpu_map__nr(const struct perf_cpu_map *cpus); /** - * perf_cpu_map__empty - is map either empty or the "any CPU"/dummy value. + * perf_cpu_map__has_any_cpu_or_is_empty - is map either empty or has the "any CPU"/dummy value. */ -LIBPERF_API bool perf_cpu_map__empty(const struct perf_cpu_map *map); +LIBPERF_API bool perf_cpu_map__has_any_cpu_or_is_empty(const struct perf_cpu_map *map); LIBPERF_API struct perf_cpu perf_cpu_map__max(const struct perf_cpu_map *map); LIBPERF_API bool perf_cpu_map__has(const struct perf_cpu_map *map, struct perf_cpu cpu); LIBPERF_API bool perf_cpu_map__equal(const struct perf_cpu_map *lhs, @@ -51,6 +75,12 @@ LIBPERF_API bool perf_cpu_map__has_any_cpu(const struct perf_cpu_map *map); (idx) < perf_cpu_map__nr(cpus); \ (idx)++, (cpu) = perf_cpu_map__cpu(cpus, idx)) +#define perf_cpu_map__for_each_cpu_skip_any(_cpu, idx, cpus) \ + for ((idx) = 0, (_cpu) = perf_cpu_map__cpu(cpus, idx); \ + (idx) < perf_cpu_map__nr(cpus); \ + (idx)++, (_cpu) = perf_cpu_map__cpu(cpus, idx)) \ + if ((_cpu).cpu != -1) + #define perf_cpu_map__for_each_idx(idx, cpus) \ for ((idx) = 0; (idx) < perf_cpu_map__nr(cpus); (idx)++) diff --git a/tools/lib/perf/libperf.map b/tools/lib/perf/libperf.map index 190b56ae92..10b3f37226 100644 --- a/tools/lib/perf/libperf.map +++ b/tools/lib/perf/libperf.map @@ -1,15 +1,15 @@ LIBPERF_0.0.1 { global: libperf_init; - perf_cpu_map__dummy_new; - perf_cpu_map__default_new; + perf_cpu_map__new_any_cpu; + perf_cpu_map__new_online_cpus; perf_cpu_map__get; perf_cpu_map__put; perf_cpu_map__new; perf_cpu_map__read; perf_cpu_map__nr; perf_cpu_map__cpu; - perf_cpu_map__empty; + perf_cpu_map__has_any_cpu_or_is_empty; perf_cpu_map__max; perf_cpu_map__has; perf_thread_map__new_array; diff --git a/tools/lib/perf/mmap.c b/tools/lib/perf/mmap.c index 2184814b37..0c903c2372 100644 --- a/tools/lib/perf/mmap.c +++ b/tools/lib/perf/mmap.c @@ -19,6 +19,7 @@ void perf_mmap__init(struct perf_mmap *map, struct perf_mmap *prev, bool overwrite, libperf_unmap_cb_t unmap_cb) { + /* Assume fields were zero initialized. */ map->fd = -1; map->overwrite = overwrite; map->unmap_cb = unmap_cb; @@ -51,13 +52,18 @@ int perf_mmap__mmap(struct perf_mmap *map, struct perf_mmap_param *mp, void perf_mmap__munmap(struct perf_mmap *map) { - if (map && map->base != NULL) { + if (!map) + return; + + zfree(&map->event_copy); + map->event_copy_sz = 0; + if (map->base) { munmap(map->base, perf_mmap__mmap_len(map)); map->base = NULL; map->fd = -1; refcount_set(&map->refcnt, 0); } - if (map && map->unmap_cb) + if (map->unmap_cb) map->unmap_cb(map); } @@ -223,9 +229,17 @@ static union perf_event *perf_mmap__read(struct perf_mmap *map, */ if ((*startp & map->mask) + size != ((*startp + size) & map->mask)) { unsigned int offset = *startp; - unsigned int len = min(sizeof(*event), size), cpy; + unsigned int len = size, cpy; void *dst = map->event_copy; + if (size > map->event_copy_sz) { + dst = realloc(map->event_copy, size); + if (!dst) + return NULL; + map->event_copy = dst; + map->event_copy_sz = size; + } + do { cpy = min(map->mask + 1 - (offset & map->mask), len); memcpy(dst, &data[offset & map->mask], cpy); diff --git a/tools/lib/perf/tests/test-cpumap.c b/tools/lib/perf/tests/test-cpumap.c index 87b0510a55..c998b1dae8 100644 --- a/tools/lib/perf/tests/test-cpumap.c +++ b/tools/lib/perf/tests/test-cpumap.c @@ -21,7 +21,7 @@ int test_cpumap(int argc, char **argv) libperf_init(libperf_print); - cpus = perf_cpu_map__dummy_new(); + cpus = perf_cpu_map__new_any_cpu(); if (!cpus) return -1; @@ -29,7 +29,7 @@ int test_cpumap(int argc, char **argv) perf_cpu_map__put(cpus); perf_cpu_map__put(cpus); - cpus = perf_cpu_map__default_new(); + cpus = perf_cpu_map__new_online_cpus(); if (!cpus) return -1; diff --git a/tools/lib/perf/tests/test-evlist.c b/tools/lib/perf/tests/test-evlist.c index ed616fc19b..10f70cb41f 100644 --- a/tools/lib/perf/tests/test-evlist.c +++ b/tools/lib/perf/tests/test-evlist.c @@ -46,7 +46,7 @@ static int test_stat_cpu(void) }; int err, idx; - cpus = perf_cpu_map__new(NULL); + cpus = perf_cpu_map__new_online_cpus(); __T("failed to create cpus", cpus); evlist = perf_evlist__new(); @@ -261,7 +261,7 @@ static int test_mmap_thread(void) threads = perf_thread_map__new_dummy(); __T("failed to create threads", threads); - cpus = perf_cpu_map__dummy_new(); + cpus = perf_cpu_map__new_any_cpu(); __T("failed to create cpus", cpus); perf_thread_map__set_pid(threads, 0, pid); @@ -350,7 +350,7 @@ static int test_mmap_cpus(void) attr.config = id; - cpus = perf_cpu_map__new(NULL); + cpus = perf_cpu_map__new_online_cpus(); __T("failed to create cpus", cpus); evlist = perf_evlist__new(); diff --git a/tools/lib/perf/tests/test-evsel.c b/tools/lib/perf/tests/test-evsel.c index a11fc51bfb..545ec31505 100644 --- a/tools/lib/perf/tests/test-evsel.c +++ b/tools/lib/perf/tests/test-evsel.c @@ -27,7 +27,7 @@ static int test_stat_cpu(void) }; int err, idx; - cpus = perf_cpu_map__new(NULL); + cpus = perf_cpu_map__new_online_cpus(); __T("failed to create cpus", cpus); evsel = perf_evsel__new(&attr); diff --git a/tools/net/ynl/Makefile b/tools/net/ynl/Makefile index d664b36deb..da1aa10bbc 100644 --- a/tools/net/ynl/Makefile +++ b/tools/net/ynl/Makefile @@ -4,6 +4,8 @@ SUBDIRS = lib generated samples all: $(SUBDIRS) +samples: | lib generated + $(SUBDIRS): @if [ -f "$@/Makefile" ] ; then \ $(MAKE) -C $@ ; \ diff --git a/tools/net/ynl/generated/.gitignore b/tools/net/ynl/generated/.gitignore new file mode 100644 index 0000000000..ade488626d --- /dev/null +++ b/tools/net/ynl/generated/.gitignore @@ -0,0 +1,2 @@ +*-user.c +*-user.h diff --git a/tools/net/ynl/generated/devlink-user.c b/tools/net/ynl/generated/devlink-user.c deleted file mode 100644 index 8e757e249d..0000000000 --- a/tools/net/ynl/generated/devlink-user.c +++ /dev/null @@ -1,6864 +0,0 @@ -// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/devlink.yaml */ -/* YNL-GEN user source */ - -#include -#include -#include "devlink-user.h" -#include "ynl.h" -#include - -#include -#include - -/* Enums */ -static const char * const devlink_op_strmap[] = { - [3] = "get", - // skip "port-get", duplicate reply value - [DEVLINK_CMD_PORT_NEW] = "port-new", - [13] = "sb-get", - [17] = "sb-pool-get", - [21] = "sb-port-pool-get", - [25] = "sb-tc-pool-bind-get", - [DEVLINK_CMD_ESWITCH_GET] = "eswitch-get", - [DEVLINK_CMD_DPIPE_TABLE_GET] = "dpipe-table-get", - [DEVLINK_CMD_DPIPE_ENTRIES_GET] = "dpipe-entries-get", - [DEVLINK_CMD_DPIPE_HEADERS_GET] = "dpipe-headers-get", - [DEVLINK_CMD_RESOURCE_DUMP] = "resource-dump", - [DEVLINK_CMD_RELOAD] = "reload", - [DEVLINK_CMD_PARAM_GET] = "param-get", - [DEVLINK_CMD_REGION_GET] = "region-get", - [DEVLINK_CMD_REGION_NEW] = "region-new", - [DEVLINK_CMD_REGION_READ] = "region-read", - [DEVLINK_CMD_PORT_PARAM_GET] = "port-param-get", - [DEVLINK_CMD_INFO_GET] = "info-get", - [DEVLINK_CMD_HEALTH_REPORTER_GET] = "health-reporter-get", - [DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET] = "health-reporter-dump-get", - [63] = "trap-get", - [67] = "trap-group-get", - [71] = "trap-policer-get", - [76] = "rate-get", - [80] = "linecard-get", - [DEVLINK_CMD_SELFTESTS_GET] = "selftests-get", -}; - -const char *devlink_op_str(int op) -{ - if (op < 0 || op >= (int)MNL_ARRAY_SIZE(devlink_op_strmap)) - return NULL; - return devlink_op_strmap[op]; -} - -static const char * const devlink_sb_pool_type_strmap[] = { - [0] = "ingress", - [1] = "egress", -}; - -const char *devlink_sb_pool_type_str(enum devlink_sb_pool_type value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_sb_pool_type_strmap)) - return NULL; - return devlink_sb_pool_type_strmap[value]; -} - -static const char * const devlink_port_type_strmap[] = { - [0] = "notset", - [1] = "auto", - [2] = "eth", - [3] = "ib", -}; - -const char *devlink_port_type_str(enum devlink_port_type value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_port_type_strmap)) - return NULL; - return devlink_port_type_strmap[value]; -} - -static const char * const devlink_port_flavour_strmap[] = { - [0] = "physical", - [1] = "cpu", - [2] = "dsa", - [3] = "pci_pf", - [4] = "pci_vf", - [5] = "virtual", - [6] = "unused", - [7] = "pci_sf", -}; - -const char *devlink_port_flavour_str(enum devlink_port_flavour value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_port_flavour_strmap)) - return NULL; - return devlink_port_flavour_strmap[value]; -} - -static const char * const devlink_port_fn_state_strmap[] = { - [0] = "inactive", - [1] = "active", -}; - -const char *devlink_port_fn_state_str(enum devlink_port_fn_state value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_port_fn_state_strmap)) - return NULL; - return devlink_port_fn_state_strmap[value]; -} - -static const char * const devlink_port_fn_opstate_strmap[] = { - [0] = "detached", - [1] = "attached", -}; - -const char *devlink_port_fn_opstate_str(enum devlink_port_fn_opstate value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_port_fn_opstate_strmap)) - return NULL; - return devlink_port_fn_opstate_strmap[value]; -} - -static const char * const devlink_port_fn_attr_cap_strmap[] = { - [0] = "roce-bit", - [1] = "migratable-bit", - [2] = "ipsec-crypto-bit", - [3] = "ipsec-packet-bit", -}; - -const char *devlink_port_fn_attr_cap_str(enum devlink_port_fn_attr_cap value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_port_fn_attr_cap_strmap)) - return NULL; - return devlink_port_fn_attr_cap_strmap[value]; -} - -static const char * const devlink_sb_threshold_type_strmap[] = { - [0] = "static", - [1] = "dynamic", -}; - -const char *devlink_sb_threshold_type_str(enum devlink_sb_threshold_type value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_sb_threshold_type_strmap)) - return NULL; - return devlink_sb_threshold_type_strmap[value]; -} - -static const char * const devlink_eswitch_mode_strmap[] = { - [0] = "legacy", - [1] = "switchdev", -}; - -const char *devlink_eswitch_mode_str(enum devlink_eswitch_mode value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_eswitch_mode_strmap)) - return NULL; - return devlink_eswitch_mode_strmap[value]; -} - -static const char * const devlink_eswitch_inline_mode_strmap[] = { - [0] = "none", - [1] = "link", - [2] = "network", - [3] = "transport", -}; - -const char * -devlink_eswitch_inline_mode_str(enum devlink_eswitch_inline_mode value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_eswitch_inline_mode_strmap)) - return NULL; - return devlink_eswitch_inline_mode_strmap[value]; -} - -static const char * const devlink_eswitch_encap_mode_strmap[] = { - [0] = "none", - [1] = "basic", -}; - -const char * -devlink_eswitch_encap_mode_str(enum devlink_eswitch_encap_mode value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_eswitch_encap_mode_strmap)) - return NULL; - return devlink_eswitch_encap_mode_strmap[value]; -} - -static const char * const devlink_dpipe_match_type_strmap[] = { - [0] = "field-exact", -}; - -const char *devlink_dpipe_match_type_str(enum devlink_dpipe_match_type value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_dpipe_match_type_strmap)) - return NULL; - return devlink_dpipe_match_type_strmap[value]; -} - -static const char * const devlink_dpipe_action_type_strmap[] = { - [0] = "field-modify", -}; - -const char *devlink_dpipe_action_type_str(enum devlink_dpipe_action_type value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_dpipe_action_type_strmap)) - return NULL; - return devlink_dpipe_action_type_strmap[value]; -} - -static const char * const devlink_dpipe_field_mapping_type_strmap[] = { - [0] = "none", - [1] = "ifindex", -}; - -const char * -devlink_dpipe_field_mapping_type_str(enum devlink_dpipe_field_mapping_type value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_dpipe_field_mapping_type_strmap)) - return NULL; - return devlink_dpipe_field_mapping_type_strmap[value]; -} - -static const char * const devlink_resource_unit_strmap[] = { - [0] = "entry", -}; - -const char *devlink_resource_unit_str(enum devlink_resource_unit value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_resource_unit_strmap)) - return NULL; - return devlink_resource_unit_strmap[value]; -} - -static const char * const devlink_reload_action_strmap[] = { - [1] = "driver-reinit", - [2] = "fw-activate", -}; - -const char *devlink_reload_action_str(enum devlink_reload_action value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_reload_action_strmap)) - return NULL; - return devlink_reload_action_strmap[value]; -} - -static const char * const devlink_param_cmode_strmap[] = { - [0] = "runtime", - [1] = "driverinit", - [2] = "permanent", -}; - -const char *devlink_param_cmode_str(enum devlink_param_cmode value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_param_cmode_strmap)) - return NULL; - return devlink_param_cmode_strmap[value]; -} - -static const char * const devlink_flash_overwrite_strmap[] = { - [0] = "settings-bit", - [1] = "identifiers-bit", -}; - -const char *devlink_flash_overwrite_str(enum devlink_flash_overwrite value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_flash_overwrite_strmap)) - return NULL; - return devlink_flash_overwrite_strmap[value]; -} - -static const char * const devlink_trap_action_strmap[] = { - [0] = "drop", - [1] = "trap", - [2] = "mirror", -}; - -const char *devlink_trap_action_str(enum devlink_trap_action value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_trap_action_strmap)) - return NULL; - return devlink_trap_action_strmap[value]; -} - -/* Policies */ -struct ynl_policy_attr devlink_dl_dpipe_match_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_DPIPE_MATCH_TYPE] = { .name = "dpipe-match-type", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_DPIPE_HEADER_ID] = { .name = "dpipe-header-id", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_DPIPE_HEADER_GLOBAL] = { .name = "dpipe-header-global", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_DPIPE_HEADER_INDEX] = { .name = "dpipe-header-index", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_DPIPE_FIELD_ID] = { .name = "dpipe-field-id", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest devlink_dl_dpipe_match_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dpipe_match_policy, -}; - -struct ynl_policy_attr devlink_dl_dpipe_match_value_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_DPIPE_MATCH] = { .name = "dpipe-match", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_match_nest, }, - [DEVLINK_ATTR_DPIPE_VALUE] = { .name = "dpipe-value", .type = YNL_PT_BINARY,}, - [DEVLINK_ATTR_DPIPE_VALUE_MASK] = { .name = "dpipe-value-mask", .type = YNL_PT_BINARY,}, - [DEVLINK_ATTR_DPIPE_VALUE_MAPPING] = { .name = "dpipe-value-mapping", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest devlink_dl_dpipe_match_value_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dpipe_match_value_policy, -}; - -struct ynl_policy_attr devlink_dl_dpipe_action_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_DPIPE_ACTION_TYPE] = { .name = "dpipe-action-type", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_DPIPE_HEADER_ID] = { .name = "dpipe-header-id", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_DPIPE_HEADER_GLOBAL] = { .name = "dpipe-header-global", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_DPIPE_HEADER_INDEX] = { .name = "dpipe-header-index", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_DPIPE_FIELD_ID] = { .name = "dpipe-field-id", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest devlink_dl_dpipe_action_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dpipe_action_policy, -}; - -struct ynl_policy_attr devlink_dl_dpipe_action_value_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_DPIPE_ACTION] = { .name = "dpipe-action", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_action_nest, }, - [DEVLINK_ATTR_DPIPE_VALUE] = { .name = "dpipe-value", .type = YNL_PT_BINARY,}, - [DEVLINK_ATTR_DPIPE_VALUE_MASK] = { .name = "dpipe-value-mask", .type = YNL_PT_BINARY,}, - [DEVLINK_ATTR_DPIPE_VALUE_MAPPING] = { .name = "dpipe-value-mapping", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest devlink_dl_dpipe_action_value_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dpipe_action_value_policy, -}; - -struct ynl_policy_attr devlink_dl_dpipe_field_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_DPIPE_FIELD_NAME] = { .name = "dpipe-field-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_DPIPE_FIELD_ID] = { .name = "dpipe-field-id", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH] = { .name = "dpipe-field-bitwidth", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE] = { .name = "dpipe-field-mapping-type", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest devlink_dl_dpipe_field_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dpipe_field_policy, -}; - -struct ynl_policy_attr devlink_dl_resource_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_RESOURCE_NAME] = { .name = "resource-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_RESOURCE_ID] = { .name = "resource-id", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_RESOURCE_SIZE] = { .name = "resource-size", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_RESOURCE_SIZE_NEW] = { .name = "resource-size-new", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_RESOURCE_SIZE_VALID] = { .name = "resource-size-valid", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_RESOURCE_SIZE_MIN] = { .name = "resource-size-min", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_RESOURCE_SIZE_MAX] = { .name = "resource-size-max", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_RESOURCE_SIZE_GRAN] = { .name = "resource-size-gran", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_RESOURCE_UNIT] = { .name = "resource-unit", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_RESOURCE_OCC] = { .name = "resource-occ", .type = YNL_PT_U64, }, -}; - -struct ynl_policy_nest devlink_dl_resource_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_resource_policy, -}; - -struct ynl_policy_attr devlink_dl_info_version_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_INFO_VERSION_NAME] = { .name = "info-version-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_INFO_VERSION_VALUE] = { .name = "info-version-value", .type = YNL_PT_NUL_STR, }, -}; - -struct ynl_policy_nest devlink_dl_info_version_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_info_version_policy, -}; - -struct ynl_policy_attr devlink_dl_fmsg_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_FMSG_OBJ_NEST_START] = { .name = "fmsg-obj-nest-start", .type = YNL_PT_FLAG, }, - [DEVLINK_ATTR_FMSG_PAIR_NEST_START] = { .name = "fmsg-pair-nest-start", .type = YNL_PT_FLAG, }, - [DEVLINK_ATTR_FMSG_ARR_NEST_START] = { .name = "fmsg-arr-nest-start", .type = YNL_PT_FLAG, }, - [DEVLINK_ATTR_FMSG_NEST_END] = { .name = "fmsg-nest-end", .type = YNL_PT_FLAG, }, - [DEVLINK_ATTR_FMSG_OBJ_NAME] = { .name = "fmsg-obj-name", .type = YNL_PT_NUL_STR, }, -}; - -struct ynl_policy_nest devlink_dl_fmsg_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_fmsg_policy, -}; - -struct ynl_policy_attr devlink_dl_port_function_policy[DEVLINK_PORT_FUNCTION_ATTR_MAX + 1] = { - [DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR] = { .name = "hw-addr", .type = YNL_PT_BINARY,}, - [DEVLINK_PORT_FN_ATTR_STATE] = { .name = "state", .type = YNL_PT_U8, }, - [DEVLINK_PORT_FN_ATTR_OPSTATE] = { .name = "opstate", .type = YNL_PT_U8, }, - [DEVLINK_PORT_FN_ATTR_CAPS] = { .name = "caps", .type = YNL_PT_BITFIELD32, }, -}; - -struct ynl_policy_nest devlink_dl_port_function_nest = { - .max_attr = DEVLINK_PORT_FUNCTION_ATTR_MAX, - .table = devlink_dl_port_function_policy, -}; - -struct ynl_policy_attr devlink_dl_reload_stats_entry_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_RELOAD_STATS_LIMIT] = { .name = "reload-stats-limit", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_RELOAD_STATS_VALUE] = { .name = "reload-stats-value", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest devlink_dl_reload_stats_entry_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_reload_stats_entry_policy, -}; - -struct ynl_policy_attr devlink_dl_reload_act_stats_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_RELOAD_STATS_ENTRY] = { .name = "reload-stats-entry", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_entry_nest, }, -}; - -struct ynl_policy_nest devlink_dl_reload_act_stats_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_reload_act_stats_policy, -}; - -struct ynl_policy_attr devlink_dl_selftest_id_policy[DEVLINK_ATTR_SELFTEST_ID_MAX + 1] = { - [DEVLINK_ATTR_SELFTEST_ID_FLASH] = { .name = "flash", .type = YNL_PT_FLAG, }, -}; - -struct ynl_policy_nest devlink_dl_selftest_id_nest = { - .max_attr = DEVLINK_ATTR_SELFTEST_ID_MAX, - .table = devlink_dl_selftest_id_policy, -}; - -struct ynl_policy_attr devlink_dl_dpipe_table_matches_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_DPIPE_MATCH] = { .name = "dpipe-match", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_match_nest, }, -}; - -struct ynl_policy_nest devlink_dl_dpipe_table_matches_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dpipe_table_matches_policy, -}; - -struct ynl_policy_attr devlink_dl_dpipe_table_actions_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_DPIPE_ACTION] = { .name = "dpipe-action", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_action_nest, }, -}; - -struct ynl_policy_nest devlink_dl_dpipe_table_actions_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dpipe_table_actions_policy, -}; - -struct ynl_policy_attr devlink_dl_dpipe_entry_match_values_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_DPIPE_MATCH_VALUE] = { .name = "dpipe-match-value", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_match_value_nest, }, -}; - -struct ynl_policy_nest devlink_dl_dpipe_entry_match_values_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dpipe_entry_match_values_policy, -}; - -struct ynl_policy_attr devlink_dl_dpipe_entry_action_values_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_DPIPE_ACTION_VALUE] = { .name = "dpipe-action-value", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_action_value_nest, }, -}; - -struct ynl_policy_nest devlink_dl_dpipe_entry_action_values_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dpipe_entry_action_values_policy, -}; - -struct ynl_policy_attr devlink_dl_dpipe_header_fields_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_DPIPE_FIELD] = { .name = "dpipe-field", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_field_nest, }, -}; - -struct ynl_policy_nest devlink_dl_dpipe_header_fields_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dpipe_header_fields_policy, -}; - -struct ynl_policy_attr devlink_dl_resource_list_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_RESOURCE] = { .name = "resource", .type = YNL_PT_NEST, .nest = &devlink_dl_resource_nest, }, -}; - -struct ynl_policy_nest devlink_dl_resource_list_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_resource_list_policy, -}; - -struct ynl_policy_attr devlink_dl_reload_act_info_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_RELOAD_ACTION] = { .name = "reload-action", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_RELOAD_ACTION_STATS] = { .name = "reload-action-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_act_stats_nest, }, -}; - -struct ynl_policy_nest devlink_dl_reload_act_info_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_reload_act_info_policy, -}; - -struct ynl_policy_attr devlink_dl_dpipe_table_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_DPIPE_TABLE_NAME] = { .name = "dpipe-table-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_DPIPE_TABLE_SIZE] = { .name = "dpipe-table-size", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_DPIPE_TABLE_MATCHES] = { .name = "dpipe-table-matches", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_table_matches_nest, }, - [DEVLINK_ATTR_DPIPE_TABLE_ACTIONS] = { .name = "dpipe-table-actions", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_table_actions_nest, }, - [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = { .name = "dpipe-table-counters-enabled", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID] = { .name = "dpipe-table-resource-id", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS] = { .name = "dpipe-table-resource-units", .type = YNL_PT_U64, }, -}; - -struct ynl_policy_nest devlink_dl_dpipe_table_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dpipe_table_policy, -}; - -struct ynl_policy_attr devlink_dl_dpipe_entry_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_DPIPE_ENTRY_INDEX] = { .name = "dpipe-entry-index", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES] = { .name = "dpipe-entry-match-values", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_entry_match_values_nest, }, - [DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES] = { .name = "dpipe-entry-action-values", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_entry_action_values_nest, }, - [DEVLINK_ATTR_DPIPE_ENTRY_COUNTER] = { .name = "dpipe-entry-counter", .type = YNL_PT_U64, }, -}; - -struct ynl_policy_nest devlink_dl_dpipe_entry_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dpipe_entry_policy, -}; - -struct ynl_policy_attr devlink_dl_dpipe_header_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_DPIPE_HEADER_NAME] = { .name = "dpipe-header-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_DPIPE_HEADER_ID] = { .name = "dpipe-header-id", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_DPIPE_HEADER_GLOBAL] = { .name = "dpipe-header-global", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_DPIPE_HEADER_FIELDS] = { .name = "dpipe-header-fields", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_header_fields_nest, }, -}; - -struct ynl_policy_nest devlink_dl_dpipe_header_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dpipe_header_policy, -}; - -struct ynl_policy_attr devlink_dl_reload_stats_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_RELOAD_ACTION_INFO] = { .name = "reload-action-info", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_act_info_nest, }, -}; - -struct ynl_policy_nest devlink_dl_reload_stats_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_reload_stats_policy, -}; - -struct ynl_policy_attr devlink_dl_dpipe_tables_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_DPIPE_TABLE] = { .name = "dpipe-table", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_table_nest, }, -}; - -struct ynl_policy_nest devlink_dl_dpipe_tables_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dpipe_tables_policy, -}; - -struct ynl_policy_attr devlink_dl_dpipe_entries_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_DPIPE_ENTRY] = { .name = "dpipe-entry", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_entry_nest, }, -}; - -struct ynl_policy_nest devlink_dl_dpipe_entries_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dpipe_entries_policy, -}; - -struct ynl_policy_attr devlink_dl_dpipe_headers_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_DPIPE_HEADER] = { .name = "dpipe-header", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_header_nest, }, -}; - -struct ynl_policy_nest devlink_dl_dpipe_headers_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dpipe_headers_policy, -}; - -struct ynl_policy_attr devlink_dl_dev_stats_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_RELOAD_STATS] = { .name = "reload-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_nest, }, - [DEVLINK_ATTR_REMOTE_RELOAD_STATS] = { .name = "remote-reload-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_nest, }, -}; - -struct ynl_policy_nest devlink_dl_dev_stats_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_dl_dev_stats_policy, -}; - -struct ynl_policy_attr devlink_policy[DEVLINK_ATTR_MAX + 1] = { - [DEVLINK_ATTR_BUS_NAME] = { .name = "bus-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_DEV_NAME] = { .name = "dev-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_PORT_INDEX] = { .name = "port-index", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_PORT_TYPE] = { .name = "port-type", .type = YNL_PT_U16, }, - [DEVLINK_ATTR_PORT_SPLIT_COUNT] = { .name = "port-split-count", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_SB_INDEX] = { .name = "sb-index", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_SB_POOL_INDEX] = { .name = "sb-pool-index", .type = YNL_PT_U16, }, - [DEVLINK_ATTR_SB_POOL_TYPE] = { .name = "sb-pool-type", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_SB_POOL_SIZE] = { .name = "sb-pool-size", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = { .name = "sb-pool-threshold-type", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_SB_THRESHOLD] = { .name = "sb-threshold", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_SB_TC_INDEX] = { .name = "sb-tc-index", .type = YNL_PT_U16, }, - [DEVLINK_ATTR_ESWITCH_MODE] = { .name = "eswitch-mode", .type = YNL_PT_U16, }, - [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = { .name = "eswitch-inline-mode", .type = YNL_PT_U16, }, - [DEVLINK_ATTR_DPIPE_TABLES] = { .name = "dpipe-tables", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_tables_nest, }, - [DEVLINK_ATTR_DPIPE_TABLE] = { .name = "dpipe-table", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_table_nest, }, - [DEVLINK_ATTR_DPIPE_TABLE_NAME] = { .name = "dpipe-table-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_DPIPE_TABLE_SIZE] = { .name = "dpipe-table-size", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_DPIPE_TABLE_MATCHES] = { .name = "dpipe-table-matches", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_table_matches_nest, }, - [DEVLINK_ATTR_DPIPE_TABLE_ACTIONS] = { .name = "dpipe-table-actions", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_table_actions_nest, }, - [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = { .name = "dpipe-table-counters-enabled", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_DPIPE_ENTRIES] = { .name = "dpipe-entries", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_entries_nest, }, - [DEVLINK_ATTR_DPIPE_ENTRY] = { .name = "dpipe-entry", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_entry_nest, }, - [DEVLINK_ATTR_DPIPE_ENTRY_INDEX] = { .name = "dpipe-entry-index", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES] = { .name = "dpipe-entry-match-values", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_entry_match_values_nest, }, - [DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES] = { .name = "dpipe-entry-action-values", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_entry_action_values_nest, }, - [DEVLINK_ATTR_DPIPE_ENTRY_COUNTER] = { .name = "dpipe-entry-counter", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_DPIPE_MATCH] = { .name = "dpipe-match", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_match_nest, }, - [DEVLINK_ATTR_DPIPE_MATCH_VALUE] = { .name = "dpipe-match-value", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_match_value_nest, }, - [DEVLINK_ATTR_DPIPE_MATCH_TYPE] = { .name = "dpipe-match-type", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_DPIPE_ACTION] = { .name = "dpipe-action", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_action_nest, }, - [DEVLINK_ATTR_DPIPE_ACTION_VALUE] = { .name = "dpipe-action-value", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_action_value_nest, }, - [DEVLINK_ATTR_DPIPE_ACTION_TYPE] = { .name = "dpipe-action-type", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_DPIPE_VALUE] = { .name = "dpipe-value", .type = YNL_PT_BINARY,}, - [DEVLINK_ATTR_DPIPE_VALUE_MASK] = { .name = "dpipe-value-mask", .type = YNL_PT_BINARY,}, - [DEVLINK_ATTR_DPIPE_VALUE_MAPPING] = { .name = "dpipe-value-mapping", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_DPIPE_HEADERS] = { .name = "dpipe-headers", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_headers_nest, }, - [DEVLINK_ATTR_DPIPE_HEADER] = { .name = "dpipe-header", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_header_nest, }, - [DEVLINK_ATTR_DPIPE_HEADER_NAME] = { .name = "dpipe-header-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_DPIPE_HEADER_ID] = { .name = "dpipe-header-id", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_DPIPE_HEADER_FIELDS] = { .name = "dpipe-header-fields", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_header_fields_nest, }, - [DEVLINK_ATTR_DPIPE_HEADER_GLOBAL] = { .name = "dpipe-header-global", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_DPIPE_HEADER_INDEX] = { .name = "dpipe-header-index", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_DPIPE_FIELD] = { .name = "dpipe-field", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_field_nest, }, - [DEVLINK_ATTR_DPIPE_FIELD_NAME] = { .name = "dpipe-field-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_DPIPE_FIELD_ID] = { .name = "dpipe-field-id", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH] = { .name = "dpipe-field-bitwidth", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE] = { .name = "dpipe-field-mapping-type", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_PAD] = { .name = "pad", .type = YNL_PT_IGNORE, }, - [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = { .name = "eswitch-encap-mode", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_RESOURCE_LIST] = { .name = "resource-list", .type = YNL_PT_NEST, .nest = &devlink_dl_resource_list_nest, }, - [DEVLINK_ATTR_RESOURCE] = { .name = "resource", .type = YNL_PT_NEST, .nest = &devlink_dl_resource_nest, }, - [DEVLINK_ATTR_RESOURCE_NAME] = { .name = "resource-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_RESOURCE_ID] = { .name = "resource-id", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_RESOURCE_SIZE] = { .name = "resource-size", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_RESOURCE_SIZE_NEW] = { .name = "resource-size-new", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_RESOURCE_SIZE_VALID] = { .name = "resource-size-valid", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_RESOURCE_SIZE_MIN] = { .name = "resource-size-min", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_RESOURCE_SIZE_MAX] = { .name = "resource-size-max", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_RESOURCE_SIZE_GRAN] = { .name = "resource-size-gran", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_RESOURCE_UNIT] = { .name = "resource-unit", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_RESOURCE_OCC] = { .name = "resource-occ", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID] = { .name = "dpipe-table-resource-id", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS] = { .name = "dpipe-table-resource-units", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_PORT_FLAVOUR] = { .name = "port-flavour", .type = YNL_PT_U16, }, - [DEVLINK_ATTR_PARAM_NAME] = { .name = "param-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_PARAM_TYPE] = { .name = "param-type", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_PARAM_VALUE_CMODE] = { .name = "param-value-cmode", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_REGION_NAME] = { .name = "region-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_REGION_SNAPSHOT_ID] = { .name = "region-snapshot-id", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_REGION_CHUNK_ADDR] = { .name = "region-chunk-addr", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_REGION_CHUNK_LEN] = { .name = "region-chunk-len", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_INFO_DRIVER_NAME] = { .name = "info-driver-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_INFO_SERIAL_NUMBER] = { .name = "info-serial-number", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_INFO_VERSION_FIXED] = { .name = "info-version-fixed", .type = YNL_PT_NEST, .nest = &devlink_dl_info_version_nest, }, - [DEVLINK_ATTR_INFO_VERSION_RUNNING] = { .name = "info-version-running", .type = YNL_PT_NEST, .nest = &devlink_dl_info_version_nest, }, - [DEVLINK_ATTR_INFO_VERSION_STORED] = { .name = "info-version-stored", .type = YNL_PT_NEST, .nest = &devlink_dl_info_version_nest, }, - [DEVLINK_ATTR_INFO_VERSION_NAME] = { .name = "info-version-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_INFO_VERSION_VALUE] = { .name = "info-version-value", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_FMSG] = { .name = "fmsg", .type = YNL_PT_NEST, .nest = &devlink_dl_fmsg_nest, }, - [DEVLINK_ATTR_FMSG_OBJ_NEST_START] = { .name = "fmsg-obj-nest-start", .type = YNL_PT_FLAG, }, - [DEVLINK_ATTR_FMSG_PAIR_NEST_START] = { .name = "fmsg-pair-nest-start", .type = YNL_PT_FLAG, }, - [DEVLINK_ATTR_FMSG_ARR_NEST_START] = { .name = "fmsg-arr-nest-start", .type = YNL_PT_FLAG, }, - [DEVLINK_ATTR_FMSG_NEST_END] = { .name = "fmsg-nest-end", .type = YNL_PT_FLAG, }, - [DEVLINK_ATTR_FMSG_OBJ_NAME] = { .name = "fmsg-obj-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = { .name = "health-reporter-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] = { .name = "health-reporter-graceful-period", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER] = { .name = "health-reporter-auto-recover", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME] = { .name = "flash-update-file-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_FLASH_UPDATE_COMPONENT] = { .name = "flash-update-component", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_PORT_PCI_PF_NUMBER] = { .name = "port-pci-pf-number", .type = YNL_PT_U16, }, - [DEVLINK_ATTR_TRAP_NAME] = { .name = "trap-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_TRAP_ACTION] = { .name = "trap-action", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_TRAP_GROUP_NAME] = { .name = "trap-group-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_RELOAD_FAILED] = { .name = "reload-failed", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_NETNS_FD] = { .name = "netns-fd", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_NETNS_PID] = { .name = "netns-pid", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_NETNS_ID] = { .name = "netns-id", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP] = { .name = "health-reporter-auto-dump", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_TRAP_POLICER_ID] = { .name = "trap-policer-id", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_TRAP_POLICER_RATE] = { .name = "trap-policer-rate", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_TRAP_POLICER_BURST] = { .name = "trap-policer-burst", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_PORT_FUNCTION] = { .name = "port-function", .type = YNL_PT_NEST, .nest = &devlink_dl_port_function_nest, }, - [DEVLINK_ATTR_PORT_CONTROLLER_NUMBER] = { .name = "port-controller-number", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_FLASH_UPDATE_OVERWRITE_MASK] = { .name = "flash-update-overwrite-mask", .type = YNL_PT_BITFIELD32, }, - [DEVLINK_ATTR_RELOAD_ACTION] = { .name = "reload-action", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_RELOAD_ACTIONS_PERFORMED] = { .name = "reload-actions-performed", .type = YNL_PT_BITFIELD32, }, - [DEVLINK_ATTR_RELOAD_LIMITS] = { .name = "reload-limits", .type = YNL_PT_BITFIELD32, }, - [DEVLINK_ATTR_DEV_STATS] = { .name = "dev-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_dev_stats_nest, }, - [DEVLINK_ATTR_RELOAD_STATS] = { .name = "reload-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_nest, }, - [DEVLINK_ATTR_RELOAD_STATS_ENTRY] = { .name = "reload-stats-entry", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_entry_nest, }, - [DEVLINK_ATTR_RELOAD_STATS_LIMIT] = { .name = "reload-stats-limit", .type = YNL_PT_U8, }, - [DEVLINK_ATTR_RELOAD_STATS_VALUE] = { .name = "reload-stats-value", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_REMOTE_RELOAD_STATS] = { .name = "remote-reload-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_nest, }, - [DEVLINK_ATTR_RELOAD_ACTION_INFO] = { .name = "reload-action-info", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_act_info_nest, }, - [DEVLINK_ATTR_RELOAD_ACTION_STATS] = { .name = "reload-action-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_act_stats_nest, }, - [DEVLINK_ATTR_PORT_PCI_SF_NUMBER] = { .name = "port-pci-sf-number", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_RATE_TX_SHARE] = { .name = "rate-tx-share", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_RATE_TX_MAX] = { .name = "rate-tx-max", .type = YNL_PT_U64, }, - [DEVLINK_ATTR_RATE_NODE_NAME] = { .name = "rate-node-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_RATE_PARENT_NODE_NAME] = { .name = "rate-parent-node-name", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_LINECARD_INDEX] = { .name = "linecard-index", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_LINECARD_TYPE] = { .name = "linecard-type", .type = YNL_PT_NUL_STR, }, - [DEVLINK_ATTR_SELFTESTS] = { .name = "selftests", .type = YNL_PT_NEST, .nest = &devlink_dl_selftest_id_nest, }, - [DEVLINK_ATTR_RATE_TX_PRIORITY] = { .name = "rate-tx-priority", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_RATE_TX_WEIGHT] = { .name = "rate-tx-weight", .type = YNL_PT_U32, }, - [DEVLINK_ATTR_REGION_DIRECT] = { .name = "region-direct", .type = YNL_PT_FLAG, }, -}; - -struct ynl_policy_nest devlink_nest = { - .max_attr = DEVLINK_ATTR_MAX, - .table = devlink_policy, -}; - -/* Common nested types */ -void devlink_dl_dpipe_match_free(struct devlink_dl_dpipe_match *obj) -{ -} - -int devlink_dl_dpipe_match_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dpipe_match *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_DPIPE_MATCH_TYPE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_match_type = 1; - dst->dpipe_match_type = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_DPIPE_HEADER_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_header_id = 1; - dst->dpipe_header_id = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_DPIPE_HEADER_GLOBAL) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_header_global = 1; - dst->dpipe_header_global = mnl_attr_get_u8(attr); - } else if (type == DEVLINK_ATTR_DPIPE_HEADER_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_header_index = 1; - dst->dpipe_header_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_DPIPE_FIELD_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_field_id = 1; - dst->dpipe_field_id = mnl_attr_get_u32(attr); - } - } - - return 0; -} - -void -devlink_dl_dpipe_match_value_free(struct devlink_dl_dpipe_match_value *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_dpipe_match; i++) - devlink_dl_dpipe_match_free(&obj->dpipe_match[i]); - free(obj->dpipe_match); - free(obj->dpipe_value); - free(obj->dpipe_value_mask); -} - -int devlink_dl_dpipe_match_value_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dpipe_match_value *dst = yarg->data; - unsigned int n_dpipe_match = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->dpipe_match) - return ynl_error_parse(yarg, "attribute already present (dl-dpipe-match-value.dpipe-match)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_DPIPE_MATCH) { - n_dpipe_match++; - } else if (type == DEVLINK_ATTR_DPIPE_VALUE) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.dpipe_value_len = len; - dst->dpipe_value = malloc(len); - memcpy(dst->dpipe_value, mnl_attr_get_payload(attr), len); - } else if (type == DEVLINK_ATTR_DPIPE_VALUE_MASK) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.dpipe_value_mask_len = len; - dst->dpipe_value_mask = malloc(len); - memcpy(dst->dpipe_value_mask, mnl_attr_get_payload(attr), len); - } else if (type == DEVLINK_ATTR_DPIPE_VALUE_MAPPING) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_value_mapping = 1; - dst->dpipe_value_mapping = mnl_attr_get_u32(attr); - } - } - - if (n_dpipe_match) { - dst->dpipe_match = calloc(n_dpipe_match, sizeof(*dst->dpipe_match)); - dst->n_dpipe_match = n_dpipe_match; - i = 0; - parg.rsp_policy = &devlink_dl_dpipe_match_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DPIPE_MATCH) { - parg.data = &dst->dpipe_match[i]; - if (devlink_dl_dpipe_match_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void devlink_dl_dpipe_action_free(struct devlink_dl_dpipe_action *obj) -{ -} - -int devlink_dl_dpipe_action_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dpipe_action *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_DPIPE_ACTION_TYPE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_action_type = 1; - dst->dpipe_action_type = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_DPIPE_HEADER_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_header_id = 1; - dst->dpipe_header_id = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_DPIPE_HEADER_GLOBAL) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_header_global = 1; - dst->dpipe_header_global = mnl_attr_get_u8(attr); - } else if (type == DEVLINK_ATTR_DPIPE_HEADER_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_header_index = 1; - dst->dpipe_header_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_DPIPE_FIELD_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_field_id = 1; - dst->dpipe_field_id = mnl_attr_get_u32(attr); - } - } - - return 0; -} - -void -devlink_dl_dpipe_action_value_free(struct devlink_dl_dpipe_action_value *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_dpipe_action; i++) - devlink_dl_dpipe_action_free(&obj->dpipe_action[i]); - free(obj->dpipe_action); - free(obj->dpipe_value); - free(obj->dpipe_value_mask); -} - -int devlink_dl_dpipe_action_value_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dpipe_action_value *dst = yarg->data; - unsigned int n_dpipe_action = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->dpipe_action) - return ynl_error_parse(yarg, "attribute already present (dl-dpipe-action-value.dpipe-action)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_DPIPE_ACTION) { - n_dpipe_action++; - } else if (type == DEVLINK_ATTR_DPIPE_VALUE) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.dpipe_value_len = len; - dst->dpipe_value = malloc(len); - memcpy(dst->dpipe_value, mnl_attr_get_payload(attr), len); - } else if (type == DEVLINK_ATTR_DPIPE_VALUE_MASK) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.dpipe_value_mask_len = len; - dst->dpipe_value_mask = malloc(len); - memcpy(dst->dpipe_value_mask, mnl_attr_get_payload(attr), len); - } else if (type == DEVLINK_ATTR_DPIPE_VALUE_MAPPING) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_value_mapping = 1; - dst->dpipe_value_mapping = mnl_attr_get_u32(attr); - } - } - - if (n_dpipe_action) { - dst->dpipe_action = calloc(n_dpipe_action, sizeof(*dst->dpipe_action)); - dst->n_dpipe_action = n_dpipe_action; - i = 0; - parg.rsp_policy = &devlink_dl_dpipe_action_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DPIPE_ACTION) { - parg.data = &dst->dpipe_action[i]; - if (devlink_dl_dpipe_action_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void devlink_dl_dpipe_field_free(struct devlink_dl_dpipe_field *obj) -{ - free(obj->dpipe_field_name); -} - -int devlink_dl_dpipe_field_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dpipe_field *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_DPIPE_FIELD_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dpipe_field_name_len = len; - dst->dpipe_field_name = malloc(len + 1); - memcpy(dst->dpipe_field_name, mnl_attr_get_str(attr), len); - dst->dpipe_field_name[len] = 0; - } else if (type == DEVLINK_ATTR_DPIPE_FIELD_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_field_id = 1; - dst->dpipe_field_id = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_field_bitwidth = 1; - dst->dpipe_field_bitwidth = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_field_mapping_type = 1; - dst->dpipe_field_mapping_type = mnl_attr_get_u32(attr); - } - } - - return 0; -} - -void devlink_dl_resource_free(struct devlink_dl_resource *obj) -{ - free(obj->resource_name); -} - -int devlink_dl_resource_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_resource *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_RESOURCE_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.resource_name_len = len; - dst->resource_name = malloc(len + 1); - memcpy(dst->resource_name, mnl_attr_get_str(attr), len); - dst->resource_name[len] = 0; - } else if (type == DEVLINK_ATTR_RESOURCE_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.resource_id = 1; - dst->resource_id = mnl_attr_get_u64(attr); - } else if (type == DEVLINK_ATTR_RESOURCE_SIZE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.resource_size = 1; - dst->resource_size = mnl_attr_get_u64(attr); - } else if (type == DEVLINK_ATTR_RESOURCE_SIZE_NEW) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.resource_size_new = 1; - dst->resource_size_new = mnl_attr_get_u64(attr); - } else if (type == DEVLINK_ATTR_RESOURCE_SIZE_VALID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.resource_size_valid = 1; - dst->resource_size_valid = mnl_attr_get_u8(attr); - } else if (type == DEVLINK_ATTR_RESOURCE_SIZE_MIN) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.resource_size_min = 1; - dst->resource_size_min = mnl_attr_get_u64(attr); - } else if (type == DEVLINK_ATTR_RESOURCE_SIZE_MAX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.resource_size_max = 1; - dst->resource_size_max = mnl_attr_get_u64(attr); - } else if (type == DEVLINK_ATTR_RESOURCE_SIZE_GRAN) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.resource_size_gran = 1; - dst->resource_size_gran = mnl_attr_get_u64(attr); - } else if (type == DEVLINK_ATTR_RESOURCE_UNIT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.resource_unit = 1; - dst->resource_unit = mnl_attr_get_u8(attr); - } else if (type == DEVLINK_ATTR_RESOURCE_OCC) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.resource_occ = 1; - dst->resource_occ = mnl_attr_get_u64(attr); - } - } - - return 0; -} - -void devlink_dl_info_version_free(struct devlink_dl_info_version *obj) -{ - free(obj->info_version_name); - free(obj->info_version_value); -} - -int devlink_dl_info_version_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_info_version *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_INFO_VERSION_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.info_version_name_len = len; - dst->info_version_name = malloc(len + 1); - memcpy(dst->info_version_name, mnl_attr_get_str(attr), len); - dst->info_version_name[len] = 0; - } else if (type == DEVLINK_ATTR_INFO_VERSION_VALUE) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.info_version_value_len = len; - dst->info_version_value = malloc(len + 1); - memcpy(dst->info_version_value, mnl_attr_get_str(attr), len); - dst->info_version_value[len] = 0; - } - } - - return 0; -} - -void devlink_dl_fmsg_free(struct devlink_dl_fmsg *obj) -{ - free(obj->fmsg_obj_name); -} - -int devlink_dl_fmsg_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_fmsg *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_FMSG_OBJ_NEST_START) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.fmsg_obj_nest_start = 1; - } else if (type == DEVLINK_ATTR_FMSG_PAIR_NEST_START) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.fmsg_pair_nest_start = 1; - } else if (type == DEVLINK_ATTR_FMSG_ARR_NEST_START) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.fmsg_arr_nest_start = 1; - } else if (type == DEVLINK_ATTR_FMSG_NEST_END) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.fmsg_nest_end = 1; - } else if (type == DEVLINK_ATTR_FMSG_OBJ_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.fmsg_obj_name_len = len; - dst->fmsg_obj_name = malloc(len + 1); - memcpy(dst->fmsg_obj_name, mnl_attr_get_str(attr), len); - dst->fmsg_obj_name[len] = 0; - } - } - - return 0; -} - -void devlink_dl_port_function_free(struct devlink_dl_port_function *obj) -{ - free(obj->hw_addr); -} - -int devlink_dl_port_function_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct devlink_dl_port_function *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - if (obj->_present.hw_addr_len) - mnl_attr_put(nlh, DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR, obj->_present.hw_addr_len, obj->hw_addr); - if (obj->_present.state) - mnl_attr_put_u8(nlh, DEVLINK_PORT_FN_ATTR_STATE, obj->state); - if (obj->_present.opstate) - mnl_attr_put_u8(nlh, DEVLINK_PORT_FN_ATTR_OPSTATE, obj->opstate); - if (obj->_present.caps) - mnl_attr_put(nlh, DEVLINK_PORT_FN_ATTR_CAPS, sizeof(struct nla_bitfield32), &obj->caps); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -void -devlink_dl_reload_stats_entry_free(struct devlink_dl_reload_stats_entry *obj) -{ -} - -int devlink_dl_reload_stats_entry_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_reload_stats_entry *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_RELOAD_STATS_LIMIT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.reload_stats_limit = 1; - dst->reload_stats_limit = mnl_attr_get_u8(attr); - } else if (type == DEVLINK_ATTR_RELOAD_STATS_VALUE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.reload_stats_value = 1; - dst->reload_stats_value = mnl_attr_get_u32(attr); - } - } - - return 0; -} - -void devlink_dl_reload_act_stats_free(struct devlink_dl_reload_act_stats *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_reload_stats_entry; i++) - devlink_dl_reload_stats_entry_free(&obj->reload_stats_entry[i]); - free(obj->reload_stats_entry); -} - -int devlink_dl_reload_act_stats_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_reload_act_stats *dst = yarg->data; - unsigned int n_reload_stats_entry = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->reload_stats_entry) - return ynl_error_parse(yarg, "attribute already present (dl-reload-act-stats.reload-stats-entry)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_RELOAD_STATS_ENTRY) { - n_reload_stats_entry++; - } - } - - if (n_reload_stats_entry) { - dst->reload_stats_entry = calloc(n_reload_stats_entry, sizeof(*dst->reload_stats_entry)); - dst->n_reload_stats_entry = n_reload_stats_entry; - i = 0; - parg.rsp_policy = &devlink_dl_reload_stats_entry_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_STATS_ENTRY) { - parg.data = &dst->reload_stats_entry[i]; - if (devlink_dl_reload_stats_entry_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void devlink_dl_selftest_id_free(struct devlink_dl_selftest_id *obj) -{ -} - -int devlink_dl_selftest_id_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct devlink_dl_selftest_id *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - if (obj->_present.flash) - mnl_attr_put(nlh, DEVLINK_ATTR_SELFTEST_ID_FLASH, 0, NULL); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -void -devlink_dl_dpipe_table_matches_free(struct devlink_dl_dpipe_table_matches *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_dpipe_match; i++) - devlink_dl_dpipe_match_free(&obj->dpipe_match[i]); - free(obj->dpipe_match); -} - -int devlink_dl_dpipe_table_matches_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dpipe_table_matches *dst = yarg->data; - unsigned int n_dpipe_match = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->dpipe_match) - return ynl_error_parse(yarg, "attribute already present (dl-dpipe-table-matches.dpipe-match)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_DPIPE_MATCH) { - n_dpipe_match++; - } - } - - if (n_dpipe_match) { - dst->dpipe_match = calloc(n_dpipe_match, sizeof(*dst->dpipe_match)); - dst->n_dpipe_match = n_dpipe_match; - i = 0; - parg.rsp_policy = &devlink_dl_dpipe_match_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DPIPE_MATCH) { - parg.data = &dst->dpipe_match[i]; - if (devlink_dl_dpipe_match_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void -devlink_dl_dpipe_table_actions_free(struct devlink_dl_dpipe_table_actions *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_dpipe_action; i++) - devlink_dl_dpipe_action_free(&obj->dpipe_action[i]); - free(obj->dpipe_action); -} - -int devlink_dl_dpipe_table_actions_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dpipe_table_actions *dst = yarg->data; - unsigned int n_dpipe_action = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->dpipe_action) - return ynl_error_parse(yarg, "attribute already present (dl-dpipe-table-actions.dpipe-action)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_DPIPE_ACTION) { - n_dpipe_action++; - } - } - - if (n_dpipe_action) { - dst->dpipe_action = calloc(n_dpipe_action, sizeof(*dst->dpipe_action)); - dst->n_dpipe_action = n_dpipe_action; - i = 0; - parg.rsp_policy = &devlink_dl_dpipe_action_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DPIPE_ACTION) { - parg.data = &dst->dpipe_action[i]; - if (devlink_dl_dpipe_action_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void -devlink_dl_dpipe_entry_match_values_free(struct devlink_dl_dpipe_entry_match_values *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_dpipe_match_value; i++) - devlink_dl_dpipe_match_value_free(&obj->dpipe_match_value[i]); - free(obj->dpipe_match_value); -} - -int devlink_dl_dpipe_entry_match_values_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dpipe_entry_match_values *dst = yarg->data; - unsigned int n_dpipe_match_value = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->dpipe_match_value) - return ynl_error_parse(yarg, "attribute already present (dl-dpipe-entry-match-values.dpipe-match-value)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_DPIPE_MATCH_VALUE) { - n_dpipe_match_value++; - } - } - - if (n_dpipe_match_value) { - dst->dpipe_match_value = calloc(n_dpipe_match_value, sizeof(*dst->dpipe_match_value)); - dst->n_dpipe_match_value = n_dpipe_match_value; - i = 0; - parg.rsp_policy = &devlink_dl_dpipe_match_value_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DPIPE_MATCH_VALUE) { - parg.data = &dst->dpipe_match_value[i]; - if (devlink_dl_dpipe_match_value_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void -devlink_dl_dpipe_entry_action_values_free(struct devlink_dl_dpipe_entry_action_values *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_dpipe_action_value; i++) - devlink_dl_dpipe_action_value_free(&obj->dpipe_action_value[i]); - free(obj->dpipe_action_value); -} - -int devlink_dl_dpipe_entry_action_values_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dpipe_entry_action_values *dst = yarg->data; - unsigned int n_dpipe_action_value = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->dpipe_action_value) - return ynl_error_parse(yarg, "attribute already present (dl-dpipe-entry-action-values.dpipe-action-value)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_DPIPE_ACTION_VALUE) { - n_dpipe_action_value++; - } - } - - if (n_dpipe_action_value) { - dst->dpipe_action_value = calloc(n_dpipe_action_value, sizeof(*dst->dpipe_action_value)); - dst->n_dpipe_action_value = n_dpipe_action_value; - i = 0; - parg.rsp_policy = &devlink_dl_dpipe_action_value_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DPIPE_ACTION_VALUE) { - parg.data = &dst->dpipe_action_value[i]; - if (devlink_dl_dpipe_action_value_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void -devlink_dl_dpipe_header_fields_free(struct devlink_dl_dpipe_header_fields *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_dpipe_field; i++) - devlink_dl_dpipe_field_free(&obj->dpipe_field[i]); - free(obj->dpipe_field); -} - -int devlink_dl_dpipe_header_fields_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dpipe_header_fields *dst = yarg->data; - unsigned int n_dpipe_field = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->dpipe_field) - return ynl_error_parse(yarg, "attribute already present (dl-dpipe-header-fields.dpipe-field)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_DPIPE_FIELD) { - n_dpipe_field++; - } - } - - if (n_dpipe_field) { - dst->dpipe_field = calloc(n_dpipe_field, sizeof(*dst->dpipe_field)); - dst->n_dpipe_field = n_dpipe_field; - i = 0; - parg.rsp_policy = &devlink_dl_dpipe_field_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DPIPE_FIELD) { - parg.data = &dst->dpipe_field[i]; - if (devlink_dl_dpipe_field_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void devlink_dl_resource_list_free(struct devlink_dl_resource_list *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_resource; i++) - devlink_dl_resource_free(&obj->resource[i]); - free(obj->resource); -} - -int devlink_dl_resource_list_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_resource_list *dst = yarg->data; - unsigned int n_resource = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->resource) - return ynl_error_parse(yarg, "attribute already present (dl-resource-list.resource)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_RESOURCE) { - n_resource++; - } - } - - if (n_resource) { - dst->resource = calloc(n_resource, sizeof(*dst->resource)); - dst->n_resource = n_resource; - i = 0; - parg.rsp_policy = &devlink_dl_resource_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RESOURCE) { - parg.data = &dst->resource[i]; - if (devlink_dl_resource_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void devlink_dl_reload_act_info_free(struct devlink_dl_reload_act_info *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_reload_action_stats; i++) - devlink_dl_reload_act_stats_free(&obj->reload_action_stats[i]); - free(obj->reload_action_stats); -} - -int devlink_dl_reload_act_info_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_reload_act_info *dst = yarg->data; - unsigned int n_reload_action_stats = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->reload_action_stats) - return ynl_error_parse(yarg, "attribute already present (dl-reload-act-info.reload-action-stats)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_RELOAD_ACTION) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.reload_action = 1; - dst->reload_action = mnl_attr_get_u8(attr); - } else if (type == DEVLINK_ATTR_RELOAD_ACTION_STATS) { - n_reload_action_stats++; - } - } - - if (n_reload_action_stats) { - dst->reload_action_stats = calloc(n_reload_action_stats, sizeof(*dst->reload_action_stats)); - dst->n_reload_action_stats = n_reload_action_stats; - i = 0; - parg.rsp_policy = &devlink_dl_reload_act_stats_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_ACTION_STATS) { - parg.data = &dst->reload_action_stats[i]; - if (devlink_dl_reload_act_stats_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void devlink_dl_dpipe_table_free(struct devlink_dl_dpipe_table *obj) -{ - free(obj->dpipe_table_name); - devlink_dl_dpipe_table_matches_free(&obj->dpipe_table_matches); - devlink_dl_dpipe_table_actions_free(&obj->dpipe_table_actions); -} - -int devlink_dl_dpipe_table_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dpipe_table *dst = yarg->data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - parg.ys = yarg->ys; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_DPIPE_TABLE_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dpipe_table_name_len = len; - dst->dpipe_table_name = malloc(len + 1); - memcpy(dst->dpipe_table_name, mnl_attr_get_str(attr), len); - dst->dpipe_table_name[len] = 0; - } else if (type == DEVLINK_ATTR_DPIPE_TABLE_SIZE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_table_size = 1; - dst->dpipe_table_size = mnl_attr_get_u64(attr); - } else if (type == DEVLINK_ATTR_DPIPE_TABLE_MATCHES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_table_matches = 1; - - parg.rsp_policy = &devlink_dl_dpipe_table_matches_nest; - parg.data = &dst->dpipe_table_matches; - if (devlink_dl_dpipe_table_matches_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == DEVLINK_ATTR_DPIPE_TABLE_ACTIONS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_table_actions = 1; - - parg.rsp_policy = &devlink_dl_dpipe_table_actions_nest; - parg.data = &dst->dpipe_table_actions; - if (devlink_dl_dpipe_table_actions_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_table_counters_enabled = 1; - dst->dpipe_table_counters_enabled = mnl_attr_get_u8(attr); - } else if (type == DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_table_resource_id = 1; - dst->dpipe_table_resource_id = mnl_attr_get_u64(attr); - } else if (type == DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_table_resource_units = 1; - dst->dpipe_table_resource_units = mnl_attr_get_u64(attr); - } - } - - return 0; -} - -void devlink_dl_dpipe_entry_free(struct devlink_dl_dpipe_entry *obj) -{ - devlink_dl_dpipe_entry_match_values_free(&obj->dpipe_entry_match_values); - devlink_dl_dpipe_entry_action_values_free(&obj->dpipe_entry_action_values); -} - -int devlink_dl_dpipe_entry_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dpipe_entry *dst = yarg->data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - parg.ys = yarg->ys; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_DPIPE_ENTRY_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_entry_index = 1; - dst->dpipe_entry_index = mnl_attr_get_u64(attr); - } else if (type == DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_entry_match_values = 1; - - parg.rsp_policy = &devlink_dl_dpipe_entry_match_values_nest; - parg.data = &dst->dpipe_entry_match_values; - if (devlink_dl_dpipe_entry_match_values_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_entry_action_values = 1; - - parg.rsp_policy = &devlink_dl_dpipe_entry_action_values_nest; - parg.data = &dst->dpipe_entry_action_values; - if (devlink_dl_dpipe_entry_action_values_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == DEVLINK_ATTR_DPIPE_ENTRY_COUNTER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_entry_counter = 1; - dst->dpipe_entry_counter = mnl_attr_get_u64(attr); - } - } - - return 0; -} - -void devlink_dl_dpipe_header_free(struct devlink_dl_dpipe_header *obj) -{ - free(obj->dpipe_header_name); - devlink_dl_dpipe_header_fields_free(&obj->dpipe_header_fields); -} - -int devlink_dl_dpipe_header_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dpipe_header *dst = yarg->data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - parg.ys = yarg->ys; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_DPIPE_HEADER_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dpipe_header_name_len = len; - dst->dpipe_header_name = malloc(len + 1); - memcpy(dst->dpipe_header_name, mnl_attr_get_str(attr), len); - dst->dpipe_header_name[len] = 0; - } else if (type == DEVLINK_ATTR_DPIPE_HEADER_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_header_id = 1; - dst->dpipe_header_id = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_DPIPE_HEADER_GLOBAL) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_header_global = 1; - dst->dpipe_header_global = mnl_attr_get_u8(attr); - } else if (type == DEVLINK_ATTR_DPIPE_HEADER_FIELDS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_header_fields = 1; - - parg.rsp_policy = &devlink_dl_dpipe_header_fields_nest; - parg.data = &dst->dpipe_header_fields; - if (devlink_dl_dpipe_header_fields_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return 0; -} - -void devlink_dl_reload_stats_free(struct devlink_dl_reload_stats *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_reload_action_info; i++) - devlink_dl_reload_act_info_free(&obj->reload_action_info[i]); - free(obj->reload_action_info); -} - -int devlink_dl_reload_stats_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_reload_stats *dst = yarg->data; - unsigned int n_reload_action_info = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->reload_action_info) - return ynl_error_parse(yarg, "attribute already present (dl-reload-stats.reload-action-info)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_RELOAD_ACTION_INFO) { - n_reload_action_info++; - } - } - - if (n_reload_action_info) { - dst->reload_action_info = calloc(n_reload_action_info, sizeof(*dst->reload_action_info)); - dst->n_reload_action_info = n_reload_action_info; - i = 0; - parg.rsp_policy = &devlink_dl_reload_act_info_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_ACTION_INFO) { - parg.data = &dst->reload_action_info[i]; - if (devlink_dl_reload_act_info_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void devlink_dl_dpipe_tables_free(struct devlink_dl_dpipe_tables *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_dpipe_table; i++) - devlink_dl_dpipe_table_free(&obj->dpipe_table[i]); - free(obj->dpipe_table); -} - -int devlink_dl_dpipe_tables_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dpipe_tables *dst = yarg->data; - unsigned int n_dpipe_table = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->dpipe_table) - return ynl_error_parse(yarg, "attribute already present (dl-dpipe-tables.dpipe-table)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_DPIPE_TABLE) { - n_dpipe_table++; - } - } - - if (n_dpipe_table) { - dst->dpipe_table = calloc(n_dpipe_table, sizeof(*dst->dpipe_table)); - dst->n_dpipe_table = n_dpipe_table; - i = 0; - parg.rsp_policy = &devlink_dl_dpipe_table_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DPIPE_TABLE) { - parg.data = &dst->dpipe_table[i]; - if (devlink_dl_dpipe_table_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void devlink_dl_dpipe_entries_free(struct devlink_dl_dpipe_entries *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_dpipe_entry; i++) - devlink_dl_dpipe_entry_free(&obj->dpipe_entry[i]); - free(obj->dpipe_entry); -} - -int devlink_dl_dpipe_entries_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dpipe_entries *dst = yarg->data; - unsigned int n_dpipe_entry = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->dpipe_entry) - return ynl_error_parse(yarg, "attribute already present (dl-dpipe-entries.dpipe-entry)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_DPIPE_ENTRY) { - n_dpipe_entry++; - } - } - - if (n_dpipe_entry) { - dst->dpipe_entry = calloc(n_dpipe_entry, sizeof(*dst->dpipe_entry)); - dst->n_dpipe_entry = n_dpipe_entry; - i = 0; - parg.rsp_policy = &devlink_dl_dpipe_entry_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DPIPE_ENTRY) { - parg.data = &dst->dpipe_entry[i]; - if (devlink_dl_dpipe_entry_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void devlink_dl_dpipe_headers_free(struct devlink_dl_dpipe_headers *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_dpipe_header; i++) - devlink_dl_dpipe_header_free(&obj->dpipe_header[i]); - free(obj->dpipe_header); -} - -int devlink_dl_dpipe_headers_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dpipe_headers *dst = yarg->data; - unsigned int n_dpipe_header = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->dpipe_header) - return ynl_error_parse(yarg, "attribute already present (dl-dpipe-headers.dpipe-header)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_DPIPE_HEADER) { - n_dpipe_header++; - } - } - - if (n_dpipe_header) { - dst->dpipe_header = calloc(n_dpipe_header, sizeof(*dst->dpipe_header)); - dst->n_dpipe_header = n_dpipe_header; - i = 0; - parg.rsp_policy = &devlink_dl_dpipe_header_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DPIPE_HEADER) { - parg.data = &dst->dpipe_header[i]; - if (devlink_dl_dpipe_header_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void devlink_dl_dev_stats_free(struct devlink_dl_dev_stats *obj) -{ - devlink_dl_reload_stats_free(&obj->reload_stats); - devlink_dl_reload_stats_free(&obj->remote_reload_stats); -} - -int devlink_dl_dev_stats_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dev_stats *dst = yarg->data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - parg.ys = yarg->ys; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_RELOAD_STATS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.reload_stats = 1; - - parg.rsp_policy = &devlink_dl_reload_stats_nest; - parg.data = &dst->reload_stats; - if (devlink_dl_reload_stats_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == DEVLINK_ATTR_REMOTE_RELOAD_STATS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.remote_reload_stats = 1; - - parg.rsp_policy = &devlink_dl_reload_stats_nest; - parg.data = &dst->remote_reload_stats; - if (devlink_dl_reload_stats_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return 0; -} - -/* ============== DEVLINK_CMD_GET ============== */ -/* DEVLINK_CMD_GET - do */ -void devlink_get_req_free(struct devlink_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void devlink_get_rsp_free(struct devlink_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - devlink_dl_dev_stats_free(&rsp->dev_stats); - free(rsp); -} - -int devlink_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct devlink_get_rsp *dst; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_RELOAD_FAILED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.reload_failed = 1; - dst->reload_failed = mnl_attr_get_u8(attr); - } else if (type == DEVLINK_ATTR_DEV_STATS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dev_stats = 1; - - parg.rsp_policy = &devlink_dl_dev_stats_nest; - parg.data = &dst->dev_stats; - if (devlink_dl_dev_stats_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct devlink_get_rsp * -devlink_get(struct ynl_sock *ys, struct devlink_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_get_rsp_parse; - yrs.rsp_cmd = 3; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_GET - dump */ -void devlink_get_list_free(struct devlink_get_list *rsp) -{ - struct devlink_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - devlink_dl_dev_stats_free(&rsp->obj.dev_stats); - free(rsp); - } -} - -struct devlink_get_list *devlink_get_dump(struct ynl_sock *ys) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_get_list); - yds.cb = devlink_get_rsp_parse; - yds.rsp_cmd = 3; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_GET, 1); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_PORT_GET ============== */ -/* DEVLINK_CMD_PORT_GET - do */ -void devlink_port_get_req_free(struct devlink_port_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void devlink_port_get_rsp_free(struct devlink_port_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp); -} - -int devlink_port_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct devlink_port_get_rsp *dst; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PORT_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port_index = 1; - dst->port_index = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct devlink_port_get_rsp * -devlink_port_get(struct ynl_sock *ys, struct devlink_port_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_port_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PORT_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_port_get_rsp_parse; - yrs.rsp_cmd = 7; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_port_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_PORT_GET - dump */ -int devlink_port_get_rsp_dump_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_port_get_rsp_dump *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PORT_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port_index = 1; - dst->port_index = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -void devlink_port_get_rsp_list_free(struct devlink_port_get_rsp_list *rsp) -{ - struct devlink_port_get_rsp_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp); - } -} - -struct devlink_port_get_rsp_list * -devlink_port_get_dump(struct ynl_sock *ys, - struct devlink_port_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_port_get_rsp_list); - yds.cb = devlink_port_get_rsp_dump_parse; - yds.rsp_cmd = 7; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_PORT_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_port_get_rsp_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_PORT_SET ============== */ -/* DEVLINK_CMD_PORT_SET - do */ -void devlink_port_set_req_free(struct devlink_port_set_req *req) -{ - free(req->bus_name); - free(req->dev_name); - devlink_dl_port_function_free(&req->port_function); - free(req); -} - -int devlink_port_set(struct ynl_sock *ys, struct devlink_port_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PORT_SET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.port_type) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_PORT_TYPE, req->port_type); - if (req->_present.port_function) - devlink_dl_port_function_put(nlh, DEVLINK_ATTR_PORT_FUNCTION, &req->port_function); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_PORT_NEW ============== */ -/* DEVLINK_CMD_PORT_NEW - do */ -void devlink_port_new_req_free(struct devlink_port_new_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void devlink_port_new_rsp_free(struct devlink_port_new_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp); -} - -int devlink_port_new_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct devlink_port_new_rsp *dst; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PORT_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port_index = 1; - dst->port_index = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct devlink_port_new_rsp * -devlink_port_new(struct ynl_sock *ys, struct devlink_port_new_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_port_new_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PORT_NEW, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.port_flavour) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_PORT_FLAVOUR, req->port_flavour); - if (req->_present.port_pci_pf_number) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_PORT_PCI_PF_NUMBER, req->port_pci_pf_number); - if (req->_present.port_pci_sf_number) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_PCI_SF_NUMBER, req->port_pci_sf_number); - if (req->_present.port_controller_number) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_CONTROLLER_NUMBER, req->port_controller_number); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_port_new_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_PORT_NEW; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_port_new_rsp_free(rsp); - return NULL; -} - -/* ============== DEVLINK_CMD_PORT_DEL ============== */ -/* DEVLINK_CMD_PORT_DEL - do */ -void devlink_port_del_req_free(struct devlink_port_del_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -int devlink_port_del(struct ynl_sock *ys, struct devlink_port_del_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PORT_DEL, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_PORT_SPLIT ============== */ -/* DEVLINK_CMD_PORT_SPLIT - do */ -void devlink_port_split_req_free(struct devlink_port_split_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -int devlink_port_split(struct ynl_sock *ys, struct devlink_port_split_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PORT_SPLIT, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.port_split_count) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_SPLIT_COUNT, req->port_split_count); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_PORT_UNSPLIT ============== */ -/* DEVLINK_CMD_PORT_UNSPLIT - do */ -void devlink_port_unsplit_req_free(struct devlink_port_unsplit_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -int devlink_port_unsplit(struct ynl_sock *ys, - struct devlink_port_unsplit_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PORT_UNSPLIT, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_SB_GET ============== */ -/* DEVLINK_CMD_SB_GET - do */ -void devlink_sb_get_req_free(struct devlink_sb_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void devlink_sb_get_rsp_free(struct devlink_sb_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp); -} - -int devlink_sb_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct devlink_sb_get_rsp *dst; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_SB_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sb_index = 1; - dst->sb_index = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct devlink_sb_get_rsp * -devlink_sb_get(struct ynl_sock *ys, struct devlink_sb_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_sb_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.sb_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_sb_get_rsp_parse; - yrs.rsp_cmd = 13; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_sb_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_SB_GET - dump */ -void devlink_sb_get_list_free(struct devlink_sb_get_list *rsp) -{ - struct devlink_sb_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp); - } -} - -struct devlink_sb_get_list * -devlink_sb_get_dump(struct ynl_sock *ys, struct devlink_sb_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_sb_get_list); - yds.cb = devlink_sb_get_rsp_parse; - yds.rsp_cmd = 13; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_SB_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_sb_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_SB_POOL_GET ============== */ -/* DEVLINK_CMD_SB_POOL_GET - do */ -void devlink_sb_pool_get_req_free(struct devlink_sb_pool_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void devlink_sb_pool_get_rsp_free(struct devlink_sb_pool_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp); -} - -int devlink_sb_pool_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_sb_pool_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_SB_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sb_index = 1; - dst->sb_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_SB_POOL_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sb_pool_index = 1; - dst->sb_pool_index = mnl_attr_get_u16(attr); - } - } - - return MNL_CB_OK; -} - -struct devlink_sb_pool_get_rsp * -devlink_sb_pool_get(struct ynl_sock *ys, struct devlink_sb_pool_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_sb_pool_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_POOL_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.sb_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); - if (req->_present.sb_pool_index) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX, req->sb_pool_index); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_sb_pool_get_rsp_parse; - yrs.rsp_cmd = 17; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_sb_pool_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_SB_POOL_GET - dump */ -void devlink_sb_pool_get_list_free(struct devlink_sb_pool_get_list *rsp) -{ - struct devlink_sb_pool_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp); - } -} - -struct devlink_sb_pool_get_list * -devlink_sb_pool_get_dump(struct ynl_sock *ys, - struct devlink_sb_pool_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_sb_pool_get_list); - yds.cb = devlink_sb_pool_get_rsp_parse; - yds.rsp_cmd = 17; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_SB_POOL_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_sb_pool_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_SB_POOL_SET ============== */ -/* DEVLINK_CMD_SB_POOL_SET - do */ -void devlink_sb_pool_set_req_free(struct devlink_sb_pool_set_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -int devlink_sb_pool_set(struct ynl_sock *ys, - struct devlink_sb_pool_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_POOL_SET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.sb_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); - if (req->_present.sb_pool_index) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX, req->sb_pool_index); - if (req->_present.sb_pool_threshold_type) - mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE, req->sb_pool_threshold_type); - if (req->_present.sb_pool_size) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_POOL_SIZE, req->sb_pool_size); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_SB_PORT_POOL_GET ============== */ -/* DEVLINK_CMD_SB_PORT_POOL_GET - do */ -void -devlink_sb_port_pool_get_req_free(struct devlink_sb_port_pool_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void -devlink_sb_port_pool_get_rsp_free(struct devlink_sb_port_pool_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp); -} - -int devlink_sb_port_pool_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_sb_port_pool_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PORT_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port_index = 1; - dst->port_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_SB_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sb_index = 1; - dst->sb_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_SB_POOL_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sb_pool_index = 1; - dst->sb_pool_index = mnl_attr_get_u16(attr); - } - } - - return MNL_CB_OK; -} - -struct devlink_sb_port_pool_get_rsp * -devlink_sb_port_pool_get(struct ynl_sock *ys, - struct devlink_sb_port_pool_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_sb_port_pool_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_PORT_POOL_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.sb_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); - if (req->_present.sb_pool_index) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX, req->sb_pool_index); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_sb_port_pool_get_rsp_parse; - yrs.rsp_cmd = 21; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_sb_port_pool_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_SB_PORT_POOL_GET - dump */ -void -devlink_sb_port_pool_get_list_free(struct devlink_sb_port_pool_get_list *rsp) -{ - struct devlink_sb_port_pool_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp); - } -} - -struct devlink_sb_port_pool_get_list * -devlink_sb_port_pool_get_dump(struct ynl_sock *ys, - struct devlink_sb_port_pool_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_sb_port_pool_get_list); - yds.cb = devlink_sb_port_pool_get_rsp_parse; - yds.rsp_cmd = 21; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_SB_PORT_POOL_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_sb_port_pool_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_SB_PORT_POOL_SET ============== */ -/* DEVLINK_CMD_SB_PORT_POOL_SET - do */ -void -devlink_sb_port_pool_set_req_free(struct devlink_sb_port_pool_set_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -int devlink_sb_port_pool_set(struct ynl_sock *ys, - struct devlink_sb_port_pool_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_PORT_POOL_SET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.sb_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); - if (req->_present.sb_pool_index) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX, req->sb_pool_index); - if (req->_present.sb_threshold) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_THRESHOLD, req->sb_threshold); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_SB_TC_POOL_BIND_GET ============== */ -/* DEVLINK_CMD_SB_TC_POOL_BIND_GET - do */ -void -devlink_sb_tc_pool_bind_get_req_free(struct devlink_sb_tc_pool_bind_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void -devlink_sb_tc_pool_bind_get_rsp_free(struct devlink_sb_tc_pool_bind_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp); -} - -int devlink_sb_tc_pool_bind_get_rsp_parse(const struct nlmsghdr *nlh, - void *data) -{ - struct devlink_sb_tc_pool_bind_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PORT_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port_index = 1; - dst->port_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_SB_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sb_index = 1; - dst->sb_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_SB_POOL_TYPE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sb_pool_type = 1; - dst->sb_pool_type = mnl_attr_get_u8(attr); - } else if (type == DEVLINK_ATTR_SB_TC_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sb_tc_index = 1; - dst->sb_tc_index = mnl_attr_get_u16(attr); - } - } - - return MNL_CB_OK; -} - -struct devlink_sb_tc_pool_bind_get_rsp * -devlink_sb_tc_pool_bind_get(struct ynl_sock *ys, - struct devlink_sb_tc_pool_bind_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_sb_tc_pool_bind_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_TC_POOL_BIND_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.sb_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); - if (req->_present.sb_pool_type) - mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_TYPE, req->sb_pool_type); - if (req->_present.sb_tc_index) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_TC_INDEX, req->sb_tc_index); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_sb_tc_pool_bind_get_rsp_parse; - yrs.rsp_cmd = 25; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_sb_tc_pool_bind_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_SB_TC_POOL_BIND_GET - dump */ -void -devlink_sb_tc_pool_bind_get_list_free(struct devlink_sb_tc_pool_bind_get_list *rsp) -{ - struct devlink_sb_tc_pool_bind_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp); - } -} - -struct devlink_sb_tc_pool_bind_get_list * -devlink_sb_tc_pool_bind_get_dump(struct ynl_sock *ys, - struct devlink_sb_tc_pool_bind_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_sb_tc_pool_bind_get_list); - yds.cb = devlink_sb_tc_pool_bind_get_rsp_parse; - yds.rsp_cmd = 25; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_SB_TC_POOL_BIND_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_sb_tc_pool_bind_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_SB_TC_POOL_BIND_SET ============== */ -/* DEVLINK_CMD_SB_TC_POOL_BIND_SET - do */ -void -devlink_sb_tc_pool_bind_set_req_free(struct devlink_sb_tc_pool_bind_set_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -int devlink_sb_tc_pool_bind_set(struct ynl_sock *ys, - struct devlink_sb_tc_pool_bind_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_TC_POOL_BIND_SET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.sb_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); - if (req->_present.sb_pool_index) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX, req->sb_pool_index); - if (req->_present.sb_pool_type) - mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_TYPE, req->sb_pool_type); - if (req->_present.sb_tc_index) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_TC_INDEX, req->sb_tc_index); - if (req->_present.sb_threshold) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_THRESHOLD, req->sb_threshold); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_SB_OCC_SNAPSHOT ============== */ -/* DEVLINK_CMD_SB_OCC_SNAPSHOT - do */ -void devlink_sb_occ_snapshot_req_free(struct devlink_sb_occ_snapshot_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -int devlink_sb_occ_snapshot(struct ynl_sock *ys, - struct devlink_sb_occ_snapshot_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_OCC_SNAPSHOT, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.sb_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_SB_OCC_MAX_CLEAR ============== */ -/* DEVLINK_CMD_SB_OCC_MAX_CLEAR - do */ -void -devlink_sb_occ_max_clear_req_free(struct devlink_sb_occ_max_clear_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -int devlink_sb_occ_max_clear(struct ynl_sock *ys, - struct devlink_sb_occ_max_clear_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_OCC_MAX_CLEAR, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.sb_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_ESWITCH_GET ============== */ -/* DEVLINK_CMD_ESWITCH_GET - do */ -void devlink_eswitch_get_req_free(struct devlink_eswitch_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void devlink_eswitch_get_rsp_free(struct devlink_eswitch_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp); -} - -int devlink_eswitch_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_eswitch_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_ESWITCH_MODE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.eswitch_mode = 1; - dst->eswitch_mode = mnl_attr_get_u16(attr); - } else if (type == DEVLINK_ATTR_ESWITCH_INLINE_MODE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.eswitch_inline_mode = 1; - dst->eswitch_inline_mode = mnl_attr_get_u16(attr); - } else if (type == DEVLINK_ATTR_ESWITCH_ENCAP_MODE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.eswitch_encap_mode = 1; - dst->eswitch_encap_mode = mnl_attr_get_u8(attr); - } - } - - return MNL_CB_OK; -} - -struct devlink_eswitch_get_rsp * -devlink_eswitch_get(struct ynl_sock *ys, struct devlink_eswitch_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_eswitch_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_ESWITCH_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_eswitch_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_ESWITCH_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_eswitch_get_rsp_free(rsp); - return NULL; -} - -/* ============== DEVLINK_CMD_ESWITCH_SET ============== */ -/* DEVLINK_CMD_ESWITCH_SET - do */ -void devlink_eswitch_set_req_free(struct devlink_eswitch_set_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -int devlink_eswitch_set(struct ynl_sock *ys, - struct devlink_eswitch_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_ESWITCH_SET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.eswitch_mode) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_ESWITCH_MODE, req->eswitch_mode); - if (req->_present.eswitch_inline_mode) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_ESWITCH_INLINE_MODE, req->eswitch_inline_mode); - if (req->_present.eswitch_encap_mode) - mnl_attr_put_u8(nlh, DEVLINK_ATTR_ESWITCH_ENCAP_MODE, req->eswitch_encap_mode); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_DPIPE_TABLE_GET ============== */ -/* DEVLINK_CMD_DPIPE_TABLE_GET - do */ -void devlink_dpipe_table_get_req_free(struct devlink_dpipe_table_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->dpipe_table_name); - free(req); -} - -void devlink_dpipe_table_get_rsp_free(struct devlink_dpipe_table_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - devlink_dl_dpipe_tables_free(&rsp->dpipe_tables); - free(rsp); -} - -int devlink_dpipe_table_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_dpipe_table_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_DPIPE_TABLES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_tables = 1; - - parg.rsp_policy = &devlink_dl_dpipe_tables_nest; - parg.data = &dst->dpipe_tables; - if (devlink_dl_dpipe_tables_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct devlink_dpipe_table_get_rsp * -devlink_dpipe_table_get(struct ynl_sock *ys, - struct devlink_dpipe_table_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_dpipe_table_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_DPIPE_TABLE_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.dpipe_table_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DPIPE_TABLE_NAME, req->dpipe_table_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_dpipe_table_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_DPIPE_TABLE_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_dpipe_table_get_rsp_free(rsp); - return NULL; -} - -/* ============== DEVLINK_CMD_DPIPE_ENTRIES_GET ============== */ -/* DEVLINK_CMD_DPIPE_ENTRIES_GET - do */ -void -devlink_dpipe_entries_get_req_free(struct devlink_dpipe_entries_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->dpipe_table_name); - free(req); -} - -void -devlink_dpipe_entries_get_rsp_free(struct devlink_dpipe_entries_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - devlink_dl_dpipe_entries_free(&rsp->dpipe_entries); - free(rsp); -} - -int devlink_dpipe_entries_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_dpipe_entries_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_DPIPE_ENTRIES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_entries = 1; - - parg.rsp_policy = &devlink_dl_dpipe_entries_nest; - parg.data = &dst->dpipe_entries; - if (devlink_dl_dpipe_entries_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct devlink_dpipe_entries_get_rsp * -devlink_dpipe_entries_get(struct ynl_sock *ys, - struct devlink_dpipe_entries_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_dpipe_entries_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_DPIPE_ENTRIES_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.dpipe_table_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DPIPE_TABLE_NAME, req->dpipe_table_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_dpipe_entries_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_DPIPE_ENTRIES_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_dpipe_entries_get_rsp_free(rsp); - return NULL; -} - -/* ============== DEVLINK_CMD_DPIPE_HEADERS_GET ============== */ -/* DEVLINK_CMD_DPIPE_HEADERS_GET - do */ -void -devlink_dpipe_headers_get_req_free(struct devlink_dpipe_headers_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void -devlink_dpipe_headers_get_rsp_free(struct devlink_dpipe_headers_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - devlink_dl_dpipe_headers_free(&rsp->dpipe_headers); - free(rsp); -} - -int devlink_dpipe_headers_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_dpipe_headers_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_DPIPE_HEADERS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dpipe_headers = 1; - - parg.rsp_policy = &devlink_dl_dpipe_headers_nest; - parg.data = &dst->dpipe_headers; - if (devlink_dl_dpipe_headers_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct devlink_dpipe_headers_get_rsp * -devlink_dpipe_headers_get(struct ynl_sock *ys, - struct devlink_dpipe_headers_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_dpipe_headers_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_DPIPE_HEADERS_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_dpipe_headers_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_DPIPE_HEADERS_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_dpipe_headers_get_rsp_free(rsp); - return NULL; -} - -/* ============== DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET ============== */ -/* DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET - do */ -void -devlink_dpipe_table_counters_set_req_free(struct devlink_dpipe_table_counters_set_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->dpipe_table_name); - free(req); -} - -int devlink_dpipe_table_counters_set(struct ynl_sock *ys, - struct devlink_dpipe_table_counters_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.dpipe_table_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DPIPE_TABLE_NAME, req->dpipe_table_name); - if (req->_present.dpipe_table_counters_enabled) - mnl_attr_put_u8(nlh, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED, req->dpipe_table_counters_enabled); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_RESOURCE_SET ============== */ -/* DEVLINK_CMD_RESOURCE_SET - do */ -void devlink_resource_set_req_free(struct devlink_resource_set_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -int devlink_resource_set(struct ynl_sock *ys, - struct devlink_resource_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_RESOURCE_SET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.resource_id) - mnl_attr_put_u64(nlh, DEVLINK_ATTR_RESOURCE_ID, req->resource_id); - if (req->_present.resource_size) - mnl_attr_put_u64(nlh, DEVLINK_ATTR_RESOURCE_SIZE, req->resource_size); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_RESOURCE_DUMP ============== */ -/* DEVLINK_CMD_RESOURCE_DUMP - do */ -void devlink_resource_dump_req_free(struct devlink_resource_dump_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void devlink_resource_dump_rsp_free(struct devlink_resource_dump_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - devlink_dl_resource_list_free(&rsp->resource_list); - free(rsp); -} - -int devlink_resource_dump_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_resource_dump_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_RESOURCE_LIST) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.resource_list = 1; - - parg.rsp_policy = &devlink_dl_resource_list_nest; - parg.data = &dst->resource_list; - if (devlink_dl_resource_list_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct devlink_resource_dump_rsp * -devlink_resource_dump(struct ynl_sock *ys, - struct devlink_resource_dump_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_resource_dump_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_RESOURCE_DUMP, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_resource_dump_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_RESOURCE_DUMP; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_resource_dump_rsp_free(rsp); - return NULL; -} - -/* ============== DEVLINK_CMD_RELOAD ============== */ -/* DEVLINK_CMD_RELOAD - do */ -void devlink_reload_req_free(struct devlink_reload_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void devlink_reload_rsp_free(struct devlink_reload_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp); -} - -int devlink_reload_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct devlink_reload_rsp *dst; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_RELOAD_ACTIONS_PERFORMED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.reload_actions_performed = 1; - memcpy(&dst->reload_actions_performed, mnl_attr_get_payload(attr), sizeof(struct nla_bitfield32)); - } - } - - return MNL_CB_OK; -} - -struct devlink_reload_rsp * -devlink_reload(struct ynl_sock *ys, struct devlink_reload_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_reload_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_RELOAD, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.reload_action) - mnl_attr_put_u8(nlh, DEVLINK_ATTR_RELOAD_ACTION, req->reload_action); - if (req->_present.reload_limits) - mnl_attr_put(nlh, DEVLINK_ATTR_RELOAD_LIMITS, sizeof(struct nla_bitfield32), &req->reload_limits); - if (req->_present.netns_pid) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_NETNS_PID, req->netns_pid); - if (req->_present.netns_fd) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_NETNS_FD, req->netns_fd); - if (req->_present.netns_id) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_NETNS_ID, req->netns_id); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_reload_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_RELOAD; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_reload_rsp_free(rsp); - return NULL; -} - -/* ============== DEVLINK_CMD_PARAM_GET ============== */ -/* DEVLINK_CMD_PARAM_GET - do */ -void devlink_param_get_req_free(struct devlink_param_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->param_name); - free(req); -} - -void devlink_param_get_rsp_free(struct devlink_param_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp->param_name); - free(rsp); -} - -int devlink_param_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_param_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PARAM_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.param_name_len = len; - dst->param_name = malloc(len + 1); - memcpy(dst->param_name, mnl_attr_get_str(attr), len); - dst->param_name[len] = 0; - } - } - - return MNL_CB_OK; -} - -struct devlink_param_get_rsp * -devlink_param_get(struct ynl_sock *ys, struct devlink_param_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_param_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PARAM_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.param_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_PARAM_NAME, req->param_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_param_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_PARAM_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_param_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_PARAM_GET - dump */ -void devlink_param_get_list_free(struct devlink_param_get_list *rsp) -{ - struct devlink_param_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp->obj.param_name); - free(rsp); - } -} - -struct devlink_param_get_list * -devlink_param_get_dump(struct ynl_sock *ys, - struct devlink_param_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_param_get_list); - yds.cb = devlink_param_get_rsp_parse; - yds.rsp_cmd = DEVLINK_CMD_PARAM_GET; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_PARAM_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_param_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_PARAM_SET ============== */ -/* DEVLINK_CMD_PARAM_SET - do */ -void devlink_param_set_req_free(struct devlink_param_set_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->param_name); - free(req); -} - -int devlink_param_set(struct ynl_sock *ys, struct devlink_param_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PARAM_SET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.param_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_PARAM_NAME, req->param_name); - if (req->_present.param_type) - mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_TYPE, req->param_type); - if (req->_present.param_value_cmode) - mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_VALUE_CMODE, req->param_value_cmode); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_REGION_GET ============== */ -/* DEVLINK_CMD_REGION_GET - do */ -void devlink_region_get_req_free(struct devlink_region_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->region_name); - free(req); -} - -void devlink_region_get_rsp_free(struct devlink_region_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp->region_name); - free(rsp); -} - -int devlink_region_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_region_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PORT_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port_index = 1; - dst->port_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_REGION_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.region_name_len = len; - dst->region_name = malloc(len + 1); - memcpy(dst->region_name, mnl_attr_get_str(attr), len); - dst->region_name[len] = 0; - } - } - - return MNL_CB_OK; -} - -struct devlink_region_get_rsp * -devlink_region_get(struct ynl_sock *ys, struct devlink_region_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_region_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_REGION_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.region_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_REGION_NAME, req->region_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_region_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_REGION_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_region_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_REGION_GET - dump */ -void devlink_region_get_list_free(struct devlink_region_get_list *rsp) -{ - struct devlink_region_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp->obj.region_name); - free(rsp); - } -} - -struct devlink_region_get_list * -devlink_region_get_dump(struct ynl_sock *ys, - struct devlink_region_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_region_get_list); - yds.cb = devlink_region_get_rsp_parse; - yds.rsp_cmd = DEVLINK_CMD_REGION_GET; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_REGION_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_region_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_REGION_NEW ============== */ -/* DEVLINK_CMD_REGION_NEW - do */ -void devlink_region_new_req_free(struct devlink_region_new_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->region_name); - free(req); -} - -void devlink_region_new_rsp_free(struct devlink_region_new_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp->region_name); - free(rsp); -} - -int devlink_region_new_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_region_new_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PORT_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port_index = 1; - dst->port_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_REGION_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.region_name_len = len; - dst->region_name = malloc(len + 1); - memcpy(dst->region_name, mnl_attr_get_str(attr), len); - dst->region_name[len] = 0; - } else if (type == DEVLINK_ATTR_REGION_SNAPSHOT_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.region_snapshot_id = 1; - dst->region_snapshot_id = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct devlink_region_new_rsp * -devlink_region_new(struct ynl_sock *ys, struct devlink_region_new_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_region_new_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_REGION_NEW, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.region_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_REGION_NAME, req->region_name); - if (req->_present.region_snapshot_id) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_REGION_SNAPSHOT_ID, req->region_snapshot_id); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_region_new_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_REGION_NEW; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_region_new_rsp_free(rsp); - return NULL; -} - -/* ============== DEVLINK_CMD_REGION_DEL ============== */ -/* DEVLINK_CMD_REGION_DEL - do */ -void devlink_region_del_req_free(struct devlink_region_del_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->region_name); - free(req); -} - -int devlink_region_del(struct ynl_sock *ys, struct devlink_region_del_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_REGION_DEL, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.region_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_REGION_NAME, req->region_name); - if (req->_present.region_snapshot_id) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_REGION_SNAPSHOT_ID, req->region_snapshot_id); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_REGION_READ ============== */ -/* DEVLINK_CMD_REGION_READ - dump */ -int devlink_region_read_rsp_dump_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_region_read_rsp_dump *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PORT_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port_index = 1; - dst->port_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_REGION_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.region_name_len = len; - dst->region_name = malloc(len + 1); - memcpy(dst->region_name, mnl_attr_get_str(attr), len); - dst->region_name[len] = 0; - } - } - - return MNL_CB_OK; -} - -void -devlink_region_read_rsp_list_free(struct devlink_region_read_rsp_list *rsp) -{ - struct devlink_region_read_rsp_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp->obj.region_name); - free(rsp); - } -} - -struct devlink_region_read_rsp_list * -devlink_region_read_dump(struct ynl_sock *ys, - struct devlink_region_read_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_region_read_rsp_list); - yds.cb = devlink_region_read_rsp_dump_parse; - yds.rsp_cmd = DEVLINK_CMD_REGION_READ; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_REGION_READ, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.region_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_REGION_NAME, req->region_name); - if (req->_present.region_snapshot_id) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_REGION_SNAPSHOT_ID, req->region_snapshot_id); - if (req->_present.region_direct) - mnl_attr_put(nlh, DEVLINK_ATTR_REGION_DIRECT, 0, NULL); - if (req->_present.region_chunk_addr) - mnl_attr_put_u64(nlh, DEVLINK_ATTR_REGION_CHUNK_ADDR, req->region_chunk_addr); - if (req->_present.region_chunk_len) - mnl_attr_put_u64(nlh, DEVLINK_ATTR_REGION_CHUNK_LEN, req->region_chunk_len); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_region_read_rsp_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_PORT_PARAM_GET ============== */ -/* DEVLINK_CMD_PORT_PARAM_GET - do */ -void devlink_port_param_get_req_free(struct devlink_port_param_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void devlink_port_param_get_rsp_free(struct devlink_port_param_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp); -} - -int devlink_port_param_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_port_param_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PORT_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port_index = 1; - dst->port_index = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct devlink_port_param_get_rsp * -devlink_port_param_get(struct ynl_sock *ys, - struct devlink_port_param_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_port_param_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PORT_PARAM_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_port_param_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_PORT_PARAM_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_port_param_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_PORT_PARAM_GET - dump */ -void devlink_port_param_get_list_free(struct devlink_port_param_get_list *rsp) -{ - struct devlink_port_param_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp); - } -} - -struct devlink_port_param_get_list * -devlink_port_param_get_dump(struct ynl_sock *ys) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_port_param_get_list); - yds.cb = devlink_port_param_get_rsp_parse; - yds.rsp_cmd = DEVLINK_CMD_PORT_PARAM_GET; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_PORT_PARAM_GET, 1); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_port_param_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_PORT_PARAM_SET ============== */ -/* DEVLINK_CMD_PORT_PARAM_SET - do */ -void devlink_port_param_set_req_free(struct devlink_port_param_set_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -int devlink_port_param_set(struct ynl_sock *ys, - struct devlink_port_param_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PORT_PARAM_SET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_INFO_GET ============== */ -/* DEVLINK_CMD_INFO_GET - do */ -void devlink_info_get_req_free(struct devlink_info_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void devlink_info_get_rsp_free(struct devlink_info_get_rsp *rsp) -{ - unsigned int i; - - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp->info_driver_name); - free(rsp->info_serial_number); - for (i = 0; i < rsp->n_info_version_fixed; i++) - devlink_dl_info_version_free(&rsp->info_version_fixed[i]); - free(rsp->info_version_fixed); - for (i = 0; i < rsp->n_info_version_running; i++) - devlink_dl_info_version_free(&rsp->info_version_running[i]); - free(rsp->info_version_running); - for (i = 0; i < rsp->n_info_version_stored; i++) - devlink_dl_info_version_free(&rsp->info_version_stored[i]); - free(rsp->info_version_stored); - free(rsp); -} - -int devlink_info_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - unsigned int n_info_version_running = 0; - unsigned int n_info_version_stored = 0; - unsigned int n_info_version_fixed = 0; - struct ynl_parse_arg *yarg = data; - struct devlink_info_get_rsp *dst; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - dst = yarg->data; - parg.ys = yarg->ys; - - if (dst->info_version_fixed) - return ynl_error_parse(yarg, "attribute already present (devlink.info-version-fixed)"); - if (dst->info_version_running) - return ynl_error_parse(yarg, "attribute already present (devlink.info-version-running)"); - if (dst->info_version_stored) - return ynl_error_parse(yarg, "attribute already present (devlink.info-version-stored)"); - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_INFO_DRIVER_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.info_driver_name_len = len; - dst->info_driver_name = malloc(len + 1); - memcpy(dst->info_driver_name, mnl_attr_get_str(attr), len); - dst->info_driver_name[len] = 0; - } else if (type == DEVLINK_ATTR_INFO_SERIAL_NUMBER) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.info_serial_number_len = len; - dst->info_serial_number = malloc(len + 1); - memcpy(dst->info_serial_number, mnl_attr_get_str(attr), len); - dst->info_serial_number[len] = 0; - } else if (type == DEVLINK_ATTR_INFO_VERSION_FIXED) { - n_info_version_fixed++; - } else if (type == DEVLINK_ATTR_INFO_VERSION_RUNNING) { - n_info_version_running++; - } else if (type == DEVLINK_ATTR_INFO_VERSION_STORED) { - n_info_version_stored++; - } - } - - if (n_info_version_fixed) { - dst->info_version_fixed = calloc(n_info_version_fixed, sizeof(*dst->info_version_fixed)); - dst->n_info_version_fixed = n_info_version_fixed; - i = 0; - parg.rsp_policy = &devlink_dl_info_version_nest; - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_VERSION_FIXED) { - parg.data = &dst->info_version_fixed[i]; - if (devlink_dl_info_version_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - if (n_info_version_running) { - dst->info_version_running = calloc(n_info_version_running, sizeof(*dst->info_version_running)); - dst->n_info_version_running = n_info_version_running; - i = 0; - parg.rsp_policy = &devlink_dl_info_version_nest; - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_VERSION_RUNNING) { - parg.data = &dst->info_version_running[i]; - if (devlink_dl_info_version_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - if (n_info_version_stored) { - dst->info_version_stored = calloc(n_info_version_stored, sizeof(*dst->info_version_stored)); - dst->n_info_version_stored = n_info_version_stored; - i = 0; - parg.rsp_policy = &devlink_dl_info_version_nest; - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_VERSION_STORED) { - parg.data = &dst->info_version_stored[i]; - if (devlink_dl_info_version_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return MNL_CB_OK; -} - -struct devlink_info_get_rsp * -devlink_info_get(struct ynl_sock *ys, struct devlink_info_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_info_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_INFO_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_info_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_INFO_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_info_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_INFO_GET - dump */ -void devlink_info_get_list_free(struct devlink_info_get_list *rsp) -{ - struct devlink_info_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - unsigned int i; - - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp->obj.info_driver_name); - free(rsp->obj.info_serial_number); - for (i = 0; i < rsp->obj.n_info_version_fixed; i++) - devlink_dl_info_version_free(&rsp->obj.info_version_fixed[i]); - free(rsp->obj.info_version_fixed); - for (i = 0; i < rsp->obj.n_info_version_running; i++) - devlink_dl_info_version_free(&rsp->obj.info_version_running[i]); - free(rsp->obj.info_version_running); - for (i = 0; i < rsp->obj.n_info_version_stored; i++) - devlink_dl_info_version_free(&rsp->obj.info_version_stored[i]); - free(rsp->obj.info_version_stored); - free(rsp); - } -} - -struct devlink_info_get_list *devlink_info_get_dump(struct ynl_sock *ys) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_info_get_list); - yds.cb = devlink_info_get_rsp_parse; - yds.rsp_cmd = DEVLINK_CMD_INFO_GET; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_INFO_GET, 1); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_info_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_HEALTH_REPORTER_GET ============== */ -/* DEVLINK_CMD_HEALTH_REPORTER_GET - do */ -void -devlink_health_reporter_get_req_free(struct devlink_health_reporter_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->health_reporter_name); - free(req); -} - -void -devlink_health_reporter_get_rsp_free(struct devlink_health_reporter_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp->health_reporter_name); - free(rsp); -} - -int devlink_health_reporter_get_rsp_parse(const struct nlmsghdr *nlh, - void *data) -{ - struct devlink_health_reporter_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PORT_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port_index = 1; - dst->port_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_HEALTH_REPORTER_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.health_reporter_name_len = len; - dst->health_reporter_name = malloc(len + 1); - memcpy(dst->health_reporter_name, mnl_attr_get_str(attr), len); - dst->health_reporter_name[len] = 0; - } - } - - return MNL_CB_OK; -} - -struct devlink_health_reporter_get_rsp * -devlink_health_reporter_get(struct ynl_sock *ys, - struct devlink_health_reporter_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_health_reporter_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_HEALTH_REPORTER_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.health_reporter_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_HEALTH_REPORTER_NAME, req->health_reporter_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_health_reporter_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_HEALTH_REPORTER_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_health_reporter_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_HEALTH_REPORTER_GET - dump */ -void -devlink_health_reporter_get_list_free(struct devlink_health_reporter_get_list *rsp) -{ - struct devlink_health_reporter_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp->obj.health_reporter_name); - free(rsp); - } -} - -struct devlink_health_reporter_get_list * -devlink_health_reporter_get_dump(struct ynl_sock *ys, - struct devlink_health_reporter_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_health_reporter_get_list); - yds.cb = devlink_health_reporter_get_rsp_parse; - yds.rsp_cmd = DEVLINK_CMD_HEALTH_REPORTER_GET; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_HEALTH_REPORTER_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_health_reporter_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_HEALTH_REPORTER_SET ============== */ -/* DEVLINK_CMD_HEALTH_REPORTER_SET - do */ -void -devlink_health_reporter_set_req_free(struct devlink_health_reporter_set_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->health_reporter_name); - free(req); -} - -int devlink_health_reporter_set(struct ynl_sock *ys, - struct devlink_health_reporter_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_HEALTH_REPORTER_SET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.health_reporter_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_HEALTH_REPORTER_NAME, req->health_reporter_name); - if (req->_present.health_reporter_graceful_period) - mnl_attr_put_u64(nlh, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD, req->health_reporter_graceful_period); - if (req->_present.health_reporter_auto_recover) - mnl_attr_put_u8(nlh, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER, req->health_reporter_auto_recover); - if (req->_present.health_reporter_auto_dump) - mnl_attr_put_u8(nlh, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP, req->health_reporter_auto_dump); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_HEALTH_REPORTER_RECOVER ============== */ -/* DEVLINK_CMD_HEALTH_REPORTER_RECOVER - do */ -void -devlink_health_reporter_recover_req_free(struct devlink_health_reporter_recover_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->health_reporter_name); - free(req); -} - -int devlink_health_reporter_recover(struct ynl_sock *ys, - struct devlink_health_reporter_recover_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_HEALTH_REPORTER_RECOVER, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.health_reporter_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_HEALTH_REPORTER_NAME, req->health_reporter_name); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE ============== */ -/* DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE - do */ -void -devlink_health_reporter_diagnose_req_free(struct devlink_health_reporter_diagnose_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->health_reporter_name); - free(req); -} - -int devlink_health_reporter_diagnose(struct ynl_sock *ys, - struct devlink_health_reporter_diagnose_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.health_reporter_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_HEALTH_REPORTER_NAME, req->health_reporter_name); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET ============== */ -/* DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET - dump */ -int devlink_health_reporter_dump_get_rsp_dump_parse(const struct nlmsghdr *nlh, - void *data) -{ - struct devlink_health_reporter_dump_get_rsp_dump *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_FMSG) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.fmsg = 1; - - parg.rsp_policy = &devlink_dl_fmsg_nest; - parg.data = &dst->fmsg; - if (devlink_dl_fmsg_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -void -devlink_health_reporter_dump_get_rsp_list_free(struct devlink_health_reporter_dump_get_rsp_list *rsp) -{ - struct devlink_health_reporter_dump_get_rsp_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - devlink_dl_fmsg_free(&rsp->obj.fmsg); - free(rsp); - } -} - -struct devlink_health_reporter_dump_get_rsp_list * -devlink_health_reporter_dump_get_dump(struct ynl_sock *ys, - struct devlink_health_reporter_dump_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_health_reporter_dump_get_rsp_list); - yds.cb = devlink_health_reporter_dump_get_rsp_dump_parse; - yds.rsp_cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.health_reporter_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_HEALTH_REPORTER_NAME, req->health_reporter_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_health_reporter_dump_get_rsp_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR ============== */ -/* DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR - do */ -void -devlink_health_reporter_dump_clear_req_free(struct devlink_health_reporter_dump_clear_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->health_reporter_name); - free(req); -} - -int devlink_health_reporter_dump_clear(struct ynl_sock *ys, - struct devlink_health_reporter_dump_clear_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.health_reporter_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_HEALTH_REPORTER_NAME, req->health_reporter_name); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_FLASH_UPDATE ============== */ -/* DEVLINK_CMD_FLASH_UPDATE - do */ -void devlink_flash_update_req_free(struct devlink_flash_update_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->flash_update_file_name); - free(req->flash_update_component); - free(req); -} - -int devlink_flash_update(struct ynl_sock *ys, - struct devlink_flash_update_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_FLASH_UPDATE, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.flash_update_file_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME, req->flash_update_file_name); - if (req->_present.flash_update_component_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT, req->flash_update_component); - if (req->_present.flash_update_overwrite_mask) - mnl_attr_put(nlh, DEVLINK_ATTR_FLASH_UPDATE_OVERWRITE_MASK, sizeof(struct nla_bitfield32), &req->flash_update_overwrite_mask); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_TRAP_GET ============== */ -/* DEVLINK_CMD_TRAP_GET - do */ -void devlink_trap_get_req_free(struct devlink_trap_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->trap_name); - free(req); -} - -void devlink_trap_get_rsp_free(struct devlink_trap_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp->trap_name); - free(rsp); -} - -int devlink_trap_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct devlink_trap_get_rsp *dst; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_TRAP_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.trap_name_len = len; - dst->trap_name = malloc(len + 1); - memcpy(dst->trap_name, mnl_attr_get_str(attr), len); - dst->trap_name[len] = 0; - } - } - - return MNL_CB_OK; -} - -struct devlink_trap_get_rsp * -devlink_trap_get(struct ynl_sock *ys, struct devlink_trap_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_trap_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_TRAP_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.trap_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_TRAP_NAME, req->trap_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_trap_get_rsp_parse; - yrs.rsp_cmd = 63; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_trap_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_TRAP_GET - dump */ -void devlink_trap_get_list_free(struct devlink_trap_get_list *rsp) -{ - struct devlink_trap_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp->obj.trap_name); - free(rsp); - } -} - -struct devlink_trap_get_list * -devlink_trap_get_dump(struct ynl_sock *ys, - struct devlink_trap_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_trap_get_list); - yds.cb = devlink_trap_get_rsp_parse; - yds.rsp_cmd = 63; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_TRAP_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_trap_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_TRAP_SET ============== */ -/* DEVLINK_CMD_TRAP_SET - do */ -void devlink_trap_set_req_free(struct devlink_trap_set_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->trap_name); - free(req); -} - -int devlink_trap_set(struct ynl_sock *ys, struct devlink_trap_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_TRAP_SET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.trap_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_TRAP_NAME, req->trap_name); - if (req->_present.trap_action) - mnl_attr_put_u8(nlh, DEVLINK_ATTR_TRAP_ACTION, req->trap_action); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_TRAP_GROUP_GET ============== */ -/* DEVLINK_CMD_TRAP_GROUP_GET - do */ -void devlink_trap_group_get_req_free(struct devlink_trap_group_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->trap_group_name); - free(req); -} - -void devlink_trap_group_get_rsp_free(struct devlink_trap_group_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp->trap_group_name); - free(rsp); -} - -int devlink_trap_group_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_trap_group_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_TRAP_GROUP_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.trap_group_name_len = len; - dst->trap_group_name = malloc(len + 1); - memcpy(dst->trap_group_name, mnl_attr_get_str(attr), len); - dst->trap_group_name[len] = 0; - } - } - - return MNL_CB_OK; -} - -struct devlink_trap_group_get_rsp * -devlink_trap_group_get(struct ynl_sock *ys, - struct devlink_trap_group_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_trap_group_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_TRAP_GROUP_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.trap_group_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_TRAP_GROUP_NAME, req->trap_group_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_trap_group_get_rsp_parse; - yrs.rsp_cmd = 67; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_trap_group_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_TRAP_GROUP_GET - dump */ -void devlink_trap_group_get_list_free(struct devlink_trap_group_get_list *rsp) -{ - struct devlink_trap_group_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp->obj.trap_group_name); - free(rsp); - } -} - -struct devlink_trap_group_get_list * -devlink_trap_group_get_dump(struct ynl_sock *ys, - struct devlink_trap_group_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_trap_group_get_list); - yds.cb = devlink_trap_group_get_rsp_parse; - yds.rsp_cmd = 67; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_TRAP_GROUP_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_trap_group_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_TRAP_GROUP_SET ============== */ -/* DEVLINK_CMD_TRAP_GROUP_SET - do */ -void devlink_trap_group_set_req_free(struct devlink_trap_group_set_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->trap_group_name); - free(req); -} - -int devlink_trap_group_set(struct ynl_sock *ys, - struct devlink_trap_group_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_TRAP_GROUP_SET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.trap_group_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_TRAP_GROUP_NAME, req->trap_group_name); - if (req->_present.trap_action) - mnl_attr_put_u8(nlh, DEVLINK_ATTR_TRAP_ACTION, req->trap_action); - if (req->_present.trap_policer_id) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_TRAP_POLICER_ID, req->trap_policer_id); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_TRAP_POLICER_GET ============== */ -/* DEVLINK_CMD_TRAP_POLICER_GET - do */ -void -devlink_trap_policer_get_req_free(struct devlink_trap_policer_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void -devlink_trap_policer_get_rsp_free(struct devlink_trap_policer_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp); -} - -int devlink_trap_policer_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_trap_policer_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_TRAP_POLICER_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.trap_policer_id = 1; - dst->trap_policer_id = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct devlink_trap_policer_get_rsp * -devlink_trap_policer_get(struct ynl_sock *ys, - struct devlink_trap_policer_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_trap_policer_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_TRAP_POLICER_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.trap_policer_id) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_TRAP_POLICER_ID, req->trap_policer_id); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_trap_policer_get_rsp_parse; - yrs.rsp_cmd = 71; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_trap_policer_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_TRAP_POLICER_GET - dump */ -void -devlink_trap_policer_get_list_free(struct devlink_trap_policer_get_list *rsp) -{ - struct devlink_trap_policer_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp); - } -} - -struct devlink_trap_policer_get_list * -devlink_trap_policer_get_dump(struct ynl_sock *ys, - struct devlink_trap_policer_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_trap_policer_get_list); - yds.cb = devlink_trap_policer_get_rsp_parse; - yds.rsp_cmd = 71; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_TRAP_POLICER_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_trap_policer_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_TRAP_POLICER_SET ============== */ -/* DEVLINK_CMD_TRAP_POLICER_SET - do */ -void -devlink_trap_policer_set_req_free(struct devlink_trap_policer_set_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -int devlink_trap_policer_set(struct ynl_sock *ys, - struct devlink_trap_policer_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_TRAP_POLICER_SET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.trap_policer_id) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_TRAP_POLICER_ID, req->trap_policer_id); - if (req->_present.trap_policer_rate) - mnl_attr_put_u64(nlh, DEVLINK_ATTR_TRAP_POLICER_RATE, req->trap_policer_rate); - if (req->_present.trap_policer_burst) - mnl_attr_put_u64(nlh, DEVLINK_ATTR_TRAP_POLICER_BURST, req->trap_policer_burst); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_HEALTH_REPORTER_TEST ============== */ -/* DEVLINK_CMD_HEALTH_REPORTER_TEST - do */ -void -devlink_health_reporter_test_req_free(struct devlink_health_reporter_test_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->health_reporter_name); - free(req); -} - -int devlink_health_reporter_test(struct ynl_sock *ys, - struct devlink_health_reporter_test_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_HEALTH_REPORTER_TEST, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.health_reporter_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_HEALTH_REPORTER_NAME, req->health_reporter_name); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_RATE_GET ============== */ -/* DEVLINK_CMD_RATE_GET - do */ -void devlink_rate_get_req_free(struct devlink_rate_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->rate_node_name); - free(req); -} - -void devlink_rate_get_rsp_free(struct devlink_rate_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp->rate_node_name); - free(rsp); -} - -int devlink_rate_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct devlink_rate_get_rsp *dst; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PORT_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port_index = 1; - dst->port_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_RATE_NODE_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.rate_node_name_len = len; - dst->rate_node_name = malloc(len + 1); - memcpy(dst->rate_node_name, mnl_attr_get_str(attr), len); - dst->rate_node_name[len] = 0; - } - } - - return MNL_CB_OK; -} - -struct devlink_rate_get_rsp * -devlink_rate_get(struct ynl_sock *ys, struct devlink_rate_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_rate_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_RATE_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.rate_node_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_RATE_NODE_NAME, req->rate_node_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_rate_get_rsp_parse; - yrs.rsp_cmd = 76; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_rate_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_RATE_GET - dump */ -void devlink_rate_get_list_free(struct devlink_rate_get_list *rsp) -{ - struct devlink_rate_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp->obj.rate_node_name); - free(rsp); - } -} - -struct devlink_rate_get_list * -devlink_rate_get_dump(struct ynl_sock *ys, - struct devlink_rate_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_rate_get_list); - yds.cb = devlink_rate_get_rsp_parse; - yds.rsp_cmd = 76; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_RATE_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_rate_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_RATE_SET ============== */ -/* DEVLINK_CMD_RATE_SET - do */ -void devlink_rate_set_req_free(struct devlink_rate_set_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->rate_node_name); - free(req->rate_parent_node_name); - free(req); -} - -int devlink_rate_set(struct ynl_sock *ys, struct devlink_rate_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_RATE_SET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.rate_node_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_RATE_NODE_NAME, req->rate_node_name); - if (req->_present.rate_tx_share) - mnl_attr_put_u64(nlh, DEVLINK_ATTR_RATE_TX_SHARE, req->rate_tx_share); - if (req->_present.rate_tx_max) - mnl_attr_put_u64(nlh, DEVLINK_ATTR_RATE_TX_MAX, req->rate_tx_max); - if (req->_present.rate_tx_priority) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_RATE_TX_PRIORITY, req->rate_tx_priority); - if (req->_present.rate_tx_weight) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_RATE_TX_WEIGHT, req->rate_tx_weight); - if (req->_present.rate_parent_node_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_RATE_PARENT_NODE_NAME, req->rate_parent_node_name); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_RATE_NEW ============== */ -/* DEVLINK_CMD_RATE_NEW - do */ -void devlink_rate_new_req_free(struct devlink_rate_new_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->rate_node_name); - free(req->rate_parent_node_name); - free(req); -} - -int devlink_rate_new(struct ynl_sock *ys, struct devlink_rate_new_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_RATE_NEW, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.rate_node_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_RATE_NODE_NAME, req->rate_node_name); - if (req->_present.rate_tx_share) - mnl_attr_put_u64(nlh, DEVLINK_ATTR_RATE_TX_SHARE, req->rate_tx_share); - if (req->_present.rate_tx_max) - mnl_attr_put_u64(nlh, DEVLINK_ATTR_RATE_TX_MAX, req->rate_tx_max); - if (req->_present.rate_tx_priority) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_RATE_TX_PRIORITY, req->rate_tx_priority); - if (req->_present.rate_tx_weight) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_RATE_TX_WEIGHT, req->rate_tx_weight); - if (req->_present.rate_parent_node_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_RATE_PARENT_NODE_NAME, req->rate_parent_node_name); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_RATE_DEL ============== */ -/* DEVLINK_CMD_RATE_DEL - do */ -void devlink_rate_del_req_free(struct devlink_rate_del_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->rate_node_name); - free(req); -} - -int devlink_rate_del(struct ynl_sock *ys, struct devlink_rate_del_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_RATE_DEL, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.rate_node_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_RATE_NODE_NAME, req->rate_node_name); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_LINECARD_GET ============== */ -/* DEVLINK_CMD_LINECARD_GET - do */ -void devlink_linecard_get_req_free(struct devlink_linecard_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void devlink_linecard_get_rsp_free(struct devlink_linecard_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp); -} - -int devlink_linecard_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_linecard_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_LINECARD_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.linecard_index = 1; - dst->linecard_index = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct devlink_linecard_get_rsp * -devlink_linecard_get(struct ynl_sock *ys, struct devlink_linecard_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_linecard_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_LINECARD_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.linecard_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_LINECARD_INDEX, req->linecard_index); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_linecard_get_rsp_parse; - yrs.rsp_cmd = 80; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_linecard_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_LINECARD_GET - dump */ -void devlink_linecard_get_list_free(struct devlink_linecard_get_list *rsp) -{ - struct devlink_linecard_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp); - } -} - -struct devlink_linecard_get_list * -devlink_linecard_get_dump(struct ynl_sock *ys, - struct devlink_linecard_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_linecard_get_list); - yds.cb = devlink_linecard_get_rsp_parse; - yds.rsp_cmd = 80; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_LINECARD_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_linecard_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_LINECARD_SET ============== */ -/* DEVLINK_CMD_LINECARD_SET - do */ -void devlink_linecard_set_req_free(struct devlink_linecard_set_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->linecard_type); - free(req); -} - -int devlink_linecard_set(struct ynl_sock *ys, - struct devlink_linecard_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_LINECARD_SET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.linecard_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_LINECARD_INDEX, req->linecard_index); - if (req->_present.linecard_type_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_LINECARD_TYPE, req->linecard_type); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== DEVLINK_CMD_SELFTESTS_GET ============== */ -/* DEVLINK_CMD_SELFTESTS_GET - do */ -void devlink_selftests_get_req_free(struct devlink_selftests_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req); -} - -void devlink_selftests_get_rsp_free(struct devlink_selftests_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp); -} - -int devlink_selftests_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct devlink_selftests_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == DEVLINK_ATTR_BUS_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.bus_name_len = len; - dst->bus_name = malloc(len + 1); - memcpy(dst->bus_name, mnl_attr_get_str(attr), len); - dst->bus_name[len] = 0; - } else if (type == DEVLINK_ATTR_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } - } - - return MNL_CB_OK; -} - -struct devlink_selftests_get_rsp * -devlink_selftests_get(struct ynl_sock *ys, - struct devlink_selftests_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_selftests_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SELFTESTS_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_selftests_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_SELFTESTS_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_selftests_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_SELFTESTS_GET - dump */ -void devlink_selftests_get_list_free(struct devlink_selftests_get_list *rsp) -{ - struct devlink_selftests_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp); - } -} - -struct devlink_selftests_get_list * -devlink_selftests_get_dump(struct ynl_sock *ys) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_selftests_get_list); - yds.cb = devlink_selftests_get_rsp_parse; - yds.rsp_cmd = DEVLINK_CMD_SELFTESTS_GET; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_SELFTESTS_GET, 1); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_selftests_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_SELFTESTS_RUN ============== */ -/* DEVLINK_CMD_SELFTESTS_RUN - do */ -void devlink_selftests_run_req_free(struct devlink_selftests_run_req *req) -{ - free(req->bus_name); - free(req->dev_name); - devlink_dl_selftest_id_free(&req->selftests); - free(req); -} - -int devlink_selftests_run(struct ynl_sock *ys, - struct devlink_selftests_run_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SELFTESTS_RUN, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.selftests) - devlink_dl_selftest_id_put(nlh, DEVLINK_ATTR_SELFTESTS, &req->selftests); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -const struct ynl_family ynl_devlink_family = { - .name = "devlink", -}; diff --git a/tools/net/ynl/generated/devlink-user.h b/tools/net/ynl/generated/devlink-user.h deleted file mode 100644 index 1db4edc36e..0000000000 --- a/tools/net/ynl/generated/devlink-user.h +++ /dev/null @@ -1,5255 +0,0 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/devlink.yaml */ -/* YNL-GEN user header */ - -#ifndef _LINUX_DEVLINK_GEN_H -#define _LINUX_DEVLINK_GEN_H - -#include -#include -#include -#include -#include - -struct ynl_sock; - -extern const struct ynl_family ynl_devlink_family; - -/* Enums */ -const char *devlink_op_str(int op); -const char *devlink_sb_pool_type_str(enum devlink_sb_pool_type value); -const char *devlink_port_type_str(enum devlink_port_type value); -const char *devlink_port_flavour_str(enum devlink_port_flavour value); -const char *devlink_port_fn_state_str(enum devlink_port_fn_state value); -const char *devlink_port_fn_opstate_str(enum devlink_port_fn_opstate value); -const char *devlink_port_fn_attr_cap_str(enum devlink_port_fn_attr_cap value); -const char * -devlink_sb_threshold_type_str(enum devlink_sb_threshold_type value); -const char *devlink_eswitch_mode_str(enum devlink_eswitch_mode value); -const char * -devlink_eswitch_inline_mode_str(enum devlink_eswitch_inline_mode value); -const char * -devlink_eswitch_encap_mode_str(enum devlink_eswitch_encap_mode value); -const char *devlink_dpipe_match_type_str(enum devlink_dpipe_match_type value); -const char * -devlink_dpipe_action_type_str(enum devlink_dpipe_action_type value); -const char * -devlink_dpipe_field_mapping_type_str(enum devlink_dpipe_field_mapping_type value); -const char *devlink_resource_unit_str(enum devlink_resource_unit value); -const char *devlink_reload_action_str(enum devlink_reload_action value); -const char *devlink_param_cmode_str(enum devlink_param_cmode value); -const char *devlink_flash_overwrite_str(enum devlink_flash_overwrite value); -const char *devlink_trap_action_str(enum devlink_trap_action value); - -/* Common nested types */ -struct devlink_dl_dpipe_match { - struct { - __u32 dpipe_match_type:1; - __u32 dpipe_header_id:1; - __u32 dpipe_header_global:1; - __u32 dpipe_header_index:1; - __u32 dpipe_field_id:1; - } _present; - - enum devlink_dpipe_match_type dpipe_match_type; - __u32 dpipe_header_id; - __u8 dpipe_header_global; - __u32 dpipe_header_index; - __u32 dpipe_field_id; -}; - -struct devlink_dl_dpipe_match_value { - struct { - __u32 dpipe_value_len; - __u32 dpipe_value_mask_len; - __u32 dpipe_value_mapping:1; - } _present; - - unsigned int n_dpipe_match; - struct devlink_dl_dpipe_match *dpipe_match; - void *dpipe_value; - void *dpipe_value_mask; - __u32 dpipe_value_mapping; -}; - -struct devlink_dl_dpipe_action { - struct { - __u32 dpipe_action_type:1; - __u32 dpipe_header_id:1; - __u32 dpipe_header_global:1; - __u32 dpipe_header_index:1; - __u32 dpipe_field_id:1; - } _present; - - enum devlink_dpipe_action_type dpipe_action_type; - __u32 dpipe_header_id; - __u8 dpipe_header_global; - __u32 dpipe_header_index; - __u32 dpipe_field_id; -}; - -struct devlink_dl_dpipe_action_value { - struct { - __u32 dpipe_value_len; - __u32 dpipe_value_mask_len; - __u32 dpipe_value_mapping:1; - } _present; - - unsigned int n_dpipe_action; - struct devlink_dl_dpipe_action *dpipe_action; - void *dpipe_value; - void *dpipe_value_mask; - __u32 dpipe_value_mapping; -}; - -struct devlink_dl_dpipe_field { - struct { - __u32 dpipe_field_name_len; - __u32 dpipe_field_id:1; - __u32 dpipe_field_bitwidth:1; - __u32 dpipe_field_mapping_type:1; - } _present; - - char *dpipe_field_name; - __u32 dpipe_field_id; - __u32 dpipe_field_bitwidth; - enum devlink_dpipe_field_mapping_type dpipe_field_mapping_type; -}; - -struct devlink_dl_resource { - struct { - __u32 resource_name_len; - __u32 resource_id:1; - __u32 resource_size:1; - __u32 resource_size_new:1; - __u32 resource_size_valid:1; - __u32 resource_size_min:1; - __u32 resource_size_max:1; - __u32 resource_size_gran:1; - __u32 resource_unit:1; - __u32 resource_occ:1; - } _present; - - char *resource_name; - __u64 resource_id; - __u64 resource_size; - __u64 resource_size_new; - __u8 resource_size_valid; - __u64 resource_size_min; - __u64 resource_size_max; - __u64 resource_size_gran; - enum devlink_resource_unit resource_unit; - __u64 resource_occ; -}; - -struct devlink_dl_info_version { - struct { - __u32 info_version_name_len; - __u32 info_version_value_len; - } _present; - - char *info_version_name; - char *info_version_value; -}; - -struct devlink_dl_fmsg { - struct { - __u32 fmsg_obj_nest_start:1; - __u32 fmsg_pair_nest_start:1; - __u32 fmsg_arr_nest_start:1; - __u32 fmsg_nest_end:1; - __u32 fmsg_obj_name_len; - } _present; - - char *fmsg_obj_name; -}; - -struct devlink_dl_port_function { - struct { - __u32 hw_addr_len; - __u32 state:1; - __u32 opstate:1; - __u32 caps:1; - } _present; - - void *hw_addr; - enum devlink_port_fn_state state; - enum devlink_port_fn_opstate opstate; - struct nla_bitfield32 caps; -}; - -struct devlink_dl_reload_stats_entry { - struct { - __u32 reload_stats_limit:1; - __u32 reload_stats_value:1; - } _present; - - __u8 reload_stats_limit; - __u32 reload_stats_value; -}; - -struct devlink_dl_reload_act_stats { - unsigned int n_reload_stats_entry; - struct devlink_dl_reload_stats_entry *reload_stats_entry; -}; - -struct devlink_dl_selftest_id { - struct { - __u32 flash:1; - } _present; -}; - -struct devlink_dl_dpipe_table_matches { - unsigned int n_dpipe_match; - struct devlink_dl_dpipe_match *dpipe_match; -}; - -struct devlink_dl_dpipe_table_actions { - unsigned int n_dpipe_action; - struct devlink_dl_dpipe_action *dpipe_action; -}; - -struct devlink_dl_dpipe_entry_match_values { - unsigned int n_dpipe_match_value; - struct devlink_dl_dpipe_match_value *dpipe_match_value; -}; - -struct devlink_dl_dpipe_entry_action_values { - unsigned int n_dpipe_action_value; - struct devlink_dl_dpipe_action_value *dpipe_action_value; -}; - -struct devlink_dl_dpipe_header_fields { - unsigned int n_dpipe_field; - struct devlink_dl_dpipe_field *dpipe_field; -}; - -struct devlink_dl_resource_list { - unsigned int n_resource; - struct devlink_dl_resource *resource; -}; - -struct devlink_dl_reload_act_info { - struct { - __u32 reload_action:1; - } _present; - - enum devlink_reload_action reload_action; - unsigned int n_reload_action_stats; - struct devlink_dl_reload_act_stats *reload_action_stats; -}; - -struct devlink_dl_dpipe_table { - struct { - __u32 dpipe_table_name_len; - __u32 dpipe_table_size:1; - __u32 dpipe_table_matches:1; - __u32 dpipe_table_actions:1; - __u32 dpipe_table_counters_enabled:1; - __u32 dpipe_table_resource_id:1; - __u32 dpipe_table_resource_units:1; - } _present; - - char *dpipe_table_name; - __u64 dpipe_table_size; - struct devlink_dl_dpipe_table_matches dpipe_table_matches; - struct devlink_dl_dpipe_table_actions dpipe_table_actions; - __u8 dpipe_table_counters_enabled; - __u64 dpipe_table_resource_id; - __u64 dpipe_table_resource_units; -}; - -struct devlink_dl_dpipe_entry { - struct { - __u32 dpipe_entry_index:1; - __u32 dpipe_entry_match_values:1; - __u32 dpipe_entry_action_values:1; - __u32 dpipe_entry_counter:1; - } _present; - - __u64 dpipe_entry_index; - struct devlink_dl_dpipe_entry_match_values dpipe_entry_match_values; - struct devlink_dl_dpipe_entry_action_values dpipe_entry_action_values; - __u64 dpipe_entry_counter; -}; - -struct devlink_dl_dpipe_header { - struct { - __u32 dpipe_header_name_len; - __u32 dpipe_header_id:1; - __u32 dpipe_header_global:1; - __u32 dpipe_header_fields:1; - } _present; - - char *dpipe_header_name; - __u32 dpipe_header_id; - __u8 dpipe_header_global; - struct devlink_dl_dpipe_header_fields dpipe_header_fields; -}; - -struct devlink_dl_reload_stats { - unsigned int n_reload_action_info; - struct devlink_dl_reload_act_info *reload_action_info; -}; - -struct devlink_dl_dpipe_tables { - unsigned int n_dpipe_table; - struct devlink_dl_dpipe_table *dpipe_table; -}; - -struct devlink_dl_dpipe_entries { - unsigned int n_dpipe_entry; - struct devlink_dl_dpipe_entry *dpipe_entry; -}; - -struct devlink_dl_dpipe_headers { - unsigned int n_dpipe_header; - struct devlink_dl_dpipe_header *dpipe_header; -}; - -struct devlink_dl_dev_stats { - struct { - __u32 reload_stats:1; - __u32 remote_reload_stats:1; - } _present; - - struct devlink_dl_reload_stats reload_stats; - struct devlink_dl_reload_stats remote_reload_stats; -}; - -/* ============== DEVLINK_CMD_GET ============== */ -/* DEVLINK_CMD_GET - do */ -struct devlink_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_get_req *devlink_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_get_req)); -} -void devlink_get_req_free(struct devlink_get_req *req); - -static inline void -devlink_get_req_set_bus_name(struct devlink_get_req *req, const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_get_req_set_dev_name(struct devlink_get_req *req, const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 reload_failed:1; - __u32 dev_stats:1; - } _present; - - char *bus_name; - char *dev_name; - __u8 reload_failed; - struct devlink_dl_dev_stats dev_stats; -}; - -void devlink_get_rsp_free(struct devlink_get_rsp *rsp); - -/* - * Get devlink instances. - */ -struct devlink_get_rsp * -devlink_get(struct ynl_sock *ys, struct devlink_get_req *req); - -/* DEVLINK_CMD_GET - dump */ -struct devlink_get_list { - struct devlink_get_list *next; - struct devlink_get_rsp obj __attribute__((aligned(8))); -}; - -void devlink_get_list_free(struct devlink_get_list *rsp); - -struct devlink_get_list *devlink_get_dump(struct ynl_sock *ys); - -/* ============== DEVLINK_CMD_PORT_GET ============== */ -/* DEVLINK_CMD_PORT_GET - do */ -struct devlink_port_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; -}; - -static inline struct devlink_port_get_req *devlink_port_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_port_get_req)); -} -void devlink_port_get_req_free(struct devlink_port_get_req *req); - -static inline void -devlink_port_get_req_set_bus_name(struct devlink_port_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_port_get_req_set_dev_name(struct devlink_port_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_port_get_req_set_port_index(struct devlink_port_get_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} - -struct devlink_port_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; -}; - -void devlink_port_get_rsp_free(struct devlink_port_get_rsp *rsp); - -/* - * Get devlink port instances. - */ -struct devlink_port_get_rsp * -devlink_port_get(struct ynl_sock *ys, struct devlink_port_get_req *req); - -/* DEVLINK_CMD_PORT_GET - dump */ -struct devlink_port_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_port_get_req_dump * -devlink_port_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_port_get_req_dump)); -} -void devlink_port_get_req_dump_free(struct devlink_port_get_req_dump *req); - -static inline void -devlink_port_get_req_dump_set_bus_name(struct devlink_port_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_port_get_req_dump_set_dev_name(struct devlink_port_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_port_get_rsp_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; -}; - -struct devlink_port_get_rsp_list { - struct devlink_port_get_rsp_list *next; - struct devlink_port_get_rsp_dump obj __attribute__((aligned(8))); -}; - -void devlink_port_get_rsp_list_free(struct devlink_port_get_rsp_list *rsp); - -struct devlink_port_get_rsp_list * -devlink_port_get_dump(struct ynl_sock *ys, - struct devlink_port_get_req_dump *req); - -/* ============== DEVLINK_CMD_PORT_SET ============== */ -/* DEVLINK_CMD_PORT_SET - do */ -struct devlink_port_set_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 port_type:1; - __u32 port_function:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - enum devlink_port_type port_type; - struct devlink_dl_port_function port_function; -}; - -static inline struct devlink_port_set_req *devlink_port_set_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_port_set_req)); -} -void devlink_port_set_req_free(struct devlink_port_set_req *req); - -static inline void -devlink_port_set_req_set_bus_name(struct devlink_port_set_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_port_set_req_set_dev_name(struct devlink_port_set_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_port_set_req_set_port_index(struct devlink_port_set_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_port_set_req_set_port_type(struct devlink_port_set_req *req, - enum devlink_port_type port_type) -{ - req->_present.port_type = 1; - req->port_type = port_type; -} -static inline void -devlink_port_set_req_set_port_function_hw_addr(struct devlink_port_set_req *req, - const void *hw_addr, size_t len) -{ - free(req->port_function.hw_addr); - req->port_function._present.hw_addr_len = len; - req->port_function.hw_addr = malloc(req->port_function._present.hw_addr_len); - memcpy(req->port_function.hw_addr, hw_addr, req->port_function._present.hw_addr_len); -} -static inline void -devlink_port_set_req_set_port_function_state(struct devlink_port_set_req *req, - enum devlink_port_fn_state state) -{ - req->_present.port_function = 1; - req->port_function._present.state = 1; - req->port_function.state = state; -} -static inline void -devlink_port_set_req_set_port_function_opstate(struct devlink_port_set_req *req, - enum devlink_port_fn_opstate opstate) -{ - req->_present.port_function = 1; - req->port_function._present.opstate = 1; - req->port_function.opstate = opstate; -} -static inline void -devlink_port_set_req_set_port_function_caps(struct devlink_port_set_req *req, - struct nla_bitfield32 *caps) -{ - req->_present.port_function = 1; - req->port_function._present.caps = 1; - memcpy(&req->port_function.caps, caps, sizeof(struct nla_bitfield32)); -} - -/* - * Set devlink port instances. - */ -int devlink_port_set(struct ynl_sock *ys, struct devlink_port_set_req *req); - -/* ============== DEVLINK_CMD_PORT_NEW ============== */ -/* DEVLINK_CMD_PORT_NEW - do */ -struct devlink_port_new_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 port_flavour:1; - __u32 port_pci_pf_number:1; - __u32 port_pci_sf_number:1; - __u32 port_controller_number:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - enum devlink_port_flavour port_flavour; - __u16 port_pci_pf_number; - __u32 port_pci_sf_number; - __u32 port_controller_number; -}; - -static inline struct devlink_port_new_req *devlink_port_new_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_port_new_req)); -} -void devlink_port_new_req_free(struct devlink_port_new_req *req); - -static inline void -devlink_port_new_req_set_bus_name(struct devlink_port_new_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_port_new_req_set_dev_name(struct devlink_port_new_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_port_new_req_set_port_index(struct devlink_port_new_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_port_new_req_set_port_flavour(struct devlink_port_new_req *req, - enum devlink_port_flavour port_flavour) -{ - req->_present.port_flavour = 1; - req->port_flavour = port_flavour; -} -static inline void -devlink_port_new_req_set_port_pci_pf_number(struct devlink_port_new_req *req, - __u16 port_pci_pf_number) -{ - req->_present.port_pci_pf_number = 1; - req->port_pci_pf_number = port_pci_pf_number; -} -static inline void -devlink_port_new_req_set_port_pci_sf_number(struct devlink_port_new_req *req, - __u32 port_pci_sf_number) -{ - req->_present.port_pci_sf_number = 1; - req->port_pci_sf_number = port_pci_sf_number; -} -static inline void -devlink_port_new_req_set_port_controller_number(struct devlink_port_new_req *req, - __u32 port_controller_number) -{ - req->_present.port_controller_number = 1; - req->port_controller_number = port_controller_number; -} - -struct devlink_port_new_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; -}; - -void devlink_port_new_rsp_free(struct devlink_port_new_rsp *rsp); - -/* - * Create devlink port instances. - */ -struct devlink_port_new_rsp * -devlink_port_new(struct ynl_sock *ys, struct devlink_port_new_req *req); - -/* ============== DEVLINK_CMD_PORT_DEL ============== */ -/* DEVLINK_CMD_PORT_DEL - do */ -struct devlink_port_del_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; -}; - -static inline struct devlink_port_del_req *devlink_port_del_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_port_del_req)); -} -void devlink_port_del_req_free(struct devlink_port_del_req *req); - -static inline void -devlink_port_del_req_set_bus_name(struct devlink_port_del_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_port_del_req_set_dev_name(struct devlink_port_del_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_port_del_req_set_port_index(struct devlink_port_del_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} - -/* - * Delete devlink port instances. - */ -int devlink_port_del(struct ynl_sock *ys, struct devlink_port_del_req *req); - -/* ============== DEVLINK_CMD_PORT_SPLIT ============== */ -/* DEVLINK_CMD_PORT_SPLIT - do */ -struct devlink_port_split_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 port_split_count:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - __u32 port_split_count; -}; - -static inline struct devlink_port_split_req *devlink_port_split_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_port_split_req)); -} -void devlink_port_split_req_free(struct devlink_port_split_req *req); - -static inline void -devlink_port_split_req_set_bus_name(struct devlink_port_split_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_port_split_req_set_dev_name(struct devlink_port_split_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_port_split_req_set_port_index(struct devlink_port_split_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_port_split_req_set_port_split_count(struct devlink_port_split_req *req, - __u32 port_split_count) -{ - req->_present.port_split_count = 1; - req->port_split_count = port_split_count; -} - -/* - * Split devlink port instances. - */ -int devlink_port_split(struct ynl_sock *ys, struct devlink_port_split_req *req); - -/* ============== DEVLINK_CMD_PORT_UNSPLIT ============== */ -/* DEVLINK_CMD_PORT_UNSPLIT - do */ -struct devlink_port_unsplit_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; -}; - -static inline struct devlink_port_unsplit_req * -devlink_port_unsplit_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_port_unsplit_req)); -} -void devlink_port_unsplit_req_free(struct devlink_port_unsplit_req *req); - -static inline void -devlink_port_unsplit_req_set_bus_name(struct devlink_port_unsplit_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_port_unsplit_req_set_dev_name(struct devlink_port_unsplit_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_port_unsplit_req_set_port_index(struct devlink_port_unsplit_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} - -/* - * Unplit devlink port instances. - */ -int devlink_port_unsplit(struct ynl_sock *ys, - struct devlink_port_unsplit_req *req); - -/* ============== DEVLINK_CMD_SB_GET ============== */ -/* DEVLINK_CMD_SB_GET - do */ -struct devlink_sb_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 sb_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 sb_index; -}; - -static inline struct devlink_sb_get_req *devlink_sb_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_get_req)); -} -void devlink_sb_get_req_free(struct devlink_sb_get_req *req); - -static inline void -devlink_sb_get_req_set_bus_name(struct devlink_sb_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_get_req_set_dev_name(struct devlink_sb_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_sb_get_req_set_sb_index(struct devlink_sb_get_req *req, __u32 sb_index) -{ - req->_present.sb_index = 1; - req->sb_index = sb_index; -} - -struct devlink_sb_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 sb_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 sb_index; -}; - -void devlink_sb_get_rsp_free(struct devlink_sb_get_rsp *rsp); - -/* - * Get shared buffer instances. - */ -struct devlink_sb_get_rsp * -devlink_sb_get(struct ynl_sock *ys, struct devlink_sb_get_req *req); - -/* DEVLINK_CMD_SB_GET - dump */ -struct devlink_sb_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_sb_get_req_dump * -devlink_sb_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_get_req_dump)); -} -void devlink_sb_get_req_dump_free(struct devlink_sb_get_req_dump *req); - -static inline void -devlink_sb_get_req_dump_set_bus_name(struct devlink_sb_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_get_req_dump_set_dev_name(struct devlink_sb_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_sb_get_list { - struct devlink_sb_get_list *next; - struct devlink_sb_get_rsp obj __attribute__((aligned(8))); -}; - -void devlink_sb_get_list_free(struct devlink_sb_get_list *rsp); - -struct devlink_sb_get_list * -devlink_sb_get_dump(struct ynl_sock *ys, struct devlink_sb_get_req_dump *req); - -/* ============== DEVLINK_CMD_SB_POOL_GET ============== */ -/* DEVLINK_CMD_SB_POOL_GET - do */ -struct devlink_sb_pool_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 sb_index:1; - __u32 sb_pool_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 sb_index; - __u16 sb_pool_index; -}; - -static inline struct devlink_sb_pool_get_req * -devlink_sb_pool_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_pool_get_req)); -} -void devlink_sb_pool_get_req_free(struct devlink_sb_pool_get_req *req); - -static inline void -devlink_sb_pool_get_req_set_bus_name(struct devlink_sb_pool_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_pool_get_req_set_dev_name(struct devlink_sb_pool_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_sb_pool_get_req_set_sb_index(struct devlink_sb_pool_get_req *req, - __u32 sb_index) -{ - req->_present.sb_index = 1; - req->sb_index = sb_index; -} -static inline void -devlink_sb_pool_get_req_set_sb_pool_index(struct devlink_sb_pool_get_req *req, - __u16 sb_pool_index) -{ - req->_present.sb_pool_index = 1; - req->sb_pool_index = sb_pool_index; -} - -struct devlink_sb_pool_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 sb_index:1; - __u32 sb_pool_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 sb_index; - __u16 sb_pool_index; -}; - -void devlink_sb_pool_get_rsp_free(struct devlink_sb_pool_get_rsp *rsp); - -/* - * Get shared buffer pool instances. - */ -struct devlink_sb_pool_get_rsp * -devlink_sb_pool_get(struct ynl_sock *ys, struct devlink_sb_pool_get_req *req); - -/* DEVLINK_CMD_SB_POOL_GET - dump */ -struct devlink_sb_pool_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_sb_pool_get_req_dump * -devlink_sb_pool_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_pool_get_req_dump)); -} -void -devlink_sb_pool_get_req_dump_free(struct devlink_sb_pool_get_req_dump *req); - -static inline void -devlink_sb_pool_get_req_dump_set_bus_name(struct devlink_sb_pool_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_pool_get_req_dump_set_dev_name(struct devlink_sb_pool_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_sb_pool_get_list { - struct devlink_sb_pool_get_list *next; - struct devlink_sb_pool_get_rsp obj __attribute__((aligned(8))); -}; - -void devlink_sb_pool_get_list_free(struct devlink_sb_pool_get_list *rsp); - -struct devlink_sb_pool_get_list * -devlink_sb_pool_get_dump(struct ynl_sock *ys, - struct devlink_sb_pool_get_req_dump *req); - -/* ============== DEVLINK_CMD_SB_POOL_SET ============== */ -/* DEVLINK_CMD_SB_POOL_SET - do */ -struct devlink_sb_pool_set_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 sb_index:1; - __u32 sb_pool_index:1; - __u32 sb_pool_threshold_type:1; - __u32 sb_pool_size:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 sb_index; - __u16 sb_pool_index; - enum devlink_sb_threshold_type sb_pool_threshold_type; - __u32 sb_pool_size; -}; - -static inline struct devlink_sb_pool_set_req * -devlink_sb_pool_set_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_pool_set_req)); -} -void devlink_sb_pool_set_req_free(struct devlink_sb_pool_set_req *req); - -static inline void -devlink_sb_pool_set_req_set_bus_name(struct devlink_sb_pool_set_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_pool_set_req_set_dev_name(struct devlink_sb_pool_set_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_sb_pool_set_req_set_sb_index(struct devlink_sb_pool_set_req *req, - __u32 sb_index) -{ - req->_present.sb_index = 1; - req->sb_index = sb_index; -} -static inline void -devlink_sb_pool_set_req_set_sb_pool_index(struct devlink_sb_pool_set_req *req, - __u16 sb_pool_index) -{ - req->_present.sb_pool_index = 1; - req->sb_pool_index = sb_pool_index; -} -static inline void -devlink_sb_pool_set_req_set_sb_pool_threshold_type(struct devlink_sb_pool_set_req *req, - enum devlink_sb_threshold_type sb_pool_threshold_type) -{ - req->_present.sb_pool_threshold_type = 1; - req->sb_pool_threshold_type = sb_pool_threshold_type; -} -static inline void -devlink_sb_pool_set_req_set_sb_pool_size(struct devlink_sb_pool_set_req *req, - __u32 sb_pool_size) -{ - req->_present.sb_pool_size = 1; - req->sb_pool_size = sb_pool_size; -} - -/* - * Set shared buffer pool instances. - */ -int devlink_sb_pool_set(struct ynl_sock *ys, - struct devlink_sb_pool_set_req *req); - -/* ============== DEVLINK_CMD_SB_PORT_POOL_GET ============== */ -/* DEVLINK_CMD_SB_PORT_POOL_GET - do */ -struct devlink_sb_port_pool_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 sb_index:1; - __u32 sb_pool_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - __u32 sb_index; - __u16 sb_pool_index; -}; - -static inline struct devlink_sb_port_pool_get_req * -devlink_sb_port_pool_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_port_pool_get_req)); -} -void -devlink_sb_port_pool_get_req_free(struct devlink_sb_port_pool_get_req *req); - -static inline void -devlink_sb_port_pool_get_req_set_bus_name(struct devlink_sb_port_pool_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_port_pool_get_req_set_dev_name(struct devlink_sb_port_pool_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_sb_port_pool_get_req_set_port_index(struct devlink_sb_port_pool_get_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_sb_port_pool_get_req_set_sb_index(struct devlink_sb_port_pool_get_req *req, - __u32 sb_index) -{ - req->_present.sb_index = 1; - req->sb_index = sb_index; -} -static inline void -devlink_sb_port_pool_get_req_set_sb_pool_index(struct devlink_sb_port_pool_get_req *req, - __u16 sb_pool_index) -{ - req->_present.sb_pool_index = 1; - req->sb_pool_index = sb_pool_index; -} - -struct devlink_sb_port_pool_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 sb_index:1; - __u32 sb_pool_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - __u32 sb_index; - __u16 sb_pool_index; -}; - -void -devlink_sb_port_pool_get_rsp_free(struct devlink_sb_port_pool_get_rsp *rsp); - -/* - * Get shared buffer port-pool combinations and threshold. - */ -struct devlink_sb_port_pool_get_rsp * -devlink_sb_port_pool_get(struct ynl_sock *ys, - struct devlink_sb_port_pool_get_req *req); - -/* DEVLINK_CMD_SB_PORT_POOL_GET - dump */ -struct devlink_sb_port_pool_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_sb_port_pool_get_req_dump * -devlink_sb_port_pool_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_port_pool_get_req_dump)); -} -void -devlink_sb_port_pool_get_req_dump_free(struct devlink_sb_port_pool_get_req_dump *req); - -static inline void -devlink_sb_port_pool_get_req_dump_set_bus_name(struct devlink_sb_port_pool_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_port_pool_get_req_dump_set_dev_name(struct devlink_sb_port_pool_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_sb_port_pool_get_list { - struct devlink_sb_port_pool_get_list *next; - struct devlink_sb_port_pool_get_rsp obj __attribute__((aligned(8))); -}; - -void -devlink_sb_port_pool_get_list_free(struct devlink_sb_port_pool_get_list *rsp); - -struct devlink_sb_port_pool_get_list * -devlink_sb_port_pool_get_dump(struct ynl_sock *ys, - struct devlink_sb_port_pool_get_req_dump *req); - -/* ============== DEVLINK_CMD_SB_PORT_POOL_SET ============== */ -/* DEVLINK_CMD_SB_PORT_POOL_SET - do */ -struct devlink_sb_port_pool_set_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 sb_index:1; - __u32 sb_pool_index:1; - __u32 sb_threshold:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - __u32 sb_index; - __u16 sb_pool_index; - __u32 sb_threshold; -}; - -static inline struct devlink_sb_port_pool_set_req * -devlink_sb_port_pool_set_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_port_pool_set_req)); -} -void -devlink_sb_port_pool_set_req_free(struct devlink_sb_port_pool_set_req *req); - -static inline void -devlink_sb_port_pool_set_req_set_bus_name(struct devlink_sb_port_pool_set_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_port_pool_set_req_set_dev_name(struct devlink_sb_port_pool_set_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_sb_port_pool_set_req_set_port_index(struct devlink_sb_port_pool_set_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_sb_port_pool_set_req_set_sb_index(struct devlink_sb_port_pool_set_req *req, - __u32 sb_index) -{ - req->_present.sb_index = 1; - req->sb_index = sb_index; -} -static inline void -devlink_sb_port_pool_set_req_set_sb_pool_index(struct devlink_sb_port_pool_set_req *req, - __u16 sb_pool_index) -{ - req->_present.sb_pool_index = 1; - req->sb_pool_index = sb_pool_index; -} -static inline void -devlink_sb_port_pool_set_req_set_sb_threshold(struct devlink_sb_port_pool_set_req *req, - __u32 sb_threshold) -{ - req->_present.sb_threshold = 1; - req->sb_threshold = sb_threshold; -} - -/* - * Set shared buffer port-pool combinations and threshold. - */ -int devlink_sb_port_pool_set(struct ynl_sock *ys, - struct devlink_sb_port_pool_set_req *req); - -/* ============== DEVLINK_CMD_SB_TC_POOL_BIND_GET ============== */ -/* DEVLINK_CMD_SB_TC_POOL_BIND_GET - do */ -struct devlink_sb_tc_pool_bind_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 sb_index:1; - __u32 sb_pool_type:1; - __u32 sb_tc_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - __u32 sb_index; - enum devlink_sb_pool_type sb_pool_type; - __u16 sb_tc_index; -}; - -static inline struct devlink_sb_tc_pool_bind_get_req * -devlink_sb_tc_pool_bind_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_tc_pool_bind_get_req)); -} -void -devlink_sb_tc_pool_bind_get_req_free(struct devlink_sb_tc_pool_bind_get_req *req); - -static inline void -devlink_sb_tc_pool_bind_get_req_set_bus_name(struct devlink_sb_tc_pool_bind_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_tc_pool_bind_get_req_set_dev_name(struct devlink_sb_tc_pool_bind_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_sb_tc_pool_bind_get_req_set_port_index(struct devlink_sb_tc_pool_bind_get_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_sb_tc_pool_bind_get_req_set_sb_index(struct devlink_sb_tc_pool_bind_get_req *req, - __u32 sb_index) -{ - req->_present.sb_index = 1; - req->sb_index = sb_index; -} -static inline void -devlink_sb_tc_pool_bind_get_req_set_sb_pool_type(struct devlink_sb_tc_pool_bind_get_req *req, - enum devlink_sb_pool_type sb_pool_type) -{ - req->_present.sb_pool_type = 1; - req->sb_pool_type = sb_pool_type; -} -static inline void -devlink_sb_tc_pool_bind_get_req_set_sb_tc_index(struct devlink_sb_tc_pool_bind_get_req *req, - __u16 sb_tc_index) -{ - req->_present.sb_tc_index = 1; - req->sb_tc_index = sb_tc_index; -} - -struct devlink_sb_tc_pool_bind_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 sb_index:1; - __u32 sb_pool_type:1; - __u32 sb_tc_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - __u32 sb_index; - enum devlink_sb_pool_type sb_pool_type; - __u16 sb_tc_index; -}; - -void -devlink_sb_tc_pool_bind_get_rsp_free(struct devlink_sb_tc_pool_bind_get_rsp *rsp); - -/* - * Get shared buffer port-TC to pool bindings and threshold. - */ -struct devlink_sb_tc_pool_bind_get_rsp * -devlink_sb_tc_pool_bind_get(struct ynl_sock *ys, - struct devlink_sb_tc_pool_bind_get_req *req); - -/* DEVLINK_CMD_SB_TC_POOL_BIND_GET - dump */ -struct devlink_sb_tc_pool_bind_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_sb_tc_pool_bind_get_req_dump * -devlink_sb_tc_pool_bind_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_tc_pool_bind_get_req_dump)); -} -void -devlink_sb_tc_pool_bind_get_req_dump_free(struct devlink_sb_tc_pool_bind_get_req_dump *req); - -static inline void -devlink_sb_tc_pool_bind_get_req_dump_set_bus_name(struct devlink_sb_tc_pool_bind_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_tc_pool_bind_get_req_dump_set_dev_name(struct devlink_sb_tc_pool_bind_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_sb_tc_pool_bind_get_list { - struct devlink_sb_tc_pool_bind_get_list *next; - struct devlink_sb_tc_pool_bind_get_rsp obj __attribute__((aligned(8))); -}; - -void -devlink_sb_tc_pool_bind_get_list_free(struct devlink_sb_tc_pool_bind_get_list *rsp); - -struct devlink_sb_tc_pool_bind_get_list * -devlink_sb_tc_pool_bind_get_dump(struct ynl_sock *ys, - struct devlink_sb_tc_pool_bind_get_req_dump *req); - -/* ============== DEVLINK_CMD_SB_TC_POOL_BIND_SET ============== */ -/* DEVLINK_CMD_SB_TC_POOL_BIND_SET - do */ -struct devlink_sb_tc_pool_bind_set_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 sb_index:1; - __u32 sb_pool_index:1; - __u32 sb_pool_type:1; - __u32 sb_tc_index:1; - __u32 sb_threshold:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - __u32 sb_index; - __u16 sb_pool_index; - enum devlink_sb_pool_type sb_pool_type; - __u16 sb_tc_index; - __u32 sb_threshold; -}; - -static inline struct devlink_sb_tc_pool_bind_set_req * -devlink_sb_tc_pool_bind_set_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_tc_pool_bind_set_req)); -} -void -devlink_sb_tc_pool_bind_set_req_free(struct devlink_sb_tc_pool_bind_set_req *req); - -static inline void -devlink_sb_tc_pool_bind_set_req_set_bus_name(struct devlink_sb_tc_pool_bind_set_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_tc_pool_bind_set_req_set_dev_name(struct devlink_sb_tc_pool_bind_set_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_sb_tc_pool_bind_set_req_set_port_index(struct devlink_sb_tc_pool_bind_set_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_sb_tc_pool_bind_set_req_set_sb_index(struct devlink_sb_tc_pool_bind_set_req *req, - __u32 sb_index) -{ - req->_present.sb_index = 1; - req->sb_index = sb_index; -} -static inline void -devlink_sb_tc_pool_bind_set_req_set_sb_pool_index(struct devlink_sb_tc_pool_bind_set_req *req, - __u16 sb_pool_index) -{ - req->_present.sb_pool_index = 1; - req->sb_pool_index = sb_pool_index; -} -static inline void -devlink_sb_tc_pool_bind_set_req_set_sb_pool_type(struct devlink_sb_tc_pool_bind_set_req *req, - enum devlink_sb_pool_type sb_pool_type) -{ - req->_present.sb_pool_type = 1; - req->sb_pool_type = sb_pool_type; -} -static inline void -devlink_sb_tc_pool_bind_set_req_set_sb_tc_index(struct devlink_sb_tc_pool_bind_set_req *req, - __u16 sb_tc_index) -{ - req->_present.sb_tc_index = 1; - req->sb_tc_index = sb_tc_index; -} -static inline void -devlink_sb_tc_pool_bind_set_req_set_sb_threshold(struct devlink_sb_tc_pool_bind_set_req *req, - __u32 sb_threshold) -{ - req->_present.sb_threshold = 1; - req->sb_threshold = sb_threshold; -} - -/* - * Set shared buffer port-TC to pool bindings and threshold. - */ -int devlink_sb_tc_pool_bind_set(struct ynl_sock *ys, - struct devlink_sb_tc_pool_bind_set_req *req); - -/* ============== DEVLINK_CMD_SB_OCC_SNAPSHOT ============== */ -/* DEVLINK_CMD_SB_OCC_SNAPSHOT - do */ -struct devlink_sb_occ_snapshot_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 sb_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 sb_index; -}; - -static inline struct devlink_sb_occ_snapshot_req * -devlink_sb_occ_snapshot_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_occ_snapshot_req)); -} -void devlink_sb_occ_snapshot_req_free(struct devlink_sb_occ_snapshot_req *req); - -static inline void -devlink_sb_occ_snapshot_req_set_bus_name(struct devlink_sb_occ_snapshot_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_occ_snapshot_req_set_dev_name(struct devlink_sb_occ_snapshot_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_sb_occ_snapshot_req_set_sb_index(struct devlink_sb_occ_snapshot_req *req, - __u32 sb_index) -{ - req->_present.sb_index = 1; - req->sb_index = sb_index; -} - -/* - * Take occupancy snapshot of shared buffer. - */ -int devlink_sb_occ_snapshot(struct ynl_sock *ys, - struct devlink_sb_occ_snapshot_req *req); - -/* ============== DEVLINK_CMD_SB_OCC_MAX_CLEAR ============== */ -/* DEVLINK_CMD_SB_OCC_MAX_CLEAR - do */ -struct devlink_sb_occ_max_clear_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 sb_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 sb_index; -}; - -static inline struct devlink_sb_occ_max_clear_req * -devlink_sb_occ_max_clear_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_sb_occ_max_clear_req)); -} -void -devlink_sb_occ_max_clear_req_free(struct devlink_sb_occ_max_clear_req *req); - -static inline void -devlink_sb_occ_max_clear_req_set_bus_name(struct devlink_sb_occ_max_clear_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_sb_occ_max_clear_req_set_dev_name(struct devlink_sb_occ_max_clear_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_sb_occ_max_clear_req_set_sb_index(struct devlink_sb_occ_max_clear_req *req, - __u32 sb_index) -{ - req->_present.sb_index = 1; - req->sb_index = sb_index; -} - -/* - * Clear occupancy watermarks of shared buffer. - */ -int devlink_sb_occ_max_clear(struct ynl_sock *ys, - struct devlink_sb_occ_max_clear_req *req); - -/* ============== DEVLINK_CMD_ESWITCH_GET ============== */ -/* DEVLINK_CMD_ESWITCH_GET - do */ -struct devlink_eswitch_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_eswitch_get_req * -devlink_eswitch_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_eswitch_get_req)); -} -void devlink_eswitch_get_req_free(struct devlink_eswitch_get_req *req); - -static inline void -devlink_eswitch_get_req_set_bus_name(struct devlink_eswitch_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_eswitch_get_req_set_dev_name(struct devlink_eswitch_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_eswitch_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 eswitch_mode:1; - __u32 eswitch_inline_mode:1; - __u32 eswitch_encap_mode:1; - } _present; - - char *bus_name; - char *dev_name; - enum devlink_eswitch_mode eswitch_mode; - enum devlink_eswitch_inline_mode eswitch_inline_mode; - enum devlink_eswitch_encap_mode eswitch_encap_mode; -}; - -void devlink_eswitch_get_rsp_free(struct devlink_eswitch_get_rsp *rsp); - -/* - * Get eswitch attributes. - */ -struct devlink_eswitch_get_rsp * -devlink_eswitch_get(struct ynl_sock *ys, struct devlink_eswitch_get_req *req); - -/* ============== DEVLINK_CMD_ESWITCH_SET ============== */ -/* DEVLINK_CMD_ESWITCH_SET - do */ -struct devlink_eswitch_set_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 eswitch_mode:1; - __u32 eswitch_inline_mode:1; - __u32 eswitch_encap_mode:1; - } _present; - - char *bus_name; - char *dev_name; - enum devlink_eswitch_mode eswitch_mode; - enum devlink_eswitch_inline_mode eswitch_inline_mode; - enum devlink_eswitch_encap_mode eswitch_encap_mode; -}; - -static inline struct devlink_eswitch_set_req * -devlink_eswitch_set_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_eswitch_set_req)); -} -void devlink_eswitch_set_req_free(struct devlink_eswitch_set_req *req); - -static inline void -devlink_eswitch_set_req_set_bus_name(struct devlink_eswitch_set_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_eswitch_set_req_set_dev_name(struct devlink_eswitch_set_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_eswitch_set_req_set_eswitch_mode(struct devlink_eswitch_set_req *req, - enum devlink_eswitch_mode eswitch_mode) -{ - req->_present.eswitch_mode = 1; - req->eswitch_mode = eswitch_mode; -} -static inline void -devlink_eswitch_set_req_set_eswitch_inline_mode(struct devlink_eswitch_set_req *req, - enum devlink_eswitch_inline_mode eswitch_inline_mode) -{ - req->_present.eswitch_inline_mode = 1; - req->eswitch_inline_mode = eswitch_inline_mode; -} -static inline void -devlink_eswitch_set_req_set_eswitch_encap_mode(struct devlink_eswitch_set_req *req, - enum devlink_eswitch_encap_mode eswitch_encap_mode) -{ - req->_present.eswitch_encap_mode = 1; - req->eswitch_encap_mode = eswitch_encap_mode; -} - -/* - * Set eswitch attributes. - */ -int devlink_eswitch_set(struct ynl_sock *ys, - struct devlink_eswitch_set_req *req); - -/* ============== DEVLINK_CMD_DPIPE_TABLE_GET ============== */ -/* DEVLINK_CMD_DPIPE_TABLE_GET - do */ -struct devlink_dpipe_table_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 dpipe_table_name_len; - } _present; - - char *bus_name; - char *dev_name; - char *dpipe_table_name; -}; - -static inline struct devlink_dpipe_table_get_req * -devlink_dpipe_table_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_dpipe_table_get_req)); -} -void devlink_dpipe_table_get_req_free(struct devlink_dpipe_table_get_req *req); - -static inline void -devlink_dpipe_table_get_req_set_bus_name(struct devlink_dpipe_table_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_dpipe_table_get_req_set_dev_name(struct devlink_dpipe_table_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_dpipe_table_get_req_set_dpipe_table_name(struct devlink_dpipe_table_get_req *req, - const char *dpipe_table_name) -{ - free(req->dpipe_table_name); - req->_present.dpipe_table_name_len = strlen(dpipe_table_name); - req->dpipe_table_name = malloc(req->_present.dpipe_table_name_len + 1); - memcpy(req->dpipe_table_name, dpipe_table_name, req->_present.dpipe_table_name_len); - req->dpipe_table_name[req->_present.dpipe_table_name_len] = 0; -} - -struct devlink_dpipe_table_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 dpipe_tables:1; - } _present; - - char *bus_name; - char *dev_name; - struct devlink_dl_dpipe_tables dpipe_tables; -}; - -void devlink_dpipe_table_get_rsp_free(struct devlink_dpipe_table_get_rsp *rsp); - -/* - * Get dpipe table attributes. - */ -struct devlink_dpipe_table_get_rsp * -devlink_dpipe_table_get(struct ynl_sock *ys, - struct devlink_dpipe_table_get_req *req); - -/* ============== DEVLINK_CMD_DPIPE_ENTRIES_GET ============== */ -/* DEVLINK_CMD_DPIPE_ENTRIES_GET - do */ -struct devlink_dpipe_entries_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 dpipe_table_name_len; - } _present; - - char *bus_name; - char *dev_name; - char *dpipe_table_name; -}; - -static inline struct devlink_dpipe_entries_get_req * -devlink_dpipe_entries_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_dpipe_entries_get_req)); -} -void -devlink_dpipe_entries_get_req_free(struct devlink_dpipe_entries_get_req *req); - -static inline void -devlink_dpipe_entries_get_req_set_bus_name(struct devlink_dpipe_entries_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_dpipe_entries_get_req_set_dev_name(struct devlink_dpipe_entries_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_dpipe_entries_get_req_set_dpipe_table_name(struct devlink_dpipe_entries_get_req *req, - const char *dpipe_table_name) -{ - free(req->dpipe_table_name); - req->_present.dpipe_table_name_len = strlen(dpipe_table_name); - req->dpipe_table_name = malloc(req->_present.dpipe_table_name_len + 1); - memcpy(req->dpipe_table_name, dpipe_table_name, req->_present.dpipe_table_name_len); - req->dpipe_table_name[req->_present.dpipe_table_name_len] = 0; -} - -struct devlink_dpipe_entries_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 dpipe_entries:1; - } _present; - - char *bus_name; - char *dev_name; - struct devlink_dl_dpipe_entries dpipe_entries; -}; - -void -devlink_dpipe_entries_get_rsp_free(struct devlink_dpipe_entries_get_rsp *rsp); - -/* - * Get dpipe entries attributes. - */ -struct devlink_dpipe_entries_get_rsp * -devlink_dpipe_entries_get(struct ynl_sock *ys, - struct devlink_dpipe_entries_get_req *req); - -/* ============== DEVLINK_CMD_DPIPE_HEADERS_GET ============== */ -/* DEVLINK_CMD_DPIPE_HEADERS_GET - do */ -struct devlink_dpipe_headers_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_dpipe_headers_get_req * -devlink_dpipe_headers_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_dpipe_headers_get_req)); -} -void -devlink_dpipe_headers_get_req_free(struct devlink_dpipe_headers_get_req *req); - -static inline void -devlink_dpipe_headers_get_req_set_bus_name(struct devlink_dpipe_headers_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_dpipe_headers_get_req_set_dev_name(struct devlink_dpipe_headers_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_dpipe_headers_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 dpipe_headers:1; - } _present; - - char *bus_name; - char *dev_name; - struct devlink_dl_dpipe_headers dpipe_headers; -}; - -void -devlink_dpipe_headers_get_rsp_free(struct devlink_dpipe_headers_get_rsp *rsp); - -/* - * Get dpipe headers attributes. - */ -struct devlink_dpipe_headers_get_rsp * -devlink_dpipe_headers_get(struct ynl_sock *ys, - struct devlink_dpipe_headers_get_req *req); - -/* ============== DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET ============== */ -/* DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET - do */ -struct devlink_dpipe_table_counters_set_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 dpipe_table_name_len; - __u32 dpipe_table_counters_enabled:1; - } _present; - - char *bus_name; - char *dev_name; - char *dpipe_table_name; - __u8 dpipe_table_counters_enabled; -}; - -static inline struct devlink_dpipe_table_counters_set_req * -devlink_dpipe_table_counters_set_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_dpipe_table_counters_set_req)); -} -void -devlink_dpipe_table_counters_set_req_free(struct devlink_dpipe_table_counters_set_req *req); - -static inline void -devlink_dpipe_table_counters_set_req_set_bus_name(struct devlink_dpipe_table_counters_set_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_dpipe_table_counters_set_req_set_dev_name(struct devlink_dpipe_table_counters_set_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_dpipe_table_counters_set_req_set_dpipe_table_name(struct devlink_dpipe_table_counters_set_req *req, - const char *dpipe_table_name) -{ - free(req->dpipe_table_name); - req->_present.dpipe_table_name_len = strlen(dpipe_table_name); - req->dpipe_table_name = malloc(req->_present.dpipe_table_name_len + 1); - memcpy(req->dpipe_table_name, dpipe_table_name, req->_present.dpipe_table_name_len); - req->dpipe_table_name[req->_present.dpipe_table_name_len] = 0; -} -static inline void -devlink_dpipe_table_counters_set_req_set_dpipe_table_counters_enabled(struct devlink_dpipe_table_counters_set_req *req, - __u8 dpipe_table_counters_enabled) -{ - req->_present.dpipe_table_counters_enabled = 1; - req->dpipe_table_counters_enabled = dpipe_table_counters_enabled; -} - -/* - * Set dpipe counter attributes. - */ -int devlink_dpipe_table_counters_set(struct ynl_sock *ys, - struct devlink_dpipe_table_counters_set_req *req); - -/* ============== DEVLINK_CMD_RESOURCE_SET ============== */ -/* DEVLINK_CMD_RESOURCE_SET - do */ -struct devlink_resource_set_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 resource_id:1; - __u32 resource_size:1; - } _present; - - char *bus_name; - char *dev_name; - __u64 resource_id; - __u64 resource_size; -}; - -static inline struct devlink_resource_set_req * -devlink_resource_set_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_resource_set_req)); -} -void devlink_resource_set_req_free(struct devlink_resource_set_req *req); - -static inline void -devlink_resource_set_req_set_bus_name(struct devlink_resource_set_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_resource_set_req_set_dev_name(struct devlink_resource_set_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_resource_set_req_set_resource_id(struct devlink_resource_set_req *req, - __u64 resource_id) -{ - req->_present.resource_id = 1; - req->resource_id = resource_id; -} -static inline void -devlink_resource_set_req_set_resource_size(struct devlink_resource_set_req *req, - __u64 resource_size) -{ - req->_present.resource_size = 1; - req->resource_size = resource_size; -} - -/* - * Set resource attributes. - */ -int devlink_resource_set(struct ynl_sock *ys, - struct devlink_resource_set_req *req); - -/* ============== DEVLINK_CMD_RESOURCE_DUMP ============== */ -/* DEVLINK_CMD_RESOURCE_DUMP - do */ -struct devlink_resource_dump_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_resource_dump_req * -devlink_resource_dump_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_resource_dump_req)); -} -void devlink_resource_dump_req_free(struct devlink_resource_dump_req *req); - -static inline void -devlink_resource_dump_req_set_bus_name(struct devlink_resource_dump_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_resource_dump_req_set_dev_name(struct devlink_resource_dump_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_resource_dump_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 resource_list:1; - } _present; - - char *bus_name; - char *dev_name; - struct devlink_dl_resource_list resource_list; -}; - -void devlink_resource_dump_rsp_free(struct devlink_resource_dump_rsp *rsp); - -/* - * Get resource attributes. - */ -struct devlink_resource_dump_rsp * -devlink_resource_dump(struct ynl_sock *ys, - struct devlink_resource_dump_req *req); - -/* ============== DEVLINK_CMD_RELOAD ============== */ -/* DEVLINK_CMD_RELOAD - do */ -struct devlink_reload_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 reload_action:1; - __u32 reload_limits:1; - __u32 netns_pid:1; - __u32 netns_fd:1; - __u32 netns_id:1; - } _present; - - char *bus_name; - char *dev_name; - enum devlink_reload_action reload_action; - struct nla_bitfield32 reload_limits; - __u32 netns_pid; - __u32 netns_fd; - __u32 netns_id; -}; - -static inline struct devlink_reload_req *devlink_reload_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_reload_req)); -} -void devlink_reload_req_free(struct devlink_reload_req *req); - -static inline void -devlink_reload_req_set_bus_name(struct devlink_reload_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_reload_req_set_dev_name(struct devlink_reload_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_reload_req_set_reload_action(struct devlink_reload_req *req, - enum devlink_reload_action reload_action) -{ - req->_present.reload_action = 1; - req->reload_action = reload_action; -} -static inline void -devlink_reload_req_set_reload_limits(struct devlink_reload_req *req, - struct nla_bitfield32 *reload_limits) -{ - req->_present.reload_limits = 1; - memcpy(&req->reload_limits, reload_limits, sizeof(struct nla_bitfield32)); -} -static inline void -devlink_reload_req_set_netns_pid(struct devlink_reload_req *req, - __u32 netns_pid) -{ - req->_present.netns_pid = 1; - req->netns_pid = netns_pid; -} -static inline void -devlink_reload_req_set_netns_fd(struct devlink_reload_req *req, __u32 netns_fd) -{ - req->_present.netns_fd = 1; - req->netns_fd = netns_fd; -} -static inline void -devlink_reload_req_set_netns_id(struct devlink_reload_req *req, __u32 netns_id) -{ - req->_present.netns_id = 1; - req->netns_id = netns_id; -} - -struct devlink_reload_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 reload_actions_performed:1; - } _present; - - char *bus_name; - char *dev_name; - struct nla_bitfield32 reload_actions_performed; -}; - -void devlink_reload_rsp_free(struct devlink_reload_rsp *rsp); - -/* - * Reload devlink. - */ -struct devlink_reload_rsp * -devlink_reload(struct ynl_sock *ys, struct devlink_reload_req *req); - -/* ============== DEVLINK_CMD_PARAM_GET ============== */ -/* DEVLINK_CMD_PARAM_GET - do */ -struct devlink_param_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 param_name_len; - } _present; - - char *bus_name; - char *dev_name; - char *param_name; -}; - -static inline struct devlink_param_get_req *devlink_param_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_param_get_req)); -} -void devlink_param_get_req_free(struct devlink_param_get_req *req); - -static inline void -devlink_param_get_req_set_bus_name(struct devlink_param_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_param_get_req_set_dev_name(struct devlink_param_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_param_get_req_set_param_name(struct devlink_param_get_req *req, - const char *param_name) -{ - free(req->param_name); - req->_present.param_name_len = strlen(param_name); - req->param_name = malloc(req->_present.param_name_len + 1); - memcpy(req->param_name, param_name, req->_present.param_name_len); - req->param_name[req->_present.param_name_len] = 0; -} - -struct devlink_param_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 param_name_len; - } _present; - - char *bus_name; - char *dev_name; - char *param_name; -}; - -void devlink_param_get_rsp_free(struct devlink_param_get_rsp *rsp); - -/* - * Get param instances. - */ -struct devlink_param_get_rsp * -devlink_param_get(struct ynl_sock *ys, struct devlink_param_get_req *req); - -/* DEVLINK_CMD_PARAM_GET - dump */ -struct devlink_param_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_param_get_req_dump * -devlink_param_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_param_get_req_dump)); -} -void devlink_param_get_req_dump_free(struct devlink_param_get_req_dump *req); - -static inline void -devlink_param_get_req_dump_set_bus_name(struct devlink_param_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_param_get_req_dump_set_dev_name(struct devlink_param_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_param_get_list { - struct devlink_param_get_list *next; - struct devlink_param_get_rsp obj __attribute__((aligned(8))); -}; - -void devlink_param_get_list_free(struct devlink_param_get_list *rsp); - -struct devlink_param_get_list * -devlink_param_get_dump(struct ynl_sock *ys, - struct devlink_param_get_req_dump *req); - -/* ============== DEVLINK_CMD_PARAM_SET ============== */ -/* DEVLINK_CMD_PARAM_SET - do */ -struct devlink_param_set_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 param_name_len; - __u32 param_type:1; - __u32 param_value_cmode:1; - } _present; - - char *bus_name; - char *dev_name; - char *param_name; - __u8 param_type; - enum devlink_param_cmode param_value_cmode; -}; - -static inline struct devlink_param_set_req *devlink_param_set_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_param_set_req)); -} -void devlink_param_set_req_free(struct devlink_param_set_req *req); - -static inline void -devlink_param_set_req_set_bus_name(struct devlink_param_set_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_param_set_req_set_dev_name(struct devlink_param_set_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_param_set_req_set_param_name(struct devlink_param_set_req *req, - const char *param_name) -{ - free(req->param_name); - req->_present.param_name_len = strlen(param_name); - req->param_name = malloc(req->_present.param_name_len + 1); - memcpy(req->param_name, param_name, req->_present.param_name_len); - req->param_name[req->_present.param_name_len] = 0; -} -static inline void -devlink_param_set_req_set_param_type(struct devlink_param_set_req *req, - __u8 param_type) -{ - req->_present.param_type = 1; - req->param_type = param_type; -} -static inline void -devlink_param_set_req_set_param_value_cmode(struct devlink_param_set_req *req, - enum devlink_param_cmode param_value_cmode) -{ - req->_present.param_value_cmode = 1; - req->param_value_cmode = param_value_cmode; -} - -/* - * Set param instances. - */ -int devlink_param_set(struct ynl_sock *ys, struct devlink_param_set_req *req); - -/* ============== DEVLINK_CMD_REGION_GET ============== */ -/* DEVLINK_CMD_REGION_GET - do */ -struct devlink_region_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 region_name_len; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *region_name; -}; - -static inline struct devlink_region_get_req *devlink_region_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_region_get_req)); -} -void devlink_region_get_req_free(struct devlink_region_get_req *req); - -static inline void -devlink_region_get_req_set_bus_name(struct devlink_region_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_region_get_req_set_dev_name(struct devlink_region_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_region_get_req_set_port_index(struct devlink_region_get_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_region_get_req_set_region_name(struct devlink_region_get_req *req, - const char *region_name) -{ - free(req->region_name); - req->_present.region_name_len = strlen(region_name); - req->region_name = malloc(req->_present.region_name_len + 1); - memcpy(req->region_name, region_name, req->_present.region_name_len); - req->region_name[req->_present.region_name_len] = 0; -} - -struct devlink_region_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 region_name_len; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *region_name; -}; - -void devlink_region_get_rsp_free(struct devlink_region_get_rsp *rsp); - -/* - * Get region instances. - */ -struct devlink_region_get_rsp * -devlink_region_get(struct ynl_sock *ys, struct devlink_region_get_req *req); - -/* DEVLINK_CMD_REGION_GET - dump */ -struct devlink_region_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_region_get_req_dump * -devlink_region_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_region_get_req_dump)); -} -void devlink_region_get_req_dump_free(struct devlink_region_get_req_dump *req); - -static inline void -devlink_region_get_req_dump_set_bus_name(struct devlink_region_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_region_get_req_dump_set_dev_name(struct devlink_region_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_region_get_list { - struct devlink_region_get_list *next; - struct devlink_region_get_rsp obj __attribute__((aligned(8))); -}; - -void devlink_region_get_list_free(struct devlink_region_get_list *rsp); - -struct devlink_region_get_list * -devlink_region_get_dump(struct ynl_sock *ys, - struct devlink_region_get_req_dump *req); - -/* ============== DEVLINK_CMD_REGION_NEW ============== */ -/* DEVLINK_CMD_REGION_NEW - do */ -struct devlink_region_new_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 region_name_len; - __u32 region_snapshot_id:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *region_name; - __u32 region_snapshot_id; -}; - -static inline struct devlink_region_new_req *devlink_region_new_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_region_new_req)); -} -void devlink_region_new_req_free(struct devlink_region_new_req *req); - -static inline void -devlink_region_new_req_set_bus_name(struct devlink_region_new_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_region_new_req_set_dev_name(struct devlink_region_new_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_region_new_req_set_port_index(struct devlink_region_new_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_region_new_req_set_region_name(struct devlink_region_new_req *req, - const char *region_name) -{ - free(req->region_name); - req->_present.region_name_len = strlen(region_name); - req->region_name = malloc(req->_present.region_name_len + 1); - memcpy(req->region_name, region_name, req->_present.region_name_len); - req->region_name[req->_present.region_name_len] = 0; -} -static inline void -devlink_region_new_req_set_region_snapshot_id(struct devlink_region_new_req *req, - __u32 region_snapshot_id) -{ - req->_present.region_snapshot_id = 1; - req->region_snapshot_id = region_snapshot_id; -} - -struct devlink_region_new_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 region_name_len; - __u32 region_snapshot_id:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *region_name; - __u32 region_snapshot_id; -}; - -void devlink_region_new_rsp_free(struct devlink_region_new_rsp *rsp); - -/* - * Create region snapshot. - */ -struct devlink_region_new_rsp * -devlink_region_new(struct ynl_sock *ys, struct devlink_region_new_req *req); - -/* ============== DEVLINK_CMD_REGION_DEL ============== */ -/* DEVLINK_CMD_REGION_DEL - do */ -struct devlink_region_del_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 region_name_len; - __u32 region_snapshot_id:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *region_name; - __u32 region_snapshot_id; -}; - -static inline struct devlink_region_del_req *devlink_region_del_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_region_del_req)); -} -void devlink_region_del_req_free(struct devlink_region_del_req *req); - -static inline void -devlink_region_del_req_set_bus_name(struct devlink_region_del_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_region_del_req_set_dev_name(struct devlink_region_del_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_region_del_req_set_port_index(struct devlink_region_del_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_region_del_req_set_region_name(struct devlink_region_del_req *req, - const char *region_name) -{ - free(req->region_name); - req->_present.region_name_len = strlen(region_name); - req->region_name = malloc(req->_present.region_name_len + 1); - memcpy(req->region_name, region_name, req->_present.region_name_len); - req->region_name[req->_present.region_name_len] = 0; -} -static inline void -devlink_region_del_req_set_region_snapshot_id(struct devlink_region_del_req *req, - __u32 region_snapshot_id) -{ - req->_present.region_snapshot_id = 1; - req->region_snapshot_id = region_snapshot_id; -} - -/* - * Delete region snapshot. - */ -int devlink_region_del(struct ynl_sock *ys, struct devlink_region_del_req *req); - -/* ============== DEVLINK_CMD_REGION_READ ============== */ -/* DEVLINK_CMD_REGION_READ - dump */ -struct devlink_region_read_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 region_name_len; - __u32 region_snapshot_id:1; - __u32 region_direct:1; - __u32 region_chunk_addr:1; - __u32 region_chunk_len:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *region_name; - __u32 region_snapshot_id; - __u64 region_chunk_addr; - __u64 region_chunk_len; -}; - -static inline struct devlink_region_read_req_dump * -devlink_region_read_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_region_read_req_dump)); -} -void -devlink_region_read_req_dump_free(struct devlink_region_read_req_dump *req); - -static inline void -devlink_region_read_req_dump_set_bus_name(struct devlink_region_read_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_region_read_req_dump_set_dev_name(struct devlink_region_read_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_region_read_req_dump_set_port_index(struct devlink_region_read_req_dump *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_region_read_req_dump_set_region_name(struct devlink_region_read_req_dump *req, - const char *region_name) -{ - free(req->region_name); - req->_present.region_name_len = strlen(region_name); - req->region_name = malloc(req->_present.region_name_len + 1); - memcpy(req->region_name, region_name, req->_present.region_name_len); - req->region_name[req->_present.region_name_len] = 0; -} -static inline void -devlink_region_read_req_dump_set_region_snapshot_id(struct devlink_region_read_req_dump *req, - __u32 region_snapshot_id) -{ - req->_present.region_snapshot_id = 1; - req->region_snapshot_id = region_snapshot_id; -} -static inline void -devlink_region_read_req_dump_set_region_direct(struct devlink_region_read_req_dump *req) -{ - req->_present.region_direct = 1; -} -static inline void -devlink_region_read_req_dump_set_region_chunk_addr(struct devlink_region_read_req_dump *req, - __u64 region_chunk_addr) -{ - req->_present.region_chunk_addr = 1; - req->region_chunk_addr = region_chunk_addr; -} -static inline void -devlink_region_read_req_dump_set_region_chunk_len(struct devlink_region_read_req_dump *req, - __u64 region_chunk_len) -{ - req->_present.region_chunk_len = 1; - req->region_chunk_len = region_chunk_len; -} - -struct devlink_region_read_rsp_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 region_name_len; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *region_name; -}; - -struct devlink_region_read_rsp_list { - struct devlink_region_read_rsp_list *next; - struct devlink_region_read_rsp_dump obj __attribute__((aligned(8))); -}; - -void -devlink_region_read_rsp_list_free(struct devlink_region_read_rsp_list *rsp); - -struct devlink_region_read_rsp_list * -devlink_region_read_dump(struct ynl_sock *ys, - struct devlink_region_read_req_dump *req); - -/* ============== DEVLINK_CMD_PORT_PARAM_GET ============== */ -/* DEVLINK_CMD_PORT_PARAM_GET - do */ -struct devlink_port_param_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; -}; - -static inline struct devlink_port_param_get_req * -devlink_port_param_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_port_param_get_req)); -} -void devlink_port_param_get_req_free(struct devlink_port_param_get_req *req); - -static inline void -devlink_port_param_get_req_set_bus_name(struct devlink_port_param_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_port_param_get_req_set_dev_name(struct devlink_port_param_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_port_param_get_req_set_port_index(struct devlink_port_param_get_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} - -struct devlink_port_param_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; -}; - -void devlink_port_param_get_rsp_free(struct devlink_port_param_get_rsp *rsp); - -/* - * Get port param instances. - */ -struct devlink_port_param_get_rsp * -devlink_port_param_get(struct ynl_sock *ys, - struct devlink_port_param_get_req *req); - -/* DEVLINK_CMD_PORT_PARAM_GET - dump */ -struct devlink_port_param_get_list { - struct devlink_port_param_get_list *next; - struct devlink_port_param_get_rsp obj __attribute__((aligned(8))); -}; - -void devlink_port_param_get_list_free(struct devlink_port_param_get_list *rsp); - -struct devlink_port_param_get_list * -devlink_port_param_get_dump(struct ynl_sock *ys); - -/* ============== DEVLINK_CMD_PORT_PARAM_SET ============== */ -/* DEVLINK_CMD_PORT_PARAM_SET - do */ -struct devlink_port_param_set_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; -}; - -static inline struct devlink_port_param_set_req * -devlink_port_param_set_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_port_param_set_req)); -} -void devlink_port_param_set_req_free(struct devlink_port_param_set_req *req); - -static inline void -devlink_port_param_set_req_set_bus_name(struct devlink_port_param_set_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_port_param_set_req_set_dev_name(struct devlink_port_param_set_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_port_param_set_req_set_port_index(struct devlink_port_param_set_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} - -/* - * Set port param instances. - */ -int devlink_port_param_set(struct ynl_sock *ys, - struct devlink_port_param_set_req *req); - -/* ============== DEVLINK_CMD_INFO_GET ============== */ -/* DEVLINK_CMD_INFO_GET - do */ -struct devlink_info_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_info_get_req *devlink_info_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_info_get_req)); -} -void devlink_info_get_req_free(struct devlink_info_get_req *req); - -static inline void -devlink_info_get_req_set_bus_name(struct devlink_info_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_info_get_req_set_dev_name(struct devlink_info_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_info_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 info_driver_name_len; - __u32 info_serial_number_len; - } _present; - - char *bus_name; - char *dev_name; - char *info_driver_name; - char *info_serial_number; - unsigned int n_info_version_fixed; - struct devlink_dl_info_version *info_version_fixed; - unsigned int n_info_version_running; - struct devlink_dl_info_version *info_version_running; - unsigned int n_info_version_stored; - struct devlink_dl_info_version *info_version_stored; -}; - -void devlink_info_get_rsp_free(struct devlink_info_get_rsp *rsp); - -/* - * Get device information, like driver name, hardware and firmware versions etc. - */ -struct devlink_info_get_rsp * -devlink_info_get(struct ynl_sock *ys, struct devlink_info_get_req *req); - -/* DEVLINK_CMD_INFO_GET - dump */ -struct devlink_info_get_list { - struct devlink_info_get_list *next; - struct devlink_info_get_rsp obj __attribute__((aligned(8))); -}; - -void devlink_info_get_list_free(struct devlink_info_get_list *rsp); - -struct devlink_info_get_list *devlink_info_get_dump(struct ynl_sock *ys); - -/* ============== DEVLINK_CMD_HEALTH_REPORTER_GET ============== */ -/* DEVLINK_CMD_HEALTH_REPORTER_GET - do */ -struct devlink_health_reporter_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 health_reporter_name_len; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *health_reporter_name; -}; - -static inline struct devlink_health_reporter_get_req * -devlink_health_reporter_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_health_reporter_get_req)); -} -void -devlink_health_reporter_get_req_free(struct devlink_health_reporter_get_req *req); - -static inline void -devlink_health_reporter_get_req_set_bus_name(struct devlink_health_reporter_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_health_reporter_get_req_set_dev_name(struct devlink_health_reporter_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_health_reporter_get_req_set_port_index(struct devlink_health_reporter_get_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_health_reporter_get_req_set_health_reporter_name(struct devlink_health_reporter_get_req *req, - const char *health_reporter_name) -{ - free(req->health_reporter_name); - req->_present.health_reporter_name_len = strlen(health_reporter_name); - req->health_reporter_name = malloc(req->_present.health_reporter_name_len + 1); - memcpy(req->health_reporter_name, health_reporter_name, req->_present.health_reporter_name_len); - req->health_reporter_name[req->_present.health_reporter_name_len] = 0; -} - -struct devlink_health_reporter_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 health_reporter_name_len; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *health_reporter_name; -}; - -void -devlink_health_reporter_get_rsp_free(struct devlink_health_reporter_get_rsp *rsp); - -/* - * Get health reporter instances. - */ -struct devlink_health_reporter_get_rsp * -devlink_health_reporter_get(struct ynl_sock *ys, - struct devlink_health_reporter_get_req *req); - -/* DEVLINK_CMD_HEALTH_REPORTER_GET - dump */ -struct devlink_health_reporter_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; -}; - -static inline struct devlink_health_reporter_get_req_dump * -devlink_health_reporter_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_health_reporter_get_req_dump)); -} -void -devlink_health_reporter_get_req_dump_free(struct devlink_health_reporter_get_req_dump *req); - -static inline void -devlink_health_reporter_get_req_dump_set_bus_name(struct devlink_health_reporter_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_health_reporter_get_req_dump_set_dev_name(struct devlink_health_reporter_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_health_reporter_get_req_dump_set_port_index(struct devlink_health_reporter_get_req_dump *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} - -struct devlink_health_reporter_get_list { - struct devlink_health_reporter_get_list *next; - struct devlink_health_reporter_get_rsp obj __attribute__((aligned(8))); -}; - -void -devlink_health_reporter_get_list_free(struct devlink_health_reporter_get_list *rsp); - -struct devlink_health_reporter_get_list * -devlink_health_reporter_get_dump(struct ynl_sock *ys, - struct devlink_health_reporter_get_req_dump *req); - -/* ============== DEVLINK_CMD_HEALTH_REPORTER_SET ============== */ -/* DEVLINK_CMD_HEALTH_REPORTER_SET - do */ -struct devlink_health_reporter_set_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 health_reporter_name_len; - __u32 health_reporter_graceful_period:1; - __u32 health_reporter_auto_recover:1; - __u32 health_reporter_auto_dump:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *health_reporter_name; - __u64 health_reporter_graceful_period; - __u8 health_reporter_auto_recover; - __u8 health_reporter_auto_dump; -}; - -static inline struct devlink_health_reporter_set_req * -devlink_health_reporter_set_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_health_reporter_set_req)); -} -void -devlink_health_reporter_set_req_free(struct devlink_health_reporter_set_req *req); - -static inline void -devlink_health_reporter_set_req_set_bus_name(struct devlink_health_reporter_set_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_health_reporter_set_req_set_dev_name(struct devlink_health_reporter_set_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_health_reporter_set_req_set_port_index(struct devlink_health_reporter_set_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_health_reporter_set_req_set_health_reporter_name(struct devlink_health_reporter_set_req *req, - const char *health_reporter_name) -{ - free(req->health_reporter_name); - req->_present.health_reporter_name_len = strlen(health_reporter_name); - req->health_reporter_name = malloc(req->_present.health_reporter_name_len + 1); - memcpy(req->health_reporter_name, health_reporter_name, req->_present.health_reporter_name_len); - req->health_reporter_name[req->_present.health_reporter_name_len] = 0; -} -static inline void -devlink_health_reporter_set_req_set_health_reporter_graceful_period(struct devlink_health_reporter_set_req *req, - __u64 health_reporter_graceful_period) -{ - req->_present.health_reporter_graceful_period = 1; - req->health_reporter_graceful_period = health_reporter_graceful_period; -} -static inline void -devlink_health_reporter_set_req_set_health_reporter_auto_recover(struct devlink_health_reporter_set_req *req, - __u8 health_reporter_auto_recover) -{ - req->_present.health_reporter_auto_recover = 1; - req->health_reporter_auto_recover = health_reporter_auto_recover; -} -static inline void -devlink_health_reporter_set_req_set_health_reporter_auto_dump(struct devlink_health_reporter_set_req *req, - __u8 health_reporter_auto_dump) -{ - req->_present.health_reporter_auto_dump = 1; - req->health_reporter_auto_dump = health_reporter_auto_dump; -} - -/* - * Set health reporter instances. - */ -int devlink_health_reporter_set(struct ynl_sock *ys, - struct devlink_health_reporter_set_req *req); - -/* ============== DEVLINK_CMD_HEALTH_REPORTER_RECOVER ============== */ -/* DEVLINK_CMD_HEALTH_REPORTER_RECOVER - do */ -struct devlink_health_reporter_recover_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 health_reporter_name_len; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *health_reporter_name; -}; - -static inline struct devlink_health_reporter_recover_req * -devlink_health_reporter_recover_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_health_reporter_recover_req)); -} -void -devlink_health_reporter_recover_req_free(struct devlink_health_reporter_recover_req *req); - -static inline void -devlink_health_reporter_recover_req_set_bus_name(struct devlink_health_reporter_recover_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_health_reporter_recover_req_set_dev_name(struct devlink_health_reporter_recover_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_health_reporter_recover_req_set_port_index(struct devlink_health_reporter_recover_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_health_reporter_recover_req_set_health_reporter_name(struct devlink_health_reporter_recover_req *req, - const char *health_reporter_name) -{ - free(req->health_reporter_name); - req->_present.health_reporter_name_len = strlen(health_reporter_name); - req->health_reporter_name = malloc(req->_present.health_reporter_name_len + 1); - memcpy(req->health_reporter_name, health_reporter_name, req->_present.health_reporter_name_len); - req->health_reporter_name[req->_present.health_reporter_name_len] = 0; -} - -/* - * Recover health reporter instances. - */ -int devlink_health_reporter_recover(struct ynl_sock *ys, - struct devlink_health_reporter_recover_req *req); - -/* ============== DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE ============== */ -/* DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE - do */ -struct devlink_health_reporter_diagnose_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 health_reporter_name_len; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *health_reporter_name; -}; - -static inline struct devlink_health_reporter_diagnose_req * -devlink_health_reporter_diagnose_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_health_reporter_diagnose_req)); -} -void -devlink_health_reporter_diagnose_req_free(struct devlink_health_reporter_diagnose_req *req); - -static inline void -devlink_health_reporter_diagnose_req_set_bus_name(struct devlink_health_reporter_diagnose_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_health_reporter_diagnose_req_set_dev_name(struct devlink_health_reporter_diagnose_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_health_reporter_diagnose_req_set_port_index(struct devlink_health_reporter_diagnose_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_health_reporter_diagnose_req_set_health_reporter_name(struct devlink_health_reporter_diagnose_req *req, - const char *health_reporter_name) -{ - free(req->health_reporter_name); - req->_present.health_reporter_name_len = strlen(health_reporter_name); - req->health_reporter_name = malloc(req->_present.health_reporter_name_len + 1); - memcpy(req->health_reporter_name, health_reporter_name, req->_present.health_reporter_name_len); - req->health_reporter_name[req->_present.health_reporter_name_len] = 0; -} - -/* - * Diagnose health reporter instances. - */ -int devlink_health_reporter_diagnose(struct ynl_sock *ys, - struct devlink_health_reporter_diagnose_req *req); - -/* ============== DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET ============== */ -/* DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET - dump */ -struct devlink_health_reporter_dump_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 health_reporter_name_len; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *health_reporter_name; -}; - -static inline struct devlink_health_reporter_dump_get_req_dump * -devlink_health_reporter_dump_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_health_reporter_dump_get_req_dump)); -} -void -devlink_health_reporter_dump_get_req_dump_free(struct devlink_health_reporter_dump_get_req_dump *req); - -static inline void -devlink_health_reporter_dump_get_req_dump_set_bus_name(struct devlink_health_reporter_dump_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_health_reporter_dump_get_req_dump_set_dev_name(struct devlink_health_reporter_dump_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_health_reporter_dump_get_req_dump_set_port_index(struct devlink_health_reporter_dump_get_req_dump *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_health_reporter_dump_get_req_dump_set_health_reporter_name(struct devlink_health_reporter_dump_get_req_dump *req, - const char *health_reporter_name) -{ - free(req->health_reporter_name); - req->_present.health_reporter_name_len = strlen(health_reporter_name); - req->health_reporter_name = malloc(req->_present.health_reporter_name_len + 1); - memcpy(req->health_reporter_name, health_reporter_name, req->_present.health_reporter_name_len); - req->health_reporter_name[req->_present.health_reporter_name_len] = 0; -} - -struct devlink_health_reporter_dump_get_rsp_dump { - struct { - __u32 fmsg:1; - } _present; - - struct devlink_dl_fmsg fmsg; -}; - -struct devlink_health_reporter_dump_get_rsp_list { - struct devlink_health_reporter_dump_get_rsp_list *next; - struct devlink_health_reporter_dump_get_rsp_dump obj __attribute__((aligned(8))); -}; - -void -devlink_health_reporter_dump_get_rsp_list_free(struct devlink_health_reporter_dump_get_rsp_list *rsp); - -struct devlink_health_reporter_dump_get_rsp_list * -devlink_health_reporter_dump_get_dump(struct ynl_sock *ys, - struct devlink_health_reporter_dump_get_req_dump *req); - -/* ============== DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR ============== */ -/* DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR - do */ -struct devlink_health_reporter_dump_clear_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 health_reporter_name_len; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *health_reporter_name; -}; - -static inline struct devlink_health_reporter_dump_clear_req * -devlink_health_reporter_dump_clear_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_health_reporter_dump_clear_req)); -} -void -devlink_health_reporter_dump_clear_req_free(struct devlink_health_reporter_dump_clear_req *req); - -static inline void -devlink_health_reporter_dump_clear_req_set_bus_name(struct devlink_health_reporter_dump_clear_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_health_reporter_dump_clear_req_set_dev_name(struct devlink_health_reporter_dump_clear_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_health_reporter_dump_clear_req_set_port_index(struct devlink_health_reporter_dump_clear_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_health_reporter_dump_clear_req_set_health_reporter_name(struct devlink_health_reporter_dump_clear_req *req, - const char *health_reporter_name) -{ - free(req->health_reporter_name); - req->_present.health_reporter_name_len = strlen(health_reporter_name); - req->health_reporter_name = malloc(req->_present.health_reporter_name_len + 1); - memcpy(req->health_reporter_name, health_reporter_name, req->_present.health_reporter_name_len); - req->health_reporter_name[req->_present.health_reporter_name_len] = 0; -} - -/* - * Clear dump of health reporter instances. - */ -int devlink_health_reporter_dump_clear(struct ynl_sock *ys, - struct devlink_health_reporter_dump_clear_req *req); - -/* ============== DEVLINK_CMD_FLASH_UPDATE ============== */ -/* DEVLINK_CMD_FLASH_UPDATE - do */ -struct devlink_flash_update_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 flash_update_file_name_len; - __u32 flash_update_component_len; - __u32 flash_update_overwrite_mask:1; - } _present; - - char *bus_name; - char *dev_name; - char *flash_update_file_name; - char *flash_update_component; - struct nla_bitfield32 flash_update_overwrite_mask; -}; - -static inline struct devlink_flash_update_req * -devlink_flash_update_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_flash_update_req)); -} -void devlink_flash_update_req_free(struct devlink_flash_update_req *req); - -static inline void -devlink_flash_update_req_set_bus_name(struct devlink_flash_update_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_flash_update_req_set_dev_name(struct devlink_flash_update_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_flash_update_req_set_flash_update_file_name(struct devlink_flash_update_req *req, - const char *flash_update_file_name) -{ - free(req->flash_update_file_name); - req->_present.flash_update_file_name_len = strlen(flash_update_file_name); - req->flash_update_file_name = malloc(req->_present.flash_update_file_name_len + 1); - memcpy(req->flash_update_file_name, flash_update_file_name, req->_present.flash_update_file_name_len); - req->flash_update_file_name[req->_present.flash_update_file_name_len] = 0; -} -static inline void -devlink_flash_update_req_set_flash_update_component(struct devlink_flash_update_req *req, - const char *flash_update_component) -{ - free(req->flash_update_component); - req->_present.flash_update_component_len = strlen(flash_update_component); - req->flash_update_component = malloc(req->_present.flash_update_component_len + 1); - memcpy(req->flash_update_component, flash_update_component, req->_present.flash_update_component_len); - req->flash_update_component[req->_present.flash_update_component_len] = 0; -} -static inline void -devlink_flash_update_req_set_flash_update_overwrite_mask(struct devlink_flash_update_req *req, - struct nla_bitfield32 *flash_update_overwrite_mask) -{ - req->_present.flash_update_overwrite_mask = 1; - memcpy(&req->flash_update_overwrite_mask, flash_update_overwrite_mask, sizeof(struct nla_bitfield32)); -} - -/* - * Flash update devlink instances. - */ -int devlink_flash_update(struct ynl_sock *ys, - struct devlink_flash_update_req *req); - -/* ============== DEVLINK_CMD_TRAP_GET ============== */ -/* DEVLINK_CMD_TRAP_GET - do */ -struct devlink_trap_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 trap_name_len; - } _present; - - char *bus_name; - char *dev_name; - char *trap_name; -}; - -static inline struct devlink_trap_get_req *devlink_trap_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_trap_get_req)); -} -void devlink_trap_get_req_free(struct devlink_trap_get_req *req); - -static inline void -devlink_trap_get_req_set_bus_name(struct devlink_trap_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_trap_get_req_set_dev_name(struct devlink_trap_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_trap_get_req_set_trap_name(struct devlink_trap_get_req *req, - const char *trap_name) -{ - free(req->trap_name); - req->_present.trap_name_len = strlen(trap_name); - req->trap_name = malloc(req->_present.trap_name_len + 1); - memcpy(req->trap_name, trap_name, req->_present.trap_name_len); - req->trap_name[req->_present.trap_name_len] = 0; -} - -struct devlink_trap_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 trap_name_len; - } _present; - - char *bus_name; - char *dev_name; - char *trap_name; -}; - -void devlink_trap_get_rsp_free(struct devlink_trap_get_rsp *rsp); - -/* - * Get trap instances. - */ -struct devlink_trap_get_rsp * -devlink_trap_get(struct ynl_sock *ys, struct devlink_trap_get_req *req); - -/* DEVLINK_CMD_TRAP_GET - dump */ -struct devlink_trap_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_trap_get_req_dump * -devlink_trap_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_trap_get_req_dump)); -} -void devlink_trap_get_req_dump_free(struct devlink_trap_get_req_dump *req); - -static inline void -devlink_trap_get_req_dump_set_bus_name(struct devlink_trap_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_trap_get_req_dump_set_dev_name(struct devlink_trap_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_trap_get_list { - struct devlink_trap_get_list *next; - struct devlink_trap_get_rsp obj __attribute__((aligned(8))); -}; - -void devlink_trap_get_list_free(struct devlink_trap_get_list *rsp); - -struct devlink_trap_get_list * -devlink_trap_get_dump(struct ynl_sock *ys, - struct devlink_trap_get_req_dump *req); - -/* ============== DEVLINK_CMD_TRAP_SET ============== */ -/* DEVLINK_CMD_TRAP_SET - do */ -struct devlink_trap_set_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 trap_name_len; - __u32 trap_action:1; - } _present; - - char *bus_name; - char *dev_name; - char *trap_name; - enum devlink_trap_action trap_action; -}; - -static inline struct devlink_trap_set_req *devlink_trap_set_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_trap_set_req)); -} -void devlink_trap_set_req_free(struct devlink_trap_set_req *req); - -static inline void -devlink_trap_set_req_set_bus_name(struct devlink_trap_set_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_trap_set_req_set_dev_name(struct devlink_trap_set_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_trap_set_req_set_trap_name(struct devlink_trap_set_req *req, - const char *trap_name) -{ - free(req->trap_name); - req->_present.trap_name_len = strlen(trap_name); - req->trap_name = malloc(req->_present.trap_name_len + 1); - memcpy(req->trap_name, trap_name, req->_present.trap_name_len); - req->trap_name[req->_present.trap_name_len] = 0; -} -static inline void -devlink_trap_set_req_set_trap_action(struct devlink_trap_set_req *req, - enum devlink_trap_action trap_action) -{ - req->_present.trap_action = 1; - req->trap_action = trap_action; -} - -/* - * Set trap instances. - */ -int devlink_trap_set(struct ynl_sock *ys, struct devlink_trap_set_req *req); - -/* ============== DEVLINK_CMD_TRAP_GROUP_GET ============== */ -/* DEVLINK_CMD_TRAP_GROUP_GET - do */ -struct devlink_trap_group_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 trap_group_name_len; - } _present; - - char *bus_name; - char *dev_name; - char *trap_group_name; -}; - -static inline struct devlink_trap_group_get_req * -devlink_trap_group_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_trap_group_get_req)); -} -void devlink_trap_group_get_req_free(struct devlink_trap_group_get_req *req); - -static inline void -devlink_trap_group_get_req_set_bus_name(struct devlink_trap_group_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_trap_group_get_req_set_dev_name(struct devlink_trap_group_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_trap_group_get_req_set_trap_group_name(struct devlink_trap_group_get_req *req, - const char *trap_group_name) -{ - free(req->trap_group_name); - req->_present.trap_group_name_len = strlen(trap_group_name); - req->trap_group_name = malloc(req->_present.trap_group_name_len + 1); - memcpy(req->trap_group_name, trap_group_name, req->_present.trap_group_name_len); - req->trap_group_name[req->_present.trap_group_name_len] = 0; -} - -struct devlink_trap_group_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 trap_group_name_len; - } _present; - - char *bus_name; - char *dev_name; - char *trap_group_name; -}; - -void devlink_trap_group_get_rsp_free(struct devlink_trap_group_get_rsp *rsp); - -/* - * Get trap group instances. - */ -struct devlink_trap_group_get_rsp * -devlink_trap_group_get(struct ynl_sock *ys, - struct devlink_trap_group_get_req *req); - -/* DEVLINK_CMD_TRAP_GROUP_GET - dump */ -struct devlink_trap_group_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_trap_group_get_req_dump * -devlink_trap_group_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_trap_group_get_req_dump)); -} -void -devlink_trap_group_get_req_dump_free(struct devlink_trap_group_get_req_dump *req); - -static inline void -devlink_trap_group_get_req_dump_set_bus_name(struct devlink_trap_group_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_trap_group_get_req_dump_set_dev_name(struct devlink_trap_group_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_trap_group_get_list { - struct devlink_trap_group_get_list *next; - struct devlink_trap_group_get_rsp obj __attribute__((aligned(8))); -}; - -void devlink_trap_group_get_list_free(struct devlink_trap_group_get_list *rsp); - -struct devlink_trap_group_get_list * -devlink_trap_group_get_dump(struct ynl_sock *ys, - struct devlink_trap_group_get_req_dump *req); - -/* ============== DEVLINK_CMD_TRAP_GROUP_SET ============== */ -/* DEVLINK_CMD_TRAP_GROUP_SET - do */ -struct devlink_trap_group_set_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 trap_group_name_len; - __u32 trap_action:1; - __u32 trap_policer_id:1; - } _present; - - char *bus_name; - char *dev_name; - char *trap_group_name; - enum devlink_trap_action trap_action; - __u32 trap_policer_id; -}; - -static inline struct devlink_trap_group_set_req * -devlink_trap_group_set_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_trap_group_set_req)); -} -void devlink_trap_group_set_req_free(struct devlink_trap_group_set_req *req); - -static inline void -devlink_trap_group_set_req_set_bus_name(struct devlink_trap_group_set_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_trap_group_set_req_set_dev_name(struct devlink_trap_group_set_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_trap_group_set_req_set_trap_group_name(struct devlink_trap_group_set_req *req, - const char *trap_group_name) -{ - free(req->trap_group_name); - req->_present.trap_group_name_len = strlen(trap_group_name); - req->trap_group_name = malloc(req->_present.trap_group_name_len + 1); - memcpy(req->trap_group_name, trap_group_name, req->_present.trap_group_name_len); - req->trap_group_name[req->_present.trap_group_name_len] = 0; -} -static inline void -devlink_trap_group_set_req_set_trap_action(struct devlink_trap_group_set_req *req, - enum devlink_trap_action trap_action) -{ - req->_present.trap_action = 1; - req->trap_action = trap_action; -} -static inline void -devlink_trap_group_set_req_set_trap_policer_id(struct devlink_trap_group_set_req *req, - __u32 trap_policer_id) -{ - req->_present.trap_policer_id = 1; - req->trap_policer_id = trap_policer_id; -} - -/* - * Set trap group instances. - */ -int devlink_trap_group_set(struct ynl_sock *ys, - struct devlink_trap_group_set_req *req); - -/* ============== DEVLINK_CMD_TRAP_POLICER_GET ============== */ -/* DEVLINK_CMD_TRAP_POLICER_GET - do */ -struct devlink_trap_policer_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 trap_policer_id:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 trap_policer_id; -}; - -static inline struct devlink_trap_policer_get_req * -devlink_trap_policer_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_trap_policer_get_req)); -} -void -devlink_trap_policer_get_req_free(struct devlink_trap_policer_get_req *req); - -static inline void -devlink_trap_policer_get_req_set_bus_name(struct devlink_trap_policer_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_trap_policer_get_req_set_dev_name(struct devlink_trap_policer_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_trap_policer_get_req_set_trap_policer_id(struct devlink_trap_policer_get_req *req, - __u32 trap_policer_id) -{ - req->_present.trap_policer_id = 1; - req->trap_policer_id = trap_policer_id; -} - -struct devlink_trap_policer_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 trap_policer_id:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 trap_policer_id; -}; - -void -devlink_trap_policer_get_rsp_free(struct devlink_trap_policer_get_rsp *rsp); - -/* - * Get trap policer instances. - */ -struct devlink_trap_policer_get_rsp * -devlink_trap_policer_get(struct ynl_sock *ys, - struct devlink_trap_policer_get_req *req); - -/* DEVLINK_CMD_TRAP_POLICER_GET - dump */ -struct devlink_trap_policer_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_trap_policer_get_req_dump * -devlink_trap_policer_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_trap_policer_get_req_dump)); -} -void -devlink_trap_policer_get_req_dump_free(struct devlink_trap_policer_get_req_dump *req); - -static inline void -devlink_trap_policer_get_req_dump_set_bus_name(struct devlink_trap_policer_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_trap_policer_get_req_dump_set_dev_name(struct devlink_trap_policer_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_trap_policer_get_list { - struct devlink_trap_policer_get_list *next; - struct devlink_trap_policer_get_rsp obj __attribute__((aligned(8))); -}; - -void -devlink_trap_policer_get_list_free(struct devlink_trap_policer_get_list *rsp); - -struct devlink_trap_policer_get_list * -devlink_trap_policer_get_dump(struct ynl_sock *ys, - struct devlink_trap_policer_get_req_dump *req); - -/* ============== DEVLINK_CMD_TRAP_POLICER_SET ============== */ -/* DEVLINK_CMD_TRAP_POLICER_SET - do */ -struct devlink_trap_policer_set_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 trap_policer_id:1; - __u32 trap_policer_rate:1; - __u32 trap_policer_burst:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 trap_policer_id; - __u64 trap_policer_rate; - __u64 trap_policer_burst; -}; - -static inline struct devlink_trap_policer_set_req * -devlink_trap_policer_set_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_trap_policer_set_req)); -} -void -devlink_trap_policer_set_req_free(struct devlink_trap_policer_set_req *req); - -static inline void -devlink_trap_policer_set_req_set_bus_name(struct devlink_trap_policer_set_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_trap_policer_set_req_set_dev_name(struct devlink_trap_policer_set_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_trap_policer_set_req_set_trap_policer_id(struct devlink_trap_policer_set_req *req, - __u32 trap_policer_id) -{ - req->_present.trap_policer_id = 1; - req->trap_policer_id = trap_policer_id; -} -static inline void -devlink_trap_policer_set_req_set_trap_policer_rate(struct devlink_trap_policer_set_req *req, - __u64 trap_policer_rate) -{ - req->_present.trap_policer_rate = 1; - req->trap_policer_rate = trap_policer_rate; -} -static inline void -devlink_trap_policer_set_req_set_trap_policer_burst(struct devlink_trap_policer_set_req *req, - __u64 trap_policer_burst) -{ - req->_present.trap_policer_burst = 1; - req->trap_policer_burst = trap_policer_burst; -} - -/* - * Get trap policer instances. - */ -int devlink_trap_policer_set(struct ynl_sock *ys, - struct devlink_trap_policer_set_req *req); - -/* ============== DEVLINK_CMD_HEALTH_REPORTER_TEST ============== */ -/* DEVLINK_CMD_HEALTH_REPORTER_TEST - do */ -struct devlink_health_reporter_test_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 health_reporter_name_len; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *health_reporter_name; -}; - -static inline struct devlink_health_reporter_test_req * -devlink_health_reporter_test_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_health_reporter_test_req)); -} -void -devlink_health_reporter_test_req_free(struct devlink_health_reporter_test_req *req); - -static inline void -devlink_health_reporter_test_req_set_bus_name(struct devlink_health_reporter_test_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_health_reporter_test_req_set_dev_name(struct devlink_health_reporter_test_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_health_reporter_test_req_set_port_index(struct devlink_health_reporter_test_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_health_reporter_test_req_set_health_reporter_name(struct devlink_health_reporter_test_req *req, - const char *health_reporter_name) -{ - free(req->health_reporter_name); - req->_present.health_reporter_name_len = strlen(health_reporter_name); - req->health_reporter_name = malloc(req->_present.health_reporter_name_len + 1); - memcpy(req->health_reporter_name, health_reporter_name, req->_present.health_reporter_name_len); - req->health_reporter_name[req->_present.health_reporter_name_len] = 0; -} - -/* - * Test health reporter instances. - */ -int devlink_health_reporter_test(struct ynl_sock *ys, - struct devlink_health_reporter_test_req *req); - -/* ============== DEVLINK_CMD_RATE_GET ============== */ -/* DEVLINK_CMD_RATE_GET - do */ -struct devlink_rate_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 rate_node_name_len; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *rate_node_name; -}; - -static inline struct devlink_rate_get_req *devlink_rate_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_rate_get_req)); -} -void devlink_rate_get_req_free(struct devlink_rate_get_req *req); - -static inline void -devlink_rate_get_req_set_bus_name(struct devlink_rate_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_rate_get_req_set_dev_name(struct devlink_rate_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_rate_get_req_set_port_index(struct devlink_rate_get_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_rate_get_req_set_rate_node_name(struct devlink_rate_get_req *req, - const char *rate_node_name) -{ - free(req->rate_node_name); - req->_present.rate_node_name_len = strlen(rate_node_name); - req->rate_node_name = malloc(req->_present.rate_node_name_len + 1); - memcpy(req->rate_node_name, rate_node_name, req->_present.rate_node_name_len); - req->rate_node_name[req->_present.rate_node_name_len] = 0; -} - -struct devlink_rate_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 rate_node_name_len; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *rate_node_name; -}; - -void devlink_rate_get_rsp_free(struct devlink_rate_get_rsp *rsp); - -/* - * Get rate instances. - */ -struct devlink_rate_get_rsp * -devlink_rate_get(struct ynl_sock *ys, struct devlink_rate_get_req *req); - -/* DEVLINK_CMD_RATE_GET - dump */ -struct devlink_rate_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_rate_get_req_dump * -devlink_rate_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_rate_get_req_dump)); -} -void devlink_rate_get_req_dump_free(struct devlink_rate_get_req_dump *req); - -static inline void -devlink_rate_get_req_dump_set_bus_name(struct devlink_rate_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_rate_get_req_dump_set_dev_name(struct devlink_rate_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_rate_get_list { - struct devlink_rate_get_list *next; - struct devlink_rate_get_rsp obj __attribute__((aligned(8))); -}; - -void devlink_rate_get_list_free(struct devlink_rate_get_list *rsp); - -struct devlink_rate_get_list * -devlink_rate_get_dump(struct ynl_sock *ys, - struct devlink_rate_get_req_dump *req); - -/* ============== DEVLINK_CMD_RATE_SET ============== */ -/* DEVLINK_CMD_RATE_SET - do */ -struct devlink_rate_set_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 rate_node_name_len; - __u32 rate_tx_share:1; - __u32 rate_tx_max:1; - __u32 rate_tx_priority:1; - __u32 rate_tx_weight:1; - __u32 rate_parent_node_name_len; - } _present; - - char *bus_name; - char *dev_name; - char *rate_node_name; - __u64 rate_tx_share; - __u64 rate_tx_max; - __u32 rate_tx_priority; - __u32 rate_tx_weight; - char *rate_parent_node_name; -}; - -static inline struct devlink_rate_set_req *devlink_rate_set_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_rate_set_req)); -} -void devlink_rate_set_req_free(struct devlink_rate_set_req *req); - -static inline void -devlink_rate_set_req_set_bus_name(struct devlink_rate_set_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_rate_set_req_set_dev_name(struct devlink_rate_set_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_rate_set_req_set_rate_node_name(struct devlink_rate_set_req *req, - const char *rate_node_name) -{ - free(req->rate_node_name); - req->_present.rate_node_name_len = strlen(rate_node_name); - req->rate_node_name = malloc(req->_present.rate_node_name_len + 1); - memcpy(req->rate_node_name, rate_node_name, req->_present.rate_node_name_len); - req->rate_node_name[req->_present.rate_node_name_len] = 0; -} -static inline void -devlink_rate_set_req_set_rate_tx_share(struct devlink_rate_set_req *req, - __u64 rate_tx_share) -{ - req->_present.rate_tx_share = 1; - req->rate_tx_share = rate_tx_share; -} -static inline void -devlink_rate_set_req_set_rate_tx_max(struct devlink_rate_set_req *req, - __u64 rate_tx_max) -{ - req->_present.rate_tx_max = 1; - req->rate_tx_max = rate_tx_max; -} -static inline void -devlink_rate_set_req_set_rate_tx_priority(struct devlink_rate_set_req *req, - __u32 rate_tx_priority) -{ - req->_present.rate_tx_priority = 1; - req->rate_tx_priority = rate_tx_priority; -} -static inline void -devlink_rate_set_req_set_rate_tx_weight(struct devlink_rate_set_req *req, - __u32 rate_tx_weight) -{ - req->_present.rate_tx_weight = 1; - req->rate_tx_weight = rate_tx_weight; -} -static inline void -devlink_rate_set_req_set_rate_parent_node_name(struct devlink_rate_set_req *req, - const char *rate_parent_node_name) -{ - free(req->rate_parent_node_name); - req->_present.rate_parent_node_name_len = strlen(rate_parent_node_name); - req->rate_parent_node_name = malloc(req->_present.rate_parent_node_name_len + 1); - memcpy(req->rate_parent_node_name, rate_parent_node_name, req->_present.rate_parent_node_name_len); - req->rate_parent_node_name[req->_present.rate_parent_node_name_len] = 0; -} - -/* - * Set rate instances. - */ -int devlink_rate_set(struct ynl_sock *ys, struct devlink_rate_set_req *req); - -/* ============== DEVLINK_CMD_RATE_NEW ============== */ -/* DEVLINK_CMD_RATE_NEW - do */ -struct devlink_rate_new_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 rate_node_name_len; - __u32 rate_tx_share:1; - __u32 rate_tx_max:1; - __u32 rate_tx_priority:1; - __u32 rate_tx_weight:1; - __u32 rate_parent_node_name_len; - } _present; - - char *bus_name; - char *dev_name; - char *rate_node_name; - __u64 rate_tx_share; - __u64 rate_tx_max; - __u32 rate_tx_priority; - __u32 rate_tx_weight; - char *rate_parent_node_name; -}; - -static inline struct devlink_rate_new_req *devlink_rate_new_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_rate_new_req)); -} -void devlink_rate_new_req_free(struct devlink_rate_new_req *req); - -static inline void -devlink_rate_new_req_set_bus_name(struct devlink_rate_new_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_rate_new_req_set_dev_name(struct devlink_rate_new_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_rate_new_req_set_rate_node_name(struct devlink_rate_new_req *req, - const char *rate_node_name) -{ - free(req->rate_node_name); - req->_present.rate_node_name_len = strlen(rate_node_name); - req->rate_node_name = malloc(req->_present.rate_node_name_len + 1); - memcpy(req->rate_node_name, rate_node_name, req->_present.rate_node_name_len); - req->rate_node_name[req->_present.rate_node_name_len] = 0; -} -static inline void -devlink_rate_new_req_set_rate_tx_share(struct devlink_rate_new_req *req, - __u64 rate_tx_share) -{ - req->_present.rate_tx_share = 1; - req->rate_tx_share = rate_tx_share; -} -static inline void -devlink_rate_new_req_set_rate_tx_max(struct devlink_rate_new_req *req, - __u64 rate_tx_max) -{ - req->_present.rate_tx_max = 1; - req->rate_tx_max = rate_tx_max; -} -static inline void -devlink_rate_new_req_set_rate_tx_priority(struct devlink_rate_new_req *req, - __u32 rate_tx_priority) -{ - req->_present.rate_tx_priority = 1; - req->rate_tx_priority = rate_tx_priority; -} -static inline void -devlink_rate_new_req_set_rate_tx_weight(struct devlink_rate_new_req *req, - __u32 rate_tx_weight) -{ - req->_present.rate_tx_weight = 1; - req->rate_tx_weight = rate_tx_weight; -} -static inline void -devlink_rate_new_req_set_rate_parent_node_name(struct devlink_rate_new_req *req, - const char *rate_parent_node_name) -{ - free(req->rate_parent_node_name); - req->_present.rate_parent_node_name_len = strlen(rate_parent_node_name); - req->rate_parent_node_name = malloc(req->_present.rate_parent_node_name_len + 1); - memcpy(req->rate_parent_node_name, rate_parent_node_name, req->_present.rate_parent_node_name_len); - req->rate_parent_node_name[req->_present.rate_parent_node_name_len] = 0; -} - -/* - * Create rate instances. - */ -int devlink_rate_new(struct ynl_sock *ys, struct devlink_rate_new_req *req); - -/* ============== DEVLINK_CMD_RATE_DEL ============== */ -/* DEVLINK_CMD_RATE_DEL - do */ -struct devlink_rate_del_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 rate_node_name_len; - } _present; - - char *bus_name; - char *dev_name; - char *rate_node_name; -}; - -static inline struct devlink_rate_del_req *devlink_rate_del_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_rate_del_req)); -} -void devlink_rate_del_req_free(struct devlink_rate_del_req *req); - -static inline void -devlink_rate_del_req_set_bus_name(struct devlink_rate_del_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_rate_del_req_set_dev_name(struct devlink_rate_del_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_rate_del_req_set_rate_node_name(struct devlink_rate_del_req *req, - const char *rate_node_name) -{ - free(req->rate_node_name); - req->_present.rate_node_name_len = strlen(rate_node_name); - req->rate_node_name = malloc(req->_present.rate_node_name_len + 1); - memcpy(req->rate_node_name, rate_node_name, req->_present.rate_node_name_len); - req->rate_node_name[req->_present.rate_node_name_len] = 0; -} - -/* - * Delete rate instances. - */ -int devlink_rate_del(struct ynl_sock *ys, struct devlink_rate_del_req *req); - -/* ============== DEVLINK_CMD_LINECARD_GET ============== */ -/* DEVLINK_CMD_LINECARD_GET - do */ -struct devlink_linecard_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 linecard_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 linecard_index; -}; - -static inline struct devlink_linecard_get_req * -devlink_linecard_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_linecard_get_req)); -} -void devlink_linecard_get_req_free(struct devlink_linecard_get_req *req); - -static inline void -devlink_linecard_get_req_set_bus_name(struct devlink_linecard_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_linecard_get_req_set_dev_name(struct devlink_linecard_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_linecard_get_req_set_linecard_index(struct devlink_linecard_get_req *req, - __u32 linecard_index) -{ - req->_present.linecard_index = 1; - req->linecard_index = linecard_index; -} - -struct devlink_linecard_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 linecard_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 linecard_index; -}; - -void devlink_linecard_get_rsp_free(struct devlink_linecard_get_rsp *rsp); - -/* - * Get line card instances. - */ -struct devlink_linecard_get_rsp * -devlink_linecard_get(struct ynl_sock *ys, struct devlink_linecard_get_req *req); - -/* DEVLINK_CMD_LINECARD_GET - dump */ -struct devlink_linecard_get_req_dump { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_linecard_get_req_dump * -devlink_linecard_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct devlink_linecard_get_req_dump)); -} -void -devlink_linecard_get_req_dump_free(struct devlink_linecard_get_req_dump *req); - -static inline void -devlink_linecard_get_req_dump_set_bus_name(struct devlink_linecard_get_req_dump *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_linecard_get_req_dump_set_dev_name(struct devlink_linecard_get_req_dump *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_linecard_get_list { - struct devlink_linecard_get_list *next; - struct devlink_linecard_get_rsp obj __attribute__((aligned(8))); -}; - -void devlink_linecard_get_list_free(struct devlink_linecard_get_list *rsp); - -struct devlink_linecard_get_list * -devlink_linecard_get_dump(struct ynl_sock *ys, - struct devlink_linecard_get_req_dump *req); - -/* ============== DEVLINK_CMD_LINECARD_SET ============== */ -/* DEVLINK_CMD_LINECARD_SET - do */ -struct devlink_linecard_set_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 linecard_index:1; - __u32 linecard_type_len; - } _present; - - char *bus_name; - char *dev_name; - __u32 linecard_index; - char *linecard_type; -}; - -static inline struct devlink_linecard_set_req * -devlink_linecard_set_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_linecard_set_req)); -} -void devlink_linecard_set_req_free(struct devlink_linecard_set_req *req); - -static inline void -devlink_linecard_set_req_set_bus_name(struct devlink_linecard_set_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_linecard_set_req_set_dev_name(struct devlink_linecard_set_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_linecard_set_req_set_linecard_index(struct devlink_linecard_set_req *req, - __u32 linecard_index) -{ - req->_present.linecard_index = 1; - req->linecard_index = linecard_index; -} -static inline void -devlink_linecard_set_req_set_linecard_type(struct devlink_linecard_set_req *req, - const char *linecard_type) -{ - free(req->linecard_type); - req->_present.linecard_type_len = strlen(linecard_type); - req->linecard_type = malloc(req->_present.linecard_type_len + 1); - memcpy(req->linecard_type, linecard_type, req->_present.linecard_type_len); - req->linecard_type[req->_present.linecard_type_len] = 0; -} - -/* - * Set line card instances. - */ -int devlink_linecard_set(struct ynl_sock *ys, - struct devlink_linecard_set_req *req); - -/* ============== DEVLINK_CMD_SELFTESTS_GET ============== */ -/* DEVLINK_CMD_SELFTESTS_GET - do */ -struct devlink_selftests_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -static inline struct devlink_selftests_get_req * -devlink_selftests_get_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_selftests_get_req)); -} -void devlink_selftests_get_req_free(struct devlink_selftests_get_req *req); - -static inline void -devlink_selftests_get_req_set_bus_name(struct devlink_selftests_get_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_selftests_get_req_set_dev_name(struct devlink_selftests_get_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} - -struct devlink_selftests_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - } _present; - - char *bus_name; - char *dev_name; -}; - -void devlink_selftests_get_rsp_free(struct devlink_selftests_get_rsp *rsp); - -/* - * Get device selftest instances. - */ -struct devlink_selftests_get_rsp * -devlink_selftests_get(struct ynl_sock *ys, - struct devlink_selftests_get_req *req); - -/* DEVLINK_CMD_SELFTESTS_GET - dump */ -struct devlink_selftests_get_list { - struct devlink_selftests_get_list *next; - struct devlink_selftests_get_rsp obj __attribute__((aligned(8))); -}; - -void devlink_selftests_get_list_free(struct devlink_selftests_get_list *rsp); - -struct devlink_selftests_get_list * -devlink_selftests_get_dump(struct ynl_sock *ys); - -/* ============== DEVLINK_CMD_SELFTESTS_RUN ============== */ -/* DEVLINK_CMD_SELFTESTS_RUN - do */ -struct devlink_selftests_run_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 selftests:1; - } _present; - - char *bus_name; - char *dev_name; - struct devlink_dl_selftest_id selftests; -}; - -static inline struct devlink_selftests_run_req * -devlink_selftests_run_req_alloc(void) -{ - return calloc(1, sizeof(struct devlink_selftests_run_req)); -} -void devlink_selftests_run_req_free(struct devlink_selftests_run_req *req); - -static inline void -devlink_selftests_run_req_set_bus_name(struct devlink_selftests_run_req *req, - const char *bus_name) -{ - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; -} -static inline void -devlink_selftests_run_req_set_dev_name(struct devlink_selftests_run_req *req, - const char *dev_name) -{ - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; -} -static inline void -devlink_selftests_run_req_set_selftests_flash(struct devlink_selftests_run_req *req) -{ - req->_present.selftests = 1; - req->selftests._present.flash = 1; -} - -/* - * Run device selftest instances. - */ -int devlink_selftests_run(struct ynl_sock *ys, - struct devlink_selftests_run_req *req); - -#endif /* _LINUX_DEVLINK_GEN_H */ diff --git a/tools/net/ynl/generated/ethtool-user.c b/tools/net/ynl/generated/ethtool-user.c deleted file mode 100644 index 660435639e..0000000000 --- a/tools/net/ynl/generated/ethtool-user.c +++ /dev/null @@ -1,6370 +0,0 @@ -// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/ethtool.yaml */ -/* YNL-GEN user source */ -/* YNL-ARG --user-header linux/ethtool_netlink.h --exclude-op stats-get */ - -#include -#include -#include "ethtool-user.h" -#include "ynl.h" -#include - -#include -#include - -#include "linux/ethtool_netlink.h" - -/* Enums */ -static const char * const ethtool_op_strmap[] = { - [ETHTOOL_MSG_STRSET_GET] = "strset-get", - [ETHTOOL_MSG_LINKINFO_GET] = "linkinfo-get", - [3] = "linkinfo-ntf", - [ETHTOOL_MSG_LINKMODES_GET] = "linkmodes-get", - [5] = "linkmodes-ntf", - [ETHTOOL_MSG_LINKSTATE_GET] = "linkstate-get", - [ETHTOOL_MSG_DEBUG_GET] = "debug-get", - [8] = "debug-ntf", - [ETHTOOL_MSG_WOL_GET] = "wol-get", - [10] = "wol-ntf", - [ETHTOOL_MSG_FEATURES_GET] = "features-get", - [ETHTOOL_MSG_FEATURES_SET] = "features-set", - [13] = "features-ntf", - [14] = "privflags-get", - [15] = "privflags-ntf", - [16] = "rings-get", - [17] = "rings-ntf", - [18] = "channels-get", - [19] = "channels-ntf", - [20] = "coalesce-get", - [21] = "coalesce-ntf", - [22] = "pause-get", - [23] = "pause-ntf", - [24] = "eee-get", - [25] = "eee-ntf", - [26] = "tsinfo-get", - [27] = "cable-test-ntf", - [28] = "cable-test-tdr-ntf", - [29] = "tunnel-info-get", - [30] = "fec-get", - [31] = "fec-ntf", - [32] = "module-eeprom-get", - [34] = "phc-vclocks-get", - [35] = "module-get", - [36] = "module-ntf", - [37] = "pse-get", - [ETHTOOL_MSG_RSS_GET] = "rss-get", - [ETHTOOL_MSG_PLCA_GET_CFG] = "plca-get-cfg", - [40] = "plca-get-status", - [41] = "plca-ntf", - [ETHTOOL_MSG_MM_GET] = "mm-get", - [43] = "mm-ntf", -}; - -const char *ethtool_op_str(int op) -{ - if (op < 0 || op >= (int)MNL_ARRAY_SIZE(ethtool_op_strmap)) - return NULL; - return ethtool_op_strmap[op]; -} - -static const char * const ethtool_udp_tunnel_type_strmap[] = { - [0] = "vxlan", - [1] = "geneve", - [2] = "vxlan-gpe", -}; - -const char *ethtool_udp_tunnel_type_str(int value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(ethtool_udp_tunnel_type_strmap)) - return NULL; - return ethtool_udp_tunnel_type_strmap[value]; -} - -static const char * const ethtool_stringset_strmap[] = { -}; - -const char *ethtool_stringset_str(enum ethtool_stringset value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(ethtool_stringset_strmap)) - return NULL; - return ethtool_stringset_strmap[value]; -} - -/* Policies */ -struct ynl_policy_attr ethtool_header_policy[ETHTOOL_A_HEADER_MAX + 1] = { - [ETHTOOL_A_HEADER_DEV_INDEX] = { .name = "dev-index", .type = YNL_PT_U32, }, - [ETHTOOL_A_HEADER_DEV_NAME] = { .name = "dev-name", .type = YNL_PT_NUL_STR, }, - [ETHTOOL_A_HEADER_FLAGS] = { .name = "flags", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_header_nest = { - .max_attr = ETHTOOL_A_HEADER_MAX, - .table = ethtool_header_policy, -}; - -struct ynl_policy_attr ethtool_pause_stat_policy[ETHTOOL_A_PAUSE_STAT_MAX + 1] = { - [ETHTOOL_A_PAUSE_STAT_PAD] = { .name = "pad", .type = YNL_PT_IGNORE, }, - [ETHTOOL_A_PAUSE_STAT_TX_FRAMES] = { .name = "tx-frames", .type = YNL_PT_U64, }, - [ETHTOOL_A_PAUSE_STAT_RX_FRAMES] = { .name = "rx-frames", .type = YNL_PT_U64, }, -}; - -struct ynl_policy_nest ethtool_pause_stat_nest = { - .max_attr = ETHTOOL_A_PAUSE_STAT_MAX, - .table = ethtool_pause_stat_policy, -}; - -struct ynl_policy_attr ethtool_cable_test_tdr_cfg_policy[ETHTOOL_A_CABLE_TEST_TDR_CFG_MAX + 1] = { - [ETHTOOL_A_CABLE_TEST_TDR_CFG_FIRST] = { .name = "first", .type = YNL_PT_U32, }, - [ETHTOOL_A_CABLE_TEST_TDR_CFG_LAST] = { .name = "last", .type = YNL_PT_U32, }, - [ETHTOOL_A_CABLE_TEST_TDR_CFG_STEP] = { .name = "step", .type = YNL_PT_U32, }, - [ETHTOOL_A_CABLE_TEST_TDR_CFG_PAIR] = { .name = "pair", .type = YNL_PT_U8, }, -}; - -struct ynl_policy_nest ethtool_cable_test_tdr_cfg_nest = { - .max_attr = ETHTOOL_A_CABLE_TEST_TDR_CFG_MAX, - .table = ethtool_cable_test_tdr_cfg_policy, -}; - -struct ynl_policy_attr ethtool_fec_stat_policy[ETHTOOL_A_FEC_STAT_MAX + 1] = { - [ETHTOOL_A_FEC_STAT_PAD] = { .name = "pad", .type = YNL_PT_IGNORE, }, - [ETHTOOL_A_FEC_STAT_CORRECTED] = { .name = "corrected", .type = YNL_PT_BINARY,}, - [ETHTOOL_A_FEC_STAT_UNCORR] = { .name = "uncorr", .type = YNL_PT_BINARY,}, - [ETHTOOL_A_FEC_STAT_CORR_BITS] = { .name = "corr-bits", .type = YNL_PT_BINARY,}, -}; - -struct ynl_policy_nest ethtool_fec_stat_nest = { - .max_attr = ETHTOOL_A_FEC_STAT_MAX, - .table = ethtool_fec_stat_policy, -}; - -struct ynl_policy_attr ethtool_mm_stat_policy[ETHTOOL_A_MM_STAT_MAX + 1] = { - [ETHTOOL_A_MM_STAT_PAD] = { .name = "pad", .type = YNL_PT_IGNORE, }, - [ETHTOOL_A_MM_STAT_REASSEMBLY_ERRORS] = { .name = "reassembly-errors", .type = YNL_PT_U64, }, - [ETHTOOL_A_MM_STAT_SMD_ERRORS] = { .name = "smd-errors", .type = YNL_PT_U64, }, - [ETHTOOL_A_MM_STAT_REASSEMBLY_OK] = { .name = "reassembly-ok", .type = YNL_PT_U64, }, - [ETHTOOL_A_MM_STAT_RX_FRAG_COUNT] = { .name = "rx-frag-count", .type = YNL_PT_U64, }, - [ETHTOOL_A_MM_STAT_TX_FRAG_COUNT] = { .name = "tx-frag-count", .type = YNL_PT_U64, }, - [ETHTOOL_A_MM_STAT_HOLD_COUNT] = { .name = "hold-count", .type = YNL_PT_U64, }, -}; - -struct ynl_policy_nest ethtool_mm_stat_nest = { - .max_attr = ETHTOOL_A_MM_STAT_MAX, - .table = ethtool_mm_stat_policy, -}; - -struct ynl_policy_attr ethtool_cable_result_policy[ETHTOOL_A_CABLE_RESULT_MAX + 1] = { - [ETHTOOL_A_CABLE_RESULT_PAIR] = { .name = "pair", .type = YNL_PT_U8, }, - [ETHTOOL_A_CABLE_RESULT_CODE] = { .name = "code", .type = YNL_PT_U8, }, -}; - -struct ynl_policy_nest ethtool_cable_result_nest = { - .max_attr = ETHTOOL_A_CABLE_RESULT_MAX, - .table = ethtool_cable_result_policy, -}; - -struct ynl_policy_attr ethtool_cable_fault_length_policy[ETHTOOL_A_CABLE_FAULT_LENGTH_MAX + 1] = { - [ETHTOOL_A_CABLE_FAULT_LENGTH_PAIR] = { .name = "pair", .type = YNL_PT_U8, }, - [ETHTOOL_A_CABLE_FAULT_LENGTH_CM] = { .name = "cm", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_cable_fault_length_nest = { - .max_attr = ETHTOOL_A_CABLE_FAULT_LENGTH_MAX, - .table = ethtool_cable_fault_length_policy, -}; - -struct ynl_policy_attr ethtool_bitset_bit_policy[ETHTOOL_A_BITSET_BIT_MAX + 1] = { - [ETHTOOL_A_BITSET_BIT_INDEX] = { .name = "index", .type = YNL_PT_U32, }, - [ETHTOOL_A_BITSET_BIT_NAME] = { .name = "name", .type = YNL_PT_NUL_STR, }, - [ETHTOOL_A_BITSET_BIT_VALUE] = { .name = "value", .type = YNL_PT_FLAG, }, -}; - -struct ynl_policy_nest ethtool_bitset_bit_nest = { - .max_attr = ETHTOOL_A_BITSET_BIT_MAX, - .table = ethtool_bitset_bit_policy, -}; - -struct ynl_policy_attr ethtool_tunnel_udp_entry_policy[ETHTOOL_A_TUNNEL_UDP_ENTRY_MAX + 1] = { - [ETHTOOL_A_TUNNEL_UDP_ENTRY_PORT] = { .name = "port", .type = YNL_PT_U16, }, - [ETHTOOL_A_TUNNEL_UDP_ENTRY_TYPE] = { .name = "type", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_tunnel_udp_entry_nest = { - .max_attr = ETHTOOL_A_TUNNEL_UDP_ENTRY_MAX, - .table = ethtool_tunnel_udp_entry_policy, -}; - -struct ynl_policy_attr ethtool_string_policy[ETHTOOL_A_STRING_MAX + 1] = { - [ETHTOOL_A_STRING_INDEX] = { .name = "index", .type = YNL_PT_U32, }, - [ETHTOOL_A_STRING_VALUE] = { .name = "value", .type = YNL_PT_NUL_STR, }, -}; - -struct ynl_policy_nest ethtool_string_nest = { - .max_attr = ETHTOOL_A_STRING_MAX, - .table = ethtool_string_policy, -}; - -struct ynl_policy_attr ethtool_cable_nest_policy[ETHTOOL_A_CABLE_NEST_MAX + 1] = { - [ETHTOOL_A_CABLE_NEST_RESULT] = { .name = "result", .type = YNL_PT_NEST, .nest = ðtool_cable_result_nest, }, - [ETHTOOL_A_CABLE_NEST_FAULT_LENGTH] = { .name = "fault-length", .type = YNL_PT_NEST, .nest = ðtool_cable_fault_length_nest, }, -}; - -struct ynl_policy_nest ethtool_cable_nest_nest = { - .max_attr = ETHTOOL_A_CABLE_NEST_MAX, - .table = ethtool_cable_nest_policy, -}; - -struct ynl_policy_attr ethtool_bitset_bits_policy[ETHTOOL_A_BITSET_BITS_MAX + 1] = { - [ETHTOOL_A_BITSET_BITS_BIT] = { .name = "bit", .type = YNL_PT_NEST, .nest = ðtool_bitset_bit_nest, }, -}; - -struct ynl_policy_nest ethtool_bitset_bits_nest = { - .max_attr = ETHTOOL_A_BITSET_BITS_MAX, - .table = ethtool_bitset_bits_policy, -}; - -struct ynl_policy_attr ethtool_strings_policy[ETHTOOL_A_STRINGS_MAX + 1] = { - [ETHTOOL_A_STRINGS_STRING] = { .name = "string", .type = YNL_PT_NEST, .nest = ðtool_string_nest, }, -}; - -struct ynl_policy_nest ethtool_strings_nest = { - .max_attr = ETHTOOL_A_STRINGS_MAX, - .table = ethtool_strings_policy, -}; - -struct ynl_policy_attr ethtool_bitset_policy[ETHTOOL_A_BITSET_MAX + 1] = { - [ETHTOOL_A_BITSET_NOMASK] = { .name = "nomask", .type = YNL_PT_FLAG, }, - [ETHTOOL_A_BITSET_SIZE] = { .name = "size", .type = YNL_PT_U32, }, - [ETHTOOL_A_BITSET_BITS] = { .name = "bits", .type = YNL_PT_NEST, .nest = ðtool_bitset_bits_nest, }, -}; - -struct ynl_policy_nest ethtool_bitset_nest = { - .max_attr = ETHTOOL_A_BITSET_MAX, - .table = ethtool_bitset_policy, -}; - -struct ynl_policy_attr ethtool_stringset_policy[ETHTOOL_A_STRINGSET_MAX + 1] = { - [ETHTOOL_A_STRINGSET_ID] = { .name = "id", .type = YNL_PT_U32, }, - [ETHTOOL_A_STRINGSET_COUNT] = { .name = "count", .type = YNL_PT_U32, }, - [ETHTOOL_A_STRINGSET_STRINGS] = { .name = "strings", .type = YNL_PT_NEST, .nest = ðtool_strings_nest, }, -}; - -struct ynl_policy_nest ethtool_stringset_nest = { - .max_attr = ETHTOOL_A_STRINGSET_MAX, - .table = ethtool_stringset_policy, -}; - -struct ynl_policy_attr ethtool_tunnel_udp_table_policy[ETHTOOL_A_TUNNEL_UDP_TABLE_MAX + 1] = { - [ETHTOOL_A_TUNNEL_UDP_TABLE_SIZE] = { .name = "size", .type = YNL_PT_U32, }, - [ETHTOOL_A_TUNNEL_UDP_TABLE_TYPES] = { .name = "types", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_TUNNEL_UDP_TABLE_ENTRY] = { .name = "entry", .type = YNL_PT_NEST, .nest = ðtool_tunnel_udp_entry_nest, }, -}; - -struct ynl_policy_nest ethtool_tunnel_udp_table_nest = { - .max_attr = ETHTOOL_A_TUNNEL_UDP_TABLE_MAX, - .table = ethtool_tunnel_udp_table_policy, -}; - -struct ynl_policy_attr ethtool_stringsets_policy[ETHTOOL_A_STRINGSETS_MAX + 1] = { - [ETHTOOL_A_STRINGSETS_STRINGSET] = { .name = "stringset", .type = YNL_PT_NEST, .nest = ðtool_stringset_nest, }, -}; - -struct ynl_policy_nest ethtool_stringsets_nest = { - .max_attr = ETHTOOL_A_STRINGSETS_MAX, - .table = ethtool_stringsets_policy, -}; - -struct ynl_policy_attr ethtool_tunnel_udp_policy[ETHTOOL_A_TUNNEL_UDP_MAX + 1] = { - [ETHTOOL_A_TUNNEL_UDP_TABLE] = { .name = "table", .type = YNL_PT_NEST, .nest = ðtool_tunnel_udp_table_nest, }, -}; - -struct ynl_policy_nest ethtool_tunnel_udp_nest = { - .max_attr = ETHTOOL_A_TUNNEL_UDP_MAX, - .table = ethtool_tunnel_udp_policy, -}; - -struct ynl_policy_attr ethtool_strset_policy[ETHTOOL_A_STRSET_MAX + 1] = { - [ETHTOOL_A_STRSET_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_STRSET_STRINGSETS] = { .name = "stringsets", .type = YNL_PT_NEST, .nest = ðtool_stringsets_nest, }, - [ETHTOOL_A_STRSET_COUNTS_ONLY] = { .name = "counts-only", .type = YNL_PT_FLAG, }, -}; - -struct ynl_policy_nest ethtool_strset_nest = { - .max_attr = ETHTOOL_A_STRSET_MAX, - .table = ethtool_strset_policy, -}; - -struct ynl_policy_attr ethtool_linkinfo_policy[ETHTOOL_A_LINKINFO_MAX + 1] = { - [ETHTOOL_A_LINKINFO_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_LINKINFO_PORT] = { .name = "port", .type = YNL_PT_U8, }, - [ETHTOOL_A_LINKINFO_PHYADDR] = { .name = "phyaddr", .type = YNL_PT_U8, }, - [ETHTOOL_A_LINKINFO_TP_MDIX] = { .name = "tp-mdix", .type = YNL_PT_U8, }, - [ETHTOOL_A_LINKINFO_TP_MDIX_CTRL] = { .name = "tp-mdix-ctrl", .type = YNL_PT_U8, }, - [ETHTOOL_A_LINKINFO_TRANSCEIVER] = { .name = "transceiver", .type = YNL_PT_U8, }, -}; - -struct ynl_policy_nest ethtool_linkinfo_nest = { - .max_attr = ETHTOOL_A_LINKINFO_MAX, - .table = ethtool_linkinfo_policy, -}; - -struct ynl_policy_attr ethtool_linkmodes_policy[ETHTOOL_A_LINKMODES_MAX + 1] = { - [ETHTOOL_A_LINKMODES_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_LINKMODES_AUTONEG] = { .name = "autoneg", .type = YNL_PT_U8, }, - [ETHTOOL_A_LINKMODES_OURS] = { .name = "ours", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_LINKMODES_PEER] = { .name = "peer", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_LINKMODES_SPEED] = { .name = "speed", .type = YNL_PT_U32, }, - [ETHTOOL_A_LINKMODES_DUPLEX] = { .name = "duplex", .type = YNL_PT_U8, }, - [ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG] = { .name = "master-slave-cfg", .type = YNL_PT_U8, }, - [ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE] = { .name = "master-slave-state", .type = YNL_PT_U8, }, - [ETHTOOL_A_LINKMODES_LANES] = { .name = "lanes", .type = YNL_PT_U32, }, - [ETHTOOL_A_LINKMODES_RATE_MATCHING] = { .name = "rate-matching", .type = YNL_PT_U8, }, -}; - -struct ynl_policy_nest ethtool_linkmodes_nest = { - .max_attr = ETHTOOL_A_LINKMODES_MAX, - .table = ethtool_linkmodes_policy, -}; - -struct ynl_policy_attr ethtool_linkstate_policy[ETHTOOL_A_LINKSTATE_MAX + 1] = { - [ETHTOOL_A_LINKSTATE_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_LINKSTATE_LINK] = { .name = "link", .type = YNL_PT_U8, }, - [ETHTOOL_A_LINKSTATE_SQI] = { .name = "sqi", .type = YNL_PT_U32, }, - [ETHTOOL_A_LINKSTATE_SQI_MAX] = { .name = "sqi-max", .type = YNL_PT_U32, }, - [ETHTOOL_A_LINKSTATE_EXT_STATE] = { .name = "ext-state", .type = YNL_PT_U8, }, - [ETHTOOL_A_LINKSTATE_EXT_SUBSTATE] = { .name = "ext-substate", .type = YNL_PT_U8, }, - [ETHTOOL_A_LINKSTATE_EXT_DOWN_CNT] = { .name = "ext-down-cnt", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_linkstate_nest = { - .max_attr = ETHTOOL_A_LINKSTATE_MAX, - .table = ethtool_linkstate_policy, -}; - -struct ynl_policy_attr ethtool_debug_policy[ETHTOOL_A_DEBUG_MAX + 1] = { - [ETHTOOL_A_DEBUG_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_DEBUG_MSGMASK] = { .name = "msgmask", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, -}; - -struct ynl_policy_nest ethtool_debug_nest = { - .max_attr = ETHTOOL_A_DEBUG_MAX, - .table = ethtool_debug_policy, -}; - -struct ynl_policy_attr ethtool_wol_policy[ETHTOOL_A_WOL_MAX + 1] = { - [ETHTOOL_A_WOL_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_WOL_MODES] = { .name = "modes", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_WOL_SOPASS] = { .name = "sopass", .type = YNL_PT_BINARY,}, -}; - -struct ynl_policy_nest ethtool_wol_nest = { - .max_attr = ETHTOOL_A_WOL_MAX, - .table = ethtool_wol_policy, -}; - -struct ynl_policy_attr ethtool_features_policy[ETHTOOL_A_FEATURES_MAX + 1] = { - [ETHTOOL_A_FEATURES_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_FEATURES_HW] = { .name = "hw", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_FEATURES_WANTED] = { .name = "wanted", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_FEATURES_ACTIVE] = { .name = "active", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_FEATURES_NOCHANGE] = { .name = "nochange", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, -}; - -struct ynl_policy_nest ethtool_features_nest = { - .max_attr = ETHTOOL_A_FEATURES_MAX, - .table = ethtool_features_policy, -}; - -struct ynl_policy_attr ethtool_privflags_policy[ETHTOOL_A_PRIVFLAGS_MAX + 1] = { - [ETHTOOL_A_PRIVFLAGS_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_PRIVFLAGS_FLAGS] = { .name = "flags", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, -}; - -struct ynl_policy_nest ethtool_privflags_nest = { - .max_attr = ETHTOOL_A_PRIVFLAGS_MAX, - .table = ethtool_privflags_policy, -}; - -struct ynl_policy_attr ethtool_rings_policy[ETHTOOL_A_RINGS_MAX + 1] = { - [ETHTOOL_A_RINGS_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_RINGS_RX_MAX] = { .name = "rx-max", .type = YNL_PT_U32, }, - [ETHTOOL_A_RINGS_RX_MINI_MAX] = { .name = "rx-mini-max", .type = YNL_PT_U32, }, - [ETHTOOL_A_RINGS_RX_JUMBO_MAX] = { .name = "rx-jumbo-max", .type = YNL_PT_U32, }, - [ETHTOOL_A_RINGS_TX_MAX] = { .name = "tx-max", .type = YNL_PT_U32, }, - [ETHTOOL_A_RINGS_RX] = { .name = "rx", .type = YNL_PT_U32, }, - [ETHTOOL_A_RINGS_RX_MINI] = { .name = "rx-mini", .type = YNL_PT_U32, }, - [ETHTOOL_A_RINGS_RX_JUMBO] = { .name = "rx-jumbo", .type = YNL_PT_U32, }, - [ETHTOOL_A_RINGS_TX] = { .name = "tx", .type = YNL_PT_U32, }, - [ETHTOOL_A_RINGS_RX_BUF_LEN] = { .name = "rx-buf-len", .type = YNL_PT_U32, }, - [ETHTOOL_A_RINGS_TCP_DATA_SPLIT] = { .name = "tcp-data-split", .type = YNL_PT_U8, }, - [ETHTOOL_A_RINGS_CQE_SIZE] = { .name = "cqe-size", .type = YNL_PT_U32, }, - [ETHTOOL_A_RINGS_TX_PUSH] = { .name = "tx-push", .type = YNL_PT_U8, }, - [ETHTOOL_A_RINGS_RX_PUSH] = { .name = "rx-push", .type = YNL_PT_U8, }, - [ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN] = { .name = "tx-push-buf-len", .type = YNL_PT_U32, }, - [ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN_MAX] = { .name = "tx-push-buf-len-max", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_rings_nest = { - .max_attr = ETHTOOL_A_RINGS_MAX, - .table = ethtool_rings_policy, -}; - -struct ynl_policy_attr ethtool_channels_policy[ETHTOOL_A_CHANNELS_MAX + 1] = { - [ETHTOOL_A_CHANNELS_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_CHANNELS_RX_MAX] = { .name = "rx-max", .type = YNL_PT_U32, }, - [ETHTOOL_A_CHANNELS_TX_MAX] = { .name = "tx-max", .type = YNL_PT_U32, }, - [ETHTOOL_A_CHANNELS_OTHER_MAX] = { .name = "other-max", .type = YNL_PT_U32, }, - [ETHTOOL_A_CHANNELS_COMBINED_MAX] = { .name = "combined-max", .type = YNL_PT_U32, }, - [ETHTOOL_A_CHANNELS_RX_COUNT] = { .name = "rx-count", .type = YNL_PT_U32, }, - [ETHTOOL_A_CHANNELS_TX_COUNT] = { .name = "tx-count", .type = YNL_PT_U32, }, - [ETHTOOL_A_CHANNELS_OTHER_COUNT] = { .name = "other-count", .type = YNL_PT_U32, }, - [ETHTOOL_A_CHANNELS_COMBINED_COUNT] = { .name = "combined-count", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_channels_nest = { - .max_attr = ETHTOOL_A_CHANNELS_MAX, - .table = ethtool_channels_policy, -}; - -struct ynl_policy_attr ethtool_coalesce_policy[ETHTOOL_A_COALESCE_MAX + 1] = { - [ETHTOOL_A_COALESCE_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_COALESCE_RX_USECS] = { .name = "rx-usecs", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_RX_MAX_FRAMES] = { .name = "rx-max-frames", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_RX_USECS_IRQ] = { .name = "rx-usecs-irq", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ] = { .name = "rx-max-frames-irq", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_TX_USECS] = { .name = "tx-usecs", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_TX_MAX_FRAMES] = { .name = "tx-max-frames", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_TX_USECS_IRQ] = { .name = "tx-usecs-irq", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ] = { .name = "tx-max-frames-irq", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_STATS_BLOCK_USECS] = { .name = "stats-block-usecs", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX] = { .name = "use-adaptive-rx", .type = YNL_PT_U8, }, - [ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX] = { .name = "use-adaptive-tx", .type = YNL_PT_U8, }, - [ETHTOOL_A_COALESCE_PKT_RATE_LOW] = { .name = "pkt-rate-low", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_RX_USECS_LOW] = { .name = "rx-usecs-low", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW] = { .name = "rx-max-frames-low", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_TX_USECS_LOW] = { .name = "tx-usecs-low", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW] = { .name = "tx-max-frames-low", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_PKT_RATE_HIGH] = { .name = "pkt-rate-high", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_RX_USECS_HIGH] = { .name = "rx-usecs-high", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH] = { .name = "rx-max-frames-high", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_TX_USECS_HIGH] = { .name = "tx-usecs-high", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH] = { .name = "tx-max-frames-high", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL] = { .name = "rate-sample-interval", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_USE_CQE_MODE_TX] = { .name = "use-cqe-mode-tx", .type = YNL_PT_U8, }, - [ETHTOOL_A_COALESCE_USE_CQE_MODE_RX] = { .name = "use-cqe-mode-rx", .type = YNL_PT_U8, }, - [ETHTOOL_A_COALESCE_TX_AGGR_MAX_BYTES] = { .name = "tx-aggr-max-bytes", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_TX_AGGR_MAX_FRAMES] = { .name = "tx-aggr-max-frames", .type = YNL_PT_U32, }, - [ETHTOOL_A_COALESCE_TX_AGGR_TIME_USECS] = { .name = "tx-aggr-time-usecs", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_coalesce_nest = { - .max_attr = ETHTOOL_A_COALESCE_MAX, - .table = ethtool_coalesce_policy, -}; - -struct ynl_policy_attr ethtool_pause_policy[ETHTOOL_A_PAUSE_MAX + 1] = { - [ETHTOOL_A_PAUSE_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_PAUSE_AUTONEG] = { .name = "autoneg", .type = YNL_PT_U8, }, - [ETHTOOL_A_PAUSE_RX] = { .name = "rx", .type = YNL_PT_U8, }, - [ETHTOOL_A_PAUSE_TX] = { .name = "tx", .type = YNL_PT_U8, }, - [ETHTOOL_A_PAUSE_STATS] = { .name = "stats", .type = YNL_PT_NEST, .nest = ðtool_pause_stat_nest, }, - [ETHTOOL_A_PAUSE_STATS_SRC] = { .name = "stats-src", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_pause_nest = { - .max_attr = ETHTOOL_A_PAUSE_MAX, - .table = ethtool_pause_policy, -}; - -struct ynl_policy_attr ethtool_eee_policy[ETHTOOL_A_EEE_MAX + 1] = { - [ETHTOOL_A_EEE_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_EEE_MODES_OURS] = { .name = "modes-ours", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_EEE_MODES_PEER] = { .name = "modes-peer", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_EEE_ACTIVE] = { .name = "active", .type = YNL_PT_U8, }, - [ETHTOOL_A_EEE_ENABLED] = { .name = "enabled", .type = YNL_PT_U8, }, - [ETHTOOL_A_EEE_TX_LPI_ENABLED] = { .name = "tx-lpi-enabled", .type = YNL_PT_U8, }, - [ETHTOOL_A_EEE_TX_LPI_TIMER] = { .name = "tx-lpi-timer", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_eee_nest = { - .max_attr = ETHTOOL_A_EEE_MAX, - .table = ethtool_eee_policy, -}; - -struct ynl_policy_attr ethtool_tsinfo_policy[ETHTOOL_A_TSINFO_MAX + 1] = { - [ETHTOOL_A_TSINFO_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_TSINFO_TIMESTAMPING] = { .name = "timestamping", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_TSINFO_TX_TYPES] = { .name = "tx-types", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_TSINFO_RX_FILTERS] = { .name = "rx-filters", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_TSINFO_PHC_INDEX] = { .name = "phc-index", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_tsinfo_nest = { - .max_attr = ETHTOOL_A_TSINFO_MAX, - .table = ethtool_tsinfo_policy, -}; - -struct ynl_policy_attr ethtool_cable_test_policy[ETHTOOL_A_CABLE_TEST_MAX + 1] = { - [ETHTOOL_A_CABLE_TEST_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, -}; - -struct ynl_policy_nest ethtool_cable_test_nest = { - .max_attr = ETHTOOL_A_CABLE_TEST_MAX, - .table = ethtool_cable_test_policy, -}; - -struct ynl_policy_attr ethtool_cable_test_ntf_policy[ETHTOOL_A_CABLE_TEST_NTF_MAX + 1] = { - [ETHTOOL_A_CABLE_TEST_NTF_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_CABLE_TEST_NTF_STATUS] = { .name = "status", .type = YNL_PT_U8, }, - [ETHTOOL_A_CABLE_TEST_NTF_NEST] = { .name = "nest", .type = YNL_PT_NEST, .nest = ðtool_cable_nest_nest, }, -}; - -struct ynl_policy_nest ethtool_cable_test_ntf_nest = { - .max_attr = ETHTOOL_A_CABLE_TEST_NTF_MAX, - .table = ethtool_cable_test_ntf_policy, -}; - -struct ynl_policy_attr ethtool_cable_test_tdr_policy[ETHTOOL_A_CABLE_TEST_TDR_MAX + 1] = { - [ETHTOOL_A_CABLE_TEST_TDR_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_CABLE_TEST_TDR_CFG] = { .name = "cfg", .type = YNL_PT_NEST, .nest = ðtool_cable_test_tdr_cfg_nest, }, -}; - -struct ynl_policy_nest ethtool_cable_test_tdr_nest = { - .max_attr = ETHTOOL_A_CABLE_TEST_TDR_MAX, - .table = ethtool_cable_test_tdr_policy, -}; - -struct ynl_policy_attr ethtool_cable_test_tdr_ntf_policy[ETHTOOL_A_CABLE_TEST_TDR_NTF_MAX + 1] = { - [ETHTOOL_A_CABLE_TEST_TDR_NTF_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_CABLE_TEST_TDR_NTF_STATUS] = { .name = "status", .type = YNL_PT_U8, }, - [ETHTOOL_A_CABLE_TEST_TDR_NTF_NEST] = { .name = "nest", .type = YNL_PT_NEST, .nest = ðtool_cable_nest_nest, }, -}; - -struct ynl_policy_nest ethtool_cable_test_tdr_ntf_nest = { - .max_attr = ETHTOOL_A_CABLE_TEST_TDR_NTF_MAX, - .table = ethtool_cable_test_tdr_ntf_policy, -}; - -struct ynl_policy_attr ethtool_tunnel_info_policy[ETHTOOL_A_TUNNEL_INFO_MAX + 1] = { - [ETHTOOL_A_TUNNEL_INFO_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_TUNNEL_INFO_UDP_PORTS] = { .name = "udp-ports", .type = YNL_PT_NEST, .nest = ðtool_tunnel_udp_nest, }, -}; - -struct ynl_policy_nest ethtool_tunnel_info_nest = { - .max_attr = ETHTOOL_A_TUNNEL_INFO_MAX, - .table = ethtool_tunnel_info_policy, -}; - -struct ynl_policy_attr ethtool_fec_policy[ETHTOOL_A_FEC_MAX + 1] = { - [ETHTOOL_A_FEC_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_FEC_MODES] = { .name = "modes", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, - [ETHTOOL_A_FEC_AUTO] = { .name = "auto", .type = YNL_PT_U8, }, - [ETHTOOL_A_FEC_ACTIVE] = { .name = "active", .type = YNL_PT_U32, }, - [ETHTOOL_A_FEC_STATS] = { .name = "stats", .type = YNL_PT_NEST, .nest = ðtool_fec_stat_nest, }, -}; - -struct ynl_policy_nest ethtool_fec_nest = { - .max_attr = ETHTOOL_A_FEC_MAX, - .table = ethtool_fec_policy, -}; - -struct ynl_policy_attr ethtool_module_eeprom_policy[ETHTOOL_A_MODULE_EEPROM_MAX + 1] = { - [ETHTOOL_A_MODULE_EEPROM_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_MODULE_EEPROM_OFFSET] = { .name = "offset", .type = YNL_PT_U32, }, - [ETHTOOL_A_MODULE_EEPROM_LENGTH] = { .name = "length", .type = YNL_PT_U32, }, - [ETHTOOL_A_MODULE_EEPROM_PAGE] = { .name = "page", .type = YNL_PT_U8, }, - [ETHTOOL_A_MODULE_EEPROM_BANK] = { .name = "bank", .type = YNL_PT_U8, }, - [ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS] = { .name = "i2c-address", .type = YNL_PT_U8, }, - [ETHTOOL_A_MODULE_EEPROM_DATA] = { .name = "data", .type = YNL_PT_BINARY,}, -}; - -struct ynl_policy_nest ethtool_module_eeprom_nest = { - .max_attr = ETHTOOL_A_MODULE_EEPROM_MAX, - .table = ethtool_module_eeprom_policy, -}; - -struct ynl_policy_attr ethtool_phc_vclocks_policy[ETHTOOL_A_PHC_VCLOCKS_MAX + 1] = { - [ETHTOOL_A_PHC_VCLOCKS_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_PHC_VCLOCKS_NUM] = { .name = "num", .type = YNL_PT_U32, }, - [ETHTOOL_A_PHC_VCLOCKS_INDEX] = { .name = "index", .type = YNL_PT_BINARY,}, -}; - -struct ynl_policy_nest ethtool_phc_vclocks_nest = { - .max_attr = ETHTOOL_A_PHC_VCLOCKS_MAX, - .table = ethtool_phc_vclocks_policy, -}; - -struct ynl_policy_attr ethtool_module_policy[ETHTOOL_A_MODULE_MAX + 1] = { - [ETHTOOL_A_MODULE_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_MODULE_POWER_MODE_POLICY] = { .name = "power-mode-policy", .type = YNL_PT_U8, }, - [ETHTOOL_A_MODULE_POWER_MODE] = { .name = "power-mode", .type = YNL_PT_U8, }, -}; - -struct ynl_policy_nest ethtool_module_nest = { - .max_attr = ETHTOOL_A_MODULE_MAX, - .table = ethtool_module_policy, -}; - -struct ynl_policy_attr ethtool_pse_policy[ETHTOOL_A_PSE_MAX + 1] = { - [ETHTOOL_A_PSE_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_PODL_PSE_ADMIN_STATE] = { .name = "admin-state", .type = YNL_PT_U32, }, - [ETHTOOL_A_PODL_PSE_ADMIN_CONTROL] = { .name = "admin-control", .type = YNL_PT_U32, }, - [ETHTOOL_A_PODL_PSE_PW_D_STATUS] = { .name = "pw-d-status", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_pse_nest = { - .max_attr = ETHTOOL_A_PSE_MAX, - .table = ethtool_pse_policy, -}; - -struct ynl_policy_attr ethtool_rss_policy[ETHTOOL_A_RSS_MAX + 1] = { - [ETHTOOL_A_RSS_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_RSS_CONTEXT] = { .name = "context", .type = YNL_PT_U32, }, - [ETHTOOL_A_RSS_HFUNC] = { .name = "hfunc", .type = YNL_PT_U32, }, - [ETHTOOL_A_RSS_INDIR] = { .name = "indir", .type = YNL_PT_BINARY,}, - [ETHTOOL_A_RSS_HKEY] = { .name = "hkey", .type = YNL_PT_BINARY,}, -}; - -struct ynl_policy_nest ethtool_rss_nest = { - .max_attr = ETHTOOL_A_RSS_MAX, - .table = ethtool_rss_policy, -}; - -struct ynl_policy_attr ethtool_plca_policy[ETHTOOL_A_PLCA_MAX + 1] = { - [ETHTOOL_A_PLCA_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_PLCA_VERSION] = { .name = "version", .type = YNL_PT_U16, }, - [ETHTOOL_A_PLCA_ENABLED] = { .name = "enabled", .type = YNL_PT_U8, }, - [ETHTOOL_A_PLCA_STATUS] = { .name = "status", .type = YNL_PT_U8, }, - [ETHTOOL_A_PLCA_NODE_CNT] = { .name = "node-cnt", .type = YNL_PT_U32, }, - [ETHTOOL_A_PLCA_NODE_ID] = { .name = "node-id", .type = YNL_PT_U32, }, - [ETHTOOL_A_PLCA_TO_TMR] = { .name = "to-tmr", .type = YNL_PT_U32, }, - [ETHTOOL_A_PLCA_BURST_CNT] = { .name = "burst-cnt", .type = YNL_PT_U32, }, - [ETHTOOL_A_PLCA_BURST_TMR] = { .name = "burst-tmr", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest ethtool_plca_nest = { - .max_attr = ETHTOOL_A_PLCA_MAX, - .table = ethtool_plca_policy, -}; - -struct ynl_policy_attr ethtool_mm_policy[ETHTOOL_A_MM_MAX + 1] = { - [ETHTOOL_A_MM_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, - [ETHTOOL_A_MM_PMAC_ENABLED] = { .name = "pmac-enabled", .type = YNL_PT_U8, }, - [ETHTOOL_A_MM_TX_ENABLED] = { .name = "tx-enabled", .type = YNL_PT_U8, }, - [ETHTOOL_A_MM_TX_ACTIVE] = { .name = "tx-active", .type = YNL_PT_U8, }, - [ETHTOOL_A_MM_TX_MIN_FRAG_SIZE] = { .name = "tx-min-frag-size", .type = YNL_PT_U32, }, - [ETHTOOL_A_MM_RX_MIN_FRAG_SIZE] = { .name = "rx-min-frag-size", .type = YNL_PT_U32, }, - [ETHTOOL_A_MM_VERIFY_ENABLED] = { .name = "verify-enabled", .type = YNL_PT_U8, }, - [ETHTOOL_A_MM_VERIFY_STATUS] = { .name = "verify-status", .type = YNL_PT_U8, }, - [ETHTOOL_A_MM_VERIFY_TIME] = { .name = "verify-time", .type = YNL_PT_U32, }, - [ETHTOOL_A_MM_MAX_VERIFY_TIME] = { .name = "max-verify-time", .type = YNL_PT_U32, }, - [ETHTOOL_A_MM_STATS] = { .name = "stats", .type = YNL_PT_NEST, .nest = ðtool_mm_stat_nest, }, -}; - -struct ynl_policy_nest ethtool_mm_nest = { - .max_attr = ETHTOOL_A_MM_MAX, - .table = ethtool_mm_policy, -}; - -/* Common nested types */ -void ethtool_header_free(struct ethtool_header *obj) -{ - free(obj->dev_name); -} - -int ethtool_header_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct ethtool_header *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - if (obj->_present.dev_index) - mnl_attr_put_u32(nlh, ETHTOOL_A_HEADER_DEV_INDEX, obj->dev_index); - if (obj->_present.dev_name_len) - mnl_attr_put_strz(nlh, ETHTOOL_A_HEADER_DEV_NAME, obj->dev_name); - if (obj->_present.flags) - mnl_attr_put_u32(nlh, ETHTOOL_A_HEADER_FLAGS, obj->flags); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -int ethtool_header_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_header *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_HEADER_DEV_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dev_index = 1; - dst->dev_index = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_HEADER_DEV_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.dev_name_len = len; - dst->dev_name = malloc(len + 1); - memcpy(dst->dev_name, mnl_attr_get_str(attr), len); - dst->dev_name[len] = 0; - } else if (type == ETHTOOL_A_HEADER_FLAGS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.flags = 1; - dst->flags = mnl_attr_get_u32(attr); - } - } - - return 0; -} - -void ethtool_pause_stat_free(struct ethtool_pause_stat *obj) -{ -} - -int ethtool_pause_stat_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct ethtool_pause_stat *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - if (obj->_present.tx_frames) - mnl_attr_put_u64(nlh, ETHTOOL_A_PAUSE_STAT_TX_FRAMES, obj->tx_frames); - if (obj->_present.rx_frames) - mnl_attr_put_u64(nlh, ETHTOOL_A_PAUSE_STAT_RX_FRAMES, obj->rx_frames); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -int ethtool_pause_stat_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_pause_stat *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_PAUSE_STAT_TX_FRAMES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_frames = 1; - dst->tx_frames = mnl_attr_get_u64(attr); - } else if (type == ETHTOOL_A_PAUSE_STAT_RX_FRAMES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_frames = 1; - dst->rx_frames = mnl_attr_get_u64(attr); - } - } - - return 0; -} - -void ethtool_cable_test_tdr_cfg_free(struct ethtool_cable_test_tdr_cfg *obj) -{ -} - -void ethtool_fec_stat_free(struct ethtool_fec_stat *obj) -{ - free(obj->corrected); - free(obj->uncorr); - free(obj->corr_bits); -} - -int ethtool_fec_stat_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct ethtool_fec_stat *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - if (obj->_present.corrected_len) - mnl_attr_put(nlh, ETHTOOL_A_FEC_STAT_CORRECTED, obj->_present.corrected_len, obj->corrected); - if (obj->_present.uncorr_len) - mnl_attr_put(nlh, ETHTOOL_A_FEC_STAT_UNCORR, obj->_present.uncorr_len, obj->uncorr); - if (obj->_present.corr_bits_len) - mnl_attr_put(nlh, ETHTOOL_A_FEC_STAT_CORR_BITS, obj->_present.corr_bits_len, obj->corr_bits); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -int ethtool_fec_stat_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_fec_stat *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_FEC_STAT_CORRECTED) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.corrected_len = len; - dst->corrected = malloc(len); - memcpy(dst->corrected, mnl_attr_get_payload(attr), len); - } else if (type == ETHTOOL_A_FEC_STAT_UNCORR) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.uncorr_len = len; - dst->uncorr = malloc(len); - memcpy(dst->uncorr, mnl_attr_get_payload(attr), len); - } else if (type == ETHTOOL_A_FEC_STAT_CORR_BITS) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.corr_bits_len = len; - dst->corr_bits = malloc(len); - memcpy(dst->corr_bits, mnl_attr_get_payload(attr), len); - } - } - - return 0; -} - -void ethtool_mm_stat_free(struct ethtool_mm_stat *obj) -{ -} - -int ethtool_mm_stat_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_mm_stat *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_MM_STAT_REASSEMBLY_ERRORS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.reassembly_errors = 1; - dst->reassembly_errors = mnl_attr_get_u64(attr); - } else if (type == ETHTOOL_A_MM_STAT_SMD_ERRORS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.smd_errors = 1; - dst->smd_errors = mnl_attr_get_u64(attr); - } else if (type == ETHTOOL_A_MM_STAT_REASSEMBLY_OK) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.reassembly_ok = 1; - dst->reassembly_ok = mnl_attr_get_u64(attr); - } else if (type == ETHTOOL_A_MM_STAT_RX_FRAG_COUNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_frag_count = 1; - dst->rx_frag_count = mnl_attr_get_u64(attr); - } else if (type == ETHTOOL_A_MM_STAT_TX_FRAG_COUNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_frag_count = 1; - dst->tx_frag_count = mnl_attr_get_u64(attr); - } else if (type == ETHTOOL_A_MM_STAT_HOLD_COUNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.hold_count = 1; - dst->hold_count = mnl_attr_get_u64(attr); - } - } - - return 0; -} - -void ethtool_cable_result_free(struct ethtool_cable_result *obj) -{ -} - -int ethtool_cable_result_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_cable_result *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_CABLE_RESULT_PAIR) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.pair = 1; - dst->pair = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_CABLE_RESULT_CODE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.code = 1; - dst->code = mnl_attr_get_u8(attr); - } - } - - return 0; -} - -void ethtool_cable_fault_length_free(struct ethtool_cable_fault_length *obj) -{ -} - -int ethtool_cable_fault_length_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_cable_fault_length *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_CABLE_FAULT_LENGTH_PAIR) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.pair = 1; - dst->pair = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_CABLE_FAULT_LENGTH_CM) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.cm = 1; - dst->cm = mnl_attr_get_u32(attr); - } - } - - return 0; -} - -void ethtool_bitset_bit_free(struct ethtool_bitset_bit *obj) -{ - free(obj->name); -} - -int ethtool_bitset_bit_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct ethtool_bitset_bit *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - if (obj->_present.index) - mnl_attr_put_u32(nlh, ETHTOOL_A_BITSET_BIT_INDEX, obj->index); - if (obj->_present.name_len) - mnl_attr_put_strz(nlh, ETHTOOL_A_BITSET_BIT_NAME, obj->name); - if (obj->_present.value) - mnl_attr_put(nlh, ETHTOOL_A_BITSET_BIT_VALUE, 0, NULL); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -int ethtool_bitset_bit_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_bitset_bit *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_BITSET_BIT_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.index = 1; - dst->index = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_BITSET_BIT_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.name_len = len; - dst->name = malloc(len + 1); - memcpy(dst->name, mnl_attr_get_str(attr), len); - dst->name[len] = 0; - } else if (type == ETHTOOL_A_BITSET_BIT_VALUE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.value = 1; - } - } - - return 0; -} - -void ethtool_tunnel_udp_entry_free(struct ethtool_tunnel_udp_entry *obj) -{ -} - -int ethtool_tunnel_udp_entry_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_tunnel_udp_entry *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_TUNNEL_UDP_ENTRY_PORT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port = 1; - dst->port = mnl_attr_get_u16(attr); - } else if (type == ETHTOOL_A_TUNNEL_UDP_ENTRY_TYPE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.type = 1; - dst->type = mnl_attr_get_u32(attr); - } - } - - return 0; -} - -void ethtool_string_free(struct ethtool_string *obj) -{ - free(obj->value); -} - -int ethtool_string_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct ethtool_string *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - if (obj->_present.index) - mnl_attr_put_u32(nlh, ETHTOOL_A_STRING_INDEX, obj->index); - if (obj->_present.value_len) - mnl_attr_put_strz(nlh, ETHTOOL_A_STRING_VALUE, obj->value); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -int ethtool_string_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_string *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_STRING_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.index = 1; - dst->index = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_STRING_VALUE) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.value_len = len; - dst->value = malloc(len + 1); - memcpy(dst->value, mnl_attr_get_str(attr), len); - dst->value[len] = 0; - } - } - - return 0; -} - -void ethtool_cable_nest_free(struct ethtool_cable_nest *obj) -{ - ethtool_cable_result_free(&obj->result); - ethtool_cable_fault_length_free(&obj->fault_length); -} - -int ethtool_cable_nest_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_cable_nest *dst = yarg->data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - parg.ys = yarg->ys; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_CABLE_NEST_RESULT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.result = 1; - - parg.rsp_policy = ðtool_cable_result_nest; - parg.data = &dst->result; - if (ethtool_cable_result_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_CABLE_NEST_FAULT_LENGTH) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.fault_length = 1; - - parg.rsp_policy = ðtool_cable_fault_length_nest; - parg.data = &dst->fault_length; - if (ethtool_cable_fault_length_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return 0; -} - -void ethtool_bitset_bits_free(struct ethtool_bitset_bits *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_bit; i++) - ethtool_bitset_bit_free(&obj->bit[i]); - free(obj->bit); -} - -int ethtool_bitset_bits_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct ethtool_bitset_bits *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - for (unsigned int i = 0; i < obj->n_bit; i++) - ethtool_bitset_bit_put(nlh, ETHTOOL_A_BITSET_BITS_BIT, &obj->bit[i]); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -int ethtool_bitset_bits_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_bitset_bits *dst = yarg->data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - unsigned int n_bit = 0; - int i; - - parg.ys = yarg->ys; - - if (dst->bit) - return ynl_error_parse(yarg, "attribute already present (bitset-bits.bit)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_BITSET_BITS_BIT) { - n_bit++; - } - } - - if (n_bit) { - dst->bit = calloc(n_bit, sizeof(*dst->bit)); - dst->n_bit = n_bit; - i = 0; - parg.rsp_policy = ðtool_bitset_bit_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == ETHTOOL_A_BITSET_BITS_BIT) { - parg.data = &dst->bit[i]; - if (ethtool_bitset_bit_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void ethtool_strings_free(struct ethtool_strings *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_string; i++) - ethtool_string_free(&obj->string[i]); - free(obj->string); -} - -int ethtool_strings_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct ethtool_strings *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - for (unsigned int i = 0; i < obj->n_string; i++) - ethtool_string_put(nlh, ETHTOOL_A_STRINGS_STRING, &obj->string[i]); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -int ethtool_strings_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_strings *dst = yarg->data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - unsigned int n_string = 0; - int i; - - parg.ys = yarg->ys; - - if (dst->string) - return ynl_error_parse(yarg, "attribute already present (strings.string)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_STRINGS_STRING) { - n_string++; - } - } - - if (n_string) { - dst->string = calloc(n_string, sizeof(*dst->string)); - dst->n_string = n_string; - i = 0; - parg.rsp_policy = ðtool_string_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == ETHTOOL_A_STRINGS_STRING) { - parg.data = &dst->string[i]; - if (ethtool_string_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void ethtool_bitset_free(struct ethtool_bitset *obj) -{ - ethtool_bitset_bits_free(&obj->bits); -} - -int ethtool_bitset_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct ethtool_bitset *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - if (obj->_present.nomask) - mnl_attr_put(nlh, ETHTOOL_A_BITSET_NOMASK, 0, NULL); - if (obj->_present.size) - mnl_attr_put_u32(nlh, ETHTOOL_A_BITSET_SIZE, obj->size); - if (obj->_present.bits) - ethtool_bitset_bits_put(nlh, ETHTOOL_A_BITSET_BITS, &obj->bits); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -int ethtool_bitset_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_bitset *dst = yarg->data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - parg.ys = yarg->ys; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_BITSET_NOMASK) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.nomask = 1; - } else if (type == ETHTOOL_A_BITSET_SIZE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.size = 1; - dst->size = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_BITSET_BITS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.bits = 1; - - parg.rsp_policy = ðtool_bitset_bits_nest; - parg.data = &dst->bits; - if (ethtool_bitset_bits_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return 0; -} - -void ethtool_stringset_free(struct ethtool_stringset_ *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_strings; i++) - ethtool_strings_free(&obj->strings[i]); - free(obj->strings); -} - -int ethtool_stringset_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct ethtool_stringset_ *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - if (obj->_present.id) - mnl_attr_put_u32(nlh, ETHTOOL_A_STRINGSET_ID, obj->id); - if (obj->_present.count) - mnl_attr_put_u32(nlh, ETHTOOL_A_STRINGSET_COUNT, obj->count); - for (unsigned int i = 0; i < obj->n_strings; i++) - ethtool_strings_put(nlh, ETHTOOL_A_STRINGSET_STRINGS, &obj->strings[i]); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -int ethtool_stringset_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_stringset_ *dst = yarg->data; - unsigned int n_strings = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->strings) - return ynl_error_parse(yarg, "attribute already present (stringset.strings)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_STRINGSET_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.id = 1; - dst->id = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_STRINGSET_COUNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.count = 1; - dst->count = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_STRINGSET_STRINGS) { - n_strings++; - } - } - - if (n_strings) { - dst->strings = calloc(n_strings, sizeof(*dst->strings)); - dst->n_strings = n_strings; - i = 0; - parg.rsp_policy = ðtool_strings_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == ETHTOOL_A_STRINGSET_STRINGS) { - parg.data = &dst->strings[i]; - if (ethtool_strings_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void ethtool_tunnel_udp_table_free(struct ethtool_tunnel_udp_table *obj) -{ - unsigned int i; - - ethtool_bitset_free(&obj->types); - for (i = 0; i < obj->n_entry; i++) - ethtool_tunnel_udp_entry_free(&obj->entry[i]); - free(obj->entry); -} - -int ethtool_tunnel_udp_table_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_tunnel_udp_table *dst = yarg->data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - unsigned int n_entry = 0; - int i; - - parg.ys = yarg->ys; - - if (dst->entry) - return ynl_error_parse(yarg, "attribute already present (tunnel-udp-table.entry)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_TUNNEL_UDP_TABLE_SIZE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.size = 1; - dst->size = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_TUNNEL_UDP_TABLE_TYPES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.types = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->types; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_TUNNEL_UDP_TABLE_ENTRY) { - n_entry++; - } - } - - if (n_entry) { - dst->entry = calloc(n_entry, sizeof(*dst->entry)); - dst->n_entry = n_entry; - i = 0; - parg.rsp_policy = ðtool_tunnel_udp_entry_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == ETHTOOL_A_TUNNEL_UDP_TABLE_ENTRY) { - parg.data = &dst->entry[i]; - if (ethtool_tunnel_udp_entry_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void ethtool_stringsets_free(struct ethtool_stringsets *obj) -{ - unsigned int i; - - for (i = 0; i < obj->n_stringset; i++) - ethtool_stringset_free(&obj->stringset[i]); - free(obj->stringset); -} - -int ethtool_stringsets_put(struct nlmsghdr *nlh, unsigned int attr_type, - struct ethtool_stringsets *obj) -{ - struct nlattr *nest; - - nest = mnl_attr_nest_start(nlh, attr_type); - for (unsigned int i = 0; i < obj->n_stringset; i++) - ethtool_stringset_put(nlh, ETHTOOL_A_STRINGSETS_STRINGSET, &obj->stringset[i]); - mnl_attr_nest_end(nlh, nest); - - return 0; -} - -int ethtool_stringsets_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_stringsets *dst = yarg->data; - unsigned int n_stringset = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->stringset) - return ynl_error_parse(yarg, "attribute already present (stringsets.stringset)"); - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_STRINGSETS_STRINGSET) { - n_stringset++; - } - } - - if (n_stringset) { - dst->stringset = calloc(n_stringset, sizeof(*dst->stringset)); - dst->n_stringset = n_stringset; - i = 0; - parg.rsp_policy = ðtool_stringset_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == ETHTOOL_A_STRINGSETS_STRINGSET) { - parg.data = &dst->stringset[i]; - if (ethtool_stringset_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - - return 0; -} - -void ethtool_tunnel_udp_free(struct ethtool_tunnel_udp *obj) -{ - ethtool_tunnel_udp_table_free(&obj->table); -} - -int ethtool_tunnel_udp_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct ethtool_tunnel_udp *dst = yarg->data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - parg.ys = yarg->ys; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_TUNNEL_UDP_TABLE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.table = 1; - - parg.rsp_policy = ðtool_tunnel_udp_table_nest; - parg.data = &dst->table; - if (ethtool_tunnel_udp_table_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return 0; -} - -/* ============== ETHTOOL_MSG_STRSET_GET ============== */ -/* ETHTOOL_MSG_STRSET_GET - do */ -void ethtool_strset_get_req_free(struct ethtool_strset_get_req *req) -{ - ethtool_header_free(&req->header); - ethtool_stringsets_free(&req->stringsets); - free(req); -} - -void ethtool_strset_get_rsp_free(struct ethtool_strset_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_stringsets_free(&rsp->stringsets); - free(rsp); -} - -int ethtool_strset_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_strset_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_STRSET_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_STRSET_STRINGSETS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.stringsets = 1; - - parg.rsp_policy = ðtool_stringsets_nest; - parg.data = &dst->stringsets; - if (ethtool_stringsets_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct ethtool_strset_get_rsp * -ethtool_strset_get(struct ynl_sock *ys, struct ethtool_strset_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_strset_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_STRSET_GET, 1); - ys->req_policy = ðtool_strset_nest; - yrs.yarg.rsp_policy = ðtool_strset_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_STRSET_HEADER, &req->header); - if (req->_present.stringsets) - ethtool_stringsets_put(nlh, ETHTOOL_A_STRSET_STRINGSETS, &req->stringsets); - if (req->_present.counts_only) - mnl_attr_put(nlh, ETHTOOL_A_STRSET_COUNTS_ONLY, 0, NULL); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_strset_get_rsp_parse; - yrs.rsp_cmd = ETHTOOL_MSG_STRSET_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_strset_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_STRSET_GET - dump */ -void ethtool_strset_get_list_free(struct ethtool_strset_get_list *rsp) -{ - struct ethtool_strset_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_stringsets_free(&rsp->obj.stringsets); - free(rsp); - } -} - -struct ethtool_strset_get_list * -ethtool_strset_get_dump(struct ynl_sock *ys, - struct ethtool_strset_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_strset_get_list); - yds.cb = ethtool_strset_get_rsp_parse; - yds.rsp_cmd = ETHTOOL_MSG_STRSET_GET; - yds.rsp_policy = ðtool_strset_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_STRSET_GET, 1); - ys->req_policy = ðtool_strset_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_STRSET_HEADER, &req->header); - if (req->_present.stringsets) - ethtool_stringsets_put(nlh, ETHTOOL_A_STRSET_STRINGSETS, &req->stringsets); - if (req->_present.counts_only) - mnl_attr_put(nlh, ETHTOOL_A_STRSET_COUNTS_ONLY, 0, NULL); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_strset_get_list_free(yds.first); - return NULL; -} - -/* ============== ETHTOOL_MSG_LINKINFO_GET ============== */ -/* ETHTOOL_MSG_LINKINFO_GET - do */ -void ethtool_linkinfo_get_req_free(struct ethtool_linkinfo_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_linkinfo_get_rsp_free(struct ethtool_linkinfo_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp); -} - -int ethtool_linkinfo_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_linkinfo_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_LINKINFO_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_LINKINFO_PORT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port = 1; - dst->port = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_LINKINFO_PHYADDR) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.phyaddr = 1; - dst->phyaddr = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_LINKINFO_TP_MDIX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tp_mdix = 1; - dst->tp_mdix = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_LINKINFO_TP_MDIX_CTRL) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tp_mdix_ctrl = 1; - dst->tp_mdix_ctrl = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_LINKINFO_TRANSCEIVER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.transceiver = 1; - dst->transceiver = mnl_attr_get_u8(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_linkinfo_get_rsp * -ethtool_linkinfo_get(struct ynl_sock *ys, struct ethtool_linkinfo_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_linkinfo_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_LINKINFO_GET, 1); - ys->req_policy = ðtool_linkinfo_nest; - yrs.yarg.rsp_policy = ðtool_linkinfo_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_LINKINFO_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_linkinfo_get_rsp_parse; - yrs.rsp_cmd = ETHTOOL_MSG_LINKINFO_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_linkinfo_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_LINKINFO_GET - dump */ -void ethtool_linkinfo_get_list_free(struct ethtool_linkinfo_get_list *rsp) -{ - struct ethtool_linkinfo_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp); - } -} - -struct ethtool_linkinfo_get_list * -ethtool_linkinfo_get_dump(struct ynl_sock *ys, - struct ethtool_linkinfo_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_linkinfo_get_list); - yds.cb = ethtool_linkinfo_get_rsp_parse; - yds.rsp_cmd = ETHTOOL_MSG_LINKINFO_GET; - yds.rsp_policy = ðtool_linkinfo_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_LINKINFO_GET, 1); - ys->req_policy = ðtool_linkinfo_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_LINKINFO_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_linkinfo_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_LINKINFO_GET - notify */ -void ethtool_linkinfo_get_ntf_free(struct ethtool_linkinfo_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - free(rsp); -} - -/* ============== ETHTOOL_MSG_LINKINFO_SET ============== */ -/* ETHTOOL_MSG_LINKINFO_SET - do */ -void ethtool_linkinfo_set_req_free(struct ethtool_linkinfo_set_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -int ethtool_linkinfo_set(struct ynl_sock *ys, - struct ethtool_linkinfo_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_LINKINFO_SET, 1); - ys->req_policy = ðtool_linkinfo_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_LINKINFO_HEADER, &req->header); - if (req->_present.port) - mnl_attr_put_u8(nlh, ETHTOOL_A_LINKINFO_PORT, req->port); - if (req->_present.phyaddr) - mnl_attr_put_u8(nlh, ETHTOOL_A_LINKINFO_PHYADDR, req->phyaddr); - if (req->_present.tp_mdix) - mnl_attr_put_u8(nlh, ETHTOOL_A_LINKINFO_TP_MDIX, req->tp_mdix); - if (req->_present.tp_mdix_ctrl) - mnl_attr_put_u8(nlh, ETHTOOL_A_LINKINFO_TP_MDIX_CTRL, req->tp_mdix_ctrl); - if (req->_present.transceiver) - mnl_attr_put_u8(nlh, ETHTOOL_A_LINKINFO_TRANSCEIVER, req->transceiver); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_LINKMODES_GET ============== */ -/* ETHTOOL_MSG_LINKMODES_GET - do */ -void ethtool_linkmodes_get_req_free(struct ethtool_linkmodes_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_linkmodes_get_rsp_free(struct ethtool_linkmodes_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_bitset_free(&rsp->ours); - ethtool_bitset_free(&rsp->peer); - free(rsp); -} - -int ethtool_linkmodes_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_linkmodes_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_LINKMODES_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_LINKMODES_AUTONEG) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.autoneg = 1; - dst->autoneg = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_LINKMODES_OURS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.ours = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->ours; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_LINKMODES_PEER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.peer = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->peer; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_LINKMODES_SPEED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.speed = 1; - dst->speed = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_LINKMODES_DUPLEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.duplex = 1; - dst->duplex = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.master_slave_cfg = 1; - dst->master_slave_cfg = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.master_slave_state = 1; - dst->master_slave_state = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_LINKMODES_LANES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.lanes = 1; - dst->lanes = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_LINKMODES_RATE_MATCHING) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rate_matching = 1; - dst->rate_matching = mnl_attr_get_u8(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_linkmodes_get_rsp * -ethtool_linkmodes_get(struct ynl_sock *ys, - struct ethtool_linkmodes_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_linkmodes_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_LINKMODES_GET, 1); - ys->req_policy = ðtool_linkmodes_nest; - yrs.yarg.rsp_policy = ðtool_linkmodes_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_LINKMODES_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_linkmodes_get_rsp_parse; - yrs.rsp_cmd = ETHTOOL_MSG_LINKMODES_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_linkmodes_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_LINKMODES_GET - dump */ -void ethtool_linkmodes_get_list_free(struct ethtool_linkmodes_get_list *rsp) -{ - struct ethtool_linkmodes_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.ours); - ethtool_bitset_free(&rsp->obj.peer); - free(rsp); - } -} - -struct ethtool_linkmodes_get_list * -ethtool_linkmodes_get_dump(struct ynl_sock *ys, - struct ethtool_linkmodes_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_linkmodes_get_list); - yds.cb = ethtool_linkmodes_get_rsp_parse; - yds.rsp_cmd = ETHTOOL_MSG_LINKMODES_GET; - yds.rsp_policy = ðtool_linkmodes_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_LINKMODES_GET, 1); - ys->req_policy = ðtool_linkmodes_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_LINKMODES_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_linkmodes_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_LINKMODES_GET - notify */ -void ethtool_linkmodes_get_ntf_free(struct ethtool_linkmodes_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.ours); - ethtool_bitset_free(&rsp->obj.peer); - free(rsp); -} - -/* ============== ETHTOOL_MSG_LINKMODES_SET ============== */ -/* ETHTOOL_MSG_LINKMODES_SET - do */ -void ethtool_linkmodes_set_req_free(struct ethtool_linkmodes_set_req *req) -{ - ethtool_header_free(&req->header); - ethtool_bitset_free(&req->ours); - ethtool_bitset_free(&req->peer); - free(req); -} - -int ethtool_linkmodes_set(struct ynl_sock *ys, - struct ethtool_linkmodes_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_LINKMODES_SET, 1); - ys->req_policy = ðtool_linkmodes_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_LINKMODES_HEADER, &req->header); - if (req->_present.autoneg) - mnl_attr_put_u8(nlh, ETHTOOL_A_LINKMODES_AUTONEG, req->autoneg); - if (req->_present.ours) - ethtool_bitset_put(nlh, ETHTOOL_A_LINKMODES_OURS, &req->ours); - if (req->_present.peer) - ethtool_bitset_put(nlh, ETHTOOL_A_LINKMODES_PEER, &req->peer); - if (req->_present.speed) - mnl_attr_put_u32(nlh, ETHTOOL_A_LINKMODES_SPEED, req->speed); - if (req->_present.duplex) - mnl_attr_put_u8(nlh, ETHTOOL_A_LINKMODES_DUPLEX, req->duplex); - if (req->_present.master_slave_cfg) - mnl_attr_put_u8(nlh, ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG, req->master_slave_cfg); - if (req->_present.master_slave_state) - mnl_attr_put_u8(nlh, ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE, req->master_slave_state); - if (req->_present.lanes) - mnl_attr_put_u32(nlh, ETHTOOL_A_LINKMODES_LANES, req->lanes); - if (req->_present.rate_matching) - mnl_attr_put_u8(nlh, ETHTOOL_A_LINKMODES_RATE_MATCHING, req->rate_matching); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_LINKSTATE_GET ============== */ -/* ETHTOOL_MSG_LINKSTATE_GET - do */ -void ethtool_linkstate_get_req_free(struct ethtool_linkstate_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_linkstate_get_rsp_free(struct ethtool_linkstate_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp); -} - -int ethtool_linkstate_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_linkstate_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_LINKSTATE_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_LINKSTATE_LINK) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.link = 1; - dst->link = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_LINKSTATE_SQI) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sqi = 1; - dst->sqi = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_LINKSTATE_SQI_MAX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sqi_max = 1; - dst->sqi_max = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_LINKSTATE_EXT_STATE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.ext_state = 1; - dst->ext_state = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_LINKSTATE_EXT_SUBSTATE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.ext_substate = 1; - dst->ext_substate = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_LINKSTATE_EXT_DOWN_CNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.ext_down_cnt = 1; - dst->ext_down_cnt = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_linkstate_get_rsp * -ethtool_linkstate_get(struct ynl_sock *ys, - struct ethtool_linkstate_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_linkstate_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_LINKSTATE_GET, 1); - ys->req_policy = ðtool_linkstate_nest; - yrs.yarg.rsp_policy = ðtool_linkstate_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_LINKSTATE_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_linkstate_get_rsp_parse; - yrs.rsp_cmd = ETHTOOL_MSG_LINKSTATE_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_linkstate_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_LINKSTATE_GET - dump */ -void ethtool_linkstate_get_list_free(struct ethtool_linkstate_get_list *rsp) -{ - struct ethtool_linkstate_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp); - } -} - -struct ethtool_linkstate_get_list * -ethtool_linkstate_get_dump(struct ynl_sock *ys, - struct ethtool_linkstate_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_linkstate_get_list); - yds.cb = ethtool_linkstate_get_rsp_parse; - yds.rsp_cmd = ETHTOOL_MSG_LINKSTATE_GET; - yds.rsp_policy = ðtool_linkstate_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_LINKSTATE_GET, 1); - ys->req_policy = ðtool_linkstate_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_LINKSTATE_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_linkstate_get_list_free(yds.first); - return NULL; -} - -/* ============== ETHTOOL_MSG_DEBUG_GET ============== */ -/* ETHTOOL_MSG_DEBUG_GET - do */ -void ethtool_debug_get_req_free(struct ethtool_debug_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_debug_get_rsp_free(struct ethtool_debug_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_bitset_free(&rsp->msgmask); - free(rsp); -} - -int ethtool_debug_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_debug_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_DEBUG_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_DEBUG_MSGMASK) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.msgmask = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->msgmask; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct ethtool_debug_get_rsp * -ethtool_debug_get(struct ynl_sock *ys, struct ethtool_debug_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_debug_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_DEBUG_GET, 1); - ys->req_policy = ðtool_debug_nest; - yrs.yarg.rsp_policy = ðtool_debug_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_DEBUG_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_debug_get_rsp_parse; - yrs.rsp_cmd = ETHTOOL_MSG_DEBUG_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_debug_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_DEBUG_GET - dump */ -void ethtool_debug_get_list_free(struct ethtool_debug_get_list *rsp) -{ - struct ethtool_debug_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.msgmask); - free(rsp); - } -} - -struct ethtool_debug_get_list * -ethtool_debug_get_dump(struct ynl_sock *ys, - struct ethtool_debug_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_debug_get_list); - yds.cb = ethtool_debug_get_rsp_parse; - yds.rsp_cmd = ETHTOOL_MSG_DEBUG_GET; - yds.rsp_policy = ðtool_debug_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_DEBUG_GET, 1); - ys->req_policy = ðtool_debug_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_DEBUG_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_debug_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_DEBUG_GET - notify */ -void ethtool_debug_get_ntf_free(struct ethtool_debug_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.msgmask); - free(rsp); -} - -/* ============== ETHTOOL_MSG_DEBUG_SET ============== */ -/* ETHTOOL_MSG_DEBUG_SET - do */ -void ethtool_debug_set_req_free(struct ethtool_debug_set_req *req) -{ - ethtool_header_free(&req->header); - ethtool_bitset_free(&req->msgmask); - free(req); -} - -int ethtool_debug_set(struct ynl_sock *ys, struct ethtool_debug_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_DEBUG_SET, 1); - ys->req_policy = ðtool_debug_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_DEBUG_HEADER, &req->header); - if (req->_present.msgmask) - ethtool_bitset_put(nlh, ETHTOOL_A_DEBUG_MSGMASK, &req->msgmask); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_WOL_GET ============== */ -/* ETHTOOL_MSG_WOL_GET - do */ -void ethtool_wol_get_req_free(struct ethtool_wol_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_wol_get_rsp_free(struct ethtool_wol_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_bitset_free(&rsp->modes); - free(rsp->sopass); - free(rsp); -} - -int ethtool_wol_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct ethtool_wol_get_rsp *dst; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_WOL_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_WOL_MODES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.modes = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->modes; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_WOL_SOPASS) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.sopass_len = len; - dst->sopass = malloc(len); - memcpy(dst->sopass, mnl_attr_get_payload(attr), len); - } - } - - return MNL_CB_OK; -} - -struct ethtool_wol_get_rsp * -ethtool_wol_get(struct ynl_sock *ys, struct ethtool_wol_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_wol_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_WOL_GET, 1); - ys->req_policy = ðtool_wol_nest; - yrs.yarg.rsp_policy = ðtool_wol_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_WOL_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_wol_get_rsp_parse; - yrs.rsp_cmd = ETHTOOL_MSG_WOL_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_wol_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_WOL_GET - dump */ -void ethtool_wol_get_list_free(struct ethtool_wol_get_list *rsp) -{ - struct ethtool_wol_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.modes); - free(rsp->obj.sopass); - free(rsp); - } -} - -struct ethtool_wol_get_list * -ethtool_wol_get_dump(struct ynl_sock *ys, struct ethtool_wol_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_wol_get_list); - yds.cb = ethtool_wol_get_rsp_parse; - yds.rsp_cmd = ETHTOOL_MSG_WOL_GET; - yds.rsp_policy = ðtool_wol_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_WOL_GET, 1); - ys->req_policy = ðtool_wol_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_WOL_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_wol_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_WOL_GET - notify */ -void ethtool_wol_get_ntf_free(struct ethtool_wol_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.modes); - free(rsp->obj.sopass); - free(rsp); -} - -/* ============== ETHTOOL_MSG_WOL_SET ============== */ -/* ETHTOOL_MSG_WOL_SET - do */ -void ethtool_wol_set_req_free(struct ethtool_wol_set_req *req) -{ - ethtool_header_free(&req->header); - ethtool_bitset_free(&req->modes); - free(req->sopass); - free(req); -} - -int ethtool_wol_set(struct ynl_sock *ys, struct ethtool_wol_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_WOL_SET, 1); - ys->req_policy = ðtool_wol_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_WOL_HEADER, &req->header); - if (req->_present.modes) - ethtool_bitset_put(nlh, ETHTOOL_A_WOL_MODES, &req->modes); - if (req->_present.sopass_len) - mnl_attr_put(nlh, ETHTOOL_A_WOL_SOPASS, req->_present.sopass_len, req->sopass); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_FEATURES_GET ============== */ -/* ETHTOOL_MSG_FEATURES_GET - do */ -void ethtool_features_get_req_free(struct ethtool_features_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_features_get_rsp_free(struct ethtool_features_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_bitset_free(&rsp->hw); - ethtool_bitset_free(&rsp->wanted); - ethtool_bitset_free(&rsp->active); - ethtool_bitset_free(&rsp->nochange); - free(rsp); -} - -int ethtool_features_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_features_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_FEATURES_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_FEATURES_HW) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.hw = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->hw; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_FEATURES_WANTED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.wanted = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->wanted; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_FEATURES_ACTIVE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.active = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->active; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_FEATURES_NOCHANGE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.nochange = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->nochange; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct ethtool_features_get_rsp * -ethtool_features_get(struct ynl_sock *ys, struct ethtool_features_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_features_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_FEATURES_GET, 1); - ys->req_policy = ðtool_features_nest; - yrs.yarg.rsp_policy = ðtool_features_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_FEATURES_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_features_get_rsp_parse; - yrs.rsp_cmd = ETHTOOL_MSG_FEATURES_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_features_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_FEATURES_GET - dump */ -void ethtool_features_get_list_free(struct ethtool_features_get_list *rsp) -{ - struct ethtool_features_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.hw); - ethtool_bitset_free(&rsp->obj.wanted); - ethtool_bitset_free(&rsp->obj.active); - ethtool_bitset_free(&rsp->obj.nochange); - free(rsp); - } -} - -struct ethtool_features_get_list * -ethtool_features_get_dump(struct ynl_sock *ys, - struct ethtool_features_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_features_get_list); - yds.cb = ethtool_features_get_rsp_parse; - yds.rsp_cmd = ETHTOOL_MSG_FEATURES_GET; - yds.rsp_policy = ðtool_features_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_FEATURES_GET, 1); - ys->req_policy = ðtool_features_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_FEATURES_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_features_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_FEATURES_GET - notify */ -void ethtool_features_get_ntf_free(struct ethtool_features_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.hw); - ethtool_bitset_free(&rsp->obj.wanted); - ethtool_bitset_free(&rsp->obj.active); - ethtool_bitset_free(&rsp->obj.nochange); - free(rsp); -} - -/* ============== ETHTOOL_MSG_FEATURES_SET ============== */ -/* ETHTOOL_MSG_FEATURES_SET - do */ -void ethtool_features_set_req_free(struct ethtool_features_set_req *req) -{ - ethtool_header_free(&req->header); - ethtool_bitset_free(&req->hw); - ethtool_bitset_free(&req->wanted); - ethtool_bitset_free(&req->active); - ethtool_bitset_free(&req->nochange); - free(req); -} - -void ethtool_features_set_rsp_free(struct ethtool_features_set_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_bitset_free(&rsp->hw); - ethtool_bitset_free(&rsp->wanted); - ethtool_bitset_free(&rsp->active); - ethtool_bitset_free(&rsp->nochange); - free(rsp); -} - -int ethtool_features_set_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_features_set_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_FEATURES_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_FEATURES_HW) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.hw = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->hw; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_FEATURES_WANTED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.wanted = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->wanted; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_FEATURES_ACTIVE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.active = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->active; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_FEATURES_NOCHANGE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.nochange = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->nochange; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct ethtool_features_set_rsp * -ethtool_features_set(struct ynl_sock *ys, struct ethtool_features_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_features_set_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_FEATURES_SET, 1); - ys->req_policy = ðtool_features_nest; - yrs.yarg.rsp_policy = ðtool_features_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_FEATURES_HEADER, &req->header); - if (req->_present.hw) - ethtool_bitset_put(nlh, ETHTOOL_A_FEATURES_HW, &req->hw); - if (req->_present.wanted) - ethtool_bitset_put(nlh, ETHTOOL_A_FEATURES_WANTED, &req->wanted); - if (req->_present.active) - ethtool_bitset_put(nlh, ETHTOOL_A_FEATURES_ACTIVE, &req->active); - if (req->_present.nochange) - ethtool_bitset_put(nlh, ETHTOOL_A_FEATURES_NOCHANGE, &req->nochange); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_features_set_rsp_parse; - yrs.rsp_cmd = ETHTOOL_MSG_FEATURES_SET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_features_set_rsp_free(rsp); - return NULL; -} - -/* ============== ETHTOOL_MSG_PRIVFLAGS_GET ============== */ -/* ETHTOOL_MSG_PRIVFLAGS_GET - do */ -void ethtool_privflags_get_req_free(struct ethtool_privflags_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_privflags_get_rsp_free(struct ethtool_privflags_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_bitset_free(&rsp->flags); - free(rsp); -} - -int ethtool_privflags_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_privflags_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_PRIVFLAGS_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_PRIVFLAGS_FLAGS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.flags = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->flags; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct ethtool_privflags_get_rsp * -ethtool_privflags_get(struct ynl_sock *ys, - struct ethtool_privflags_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_privflags_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PRIVFLAGS_GET, 1); - ys->req_policy = ðtool_privflags_nest; - yrs.yarg.rsp_policy = ðtool_privflags_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PRIVFLAGS_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_privflags_get_rsp_parse; - yrs.rsp_cmd = 14; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_privflags_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_PRIVFLAGS_GET - dump */ -void ethtool_privflags_get_list_free(struct ethtool_privflags_get_list *rsp) -{ - struct ethtool_privflags_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.flags); - free(rsp); - } -} - -struct ethtool_privflags_get_list * -ethtool_privflags_get_dump(struct ynl_sock *ys, - struct ethtool_privflags_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_privflags_get_list); - yds.cb = ethtool_privflags_get_rsp_parse; - yds.rsp_cmd = 14; - yds.rsp_policy = ðtool_privflags_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_PRIVFLAGS_GET, 1); - ys->req_policy = ðtool_privflags_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PRIVFLAGS_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_privflags_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_PRIVFLAGS_GET - notify */ -void ethtool_privflags_get_ntf_free(struct ethtool_privflags_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.flags); - free(rsp); -} - -/* ============== ETHTOOL_MSG_PRIVFLAGS_SET ============== */ -/* ETHTOOL_MSG_PRIVFLAGS_SET - do */ -void ethtool_privflags_set_req_free(struct ethtool_privflags_set_req *req) -{ - ethtool_header_free(&req->header); - ethtool_bitset_free(&req->flags); - free(req); -} - -int ethtool_privflags_set(struct ynl_sock *ys, - struct ethtool_privflags_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PRIVFLAGS_SET, 1); - ys->req_policy = ðtool_privflags_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PRIVFLAGS_HEADER, &req->header); - if (req->_present.flags) - ethtool_bitset_put(nlh, ETHTOOL_A_PRIVFLAGS_FLAGS, &req->flags); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_RINGS_GET ============== */ -/* ETHTOOL_MSG_RINGS_GET - do */ -void ethtool_rings_get_req_free(struct ethtool_rings_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_rings_get_rsp_free(struct ethtool_rings_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp); -} - -int ethtool_rings_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_rings_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_RINGS_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_RINGS_RX_MAX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_max = 1; - dst->rx_max = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RINGS_RX_MINI_MAX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_mini_max = 1; - dst->rx_mini_max = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RINGS_RX_JUMBO_MAX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_jumbo_max = 1; - dst->rx_jumbo_max = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RINGS_TX_MAX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_max = 1; - dst->tx_max = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RINGS_RX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx = 1; - dst->rx = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RINGS_RX_MINI) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_mini = 1; - dst->rx_mini = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RINGS_RX_JUMBO) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_jumbo = 1; - dst->rx_jumbo = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RINGS_TX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx = 1; - dst->tx = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RINGS_RX_BUF_LEN) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_buf_len = 1; - dst->rx_buf_len = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RINGS_TCP_DATA_SPLIT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tcp_data_split = 1; - dst->tcp_data_split = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_RINGS_CQE_SIZE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.cqe_size = 1; - dst->cqe_size = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RINGS_TX_PUSH) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_push = 1; - dst->tx_push = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_RINGS_RX_PUSH) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_push = 1; - dst->rx_push = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_push_buf_len = 1; - dst->tx_push_buf_len = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN_MAX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_push_buf_len_max = 1; - dst->tx_push_buf_len_max = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_rings_get_rsp * -ethtool_rings_get(struct ynl_sock *ys, struct ethtool_rings_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_rings_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_RINGS_GET, 1); - ys->req_policy = ðtool_rings_nest; - yrs.yarg.rsp_policy = ðtool_rings_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_RINGS_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_rings_get_rsp_parse; - yrs.rsp_cmd = 16; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_rings_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_RINGS_GET - dump */ -void ethtool_rings_get_list_free(struct ethtool_rings_get_list *rsp) -{ - struct ethtool_rings_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp); - } -} - -struct ethtool_rings_get_list * -ethtool_rings_get_dump(struct ynl_sock *ys, - struct ethtool_rings_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_rings_get_list); - yds.cb = ethtool_rings_get_rsp_parse; - yds.rsp_cmd = 16; - yds.rsp_policy = ðtool_rings_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_RINGS_GET, 1); - ys->req_policy = ðtool_rings_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_RINGS_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_rings_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_RINGS_GET - notify */ -void ethtool_rings_get_ntf_free(struct ethtool_rings_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - free(rsp); -} - -/* ============== ETHTOOL_MSG_RINGS_SET ============== */ -/* ETHTOOL_MSG_RINGS_SET - do */ -void ethtool_rings_set_req_free(struct ethtool_rings_set_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -int ethtool_rings_set(struct ynl_sock *ys, struct ethtool_rings_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_RINGS_SET, 1); - ys->req_policy = ðtool_rings_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_RINGS_HEADER, &req->header); - if (req->_present.rx_max) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_RX_MAX, req->rx_max); - if (req->_present.rx_mini_max) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_RX_MINI_MAX, req->rx_mini_max); - if (req->_present.rx_jumbo_max) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_RX_JUMBO_MAX, req->rx_jumbo_max); - if (req->_present.tx_max) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_TX_MAX, req->tx_max); - if (req->_present.rx) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_RX, req->rx); - if (req->_present.rx_mini) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_RX_MINI, req->rx_mini); - if (req->_present.rx_jumbo) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_RX_JUMBO, req->rx_jumbo); - if (req->_present.tx) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_TX, req->tx); - if (req->_present.rx_buf_len) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_RX_BUF_LEN, req->rx_buf_len); - if (req->_present.tcp_data_split) - mnl_attr_put_u8(nlh, ETHTOOL_A_RINGS_TCP_DATA_SPLIT, req->tcp_data_split); - if (req->_present.cqe_size) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_CQE_SIZE, req->cqe_size); - if (req->_present.tx_push) - mnl_attr_put_u8(nlh, ETHTOOL_A_RINGS_TX_PUSH, req->tx_push); - if (req->_present.rx_push) - mnl_attr_put_u8(nlh, ETHTOOL_A_RINGS_RX_PUSH, req->rx_push); - if (req->_present.tx_push_buf_len) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN, req->tx_push_buf_len); - if (req->_present.tx_push_buf_len_max) - mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN_MAX, req->tx_push_buf_len_max); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_CHANNELS_GET ============== */ -/* ETHTOOL_MSG_CHANNELS_GET - do */ -void ethtool_channels_get_req_free(struct ethtool_channels_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_channels_get_rsp_free(struct ethtool_channels_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp); -} - -int ethtool_channels_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_channels_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_CHANNELS_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_CHANNELS_RX_MAX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_max = 1; - dst->rx_max = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_CHANNELS_TX_MAX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_max = 1; - dst->tx_max = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_CHANNELS_OTHER_MAX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.other_max = 1; - dst->other_max = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_CHANNELS_COMBINED_MAX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.combined_max = 1; - dst->combined_max = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_CHANNELS_RX_COUNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_count = 1; - dst->rx_count = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_CHANNELS_TX_COUNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_count = 1; - dst->tx_count = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_CHANNELS_OTHER_COUNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.other_count = 1; - dst->other_count = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_CHANNELS_COMBINED_COUNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.combined_count = 1; - dst->combined_count = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_channels_get_rsp * -ethtool_channels_get(struct ynl_sock *ys, struct ethtool_channels_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_channels_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_CHANNELS_GET, 1); - ys->req_policy = ðtool_channels_nest; - yrs.yarg.rsp_policy = ðtool_channels_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_CHANNELS_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_channels_get_rsp_parse; - yrs.rsp_cmd = 18; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_channels_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_CHANNELS_GET - dump */ -void ethtool_channels_get_list_free(struct ethtool_channels_get_list *rsp) -{ - struct ethtool_channels_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp); - } -} - -struct ethtool_channels_get_list * -ethtool_channels_get_dump(struct ynl_sock *ys, - struct ethtool_channels_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_channels_get_list); - yds.cb = ethtool_channels_get_rsp_parse; - yds.rsp_cmd = 18; - yds.rsp_policy = ðtool_channels_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_CHANNELS_GET, 1); - ys->req_policy = ðtool_channels_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_CHANNELS_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_channels_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_CHANNELS_GET - notify */ -void ethtool_channels_get_ntf_free(struct ethtool_channels_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - free(rsp); -} - -/* ============== ETHTOOL_MSG_CHANNELS_SET ============== */ -/* ETHTOOL_MSG_CHANNELS_SET - do */ -void ethtool_channels_set_req_free(struct ethtool_channels_set_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -int ethtool_channels_set(struct ynl_sock *ys, - struct ethtool_channels_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_CHANNELS_SET, 1); - ys->req_policy = ðtool_channels_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_CHANNELS_HEADER, &req->header); - if (req->_present.rx_max) - mnl_attr_put_u32(nlh, ETHTOOL_A_CHANNELS_RX_MAX, req->rx_max); - if (req->_present.tx_max) - mnl_attr_put_u32(nlh, ETHTOOL_A_CHANNELS_TX_MAX, req->tx_max); - if (req->_present.other_max) - mnl_attr_put_u32(nlh, ETHTOOL_A_CHANNELS_OTHER_MAX, req->other_max); - if (req->_present.combined_max) - mnl_attr_put_u32(nlh, ETHTOOL_A_CHANNELS_COMBINED_MAX, req->combined_max); - if (req->_present.rx_count) - mnl_attr_put_u32(nlh, ETHTOOL_A_CHANNELS_RX_COUNT, req->rx_count); - if (req->_present.tx_count) - mnl_attr_put_u32(nlh, ETHTOOL_A_CHANNELS_TX_COUNT, req->tx_count); - if (req->_present.other_count) - mnl_attr_put_u32(nlh, ETHTOOL_A_CHANNELS_OTHER_COUNT, req->other_count); - if (req->_present.combined_count) - mnl_attr_put_u32(nlh, ETHTOOL_A_CHANNELS_COMBINED_COUNT, req->combined_count); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_COALESCE_GET ============== */ -/* ETHTOOL_MSG_COALESCE_GET - do */ -void ethtool_coalesce_get_req_free(struct ethtool_coalesce_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_coalesce_get_rsp_free(struct ethtool_coalesce_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp); -} - -int ethtool_coalesce_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_coalesce_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_COALESCE_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_COALESCE_RX_USECS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_usecs = 1; - dst->rx_usecs = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_RX_MAX_FRAMES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_max_frames = 1; - dst->rx_max_frames = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_RX_USECS_IRQ) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_usecs_irq = 1; - dst->rx_usecs_irq = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_max_frames_irq = 1; - dst->rx_max_frames_irq = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_TX_USECS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_usecs = 1; - dst->tx_usecs = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_TX_MAX_FRAMES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_max_frames = 1; - dst->tx_max_frames = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_TX_USECS_IRQ) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_usecs_irq = 1; - dst->tx_usecs_irq = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_max_frames_irq = 1; - dst->tx_max_frames_irq = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_STATS_BLOCK_USECS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.stats_block_usecs = 1; - dst->stats_block_usecs = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.use_adaptive_rx = 1; - dst->use_adaptive_rx = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.use_adaptive_tx = 1; - dst->use_adaptive_tx = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_COALESCE_PKT_RATE_LOW) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.pkt_rate_low = 1; - dst->pkt_rate_low = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_RX_USECS_LOW) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_usecs_low = 1; - dst->rx_usecs_low = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_max_frames_low = 1; - dst->rx_max_frames_low = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_TX_USECS_LOW) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_usecs_low = 1; - dst->tx_usecs_low = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_max_frames_low = 1; - dst->tx_max_frames_low = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_PKT_RATE_HIGH) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.pkt_rate_high = 1; - dst->pkt_rate_high = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_RX_USECS_HIGH) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_usecs_high = 1; - dst->rx_usecs_high = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_max_frames_high = 1; - dst->rx_max_frames_high = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_TX_USECS_HIGH) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_usecs_high = 1; - dst->tx_usecs_high = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_max_frames_high = 1; - dst->tx_max_frames_high = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rate_sample_interval = 1; - dst->rate_sample_interval = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_USE_CQE_MODE_TX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.use_cqe_mode_tx = 1; - dst->use_cqe_mode_tx = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_COALESCE_USE_CQE_MODE_RX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.use_cqe_mode_rx = 1; - dst->use_cqe_mode_rx = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_COALESCE_TX_AGGR_MAX_BYTES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_aggr_max_bytes = 1; - dst->tx_aggr_max_bytes = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_TX_AGGR_MAX_FRAMES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_aggr_max_frames = 1; - dst->tx_aggr_max_frames = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_COALESCE_TX_AGGR_TIME_USECS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_aggr_time_usecs = 1; - dst->tx_aggr_time_usecs = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_coalesce_get_rsp * -ethtool_coalesce_get(struct ynl_sock *ys, struct ethtool_coalesce_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_coalesce_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_COALESCE_GET, 1); - ys->req_policy = ðtool_coalesce_nest; - yrs.yarg.rsp_policy = ðtool_coalesce_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_COALESCE_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_coalesce_get_rsp_parse; - yrs.rsp_cmd = 20; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_coalesce_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_COALESCE_GET - dump */ -void ethtool_coalesce_get_list_free(struct ethtool_coalesce_get_list *rsp) -{ - struct ethtool_coalesce_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp); - } -} - -struct ethtool_coalesce_get_list * -ethtool_coalesce_get_dump(struct ynl_sock *ys, - struct ethtool_coalesce_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_coalesce_get_list); - yds.cb = ethtool_coalesce_get_rsp_parse; - yds.rsp_cmd = 20; - yds.rsp_policy = ðtool_coalesce_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_COALESCE_GET, 1); - ys->req_policy = ðtool_coalesce_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_COALESCE_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_coalesce_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_COALESCE_GET - notify */ -void ethtool_coalesce_get_ntf_free(struct ethtool_coalesce_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - free(rsp); -} - -/* ============== ETHTOOL_MSG_COALESCE_SET ============== */ -/* ETHTOOL_MSG_COALESCE_SET - do */ -void ethtool_coalesce_set_req_free(struct ethtool_coalesce_set_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -int ethtool_coalesce_set(struct ynl_sock *ys, - struct ethtool_coalesce_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_COALESCE_SET, 1); - ys->req_policy = ðtool_coalesce_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_COALESCE_HEADER, &req->header); - if (req->_present.rx_usecs) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RX_USECS, req->rx_usecs); - if (req->_present.rx_max_frames) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RX_MAX_FRAMES, req->rx_max_frames); - if (req->_present.rx_usecs_irq) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RX_USECS_IRQ, req->rx_usecs_irq); - if (req->_present.rx_max_frames_irq) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ, req->rx_max_frames_irq); - if (req->_present.tx_usecs) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_USECS, req->tx_usecs); - if (req->_present.tx_max_frames) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_MAX_FRAMES, req->tx_max_frames); - if (req->_present.tx_usecs_irq) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_USECS_IRQ, req->tx_usecs_irq); - if (req->_present.tx_max_frames_irq) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ, req->tx_max_frames_irq); - if (req->_present.stats_block_usecs) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_STATS_BLOCK_USECS, req->stats_block_usecs); - if (req->_present.use_adaptive_rx) - mnl_attr_put_u8(nlh, ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX, req->use_adaptive_rx); - if (req->_present.use_adaptive_tx) - mnl_attr_put_u8(nlh, ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX, req->use_adaptive_tx); - if (req->_present.pkt_rate_low) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_PKT_RATE_LOW, req->pkt_rate_low); - if (req->_present.rx_usecs_low) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RX_USECS_LOW, req->rx_usecs_low); - if (req->_present.rx_max_frames_low) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW, req->rx_max_frames_low); - if (req->_present.tx_usecs_low) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_USECS_LOW, req->tx_usecs_low); - if (req->_present.tx_max_frames_low) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW, req->tx_max_frames_low); - if (req->_present.pkt_rate_high) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_PKT_RATE_HIGH, req->pkt_rate_high); - if (req->_present.rx_usecs_high) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RX_USECS_HIGH, req->rx_usecs_high); - if (req->_present.rx_max_frames_high) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH, req->rx_max_frames_high); - if (req->_present.tx_usecs_high) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_USECS_HIGH, req->tx_usecs_high); - if (req->_present.tx_max_frames_high) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH, req->tx_max_frames_high); - if (req->_present.rate_sample_interval) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL, req->rate_sample_interval); - if (req->_present.use_cqe_mode_tx) - mnl_attr_put_u8(nlh, ETHTOOL_A_COALESCE_USE_CQE_MODE_TX, req->use_cqe_mode_tx); - if (req->_present.use_cqe_mode_rx) - mnl_attr_put_u8(nlh, ETHTOOL_A_COALESCE_USE_CQE_MODE_RX, req->use_cqe_mode_rx); - if (req->_present.tx_aggr_max_bytes) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_AGGR_MAX_BYTES, req->tx_aggr_max_bytes); - if (req->_present.tx_aggr_max_frames) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_AGGR_MAX_FRAMES, req->tx_aggr_max_frames); - if (req->_present.tx_aggr_time_usecs) - mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_AGGR_TIME_USECS, req->tx_aggr_time_usecs); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_PAUSE_GET ============== */ -/* ETHTOOL_MSG_PAUSE_GET - do */ -void ethtool_pause_get_req_free(struct ethtool_pause_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_pause_get_rsp_free(struct ethtool_pause_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_pause_stat_free(&rsp->stats); - free(rsp); -} - -int ethtool_pause_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_pause_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_PAUSE_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_PAUSE_AUTONEG) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.autoneg = 1; - dst->autoneg = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_PAUSE_RX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx = 1; - dst->rx = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_PAUSE_TX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx = 1; - dst->tx = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_PAUSE_STATS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.stats = 1; - - parg.rsp_policy = ðtool_pause_stat_nest; - parg.data = &dst->stats; - if (ethtool_pause_stat_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_PAUSE_STATS_SRC) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.stats_src = 1; - dst->stats_src = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_pause_get_rsp * -ethtool_pause_get(struct ynl_sock *ys, struct ethtool_pause_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_pause_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PAUSE_GET, 1); - ys->req_policy = ðtool_pause_nest; - yrs.yarg.rsp_policy = ðtool_pause_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PAUSE_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_pause_get_rsp_parse; - yrs.rsp_cmd = 22; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_pause_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_PAUSE_GET - dump */ -void ethtool_pause_get_list_free(struct ethtool_pause_get_list *rsp) -{ - struct ethtool_pause_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_pause_stat_free(&rsp->obj.stats); - free(rsp); - } -} - -struct ethtool_pause_get_list * -ethtool_pause_get_dump(struct ynl_sock *ys, - struct ethtool_pause_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_pause_get_list); - yds.cb = ethtool_pause_get_rsp_parse; - yds.rsp_cmd = 22; - yds.rsp_policy = ðtool_pause_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_PAUSE_GET, 1); - ys->req_policy = ðtool_pause_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PAUSE_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_pause_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_PAUSE_GET - notify */ -void ethtool_pause_get_ntf_free(struct ethtool_pause_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - ethtool_pause_stat_free(&rsp->obj.stats); - free(rsp); -} - -/* ============== ETHTOOL_MSG_PAUSE_SET ============== */ -/* ETHTOOL_MSG_PAUSE_SET - do */ -void ethtool_pause_set_req_free(struct ethtool_pause_set_req *req) -{ - ethtool_header_free(&req->header); - ethtool_pause_stat_free(&req->stats); - free(req); -} - -int ethtool_pause_set(struct ynl_sock *ys, struct ethtool_pause_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PAUSE_SET, 1); - ys->req_policy = ðtool_pause_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PAUSE_HEADER, &req->header); - if (req->_present.autoneg) - mnl_attr_put_u8(nlh, ETHTOOL_A_PAUSE_AUTONEG, req->autoneg); - if (req->_present.rx) - mnl_attr_put_u8(nlh, ETHTOOL_A_PAUSE_RX, req->rx); - if (req->_present.tx) - mnl_attr_put_u8(nlh, ETHTOOL_A_PAUSE_TX, req->tx); - if (req->_present.stats) - ethtool_pause_stat_put(nlh, ETHTOOL_A_PAUSE_STATS, &req->stats); - if (req->_present.stats_src) - mnl_attr_put_u32(nlh, ETHTOOL_A_PAUSE_STATS_SRC, req->stats_src); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_EEE_GET ============== */ -/* ETHTOOL_MSG_EEE_GET - do */ -void ethtool_eee_get_req_free(struct ethtool_eee_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_eee_get_rsp_free(struct ethtool_eee_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_bitset_free(&rsp->modes_ours); - ethtool_bitset_free(&rsp->modes_peer); - free(rsp); -} - -int ethtool_eee_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct ethtool_eee_get_rsp *dst; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_EEE_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_EEE_MODES_OURS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.modes_ours = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->modes_ours; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_EEE_MODES_PEER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.modes_peer = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->modes_peer; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_EEE_ACTIVE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.active = 1; - dst->active = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_EEE_ENABLED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.enabled = 1; - dst->enabled = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_EEE_TX_LPI_ENABLED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_lpi_enabled = 1; - dst->tx_lpi_enabled = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_EEE_TX_LPI_TIMER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_lpi_timer = 1; - dst->tx_lpi_timer = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_eee_get_rsp * -ethtool_eee_get(struct ynl_sock *ys, struct ethtool_eee_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_eee_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_EEE_GET, 1); - ys->req_policy = ðtool_eee_nest; - yrs.yarg.rsp_policy = ðtool_eee_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_EEE_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_eee_get_rsp_parse; - yrs.rsp_cmd = 24; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_eee_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_EEE_GET - dump */ -void ethtool_eee_get_list_free(struct ethtool_eee_get_list *rsp) -{ - struct ethtool_eee_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.modes_ours); - ethtool_bitset_free(&rsp->obj.modes_peer); - free(rsp); - } -} - -struct ethtool_eee_get_list * -ethtool_eee_get_dump(struct ynl_sock *ys, struct ethtool_eee_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_eee_get_list); - yds.cb = ethtool_eee_get_rsp_parse; - yds.rsp_cmd = 24; - yds.rsp_policy = ðtool_eee_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_EEE_GET, 1); - ys->req_policy = ðtool_eee_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_EEE_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_eee_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_EEE_GET - notify */ -void ethtool_eee_get_ntf_free(struct ethtool_eee_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.modes_ours); - ethtool_bitset_free(&rsp->obj.modes_peer); - free(rsp); -} - -/* ============== ETHTOOL_MSG_EEE_SET ============== */ -/* ETHTOOL_MSG_EEE_SET - do */ -void ethtool_eee_set_req_free(struct ethtool_eee_set_req *req) -{ - ethtool_header_free(&req->header); - ethtool_bitset_free(&req->modes_ours); - ethtool_bitset_free(&req->modes_peer); - free(req); -} - -int ethtool_eee_set(struct ynl_sock *ys, struct ethtool_eee_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_EEE_SET, 1); - ys->req_policy = ðtool_eee_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_EEE_HEADER, &req->header); - if (req->_present.modes_ours) - ethtool_bitset_put(nlh, ETHTOOL_A_EEE_MODES_OURS, &req->modes_ours); - if (req->_present.modes_peer) - ethtool_bitset_put(nlh, ETHTOOL_A_EEE_MODES_PEER, &req->modes_peer); - if (req->_present.active) - mnl_attr_put_u8(nlh, ETHTOOL_A_EEE_ACTIVE, req->active); - if (req->_present.enabled) - mnl_attr_put_u8(nlh, ETHTOOL_A_EEE_ENABLED, req->enabled); - if (req->_present.tx_lpi_enabled) - mnl_attr_put_u8(nlh, ETHTOOL_A_EEE_TX_LPI_ENABLED, req->tx_lpi_enabled); - if (req->_present.tx_lpi_timer) - mnl_attr_put_u32(nlh, ETHTOOL_A_EEE_TX_LPI_TIMER, req->tx_lpi_timer); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_TSINFO_GET ============== */ -/* ETHTOOL_MSG_TSINFO_GET - do */ -void ethtool_tsinfo_get_req_free(struct ethtool_tsinfo_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_tsinfo_get_rsp_free(struct ethtool_tsinfo_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_bitset_free(&rsp->timestamping); - ethtool_bitset_free(&rsp->tx_types); - ethtool_bitset_free(&rsp->rx_filters); - free(rsp); -} - -int ethtool_tsinfo_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_tsinfo_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_TSINFO_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_TSINFO_TIMESTAMPING) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.timestamping = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->timestamping; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_TSINFO_TX_TYPES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_types = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->tx_types; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_TSINFO_RX_FILTERS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_filters = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->rx_filters; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_TSINFO_PHC_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.phc_index = 1; - dst->phc_index = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_tsinfo_get_rsp * -ethtool_tsinfo_get(struct ynl_sock *ys, struct ethtool_tsinfo_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_tsinfo_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_TSINFO_GET, 1); - ys->req_policy = ðtool_tsinfo_nest; - yrs.yarg.rsp_policy = ðtool_tsinfo_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_TSINFO_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_tsinfo_get_rsp_parse; - yrs.rsp_cmd = 26; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_tsinfo_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_TSINFO_GET - dump */ -void ethtool_tsinfo_get_list_free(struct ethtool_tsinfo_get_list *rsp) -{ - struct ethtool_tsinfo_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.timestamping); - ethtool_bitset_free(&rsp->obj.tx_types); - ethtool_bitset_free(&rsp->obj.rx_filters); - free(rsp); - } -} - -struct ethtool_tsinfo_get_list * -ethtool_tsinfo_get_dump(struct ynl_sock *ys, - struct ethtool_tsinfo_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_tsinfo_get_list); - yds.cb = ethtool_tsinfo_get_rsp_parse; - yds.rsp_cmd = 26; - yds.rsp_policy = ðtool_tsinfo_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_TSINFO_GET, 1); - ys->req_policy = ðtool_tsinfo_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_TSINFO_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_tsinfo_get_list_free(yds.first); - return NULL; -} - -/* ============== ETHTOOL_MSG_CABLE_TEST_ACT ============== */ -/* ETHTOOL_MSG_CABLE_TEST_ACT - do */ -void ethtool_cable_test_act_req_free(struct ethtool_cable_test_act_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -int ethtool_cable_test_act(struct ynl_sock *ys, - struct ethtool_cable_test_act_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_CABLE_TEST_ACT, 1); - ys->req_policy = ðtool_cable_test_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_CABLE_TEST_HEADER, &req->header); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_CABLE_TEST_TDR_ACT ============== */ -/* ETHTOOL_MSG_CABLE_TEST_TDR_ACT - do */ -void -ethtool_cable_test_tdr_act_req_free(struct ethtool_cable_test_tdr_act_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -int ethtool_cable_test_tdr_act(struct ynl_sock *ys, - struct ethtool_cable_test_tdr_act_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_CABLE_TEST_TDR_ACT, 1); - ys->req_policy = ðtool_cable_test_tdr_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_CABLE_TEST_TDR_HEADER, &req->header); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_TUNNEL_INFO_GET ============== */ -/* ETHTOOL_MSG_TUNNEL_INFO_GET - do */ -void ethtool_tunnel_info_get_req_free(struct ethtool_tunnel_info_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_tunnel_info_get_rsp_free(struct ethtool_tunnel_info_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_tunnel_udp_free(&rsp->udp_ports); - free(rsp); -} - -int ethtool_tunnel_info_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_tunnel_info_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_TUNNEL_INFO_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_TUNNEL_INFO_UDP_PORTS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.udp_ports = 1; - - parg.rsp_policy = ðtool_tunnel_udp_nest; - parg.data = &dst->udp_ports; - if (ethtool_tunnel_udp_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct ethtool_tunnel_info_get_rsp * -ethtool_tunnel_info_get(struct ynl_sock *ys, - struct ethtool_tunnel_info_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_tunnel_info_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_TUNNEL_INFO_GET, 1); - ys->req_policy = ðtool_tunnel_info_nest; - yrs.yarg.rsp_policy = ðtool_tunnel_info_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_TUNNEL_INFO_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_tunnel_info_get_rsp_parse; - yrs.rsp_cmd = 29; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_tunnel_info_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_TUNNEL_INFO_GET - dump */ -void -ethtool_tunnel_info_get_list_free(struct ethtool_tunnel_info_get_list *rsp) -{ - struct ethtool_tunnel_info_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_tunnel_udp_free(&rsp->obj.udp_ports); - free(rsp); - } -} - -struct ethtool_tunnel_info_get_list * -ethtool_tunnel_info_get_dump(struct ynl_sock *ys, - struct ethtool_tunnel_info_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_tunnel_info_get_list); - yds.cb = ethtool_tunnel_info_get_rsp_parse; - yds.rsp_cmd = 29; - yds.rsp_policy = ðtool_tunnel_info_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_TUNNEL_INFO_GET, 1); - ys->req_policy = ðtool_tunnel_info_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_TUNNEL_INFO_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_tunnel_info_get_list_free(yds.first); - return NULL; -} - -/* ============== ETHTOOL_MSG_FEC_GET ============== */ -/* ETHTOOL_MSG_FEC_GET - do */ -void ethtool_fec_get_req_free(struct ethtool_fec_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_fec_get_rsp_free(struct ethtool_fec_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_bitset_free(&rsp->modes); - ethtool_fec_stat_free(&rsp->stats); - free(rsp); -} - -int ethtool_fec_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct ethtool_fec_get_rsp *dst; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_FEC_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_FEC_MODES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.modes = 1; - - parg.rsp_policy = ðtool_bitset_nest; - parg.data = &dst->modes; - if (ethtool_bitset_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_FEC_AUTO) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.auto_ = 1; - dst->auto_ = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_FEC_ACTIVE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.active = 1; - dst->active = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_FEC_STATS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.stats = 1; - - parg.rsp_policy = ðtool_fec_stat_nest; - parg.data = &dst->stats; - if (ethtool_fec_stat_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct ethtool_fec_get_rsp * -ethtool_fec_get(struct ynl_sock *ys, struct ethtool_fec_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_fec_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_FEC_GET, 1); - ys->req_policy = ðtool_fec_nest; - yrs.yarg.rsp_policy = ðtool_fec_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_FEC_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_fec_get_rsp_parse; - yrs.rsp_cmd = 30; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_fec_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_FEC_GET - dump */ -void ethtool_fec_get_list_free(struct ethtool_fec_get_list *rsp) -{ - struct ethtool_fec_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.modes); - ethtool_fec_stat_free(&rsp->obj.stats); - free(rsp); - } -} - -struct ethtool_fec_get_list * -ethtool_fec_get_dump(struct ynl_sock *ys, struct ethtool_fec_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_fec_get_list); - yds.cb = ethtool_fec_get_rsp_parse; - yds.rsp_cmd = 30; - yds.rsp_policy = ðtool_fec_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_FEC_GET, 1); - ys->req_policy = ðtool_fec_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_FEC_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_fec_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_FEC_GET - notify */ -void ethtool_fec_get_ntf_free(struct ethtool_fec_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - ethtool_bitset_free(&rsp->obj.modes); - ethtool_fec_stat_free(&rsp->obj.stats); - free(rsp); -} - -/* ============== ETHTOOL_MSG_FEC_SET ============== */ -/* ETHTOOL_MSG_FEC_SET - do */ -void ethtool_fec_set_req_free(struct ethtool_fec_set_req *req) -{ - ethtool_header_free(&req->header); - ethtool_bitset_free(&req->modes); - ethtool_fec_stat_free(&req->stats); - free(req); -} - -int ethtool_fec_set(struct ynl_sock *ys, struct ethtool_fec_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_FEC_SET, 1); - ys->req_policy = ðtool_fec_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_FEC_HEADER, &req->header); - if (req->_present.modes) - ethtool_bitset_put(nlh, ETHTOOL_A_FEC_MODES, &req->modes); - if (req->_present.auto_) - mnl_attr_put_u8(nlh, ETHTOOL_A_FEC_AUTO, req->auto_); - if (req->_present.active) - mnl_attr_put_u32(nlh, ETHTOOL_A_FEC_ACTIVE, req->active); - if (req->_present.stats) - ethtool_fec_stat_put(nlh, ETHTOOL_A_FEC_STATS, &req->stats); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_MODULE_EEPROM_GET ============== */ -/* ETHTOOL_MSG_MODULE_EEPROM_GET - do */ -void -ethtool_module_eeprom_get_req_free(struct ethtool_module_eeprom_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void -ethtool_module_eeprom_get_rsp_free(struct ethtool_module_eeprom_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp->data); - free(rsp); -} - -int ethtool_module_eeprom_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_module_eeprom_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_MODULE_EEPROM_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_MODULE_EEPROM_OFFSET) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.offset = 1; - dst->offset = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_MODULE_EEPROM_LENGTH) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.length = 1; - dst->length = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_MODULE_EEPROM_PAGE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.page = 1; - dst->page = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_MODULE_EEPROM_BANK) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.bank = 1; - dst->bank = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.i2c_address = 1; - dst->i2c_address = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_MODULE_EEPROM_DATA) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.data_len = len; - dst->data = malloc(len); - memcpy(dst->data, mnl_attr_get_payload(attr), len); - } - } - - return MNL_CB_OK; -} - -struct ethtool_module_eeprom_get_rsp * -ethtool_module_eeprom_get(struct ynl_sock *ys, - struct ethtool_module_eeprom_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_module_eeprom_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_MODULE_EEPROM_GET, 1); - ys->req_policy = ðtool_module_eeprom_nest; - yrs.yarg.rsp_policy = ðtool_module_eeprom_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_MODULE_EEPROM_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_module_eeprom_get_rsp_parse; - yrs.rsp_cmd = 32; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_module_eeprom_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_MODULE_EEPROM_GET - dump */ -void -ethtool_module_eeprom_get_list_free(struct ethtool_module_eeprom_get_list *rsp) -{ - struct ethtool_module_eeprom_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp->obj.data); - free(rsp); - } -} - -struct ethtool_module_eeprom_get_list * -ethtool_module_eeprom_get_dump(struct ynl_sock *ys, - struct ethtool_module_eeprom_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_module_eeprom_get_list); - yds.cb = ethtool_module_eeprom_get_rsp_parse; - yds.rsp_cmd = 32; - yds.rsp_policy = ðtool_module_eeprom_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_MODULE_EEPROM_GET, 1); - ys->req_policy = ðtool_module_eeprom_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_MODULE_EEPROM_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_module_eeprom_get_list_free(yds.first); - return NULL; -} - -/* ============== ETHTOOL_MSG_PHC_VCLOCKS_GET ============== */ -/* ETHTOOL_MSG_PHC_VCLOCKS_GET - do */ -void ethtool_phc_vclocks_get_req_free(struct ethtool_phc_vclocks_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_phc_vclocks_get_rsp_free(struct ethtool_phc_vclocks_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp); -} - -int ethtool_phc_vclocks_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_phc_vclocks_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_PHC_VCLOCKS_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_PHC_VCLOCKS_NUM) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.num = 1; - dst->num = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_phc_vclocks_get_rsp * -ethtool_phc_vclocks_get(struct ynl_sock *ys, - struct ethtool_phc_vclocks_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_phc_vclocks_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PHC_VCLOCKS_GET, 1); - ys->req_policy = ðtool_phc_vclocks_nest; - yrs.yarg.rsp_policy = ðtool_phc_vclocks_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PHC_VCLOCKS_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_phc_vclocks_get_rsp_parse; - yrs.rsp_cmd = 34; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_phc_vclocks_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_PHC_VCLOCKS_GET - dump */ -void -ethtool_phc_vclocks_get_list_free(struct ethtool_phc_vclocks_get_list *rsp) -{ - struct ethtool_phc_vclocks_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp); - } -} - -struct ethtool_phc_vclocks_get_list * -ethtool_phc_vclocks_get_dump(struct ynl_sock *ys, - struct ethtool_phc_vclocks_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_phc_vclocks_get_list); - yds.cb = ethtool_phc_vclocks_get_rsp_parse; - yds.rsp_cmd = 34; - yds.rsp_policy = ðtool_phc_vclocks_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_PHC_VCLOCKS_GET, 1); - ys->req_policy = ðtool_phc_vclocks_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PHC_VCLOCKS_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_phc_vclocks_get_list_free(yds.first); - return NULL; -} - -/* ============== ETHTOOL_MSG_MODULE_GET ============== */ -/* ETHTOOL_MSG_MODULE_GET - do */ -void ethtool_module_get_req_free(struct ethtool_module_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_module_get_rsp_free(struct ethtool_module_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp); -} - -int ethtool_module_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_module_get_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_MODULE_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_MODULE_POWER_MODE_POLICY) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.power_mode_policy = 1; - dst->power_mode_policy = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_MODULE_POWER_MODE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.power_mode = 1; - dst->power_mode = mnl_attr_get_u8(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_module_get_rsp * -ethtool_module_get(struct ynl_sock *ys, struct ethtool_module_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_module_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_MODULE_GET, 1); - ys->req_policy = ðtool_module_nest; - yrs.yarg.rsp_policy = ðtool_module_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_MODULE_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_module_get_rsp_parse; - yrs.rsp_cmd = 35; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_module_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_MODULE_GET - dump */ -void ethtool_module_get_list_free(struct ethtool_module_get_list *rsp) -{ - struct ethtool_module_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp); - } -} - -struct ethtool_module_get_list * -ethtool_module_get_dump(struct ynl_sock *ys, - struct ethtool_module_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_module_get_list); - yds.cb = ethtool_module_get_rsp_parse; - yds.rsp_cmd = 35; - yds.rsp_policy = ðtool_module_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_MODULE_GET, 1); - ys->req_policy = ðtool_module_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_MODULE_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_module_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_MODULE_GET - notify */ -void ethtool_module_get_ntf_free(struct ethtool_module_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - free(rsp); -} - -/* ============== ETHTOOL_MSG_MODULE_SET ============== */ -/* ETHTOOL_MSG_MODULE_SET - do */ -void ethtool_module_set_req_free(struct ethtool_module_set_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -int ethtool_module_set(struct ynl_sock *ys, struct ethtool_module_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_MODULE_SET, 1); - ys->req_policy = ðtool_module_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_MODULE_HEADER, &req->header); - if (req->_present.power_mode_policy) - mnl_attr_put_u8(nlh, ETHTOOL_A_MODULE_POWER_MODE_POLICY, req->power_mode_policy); - if (req->_present.power_mode) - mnl_attr_put_u8(nlh, ETHTOOL_A_MODULE_POWER_MODE, req->power_mode); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_PSE_GET ============== */ -/* ETHTOOL_MSG_PSE_GET - do */ -void ethtool_pse_get_req_free(struct ethtool_pse_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_pse_get_rsp_free(struct ethtool_pse_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp); -} - -int ethtool_pse_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct ethtool_pse_get_rsp *dst; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_PSE_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_PODL_PSE_ADMIN_STATE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.admin_state = 1; - dst->admin_state = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_PODL_PSE_ADMIN_CONTROL) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.admin_control = 1; - dst->admin_control = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_PODL_PSE_PW_D_STATUS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.pw_d_status = 1; - dst->pw_d_status = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_pse_get_rsp * -ethtool_pse_get(struct ynl_sock *ys, struct ethtool_pse_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_pse_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PSE_GET, 1); - ys->req_policy = ðtool_pse_nest; - yrs.yarg.rsp_policy = ðtool_pse_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PSE_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_pse_get_rsp_parse; - yrs.rsp_cmd = 37; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_pse_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_PSE_GET - dump */ -void ethtool_pse_get_list_free(struct ethtool_pse_get_list *rsp) -{ - struct ethtool_pse_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp); - } -} - -struct ethtool_pse_get_list * -ethtool_pse_get_dump(struct ynl_sock *ys, struct ethtool_pse_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_pse_get_list); - yds.cb = ethtool_pse_get_rsp_parse; - yds.rsp_cmd = 37; - yds.rsp_policy = ðtool_pse_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_PSE_GET, 1); - ys->req_policy = ðtool_pse_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PSE_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_pse_get_list_free(yds.first); - return NULL; -} - -/* ============== ETHTOOL_MSG_PSE_SET ============== */ -/* ETHTOOL_MSG_PSE_SET - do */ -void ethtool_pse_set_req_free(struct ethtool_pse_set_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -int ethtool_pse_set(struct ynl_sock *ys, struct ethtool_pse_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PSE_SET, 1); - ys->req_policy = ðtool_pse_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PSE_HEADER, &req->header); - if (req->_present.admin_state) - mnl_attr_put_u32(nlh, ETHTOOL_A_PODL_PSE_ADMIN_STATE, req->admin_state); - if (req->_present.admin_control) - mnl_attr_put_u32(nlh, ETHTOOL_A_PODL_PSE_ADMIN_CONTROL, req->admin_control); - if (req->_present.pw_d_status) - mnl_attr_put_u32(nlh, ETHTOOL_A_PODL_PSE_PW_D_STATUS, req->pw_d_status); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_RSS_GET ============== */ -/* ETHTOOL_MSG_RSS_GET - do */ -void ethtool_rss_get_req_free(struct ethtool_rss_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_rss_get_rsp_free(struct ethtool_rss_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp->indir); - free(rsp->hkey); - free(rsp); -} - -int ethtool_rss_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct ethtool_rss_get_rsp *dst; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_RSS_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_RSS_CONTEXT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.context = 1; - dst->context = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RSS_HFUNC) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.hfunc = 1; - dst->hfunc = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_RSS_INDIR) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.indir_len = len; - dst->indir = malloc(len); - memcpy(dst->indir, mnl_attr_get_payload(attr), len); - } else if (type == ETHTOOL_A_RSS_HKEY) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.hkey_len = len; - dst->hkey = malloc(len); - memcpy(dst->hkey, mnl_attr_get_payload(attr), len); - } - } - - return MNL_CB_OK; -} - -struct ethtool_rss_get_rsp * -ethtool_rss_get(struct ynl_sock *ys, struct ethtool_rss_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_rss_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_RSS_GET, 1); - ys->req_policy = ðtool_rss_nest; - yrs.yarg.rsp_policy = ðtool_rss_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_RSS_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_rss_get_rsp_parse; - yrs.rsp_cmd = ETHTOOL_MSG_RSS_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_rss_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_RSS_GET - dump */ -void ethtool_rss_get_list_free(struct ethtool_rss_get_list *rsp) -{ - struct ethtool_rss_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp->obj.indir); - free(rsp->obj.hkey); - free(rsp); - } -} - -struct ethtool_rss_get_list * -ethtool_rss_get_dump(struct ynl_sock *ys, struct ethtool_rss_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_rss_get_list); - yds.cb = ethtool_rss_get_rsp_parse; - yds.rsp_cmd = ETHTOOL_MSG_RSS_GET; - yds.rsp_policy = ðtool_rss_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_RSS_GET, 1); - ys->req_policy = ðtool_rss_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_RSS_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_rss_get_list_free(yds.first); - return NULL; -} - -/* ============== ETHTOOL_MSG_PLCA_GET_CFG ============== */ -/* ETHTOOL_MSG_PLCA_GET_CFG - do */ -void ethtool_plca_get_cfg_req_free(struct ethtool_plca_get_cfg_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_plca_get_cfg_rsp_free(struct ethtool_plca_get_cfg_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp); -} - -int ethtool_plca_get_cfg_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_plca_get_cfg_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_PLCA_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_PLCA_VERSION) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.version = 1; - dst->version = mnl_attr_get_u16(attr); - } else if (type == ETHTOOL_A_PLCA_ENABLED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.enabled = 1; - dst->enabled = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_PLCA_STATUS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.status = 1; - dst->status = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_PLCA_NODE_CNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.node_cnt = 1; - dst->node_cnt = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_PLCA_NODE_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.node_id = 1; - dst->node_id = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_PLCA_TO_TMR) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.to_tmr = 1; - dst->to_tmr = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_PLCA_BURST_CNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.burst_cnt = 1; - dst->burst_cnt = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_PLCA_BURST_TMR) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.burst_tmr = 1; - dst->burst_tmr = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_plca_get_cfg_rsp * -ethtool_plca_get_cfg(struct ynl_sock *ys, struct ethtool_plca_get_cfg_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_plca_get_cfg_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PLCA_GET_CFG, 1); - ys->req_policy = ðtool_plca_nest; - yrs.yarg.rsp_policy = ðtool_plca_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PLCA_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_plca_get_cfg_rsp_parse; - yrs.rsp_cmd = ETHTOOL_MSG_PLCA_GET_CFG; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_plca_get_cfg_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_PLCA_GET_CFG - dump */ -void ethtool_plca_get_cfg_list_free(struct ethtool_plca_get_cfg_list *rsp) -{ - struct ethtool_plca_get_cfg_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp); - } -} - -struct ethtool_plca_get_cfg_list * -ethtool_plca_get_cfg_dump(struct ynl_sock *ys, - struct ethtool_plca_get_cfg_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_plca_get_cfg_list); - yds.cb = ethtool_plca_get_cfg_rsp_parse; - yds.rsp_cmd = ETHTOOL_MSG_PLCA_GET_CFG; - yds.rsp_policy = ðtool_plca_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_PLCA_GET_CFG, 1); - ys->req_policy = ðtool_plca_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PLCA_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_plca_get_cfg_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_PLCA_GET_CFG - notify */ -void ethtool_plca_get_cfg_ntf_free(struct ethtool_plca_get_cfg_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - free(rsp); -} - -/* ============== ETHTOOL_MSG_PLCA_SET_CFG ============== */ -/* ETHTOOL_MSG_PLCA_SET_CFG - do */ -void ethtool_plca_set_cfg_req_free(struct ethtool_plca_set_cfg_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -int ethtool_plca_set_cfg(struct ynl_sock *ys, - struct ethtool_plca_set_cfg_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PLCA_SET_CFG, 1); - ys->req_policy = ðtool_plca_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PLCA_HEADER, &req->header); - if (req->_present.version) - mnl_attr_put_u16(nlh, ETHTOOL_A_PLCA_VERSION, req->version); - if (req->_present.enabled) - mnl_attr_put_u8(nlh, ETHTOOL_A_PLCA_ENABLED, req->enabled); - if (req->_present.status) - mnl_attr_put_u8(nlh, ETHTOOL_A_PLCA_STATUS, req->status); - if (req->_present.node_cnt) - mnl_attr_put_u32(nlh, ETHTOOL_A_PLCA_NODE_CNT, req->node_cnt); - if (req->_present.node_id) - mnl_attr_put_u32(nlh, ETHTOOL_A_PLCA_NODE_ID, req->node_id); - if (req->_present.to_tmr) - mnl_attr_put_u32(nlh, ETHTOOL_A_PLCA_TO_TMR, req->to_tmr); - if (req->_present.burst_cnt) - mnl_attr_put_u32(nlh, ETHTOOL_A_PLCA_BURST_CNT, req->burst_cnt); - if (req->_present.burst_tmr) - mnl_attr_put_u32(nlh, ETHTOOL_A_PLCA_BURST_TMR, req->burst_tmr); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== ETHTOOL_MSG_PLCA_GET_STATUS ============== */ -/* ETHTOOL_MSG_PLCA_GET_STATUS - do */ -void ethtool_plca_get_status_req_free(struct ethtool_plca_get_status_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_plca_get_status_rsp_free(struct ethtool_plca_get_status_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - free(rsp); -} - -int ethtool_plca_get_status_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_plca_get_status_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_PLCA_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_PLCA_VERSION) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.version = 1; - dst->version = mnl_attr_get_u16(attr); - } else if (type == ETHTOOL_A_PLCA_ENABLED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.enabled = 1; - dst->enabled = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_PLCA_STATUS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.status = 1; - dst->status = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_PLCA_NODE_CNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.node_cnt = 1; - dst->node_cnt = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_PLCA_NODE_ID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.node_id = 1; - dst->node_id = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_PLCA_TO_TMR) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.to_tmr = 1; - dst->to_tmr = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_PLCA_BURST_CNT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.burst_cnt = 1; - dst->burst_cnt = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_PLCA_BURST_TMR) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.burst_tmr = 1; - dst->burst_tmr = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct ethtool_plca_get_status_rsp * -ethtool_plca_get_status(struct ynl_sock *ys, - struct ethtool_plca_get_status_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_plca_get_status_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PLCA_GET_STATUS, 1); - ys->req_policy = ðtool_plca_nest; - yrs.yarg.rsp_policy = ðtool_plca_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PLCA_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_plca_get_status_rsp_parse; - yrs.rsp_cmd = 40; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_plca_get_status_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_PLCA_GET_STATUS - dump */ -void -ethtool_plca_get_status_list_free(struct ethtool_plca_get_status_list *rsp) -{ - struct ethtool_plca_get_status_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - free(rsp); - } -} - -struct ethtool_plca_get_status_list * -ethtool_plca_get_status_dump(struct ynl_sock *ys, - struct ethtool_plca_get_status_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_plca_get_status_list); - yds.cb = ethtool_plca_get_status_rsp_parse; - yds.rsp_cmd = 40; - yds.rsp_policy = ðtool_plca_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_PLCA_GET_STATUS, 1); - ys->req_policy = ðtool_plca_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_PLCA_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_plca_get_status_list_free(yds.first); - return NULL; -} - -/* ============== ETHTOOL_MSG_MM_GET ============== */ -/* ETHTOOL_MSG_MM_GET - do */ -void ethtool_mm_get_req_free(struct ethtool_mm_get_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -void ethtool_mm_get_rsp_free(struct ethtool_mm_get_rsp *rsp) -{ - ethtool_header_free(&rsp->header); - ethtool_mm_stat_free(&rsp->stats); - free(rsp); -} - -int ethtool_mm_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct ethtool_mm_get_rsp *dst; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_MM_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_MM_PMAC_ENABLED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.pmac_enabled = 1; - dst->pmac_enabled = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_MM_TX_ENABLED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_enabled = 1; - dst->tx_enabled = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_MM_TX_ACTIVE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_active = 1; - dst->tx_active = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_MM_TX_MIN_FRAG_SIZE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.tx_min_frag_size = 1; - dst->tx_min_frag_size = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_MM_RX_MIN_FRAG_SIZE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.rx_min_frag_size = 1; - dst->rx_min_frag_size = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_MM_VERIFY_ENABLED) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.verify_enabled = 1; - dst->verify_enabled = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_MM_VERIFY_TIME) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.verify_time = 1; - dst->verify_time = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_MM_MAX_VERIFY_TIME) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.max_verify_time = 1; - dst->max_verify_time = mnl_attr_get_u32(attr); - } else if (type == ETHTOOL_A_MM_STATS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.stats = 1; - - parg.rsp_policy = ðtool_mm_stat_nest; - parg.data = &dst->stats; - if (ethtool_mm_stat_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -struct ethtool_mm_get_rsp * -ethtool_mm_get(struct ynl_sock *ys, struct ethtool_mm_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct ethtool_mm_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_MM_GET, 1); - ys->req_policy = ðtool_mm_nest; - yrs.yarg.rsp_policy = ðtool_mm_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_MM_HEADER, &req->header); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = ethtool_mm_get_rsp_parse; - yrs.rsp_cmd = ETHTOOL_MSG_MM_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - ethtool_mm_get_rsp_free(rsp); - return NULL; -} - -/* ETHTOOL_MSG_MM_GET - dump */ -void ethtool_mm_get_list_free(struct ethtool_mm_get_list *rsp) -{ - struct ethtool_mm_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - ethtool_header_free(&rsp->obj.header); - ethtool_mm_stat_free(&rsp->obj.stats); - free(rsp); - } -} - -struct ethtool_mm_get_list * -ethtool_mm_get_dump(struct ynl_sock *ys, struct ethtool_mm_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct ethtool_mm_get_list); - yds.cb = ethtool_mm_get_rsp_parse; - yds.rsp_cmd = ETHTOOL_MSG_MM_GET; - yds.rsp_policy = ðtool_mm_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_MM_GET, 1); - ys->req_policy = ðtool_mm_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_MM_HEADER, &req->header); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - ethtool_mm_get_list_free(yds.first); - return NULL; -} - -/* ETHTOOL_MSG_MM_GET - notify */ -void ethtool_mm_get_ntf_free(struct ethtool_mm_get_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - ethtool_mm_stat_free(&rsp->obj.stats); - free(rsp); -} - -/* ============== ETHTOOL_MSG_MM_SET ============== */ -/* ETHTOOL_MSG_MM_SET - do */ -void ethtool_mm_set_req_free(struct ethtool_mm_set_req *req) -{ - ethtool_header_free(&req->header); - free(req); -} - -int ethtool_mm_set(struct ynl_sock *ys, struct ethtool_mm_set_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_MM_SET, 1); - ys->req_policy = ðtool_mm_nest; - - if (req->_present.header) - ethtool_header_put(nlh, ETHTOOL_A_MM_HEADER, &req->header); - if (req->_present.verify_enabled) - mnl_attr_put_u8(nlh, ETHTOOL_A_MM_VERIFY_ENABLED, req->verify_enabled); - if (req->_present.verify_time) - mnl_attr_put_u32(nlh, ETHTOOL_A_MM_VERIFY_TIME, req->verify_time); - if (req->_present.tx_enabled) - mnl_attr_put_u8(nlh, ETHTOOL_A_MM_TX_ENABLED, req->tx_enabled); - if (req->_present.pmac_enabled) - mnl_attr_put_u8(nlh, ETHTOOL_A_MM_PMAC_ENABLED, req->pmac_enabled); - if (req->_present.tx_min_frag_size) - mnl_attr_put_u32(nlh, ETHTOOL_A_MM_TX_MIN_FRAG_SIZE, req->tx_min_frag_size); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ETHTOOL_MSG_CABLE_TEST_NTF - event */ -int ethtool_cable_test_ntf_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ethtool_cable_test_ntf_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_CABLE_TEST_NTF_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_CABLE_TEST_NTF_STATUS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.status = 1; - dst->status = mnl_attr_get_u8(attr); - } - } - - return MNL_CB_OK; -} - -void ethtool_cable_test_ntf_free(struct ethtool_cable_test_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - free(rsp); -} - -/* ETHTOOL_MSG_CABLE_TEST_TDR_NTF - event */ -int ethtool_cable_test_tdr_ntf_rsp_parse(const struct nlmsghdr *nlh, - void *data) -{ - struct ethtool_cable_test_tdr_ntf_rsp *dst; - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct ynl_parse_arg parg; - - dst = yarg->data; - parg.ys = yarg->ys; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == ETHTOOL_A_CABLE_TEST_TDR_NTF_HEADER) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.header = 1; - - parg.rsp_policy = ðtool_header_nest; - parg.data = &dst->header; - if (ethtool_header_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == ETHTOOL_A_CABLE_TEST_TDR_NTF_STATUS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.status = 1; - dst->status = mnl_attr_get_u8(attr); - } else if (type == ETHTOOL_A_CABLE_TEST_TDR_NTF_NEST) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.nest = 1; - - parg.rsp_policy = ðtool_cable_nest_nest; - parg.data = &dst->nest; - if (ethtool_cable_nest_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } - - return MNL_CB_OK; -} - -void ethtool_cable_test_tdr_ntf_free(struct ethtool_cable_test_tdr_ntf *rsp) -{ - ethtool_header_free(&rsp->obj.header); - ethtool_cable_nest_free(&rsp->obj.nest); - free(rsp); -} - -static const struct ynl_ntf_info ethtool_ntf_info[] = { - [ETHTOOL_MSG_LINKINFO_NTF] = { - .alloc_sz = sizeof(struct ethtool_linkinfo_get_ntf), - .cb = ethtool_linkinfo_get_rsp_parse, - .policy = ðtool_linkinfo_nest, - .free = (void *)ethtool_linkinfo_get_ntf_free, - }, - [ETHTOOL_MSG_LINKMODES_NTF] = { - .alloc_sz = sizeof(struct ethtool_linkmodes_get_ntf), - .cb = ethtool_linkmodes_get_rsp_parse, - .policy = ðtool_linkmodes_nest, - .free = (void *)ethtool_linkmodes_get_ntf_free, - }, - [ETHTOOL_MSG_DEBUG_NTF] = { - .alloc_sz = sizeof(struct ethtool_debug_get_ntf), - .cb = ethtool_debug_get_rsp_parse, - .policy = ðtool_debug_nest, - .free = (void *)ethtool_debug_get_ntf_free, - }, - [ETHTOOL_MSG_WOL_NTF] = { - .alloc_sz = sizeof(struct ethtool_wol_get_ntf), - .cb = ethtool_wol_get_rsp_parse, - .policy = ðtool_wol_nest, - .free = (void *)ethtool_wol_get_ntf_free, - }, - [ETHTOOL_MSG_FEATURES_NTF] = { - .alloc_sz = sizeof(struct ethtool_features_get_ntf), - .cb = ethtool_features_get_rsp_parse, - .policy = ðtool_features_nest, - .free = (void *)ethtool_features_get_ntf_free, - }, - [ETHTOOL_MSG_PRIVFLAGS_NTF] = { - .alloc_sz = sizeof(struct ethtool_privflags_get_ntf), - .cb = ethtool_privflags_get_rsp_parse, - .policy = ðtool_privflags_nest, - .free = (void *)ethtool_privflags_get_ntf_free, - }, - [ETHTOOL_MSG_RINGS_NTF] = { - .alloc_sz = sizeof(struct ethtool_rings_get_ntf), - .cb = ethtool_rings_get_rsp_parse, - .policy = ðtool_rings_nest, - .free = (void *)ethtool_rings_get_ntf_free, - }, - [ETHTOOL_MSG_CHANNELS_NTF] = { - .alloc_sz = sizeof(struct ethtool_channels_get_ntf), - .cb = ethtool_channels_get_rsp_parse, - .policy = ðtool_channels_nest, - .free = (void *)ethtool_channels_get_ntf_free, - }, - [ETHTOOL_MSG_COALESCE_NTF] = { - .alloc_sz = sizeof(struct ethtool_coalesce_get_ntf), - .cb = ethtool_coalesce_get_rsp_parse, - .policy = ðtool_coalesce_nest, - .free = (void *)ethtool_coalesce_get_ntf_free, - }, - [ETHTOOL_MSG_PAUSE_NTF] = { - .alloc_sz = sizeof(struct ethtool_pause_get_ntf), - .cb = ethtool_pause_get_rsp_parse, - .policy = ðtool_pause_nest, - .free = (void *)ethtool_pause_get_ntf_free, - }, - [ETHTOOL_MSG_EEE_NTF] = { - .alloc_sz = sizeof(struct ethtool_eee_get_ntf), - .cb = ethtool_eee_get_rsp_parse, - .policy = ðtool_eee_nest, - .free = (void *)ethtool_eee_get_ntf_free, - }, - [ETHTOOL_MSG_CABLE_TEST_NTF] = { - .alloc_sz = sizeof(struct ethtool_cable_test_ntf), - .cb = ethtool_cable_test_ntf_rsp_parse, - .policy = ðtool_cable_test_ntf_nest, - .free = (void *)ethtool_cable_test_ntf_free, - }, - [ETHTOOL_MSG_CABLE_TEST_TDR_NTF] = { - .alloc_sz = sizeof(struct ethtool_cable_test_tdr_ntf), - .cb = ethtool_cable_test_tdr_ntf_rsp_parse, - .policy = ðtool_cable_test_tdr_ntf_nest, - .free = (void *)ethtool_cable_test_tdr_ntf_free, - }, - [ETHTOOL_MSG_FEC_NTF] = { - .alloc_sz = sizeof(struct ethtool_fec_get_ntf), - .cb = ethtool_fec_get_rsp_parse, - .policy = ðtool_fec_nest, - .free = (void *)ethtool_fec_get_ntf_free, - }, - [ETHTOOL_MSG_MODULE_NTF] = { - .alloc_sz = sizeof(struct ethtool_module_get_ntf), - .cb = ethtool_module_get_rsp_parse, - .policy = ðtool_module_nest, - .free = (void *)ethtool_module_get_ntf_free, - }, - [ETHTOOL_MSG_PLCA_NTF] = { - .alloc_sz = sizeof(struct ethtool_plca_get_cfg_ntf), - .cb = ethtool_plca_get_cfg_rsp_parse, - .policy = ðtool_plca_nest, - .free = (void *)ethtool_plca_get_cfg_ntf_free, - }, - [ETHTOOL_MSG_MM_NTF] = { - .alloc_sz = sizeof(struct ethtool_mm_get_ntf), - .cb = ethtool_mm_get_rsp_parse, - .policy = ðtool_mm_nest, - .free = (void *)ethtool_mm_get_ntf_free, - }, -}; - -const struct ynl_family ynl_ethtool_family = { - .name = "ethtool", - .ntf_info = ethtool_ntf_info, - .ntf_info_size = MNL_ARRAY_SIZE(ethtool_ntf_info), -}; diff --git a/tools/net/ynl/generated/ethtool-user.h b/tools/net/ynl/generated/ethtool-user.h deleted file mode 100644 index ca0ec5fd77..0000000000 --- a/tools/net/ynl/generated/ethtool-user.h +++ /dev/null @@ -1,5535 +0,0 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/ethtool.yaml */ -/* YNL-GEN user header */ -/* YNL-ARG --user-header linux/ethtool_netlink.h --exclude-op stats-get */ - -#ifndef _LINUX_ETHTOOL_GEN_H -#define _LINUX_ETHTOOL_GEN_H - -#include -#include -#include -#include - -struct ynl_sock; - -extern const struct ynl_family ynl_ethtool_family; - -/* Enums */ -const char *ethtool_op_str(int op); -const char *ethtool_udp_tunnel_type_str(int value); -const char *ethtool_stringset_str(enum ethtool_stringset value); - -/* Common nested types */ -struct ethtool_header { - struct { - __u32 dev_index:1; - __u32 dev_name_len; - __u32 flags:1; - } _present; - - __u32 dev_index; - char *dev_name; - __u32 flags; -}; - -struct ethtool_pause_stat { - struct { - __u32 tx_frames:1; - __u32 rx_frames:1; - } _present; - - __u64 tx_frames; - __u64 rx_frames; -}; - -struct ethtool_cable_test_tdr_cfg { - struct { - __u32 first:1; - __u32 last:1; - __u32 step:1; - __u32 pair:1; - } _present; - - __u32 first; - __u32 last; - __u32 step; - __u8 pair; -}; - -struct ethtool_fec_stat { - struct { - __u32 corrected_len; - __u32 uncorr_len; - __u32 corr_bits_len; - } _present; - - void *corrected; - void *uncorr; - void *corr_bits; -}; - -struct ethtool_mm_stat { - struct { - __u32 reassembly_errors:1; - __u32 smd_errors:1; - __u32 reassembly_ok:1; - __u32 rx_frag_count:1; - __u32 tx_frag_count:1; - __u32 hold_count:1; - } _present; - - __u64 reassembly_errors; - __u64 smd_errors; - __u64 reassembly_ok; - __u64 rx_frag_count; - __u64 tx_frag_count; - __u64 hold_count; -}; - -struct ethtool_cable_result { - struct { - __u32 pair:1; - __u32 code:1; - } _present; - - __u8 pair; - __u8 code; -}; - -struct ethtool_cable_fault_length { - struct { - __u32 pair:1; - __u32 cm:1; - } _present; - - __u8 pair; - __u32 cm; -}; - -struct ethtool_bitset_bit { - struct { - __u32 index:1; - __u32 name_len; - __u32 value:1; - } _present; - - __u32 index; - char *name; -}; - -struct ethtool_tunnel_udp_entry { - struct { - __u32 port:1; - __u32 type:1; - } _present; - - __u16 port /* big-endian */; - __u32 type; -}; - -struct ethtool_string { - struct { - __u32 index:1; - __u32 value_len; - } _present; - - __u32 index; - char *value; -}; - -struct ethtool_cable_nest { - struct { - __u32 result:1; - __u32 fault_length:1; - } _present; - - struct ethtool_cable_result result; - struct ethtool_cable_fault_length fault_length; -}; - -struct ethtool_bitset_bits { - unsigned int n_bit; - struct ethtool_bitset_bit *bit; -}; - -struct ethtool_strings { - unsigned int n_string; - struct ethtool_string *string; -}; - -struct ethtool_bitset { - struct { - __u32 nomask:1; - __u32 size:1; - __u32 bits:1; - } _present; - - __u32 size; - struct ethtool_bitset_bits bits; -}; - -struct ethtool_stringset_ { - struct { - __u32 id:1; - __u32 count:1; - } _present; - - __u32 id; - __u32 count; - unsigned int n_strings; - struct ethtool_strings *strings; -}; - -struct ethtool_tunnel_udp_table { - struct { - __u32 size:1; - __u32 types:1; - } _present; - - __u32 size; - struct ethtool_bitset types; - unsigned int n_entry; - struct ethtool_tunnel_udp_entry *entry; -}; - -struct ethtool_stringsets { - unsigned int n_stringset; - struct ethtool_stringset_ *stringset; -}; - -struct ethtool_tunnel_udp { - struct { - __u32 table:1; - } _present; - - struct ethtool_tunnel_udp_table table; -}; - -/* ============== ETHTOOL_MSG_STRSET_GET ============== */ -/* ETHTOOL_MSG_STRSET_GET - do */ -struct ethtool_strset_get_req { - struct { - __u32 header:1; - __u32 stringsets:1; - __u32 counts_only:1; - } _present; - - struct ethtool_header header; - struct ethtool_stringsets stringsets; -}; - -static inline struct ethtool_strset_get_req *ethtool_strset_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_strset_get_req)); -} -void ethtool_strset_get_req_free(struct ethtool_strset_get_req *req); - -static inline void -ethtool_strset_get_req_set_header_dev_index(struct ethtool_strset_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_strset_get_req_set_header_dev_name(struct ethtool_strset_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_strset_get_req_set_header_flags(struct ethtool_strset_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -__ethtool_strset_get_req_set_stringsets_stringset(struct ethtool_strset_get_req *req, - struct ethtool_stringset_ *stringset, - unsigned int n_stringset) -{ - free(req->stringsets.stringset); - req->stringsets.stringset = stringset; - req->stringsets.n_stringset = n_stringset; -} -static inline void -ethtool_strset_get_req_set_counts_only(struct ethtool_strset_get_req *req) -{ - req->_present.counts_only = 1; -} - -struct ethtool_strset_get_rsp { - struct { - __u32 header:1; - __u32 stringsets:1; - } _present; - - struct ethtool_header header; - struct ethtool_stringsets stringsets; -}; - -void ethtool_strset_get_rsp_free(struct ethtool_strset_get_rsp *rsp); - -/* - * Get string set from the kernel. - */ -struct ethtool_strset_get_rsp * -ethtool_strset_get(struct ynl_sock *ys, struct ethtool_strset_get_req *req); - -/* ETHTOOL_MSG_STRSET_GET - dump */ -struct ethtool_strset_get_req_dump { - struct { - __u32 header:1; - __u32 stringsets:1; - __u32 counts_only:1; - } _present; - - struct ethtool_header header; - struct ethtool_stringsets stringsets; -}; - -static inline struct ethtool_strset_get_req_dump * -ethtool_strset_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_strset_get_req_dump)); -} -void ethtool_strset_get_req_dump_free(struct ethtool_strset_get_req_dump *req); - -static inline void -ethtool_strset_get_req_dump_set_header_dev_index(struct ethtool_strset_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_strset_get_req_dump_set_header_dev_name(struct ethtool_strset_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_strset_get_req_dump_set_header_flags(struct ethtool_strset_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -__ethtool_strset_get_req_dump_set_stringsets_stringset(struct ethtool_strset_get_req_dump *req, - struct ethtool_stringset_ *stringset, - unsigned int n_stringset) -{ - free(req->stringsets.stringset); - req->stringsets.stringset = stringset; - req->stringsets.n_stringset = n_stringset; -} -static inline void -ethtool_strset_get_req_dump_set_counts_only(struct ethtool_strset_get_req_dump *req) -{ - req->_present.counts_only = 1; -} - -struct ethtool_strset_get_list { - struct ethtool_strset_get_list *next; - struct ethtool_strset_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_strset_get_list_free(struct ethtool_strset_get_list *rsp); - -struct ethtool_strset_get_list * -ethtool_strset_get_dump(struct ynl_sock *ys, - struct ethtool_strset_get_req_dump *req); - -/* ============== ETHTOOL_MSG_LINKINFO_GET ============== */ -/* ETHTOOL_MSG_LINKINFO_GET - do */ -struct ethtool_linkinfo_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_linkinfo_get_req * -ethtool_linkinfo_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_linkinfo_get_req)); -} -void ethtool_linkinfo_get_req_free(struct ethtool_linkinfo_get_req *req); - -static inline void -ethtool_linkinfo_get_req_set_header_dev_index(struct ethtool_linkinfo_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_linkinfo_get_req_set_header_dev_name(struct ethtool_linkinfo_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_linkinfo_get_req_set_header_flags(struct ethtool_linkinfo_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_linkinfo_get_rsp { - struct { - __u32 header:1; - __u32 port:1; - __u32 phyaddr:1; - __u32 tp_mdix:1; - __u32 tp_mdix_ctrl:1; - __u32 transceiver:1; - } _present; - - struct ethtool_header header; - __u8 port; - __u8 phyaddr; - __u8 tp_mdix; - __u8 tp_mdix_ctrl; - __u8 transceiver; -}; - -void ethtool_linkinfo_get_rsp_free(struct ethtool_linkinfo_get_rsp *rsp); - -/* - * Get link info. - */ -struct ethtool_linkinfo_get_rsp * -ethtool_linkinfo_get(struct ynl_sock *ys, struct ethtool_linkinfo_get_req *req); - -/* ETHTOOL_MSG_LINKINFO_GET - dump */ -struct ethtool_linkinfo_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_linkinfo_get_req_dump * -ethtool_linkinfo_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_linkinfo_get_req_dump)); -} -void -ethtool_linkinfo_get_req_dump_free(struct ethtool_linkinfo_get_req_dump *req); - -static inline void -ethtool_linkinfo_get_req_dump_set_header_dev_index(struct ethtool_linkinfo_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_linkinfo_get_req_dump_set_header_dev_name(struct ethtool_linkinfo_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_linkinfo_get_req_dump_set_header_flags(struct ethtool_linkinfo_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_linkinfo_get_list { - struct ethtool_linkinfo_get_list *next; - struct ethtool_linkinfo_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_linkinfo_get_list_free(struct ethtool_linkinfo_get_list *rsp); - -struct ethtool_linkinfo_get_list * -ethtool_linkinfo_get_dump(struct ynl_sock *ys, - struct ethtool_linkinfo_get_req_dump *req); - -/* ETHTOOL_MSG_LINKINFO_GET - notify */ -struct ethtool_linkinfo_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_linkinfo_get_ntf *ntf); - struct ethtool_linkinfo_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_linkinfo_get_ntf_free(struct ethtool_linkinfo_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_LINKINFO_SET ============== */ -/* ETHTOOL_MSG_LINKINFO_SET - do */ -struct ethtool_linkinfo_set_req { - struct { - __u32 header:1; - __u32 port:1; - __u32 phyaddr:1; - __u32 tp_mdix:1; - __u32 tp_mdix_ctrl:1; - __u32 transceiver:1; - } _present; - - struct ethtool_header header; - __u8 port; - __u8 phyaddr; - __u8 tp_mdix; - __u8 tp_mdix_ctrl; - __u8 transceiver; -}; - -static inline struct ethtool_linkinfo_set_req * -ethtool_linkinfo_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_linkinfo_set_req)); -} -void ethtool_linkinfo_set_req_free(struct ethtool_linkinfo_set_req *req); - -static inline void -ethtool_linkinfo_set_req_set_header_dev_index(struct ethtool_linkinfo_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_linkinfo_set_req_set_header_dev_name(struct ethtool_linkinfo_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_linkinfo_set_req_set_header_flags(struct ethtool_linkinfo_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_linkinfo_set_req_set_port(struct ethtool_linkinfo_set_req *req, - __u8 port) -{ - req->_present.port = 1; - req->port = port; -} -static inline void -ethtool_linkinfo_set_req_set_phyaddr(struct ethtool_linkinfo_set_req *req, - __u8 phyaddr) -{ - req->_present.phyaddr = 1; - req->phyaddr = phyaddr; -} -static inline void -ethtool_linkinfo_set_req_set_tp_mdix(struct ethtool_linkinfo_set_req *req, - __u8 tp_mdix) -{ - req->_present.tp_mdix = 1; - req->tp_mdix = tp_mdix; -} -static inline void -ethtool_linkinfo_set_req_set_tp_mdix_ctrl(struct ethtool_linkinfo_set_req *req, - __u8 tp_mdix_ctrl) -{ - req->_present.tp_mdix_ctrl = 1; - req->tp_mdix_ctrl = tp_mdix_ctrl; -} -static inline void -ethtool_linkinfo_set_req_set_transceiver(struct ethtool_linkinfo_set_req *req, - __u8 transceiver) -{ - req->_present.transceiver = 1; - req->transceiver = transceiver; -} - -/* - * Set link info. - */ -int ethtool_linkinfo_set(struct ynl_sock *ys, - struct ethtool_linkinfo_set_req *req); - -/* ============== ETHTOOL_MSG_LINKMODES_GET ============== */ -/* ETHTOOL_MSG_LINKMODES_GET - do */ -struct ethtool_linkmodes_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_linkmodes_get_req * -ethtool_linkmodes_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_linkmodes_get_req)); -} -void ethtool_linkmodes_get_req_free(struct ethtool_linkmodes_get_req *req); - -static inline void -ethtool_linkmodes_get_req_set_header_dev_index(struct ethtool_linkmodes_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_linkmodes_get_req_set_header_dev_name(struct ethtool_linkmodes_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_linkmodes_get_req_set_header_flags(struct ethtool_linkmodes_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_linkmodes_get_rsp { - struct { - __u32 header:1; - __u32 autoneg:1; - __u32 ours:1; - __u32 peer:1; - __u32 speed:1; - __u32 duplex:1; - __u32 master_slave_cfg:1; - __u32 master_slave_state:1; - __u32 lanes:1; - __u32 rate_matching:1; - } _present; - - struct ethtool_header header; - __u8 autoneg; - struct ethtool_bitset ours; - struct ethtool_bitset peer; - __u32 speed; - __u8 duplex; - __u8 master_slave_cfg; - __u8 master_slave_state; - __u32 lanes; - __u8 rate_matching; -}; - -void ethtool_linkmodes_get_rsp_free(struct ethtool_linkmodes_get_rsp *rsp); - -/* - * Get link modes. - */ -struct ethtool_linkmodes_get_rsp * -ethtool_linkmodes_get(struct ynl_sock *ys, - struct ethtool_linkmodes_get_req *req); - -/* ETHTOOL_MSG_LINKMODES_GET - dump */ -struct ethtool_linkmodes_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_linkmodes_get_req_dump * -ethtool_linkmodes_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_linkmodes_get_req_dump)); -} -void -ethtool_linkmodes_get_req_dump_free(struct ethtool_linkmodes_get_req_dump *req); - -static inline void -ethtool_linkmodes_get_req_dump_set_header_dev_index(struct ethtool_linkmodes_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_linkmodes_get_req_dump_set_header_dev_name(struct ethtool_linkmodes_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_linkmodes_get_req_dump_set_header_flags(struct ethtool_linkmodes_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_linkmodes_get_list { - struct ethtool_linkmodes_get_list *next; - struct ethtool_linkmodes_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_linkmodes_get_list_free(struct ethtool_linkmodes_get_list *rsp); - -struct ethtool_linkmodes_get_list * -ethtool_linkmodes_get_dump(struct ynl_sock *ys, - struct ethtool_linkmodes_get_req_dump *req); - -/* ETHTOOL_MSG_LINKMODES_GET - notify */ -struct ethtool_linkmodes_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_linkmodes_get_ntf *ntf); - struct ethtool_linkmodes_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_linkmodes_get_ntf_free(struct ethtool_linkmodes_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_LINKMODES_SET ============== */ -/* ETHTOOL_MSG_LINKMODES_SET - do */ -struct ethtool_linkmodes_set_req { - struct { - __u32 header:1; - __u32 autoneg:1; - __u32 ours:1; - __u32 peer:1; - __u32 speed:1; - __u32 duplex:1; - __u32 master_slave_cfg:1; - __u32 master_slave_state:1; - __u32 lanes:1; - __u32 rate_matching:1; - } _present; - - struct ethtool_header header; - __u8 autoneg; - struct ethtool_bitset ours; - struct ethtool_bitset peer; - __u32 speed; - __u8 duplex; - __u8 master_slave_cfg; - __u8 master_slave_state; - __u32 lanes; - __u8 rate_matching; -}; - -static inline struct ethtool_linkmodes_set_req * -ethtool_linkmodes_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_linkmodes_set_req)); -} -void ethtool_linkmodes_set_req_free(struct ethtool_linkmodes_set_req *req); - -static inline void -ethtool_linkmodes_set_req_set_header_dev_index(struct ethtool_linkmodes_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_linkmodes_set_req_set_header_dev_name(struct ethtool_linkmodes_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_linkmodes_set_req_set_header_flags(struct ethtool_linkmodes_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_linkmodes_set_req_set_autoneg(struct ethtool_linkmodes_set_req *req, - __u8 autoneg) -{ - req->_present.autoneg = 1; - req->autoneg = autoneg; -} -static inline void -ethtool_linkmodes_set_req_set_ours_nomask(struct ethtool_linkmodes_set_req *req) -{ - req->_present.ours = 1; - req->ours._present.nomask = 1; -} -static inline void -ethtool_linkmodes_set_req_set_ours_size(struct ethtool_linkmodes_set_req *req, - __u32 size) -{ - req->_present.ours = 1; - req->ours._present.size = 1; - req->ours.size = size; -} -static inline void -__ethtool_linkmodes_set_req_set_ours_bits_bit(struct ethtool_linkmodes_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->ours.bits.bit); - req->ours.bits.bit = bit; - req->ours.bits.n_bit = n_bit; -} -static inline void -ethtool_linkmodes_set_req_set_peer_nomask(struct ethtool_linkmodes_set_req *req) -{ - req->_present.peer = 1; - req->peer._present.nomask = 1; -} -static inline void -ethtool_linkmodes_set_req_set_peer_size(struct ethtool_linkmodes_set_req *req, - __u32 size) -{ - req->_present.peer = 1; - req->peer._present.size = 1; - req->peer.size = size; -} -static inline void -__ethtool_linkmodes_set_req_set_peer_bits_bit(struct ethtool_linkmodes_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->peer.bits.bit); - req->peer.bits.bit = bit; - req->peer.bits.n_bit = n_bit; -} -static inline void -ethtool_linkmodes_set_req_set_speed(struct ethtool_linkmodes_set_req *req, - __u32 speed) -{ - req->_present.speed = 1; - req->speed = speed; -} -static inline void -ethtool_linkmodes_set_req_set_duplex(struct ethtool_linkmodes_set_req *req, - __u8 duplex) -{ - req->_present.duplex = 1; - req->duplex = duplex; -} -static inline void -ethtool_linkmodes_set_req_set_master_slave_cfg(struct ethtool_linkmodes_set_req *req, - __u8 master_slave_cfg) -{ - req->_present.master_slave_cfg = 1; - req->master_slave_cfg = master_slave_cfg; -} -static inline void -ethtool_linkmodes_set_req_set_master_slave_state(struct ethtool_linkmodes_set_req *req, - __u8 master_slave_state) -{ - req->_present.master_slave_state = 1; - req->master_slave_state = master_slave_state; -} -static inline void -ethtool_linkmodes_set_req_set_lanes(struct ethtool_linkmodes_set_req *req, - __u32 lanes) -{ - req->_present.lanes = 1; - req->lanes = lanes; -} -static inline void -ethtool_linkmodes_set_req_set_rate_matching(struct ethtool_linkmodes_set_req *req, - __u8 rate_matching) -{ - req->_present.rate_matching = 1; - req->rate_matching = rate_matching; -} - -/* - * Set link modes. - */ -int ethtool_linkmodes_set(struct ynl_sock *ys, - struct ethtool_linkmodes_set_req *req); - -/* ============== ETHTOOL_MSG_LINKSTATE_GET ============== */ -/* ETHTOOL_MSG_LINKSTATE_GET - do */ -struct ethtool_linkstate_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_linkstate_get_req * -ethtool_linkstate_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_linkstate_get_req)); -} -void ethtool_linkstate_get_req_free(struct ethtool_linkstate_get_req *req); - -static inline void -ethtool_linkstate_get_req_set_header_dev_index(struct ethtool_linkstate_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_linkstate_get_req_set_header_dev_name(struct ethtool_linkstate_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_linkstate_get_req_set_header_flags(struct ethtool_linkstate_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_linkstate_get_rsp { - struct { - __u32 header:1; - __u32 link:1; - __u32 sqi:1; - __u32 sqi_max:1; - __u32 ext_state:1; - __u32 ext_substate:1; - __u32 ext_down_cnt:1; - } _present; - - struct ethtool_header header; - __u8 link; - __u32 sqi; - __u32 sqi_max; - __u8 ext_state; - __u8 ext_substate; - __u32 ext_down_cnt; -}; - -void ethtool_linkstate_get_rsp_free(struct ethtool_linkstate_get_rsp *rsp); - -/* - * Get link state. - */ -struct ethtool_linkstate_get_rsp * -ethtool_linkstate_get(struct ynl_sock *ys, - struct ethtool_linkstate_get_req *req); - -/* ETHTOOL_MSG_LINKSTATE_GET - dump */ -struct ethtool_linkstate_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_linkstate_get_req_dump * -ethtool_linkstate_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_linkstate_get_req_dump)); -} -void -ethtool_linkstate_get_req_dump_free(struct ethtool_linkstate_get_req_dump *req); - -static inline void -ethtool_linkstate_get_req_dump_set_header_dev_index(struct ethtool_linkstate_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_linkstate_get_req_dump_set_header_dev_name(struct ethtool_linkstate_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_linkstate_get_req_dump_set_header_flags(struct ethtool_linkstate_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_linkstate_get_list { - struct ethtool_linkstate_get_list *next; - struct ethtool_linkstate_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_linkstate_get_list_free(struct ethtool_linkstate_get_list *rsp); - -struct ethtool_linkstate_get_list * -ethtool_linkstate_get_dump(struct ynl_sock *ys, - struct ethtool_linkstate_get_req_dump *req); - -/* ============== ETHTOOL_MSG_DEBUG_GET ============== */ -/* ETHTOOL_MSG_DEBUG_GET - do */ -struct ethtool_debug_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_debug_get_req *ethtool_debug_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_debug_get_req)); -} -void ethtool_debug_get_req_free(struct ethtool_debug_get_req *req); - -static inline void -ethtool_debug_get_req_set_header_dev_index(struct ethtool_debug_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_debug_get_req_set_header_dev_name(struct ethtool_debug_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_debug_get_req_set_header_flags(struct ethtool_debug_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_debug_get_rsp { - struct { - __u32 header:1; - __u32 msgmask:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset msgmask; -}; - -void ethtool_debug_get_rsp_free(struct ethtool_debug_get_rsp *rsp); - -/* - * Get debug message mask. - */ -struct ethtool_debug_get_rsp * -ethtool_debug_get(struct ynl_sock *ys, struct ethtool_debug_get_req *req); - -/* ETHTOOL_MSG_DEBUG_GET - dump */ -struct ethtool_debug_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_debug_get_req_dump * -ethtool_debug_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_debug_get_req_dump)); -} -void ethtool_debug_get_req_dump_free(struct ethtool_debug_get_req_dump *req); - -static inline void -ethtool_debug_get_req_dump_set_header_dev_index(struct ethtool_debug_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_debug_get_req_dump_set_header_dev_name(struct ethtool_debug_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_debug_get_req_dump_set_header_flags(struct ethtool_debug_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_debug_get_list { - struct ethtool_debug_get_list *next; - struct ethtool_debug_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_debug_get_list_free(struct ethtool_debug_get_list *rsp); - -struct ethtool_debug_get_list * -ethtool_debug_get_dump(struct ynl_sock *ys, - struct ethtool_debug_get_req_dump *req); - -/* ETHTOOL_MSG_DEBUG_GET - notify */ -struct ethtool_debug_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_debug_get_ntf *ntf); - struct ethtool_debug_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_debug_get_ntf_free(struct ethtool_debug_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_DEBUG_SET ============== */ -/* ETHTOOL_MSG_DEBUG_SET - do */ -struct ethtool_debug_set_req { - struct { - __u32 header:1; - __u32 msgmask:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset msgmask; -}; - -static inline struct ethtool_debug_set_req *ethtool_debug_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_debug_set_req)); -} -void ethtool_debug_set_req_free(struct ethtool_debug_set_req *req); - -static inline void -ethtool_debug_set_req_set_header_dev_index(struct ethtool_debug_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_debug_set_req_set_header_dev_name(struct ethtool_debug_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_debug_set_req_set_header_flags(struct ethtool_debug_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_debug_set_req_set_msgmask_nomask(struct ethtool_debug_set_req *req) -{ - req->_present.msgmask = 1; - req->msgmask._present.nomask = 1; -} -static inline void -ethtool_debug_set_req_set_msgmask_size(struct ethtool_debug_set_req *req, - __u32 size) -{ - req->_present.msgmask = 1; - req->msgmask._present.size = 1; - req->msgmask.size = size; -} -static inline void -__ethtool_debug_set_req_set_msgmask_bits_bit(struct ethtool_debug_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->msgmask.bits.bit); - req->msgmask.bits.bit = bit; - req->msgmask.bits.n_bit = n_bit; -} - -/* - * Set debug message mask. - */ -int ethtool_debug_set(struct ynl_sock *ys, struct ethtool_debug_set_req *req); - -/* ============== ETHTOOL_MSG_WOL_GET ============== */ -/* ETHTOOL_MSG_WOL_GET - do */ -struct ethtool_wol_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_wol_get_req *ethtool_wol_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_wol_get_req)); -} -void ethtool_wol_get_req_free(struct ethtool_wol_get_req *req); - -static inline void -ethtool_wol_get_req_set_header_dev_index(struct ethtool_wol_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_wol_get_req_set_header_dev_name(struct ethtool_wol_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_wol_get_req_set_header_flags(struct ethtool_wol_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_wol_get_rsp { - struct { - __u32 header:1; - __u32 modes:1; - __u32 sopass_len; - } _present; - - struct ethtool_header header; - struct ethtool_bitset modes; - void *sopass; -}; - -void ethtool_wol_get_rsp_free(struct ethtool_wol_get_rsp *rsp); - -/* - * Get WOL params. - */ -struct ethtool_wol_get_rsp * -ethtool_wol_get(struct ynl_sock *ys, struct ethtool_wol_get_req *req); - -/* ETHTOOL_MSG_WOL_GET - dump */ -struct ethtool_wol_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_wol_get_req_dump * -ethtool_wol_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_wol_get_req_dump)); -} -void ethtool_wol_get_req_dump_free(struct ethtool_wol_get_req_dump *req); - -static inline void -ethtool_wol_get_req_dump_set_header_dev_index(struct ethtool_wol_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_wol_get_req_dump_set_header_dev_name(struct ethtool_wol_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_wol_get_req_dump_set_header_flags(struct ethtool_wol_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_wol_get_list { - struct ethtool_wol_get_list *next; - struct ethtool_wol_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_wol_get_list_free(struct ethtool_wol_get_list *rsp); - -struct ethtool_wol_get_list * -ethtool_wol_get_dump(struct ynl_sock *ys, struct ethtool_wol_get_req_dump *req); - -/* ETHTOOL_MSG_WOL_GET - notify */ -struct ethtool_wol_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_wol_get_ntf *ntf); - struct ethtool_wol_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_wol_get_ntf_free(struct ethtool_wol_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_WOL_SET ============== */ -/* ETHTOOL_MSG_WOL_SET - do */ -struct ethtool_wol_set_req { - struct { - __u32 header:1; - __u32 modes:1; - __u32 sopass_len; - } _present; - - struct ethtool_header header; - struct ethtool_bitset modes; - void *sopass; -}; - -static inline struct ethtool_wol_set_req *ethtool_wol_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_wol_set_req)); -} -void ethtool_wol_set_req_free(struct ethtool_wol_set_req *req); - -static inline void -ethtool_wol_set_req_set_header_dev_index(struct ethtool_wol_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_wol_set_req_set_header_dev_name(struct ethtool_wol_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_wol_set_req_set_header_flags(struct ethtool_wol_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_wol_set_req_set_modes_nomask(struct ethtool_wol_set_req *req) -{ - req->_present.modes = 1; - req->modes._present.nomask = 1; -} -static inline void -ethtool_wol_set_req_set_modes_size(struct ethtool_wol_set_req *req, __u32 size) -{ - req->_present.modes = 1; - req->modes._present.size = 1; - req->modes.size = size; -} -static inline void -__ethtool_wol_set_req_set_modes_bits_bit(struct ethtool_wol_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->modes.bits.bit); - req->modes.bits.bit = bit; - req->modes.bits.n_bit = n_bit; -} -static inline void -ethtool_wol_set_req_set_sopass(struct ethtool_wol_set_req *req, - const void *sopass, size_t len) -{ - free(req->sopass); - req->_present.sopass_len = len; - req->sopass = malloc(req->_present.sopass_len); - memcpy(req->sopass, sopass, req->_present.sopass_len); -} - -/* - * Set WOL params. - */ -int ethtool_wol_set(struct ynl_sock *ys, struct ethtool_wol_set_req *req); - -/* ============== ETHTOOL_MSG_FEATURES_GET ============== */ -/* ETHTOOL_MSG_FEATURES_GET - do */ -struct ethtool_features_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_features_get_req * -ethtool_features_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_features_get_req)); -} -void ethtool_features_get_req_free(struct ethtool_features_get_req *req); - -static inline void -ethtool_features_get_req_set_header_dev_index(struct ethtool_features_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_features_get_req_set_header_dev_name(struct ethtool_features_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_features_get_req_set_header_flags(struct ethtool_features_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_features_get_rsp { - struct { - __u32 header:1; - __u32 hw:1; - __u32 wanted:1; - __u32 active:1; - __u32 nochange:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset hw; - struct ethtool_bitset wanted; - struct ethtool_bitset active; - struct ethtool_bitset nochange; -}; - -void ethtool_features_get_rsp_free(struct ethtool_features_get_rsp *rsp); - -/* - * Get features. - */ -struct ethtool_features_get_rsp * -ethtool_features_get(struct ynl_sock *ys, struct ethtool_features_get_req *req); - -/* ETHTOOL_MSG_FEATURES_GET - dump */ -struct ethtool_features_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_features_get_req_dump * -ethtool_features_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_features_get_req_dump)); -} -void -ethtool_features_get_req_dump_free(struct ethtool_features_get_req_dump *req); - -static inline void -ethtool_features_get_req_dump_set_header_dev_index(struct ethtool_features_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_features_get_req_dump_set_header_dev_name(struct ethtool_features_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_features_get_req_dump_set_header_flags(struct ethtool_features_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_features_get_list { - struct ethtool_features_get_list *next; - struct ethtool_features_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_features_get_list_free(struct ethtool_features_get_list *rsp); - -struct ethtool_features_get_list * -ethtool_features_get_dump(struct ynl_sock *ys, - struct ethtool_features_get_req_dump *req); - -/* ETHTOOL_MSG_FEATURES_GET - notify */ -struct ethtool_features_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_features_get_ntf *ntf); - struct ethtool_features_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_features_get_ntf_free(struct ethtool_features_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_FEATURES_SET ============== */ -/* ETHTOOL_MSG_FEATURES_SET - do */ -struct ethtool_features_set_req { - struct { - __u32 header:1; - __u32 hw:1; - __u32 wanted:1; - __u32 active:1; - __u32 nochange:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset hw; - struct ethtool_bitset wanted; - struct ethtool_bitset active; - struct ethtool_bitset nochange; -}; - -static inline struct ethtool_features_set_req * -ethtool_features_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_features_set_req)); -} -void ethtool_features_set_req_free(struct ethtool_features_set_req *req); - -static inline void -ethtool_features_set_req_set_header_dev_index(struct ethtool_features_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_features_set_req_set_header_dev_name(struct ethtool_features_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_features_set_req_set_header_flags(struct ethtool_features_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_features_set_req_set_hw_nomask(struct ethtool_features_set_req *req) -{ - req->_present.hw = 1; - req->hw._present.nomask = 1; -} -static inline void -ethtool_features_set_req_set_hw_size(struct ethtool_features_set_req *req, - __u32 size) -{ - req->_present.hw = 1; - req->hw._present.size = 1; - req->hw.size = size; -} -static inline void -__ethtool_features_set_req_set_hw_bits_bit(struct ethtool_features_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->hw.bits.bit); - req->hw.bits.bit = bit; - req->hw.bits.n_bit = n_bit; -} -static inline void -ethtool_features_set_req_set_wanted_nomask(struct ethtool_features_set_req *req) -{ - req->_present.wanted = 1; - req->wanted._present.nomask = 1; -} -static inline void -ethtool_features_set_req_set_wanted_size(struct ethtool_features_set_req *req, - __u32 size) -{ - req->_present.wanted = 1; - req->wanted._present.size = 1; - req->wanted.size = size; -} -static inline void -__ethtool_features_set_req_set_wanted_bits_bit(struct ethtool_features_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->wanted.bits.bit); - req->wanted.bits.bit = bit; - req->wanted.bits.n_bit = n_bit; -} -static inline void -ethtool_features_set_req_set_active_nomask(struct ethtool_features_set_req *req) -{ - req->_present.active = 1; - req->active._present.nomask = 1; -} -static inline void -ethtool_features_set_req_set_active_size(struct ethtool_features_set_req *req, - __u32 size) -{ - req->_present.active = 1; - req->active._present.size = 1; - req->active.size = size; -} -static inline void -__ethtool_features_set_req_set_active_bits_bit(struct ethtool_features_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->active.bits.bit); - req->active.bits.bit = bit; - req->active.bits.n_bit = n_bit; -} -static inline void -ethtool_features_set_req_set_nochange_nomask(struct ethtool_features_set_req *req) -{ - req->_present.nochange = 1; - req->nochange._present.nomask = 1; -} -static inline void -ethtool_features_set_req_set_nochange_size(struct ethtool_features_set_req *req, - __u32 size) -{ - req->_present.nochange = 1; - req->nochange._present.size = 1; - req->nochange.size = size; -} -static inline void -__ethtool_features_set_req_set_nochange_bits_bit(struct ethtool_features_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->nochange.bits.bit); - req->nochange.bits.bit = bit; - req->nochange.bits.n_bit = n_bit; -} - -struct ethtool_features_set_rsp { - struct { - __u32 header:1; - __u32 hw:1; - __u32 wanted:1; - __u32 active:1; - __u32 nochange:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset hw; - struct ethtool_bitset wanted; - struct ethtool_bitset active; - struct ethtool_bitset nochange; -}; - -void ethtool_features_set_rsp_free(struct ethtool_features_set_rsp *rsp); - -/* - * Set features. - */ -struct ethtool_features_set_rsp * -ethtool_features_set(struct ynl_sock *ys, struct ethtool_features_set_req *req); - -/* ============== ETHTOOL_MSG_PRIVFLAGS_GET ============== */ -/* ETHTOOL_MSG_PRIVFLAGS_GET - do */ -struct ethtool_privflags_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_privflags_get_req * -ethtool_privflags_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_privflags_get_req)); -} -void ethtool_privflags_get_req_free(struct ethtool_privflags_get_req *req); - -static inline void -ethtool_privflags_get_req_set_header_dev_index(struct ethtool_privflags_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_privflags_get_req_set_header_dev_name(struct ethtool_privflags_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_privflags_get_req_set_header_flags(struct ethtool_privflags_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_privflags_get_rsp { - struct { - __u32 header:1; - __u32 flags:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset flags; -}; - -void ethtool_privflags_get_rsp_free(struct ethtool_privflags_get_rsp *rsp); - -/* - * Get device private flags. - */ -struct ethtool_privflags_get_rsp * -ethtool_privflags_get(struct ynl_sock *ys, - struct ethtool_privflags_get_req *req); - -/* ETHTOOL_MSG_PRIVFLAGS_GET - dump */ -struct ethtool_privflags_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_privflags_get_req_dump * -ethtool_privflags_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_privflags_get_req_dump)); -} -void -ethtool_privflags_get_req_dump_free(struct ethtool_privflags_get_req_dump *req); - -static inline void -ethtool_privflags_get_req_dump_set_header_dev_index(struct ethtool_privflags_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_privflags_get_req_dump_set_header_dev_name(struct ethtool_privflags_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_privflags_get_req_dump_set_header_flags(struct ethtool_privflags_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_privflags_get_list { - struct ethtool_privflags_get_list *next; - struct ethtool_privflags_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_privflags_get_list_free(struct ethtool_privflags_get_list *rsp); - -struct ethtool_privflags_get_list * -ethtool_privflags_get_dump(struct ynl_sock *ys, - struct ethtool_privflags_get_req_dump *req); - -/* ETHTOOL_MSG_PRIVFLAGS_GET - notify */ -struct ethtool_privflags_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_privflags_get_ntf *ntf); - struct ethtool_privflags_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_privflags_get_ntf_free(struct ethtool_privflags_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_PRIVFLAGS_SET ============== */ -/* ETHTOOL_MSG_PRIVFLAGS_SET - do */ -struct ethtool_privflags_set_req { - struct { - __u32 header:1; - __u32 flags:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset flags; -}; - -static inline struct ethtool_privflags_set_req * -ethtool_privflags_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_privflags_set_req)); -} -void ethtool_privflags_set_req_free(struct ethtool_privflags_set_req *req); - -static inline void -ethtool_privflags_set_req_set_header_dev_index(struct ethtool_privflags_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_privflags_set_req_set_header_dev_name(struct ethtool_privflags_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_privflags_set_req_set_header_flags(struct ethtool_privflags_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_privflags_set_req_set_flags_nomask(struct ethtool_privflags_set_req *req) -{ - req->_present.flags = 1; - req->flags._present.nomask = 1; -} -static inline void -ethtool_privflags_set_req_set_flags_size(struct ethtool_privflags_set_req *req, - __u32 size) -{ - req->_present.flags = 1; - req->flags._present.size = 1; - req->flags.size = size; -} -static inline void -__ethtool_privflags_set_req_set_flags_bits_bit(struct ethtool_privflags_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->flags.bits.bit); - req->flags.bits.bit = bit; - req->flags.bits.n_bit = n_bit; -} - -/* - * Set device private flags. - */ -int ethtool_privflags_set(struct ynl_sock *ys, - struct ethtool_privflags_set_req *req); - -/* ============== ETHTOOL_MSG_RINGS_GET ============== */ -/* ETHTOOL_MSG_RINGS_GET - do */ -struct ethtool_rings_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_rings_get_req *ethtool_rings_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_rings_get_req)); -} -void ethtool_rings_get_req_free(struct ethtool_rings_get_req *req); - -static inline void -ethtool_rings_get_req_set_header_dev_index(struct ethtool_rings_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_rings_get_req_set_header_dev_name(struct ethtool_rings_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_rings_get_req_set_header_flags(struct ethtool_rings_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_rings_get_rsp { - struct { - __u32 header:1; - __u32 rx_max:1; - __u32 rx_mini_max:1; - __u32 rx_jumbo_max:1; - __u32 tx_max:1; - __u32 rx:1; - __u32 rx_mini:1; - __u32 rx_jumbo:1; - __u32 tx:1; - __u32 rx_buf_len:1; - __u32 tcp_data_split:1; - __u32 cqe_size:1; - __u32 tx_push:1; - __u32 rx_push:1; - __u32 tx_push_buf_len:1; - __u32 tx_push_buf_len_max:1; - } _present; - - struct ethtool_header header; - __u32 rx_max; - __u32 rx_mini_max; - __u32 rx_jumbo_max; - __u32 tx_max; - __u32 rx; - __u32 rx_mini; - __u32 rx_jumbo; - __u32 tx; - __u32 rx_buf_len; - __u8 tcp_data_split; - __u32 cqe_size; - __u8 tx_push; - __u8 rx_push; - __u32 tx_push_buf_len; - __u32 tx_push_buf_len_max; -}; - -void ethtool_rings_get_rsp_free(struct ethtool_rings_get_rsp *rsp); - -/* - * Get ring params. - */ -struct ethtool_rings_get_rsp * -ethtool_rings_get(struct ynl_sock *ys, struct ethtool_rings_get_req *req); - -/* ETHTOOL_MSG_RINGS_GET - dump */ -struct ethtool_rings_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_rings_get_req_dump * -ethtool_rings_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_rings_get_req_dump)); -} -void ethtool_rings_get_req_dump_free(struct ethtool_rings_get_req_dump *req); - -static inline void -ethtool_rings_get_req_dump_set_header_dev_index(struct ethtool_rings_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_rings_get_req_dump_set_header_dev_name(struct ethtool_rings_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_rings_get_req_dump_set_header_flags(struct ethtool_rings_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_rings_get_list { - struct ethtool_rings_get_list *next; - struct ethtool_rings_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_rings_get_list_free(struct ethtool_rings_get_list *rsp); - -struct ethtool_rings_get_list * -ethtool_rings_get_dump(struct ynl_sock *ys, - struct ethtool_rings_get_req_dump *req); - -/* ETHTOOL_MSG_RINGS_GET - notify */ -struct ethtool_rings_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_rings_get_ntf *ntf); - struct ethtool_rings_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_rings_get_ntf_free(struct ethtool_rings_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_RINGS_SET ============== */ -/* ETHTOOL_MSG_RINGS_SET - do */ -struct ethtool_rings_set_req { - struct { - __u32 header:1; - __u32 rx_max:1; - __u32 rx_mini_max:1; - __u32 rx_jumbo_max:1; - __u32 tx_max:1; - __u32 rx:1; - __u32 rx_mini:1; - __u32 rx_jumbo:1; - __u32 tx:1; - __u32 rx_buf_len:1; - __u32 tcp_data_split:1; - __u32 cqe_size:1; - __u32 tx_push:1; - __u32 rx_push:1; - __u32 tx_push_buf_len:1; - __u32 tx_push_buf_len_max:1; - } _present; - - struct ethtool_header header; - __u32 rx_max; - __u32 rx_mini_max; - __u32 rx_jumbo_max; - __u32 tx_max; - __u32 rx; - __u32 rx_mini; - __u32 rx_jumbo; - __u32 tx; - __u32 rx_buf_len; - __u8 tcp_data_split; - __u32 cqe_size; - __u8 tx_push; - __u8 rx_push; - __u32 tx_push_buf_len; - __u32 tx_push_buf_len_max; -}; - -static inline struct ethtool_rings_set_req *ethtool_rings_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_rings_set_req)); -} -void ethtool_rings_set_req_free(struct ethtool_rings_set_req *req); - -static inline void -ethtool_rings_set_req_set_header_dev_index(struct ethtool_rings_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_rings_set_req_set_header_dev_name(struct ethtool_rings_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_rings_set_req_set_header_flags(struct ethtool_rings_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_rings_set_req_set_rx_max(struct ethtool_rings_set_req *req, - __u32 rx_max) -{ - req->_present.rx_max = 1; - req->rx_max = rx_max; -} -static inline void -ethtool_rings_set_req_set_rx_mini_max(struct ethtool_rings_set_req *req, - __u32 rx_mini_max) -{ - req->_present.rx_mini_max = 1; - req->rx_mini_max = rx_mini_max; -} -static inline void -ethtool_rings_set_req_set_rx_jumbo_max(struct ethtool_rings_set_req *req, - __u32 rx_jumbo_max) -{ - req->_present.rx_jumbo_max = 1; - req->rx_jumbo_max = rx_jumbo_max; -} -static inline void -ethtool_rings_set_req_set_tx_max(struct ethtool_rings_set_req *req, - __u32 tx_max) -{ - req->_present.tx_max = 1; - req->tx_max = tx_max; -} -static inline void -ethtool_rings_set_req_set_rx(struct ethtool_rings_set_req *req, __u32 rx) -{ - req->_present.rx = 1; - req->rx = rx; -} -static inline void -ethtool_rings_set_req_set_rx_mini(struct ethtool_rings_set_req *req, - __u32 rx_mini) -{ - req->_present.rx_mini = 1; - req->rx_mini = rx_mini; -} -static inline void -ethtool_rings_set_req_set_rx_jumbo(struct ethtool_rings_set_req *req, - __u32 rx_jumbo) -{ - req->_present.rx_jumbo = 1; - req->rx_jumbo = rx_jumbo; -} -static inline void -ethtool_rings_set_req_set_tx(struct ethtool_rings_set_req *req, __u32 tx) -{ - req->_present.tx = 1; - req->tx = tx; -} -static inline void -ethtool_rings_set_req_set_rx_buf_len(struct ethtool_rings_set_req *req, - __u32 rx_buf_len) -{ - req->_present.rx_buf_len = 1; - req->rx_buf_len = rx_buf_len; -} -static inline void -ethtool_rings_set_req_set_tcp_data_split(struct ethtool_rings_set_req *req, - __u8 tcp_data_split) -{ - req->_present.tcp_data_split = 1; - req->tcp_data_split = tcp_data_split; -} -static inline void -ethtool_rings_set_req_set_cqe_size(struct ethtool_rings_set_req *req, - __u32 cqe_size) -{ - req->_present.cqe_size = 1; - req->cqe_size = cqe_size; -} -static inline void -ethtool_rings_set_req_set_tx_push(struct ethtool_rings_set_req *req, - __u8 tx_push) -{ - req->_present.tx_push = 1; - req->tx_push = tx_push; -} -static inline void -ethtool_rings_set_req_set_rx_push(struct ethtool_rings_set_req *req, - __u8 rx_push) -{ - req->_present.rx_push = 1; - req->rx_push = rx_push; -} -static inline void -ethtool_rings_set_req_set_tx_push_buf_len(struct ethtool_rings_set_req *req, - __u32 tx_push_buf_len) -{ - req->_present.tx_push_buf_len = 1; - req->tx_push_buf_len = tx_push_buf_len; -} -static inline void -ethtool_rings_set_req_set_tx_push_buf_len_max(struct ethtool_rings_set_req *req, - __u32 tx_push_buf_len_max) -{ - req->_present.tx_push_buf_len_max = 1; - req->tx_push_buf_len_max = tx_push_buf_len_max; -} - -/* - * Set ring params. - */ -int ethtool_rings_set(struct ynl_sock *ys, struct ethtool_rings_set_req *req); - -/* ============== ETHTOOL_MSG_CHANNELS_GET ============== */ -/* ETHTOOL_MSG_CHANNELS_GET - do */ -struct ethtool_channels_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_channels_get_req * -ethtool_channels_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_channels_get_req)); -} -void ethtool_channels_get_req_free(struct ethtool_channels_get_req *req); - -static inline void -ethtool_channels_get_req_set_header_dev_index(struct ethtool_channels_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_channels_get_req_set_header_dev_name(struct ethtool_channels_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_channels_get_req_set_header_flags(struct ethtool_channels_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_channels_get_rsp { - struct { - __u32 header:1; - __u32 rx_max:1; - __u32 tx_max:1; - __u32 other_max:1; - __u32 combined_max:1; - __u32 rx_count:1; - __u32 tx_count:1; - __u32 other_count:1; - __u32 combined_count:1; - } _present; - - struct ethtool_header header; - __u32 rx_max; - __u32 tx_max; - __u32 other_max; - __u32 combined_max; - __u32 rx_count; - __u32 tx_count; - __u32 other_count; - __u32 combined_count; -}; - -void ethtool_channels_get_rsp_free(struct ethtool_channels_get_rsp *rsp); - -/* - * Get channel params. - */ -struct ethtool_channels_get_rsp * -ethtool_channels_get(struct ynl_sock *ys, struct ethtool_channels_get_req *req); - -/* ETHTOOL_MSG_CHANNELS_GET - dump */ -struct ethtool_channels_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_channels_get_req_dump * -ethtool_channels_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_channels_get_req_dump)); -} -void -ethtool_channels_get_req_dump_free(struct ethtool_channels_get_req_dump *req); - -static inline void -ethtool_channels_get_req_dump_set_header_dev_index(struct ethtool_channels_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_channels_get_req_dump_set_header_dev_name(struct ethtool_channels_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_channels_get_req_dump_set_header_flags(struct ethtool_channels_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_channels_get_list { - struct ethtool_channels_get_list *next; - struct ethtool_channels_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_channels_get_list_free(struct ethtool_channels_get_list *rsp); - -struct ethtool_channels_get_list * -ethtool_channels_get_dump(struct ynl_sock *ys, - struct ethtool_channels_get_req_dump *req); - -/* ETHTOOL_MSG_CHANNELS_GET - notify */ -struct ethtool_channels_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_channels_get_ntf *ntf); - struct ethtool_channels_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_channels_get_ntf_free(struct ethtool_channels_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_CHANNELS_SET ============== */ -/* ETHTOOL_MSG_CHANNELS_SET - do */ -struct ethtool_channels_set_req { - struct { - __u32 header:1; - __u32 rx_max:1; - __u32 tx_max:1; - __u32 other_max:1; - __u32 combined_max:1; - __u32 rx_count:1; - __u32 tx_count:1; - __u32 other_count:1; - __u32 combined_count:1; - } _present; - - struct ethtool_header header; - __u32 rx_max; - __u32 tx_max; - __u32 other_max; - __u32 combined_max; - __u32 rx_count; - __u32 tx_count; - __u32 other_count; - __u32 combined_count; -}; - -static inline struct ethtool_channels_set_req * -ethtool_channels_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_channels_set_req)); -} -void ethtool_channels_set_req_free(struct ethtool_channels_set_req *req); - -static inline void -ethtool_channels_set_req_set_header_dev_index(struct ethtool_channels_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_channels_set_req_set_header_dev_name(struct ethtool_channels_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_channels_set_req_set_header_flags(struct ethtool_channels_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_channels_set_req_set_rx_max(struct ethtool_channels_set_req *req, - __u32 rx_max) -{ - req->_present.rx_max = 1; - req->rx_max = rx_max; -} -static inline void -ethtool_channels_set_req_set_tx_max(struct ethtool_channels_set_req *req, - __u32 tx_max) -{ - req->_present.tx_max = 1; - req->tx_max = tx_max; -} -static inline void -ethtool_channels_set_req_set_other_max(struct ethtool_channels_set_req *req, - __u32 other_max) -{ - req->_present.other_max = 1; - req->other_max = other_max; -} -static inline void -ethtool_channels_set_req_set_combined_max(struct ethtool_channels_set_req *req, - __u32 combined_max) -{ - req->_present.combined_max = 1; - req->combined_max = combined_max; -} -static inline void -ethtool_channels_set_req_set_rx_count(struct ethtool_channels_set_req *req, - __u32 rx_count) -{ - req->_present.rx_count = 1; - req->rx_count = rx_count; -} -static inline void -ethtool_channels_set_req_set_tx_count(struct ethtool_channels_set_req *req, - __u32 tx_count) -{ - req->_present.tx_count = 1; - req->tx_count = tx_count; -} -static inline void -ethtool_channels_set_req_set_other_count(struct ethtool_channels_set_req *req, - __u32 other_count) -{ - req->_present.other_count = 1; - req->other_count = other_count; -} -static inline void -ethtool_channels_set_req_set_combined_count(struct ethtool_channels_set_req *req, - __u32 combined_count) -{ - req->_present.combined_count = 1; - req->combined_count = combined_count; -} - -/* - * Set channel params. - */ -int ethtool_channels_set(struct ynl_sock *ys, - struct ethtool_channels_set_req *req); - -/* ============== ETHTOOL_MSG_COALESCE_GET ============== */ -/* ETHTOOL_MSG_COALESCE_GET - do */ -struct ethtool_coalesce_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_coalesce_get_req * -ethtool_coalesce_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_coalesce_get_req)); -} -void ethtool_coalesce_get_req_free(struct ethtool_coalesce_get_req *req); - -static inline void -ethtool_coalesce_get_req_set_header_dev_index(struct ethtool_coalesce_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_coalesce_get_req_set_header_dev_name(struct ethtool_coalesce_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_coalesce_get_req_set_header_flags(struct ethtool_coalesce_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_coalesce_get_rsp { - struct { - __u32 header:1; - __u32 rx_usecs:1; - __u32 rx_max_frames:1; - __u32 rx_usecs_irq:1; - __u32 rx_max_frames_irq:1; - __u32 tx_usecs:1; - __u32 tx_max_frames:1; - __u32 tx_usecs_irq:1; - __u32 tx_max_frames_irq:1; - __u32 stats_block_usecs:1; - __u32 use_adaptive_rx:1; - __u32 use_adaptive_tx:1; - __u32 pkt_rate_low:1; - __u32 rx_usecs_low:1; - __u32 rx_max_frames_low:1; - __u32 tx_usecs_low:1; - __u32 tx_max_frames_low:1; - __u32 pkt_rate_high:1; - __u32 rx_usecs_high:1; - __u32 rx_max_frames_high:1; - __u32 tx_usecs_high:1; - __u32 tx_max_frames_high:1; - __u32 rate_sample_interval:1; - __u32 use_cqe_mode_tx:1; - __u32 use_cqe_mode_rx:1; - __u32 tx_aggr_max_bytes:1; - __u32 tx_aggr_max_frames:1; - __u32 tx_aggr_time_usecs:1; - } _present; - - struct ethtool_header header; - __u32 rx_usecs; - __u32 rx_max_frames; - __u32 rx_usecs_irq; - __u32 rx_max_frames_irq; - __u32 tx_usecs; - __u32 tx_max_frames; - __u32 tx_usecs_irq; - __u32 tx_max_frames_irq; - __u32 stats_block_usecs; - __u8 use_adaptive_rx; - __u8 use_adaptive_tx; - __u32 pkt_rate_low; - __u32 rx_usecs_low; - __u32 rx_max_frames_low; - __u32 tx_usecs_low; - __u32 tx_max_frames_low; - __u32 pkt_rate_high; - __u32 rx_usecs_high; - __u32 rx_max_frames_high; - __u32 tx_usecs_high; - __u32 tx_max_frames_high; - __u32 rate_sample_interval; - __u8 use_cqe_mode_tx; - __u8 use_cqe_mode_rx; - __u32 tx_aggr_max_bytes; - __u32 tx_aggr_max_frames; - __u32 tx_aggr_time_usecs; -}; - -void ethtool_coalesce_get_rsp_free(struct ethtool_coalesce_get_rsp *rsp); - -/* - * Get coalesce params. - */ -struct ethtool_coalesce_get_rsp * -ethtool_coalesce_get(struct ynl_sock *ys, struct ethtool_coalesce_get_req *req); - -/* ETHTOOL_MSG_COALESCE_GET - dump */ -struct ethtool_coalesce_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_coalesce_get_req_dump * -ethtool_coalesce_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_coalesce_get_req_dump)); -} -void -ethtool_coalesce_get_req_dump_free(struct ethtool_coalesce_get_req_dump *req); - -static inline void -ethtool_coalesce_get_req_dump_set_header_dev_index(struct ethtool_coalesce_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_coalesce_get_req_dump_set_header_dev_name(struct ethtool_coalesce_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_coalesce_get_req_dump_set_header_flags(struct ethtool_coalesce_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_coalesce_get_list { - struct ethtool_coalesce_get_list *next; - struct ethtool_coalesce_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_coalesce_get_list_free(struct ethtool_coalesce_get_list *rsp); - -struct ethtool_coalesce_get_list * -ethtool_coalesce_get_dump(struct ynl_sock *ys, - struct ethtool_coalesce_get_req_dump *req); - -/* ETHTOOL_MSG_COALESCE_GET - notify */ -struct ethtool_coalesce_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_coalesce_get_ntf *ntf); - struct ethtool_coalesce_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_coalesce_get_ntf_free(struct ethtool_coalesce_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_COALESCE_SET ============== */ -/* ETHTOOL_MSG_COALESCE_SET - do */ -struct ethtool_coalesce_set_req { - struct { - __u32 header:1; - __u32 rx_usecs:1; - __u32 rx_max_frames:1; - __u32 rx_usecs_irq:1; - __u32 rx_max_frames_irq:1; - __u32 tx_usecs:1; - __u32 tx_max_frames:1; - __u32 tx_usecs_irq:1; - __u32 tx_max_frames_irq:1; - __u32 stats_block_usecs:1; - __u32 use_adaptive_rx:1; - __u32 use_adaptive_tx:1; - __u32 pkt_rate_low:1; - __u32 rx_usecs_low:1; - __u32 rx_max_frames_low:1; - __u32 tx_usecs_low:1; - __u32 tx_max_frames_low:1; - __u32 pkt_rate_high:1; - __u32 rx_usecs_high:1; - __u32 rx_max_frames_high:1; - __u32 tx_usecs_high:1; - __u32 tx_max_frames_high:1; - __u32 rate_sample_interval:1; - __u32 use_cqe_mode_tx:1; - __u32 use_cqe_mode_rx:1; - __u32 tx_aggr_max_bytes:1; - __u32 tx_aggr_max_frames:1; - __u32 tx_aggr_time_usecs:1; - } _present; - - struct ethtool_header header; - __u32 rx_usecs; - __u32 rx_max_frames; - __u32 rx_usecs_irq; - __u32 rx_max_frames_irq; - __u32 tx_usecs; - __u32 tx_max_frames; - __u32 tx_usecs_irq; - __u32 tx_max_frames_irq; - __u32 stats_block_usecs; - __u8 use_adaptive_rx; - __u8 use_adaptive_tx; - __u32 pkt_rate_low; - __u32 rx_usecs_low; - __u32 rx_max_frames_low; - __u32 tx_usecs_low; - __u32 tx_max_frames_low; - __u32 pkt_rate_high; - __u32 rx_usecs_high; - __u32 rx_max_frames_high; - __u32 tx_usecs_high; - __u32 tx_max_frames_high; - __u32 rate_sample_interval; - __u8 use_cqe_mode_tx; - __u8 use_cqe_mode_rx; - __u32 tx_aggr_max_bytes; - __u32 tx_aggr_max_frames; - __u32 tx_aggr_time_usecs; -}; - -static inline struct ethtool_coalesce_set_req * -ethtool_coalesce_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_coalesce_set_req)); -} -void ethtool_coalesce_set_req_free(struct ethtool_coalesce_set_req *req); - -static inline void -ethtool_coalesce_set_req_set_header_dev_index(struct ethtool_coalesce_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_coalesce_set_req_set_header_dev_name(struct ethtool_coalesce_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_coalesce_set_req_set_header_flags(struct ethtool_coalesce_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_coalesce_set_req_set_rx_usecs(struct ethtool_coalesce_set_req *req, - __u32 rx_usecs) -{ - req->_present.rx_usecs = 1; - req->rx_usecs = rx_usecs; -} -static inline void -ethtool_coalesce_set_req_set_rx_max_frames(struct ethtool_coalesce_set_req *req, - __u32 rx_max_frames) -{ - req->_present.rx_max_frames = 1; - req->rx_max_frames = rx_max_frames; -} -static inline void -ethtool_coalesce_set_req_set_rx_usecs_irq(struct ethtool_coalesce_set_req *req, - __u32 rx_usecs_irq) -{ - req->_present.rx_usecs_irq = 1; - req->rx_usecs_irq = rx_usecs_irq; -} -static inline void -ethtool_coalesce_set_req_set_rx_max_frames_irq(struct ethtool_coalesce_set_req *req, - __u32 rx_max_frames_irq) -{ - req->_present.rx_max_frames_irq = 1; - req->rx_max_frames_irq = rx_max_frames_irq; -} -static inline void -ethtool_coalesce_set_req_set_tx_usecs(struct ethtool_coalesce_set_req *req, - __u32 tx_usecs) -{ - req->_present.tx_usecs = 1; - req->tx_usecs = tx_usecs; -} -static inline void -ethtool_coalesce_set_req_set_tx_max_frames(struct ethtool_coalesce_set_req *req, - __u32 tx_max_frames) -{ - req->_present.tx_max_frames = 1; - req->tx_max_frames = tx_max_frames; -} -static inline void -ethtool_coalesce_set_req_set_tx_usecs_irq(struct ethtool_coalesce_set_req *req, - __u32 tx_usecs_irq) -{ - req->_present.tx_usecs_irq = 1; - req->tx_usecs_irq = tx_usecs_irq; -} -static inline void -ethtool_coalesce_set_req_set_tx_max_frames_irq(struct ethtool_coalesce_set_req *req, - __u32 tx_max_frames_irq) -{ - req->_present.tx_max_frames_irq = 1; - req->tx_max_frames_irq = tx_max_frames_irq; -} -static inline void -ethtool_coalesce_set_req_set_stats_block_usecs(struct ethtool_coalesce_set_req *req, - __u32 stats_block_usecs) -{ - req->_present.stats_block_usecs = 1; - req->stats_block_usecs = stats_block_usecs; -} -static inline void -ethtool_coalesce_set_req_set_use_adaptive_rx(struct ethtool_coalesce_set_req *req, - __u8 use_adaptive_rx) -{ - req->_present.use_adaptive_rx = 1; - req->use_adaptive_rx = use_adaptive_rx; -} -static inline void -ethtool_coalesce_set_req_set_use_adaptive_tx(struct ethtool_coalesce_set_req *req, - __u8 use_adaptive_tx) -{ - req->_present.use_adaptive_tx = 1; - req->use_adaptive_tx = use_adaptive_tx; -} -static inline void -ethtool_coalesce_set_req_set_pkt_rate_low(struct ethtool_coalesce_set_req *req, - __u32 pkt_rate_low) -{ - req->_present.pkt_rate_low = 1; - req->pkt_rate_low = pkt_rate_low; -} -static inline void -ethtool_coalesce_set_req_set_rx_usecs_low(struct ethtool_coalesce_set_req *req, - __u32 rx_usecs_low) -{ - req->_present.rx_usecs_low = 1; - req->rx_usecs_low = rx_usecs_low; -} -static inline void -ethtool_coalesce_set_req_set_rx_max_frames_low(struct ethtool_coalesce_set_req *req, - __u32 rx_max_frames_low) -{ - req->_present.rx_max_frames_low = 1; - req->rx_max_frames_low = rx_max_frames_low; -} -static inline void -ethtool_coalesce_set_req_set_tx_usecs_low(struct ethtool_coalesce_set_req *req, - __u32 tx_usecs_low) -{ - req->_present.tx_usecs_low = 1; - req->tx_usecs_low = tx_usecs_low; -} -static inline void -ethtool_coalesce_set_req_set_tx_max_frames_low(struct ethtool_coalesce_set_req *req, - __u32 tx_max_frames_low) -{ - req->_present.tx_max_frames_low = 1; - req->tx_max_frames_low = tx_max_frames_low; -} -static inline void -ethtool_coalesce_set_req_set_pkt_rate_high(struct ethtool_coalesce_set_req *req, - __u32 pkt_rate_high) -{ - req->_present.pkt_rate_high = 1; - req->pkt_rate_high = pkt_rate_high; -} -static inline void -ethtool_coalesce_set_req_set_rx_usecs_high(struct ethtool_coalesce_set_req *req, - __u32 rx_usecs_high) -{ - req->_present.rx_usecs_high = 1; - req->rx_usecs_high = rx_usecs_high; -} -static inline void -ethtool_coalesce_set_req_set_rx_max_frames_high(struct ethtool_coalesce_set_req *req, - __u32 rx_max_frames_high) -{ - req->_present.rx_max_frames_high = 1; - req->rx_max_frames_high = rx_max_frames_high; -} -static inline void -ethtool_coalesce_set_req_set_tx_usecs_high(struct ethtool_coalesce_set_req *req, - __u32 tx_usecs_high) -{ - req->_present.tx_usecs_high = 1; - req->tx_usecs_high = tx_usecs_high; -} -static inline void -ethtool_coalesce_set_req_set_tx_max_frames_high(struct ethtool_coalesce_set_req *req, - __u32 tx_max_frames_high) -{ - req->_present.tx_max_frames_high = 1; - req->tx_max_frames_high = tx_max_frames_high; -} -static inline void -ethtool_coalesce_set_req_set_rate_sample_interval(struct ethtool_coalesce_set_req *req, - __u32 rate_sample_interval) -{ - req->_present.rate_sample_interval = 1; - req->rate_sample_interval = rate_sample_interval; -} -static inline void -ethtool_coalesce_set_req_set_use_cqe_mode_tx(struct ethtool_coalesce_set_req *req, - __u8 use_cqe_mode_tx) -{ - req->_present.use_cqe_mode_tx = 1; - req->use_cqe_mode_tx = use_cqe_mode_tx; -} -static inline void -ethtool_coalesce_set_req_set_use_cqe_mode_rx(struct ethtool_coalesce_set_req *req, - __u8 use_cqe_mode_rx) -{ - req->_present.use_cqe_mode_rx = 1; - req->use_cqe_mode_rx = use_cqe_mode_rx; -} -static inline void -ethtool_coalesce_set_req_set_tx_aggr_max_bytes(struct ethtool_coalesce_set_req *req, - __u32 tx_aggr_max_bytes) -{ - req->_present.tx_aggr_max_bytes = 1; - req->tx_aggr_max_bytes = tx_aggr_max_bytes; -} -static inline void -ethtool_coalesce_set_req_set_tx_aggr_max_frames(struct ethtool_coalesce_set_req *req, - __u32 tx_aggr_max_frames) -{ - req->_present.tx_aggr_max_frames = 1; - req->tx_aggr_max_frames = tx_aggr_max_frames; -} -static inline void -ethtool_coalesce_set_req_set_tx_aggr_time_usecs(struct ethtool_coalesce_set_req *req, - __u32 tx_aggr_time_usecs) -{ - req->_present.tx_aggr_time_usecs = 1; - req->tx_aggr_time_usecs = tx_aggr_time_usecs; -} - -/* - * Set coalesce params. - */ -int ethtool_coalesce_set(struct ynl_sock *ys, - struct ethtool_coalesce_set_req *req); - -/* ============== ETHTOOL_MSG_PAUSE_GET ============== */ -/* ETHTOOL_MSG_PAUSE_GET - do */ -struct ethtool_pause_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_pause_get_req *ethtool_pause_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_pause_get_req)); -} -void ethtool_pause_get_req_free(struct ethtool_pause_get_req *req); - -static inline void -ethtool_pause_get_req_set_header_dev_index(struct ethtool_pause_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_pause_get_req_set_header_dev_name(struct ethtool_pause_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_pause_get_req_set_header_flags(struct ethtool_pause_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_pause_get_rsp { - struct { - __u32 header:1; - __u32 autoneg:1; - __u32 rx:1; - __u32 tx:1; - __u32 stats:1; - __u32 stats_src:1; - } _present; - - struct ethtool_header header; - __u8 autoneg; - __u8 rx; - __u8 tx; - struct ethtool_pause_stat stats; - __u32 stats_src; -}; - -void ethtool_pause_get_rsp_free(struct ethtool_pause_get_rsp *rsp); - -/* - * Get pause params. - */ -struct ethtool_pause_get_rsp * -ethtool_pause_get(struct ynl_sock *ys, struct ethtool_pause_get_req *req); - -/* ETHTOOL_MSG_PAUSE_GET - dump */ -struct ethtool_pause_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_pause_get_req_dump * -ethtool_pause_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_pause_get_req_dump)); -} -void ethtool_pause_get_req_dump_free(struct ethtool_pause_get_req_dump *req); - -static inline void -ethtool_pause_get_req_dump_set_header_dev_index(struct ethtool_pause_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_pause_get_req_dump_set_header_dev_name(struct ethtool_pause_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_pause_get_req_dump_set_header_flags(struct ethtool_pause_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_pause_get_list { - struct ethtool_pause_get_list *next; - struct ethtool_pause_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_pause_get_list_free(struct ethtool_pause_get_list *rsp); - -struct ethtool_pause_get_list * -ethtool_pause_get_dump(struct ynl_sock *ys, - struct ethtool_pause_get_req_dump *req); - -/* ETHTOOL_MSG_PAUSE_GET - notify */ -struct ethtool_pause_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_pause_get_ntf *ntf); - struct ethtool_pause_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_pause_get_ntf_free(struct ethtool_pause_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_PAUSE_SET ============== */ -/* ETHTOOL_MSG_PAUSE_SET - do */ -struct ethtool_pause_set_req { - struct { - __u32 header:1; - __u32 autoneg:1; - __u32 rx:1; - __u32 tx:1; - __u32 stats:1; - __u32 stats_src:1; - } _present; - - struct ethtool_header header; - __u8 autoneg; - __u8 rx; - __u8 tx; - struct ethtool_pause_stat stats; - __u32 stats_src; -}; - -static inline struct ethtool_pause_set_req *ethtool_pause_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_pause_set_req)); -} -void ethtool_pause_set_req_free(struct ethtool_pause_set_req *req); - -static inline void -ethtool_pause_set_req_set_header_dev_index(struct ethtool_pause_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_pause_set_req_set_header_dev_name(struct ethtool_pause_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_pause_set_req_set_header_flags(struct ethtool_pause_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_pause_set_req_set_autoneg(struct ethtool_pause_set_req *req, - __u8 autoneg) -{ - req->_present.autoneg = 1; - req->autoneg = autoneg; -} -static inline void -ethtool_pause_set_req_set_rx(struct ethtool_pause_set_req *req, __u8 rx) -{ - req->_present.rx = 1; - req->rx = rx; -} -static inline void -ethtool_pause_set_req_set_tx(struct ethtool_pause_set_req *req, __u8 tx) -{ - req->_present.tx = 1; - req->tx = tx; -} -static inline void -ethtool_pause_set_req_set_stats_tx_frames(struct ethtool_pause_set_req *req, - __u64 tx_frames) -{ - req->_present.stats = 1; - req->stats._present.tx_frames = 1; - req->stats.tx_frames = tx_frames; -} -static inline void -ethtool_pause_set_req_set_stats_rx_frames(struct ethtool_pause_set_req *req, - __u64 rx_frames) -{ - req->_present.stats = 1; - req->stats._present.rx_frames = 1; - req->stats.rx_frames = rx_frames; -} -static inline void -ethtool_pause_set_req_set_stats_src(struct ethtool_pause_set_req *req, - __u32 stats_src) -{ - req->_present.stats_src = 1; - req->stats_src = stats_src; -} - -/* - * Set pause params. - */ -int ethtool_pause_set(struct ynl_sock *ys, struct ethtool_pause_set_req *req); - -/* ============== ETHTOOL_MSG_EEE_GET ============== */ -/* ETHTOOL_MSG_EEE_GET - do */ -struct ethtool_eee_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_eee_get_req *ethtool_eee_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_eee_get_req)); -} -void ethtool_eee_get_req_free(struct ethtool_eee_get_req *req); - -static inline void -ethtool_eee_get_req_set_header_dev_index(struct ethtool_eee_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_eee_get_req_set_header_dev_name(struct ethtool_eee_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_eee_get_req_set_header_flags(struct ethtool_eee_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_eee_get_rsp { - struct { - __u32 header:1; - __u32 modes_ours:1; - __u32 modes_peer:1; - __u32 active:1; - __u32 enabled:1; - __u32 tx_lpi_enabled:1; - __u32 tx_lpi_timer:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset modes_ours; - struct ethtool_bitset modes_peer; - __u8 active; - __u8 enabled; - __u8 tx_lpi_enabled; - __u32 tx_lpi_timer; -}; - -void ethtool_eee_get_rsp_free(struct ethtool_eee_get_rsp *rsp); - -/* - * Get eee params. - */ -struct ethtool_eee_get_rsp * -ethtool_eee_get(struct ynl_sock *ys, struct ethtool_eee_get_req *req); - -/* ETHTOOL_MSG_EEE_GET - dump */ -struct ethtool_eee_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_eee_get_req_dump * -ethtool_eee_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_eee_get_req_dump)); -} -void ethtool_eee_get_req_dump_free(struct ethtool_eee_get_req_dump *req); - -static inline void -ethtool_eee_get_req_dump_set_header_dev_index(struct ethtool_eee_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_eee_get_req_dump_set_header_dev_name(struct ethtool_eee_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_eee_get_req_dump_set_header_flags(struct ethtool_eee_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_eee_get_list { - struct ethtool_eee_get_list *next; - struct ethtool_eee_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_eee_get_list_free(struct ethtool_eee_get_list *rsp); - -struct ethtool_eee_get_list * -ethtool_eee_get_dump(struct ynl_sock *ys, struct ethtool_eee_get_req_dump *req); - -/* ETHTOOL_MSG_EEE_GET - notify */ -struct ethtool_eee_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_eee_get_ntf *ntf); - struct ethtool_eee_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_eee_get_ntf_free(struct ethtool_eee_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_EEE_SET ============== */ -/* ETHTOOL_MSG_EEE_SET - do */ -struct ethtool_eee_set_req { - struct { - __u32 header:1; - __u32 modes_ours:1; - __u32 modes_peer:1; - __u32 active:1; - __u32 enabled:1; - __u32 tx_lpi_enabled:1; - __u32 tx_lpi_timer:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset modes_ours; - struct ethtool_bitset modes_peer; - __u8 active; - __u8 enabled; - __u8 tx_lpi_enabled; - __u32 tx_lpi_timer; -}; - -static inline struct ethtool_eee_set_req *ethtool_eee_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_eee_set_req)); -} -void ethtool_eee_set_req_free(struct ethtool_eee_set_req *req); - -static inline void -ethtool_eee_set_req_set_header_dev_index(struct ethtool_eee_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_eee_set_req_set_header_dev_name(struct ethtool_eee_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_eee_set_req_set_header_flags(struct ethtool_eee_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_eee_set_req_set_modes_ours_nomask(struct ethtool_eee_set_req *req) -{ - req->_present.modes_ours = 1; - req->modes_ours._present.nomask = 1; -} -static inline void -ethtool_eee_set_req_set_modes_ours_size(struct ethtool_eee_set_req *req, - __u32 size) -{ - req->_present.modes_ours = 1; - req->modes_ours._present.size = 1; - req->modes_ours.size = size; -} -static inline void -__ethtool_eee_set_req_set_modes_ours_bits_bit(struct ethtool_eee_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->modes_ours.bits.bit); - req->modes_ours.bits.bit = bit; - req->modes_ours.bits.n_bit = n_bit; -} -static inline void -ethtool_eee_set_req_set_modes_peer_nomask(struct ethtool_eee_set_req *req) -{ - req->_present.modes_peer = 1; - req->modes_peer._present.nomask = 1; -} -static inline void -ethtool_eee_set_req_set_modes_peer_size(struct ethtool_eee_set_req *req, - __u32 size) -{ - req->_present.modes_peer = 1; - req->modes_peer._present.size = 1; - req->modes_peer.size = size; -} -static inline void -__ethtool_eee_set_req_set_modes_peer_bits_bit(struct ethtool_eee_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->modes_peer.bits.bit); - req->modes_peer.bits.bit = bit; - req->modes_peer.bits.n_bit = n_bit; -} -static inline void -ethtool_eee_set_req_set_active(struct ethtool_eee_set_req *req, __u8 active) -{ - req->_present.active = 1; - req->active = active; -} -static inline void -ethtool_eee_set_req_set_enabled(struct ethtool_eee_set_req *req, __u8 enabled) -{ - req->_present.enabled = 1; - req->enabled = enabled; -} -static inline void -ethtool_eee_set_req_set_tx_lpi_enabled(struct ethtool_eee_set_req *req, - __u8 tx_lpi_enabled) -{ - req->_present.tx_lpi_enabled = 1; - req->tx_lpi_enabled = tx_lpi_enabled; -} -static inline void -ethtool_eee_set_req_set_tx_lpi_timer(struct ethtool_eee_set_req *req, - __u32 tx_lpi_timer) -{ - req->_present.tx_lpi_timer = 1; - req->tx_lpi_timer = tx_lpi_timer; -} - -/* - * Set eee params. - */ -int ethtool_eee_set(struct ynl_sock *ys, struct ethtool_eee_set_req *req); - -/* ============== ETHTOOL_MSG_TSINFO_GET ============== */ -/* ETHTOOL_MSG_TSINFO_GET - do */ -struct ethtool_tsinfo_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_tsinfo_get_req *ethtool_tsinfo_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_tsinfo_get_req)); -} -void ethtool_tsinfo_get_req_free(struct ethtool_tsinfo_get_req *req); - -static inline void -ethtool_tsinfo_get_req_set_header_dev_index(struct ethtool_tsinfo_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_tsinfo_get_req_set_header_dev_name(struct ethtool_tsinfo_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_tsinfo_get_req_set_header_flags(struct ethtool_tsinfo_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_tsinfo_get_rsp { - struct { - __u32 header:1; - __u32 timestamping:1; - __u32 tx_types:1; - __u32 rx_filters:1; - __u32 phc_index:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset timestamping; - struct ethtool_bitset tx_types; - struct ethtool_bitset rx_filters; - __u32 phc_index; -}; - -void ethtool_tsinfo_get_rsp_free(struct ethtool_tsinfo_get_rsp *rsp); - -/* - * Get tsinfo params. - */ -struct ethtool_tsinfo_get_rsp * -ethtool_tsinfo_get(struct ynl_sock *ys, struct ethtool_tsinfo_get_req *req); - -/* ETHTOOL_MSG_TSINFO_GET - dump */ -struct ethtool_tsinfo_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_tsinfo_get_req_dump * -ethtool_tsinfo_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_tsinfo_get_req_dump)); -} -void ethtool_tsinfo_get_req_dump_free(struct ethtool_tsinfo_get_req_dump *req); - -static inline void -ethtool_tsinfo_get_req_dump_set_header_dev_index(struct ethtool_tsinfo_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_tsinfo_get_req_dump_set_header_dev_name(struct ethtool_tsinfo_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_tsinfo_get_req_dump_set_header_flags(struct ethtool_tsinfo_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_tsinfo_get_list { - struct ethtool_tsinfo_get_list *next; - struct ethtool_tsinfo_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_tsinfo_get_list_free(struct ethtool_tsinfo_get_list *rsp); - -struct ethtool_tsinfo_get_list * -ethtool_tsinfo_get_dump(struct ynl_sock *ys, - struct ethtool_tsinfo_get_req_dump *req); - -/* ============== ETHTOOL_MSG_CABLE_TEST_ACT ============== */ -/* ETHTOOL_MSG_CABLE_TEST_ACT - do */ -struct ethtool_cable_test_act_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_cable_test_act_req * -ethtool_cable_test_act_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_cable_test_act_req)); -} -void ethtool_cable_test_act_req_free(struct ethtool_cable_test_act_req *req); - -static inline void -ethtool_cable_test_act_req_set_header_dev_index(struct ethtool_cable_test_act_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_cable_test_act_req_set_header_dev_name(struct ethtool_cable_test_act_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_cable_test_act_req_set_header_flags(struct ethtool_cable_test_act_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -/* - * Cable test. - */ -int ethtool_cable_test_act(struct ynl_sock *ys, - struct ethtool_cable_test_act_req *req); - -/* ============== ETHTOOL_MSG_CABLE_TEST_TDR_ACT ============== */ -/* ETHTOOL_MSG_CABLE_TEST_TDR_ACT - do */ -struct ethtool_cable_test_tdr_act_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_cable_test_tdr_act_req * -ethtool_cable_test_tdr_act_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_cable_test_tdr_act_req)); -} -void -ethtool_cable_test_tdr_act_req_free(struct ethtool_cable_test_tdr_act_req *req); - -static inline void -ethtool_cable_test_tdr_act_req_set_header_dev_index(struct ethtool_cable_test_tdr_act_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_cable_test_tdr_act_req_set_header_dev_name(struct ethtool_cable_test_tdr_act_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_cable_test_tdr_act_req_set_header_flags(struct ethtool_cable_test_tdr_act_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -/* - * Cable test TDR. - */ -int ethtool_cable_test_tdr_act(struct ynl_sock *ys, - struct ethtool_cable_test_tdr_act_req *req); - -/* ============== ETHTOOL_MSG_TUNNEL_INFO_GET ============== */ -/* ETHTOOL_MSG_TUNNEL_INFO_GET - do */ -struct ethtool_tunnel_info_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_tunnel_info_get_req * -ethtool_tunnel_info_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_tunnel_info_get_req)); -} -void ethtool_tunnel_info_get_req_free(struct ethtool_tunnel_info_get_req *req); - -static inline void -ethtool_tunnel_info_get_req_set_header_dev_index(struct ethtool_tunnel_info_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_tunnel_info_get_req_set_header_dev_name(struct ethtool_tunnel_info_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_tunnel_info_get_req_set_header_flags(struct ethtool_tunnel_info_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_tunnel_info_get_rsp { - struct { - __u32 header:1; - __u32 udp_ports:1; - } _present; - - struct ethtool_header header; - struct ethtool_tunnel_udp udp_ports; -}; - -void ethtool_tunnel_info_get_rsp_free(struct ethtool_tunnel_info_get_rsp *rsp); - -/* - * Get tsinfo params. - */ -struct ethtool_tunnel_info_get_rsp * -ethtool_tunnel_info_get(struct ynl_sock *ys, - struct ethtool_tunnel_info_get_req *req); - -/* ETHTOOL_MSG_TUNNEL_INFO_GET - dump */ -struct ethtool_tunnel_info_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_tunnel_info_get_req_dump * -ethtool_tunnel_info_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_tunnel_info_get_req_dump)); -} -void -ethtool_tunnel_info_get_req_dump_free(struct ethtool_tunnel_info_get_req_dump *req); - -static inline void -ethtool_tunnel_info_get_req_dump_set_header_dev_index(struct ethtool_tunnel_info_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_tunnel_info_get_req_dump_set_header_dev_name(struct ethtool_tunnel_info_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_tunnel_info_get_req_dump_set_header_flags(struct ethtool_tunnel_info_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_tunnel_info_get_list { - struct ethtool_tunnel_info_get_list *next; - struct ethtool_tunnel_info_get_rsp obj __attribute__((aligned(8))); -}; - -void -ethtool_tunnel_info_get_list_free(struct ethtool_tunnel_info_get_list *rsp); - -struct ethtool_tunnel_info_get_list * -ethtool_tunnel_info_get_dump(struct ynl_sock *ys, - struct ethtool_tunnel_info_get_req_dump *req); - -/* ============== ETHTOOL_MSG_FEC_GET ============== */ -/* ETHTOOL_MSG_FEC_GET - do */ -struct ethtool_fec_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_fec_get_req *ethtool_fec_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_fec_get_req)); -} -void ethtool_fec_get_req_free(struct ethtool_fec_get_req *req); - -static inline void -ethtool_fec_get_req_set_header_dev_index(struct ethtool_fec_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_fec_get_req_set_header_dev_name(struct ethtool_fec_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_fec_get_req_set_header_flags(struct ethtool_fec_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_fec_get_rsp { - struct { - __u32 header:1; - __u32 modes:1; - __u32 auto_:1; - __u32 active:1; - __u32 stats:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset modes; - __u8 auto_; - __u32 active; - struct ethtool_fec_stat stats; -}; - -void ethtool_fec_get_rsp_free(struct ethtool_fec_get_rsp *rsp); - -/* - * Get FEC params. - */ -struct ethtool_fec_get_rsp * -ethtool_fec_get(struct ynl_sock *ys, struct ethtool_fec_get_req *req); - -/* ETHTOOL_MSG_FEC_GET - dump */ -struct ethtool_fec_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_fec_get_req_dump * -ethtool_fec_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_fec_get_req_dump)); -} -void ethtool_fec_get_req_dump_free(struct ethtool_fec_get_req_dump *req); - -static inline void -ethtool_fec_get_req_dump_set_header_dev_index(struct ethtool_fec_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_fec_get_req_dump_set_header_dev_name(struct ethtool_fec_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_fec_get_req_dump_set_header_flags(struct ethtool_fec_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_fec_get_list { - struct ethtool_fec_get_list *next; - struct ethtool_fec_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_fec_get_list_free(struct ethtool_fec_get_list *rsp); - -struct ethtool_fec_get_list * -ethtool_fec_get_dump(struct ynl_sock *ys, struct ethtool_fec_get_req_dump *req); - -/* ETHTOOL_MSG_FEC_GET - notify */ -struct ethtool_fec_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_fec_get_ntf *ntf); - struct ethtool_fec_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_fec_get_ntf_free(struct ethtool_fec_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_FEC_SET ============== */ -/* ETHTOOL_MSG_FEC_SET - do */ -struct ethtool_fec_set_req { - struct { - __u32 header:1; - __u32 modes:1; - __u32 auto_:1; - __u32 active:1; - __u32 stats:1; - } _present; - - struct ethtool_header header; - struct ethtool_bitset modes; - __u8 auto_; - __u32 active; - struct ethtool_fec_stat stats; -}; - -static inline struct ethtool_fec_set_req *ethtool_fec_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_fec_set_req)); -} -void ethtool_fec_set_req_free(struct ethtool_fec_set_req *req); - -static inline void -ethtool_fec_set_req_set_header_dev_index(struct ethtool_fec_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_fec_set_req_set_header_dev_name(struct ethtool_fec_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_fec_set_req_set_header_flags(struct ethtool_fec_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_fec_set_req_set_modes_nomask(struct ethtool_fec_set_req *req) -{ - req->_present.modes = 1; - req->modes._present.nomask = 1; -} -static inline void -ethtool_fec_set_req_set_modes_size(struct ethtool_fec_set_req *req, __u32 size) -{ - req->_present.modes = 1; - req->modes._present.size = 1; - req->modes.size = size; -} -static inline void -__ethtool_fec_set_req_set_modes_bits_bit(struct ethtool_fec_set_req *req, - struct ethtool_bitset_bit *bit, - unsigned int n_bit) -{ - free(req->modes.bits.bit); - req->modes.bits.bit = bit; - req->modes.bits.n_bit = n_bit; -} -static inline void -ethtool_fec_set_req_set_auto_(struct ethtool_fec_set_req *req, __u8 auto_) -{ - req->_present.auto_ = 1; - req->auto_ = auto_; -} -static inline void -ethtool_fec_set_req_set_active(struct ethtool_fec_set_req *req, __u32 active) -{ - req->_present.active = 1; - req->active = active; -} -static inline void -ethtool_fec_set_req_set_stats_corrected(struct ethtool_fec_set_req *req, - const void *corrected, size_t len) -{ - free(req->stats.corrected); - req->stats._present.corrected_len = len; - req->stats.corrected = malloc(req->stats._present.corrected_len); - memcpy(req->stats.corrected, corrected, req->stats._present.corrected_len); -} -static inline void -ethtool_fec_set_req_set_stats_uncorr(struct ethtool_fec_set_req *req, - const void *uncorr, size_t len) -{ - free(req->stats.uncorr); - req->stats._present.uncorr_len = len; - req->stats.uncorr = malloc(req->stats._present.uncorr_len); - memcpy(req->stats.uncorr, uncorr, req->stats._present.uncorr_len); -} -static inline void -ethtool_fec_set_req_set_stats_corr_bits(struct ethtool_fec_set_req *req, - const void *corr_bits, size_t len) -{ - free(req->stats.corr_bits); - req->stats._present.corr_bits_len = len; - req->stats.corr_bits = malloc(req->stats._present.corr_bits_len); - memcpy(req->stats.corr_bits, corr_bits, req->stats._present.corr_bits_len); -} - -/* - * Set FEC params. - */ -int ethtool_fec_set(struct ynl_sock *ys, struct ethtool_fec_set_req *req); - -/* ============== ETHTOOL_MSG_MODULE_EEPROM_GET ============== */ -/* ETHTOOL_MSG_MODULE_EEPROM_GET - do */ -struct ethtool_module_eeprom_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_module_eeprom_get_req * -ethtool_module_eeprom_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_module_eeprom_get_req)); -} -void -ethtool_module_eeprom_get_req_free(struct ethtool_module_eeprom_get_req *req); - -static inline void -ethtool_module_eeprom_get_req_set_header_dev_index(struct ethtool_module_eeprom_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_module_eeprom_get_req_set_header_dev_name(struct ethtool_module_eeprom_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_module_eeprom_get_req_set_header_flags(struct ethtool_module_eeprom_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_module_eeprom_get_rsp { - struct { - __u32 header:1; - __u32 offset:1; - __u32 length:1; - __u32 page:1; - __u32 bank:1; - __u32 i2c_address:1; - __u32 data_len; - } _present; - - struct ethtool_header header; - __u32 offset; - __u32 length; - __u8 page; - __u8 bank; - __u8 i2c_address; - void *data; -}; - -void -ethtool_module_eeprom_get_rsp_free(struct ethtool_module_eeprom_get_rsp *rsp); - -/* - * Get module EEPROM params. - */ -struct ethtool_module_eeprom_get_rsp * -ethtool_module_eeprom_get(struct ynl_sock *ys, - struct ethtool_module_eeprom_get_req *req); - -/* ETHTOOL_MSG_MODULE_EEPROM_GET - dump */ -struct ethtool_module_eeprom_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_module_eeprom_get_req_dump * -ethtool_module_eeprom_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_module_eeprom_get_req_dump)); -} -void -ethtool_module_eeprom_get_req_dump_free(struct ethtool_module_eeprom_get_req_dump *req); - -static inline void -ethtool_module_eeprom_get_req_dump_set_header_dev_index(struct ethtool_module_eeprom_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_module_eeprom_get_req_dump_set_header_dev_name(struct ethtool_module_eeprom_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_module_eeprom_get_req_dump_set_header_flags(struct ethtool_module_eeprom_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_module_eeprom_get_list { - struct ethtool_module_eeprom_get_list *next; - struct ethtool_module_eeprom_get_rsp obj __attribute__((aligned(8))); -}; - -void -ethtool_module_eeprom_get_list_free(struct ethtool_module_eeprom_get_list *rsp); - -struct ethtool_module_eeprom_get_list * -ethtool_module_eeprom_get_dump(struct ynl_sock *ys, - struct ethtool_module_eeprom_get_req_dump *req); - -/* ============== ETHTOOL_MSG_PHC_VCLOCKS_GET ============== */ -/* ETHTOOL_MSG_PHC_VCLOCKS_GET - do */ -struct ethtool_phc_vclocks_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_phc_vclocks_get_req * -ethtool_phc_vclocks_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_phc_vclocks_get_req)); -} -void ethtool_phc_vclocks_get_req_free(struct ethtool_phc_vclocks_get_req *req); - -static inline void -ethtool_phc_vclocks_get_req_set_header_dev_index(struct ethtool_phc_vclocks_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_phc_vclocks_get_req_set_header_dev_name(struct ethtool_phc_vclocks_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_phc_vclocks_get_req_set_header_flags(struct ethtool_phc_vclocks_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_phc_vclocks_get_rsp { - struct { - __u32 header:1; - __u32 num:1; - } _present; - - struct ethtool_header header; - __u32 num; -}; - -void ethtool_phc_vclocks_get_rsp_free(struct ethtool_phc_vclocks_get_rsp *rsp); - -/* - * Get PHC VCLOCKs. - */ -struct ethtool_phc_vclocks_get_rsp * -ethtool_phc_vclocks_get(struct ynl_sock *ys, - struct ethtool_phc_vclocks_get_req *req); - -/* ETHTOOL_MSG_PHC_VCLOCKS_GET - dump */ -struct ethtool_phc_vclocks_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_phc_vclocks_get_req_dump * -ethtool_phc_vclocks_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_phc_vclocks_get_req_dump)); -} -void -ethtool_phc_vclocks_get_req_dump_free(struct ethtool_phc_vclocks_get_req_dump *req); - -static inline void -ethtool_phc_vclocks_get_req_dump_set_header_dev_index(struct ethtool_phc_vclocks_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_phc_vclocks_get_req_dump_set_header_dev_name(struct ethtool_phc_vclocks_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_phc_vclocks_get_req_dump_set_header_flags(struct ethtool_phc_vclocks_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_phc_vclocks_get_list { - struct ethtool_phc_vclocks_get_list *next; - struct ethtool_phc_vclocks_get_rsp obj __attribute__((aligned(8))); -}; - -void -ethtool_phc_vclocks_get_list_free(struct ethtool_phc_vclocks_get_list *rsp); - -struct ethtool_phc_vclocks_get_list * -ethtool_phc_vclocks_get_dump(struct ynl_sock *ys, - struct ethtool_phc_vclocks_get_req_dump *req); - -/* ============== ETHTOOL_MSG_MODULE_GET ============== */ -/* ETHTOOL_MSG_MODULE_GET - do */ -struct ethtool_module_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_module_get_req *ethtool_module_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_module_get_req)); -} -void ethtool_module_get_req_free(struct ethtool_module_get_req *req); - -static inline void -ethtool_module_get_req_set_header_dev_index(struct ethtool_module_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_module_get_req_set_header_dev_name(struct ethtool_module_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_module_get_req_set_header_flags(struct ethtool_module_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_module_get_rsp { - struct { - __u32 header:1; - __u32 power_mode_policy:1; - __u32 power_mode:1; - } _present; - - struct ethtool_header header; - __u8 power_mode_policy; - __u8 power_mode; -}; - -void ethtool_module_get_rsp_free(struct ethtool_module_get_rsp *rsp); - -/* - * Get module params. - */ -struct ethtool_module_get_rsp * -ethtool_module_get(struct ynl_sock *ys, struct ethtool_module_get_req *req); - -/* ETHTOOL_MSG_MODULE_GET - dump */ -struct ethtool_module_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_module_get_req_dump * -ethtool_module_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_module_get_req_dump)); -} -void ethtool_module_get_req_dump_free(struct ethtool_module_get_req_dump *req); - -static inline void -ethtool_module_get_req_dump_set_header_dev_index(struct ethtool_module_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_module_get_req_dump_set_header_dev_name(struct ethtool_module_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_module_get_req_dump_set_header_flags(struct ethtool_module_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_module_get_list { - struct ethtool_module_get_list *next; - struct ethtool_module_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_module_get_list_free(struct ethtool_module_get_list *rsp); - -struct ethtool_module_get_list * -ethtool_module_get_dump(struct ynl_sock *ys, - struct ethtool_module_get_req_dump *req); - -/* ETHTOOL_MSG_MODULE_GET - notify */ -struct ethtool_module_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_module_get_ntf *ntf); - struct ethtool_module_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_module_get_ntf_free(struct ethtool_module_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_MODULE_SET ============== */ -/* ETHTOOL_MSG_MODULE_SET - do */ -struct ethtool_module_set_req { - struct { - __u32 header:1; - __u32 power_mode_policy:1; - __u32 power_mode:1; - } _present; - - struct ethtool_header header; - __u8 power_mode_policy; - __u8 power_mode; -}; - -static inline struct ethtool_module_set_req *ethtool_module_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_module_set_req)); -} -void ethtool_module_set_req_free(struct ethtool_module_set_req *req); - -static inline void -ethtool_module_set_req_set_header_dev_index(struct ethtool_module_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_module_set_req_set_header_dev_name(struct ethtool_module_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_module_set_req_set_header_flags(struct ethtool_module_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_module_set_req_set_power_mode_policy(struct ethtool_module_set_req *req, - __u8 power_mode_policy) -{ - req->_present.power_mode_policy = 1; - req->power_mode_policy = power_mode_policy; -} -static inline void -ethtool_module_set_req_set_power_mode(struct ethtool_module_set_req *req, - __u8 power_mode) -{ - req->_present.power_mode = 1; - req->power_mode = power_mode; -} - -/* - * Set module params. - */ -int ethtool_module_set(struct ynl_sock *ys, struct ethtool_module_set_req *req); - -/* ============== ETHTOOL_MSG_PSE_GET ============== */ -/* ETHTOOL_MSG_PSE_GET - do */ -struct ethtool_pse_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_pse_get_req *ethtool_pse_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_pse_get_req)); -} -void ethtool_pse_get_req_free(struct ethtool_pse_get_req *req); - -static inline void -ethtool_pse_get_req_set_header_dev_index(struct ethtool_pse_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_pse_get_req_set_header_dev_name(struct ethtool_pse_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_pse_get_req_set_header_flags(struct ethtool_pse_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_pse_get_rsp { - struct { - __u32 header:1; - __u32 admin_state:1; - __u32 admin_control:1; - __u32 pw_d_status:1; - } _present; - - struct ethtool_header header; - __u32 admin_state; - __u32 admin_control; - __u32 pw_d_status; -}; - -void ethtool_pse_get_rsp_free(struct ethtool_pse_get_rsp *rsp); - -/* - * Get Power Sourcing Equipment params. - */ -struct ethtool_pse_get_rsp * -ethtool_pse_get(struct ynl_sock *ys, struct ethtool_pse_get_req *req); - -/* ETHTOOL_MSG_PSE_GET - dump */ -struct ethtool_pse_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_pse_get_req_dump * -ethtool_pse_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_pse_get_req_dump)); -} -void ethtool_pse_get_req_dump_free(struct ethtool_pse_get_req_dump *req); - -static inline void -ethtool_pse_get_req_dump_set_header_dev_index(struct ethtool_pse_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_pse_get_req_dump_set_header_dev_name(struct ethtool_pse_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_pse_get_req_dump_set_header_flags(struct ethtool_pse_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_pse_get_list { - struct ethtool_pse_get_list *next; - struct ethtool_pse_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_pse_get_list_free(struct ethtool_pse_get_list *rsp); - -struct ethtool_pse_get_list * -ethtool_pse_get_dump(struct ynl_sock *ys, struct ethtool_pse_get_req_dump *req); - -/* ============== ETHTOOL_MSG_PSE_SET ============== */ -/* ETHTOOL_MSG_PSE_SET - do */ -struct ethtool_pse_set_req { - struct { - __u32 header:1; - __u32 admin_state:1; - __u32 admin_control:1; - __u32 pw_d_status:1; - } _present; - - struct ethtool_header header; - __u32 admin_state; - __u32 admin_control; - __u32 pw_d_status; -}; - -static inline struct ethtool_pse_set_req *ethtool_pse_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_pse_set_req)); -} -void ethtool_pse_set_req_free(struct ethtool_pse_set_req *req); - -static inline void -ethtool_pse_set_req_set_header_dev_index(struct ethtool_pse_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_pse_set_req_set_header_dev_name(struct ethtool_pse_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_pse_set_req_set_header_flags(struct ethtool_pse_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_pse_set_req_set_admin_state(struct ethtool_pse_set_req *req, - __u32 admin_state) -{ - req->_present.admin_state = 1; - req->admin_state = admin_state; -} -static inline void -ethtool_pse_set_req_set_admin_control(struct ethtool_pse_set_req *req, - __u32 admin_control) -{ - req->_present.admin_control = 1; - req->admin_control = admin_control; -} -static inline void -ethtool_pse_set_req_set_pw_d_status(struct ethtool_pse_set_req *req, - __u32 pw_d_status) -{ - req->_present.pw_d_status = 1; - req->pw_d_status = pw_d_status; -} - -/* - * Set Power Sourcing Equipment params. - */ -int ethtool_pse_set(struct ynl_sock *ys, struct ethtool_pse_set_req *req); - -/* ============== ETHTOOL_MSG_RSS_GET ============== */ -/* ETHTOOL_MSG_RSS_GET - do */ -struct ethtool_rss_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_rss_get_req *ethtool_rss_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_rss_get_req)); -} -void ethtool_rss_get_req_free(struct ethtool_rss_get_req *req); - -static inline void -ethtool_rss_get_req_set_header_dev_index(struct ethtool_rss_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_rss_get_req_set_header_dev_name(struct ethtool_rss_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_rss_get_req_set_header_flags(struct ethtool_rss_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_rss_get_rsp { - struct { - __u32 header:1; - __u32 context:1; - __u32 hfunc:1; - __u32 indir_len; - __u32 hkey_len; - } _present; - - struct ethtool_header header; - __u32 context; - __u32 hfunc; - void *indir; - void *hkey; -}; - -void ethtool_rss_get_rsp_free(struct ethtool_rss_get_rsp *rsp); - -/* - * Get RSS params. - */ -struct ethtool_rss_get_rsp * -ethtool_rss_get(struct ynl_sock *ys, struct ethtool_rss_get_req *req); - -/* ETHTOOL_MSG_RSS_GET - dump */ -struct ethtool_rss_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_rss_get_req_dump * -ethtool_rss_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_rss_get_req_dump)); -} -void ethtool_rss_get_req_dump_free(struct ethtool_rss_get_req_dump *req); - -static inline void -ethtool_rss_get_req_dump_set_header_dev_index(struct ethtool_rss_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_rss_get_req_dump_set_header_dev_name(struct ethtool_rss_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_rss_get_req_dump_set_header_flags(struct ethtool_rss_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_rss_get_list { - struct ethtool_rss_get_list *next; - struct ethtool_rss_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_rss_get_list_free(struct ethtool_rss_get_list *rsp); - -struct ethtool_rss_get_list * -ethtool_rss_get_dump(struct ynl_sock *ys, struct ethtool_rss_get_req_dump *req); - -/* ============== ETHTOOL_MSG_PLCA_GET_CFG ============== */ -/* ETHTOOL_MSG_PLCA_GET_CFG - do */ -struct ethtool_plca_get_cfg_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_plca_get_cfg_req * -ethtool_plca_get_cfg_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_plca_get_cfg_req)); -} -void ethtool_plca_get_cfg_req_free(struct ethtool_plca_get_cfg_req *req); - -static inline void -ethtool_plca_get_cfg_req_set_header_dev_index(struct ethtool_plca_get_cfg_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_plca_get_cfg_req_set_header_dev_name(struct ethtool_plca_get_cfg_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_plca_get_cfg_req_set_header_flags(struct ethtool_plca_get_cfg_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_plca_get_cfg_rsp { - struct { - __u32 header:1; - __u32 version:1; - __u32 enabled:1; - __u32 status:1; - __u32 node_cnt:1; - __u32 node_id:1; - __u32 to_tmr:1; - __u32 burst_cnt:1; - __u32 burst_tmr:1; - } _present; - - struct ethtool_header header; - __u16 version; - __u8 enabled; - __u8 status; - __u32 node_cnt; - __u32 node_id; - __u32 to_tmr; - __u32 burst_cnt; - __u32 burst_tmr; -}; - -void ethtool_plca_get_cfg_rsp_free(struct ethtool_plca_get_cfg_rsp *rsp); - -/* - * Get PLCA params. - */ -struct ethtool_plca_get_cfg_rsp * -ethtool_plca_get_cfg(struct ynl_sock *ys, struct ethtool_plca_get_cfg_req *req); - -/* ETHTOOL_MSG_PLCA_GET_CFG - dump */ -struct ethtool_plca_get_cfg_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_plca_get_cfg_req_dump * -ethtool_plca_get_cfg_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_plca_get_cfg_req_dump)); -} -void -ethtool_plca_get_cfg_req_dump_free(struct ethtool_plca_get_cfg_req_dump *req); - -static inline void -ethtool_plca_get_cfg_req_dump_set_header_dev_index(struct ethtool_plca_get_cfg_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_plca_get_cfg_req_dump_set_header_dev_name(struct ethtool_plca_get_cfg_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_plca_get_cfg_req_dump_set_header_flags(struct ethtool_plca_get_cfg_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_plca_get_cfg_list { - struct ethtool_plca_get_cfg_list *next; - struct ethtool_plca_get_cfg_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_plca_get_cfg_list_free(struct ethtool_plca_get_cfg_list *rsp); - -struct ethtool_plca_get_cfg_list * -ethtool_plca_get_cfg_dump(struct ynl_sock *ys, - struct ethtool_plca_get_cfg_req_dump *req); - -/* ETHTOOL_MSG_PLCA_GET_CFG - notify */ -struct ethtool_plca_get_cfg_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_plca_get_cfg_ntf *ntf); - struct ethtool_plca_get_cfg_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_plca_get_cfg_ntf_free(struct ethtool_plca_get_cfg_ntf *rsp); - -/* ============== ETHTOOL_MSG_PLCA_SET_CFG ============== */ -/* ETHTOOL_MSG_PLCA_SET_CFG - do */ -struct ethtool_plca_set_cfg_req { - struct { - __u32 header:1; - __u32 version:1; - __u32 enabled:1; - __u32 status:1; - __u32 node_cnt:1; - __u32 node_id:1; - __u32 to_tmr:1; - __u32 burst_cnt:1; - __u32 burst_tmr:1; - } _present; - - struct ethtool_header header; - __u16 version; - __u8 enabled; - __u8 status; - __u32 node_cnt; - __u32 node_id; - __u32 to_tmr; - __u32 burst_cnt; - __u32 burst_tmr; -}; - -static inline struct ethtool_plca_set_cfg_req * -ethtool_plca_set_cfg_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_plca_set_cfg_req)); -} -void ethtool_plca_set_cfg_req_free(struct ethtool_plca_set_cfg_req *req); - -static inline void -ethtool_plca_set_cfg_req_set_header_dev_index(struct ethtool_plca_set_cfg_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_plca_set_cfg_req_set_header_dev_name(struct ethtool_plca_set_cfg_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_plca_set_cfg_req_set_header_flags(struct ethtool_plca_set_cfg_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_plca_set_cfg_req_set_version(struct ethtool_plca_set_cfg_req *req, - __u16 version) -{ - req->_present.version = 1; - req->version = version; -} -static inline void -ethtool_plca_set_cfg_req_set_enabled(struct ethtool_plca_set_cfg_req *req, - __u8 enabled) -{ - req->_present.enabled = 1; - req->enabled = enabled; -} -static inline void -ethtool_plca_set_cfg_req_set_status(struct ethtool_plca_set_cfg_req *req, - __u8 status) -{ - req->_present.status = 1; - req->status = status; -} -static inline void -ethtool_plca_set_cfg_req_set_node_cnt(struct ethtool_plca_set_cfg_req *req, - __u32 node_cnt) -{ - req->_present.node_cnt = 1; - req->node_cnt = node_cnt; -} -static inline void -ethtool_plca_set_cfg_req_set_node_id(struct ethtool_plca_set_cfg_req *req, - __u32 node_id) -{ - req->_present.node_id = 1; - req->node_id = node_id; -} -static inline void -ethtool_plca_set_cfg_req_set_to_tmr(struct ethtool_plca_set_cfg_req *req, - __u32 to_tmr) -{ - req->_present.to_tmr = 1; - req->to_tmr = to_tmr; -} -static inline void -ethtool_plca_set_cfg_req_set_burst_cnt(struct ethtool_plca_set_cfg_req *req, - __u32 burst_cnt) -{ - req->_present.burst_cnt = 1; - req->burst_cnt = burst_cnt; -} -static inline void -ethtool_plca_set_cfg_req_set_burst_tmr(struct ethtool_plca_set_cfg_req *req, - __u32 burst_tmr) -{ - req->_present.burst_tmr = 1; - req->burst_tmr = burst_tmr; -} - -/* - * Set PLCA params. - */ -int ethtool_plca_set_cfg(struct ynl_sock *ys, - struct ethtool_plca_set_cfg_req *req); - -/* ============== ETHTOOL_MSG_PLCA_GET_STATUS ============== */ -/* ETHTOOL_MSG_PLCA_GET_STATUS - do */ -struct ethtool_plca_get_status_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_plca_get_status_req * -ethtool_plca_get_status_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_plca_get_status_req)); -} -void ethtool_plca_get_status_req_free(struct ethtool_plca_get_status_req *req); - -static inline void -ethtool_plca_get_status_req_set_header_dev_index(struct ethtool_plca_get_status_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_plca_get_status_req_set_header_dev_name(struct ethtool_plca_get_status_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_plca_get_status_req_set_header_flags(struct ethtool_plca_get_status_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_plca_get_status_rsp { - struct { - __u32 header:1; - __u32 version:1; - __u32 enabled:1; - __u32 status:1; - __u32 node_cnt:1; - __u32 node_id:1; - __u32 to_tmr:1; - __u32 burst_cnt:1; - __u32 burst_tmr:1; - } _present; - - struct ethtool_header header; - __u16 version; - __u8 enabled; - __u8 status; - __u32 node_cnt; - __u32 node_id; - __u32 to_tmr; - __u32 burst_cnt; - __u32 burst_tmr; -}; - -void ethtool_plca_get_status_rsp_free(struct ethtool_plca_get_status_rsp *rsp); - -/* - * Get PLCA status params. - */ -struct ethtool_plca_get_status_rsp * -ethtool_plca_get_status(struct ynl_sock *ys, - struct ethtool_plca_get_status_req *req); - -/* ETHTOOL_MSG_PLCA_GET_STATUS - dump */ -struct ethtool_plca_get_status_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_plca_get_status_req_dump * -ethtool_plca_get_status_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_plca_get_status_req_dump)); -} -void -ethtool_plca_get_status_req_dump_free(struct ethtool_plca_get_status_req_dump *req); - -static inline void -ethtool_plca_get_status_req_dump_set_header_dev_index(struct ethtool_plca_get_status_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_plca_get_status_req_dump_set_header_dev_name(struct ethtool_plca_get_status_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_plca_get_status_req_dump_set_header_flags(struct ethtool_plca_get_status_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_plca_get_status_list { - struct ethtool_plca_get_status_list *next; - struct ethtool_plca_get_status_rsp obj __attribute__((aligned(8))); -}; - -void -ethtool_plca_get_status_list_free(struct ethtool_plca_get_status_list *rsp); - -struct ethtool_plca_get_status_list * -ethtool_plca_get_status_dump(struct ynl_sock *ys, - struct ethtool_plca_get_status_req_dump *req); - -/* ============== ETHTOOL_MSG_MM_GET ============== */ -/* ETHTOOL_MSG_MM_GET - do */ -struct ethtool_mm_get_req { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_mm_get_req *ethtool_mm_get_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_mm_get_req)); -} -void ethtool_mm_get_req_free(struct ethtool_mm_get_req *req); - -static inline void -ethtool_mm_get_req_set_header_dev_index(struct ethtool_mm_get_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_mm_get_req_set_header_dev_name(struct ethtool_mm_get_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_mm_get_req_set_header_flags(struct ethtool_mm_get_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_mm_get_rsp { - struct { - __u32 header:1; - __u32 pmac_enabled:1; - __u32 tx_enabled:1; - __u32 tx_active:1; - __u32 tx_min_frag_size:1; - __u32 rx_min_frag_size:1; - __u32 verify_enabled:1; - __u32 verify_time:1; - __u32 max_verify_time:1; - __u32 stats:1; - } _present; - - struct ethtool_header header; - __u8 pmac_enabled; - __u8 tx_enabled; - __u8 tx_active; - __u32 tx_min_frag_size; - __u32 rx_min_frag_size; - __u8 verify_enabled; - __u32 verify_time; - __u32 max_verify_time; - struct ethtool_mm_stat stats; -}; - -void ethtool_mm_get_rsp_free(struct ethtool_mm_get_rsp *rsp); - -/* - * Get MAC Merge configuration and state - */ -struct ethtool_mm_get_rsp * -ethtool_mm_get(struct ynl_sock *ys, struct ethtool_mm_get_req *req); - -/* ETHTOOL_MSG_MM_GET - dump */ -struct ethtool_mm_get_req_dump { - struct { - __u32 header:1; - } _present; - - struct ethtool_header header; -}; - -static inline struct ethtool_mm_get_req_dump * -ethtool_mm_get_req_dump_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_mm_get_req_dump)); -} -void ethtool_mm_get_req_dump_free(struct ethtool_mm_get_req_dump *req); - -static inline void -ethtool_mm_get_req_dump_set_header_dev_index(struct ethtool_mm_get_req_dump *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_mm_get_req_dump_set_header_dev_name(struct ethtool_mm_get_req_dump *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_mm_get_req_dump_set_header_flags(struct ethtool_mm_get_req_dump *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} - -struct ethtool_mm_get_list { - struct ethtool_mm_get_list *next; - struct ethtool_mm_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_mm_get_list_free(struct ethtool_mm_get_list *rsp); - -struct ethtool_mm_get_list * -ethtool_mm_get_dump(struct ynl_sock *ys, struct ethtool_mm_get_req_dump *req); - -/* ETHTOOL_MSG_MM_GET - notify */ -struct ethtool_mm_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_mm_get_ntf *ntf); - struct ethtool_mm_get_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_mm_get_ntf_free(struct ethtool_mm_get_ntf *rsp); - -/* ============== ETHTOOL_MSG_MM_SET ============== */ -/* ETHTOOL_MSG_MM_SET - do */ -struct ethtool_mm_set_req { - struct { - __u32 header:1; - __u32 verify_enabled:1; - __u32 verify_time:1; - __u32 tx_enabled:1; - __u32 pmac_enabled:1; - __u32 tx_min_frag_size:1; - } _present; - - struct ethtool_header header; - __u8 verify_enabled; - __u32 verify_time; - __u8 tx_enabled; - __u8 pmac_enabled; - __u32 tx_min_frag_size; -}; - -static inline struct ethtool_mm_set_req *ethtool_mm_set_req_alloc(void) -{ - return calloc(1, sizeof(struct ethtool_mm_set_req)); -} -void ethtool_mm_set_req_free(struct ethtool_mm_set_req *req); - -static inline void -ethtool_mm_set_req_set_header_dev_index(struct ethtool_mm_set_req *req, - __u32 dev_index) -{ - req->_present.header = 1; - req->header._present.dev_index = 1; - req->header.dev_index = dev_index; -} -static inline void -ethtool_mm_set_req_set_header_dev_name(struct ethtool_mm_set_req *req, - const char *dev_name) -{ - free(req->header.dev_name); - req->header._present.dev_name_len = strlen(dev_name); - req->header.dev_name = malloc(req->header._present.dev_name_len + 1); - memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); - req->header.dev_name[req->header._present.dev_name_len] = 0; -} -static inline void -ethtool_mm_set_req_set_header_flags(struct ethtool_mm_set_req *req, - __u32 flags) -{ - req->_present.header = 1; - req->header._present.flags = 1; - req->header.flags = flags; -} -static inline void -ethtool_mm_set_req_set_verify_enabled(struct ethtool_mm_set_req *req, - __u8 verify_enabled) -{ - req->_present.verify_enabled = 1; - req->verify_enabled = verify_enabled; -} -static inline void -ethtool_mm_set_req_set_verify_time(struct ethtool_mm_set_req *req, - __u32 verify_time) -{ - req->_present.verify_time = 1; - req->verify_time = verify_time; -} -static inline void -ethtool_mm_set_req_set_tx_enabled(struct ethtool_mm_set_req *req, - __u8 tx_enabled) -{ - req->_present.tx_enabled = 1; - req->tx_enabled = tx_enabled; -} -static inline void -ethtool_mm_set_req_set_pmac_enabled(struct ethtool_mm_set_req *req, - __u8 pmac_enabled) -{ - req->_present.pmac_enabled = 1; - req->pmac_enabled = pmac_enabled; -} -static inline void -ethtool_mm_set_req_set_tx_min_frag_size(struct ethtool_mm_set_req *req, - __u32 tx_min_frag_size) -{ - req->_present.tx_min_frag_size = 1; - req->tx_min_frag_size = tx_min_frag_size; -} - -/* - * Set MAC Merge configuration - */ -int ethtool_mm_set(struct ynl_sock *ys, struct ethtool_mm_set_req *req); - -/* ETHTOOL_MSG_CABLE_TEST_NTF - event */ -struct ethtool_cable_test_ntf_rsp { - struct { - __u32 header:1; - __u32 status:1; - } _present; - - struct ethtool_header header; - __u8 status; -}; - -struct ethtool_cable_test_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_cable_test_ntf *ntf); - struct ethtool_cable_test_ntf_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_cable_test_ntf_free(struct ethtool_cable_test_ntf *rsp); - -/* ETHTOOL_MSG_CABLE_TEST_TDR_NTF - event */ -struct ethtool_cable_test_tdr_ntf_rsp { - struct { - __u32 header:1; - __u32 status:1; - __u32 nest:1; - } _present; - - struct ethtool_header header; - __u8 status; - struct ethtool_cable_nest nest; -}; - -struct ethtool_cable_test_tdr_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ethtool_cable_test_tdr_ntf *ntf); - struct ethtool_cable_test_tdr_ntf_rsp obj __attribute__((aligned(8))); -}; - -void ethtool_cable_test_tdr_ntf_free(struct ethtool_cable_test_tdr_ntf *rsp); - -#endif /* _LINUX_ETHTOOL_GEN_H */ diff --git a/tools/net/ynl/generated/fou-user.c b/tools/net/ynl/generated/fou-user.c deleted file mode 100644 index f30bef23bc..0000000000 --- a/tools/net/ynl/generated/fou-user.c +++ /dev/null @@ -1,330 +0,0 @@ -// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/fou.yaml */ -/* YNL-GEN user source */ - -#include -#include -#include "fou-user.h" -#include "ynl.h" -#include - -#include -#include - -/* Enums */ -static const char * const fou_op_strmap[] = { - [FOU_CMD_ADD] = "add", - [FOU_CMD_DEL] = "del", - [FOU_CMD_GET] = "get", -}; - -const char *fou_op_str(int op) -{ - if (op < 0 || op >= (int)MNL_ARRAY_SIZE(fou_op_strmap)) - return NULL; - return fou_op_strmap[op]; -} - -static const char * const fou_encap_type_strmap[] = { - [0] = "unspec", - [1] = "direct", - [2] = "gue", -}; - -const char *fou_encap_type_str(int value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(fou_encap_type_strmap)) - return NULL; - return fou_encap_type_strmap[value]; -} - -/* Policies */ -struct ynl_policy_attr fou_policy[FOU_ATTR_MAX + 1] = { - [FOU_ATTR_UNSPEC] = { .name = "unspec", .type = YNL_PT_REJECT, }, - [FOU_ATTR_PORT] = { .name = "port", .type = YNL_PT_U16, }, - [FOU_ATTR_AF] = { .name = "af", .type = YNL_PT_U8, }, - [FOU_ATTR_IPPROTO] = { .name = "ipproto", .type = YNL_PT_U8, }, - [FOU_ATTR_TYPE] = { .name = "type", .type = YNL_PT_U8, }, - [FOU_ATTR_REMCSUM_NOPARTIAL] = { .name = "remcsum_nopartial", .type = YNL_PT_FLAG, }, - [FOU_ATTR_LOCAL_V4] = { .name = "local_v4", .type = YNL_PT_U32, }, - [FOU_ATTR_LOCAL_V6] = { .name = "local_v6", .type = YNL_PT_BINARY,}, - [FOU_ATTR_PEER_V4] = { .name = "peer_v4", .type = YNL_PT_U32, }, - [FOU_ATTR_PEER_V6] = { .name = "peer_v6", .type = YNL_PT_BINARY,}, - [FOU_ATTR_PEER_PORT] = { .name = "peer_port", .type = YNL_PT_U16, }, - [FOU_ATTR_IFINDEX] = { .name = "ifindex", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest fou_nest = { - .max_attr = FOU_ATTR_MAX, - .table = fou_policy, -}; - -/* Common nested types */ -/* ============== FOU_CMD_ADD ============== */ -/* FOU_CMD_ADD - do */ -void fou_add_req_free(struct fou_add_req *req) -{ - free(req->local_v6); - free(req->peer_v6); - free(req); -} - -int fou_add(struct ynl_sock *ys, struct fou_add_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, FOU_CMD_ADD, 1); - ys->req_policy = &fou_nest; - - if (req->_present.port) - mnl_attr_put_u16(nlh, FOU_ATTR_PORT, req->port); - if (req->_present.ipproto) - mnl_attr_put_u8(nlh, FOU_ATTR_IPPROTO, req->ipproto); - if (req->_present.type) - mnl_attr_put_u8(nlh, FOU_ATTR_TYPE, req->type); - if (req->_present.remcsum_nopartial) - mnl_attr_put(nlh, FOU_ATTR_REMCSUM_NOPARTIAL, 0, NULL); - if (req->_present.local_v4) - mnl_attr_put_u32(nlh, FOU_ATTR_LOCAL_V4, req->local_v4); - if (req->_present.peer_v4) - mnl_attr_put_u32(nlh, FOU_ATTR_PEER_V4, req->peer_v4); - if (req->_present.local_v6_len) - mnl_attr_put(nlh, FOU_ATTR_LOCAL_V6, req->_present.local_v6_len, req->local_v6); - if (req->_present.peer_v6_len) - mnl_attr_put(nlh, FOU_ATTR_PEER_V6, req->_present.peer_v6_len, req->peer_v6); - if (req->_present.peer_port) - mnl_attr_put_u16(nlh, FOU_ATTR_PEER_PORT, req->peer_port); - if (req->_present.ifindex) - mnl_attr_put_u32(nlh, FOU_ATTR_IFINDEX, req->ifindex); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== FOU_CMD_DEL ============== */ -/* FOU_CMD_DEL - do */ -void fou_del_req_free(struct fou_del_req *req) -{ - free(req->local_v6); - free(req->peer_v6); - free(req); -} - -int fou_del(struct ynl_sock *ys, struct fou_del_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, FOU_CMD_DEL, 1); - ys->req_policy = &fou_nest; - - if (req->_present.af) - mnl_attr_put_u8(nlh, FOU_ATTR_AF, req->af); - if (req->_present.ifindex) - mnl_attr_put_u32(nlh, FOU_ATTR_IFINDEX, req->ifindex); - if (req->_present.port) - mnl_attr_put_u16(nlh, FOU_ATTR_PORT, req->port); - if (req->_present.peer_port) - mnl_attr_put_u16(nlh, FOU_ATTR_PEER_PORT, req->peer_port); - if (req->_present.local_v4) - mnl_attr_put_u32(nlh, FOU_ATTR_LOCAL_V4, req->local_v4); - if (req->_present.peer_v4) - mnl_attr_put_u32(nlh, FOU_ATTR_PEER_V4, req->peer_v4); - if (req->_present.local_v6_len) - mnl_attr_put(nlh, FOU_ATTR_LOCAL_V6, req->_present.local_v6_len, req->local_v6); - if (req->_present.peer_v6_len) - mnl_attr_put(nlh, FOU_ATTR_PEER_V6, req->_present.peer_v6_len, req->peer_v6); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -/* ============== FOU_CMD_GET ============== */ -/* FOU_CMD_GET - do */ -void fou_get_req_free(struct fou_get_req *req) -{ - free(req->local_v6); - free(req->peer_v6); - free(req); -} - -void fou_get_rsp_free(struct fou_get_rsp *rsp) -{ - free(rsp->local_v6); - free(rsp->peer_v6); - free(rsp); -} - -int fou_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - const struct nlattr *attr; - struct fou_get_rsp *dst; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == FOU_ATTR_PORT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.port = 1; - dst->port = mnl_attr_get_u16(attr); - } else if (type == FOU_ATTR_IPPROTO) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.ipproto = 1; - dst->ipproto = mnl_attr_get_u8(attr); - } else if (type == FOU_ATTR_TYPE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.type = 1; - dst->type = mnl_attr_get_u8(attr); - } else if (type == FOU_ATTR_REMCSUM_NOPARTIAL) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.remcsum_nopartial = 1; - } else if (type == FOU_ATTR_LOCAL_V4) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.local_v4 = 1; - dst->local_v4 = mnl_attr_get_u32(attr); - } else if (type == FOU_ATTR_PEER_V4) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.peer_v4 = 1; - dst->peer_v4 = mnl_attr_get_u32(attr); - } else if (type == FOU_ATTR_LOCAL_V6) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.local_v6_len = len; - dst->local_v6 = malloc(len); - memcpy(dst->local_v6, mnl_attr_get_payload(attr), len); - } else if (type == FOU_ATTR_PEER_V6) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.peer_v6_len = len; - dst->peer_v6 = malloc(len); - memcpy(dst->peer_v6, mnl_attr_get_payload(attr), len); - } else if (type == FOU_ATTR_PEER_PORT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.peer_port = 1; - dst->peer_port = mnl_attr_get_u16(attr); - } else if (type == FOU_ATTR_IFINDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.ifindex = 1; - dst->ifindex = mnl_attr_get_u32(attr); - } - } - - return MNL_CB_OK; -} - -struct fou_get_rsp *fou_get(struct ynl_sock *ys, struct fou_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct fou_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, FOU_CMD_GET, 1); - ys->req_policy = &fou_nest; - yrs.yarg.rsp_policy = &fou_nest; - - if (req->_present.af) - mnl_attr_put_u8(nlh, FOU_ATTR_AF, req->af); - if (req->_present.ifindex) - mnl_attr_put_u32(nlh, FOU_ATTR_IFINDEX, req->ifindex); - if (req->_present.port) - mnl_attr_put_u16(nlh, FOU_ATTR_PORT, req->port); - if (req->_present.peer_port) - mnl_attr_put_u16(nlh, FOU_ATTR_PEER_PORT, req->peer_port); - if (req->_present.local_v4) - mnl_attr_put_u32(nlh, FOU_ATTR_LOCAL_V4, req->local_v4); - if (req->_present.peer_v4) - mnl_attr_put_u32(nlh, FOU_ATTR_PEER_V4, req->peer_v4); - if (req->_present.local_v6_len) - mnl_attr_put(nlh, FOU_ATTR_LOCAL_V6, req->_present.local_v6_len, req->local_v6); - if (req->_present.peer_v6_len) - mnl_attr_put(nlh, FOU_ATTR_PEER_V6, req->_present.peer_v6_len, req->peer_v6); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = fou_get_rsp_parse; - yrs.rsp_cmd = FOU_CMD_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - fou_get_rsp_free(rsp); - return NULL; -} - -/* FOU_CMD_GET - dump */ -void fou_get_list_free(struct fou_get_list *rsp) -{ - struct fou_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.local_v6); - free(rsp->obj.peer_v6); - free(rsp); - } -} - -struct fou_get_list *fou_get_dump(struct ynl_sock *ys) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct fou_get_list); - yds.cb = fou_get_rsp_parse; - yds.rsp_cmd = FOU_CMD_GET; - yds.rsp_policy = &fou_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, FOU_CMD_GET, 1); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - fou_get_list_free(yds.first); - return NULL; -} - -const struct ynl_family ynl_fou_family = { - .name = "fou", -}; diff --git a/tools/net/ynl/generated/fou-user.h b/tools/net/ynl/generated/fou-user.h deleted file mode 100644 index fd566716dd..0000000000 --- a/tools/net/ynl/generated/fou-user.h +++ /dev/null @@ -1,343 +0,0 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/fou.yaml */ -/* YNL-GEN user header */ - -#ifndef _LINUX_FOU_GEN_H -#define _LINUX_FOU_GEN_H - -#include -#include -#include -#include - -struct ynl_sock; - -extern const struct ynl_family ynl_fou_family; - -/* Enums */ -const char *fou_op_str(int op); -const char *fou_encap_type_str(int value); - -/* Common nested types */ -/* ============== FOU_CMD_ADD ============== */ -/* FOU_CMD_ADD - do */ -struct fou_add_req { - struct { - __u32 port:1; - __u32 ipproto:1; - __u32 type:1; - __u32 remcsum_nopartial:1; - __u32 local_v4:1; - __u32 peer_v4:1; - __u32 local_v6_len; - __u32 peer_v6_len; - __u32 peer_port:1; - __u32 ifindex:1; - } _present; - - __u16 port /* big-endian */; - __u8 ipproto; - __u8 type; - __u32 local_v4; - __u32 peer_v4; - void *local_v6; - void *peer_v6; - __u16 peer_port /* big-endian */; - __s32 ifindex; -}; - -static inline struct fou_add_req *fou_add_req_alloc(void) -{ - return calloc(1, sizeof(struct fou_add_req)); -} -void fou_add_req_free(struct fou_add_req *req); - -static inline void -fou_add_req_set_port(struct fou_add_req *req, __u16 port /* big-endian */) -{ - req->_present.port = 1; - req->port = port; -} -static inline void -fou_add_req_set_ipproto(struct fou_add_req *req, __u8 ipproto) -{ - req->_present.ipproto = 1; - req->ipproto = ipproto; -} -static inline void fou_add_req_set_type(struct fou_add_req *req, __u8 type) -{ - req->_present.type = 1; - req->type = type; -} -static inline void fou_add_req_set_remcsum_nopartial(struct fou_add_req *req) -{ - req->_present.remcsum_nopartial = 1; -} -static inline void -fou_add_req_set_local_v4(struct fou_add_req *req, __u32 local_v4) -{ - req->_present.local_v4 = 1; - req->local_v4 = local_v4; -} -static inline void -fou_add_req_set_peer_v4(struct fou_add_req *req, __u32 peer_v4) -{ - req->_present.peer_v4 = 1; - req->peer_v4 = peer_v4; -} -static inline void -fou_add_req_set_local_v6(struct fou_add_req *req, const void *local_v6, - size_t len) -{ - free(req->local_v6); - req->_present.local_v6_len = len; - req->local_v6 = malloc(req->_present.local_v6_len); - memcpy(req->local_v6, local_v6, req->_present.local_v6_len); -} -static inline void -fou_add_req_set_peer_v6(struct fou_add_req *req, const void *peer_v6, - size_t len) -{ - free(req->peer_v6); - req->_present.peer_v6_len = len; - req->peer_v6 = malloc(req->_present.peer_v6_len); - memcpy(req->peer_v6, peer_v6, req->_present.peer_v6_len); -} -static inline void -fou_add_req_set_peer_port(struct fou_add_req *req, - __u16 peer_port /* big-endian */) -{ - req->_present.peer_port = 1; - req->peer_port = peer_port; -} -static inline void -fou_add_req_set_ifindex(struct fou_add_req *req, __s32 ifindex) -{ - req->_present.ifindex = 1; - req->ifindex = ifindex; -} - -/* - * Add port. - */ -int fou_add(struct ynl_sock *ys, struct fou_add_req *req); - -/* ============== FOU_CMD_DEL ============== */ -/* FOU_CMD_DEL - do */ -struct fou_del_req { - struct { - __u32 af:1; - __u32 ifindex:1; - __u32 port:1; - __u32 peer_port:1; - __u32 local_v4:1; - __u32 peer_v4:1; - __u32 local_v6_len; - __u32 peer_v6_len; - } _present; - - __u8 af; - __s32 ifindex; - __u16 port /* big-endian */; - __u16 peer_port /* big-endian */; - __u32 local_v4; - __u32 peer_v4; - void *local_v6; - void *peer_v6; -}; - -static inline struct fou_del_req *fou_del_req_alloc(void) -{ - return calloc(1, sizeof(struct fou_del_req)); -} -void fou_del_req_free(struct fou_del_req *req); - -static inline void fou_del_req_set_af(struct fou_del_req *req, __u8 af) -{ - req->_present.af = 1; - req->af = af; -} -static inline void -fou_del_req_set_ifindex(struct fou_del_req *req, __s32 ifindex) -{ - req->_present.ifindex = 1; - req->ifindex = ifindex; -} -static inline void -fou_del_req_set_port(struct fou_del_req *req, __u16 port /* big-endian */) -{ - req->_present.port = 1; - req->port = port; -} -static inline void -fou_del_req_set_peer_port(struct fou_del_req *req, - __u16 peer_port /* big-endian */) -{ - req->_present.peer_port = 1; - req->peer_port = peer_port; -} -static inline void -fou_del_req_set_local_v4(struct fou_del_req *req, __u32 local_v4) -{ - req->_present.local_v4 = 1; - req->local_v4 = local_v4; -} -static inline void -fou_del_req_set_peer_v4(struct fou_del_req *req, __u32 peer_v4) -{ - req->_present.peer_v4 = 1; - req->peer_v4 = peer_v4; -} -static inline void -fou_del_req_set_local_v6(struct fou_del_req *req, const void *local_v6, - size_t len) -{ - free(req->local_v6); - req->_present.local_v6_len = len; - req->local_v6 = malloc(req->_present.local_v6_len); - memcpy(req->local_v6, local_v6, req->_present.local_v6_len); -} -static inline void -fou_del_req_set_peer_v6(struct fou_del_req *req, const void *peer_v6, - size_t len) -{ - free(req->peer_v6); - req->_present.peer_v6_len = len; - req->peer_v6 = malloc(req->_present.peer_v6_len); - memcpy(req->peer_v6, peer_v6, req->_present.peer_v6_len); -} - -/* - * Delete port. - */ -int fou_del(struct ynl_sock *ys, struct fou_del_req *req); - -/* ============== FOU_CMD_GET ============== */ -/* FOU_CMD_GET - do */ -struct fou_get_req { - struct { - __u32 af:1; - __u32 ifindex:1; - __u32 port:1; - __u32 peer_port:1; - __u32 local_v4:1; - __u32 peer_v4:1; - __u32 local_v6_len; - __u32 peer_v6_len; - } _present; - - __u8 af; - __s32 ifindex; - __u16 port /* big-endian */; - __u16 peer_port /* big-endian */; - __u32 local_v4; - __u32 peer_v4; - void *local_v6; - void *peer_v6; -}; - -static inline struct fou_get_req *fou_get_req_alloc(void) -{ - return calloc(1, sizeof(struct fou_get_req)); -} -void fou_get_req_free(struct fou_get_req *req); - -static inline void fou_get_req_set_af(struct fou_get_req *req, __u8 af) -{ - req->_present.af = 1; - req->af = af; -} -static inline void -fou_get_req_set_ifindex(struct fou_get_req *req, __s32 ifindex) -{ - req->_present.ifindex = 1; - req->ifindex = ifindex; -} -static inline void -fou_get_req_set_port(struct fou_get_req *req, __u16 port /* big-endian */) -{ - req->_present.port = 1; - req->port = port; -} -static inline void -fou_get_req_set_peer_port(struct fou_get_req *req, - __u16 peer_port /* big-endian */) -{ - req->_present.peer_port = 1; - req->peer_port = peer_port; -} -static inline void -fou_get_req_set_local_v4(struct fou_get_req *req, __u32 local_v4) -{ - req->_present.local_v4 = 1; - req->local_v4 = local_v4; -} -static inline void -fou_get_req_set_peer_v4(struct fou_get_req *req, __u32 peer_v4) -{ - req->_present.peer_v4 = 1; - req->peer_v4 = peer_v4; -} -static inline void -fou_get_req_set_local_v6(struct fou_get_req *req, const void *local_v6, - size_t len) -{ - free(req->local_v6); - req->_present.local_v6_len = len; - req->local_v6 = malloc(req->_present.local_v6_len); - memcpy(req->local_v6, local_v6, req->_present.local_v6_len); -} -static inline void -fou_get_req_set_peer_v6(struct fou_get_req *req, const void *peer_v6, - size_t len) -{ - free(req->peer_v6); - req->_present.peer_v6_len = len; - req->peer_v6 = malloc(req->_present.peer_v6_len); - memcpy(req->peer_v6, peer_v6, req->_present.peer_v6_len); -} - -struct fou_get_rsp { - struct { - __u32 port:1; - __u32 ipproto:1; - __u32 type:1; - __u32 remcsum_nopartial:1; - __u32 local_v4:1; - __u32 peer_v4:1; - __u32 local_v6_len; - __u32 peer_v6_len; - __u32 peer_port:1; - __u32 ifindex:1; - } _present; - - __u16 port /* big-endian */; - __u8 ipproto; - __u8 type; - __u32 local_v4; - __u32 peer_v4; - void *local_v6; - void *peer_v6; - __u16 peer_port /* big-endian */; - __s32 ifindex; -}; - -void fou_get_rsp_free(struct fou_get_rsp *rsp); - -/* - * Get tunnel info. - */ -struct fou_get_rsp *fou_get(struct ynl_sock *ys, struct fou_get_req *req); - -/* FOU_CMD_GET - dump */ -struct fou_get_list { - struct fou_get_list *next; - struct fou_get_rsp obj __attribute__((aligned(8))); -}; - -void fou_get_list_free(struct fou_get_list *rsp); - -struct fou_get_list *fou_get_dump(struct ynl_sock *ys); - -#endif /* _LINUX_FOU_GEN_H */ diff --git a/tools/net/ynl/generated/handshake-user.c b/tools/net/ynl/generated/handshake-user.c deleted file mode 100644 index 6901f8462c..0000000000 --- a/tools/net/ynl/generated/handshake-user.c +++ /dev/null @@ -1,332 +0,0 @@ -// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/handshake.yaml */ -/* YNL-GEN user source */ - -#include -#include -#include "handshake-user.h" -#include "ynl.h" -#include - -#include -#include - -/* Enums */ -static const char * const handshake_op_strmap[] = { - [HANDSHAKE_CMD_READY] = "ready", - [HANDSHAKE_CMD_ACCEPT] = "accept", - [HANDSHAKE_CMD_DONE] = "done", -}; - -const char *handshake_op_str(int op) -{ - if (op < 0 || op >= (int)MNL_ARRAY_SIZE(handshake_op_strmap)) - return NULL; - return handshake_op_strmap[op]; -} - -static const char * const handshake_handler_class_strmap[] = { - [0] = "none", - [1] = "tlshd", - [2] = "max", -}; - -const char *handshake_handler_class_str(enum handshake_handler_class value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(handshake_handler_class_strmap)) - return NULL; - return handshake_handler_class_strmap[value]; -} - -static const char * const handshake_msg_type_strmap[] = { - [0] = "unspec", - [1] = "clienthello", - [2] = "serverhello", -}; - -const char *handshake_msg_type_str(enum handshake_msg_type value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(handshake_msg_type_strmap)) - return NULL; - return handshake_msg_type_strmap[value]; -} - -static const char * const handshake_auth_strmap[] = { - [0] = "unspec", - [1] = "unauth", - [2] = "psk", - [3] = "x509", -}; - -const char *handshake_auth_str(enum handshake_auth value) -{ - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(handshake_auth_strmap)) - return NULL; - return handshake_auth_strmap[value]; -} - -/* Policies */ -struct ynl_policy_attr handshake_x509_policy[HANDSHAKE_A_X509_MAX + 1] = { - [HANDSHAKE_A_X509_CERT] = { .name = "cert", .type = YNL_PT_U32, }, - [HANDSHAKE_A_X509_PRIVKEY] = { .name = "privkey", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest handshake_x509_nest = { - .max_attr = HANDSHAKE_A_X509_MAX, - .table = handshake_x509_policy, -}; - -struct ynl_policy_attr handshake_accept_policy[HANDSHAKE_A_ACCEPT_MAX + 1] = { - [HANDSHAKE_A_ACCEPT_SOCKFD] = { .name = "sockfd", .type = YNL_PT_U32, }, - [HANDSHAKE_A_ACCEPT_HANDLER_CLASS] = { .name = "handler-class", .type = YNL_PT_U32, }, - [HANDSHAKE_A_ACCEPT_MESSAGE_TYPE] = { .name = "message-type", .type = YNL_PT_U32, }, - [HANDSHAKE_A_ACCEPT_TIMEOUT] = { .name = "timeout", .type = YNL_PT_U32, }, - [HANDSHAKE_A_ACCEPT_AUTH_MODE] = { .name = "auth-mode", .type = YNL_PT_U32, }, - [HANDSHAKE_A_ACCEPT_PEER_IDENTITY] = { .name = "peer-identity", .type = YNL_PT_U32, }, - [HANDSHAKE_A_ACCEPT_CERTIFICATE] = { .name = "certificate", .type = YNL_PT_NEST, .nest = &handshake_x509_nest, }, - [HANDSHAKE_A_ACCEPT_PEERNAME] = { .name = "peername", .type = YNL_PT_NUL_STR, }, -}; - -struct ynl_policy_nest handshake_accept_nest = { - .max_attr = HANDSHAKE_A_ACCEPT_MAX, - .table = handshake_accept_policy, -}; - -struct ynl_policy_attr handshake_done_policy[HANDSHAKE_A_DONE_MAX + 1] = { - [HANDSHAKE_A_DONE_STATUS] = { .name = "status", .type = YNL_PT_U32, }, - [HANDSHAKE_A_DONE_SOCKFD] = { .name = "sockfd", .type = YNL_PT_U32, }, - [HANDSHAKE_A_DONE_REMOTE_AUTH] = { .name = "remote-auth", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest handshake_done_nest = { - .max_attr = HANDSHAKE_A_DONE_MAX, - .table = handshake_done_policy, -}; - -/* Common nested types */ -void handshake_x509_free(struct handshake_x509 *obj) -{ -} - -int handshake_x509_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct handshake_x509 *dst = yarg->data; - const struct nlattr *attr; - - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == HANDSHAKE_A_X509_CERT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.cert = 1; - dst->cert = mnl_attr_get_u32(attr); - } else if (type == HANDSHAKE_A_X509_PRIVKEY) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.privkey = 1; - dst->privkey = mnl_attr_get_u32(attr); - } - } - - return 0; -} - -/* ============== HANDSHAKE_CMD_ACCEPT ============== */ -/* HANDSHAKE_CMD_ACCEPT - do */ -void handshake_accept_req_free(struct handshake_accept_req *req) -{ - free(req); -} - -void handshake_accept_rsp_free(struct handshake_accept_rsp *rsp) -{ - unsigned int i; - - free(rsp->peer_identity); - for (i = 0; i < rsp->n_certificate; i++) - handshake_x509_free(&rsp->certificate[i]); - free(rsp->certificate); - free(rsp->peername); - free(rsp); -} - -int handshake_accept_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct handshake_accept_rsp *dst; - unsigned int n_peer_identity = 0; - unsigned int n_certificate = 0; - const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - dst = yarg->data; - parg.ys = yarg->ys; - - if (dst->certificate) - return ynl_error_parse(yarg, "attribute already present (accept.certificate)"); - if (dst->peer_identity) - return ynl_error_parse(yarg, "attribute already present (accept.peer-identity)"); - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == HANDSHAKE_A_ACCEPT_SOCKFD) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sockfd = 1; - dst->sockfd = mnl_attr_get_u32(attr); - } else if (type == HANDSHAKE_A_ACCEPT_MESSAGE_TYPE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.message_type = 1; - dst->message_type = mnl_attr_get_u32(attr); - } else if (type == HANDSHAKE_A_ACCEPT_TIMEOUT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.timeout = 1; - dst->timeout = mnl_attr_get_u32(attr); - } else if (type == HANDSHAKE_A_ACCEPT_AUTH_MODE) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.auth_mode = 1; - dst->auth_mode = mnl_attr_get_u32(attr); - } else if (type == HANDSHAKE_A_ACCEPT_PEER_IDENTITY) { - n_peer_identity++; - } else if (type == HANDSHAKE_A_ACCEPT_CERTIFICATE) { - n_certificate++; - } else if (type == HANDSHAKE_A_ACCEPT_PEERNAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.peername_len = len; - dst->peername = malloc(len + 1); - memcpy(dst->peername, mnl_attr_get_str(attr), len); - dst->peername[len] = 0; - } - } - - if (n_certificate) { - dst->certificate = calloc(n_certificate, sizeof(*dst->certificate)); - dst->n_certificate = n_certificate; - i = 0; - parg.rsp_policy = &handshake_x509_nest; - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - if (mnl_attr_get_type(attr) == HANDSHAKE_A_ACCEPT_CERTIFICATE) { - parg.data = &dst->certificate[i]; - if (handshake_x509_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } - } - } - if (n_peer_identity) { - dst->peer_identity = calloc(n_peer_identity, sizeof(*dst->peer_identity)); - dst->n_peer_identity = n_peer_identity; - i = 0; - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - if (mnl_attr_get_type(attr) == HANDSHAKE_A_ACCEPT_PEER_IDENTITY) { - dst->peer_identity[i] = mnl_attr_get_u32(attr); - i++; - } - } - } - - return MNL_CB_OK; -} - -struct handshake_accept_rsp * -handshake_accept(struct ynl_sock *ys, struct handshake_accept_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct handshake_accept_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, HANDSHAKE_CMD_ACCEPT, 1); - ys->req_policy = &handshake_accept_nest; - yrs.yarg.rsp_policy = &handshake_accept_nest; - - if (req->_present.handler_class) - mnl_attr_put_u32(nlh, HANDSHAKE_A_ACCEPT_HANDLER_CLASS, req->handler_class); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = handshake_accept_rsp_parse; - yrs.rsp_cmd = HANDSHAKE_CMD_ACCEPT; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - handshake_accept_rsp_free(rsp); - return NULL; -} - -/* HANDSHAKE_CMD_ACCEPT - notify */ -void handshake_accept_ntf_free(struct handshake_accept_ntf *rsp) -{ - unsigned int i; - - free(rsp->obj.peer_identity); - for (i = 0; i < rsp->obj.n_certificate; i++) - handshake_x509_free(&rsp->obj.certificate[i]); - free(rsp->obj.certificate); - free(rsp->obj.peername); - free(rsp); -} - -/* ============== HANDSHAKE_CMD_DONE ============== */ -/* HANDSHAKE_CMD_DONE - do */ -void handshake_done_req_free(struct handshake_done_req *req) -{ - free(req->remote_auth); - free(req); -} - -int handshake_done(struct ynl_sock *ys, struct handshake_done_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, HANDSHAKE_CMD_DONE, 1); - ys->req_policy = &handshake_done_nest; - - if (req->_present.status) - mnl_attr_put_u32(nlh, HANDSHAKE_A_DONE_STATUS, req->status); - if (req->_present.sockfd) - mnl_attr_put_u32(nlh, HANDSHAKE_A_DONE_SOCKFD, req->sockfd); - for (unsigned int i = 0; i < req->n_remote_auth; i++) - mnl_attr_put_u32(nlh, HANDSHAKE_A_DONE_REMOTE_AUTH, req->remote_auth[i]); - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - return -1; - - return 0; -} - -static const struct ynl_ntf_info handshake_ntf_info[] = { - [HANDSHAKE_CMD_READY] = { - .alloc_sz = sizeof(struct handshake_accept_ntf), - .cb = handshake_accept_rsp_parse, - .policy = &handshake_accept_nest, - .free = (void *)handshake_accept_ntf_free, - }, -}; - -const struct ynl_family ynl_handshake_family = { - .name = "handshake", - .ntf_info = handshake_ntf_info, - .ntf_info_size = MNL_ARRAY_SIZE(handshake_ntf_info), -}; diff --git a/tools/net/ynl/generated/handshake-user.h b/tools/net/ynl/generated/handshake-user.h deleted file mode 100644 index bce537d8b8..0000000000 --- a/tools/net/ynl/generated/handshake-user.h +++ /dev/null @@ -1,145 +0,0 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/handshake.yaml */ -/* YNL-GEN user header */ - -#ifndef _LINUX_HANDSHAKE_GEN_H -#define _LINUX_HANDSHAKE_GEN_H - -#include -#include -#include -#include - -struct ynl_sock; - -extern const struct ynl_family ynl_handshake_family; - -/* Enums */ -const char *handshake_op_str(int op); -const char *handshake_handler_class_str(enum handshake_handler_class value); -const char *handshake_msg_type_str(enum handshake_msg_type value); -const char *handshake_auth_str(enum handshake_auth value); - -/* Common nested types */ -struct handshake_x509 { - struct { - __u32 cert:1; - __u32 privkey:1; - } _present; - - __s32 cert; - __s32 privkey; -}; - -/* ============== HANDSHAKE_CMD_ACCEPT ============== */ -/* HANDSHAKE_CMD_ACCEPT - do */ -struct handshake_accept_req { - struct { - __u32 handler_class:1; - } _present; - - enum handshake_handler_class handler_class; -}; - -static inline struct handshake_accept_req *handshake_accept_req_alloc(void) -{ - return calloc(1, sizeof(struct handshake_accept_req)); -} -void handshake_accept_req_free(struct handshake_accept_req *req); - -static inline void -handshake_accept_req_set_handler_class(struct handshake_accept_req *req, - enum handshake_handler_class handler_class) -{ - req->_present.handler_class = 1; - req->handler_class = handler_class; -} - -struct handshake_accept_rsp { - struct { - __u32 sockfd:1; - __u32 message_type:1; - __u32 timeout:1; - __u32 auth_mode:1; - __u32 peername_len; - } _present; - - __s32 sockfd; - enum handshake_msg_type message_type; - __u32 timeout; - enum handshake_auth auth_mode; - unsigned int n_peer_identity; - __u32 *peer_identity; - unsigned int n_certificate; - struct handshake_x509 *certificate; - char *peername; -}; - -void handshake_accept_rsp_free(struct handshake_accept_rsp *rsp); - -/* - * Handler retrieves next queued handshake request - */ -struct handshake_accept_rsp * -handshake_accept(struct ynl_sock *ys, struct handshake_accept_req *req); - -/* HANDSHAKE_CMD_ACCEPT - notify */ -struct handshake_accept_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct handshake_accept_ntf *ntf); - struct handshake_accept_rsp obj __attribute__((aligned(8))); -}; - -void handshake_accept_ntf_free(struct handshake_accept_ntf *rsp); - -/* ============== HANDSHAKE_CMD_DONE ============== */ -/* HANDSHAKE_CMD_DONE - do */ -struct handshake_done_req { - struct { - __u32 status:1; - __u32 sockfd:1; - } _present; - - __u32 status; - __s32 sockfd; - unsigned int n_remote_auth; - __u32 *remote_auth; -}; - -static inline struct handshake_done_req *handshake_done_req_alloc(void) -{ - return calloc(1, sizeof(struct handshake_done_req)); -} -void handshake_done_req_free(struct handshake_done_req *req); - -static inline void -handshake_done_req_set_status(struct handshake_done_req *req, __u32 status) -{ - req->_present.status = 1; - req->status = status; -} -static inline void -handshake_done_req_set_sockfd(struct handshake_done_req *req, __s32 sockfd) -{ - req->_present.sockfd = 1; - req->sockfd = sockfd; -} -static inline void -__handshake_done_req_set_remote_auth(struct handshake_done_req *req, - __u32 *remote_auth, - unsigned int n_remote_auth) -{ - free(req->remote_auth); - req->remote_auth = remote_auth; - req->n_remote_auth = n_remote_auth; -} - -/* - * Handler reports handshake completion - */ -int handshake_done(struct ynl_sock *ys, struct handshake_done_req *req); - -#endif /* _LINUX_HANDSHAKE_GEN_H */ diff --git a/tools/net/ynl/generated/netdev-user.c b/tools/net/ynl/generated/netdev-user.c deleted file mode 100644 index b5ffe8cd11..0000000000 --- a/tools/net/ynl/generated/netdev-user.c +++ /dev/null @@ -1,225 +0,0 @@ -// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/netdev.yaml */ -/* YNL-GEN user source */ - -#include -#include -#include "netdev-user.h" -#include "ynl.h" -#include - -#include -#include - -/* Enums */ -static const char * const netdev_op_strmap[] = { - [NETDEV_CMD_DEV_GET] = "dev-get", - [NETDEV_CMD_DEV_ADD_NTF] = "dev-add-ntf", - [NETDEV_CMD_DEV_DEL_NTF] = "dev-del-ntf", - [NETDEV_CMD_DEV_CHANGE_NTF] = "dev-change-ntf", -}; - -const char *netdev_op_str(int op) -{ - if (op < 0 || op >= (int)MNL_ARRAY_SIZE(netdev_op_strmap)) - return NULL; - return netdev_op_strmap[op]; -} - -static const char * const netdev_xdp_act_strmap[] = { - [0] = "basic", - [1] = "redirect", - [2] = "ndo-xmit", - [3] = "xsk-zerocopy", - [4] = "hw-offload", - [5] = "rx-sg", - [6] = "ndo-xmit-sg", -}; - -const char *netdev_xdp_act_str(enum netdev_xdp_act value) -{ - value = ffs(value) - 1; - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(netdev_xdp_act_strmap)) - return NULL; - return netdev_xdp_act_strmap[value]; -} - -static const char * const netdev_xdp_rx_metadata_strmap[] = { - [0] = "timestamp", - [1] = "hash", -}; - -const char *netdev_xdp_rx_metadata_str(enum netdev_xdp_rx_metadata value) -{ - value = ffs(value) - 1; - if (value < 0 || value >= (int)MNL_ARRAY_SIZE(netdev_xdp_rx_metadata_strmap)) - return NULL; - return netdev_xdp_rx_metadata_strmap[value]; -} - -/* Policies */ -struct ynl_policy_attr netdev_dev_policy[NETDEV_A_DEV_MAX + 1] = { - [NETDEV_A_DEV_IFINDEX] = { .name = "ifindex", .type = YNL_PT_U32, }, - [NETDEV_A_DEV_PAD] = { .name = "pad", .type = YNL_PT_IGNORE, }, - [NETDEV_A_DEV_XDP_FEATURES] = { .name = "xdp-features", .type = YNL_PT_U64, }, - [NETDEV_A_DEV_XDP_ZC_MAX_SEGS] = { .name = "xdp-zc-max-segs", .type = YNL_PT_U32, }, - [NETDEV_A_DEV_XDP_RX_METADATA_FEATURES] = { .name = "xdp-rx-metadata-features", .type = YNL_PT_U64, }, -}; - -struct ynl_policy_nest netdev_dev_nest = { - .max_attr = NETDEV_A_DEV_MAX, - .table = netdev_dev_policy, -}; - -/* Common nested types */ -/* ============== NETDEV_CMD_DEV_GET ============== */ -/* NETDEV_CMD_DEV_GET - do */ -void netdev_dev_get_req_free(struct netdev_dev_get_req *req) -{ - free(req); -} - -void netdev_dev_get_rsp_free(struct netdev_dev_get_rsp *rsp) -{ - free(rsp); -} - -int netdev_dev_get_rsp_parse(const struct nlmsghdr *nlh, void *data) -{ - struct ynl_parse_arg *yarg = data; - struct netdev_dev_get_rsp *dst; - const struct nlattr *attr; - - dst = yarg->data; - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == NETDEV_A_DEV_IFINDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.ifindex = 1; - dst->ifindex = mnl_attr_get_u32(attr); - } else if (type == NETDEV_A_DEV_XDP_FEATURES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.xdp_features = 1; - dst->xdp_features = mnl_attr_get_u64(attr); - } else if (type == NETDEV_A_DEV_XDP_ZC_MAX_SEGS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.xdp_zc_max_segs = 1; - dst->xdp_zc_max_segs = mnl_attr_get_u32(attr); - } else if (type == NETDEV_A_DEV_XDP_RX_METADATA_FEATURES) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.xdp_rx_metadata_features = 1; - dst->xdp_rx_metadata_features = mnl_attr_get_u64(attr); - } - } - - return MNL_CB_OK; -} - -struct netdev_dev_get_rsp * -netdev_dev_get(struct ynl_sock *ys, struct netdev_dev_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct netdev_dev_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, NETDEV_CMD_DEV_GET, 1); - ys->req_policy = &netdev_dev_nest; - yrs.yarg.rsp_policy = &netdev_dev_nest; - - if (req->_present.ifindex) - mnl_attr_put_u32(nlh, NETDEV_A_DEV_IFINDEX, req->ifindex); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = netdev_dev_get_rsp_parse; - yrs.rsp_cmd = NETDEV_CMD_DEV_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - netdev_dev_get_rsp_free(rsp); - return NULL; -} - -/* NETDEV_CMD_DEV_GET - dump */ -void netdev_dev_get_list_free(struct netdev_dev_get_list *rsp) -{ - struct netdev_dev_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp); - } -} - -struct netdev_dev_get_list *netdev_dev_get_dump(struct ynl_sock *ys) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct netdev_dev_get_list); - yds.cb = netdev_dev_get_rsp_parse; - yds.rsp_cmd = NETDEV_CMD_DEV_GET; - yds.rsp_policy = &netdev_dev_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, NETDEV_CMD_DEV_GET, 1); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - netdev_dev_get_list_free(yds.first); - return NULL; -} - -/* NETDEV_CMD_DEV_GET - notify */ -void netdev_dev_get_ntf_free(struct netdev_dev_get_ntf *rsp) -{ - free(rsp); -} - -static const struct ynl_ntf_info netdev_ntf_info[] = { - [NETDEV_CMD_DEV_ADD_NTF] = { - .alloc_sz = sizeof(struct netdev_dev_get_ntf), - .cb = netdev_dev_get_rsp_parse, - .policy = &netdev_dev_nest, - .free = (void *)netdev_dev_get_ntf_free, - }, - [NETDEV_CMD_DEV_DEL_NTF] = { - .alloc_sz = sizeof(struct netdev_dev_get_ntf), - .cb = netdev_dev_get_rsp_parse, - .policy = &netdev_dev_nest, - .free = (void *)netdev_dev_get_ntf_free, - }, - [NETDEV_CMD_DEV_CHANGE_NTF] = { - .alloc_sz = sizeof(struct netdev_dev_get_ntf), - .cb = netdev_dev_get_rsp_parse, - .policy = &netdev_dev_nest, - .free = (void *)netdev_dev_get_ntf_free, - }, -}; - -const struct ynl_family ynl_netdev_family = { - .name = "netdev", - .ntf_info = netdev_ntf_info, - .ntf_info_size = MNL_ARRAY_SIZE(netdev_ntf_info), -}; diff --git a/tools/net/ynl/generated/netdev-user.h b/tools/net/ynl/generated/netdev-user.h deleted file mode 100644 index 4fafac879d..0000000000 --- a/tools/net/ynl/generated/netdev-user.h +++ /dev/null @@ -1,90 +0,0 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/netdev.yaml */ -/* YNL-GEN user header */ - -#ifndef _LINUX_NETDEV_GEN_H -#define _LINUX_NETDEV_GEN_H - -#include -#include -#include -#include - -struct ynl_sock; - -extern const struct ynl_family ynl_netdev_family; - -/* Enums */ -const char *netdev_op_str(int op); -const char *netdev_xdp_act_str(enum netdev_xdp_act value); -const char *netdev_xdp_rx_metadata_str(enum netdev_xdp_rx_metadata value); - -/* Common nested types */ -/* ============== NETDEV_CMD_DEV_GET ============== */ -/* NETDEV_CMD_DEV_GET - do */ -struct netdev_dev_get_req { - struct { - __u32 ifindex:1; - } _present; - - __u32 ifindex; -}; - -static inline struct netdev_dev_get_req *netdev_dev_get_req_alloc(void) -{ - return calloc(1, sizeof(struct netdev_dev_get_req)); -} -void netdev_dev_get_req_free(struct netdev_dev_get_req *req); - -static inline void -netdev_dev_get_req_set_ifindex(struct netdev_dev_get_req *req, __u32 ifindex) -{ - req->_present.ifindex = 1; - req->ifindex = ifindex; -} - -struct netdev_dev_get_rsp { - struct { - __u32 ifindex:1; - __u32 xdp_features:1; - __u32 xdp_zc_max_segs:1; - __u32 xdp_rx_metadata_features:1; - } _present; - - __u32 ifindex; - __u64 xdp_features; - __u32 xdp_zc_max_segs; - __u64 xdp_rx_metadata_features; -}; - -void netdev_dev_get_rsp_free(struct netdev_dev_get_rsp *rsp); - -/* - * Get / dump information about a netdev. - */ -struct netdev_dev_get_rsp * -netdev_dev_get(struct ynl_sock *ys, struct netdev_dev_get_req *req); - -/* NETDEV_CMD_DEV_GET - dump */ -struct netdev_dev_get_list { - struct netdev_dev_get_list *next; - struct netdev_dev_get_rsp obj __attribute__((aligned(8))); -}; - -void netdev_dev_get_list_free(struct netdev_dev_get_list *rsp); - -struct netdev_dev_get_list *netdev_dev_get_dump(struct ynl_sock *ys); - -/* NETDEV_CMD_DEV_GET - notify */ -struct netdev_dev_get_ntf { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct netdev_dev_get_ntf *ntf); - struct netdev_dev_get_rsp obj __attribute__((aligned(8))); -}; - -void netdev_dev_get_ntf_free(struct netdev_dev_get_ntf *rsp); - -#endif /* _LINUX_NETDEV_GEN_H */ diff --git a/tools/net/ynl/generated/nfsd-user.c b/tools/net/ynl/generated/nfsd-user.c deleted file mode 100644 index 360b6448c6..0000000000 --- a/tools/net/ynl/generated/nfsd-user.c +++ /dev/null @@ -1,203 +0,0 @@ -// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/nfsd.yaml */ -/* YNL-GEN user source */ - -#include -#include -#include "nfsd-user.h" -#include "ynl.h" -#include - -#include -#include - -/* Enums */ -static const char * const nfsd_op_strmap[] = { - [NFSD_CMD_RPC_STATUS_GET] = "rpc-status-get", -}; - -const char *nfsd_op_str(int op) -{ - if (op < 0 || op >= (int)MNL_ARRAY_SIZE(nfsd_op_strmap)) - return NULL; - return nfsd_op_strmap[op]; -} - -/* Policies */ -struct ynl_policy_attr nfsd_rpc_status_policy[NFSD_A_RPC_STATUS_MAX + 1] = { - [NFSD_A_RPC_STATUS_XID] = { .name = "xid", .type = YNL_PT_U32, }, - [NFSD_A_RPC_STATUS_FLAGS] = { .name = "flags", .type = YNL_PT_U32, }, - [NFSD_A_RPC_STATUS_PROG] = { .name = "prog", .type = YNL_PT_U32, }, - [NFSD_A_RPC_STATUS_VERSION] = { .name = "version", .type = YNL_PT_U8, }, - [NFSD_A_RPC_STATUS_PROC] = { .name = "proc", .type = YNL_PT_U32, }, - [NFSD_A_RPC_STATUS_SERVICE_TIME] = { .name = "service_time", .type = YNL_PT_U64, }, - [NFSD_A_RPC_STATUS_PAD] = { .name = "pad", .type = YNL_PT_IGNORE, }, - [NFSD_A_RPC_STATUS_SADDR4] = { .name = "saddr4", .type = YNL_PT_U32, }, - [NFSD_A_RPC_STATUS_DADDR4] = { .name = "daddr4", .type = YNL_PT_U32, }, - [NFSD_A_RPC_STATUS_SADDR6] = { .name = "saddr6", .type = YNL_PT_BINARY,}, - [NFSD_A_RPC_STATUS_DADDR6] = { .name = "daddr6", .type = YNL_PT_BINARY,}, - [NFSD_A_RPC_STATUS_SPORT] = { .name = "sport", .type = YNL_PT_U16, }, - [NFSD_A_RPC_STATUS_DPORT] = { .name = "dport", .type = YNL_PT_U16, }, - [NFSD_A_RPC_STATUS_COMPOUND_OPS] = { .name = "compound-ops", .type = YNL_PT_U32, }, -}; - -struct ynl_policy_nest nfsd_rpc_status_nest = { - .max_attr = NFSD_A_RPC_STATUS_MAX, - .table = nfsd_rpc_status_policy, -}; - -/* Common nested types */ -/* ============== NFSD_CMD_RPC_STATUS_GET ============== */ -/* NFSD_CMD_RPC_STATUS_GET - dump */ -int nfsd_rpc_status_get_rsp_dump_parse(const struct nlmsghdr *nlh, void *data) -{ - struct nfsd_rpc_status_get_rsp_dump *dst; - struct ynl_parse_arg *yarg = data; - unsigned int n_compound_ops = 0; - const struct nlattr *attr; - int i; - - dst = yarg->data; - - if (dst->compound_ops) - return ynl_error_parse(yarg, "attribute already present (rpc-status.compound-ops)"); - - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - unsigned int type = mnl_attr_get_type(attr); - - if (type == NFSD_A_RPC_STATUS_XID) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.xid = 1; - dst->xid = mnl_attr_get_u32(attr); - } else if (type == NFSD_A_RPC_STATUS_FLAGS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.flags = 1; - dst->flags = mnl_attr_get_u32(attr); - } else if (type == NFSD_A_RPC_STATUS_PROG) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.prog = 1; - dst->prog = mnl_attr_get_u32(attr); - } else if (type == NFSD_A_RPC_STATUS_VERSION) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.version = 1; - dst->version = mnl_attr_get_u8(attr); - } else if (type == NFSD_A_RPC_STATUS_PROC) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.proc = 1; - dst->proc = mnl_attr_get_u32(attr); - } else if (type == NFSD_A_RPC_STATUS_SERVICE_TIME) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.service_time = 1; - dst->service_time = mnl_attr_get_u64(attr); - } else if (type == NFSD_A_RPC_STATUS_SADDR4) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.saddr4 = 1; - dst->saddr4 = mnl_attr_get_u32(attr); - } else if (type == NFSD_A_RPC_STATUS_DADDR4) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.daddr4 = 1; - dst->daddr4 = mnl_attr_get_u32(attr); - } else if (type == NFSD_A_RPC_STATUS_SADDR6) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.saddr6_len = len; - dst->saddr6 = malloc(len); - memcpy(dst->saddr6, mnl_attr_get_payload(attr), len); - } else if (type == NFSD_A_RPC_STATUS_DADDR6) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = mnl_attr_get_payload_len(attr); - dst->_present.daddr6_len = len; - dst->daddr6 = malloc(len); - memcpy(dst->daddr6, mnl_attr_get_payload(attr), len); - } else if (type == NFSD_A_RPC_STATUS_SPORT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sport = 1; - dst->sport = mnl_attr_get_u16(attr); - } else if (type == NFSD_A_RPC_STATUS_DPORT) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dport = 1; - dst->dport = mnl_attr_get_u16(attr); - } else if (type == NFSD_A_RPC_STATUS_COMPOUND_OPS) { - n_compound_ops++; - } - } - - if (n_compound_ops) { - dst->compound_ops = calloc(n_compound_ops, sizeof(*dst->compound_ops)); - dst->n_compound_ops = n_compound_ops; - i = 0; - mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - if (mnl_attr_get_type(attr) == NFSD_A_RPC_STATUS_COMPOUND_OPS) { - dst->compound_ops[i] = mnl_attr_get_u32(attr); - i++; - } - } - } - - return MNL_CB_OK; -} - -void -nfsd_rpc_status_get_rsp_list_free(struct nfsd_rpc_status_get_rsp_list *rsp) -{ - struct nfsd_rpc_status_get_rsp_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.saddr6); - free(rsp->obj.daddr6); - free(rsp->obj.compound_ops); - free(rsp); - } -} - -struct nfsd_rpc_status_get_rsp_list * -nfsd_rpc_status_get_dump(struct ynl_sock *ys) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct nfsd_rpc_status_get_rsp_list); - yds.cb = nfsd_rpc_status_get_rsp_dump_parse; - yds.rsp_cmd = NFSD_CMD_RPC_STATUS_GET; - yds.rsp_policy = &nfsd_rpc_status_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, NFSD_CMD_RPC_STATUS_GET, 1); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - nfsd_rpc_status_get_rsp_list_free(yds.first); - return NULL; -} - -const struct ynl_family ynl_nfsd_family = { - .name = "nfsd", -}; diff --git a/tools/net/ynl/generated/nfsd-user.h b/tools/net/ynl/generated/nfsd-user.h deleted file mode 100644 index 989c6e209c..0000000000 --- a/tools/net/ynl/generated/nfsd-user.h +++ /dev/null @@ -1,67 +0,0 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/nfsd.yaml */ -/* YNL-GEN user header */ - -#ifndef _LINUX_NFSD_GEN_H -#define _LINUX_NFSD_GEN_H - -#include -#include -#include -#include - -struct ynl_sock; - -extern const struct ynl_family ynl_nfsd_family; - -/* Enums */ -const char *nfsd_op_str(int op); - -/* Common nested types */ -/* ============== NFSD_CMD_RPC_STATUS_GET ============== */ -/* NFSD_CMD_RPC_STATUS_GET - dump */ -struct nfsd_rpc_status_get_rsp_dump { - struct { - __u32 xid:1; - __u32 flags:1; - __u32 prog:1; - __u32 version:1; - __u32 proc:1; - __u32 service_time:1; - __u32 saddr4:1; - __u32 daddr4:1; - __u32 saddr6_len; - __u32 daddr6_len; - __u32 sport:1; - __u32 dport:1; - } _present; - - __u32 xid /* big-endian */; - __u32 flags; - __u32 prog; - __u8 version; - __u32 proc; - __s64 service_time; - __u32 saddr4 /* big-endian */; - __u32 daddr4 /* big-endian */; - void *saddr6; - void *daddr6; - __u16 sport /* big-endian */; - __u16 dport /* big-endian */; - unsigned int n_compound_ops; - __u32 *compound_ops; -}; - -struct nfsd_rpc_status_get_rsp_list { - struct nfsd_rpc_status_get_rsp_list *next; - struct nfsd_rpc_status_get_rsp_dump obj __attribute__((aligned(8))); -}; - -void -nfsd_rpc_status_get_rsp_list_free(struct nfsd_rpc_status_get_rsp_list *rsp); - -struct nfsd_rpc_status_get_rsp_list * -nfsd_rpc_status_get_dump(struct ynl_sock *ys); - -#endif /* _LINUX_NFSD_GEN_H */ diff --git a/tools/net/ynl/lib/nlspec.py b/tools/net/ynl/lib/nlspec.py index 92889298b1..44f13e383e 100644 --- a/tools/net/ynl/lib/nlspec.py +++ b/tools/net/ynl/lib/nlspec.py @@ -158,6 +158,9 @@ class SpecAttr(SpecElement): len integer, optional byte length of binary types display_hint string, hint to help choose format specifier when displaying the value + sub_message string, name of sub message type + selector string, name of attribute used to select + sub-message type is_auto_scalar bool, attr is a variable-size scalar """ @@ -173,6 +176,8 @@ class SpecAttr(SpecElement): self.byte_order = yaml.get('byte-order') self.len = yaml.get('len') self.display_hint = yaml.get('display-hint') + self.sub_message = yaml.get('sub-message') + self.selector = yaml.get('selector') self.is_auto_scalar = self.type == "sint" or self.type == "uint" @@ -278,6 +283,47 @@ class SpecStruct(SpecElement): return self.members.items() +class SpecSubMessage(SpecElement): + """ Netlink sub-message definition + + Represents a set of sub-message formats for polymorphic nlattrs + that contain type-specific sub messages. + + Attributes: + name string, name of sub-message definition + formats dict of sub-message formats indexed by match value + """ + def __init__(self, family, yaml): + super().__init__(family, yaml) + + self.formats = collections.OrderedDict() + for elem in self.yaml['formats']: + format = self.new_format(family, elem) + self.formats[format.value] = format + + def new_format(self, family, format): + return SpecSubMessageFormat(family, format) + + +class SpecSubMessageFormat(SpecElement): + """ Netlink sub-message definition + + Represents a set of sub-message formats for polymorphic nlattrs + that contain type-specific sub messages. + + Attributes: + value attribute value to match against type selector + fixed_header string, name of fixed header, or None + attr_set string, name of attribute set, or None + """ + def __init__(self, family, yaml): + super().__init__(family, yaml) + + self.value = yaml.get('value') + self.fixed_header = yaml.get('fixed-header') + self.attr_set = yaml.get('attribute-set') + + class SpecOperation(SpecElement): """Netlink Operation @@ -365,6 +411,7 @@ class SpecFamily(SpecElement): attr_sets dict of attribute sets msgs dict of all messages (index by name) + sub_msgs dict of all sub messages (index by name) ops dict of all valid requests / responses ntfs dict of all async events consts dict of all constants/enums @@ -405,6 +452,7 @@ class SpecFamily(SpecElement): jsonschema.validate(self.yaml, schema) self.attr_sets = collections.OrderedDict() + self.sub_msgs = collections.OrderedDict() self.msgs = collections.OrderedDict() self.req_by_value = collections.OrderedDict() self.rsp_by_value = collections.OrderedDict() @@ -441,6 +489,9 @@ class SpecFamily(SpecElement): def new_struct(self, elem): return SpecStruct(self, elem) + def new_sub_message(self, elem): + return SpecSubMessage(self, elem); + def new_operation(self, elem, req_val, rsp_val): return SpecOperation(self, elem, req_val, rsp_val) @@ -529,6 +580,10 @@ class SpecFamily(SpecElement): attr_set = self.new_attr_set(elem) self.attr_sets[elem['name']] = attr_set + for elem in self.yaml.get('sub-messages', []): + sub_message = self.new_sub_message(elem) + self.sub_msgs[sub_message.name] = sub_message + if self.msg_id_model == 'unified': self._dictify_ops_unified() elif self.msg_id_model == 'directional': diff --git a/tools/net/ynl/lib/ynl-priv.h b/tools/net/ynl/lib/ynl-priv.h new file mode 100644 index 0000000000..7491da8e75 --- /dev/null +++ b/tools/net/ynl/lib/ynl-priv.h @@ -0,0 +1,144 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +#ifndef __YNL_C_PRIV_H +#define __YNL_C_PRIV_H 1 + +#include +#include +#include + +/* + * YNL internals / low level stuff + */ + +/* Generic mnl helper code */ + +enum ynl_policy_type { + YNL_PT_REJECT = 1, + YNL_PT_IGNORE, + YNL_PT_NEST, + YNL_PT_FLAG, + YNL_PT_BINARY, + YNL_PT_U8, + YNL_PT_U16, + YNL_PT_U32, + YNL_PT_U64, + YNL_PT_UINT, + YNL_PT_NUL_STR, + YNL_PT_BITFIELD32, +}; + +struct ynl_policy_attr { + enum ynl_policy_type type; + unsigned int len; + const char *name; + struct ynl_policy_nest *nest; +}; + +struct ynl_policy_nest { + unsigned int max_attr; + struct ynl_policy_attr *table; +}; + +struct ynl_parse_arg { + struct ynl_sock *ys; + struct ynl_policy_nest *rsp_policy; + void *data; +}; + +struct ynl_dump_list_type { + struct ynl_dump_list_type *next; + unsigned char data[] __attribute__((aligned(8))); +}; +extern struct ynl_dump_list_type *YNL_LIST_END; + +static inline bool ynl_dump_obj_is_last(void *obj) +{ + unsigned long uptr = (unsigned long)obj; + + uptr -= offsetof(struct ynl_dump_list_type, data); + return uptr == (unsigned long)YNL_LIST_END; +} + +static inline void *ynl_dump_obj_next(void *obj) +{ + unsigned long uptr = (unsigned long)obj; + struct ynl_dump_list_type *list; + + uptr -= offsetof(struct ynl_dump_list_type, data); + list = (void *)uptr; + uptr = (unsigned long)list->next; + uptr += offsetof(struct ynl_dump_list_type, data); + + return (void *)uptr; +} + +struct ynl_ntf_base_type { + __u16 family; + __u8 cmd; + struct ynl_ntf_base_type *next; + void (*free)(struct ynl_ntf_base_type *ntf); + unsigned char data[] __attribute__((aligned(8))); +}; + +extern mnl_cb_t ynl_cb_array[NLMSG_MIN_TYPE]; + +struct nlmsghdr * +ynl_gemsg_start_req(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version); +struct nlmsghdr * +ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version); + +int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr); + +int ynl_recv_ack(struct ynl_sock *ys, int ret); +int ynl_cb_null(const struct nlmsghdr *nlh, void *data); + +/* YNL specific helpers used by the auto-generated code */ + +struct ynl_req_state { + struct ynl_parse_arg yarg; + mnl_cb_t cb; + __u32 rsp_cmd; +}; + +struct ynl_dump_state { + struct ynl_sock *ys; + struct ynl_policy_nest *rsp_policy; + void *first; + struct ynl_dump_list_type *last; + size_t alloc_sz; + mnl_cb_t cb; + __u32 rsp_cmd; +}; + +struct ynl_ntf_info { + struct ynl_policy_nest *policy; + mnl_cb_t cb; + size_t alloc_sz; + void (*free)(struct ynl_ntf_base_type *ntf); +}; + +int ynl_exec(struct ynl_sock *ys, struct nlmsghdr *req_nlh, + struct ynl_req_state *yrs); +int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh, + struct ynl_dump_state *yds); + +void ynl_error_unknown_notification(struct ynl_sock *ys, __u8 cmd); +int ynl_error_parse(struct ynl_parse_arg *yarg, const char *msg); + +#ifndef MNL_HAS_AUTO_SCALARS +static inline uint64_t mnl_attr_get_uint(const struct nlattr *attr) +{ + if (mnl_attr_get_payload_len(attr) == 4) + return mnl_attr_get_u32(attr); + return mnl_attr_get_u64(attr); +} + +static inline void +mnl_attr_put_uint(struct nlmsghdr *nlh, uint16_t type, uint64_t data) +{ + if ((uint32_t)data == (uint64_t)data) + return mnl_attr_put_u32(nlh, type, data); + return mnl_attr_put_u64(nlh, type, data); +} +#endif +#endif diff --git a/tools/net/ynl/lib/ynl.c b/tools/net/ynl/lib/ynl.c index 2aa19004fa..45e49671ae 100644 --- a/tools/net/ynl/lib/ynl.c +++ b/tools/net/ynl/lib/ynl.c @@ -145,8 +145,10 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh, const struct nlattr *attr; const char *str = NULL; - if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS)) + if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS)) { + yerr_msg(ys, "%s", strerror(ys->err.code)); return MNL_CB_OK; + } mnl_attr_for_each(attr, nlh, hlen) { unsigned int len, type; @@ -189,12 +191,12 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh, str ? " (" : ""); start = mnl_nlmsg_get_payload_offset(ys->nlh, - sizeof(struct genlmsghdr)); + ys->family->hdr_len); end = mnl_nlmsg_get_payload_tail(ys->nlh); off = ys->err.attr_offs; off -= sizeof(struct nlmsghdr); - off -= sizeof(struct genlmsghdr); + off -= ys->family->hdr_len; n += ynl_err_walk(ys, start, end, off, ys->req_policy, &bad_attr[n], sizeof(bad_attr) - n, NULL); @@ -215,14 +217,14 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh, bad_attr[0] ? ", " : (str ? " (" : "")); start = mnl_nlmsg_get_payload_offset(ys->nlh, - sizeof(struct genlmsghdr)); + ys->family->hdr_len); end = mnl_nlmsg_get_payload_tail(ys->nlh); nest_pol = ys->req_policy; if (tb[NLMSGERR_ATTR_MISS_NEST]) { off = mnl_attr_get_u32(tb[NLMSGERR_ATTR_MISS_NEST]); off -= sizeof(struct nlmsghdr); - off -= sizeof(struct genlmsghdr); + off -= ys->family->hdr_len; n += ynl_err_walk(ys, start, end, off, ys->req_policy, &miss_attr[n], sizeof(miss_attr) - n, @@ -249,6 +251,8 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh, yerr_msg(ys, "Kernel %s: %s%s", ys->err.code ? "error" : "warning", bad_attr, miss_attr); + else + yerr_msg(ys, "%s", strerror(ys->err.code)); return MNL_CB_OK; } diff --git a/tools/net/ynl/lib/ynl.h b/tools/net/ynl/lib/ynl.h index e974378e3b..ce77a6d76c 100644 --- a/tools/net/ynl/lib/ynl.h +++ b/tools/net/ynl/lib/ynl.h @@ -3,20 +3,10 @@ #define __YNL_C_H 1 #include -#include #include #include -struct mnl_socket; -struct nlmsghdr; - -/* - * User facing code - */ - -struct ynl_ntf_base_type; -struct ynl_ntf_info; -struct ynl_sock; +#include "ynl-priv.h" enum ynl_error_code { YNL_ERROR_NONE = 0, @@ -54,6 +44,7 @@ struct ynl_error { struct ynl_family { /* private: */ const char *name; + size_t hdr_len; const struct ynl_ntf_info *ntf_info; unsigned int ntf_info_size; }; @@ -116,140 +107,4 @@ static inline bool ynl_has_ntf(struct ynl_sock *ys) struct ynl_ntf_base_type *ynl_ntf_dequeue(struct ynl_sock *ys); void ynl_ntf_free(struct ynl_ntf_base_type *ntf); - -/* - * YNL internals / low level stuff - */ - -/* Generic mnl helper code */ - -enum ynl_policy_type { - YNL_PT_REJECT = 1, - YNL_PT_IGNORE, - YNL_PT_NEST, - YNL_PT_FLAG, - YNL_PT_BINARY, - YNL_PT_U8, - YNL_PT_U16, - YNL_PT_U32, - YNL_PT_U64, - YNL_PT_UINT, - YNL_PT_NUL_STR, - YNL_PT_BITFIELD32, -}; - -struct ynl_policy_attr { - enum ynl_policy_type type; - unsigned int len; - const char *name; - struct ynl_policy_nest *nest; -}; - -struct ynl_policy_nest { - unsigned int max_attr; - struct ynl_policy_attr *table; -}; - -struct ynl_parse_arg { - struct ynl_sock *ys; - struct ynl_policy_nest *rsp_policy; - void *data; -}; - -struct ynl_dump_list_type { - struct ynl_dump_list_type *next; - unsigned char data[] __attribute__((aligned(8))); -}; -extern struct ynl_dump_list_type *YNL_LIST_END; - -static inline bool ynl_dump_obj_is_last(void *obj) -{ - unsigned long uptr = (unsigned long)obj; - - uptr -= offsetof(struct ynl_dump_list_type, data); - return uptr == (unsigned long)YNL_LIST_END; -} - -static inline void *ynl_dump_obj_next(void *obj) -{ - unsigned long uptr = (unsigned long)obj; - struct ynl_dump_list_type *list; - - uptr -= offsetof(struct ynl_dump_list_type, data); - list = (void *)uptr; - uptr = (unsigned long)list->next; - uptr += offsetof(struct ynl_dump_list_type, data); - - return (void *)uptr; -} - -struct ynl_ntf_base_type { - __u16 family; - __u8 cmd; - struct ynl_ntf_base_type *next; - void (*free)(struct ynl_ntf_base_type *ntf); - unsigned char data[] __attribute__((aligned(8))); -}; - -extern mnl_cb_t ynl_cb_array[NLMSG_MIN_TYPE]; - -struct nlmsghdr * -ynl_gemsg_start_req(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version); -struct nlmsghdr * -ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version); - -int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr); - -int ynl_recv_ack(struct ynl_sock *ys, int ret); -int ynl_cb_null(const struct nlmsghdr *nlh, void *data); - -/* YNL specific helpers used by the auto-generated code */ - -struct ynl_req_state { - struct ynl_parse_arg yarg; - mnl_cb_t cb; - __u32 rsp_cmd; -}; - -struct ynl_dump_state { - struct ynl_sock *ys; - struct ynl_policy_nest *rsp_policy; - void *first; - struct ynl_dump_list_type *last; - size_t alloc_sz; - mnl_cb_t cb; - __u32 rsp_cmd; -}; - -struct ynl_ntf_info { - struct ynl_policy_nest *policy; - mnl_cb_t cb; - size_t alloc_sz; - void (*free)(struct ynl_ntf_base_type *ntf); -}; - -int ynl_exec(struct ynl_sock *ys, struct nlmsghdr *req_nlh, - struct ynl_req_state *yrs); -int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh, - struct ynl_dump_state *yds); - -void ynl_error_unknown_notification(struct ynl_sock *ys, __u8 cmd); -int ynl_error_parse(struct ynl_parse_arg *yarg, const char *msg); - -#ifndef MNL_HAS_AUTO_SCALARS -static inline uint64_t mnl_attr_get_uint(const struct nlattr *attr) -{ - if (mnl_attr_get_len(attr) == 4) - return mnl_attr_get_u32(attr); - return mnl_attr_get_u64(attr); -} - -static inline void -mnl_attr_put_uint(struct nlmsghdr *nlh, uint16_t type, uint64_t data) -{ - if ((uint32_t)data == (uint64_t)data) - return mnl_attr_put_u32(nlh, type, data); - return mnl_attr_put_u64(nlh, type, data); -} -#endif #endif diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py index 92995bca14..571c2e2189 100644 --- a/tools/net/ynl/lib/ynl.py +++ b/tools/net/ynl/lib/ynl.py @@ -98,12 +98,12 @@ class NlAttr: } def __init__(self, raw, offset): - self._len, self._type = struct.unpack("HH", raw[offset:offset + 4]) + self._len, self._type = struct.unpack("HH", raw[offset : offset + 4]) self.type = self._type & ~Netlink.NLA_TYPE_MASK self.is_nest = self._type & Netlink.NLA_F_NESTED self.payload_len = self._len self.full_len = (self.payload_len + 3) & ~3 - self.raw = raw[offset + 4:offset + self.payload_len] + self.raw = raw[offset + 4 : offset + self.payload_len] @classmethod def get_format(cls, attr_type, byte_order=None): @@ -154,7 +154,7 @@ class NlAttr: for m in members: # TODO: handle non-scalar members if m.type == 'binary': - decoded = self.raw[offset:offset+m['len']] + decoded = self.raw[offset : offset + m['len']] offset += m['len'] elif m.type in NlAttr.type_formats: format = self.get_format(m.type, m.byte_order) @@ -170,10 +170,9 @@ class NlAttr: class NlAttrs: - def __init__(self, msg): + def __init__(self, msg, offset=0): self.attrs = [] - offset = 0 while offset < len(msg): attr = NlAttr(msg, offset) offset += attr.full_len @@ -193,12 +192,12 @@ class NlAttrs: class NlMsg: def __init__(self, msg, offset, attr_space=None): - self.hdr = msg[offset:offset + 16] + self.hdr = msg[offset : offset + 16] self.nl_len, self.nl_type, self.nl_flags, self.nl_seq, self.nl_portid = \ struct.unpack("IHHII", self.hdr) - self.raw = msg[offset + 16:offset + self.nl_len] + self.raw = msg[offset + 16 : offset + self.nl_len] self.error = 0 self.done = 0 @@ -209,6 +208,7 @@ class NlMsg: self.done = 1 extack_off = 20 elif self.nl_type == Netlink.NLMSG_DONE: + self.error = struct.unpack("i", self.raw[0:4])[0] self.done = 1 extack_off = 4 @@ -371,8 +371,8 @@ class NetlinkProtocol: fixed_header_size = 0 if ynl: op = ynl.rsp_by_value[msg.cmd()] - fixed_header_size = ynl._fixed_header_size(op) - msg.raw_attrs = NlAttrs(msg.raw[fixed_header_size:]) + fixed_header_size = ynl._fixed_header_size(op.fixed_header) + msg.raw_attrs = NlAttrs(msg.raw, fixed_header_size) return msg def get_mcast_id(self, mcast_name, mcast_groups): @@ -549,6 +549,37 @@ class YnlFamily(SpecFamily): else: rsp[name] = [decoded] + def _resolve_selector(self, attr_spec, vals): + sub_msg = attr_spec.sub_message + if sub_msg not in self.sub_msgs: + raise Exception(f"No sub-message spec named {sub_msg} for {attr_spec.name}") + sub_msg_spec = self.sub_msgs[sub_msg] + + selector = attr_spec.selector + if selector not in vals: + raise Exception(f"There is no value for {selector} to resolve '{attr_spec.name}'") + value = vals[selector] + if value not in sub_msg_spec.formats: + raise Exception(f"No message format for '{value}' in sub-message spec '{sub_msg}'") + + spec = sub_msg_spec.formats[value] + return spec + + def _decode_sub_msg(self, attr, attr_spec, rsp): + msg_format = self._resolve_selector(attr_spec, rsp) + decoded = {} + offset = 0 + if msg_format.fixed_header: + decoded.update(self._decode_fixed_header(attr, msg_format.fixed_header)); + offset = self._fixed_header_size(msg_format.fixed_header) + if msg_format.attr_set: + if msg_format.attr_set in self.attr_sets: + subdict = self._decode(NlAttrs(attr.raw, offset), msg_format.attr_set) + decoded.update(subdict) + else: + raise Exception(f"Unknown attribute-set '{attr_space}' when decoding '{attr_spec.name}'") + return decoded + def _decode(self, attrs, space): if space: attr_space = self.attr_sets[space] @@ -586,6 +617,8 @@ class YnlFamily(SpecFamily): value = self._decode_enum(value, attr_spec) selector = self._decode_enum(selector, attr_spec) decoded = {"value": value, "selector": selector} + elif attr_spec["type"] == 'sub-message': + decoded = self._decode_sub_msg(attr, attr_spec, rsp) else: if not self.process_unknown: raise Exception(f'Unknown {attr_spec["type"]} with name {attr_spec["name"]}') @@ -626,20 +659,23 @@ class YnlFamily(SpecFamily): return msg = self.nlproto.decode(self, NlMsg(request, 0, op.attr_set)) - offset = 20 + self._fixed_header_size(op) + offset = 20 + self._fixed_header_size(op.fixed_header) path = self._decode_extack_path(msg.raw_attrs, op.attr_set, offset, extack['bad-attr-offs']) if path: del extack['bad-attr-offs'] extack['bad-attr'] = path - def _fixed_header_size(self, op): - if op.fixed_header: - fixed_header_members = self.consts[op.fixed_header].members + def _fixed_header_size(self, name): + if name: + fixed_header_members = self.consts[name].members size = 0 for m in fixed_header_members: - format = NlAttr.get_format(m.type, m.byte_order) - size += format.size + if m.type in ['pad', 'binary']: + size += m.len + else: + format = NlAttr.get_format(m.type, m.byte_order) + size += format.size return size else: return 0 @@ -649,12 +685,20 @@ class YnlFamily(SpecFamily): fixed_header_attrs = dict() offset = 0 for m in fixed_header_members: - format = NlAttr.get_format(m.type, m.byte_order) - [ value ] = format.unpack_from(msg.raw, offset) - offset += format.size - if m.enum: - value = self._decode_enum(value, m) - fixed_header_attrs[m.name] = value + value = None + if m.type == 'pad': + offset += m.len + elif m.type == 'binary': + value = msg.raw[offset : offset + m.len] + offset += m.len + else: + format = NlAttr.get_format(m.type, m.byte_order) + [ value ] = format.unpack_from(msg.raw, offset) + offset += format.size + if value is not None: + if m.enum: + value = self._decode_enum(value, m) + fixed_header_attrs[m.name] = value return fixed_header_attrs def handle_ntf(self, decoded): @@ -705,7 +749,7 @@ class YnlFamily(SpecFamily): return op['do']['request']['attributes'].copy() - def _op(self, method, vals, flags, dump=False): + def _op(self, method, vals, flags=None, dump=False): op = self.ops[method] nl_flags = Netlink.NLM_F_REQUEST | Netlink.NLM_F_ACK @@ -721,8 +765,13 @@ class YnlFamily(SpecFamily): fixed_header_members = self.consts[op.fixed_header].members for m in fixed_header_members: value = vals.pop(m.name) if m.name in vals else 0 - format = NlAttr.get_format(m.type, m.byte_order) - msg += format.pack(value) + if m.type == 'pad': + msg += bytearray(m.len) + elif m.type == 'binary': + msg += bytes.fromhex(value) + else: + format = NlAttr.get_format(m.type, m.byte_order) + msg += format.pack(value) for name, value in vals.items(): msg += self._add_attr(op.attr_set.name, name, value) msg = _genl_msg_finalize(msg) @@ -769,7 +818,7 @@ class YnlFamily(SpecFamily): return rsp[0] return rsp - def do(self, method, vals, flags): + def do(self, method, vals, flags=None): return self._op(method, vals, flags) def dump(self, method, vals): diff --git a/tools/net/ynl/samples/.gitignore b/tools/net/ynl/samples/.gitignore index 2aae60c482..49637b26c4 100644 --- a/tools/net/ynl/samples/.gitignore +++ b/tools/net/ynl/samples/.gitignore @@ -1,3 +1,4 @@ ethtool devlink netdev +page-pool \ No newline at end of file diff --git a/tools/net/ynl/samples/Makefile b/tools/net/ynl/samples/Makefile index 3dbb106e87..28bdb1557a 100644 --- a/tools/net/ynl/samples/Makefile +++ b/tools/net/ynl/samples/Makefile @@ -18,7 +18,9 @@ include $(wildcard *.d) all: $(BINS) -$(BINS): ../lib/ynl.a ../generated/protos.a +CFLAGS_page-pool=$(CFLAGS_netdev) + +$(BINS): ../lib/ynl.a ../generated/protos.a $(SRCS) @echo -e '\tCC sample $@' @$(COMPILE.c) $(CFLAGS_$@) $@.c -o $@.o @$(LINK.c) $@.o -o $@ $(LDLIBS) diff --git a/tools/net/ynl/samples/netdev.c b/tools/net/ynl/samples/netdev.c index b828225daa..591b90e218 100644 --- a/tools/net/ynl/samples/netdev.c +++ b/tools/net/ynl/samples/netdev.c @@ -33,17 +33,23 @@ static void netdev_print_device(struct netdev_dev_get_rsp *d, unsigned int op) return; printf("xdp-features (%llx):", d->xdp_features); - for (int i = 0; d->xdp_features > 1U << i; i++) { + for (int i = 0; d->xdp_features >= 1U << i; i++) { if (d->xdp_features & (1U << i)) printf(" %s", netdev_xdp_act_str(1 << i)); } printf(" xdp-rx-metadata-features (%llx):", d->xdp_rx_metadata_features); - for (int i = 0; d->xdp_rx_metadata_features > 1U << i; i++) { + for (int i = 0; d->xdp_rx_metadata_features >= 1U << i; i++) { if (d->xdp_rx_metadata_features & (1U << i)) printf(" %s", netdev_xdp_rx_metadata_str(1 << i)); } + printf(" xsk-features (%llx):", d->xsk_features); + for (int i = 0; d->xsk_features >= 1U << i; i++) { + if (d->xsk_features & (1U << i)) + printf(" %s", netdev_xsk_flags_str(1 << i)); + } + printf(" xdp-zc-max-segs=%u", d->xdp_zc_max_segs); name = netdev_op_str(op); diff --git a/tools/net/ynl/samples/page-pool.c b/tools/net/ynl/samples/page-pool.c new file mode 100644 index 0000000000..098b5190d0 --- /dev/null +++ b/tools/net/ynl/samples/page-pool.c @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: GPL-2.0 +#define _GNU_SOURCE + +#include +#include + +#include + +#include + +#include "netdev-user.h" + +struct stat { + unsigned int ifc; + + struct { + unsigned int cnt; + size_t refs, bytes; + } live[2]; + + size_t alloc_slow, alloc_fast, recycle_ring, recycle_cache; +}; + +struct stats_array { + unsigned int i, max; + struct stat *s; +}; + +static struct stat *find_ifc(struct stats_array *a, unsigned int ifindex) +{ + unsigned int i; + + for (i = 0; i < a->i; i++) { + if (a->s[i].ifc == ifindex) + return &a->s[i]; + } + + a->i++; + if (a->i == a->max) { + a->max *= 2; + a->s = reallocarray(a->s, a->max, sizeof(*a->s)); + } + a->s[i].ifc = ifindex; + return &a->s[i]; +} + +static void count(struct stat *s, unsigned int l, + struct netdev_page_pool_get_rsp *pp) +{ + s->live[l].cnt++; + if (pp->_present.inflight) + s->live[l].refs += pp->inflight; + if (pp->_present.inflight_mem) + s->live[l].bytes += pp->inflight_mem; +} + +int main(int argc, char **argv) +{ + struct netdev_page_pool_stats_get_list *pp_stats; + struct netdev_page_pool_get_list *pools; + struct stats_array a = {}; + struct ynl_error yerr; + struct ynl_sock *ys; + + ys = ynl_sock_create(&ynl_netdev_family, &yerr); + if (!ys) { + fprintf(stderr, "YNL: %s\n", yerr.msg); + return 1; + } + + a.max = 128; + a.s = calloc(a.max, sizeof(*a.s)); + if (!a.s) + goto err_close; + + pools = netdev_page_pool_get_dump(ys); + if (!pools) + goto err_free; + + ynl_dump_foreach(pools, pp) { + struct stat *s = find_ifc(&a, pp->ifindex); + + count(s, 1, pp); + if (pp->_present.detach_time) + count(s, 0, pp); + } + netdev_page_pool_get_list_free(pools); + + pp_stats = netdev_page_pool_stats_get_dump(ys); + if (!pp_stats) + goto err_free; + + ynl_dump_foreach(pp_stats, pp) { + struct stat *s = find_ifc(&a, pp->info.ifindex); + + if (pp->_present.alloc_fast) + s->alloc_fast += pp->alloc_fast; + if (pp->_present.alloc_slow) + s->alloc_slow += pp->alloc_slow; + if (pp->_present.recycle_ring) + s->recycle_ring += pp->recycle_ring; + if (pp->_present.recycle_cached) + s->recycle_cache += pp->recycle_cached; + } + netdev_page_pool_stats_get_list_free(pp_stats); + + for (unsigned int i = 0; i < a.i; i++) { + char ifname[IF_NAMESIZE]; + struct stat *s = &a.s[i]; + const char *name; + double recycle; + + if (!s->ifc) { + name = "\t"; + } else { + name = if_indextoname(s->ifc, ifname); + if (name) + printf("%8s", name); + printf("[%d]\t", s->ifc); + } + + printf("page pools: %u (zombies: %u)\n", + s->live[1].cnt, s->live[0].cnt); + printf("\t\trefs: %zu bytes: %zu (refs: %zu bytes: %zu)\n", + s->live[1].refs, s->live[1].bytes, + s->live[0].refs, s->live[0].bytes); + + /* We don't know how many pages are sitting in cache and ring + * so we will under-count the recycling rate a bit. + */ + recycle = (double)(s->recycle_ring + s->recycle_cache) / + (s->alloc_fast + s->alloc_slow) * 100; + printf("\t\trecycling: %.1lf%% (alloc: %zu:%zu recycle: %zu:%zu)\n", + recycle, s->alloc_slow, s->alloc_fast, + s->recycle_ring, s->recycle_cache); + } + + ynl_sock_destroy(ys); + return 0; + +err_free: + free(a.s); +err_close: + fprintf(stderr, "YNL: %s\n", ys->err.msg); + ynl_sock_destroy(ys); + return 2; +} diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 8337aa6de2..c19dec2394 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -67,9 +67,9 @@ class Type(SpecAttr): if 'nested-attributes' in attr: self.nested_attrs = attr['nested-attributes'] if self.nested_attrs == family.name: - self.nested_render_name = f"{family.name}" + self.nested_render_name = c_lower(f"{family.name}") else: - self.nested_render_name = f"{family.name}_{c_lower(self.nested_attrs)}" + self.nested_render_name = c_lower(f"{family.name}_{self.nested_attrs}") if self.nested_attrs in self.family.consts: self.nested_struct_type = 'struct ' + self.nested_render_name + '_' @@ -105,6 +105,12 @@ class Type(SpecAttr): def is_scalar(self): return self.type in {'u8', 'u16', 'u32', 'u64', 's32', 's64'} + def is_recursive(self): + return False + + def is_recursive_for_op(self, ri): + return self.is_recursive() and not ri.op + def presence_type(self): return 'bit' @@ -145,6 +151,8 @@ class Type(SpecAttr): member = self._complex_member_type(ri) if member: ptr = '*' if self.is_multi_val() else '' + if self.is_recursive_for_op(ri): + ptr = '*' ri.cw.p(f"{member} {ptr}{self.c_name};") return members = self.arg_member(ri) @@ -235,8 +243,11 @@ class Type(SpecAttr): presence = '' for i in range(0, len(ref)): presence = f"{var}->{'.'.join(ref[:i] + [''])}_present.{ref[i]}" - if self.presence_type() == 'bit': - code.append(presence + ' = 1;') + # Every layer below last is a nest, so we know it uses bit presence + # last layer is "self" and may be a complex type + if i == len(ref) - 1 and self.presence_type() != 'bit': + continue + code.append(presence + ' = 1;') code += self._setter_lines(ri, member, presence) func_name = f"{op_prefix(ri, direction, deref=deref)}_set_{'_'.join(ref)}" @@ -264,6 +275,15 @@ class TypeUnused(Type): def attr_policy(self, cw): pass + def attr_put(self, ri, var): + pass + + def attr_get(self, ri, var, first): + pass + + def setter(self, ri, space, direction, deref=False, ref=None): + pass + class TypePad(Type): def presence_type(self): @@ -333,9 +353,8 @@ class TypeScalar(Type): else: self.is_bitfield = False - maybe_enum = not self.is_bitfield and 'enum' in self.attr - if maybe_enum and self.family.consts[self.attr['enum']].enum_name: - self.type_name = f"enum {self.family.name}_{c_lower(self.attr['enum'])}" + if not self.is_bitfield and 'enum' in self.attr: + self.type_name = self.family.consts[self.attr['enum']].user_type elif self.is_auto_scalar: self.type_name = '__' + self.type[0] + '64' else: @@ -521,11 +540,18 @@ class TypeBitfield32(Type): class TypeNest(Type): + def is_recursive(self): + return self.family.pure_nested_structs[self.nested_attrs].recursive + def _complex_member_type(self, ri): return self.nested_struct_type def free(self, ri, var, ref): - ri.cw.p(f'{self.nested_render_name}_free(&{var}->{ref}{self.c_name});') + at = '&' + if self.is_recursive_for_op(ri): + at = '' + ri.cw.p(f'if ({var}->{ref}{self.c_name})') + ri.cw.p(f'{self.nested_render_name}_free({at}{var}->{ref}{self.c_name});') def _attr_typol(self): return f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, ' @@ -534,8 +560,9 @@ class TypeNest(Type): return 'NLA_POLICY_NESTED(' + self.nested_render_name + '_nl_policy)' def attr_put(self, ri, var): + at = '' if self.is_recursive_for_op(ri) else '&' self._attr_put_line(ri, var, f"{self.nested_render_name}_put(nlh, " + - f"{self.enum_name}, &{var}->{self.c_name})") + f"{self.enum_name}, {at}{var}->{self.c_name})") def _attr_get(self, ri, var): get_lines = [f"if ({self.nested_render_name}_parse(&parg, attr))", @@ -548,6 +575,8 @@ class TypeNest(Type): ref = (ref if ref else []) + [self.c_name] for _, attr in ri.family.pure_nested_structs[self.nested_attrs].member_list(): + if attr.is_recursive(): + continue attr.setter(ri, self.nested_attrs, direction, deref=deref, ref=ref) @@ -685,16 +714,19 @@ class Struct: self.nested = type_list is None if family.name == c_lower(space_name): - self.render_name = f"{family.name}" + self.render_name = c_lower(family.name) else: - self.render_name = f"{family.name}_{c_lower(space_name)}" + self.render_name = c_lower(family.name + '-' + space_name) self.struct_name = 'struct ' + self.render_name if self.nested and space_name in family.consts: self.struct_name += '_' self.ptr_name = self.struct_name + ' *' + # All attr sets this one contains, directly or multiple levels down + self.child_nests = set() self.request = False self.reply = False + self.recursive = False self.attr_list = [] self.attrs = dict() @@ -755,11 +787,17 @@ class EnumSet(SpecEnumSet): if 'enum-name' in yaml: if yaml['enum-name']: self.enum_name = 'enum ' + c_lower(yaml['enum-name']) + self.user_type = self.enum_name else: self.enum_name = None else: self.enum_name = 'enum ' + self.render_name + if self.enum_name: + self.user_type = self.enum_name + else: + self.user_type = 'int' + self.value_pfx = yaml.get('name-prefix', f"{family.name}-{yaml['name']}-") super().__init__(family, yaml) @@ -841,7 +879,7 @@ class Operation(SpecOperation): def __init__(self, family, yaml, req_value, rsp_value): super().__init__(family, yaml, req_value, rsp_value) - self.render_name = family.name + '_' + c_lower(self.name) + self.render_name = c_lower(family.name + '_' + self.name) self.dual_policy = ('do' in yaml and 'request' in yaml['do']) and \ ('dump' in yaml and 'request' in yaml['dump']) @@ -985,6 +1023,33 @@ class Family(SpecFamily): self.root_sets[op['attribute-set']]['request'].update(req_attrs) self.root_sets[op['attribute-set']]['reply'].update(rsp_attrs) + def _sort_pure_types(self): + # Try to reorder according to dependencies + pns_key_list = list(self.pure_nested_structs.keys()) + pns_key_seen = set() + rounds = len(pns_key_list) ** 2 # it's basically bubble sort + for _ in range(rounds): + if len(pns_key_list) == 0: + break + name = pns_key_list.pop(0) + finished = True + for _, spec in self.attr_sets[name].items(): + if 'nested-attributes' in spec: + nested = spec['nested-attributes'] + # If the unknown nest we hit is recursive it's fine, it'll be a pointer + if self.pure_nested_structs[nested].recursive: + continue + if nested not in pns_key_seen: + # Dicts are sorted, this will make struct last + struct = self.pure_nested_structs.pop(name) + self.pure_nested_structs[name] = struct + finished = False + break + if finished: + pns_key_seen.add(name) + else: + pns_key_list.append(name) + def _load_nested_sets(self): attr_set_queue = list(self.root_sets.keys()) attr_set_seen = set(self.root_sets.keys()) @@ -1024,35 +1089,24 @@ class Family(SpecFamily): if attr in rs_members['reply']: self.pure_nested_structs[nested].reply = True - # Try to reorder according to dependencies - pns_key_list = list(self.pure_nested_structs.keys()) - pns_key_seen = set() - rounds = len(pns_key_list)**2 # it's basically bubble sort - for _ in range(rounds): - if len(pns_key_list) == 0: - break - name = pns_key_list.pop(0) - finished = True - for _, spec in self.attr_sets[name].items(): - if 'nested-attributes' in spec: - if spec['nested-attributes'] not in pns_key_seen: - # Dicts are sorted, this will make struct last - struct = self.pure_nested_structs.pop(name) - self.pure_nested_structs[name] = struct - finished = False - break - if finished: - pns_key_seen.add(name) - else: - pns_key_list.append(name) - # Propagate the request / reply + self._sort_pure_types() + + # Propagate the request / reply / recursive for attr_set, struct in reversed(self.pure_nested_structs.items()): for _, spec in self.attr_sets[attr_set].items(): if 'nested-attributes' in spec: - child = self.pure_nested_structs.get(spec['nested-attributes']) + child_name = spec['nested-attributes'] + struct.child_nests.add(child_name) + child = self.pure_nested_structs.get(child_name) if child: + if not child.recursive: + struct.child_nests.update(child.child_nests) child.request |= struct.request child.reply |= struct.reply + if attr_set in struct.child_nests: + struct.recursive = True + + self._sort_pure_types() def _load_attr_use(self): for _, struct in self.pure_nested_structs.items(): @@ -1119,6 +1173,10 @@ class RenderInfo: self.op_mode = op_mode self.op = op + self.fixed_hdr = None + if op and op.fixed_header: + self.fixed_hdr = 'struct ' + c_lower(op.fixed_header) + # 'do' and 'dump' response parsing is identical self.type_consistent = True if op_mode != 'do' and 'dump' in op: @@ -1158,8 +1216,9 @@ class RenderInfo: class CodeWriter: - def __init__(self, nlib, out_file=None): + def __init__(self, nlib, out_file=None, overwrite=True): self.nlib = nlib + self._overwrite = overwrite self._nl = False self._block_end = False @@ -1180,8 +1239,9 @@ class CodeWriter: return # Avoid modifying the file if contents didn't change self._out.flush() - if os.path.isfile(self._out_file) and filecmp.cmp(self._out.name, self._out_file, shallow=False): - return + if not self._overwrite and os.path.isfile(self._out_file): + if filecmp.cmp(self._out.name, self._out_file, shallow=False): + return with open(self._out_file, 'w+') as out_file: self._out.seek(0) shutil.copyfileobj(self._out, out_file) @@ -1431,7 +1491,7 @@ def op_prefix(ri, direction, deref=False): suffix += '_rsp' suffix += '_dump' if deref else '_list' - return f"{ri.family['name']}{suffix}" + return f"{ri.family.c_name}{suffix}" def type_name(ri, direction, deref=False): @@ -1464,6 +1524,10 @@ def print_dump_prototype(ri): print_prototype(ri, "request") +def put_typol_fwd(cw, struct): + cw.p(f'extern struct ynl_policy_nest {struct.render_name}_nest;') + + def put_typol(cw, struct): type_max = struct.attr_set.max_name cw.block_start(line=f'struct ynl_policy_attr {struct.render_name}_policy[{type_max} + 1] =') @@ -1483,8 +1547,8 @@ def put_typol(cw, struct): def _put_enum_to_str_helper(cw, render_name, map_name, arg_name, enum=None): args = [f'int {arg_name}'] - if enum and not ('enum-name' in enum and not enum['enum-name']): - args = [f'enum {render_name} {arg_name}'] + if enum: + args = [enum.user_type + ' ' + arg_name] cw.write_func_prot('const char *', f'{render_name}_str', args) cw.block_start() if enum and enum.type == 'flags': @@ -1497,11 +1561,11 @@ def _put_enum_to_str_helper(cw, render_name, map_name, arg_name, enum=None): def put_op_name_fwd(family, cw): - cw.write_func_prot('const char *', f'{family.name}_op_str', ['int op'], suffix=';') + cw.write_func_prot('const char *', f'{family.c_name}_op_str', ['int op'], suffix=';') def put_op_name(family, cw): - map_name = f'{family.name}_op_strmap' + map_name = f'{family.c_name}_op_strmap' cw.block_start(line=f"static const char * const {map_name}[] =") for op_name, op in family.msgs.items(): if op.rsp_value: @@ -1518,13 +1582,11 @@ def put_op_name(family, cw): cw.block_end(line=';') cw.nl() - _put_enum_to_str_helper(cw, family.name + '_op', map_name, 'op') + _put_enum_to_str_helper(cw, family.c_name + '_op', map_name, 'op') def put_enum_to_str_fwd(family, cw, enum): - args = [f'enum {enum.render_name} value'] - if 'enum-name' in enum and not enum['enum-name']: - args = ['int value'] + args = [enum.user_type + ' value'] cw.write_func_prot('const char *', f'{enum.render_name}_str', args, suffix=';') @@ -1539,12 +1601,17 @@ def put_enum_to_str(family, cw, enum): _put_enum_to_str_helper(cw, enum.render_name, map_name, 'value', enum=enum) -def put_req_nested(ri, struct): +def put_req_nested_prototype(ri, struct, suffix=';'): func_args = ['struct nlmsghdr *nlh', 'unsigned int attr_type', f'{struct.ptr_name}obj'] - ri.cw.write_func_prot('int', f'{struct.render_name}_put', func_args) + ri.cw.write_func_prot('int', f'{struct.render_name}_put', func_args, + suffix=suffix) + + +def put_req_nested(ri, struct): + put_req_nested_prototype(ri, struct, suffix='') ri.cw.block_start() ri.cw.write_func_lvar('struct nlattr *nest;') @@ -1565,7 +1632,9 @@ def _multi_parse(ri, struct, init_lines, local_vars): if struct.nested: iter_line = "mnl_attr_for_each_nested(attr, nested)" else: - iter_line = "mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr))" + if ri.fixed_hdr: + local_vars += ['void *hdr;'] + iter_line = "mnl_attr_for_each(attr, nlh, yarg->ys->family->hdr_len)" array_nests = set() multi_attrs = set() @@ -1598,6 +1667,9 @@ def _multi_parse(ri, struct, init_lines, local_vars): for arg in struct.inherited: ri.cw.p(f'dst->{arg} = {arg};') + if ri.fixed_hdr: + ri.cw.p('hdr = mnl_nlmsg_get_payload_offset(nlh, sizeof(struct genlmsghdr));') + ri.cw.p(f"memcpy(&dst->_hdr, hdr, sizeof({ri.fixed_hdr}));") for anest in sorted(all_multi): aspec = struct[anest] ri.cw.p(f"if (dst->{aspec.c_name})") @@ -1666,18 +1738,23 @@ def _multi_parse(ri, struct, init_lines, local_vars): ri.cw.nl() -def parse_rsp_nested(ri, struct): +def parse_rsp_nested_prototype(ri, struct, suffix=';'): func_args = ['struct ynl_parse_arg *yarg', 'const struct nlattr *nested'] for arg in struct.inherited: func_args.append('__u32 ' + arg) + ri.cw.write_func_prot('int', f'{struct.render_name}_parse', func_args, + suffix=suffix) + + +def parse_rsp_nested(ri, struct): + parse_rsp_nested_prototype(ri, struct, suffix='') + local_vars = ['const struct nlattr *attr;', f'{struct.ptr_name}dst = yarg->data;'] init_lines = [] - ri.cw.write_func_prot('int', f'{struct.render_name}_parse', func_args) - _multi_parse(ri, struct, init_lines, local_vars) @@ -1718,6 +1795,10 @@ def print_req(ri): ret_err = 'NULL' local_vars += [f'{type_name(ri, rdir(direction))} *rsp;'] + if ri.fixed_hdr: + local_vars += ['size_t hdr_len;', + 'void *hdr;'] + print_prototype(ri, direction, terminate=False) ri.cw.block_start() ri.cw.write_func_lvar(local_vars) @@ -1728,6 +1809,13 @@ def print_req(ri): if 'reply' in ri.op[ri.op_mode]: ri.cw.p(f"yrs.yarg.rsp_policy = &{ri.struct['reply'].render_name}_nest;") ri.cw.nl() + + if ri.fixed_hdr: + ri.cw.p("hdr_len = sizeof(req->_hdr);") + ri.cw.p("hdr = mnl_nlmsg_put_extra_header(nlh, hdr_len);") + ri.cw.p("memcpy(hdr, &req->_hdr, hdr_len);") + ri.cw.nl() + for _, attr in ri.struct["request"].member_list(): attr.attr_put(ri, "req") ri.cw.nl() @@ -1768,9 +1856,11 @@ def print_dump(ri): 'struct nlmsghdr *nlh;', 'int err;'] - for var in local_vars: - ri.cw.p(f'{var}') - ri.cw.nl() + if ri.fixed_hdr: + local_vars += ['size_t hdr_len;', + 'void *hdr;'] + + ri.cw.write_func_lvar(local_vars) ri.cw.p('yds.ys = ys;') ri.cw.p(f"yds.alloc_sz = sizeof({type_name(ri, rdir(direction))});") @@ -1783,6 +1873,12 @@ def print_dump(ri): ri.cw.nl() ri.cw.p(f"nlh = ynl_gemsg_start_dump(ys, {ri.nl.get_family_id()}, {ri.op.enum_name}, 1);") + if ri.fixed_hdr: + ri.cw.p("hdr_len = sizeof(req->_hdr);") + ri.cw.p("hdr = mnl_nlmsg_put_extra_header(nlh, hdr_len);") + ri.cw.p("memcpy(hdr, &req->_hdr, hdr_len);") + ri.cw.nl() + if "request" in ri.op[ri.op_mode]: ri.cw.p(f"ys->req_policy = &{ri.struct['request'].render_name}_nest;") ri.cw.nl() @@ -1838,7 +1934,11 @@ def _print_type(ri, direction, struct): if ri.op_mode == 'dump': suffix += '_dump' - ri.cw.block_start(line=f"struct {ri.family['name']}{suffix}") + ri.cw.block_start(line=f"struct {ri.family.c_name}{suffix}") + + if ri.fixed_hdr: + ri.cw.p(ri.fixed_hdr + ' _hdr;') + ri.cw.nl() meta_started = False for _, attr in struct.member_list(): @@ -1968,6 +2068,10 @@ def _free_type(ri, direction, struct): ri.cw.nl() +def free_rsp_nested_prototype(ri): + print_free_prototype(ri, "") + + def free_rsp_nested(ri, struct): _free_type(ri, "", struct) @@ -2068,12 +2172,13 @@ def print_kernel_policy_ranges(family, cw): first = False sign = '' if attr.type[0] == 'u' else '_signed' + suffix = 'ULL' if attr.type[0] == 'u' else 'LL' cw.block_start(line=f'static const struct netlink_range_validation{sign} {c_lower(attr.enum_name)}_range =') members = [] if 'min' in attr.checks: - members.append(('min', attr.get_limit('min'))) + members.append(('min', str(attr.get_limit('min')) + suffix)) if 'max' in attr.checks: - members.append(('max', attr.get_limit('max'))) + members.append(('max', str(attr.get_limit('max')) + suffix)) cw.write_struct_init(members) cw.block_end(line=';') cw.nl() @@ -2103,7 +2208,7 @@ def print_kernel_op_table_fwd(family, cw, terminate): cnt = len(family.ops) qual = 'static const' if not exported else 'const' - line = f"{qual} struct {struct_type} {family.name}_nl_ops[{cnt}]" + line = f"{qual} struct {struct_type} {family.c_name}_nl_ops[{cnt}]" if terminate: cw.p(f"extern {line};") else: @@ -2246,7 +2351,7 @@ def print_kernel_mcgrp_src(family, cw): if not family.mcgrps['list']: return - cw.block_start('static const struct genl_multicast_group ' + family.name + '_nl_mcgrps[] =') + cw.block_start('static const struct genl_multicast_group ' + family.c_name + '_nl_mcgrps[] =') for grp in family.mcgrps['list']: name = grp['name'] grp_id = c_upper(f"{family.name}-nlgrp-{name}") @@ -2259,7 +2364,7 @@ def print_kernel_family_struct_hdr(family, cw): if not kernel_can_gen_family_struct(family): return - cw.p(f"extern struct genl_family {family.name}_nl_family;") + cw.p(f"extern struct genl_family {family.c_name}_nl_family;") cw.nl() @@ -2274,14 +2379,14 @@ def print_kernel_family_struct_src(family, cw): cw.p('.parallel_ops\t= true,') cw.p('.module\t\t= THIS_MODULE,') if family.kernel_policy == 'per-op': - cw.p(f'.ops\t\t= {family.name}_nl_ops,') - cw.p(f'.n_ops\t\t= ARRAY_SIZE({family.name}_nl_ops),') + cw.p(f'.ops\t\t= {family.c_name}_nl_ops,') + cw.p(f'.n_ops\t\t= ARRAY_SIZE({family.c_name}_nl_ops),') elif family.kernel_policy == 'split': - cw.p(f'.split_ops\t= {family.name}_nl_ops,') - cw.p(f'.n_split_ops\t= ARRAY_SIZE({family.name}_nl_ops),') + cw.p(f'.split_ops\t= {family.c_name}_nl_ops,') + cw.p(f'.n_split_ops\t= ARRAY_SIZE({family.c_name}_nl_ops),') if family.mcgrps['list']: - cw.p(f'.mcgrps\t\t= {family.name}_nl_mcgrps,') - cw.p(f'.n_mcgrps\t= ARRAY_SIZE({family.name}_nl_mcgrps),') + cw.p(f'.mcgrps\t\t= {family.c_name}_nl_mcgrps,') + cw.p(f'.n_mcgrps\t= ARRAY_SIZE({family.c_name}_nl_mcgrps),') cw.block_end(';') @@ -2291,7 +2396,7 @@ def uapi_enum_start(family, cw, obj, ckey='', enum_name='enum-name'): if obj[enum_name]: start_line = 'enum ' + c_lower(obj[enum_name]) elif ckey and ckey in obj: - start_line = 'enum ' + family.name + '_' + c_lower(obj[ckey]) + start_line = 'enum ' + family.c_name + '_' + c_lower(obj[ckey]) cw.block_start(line=start_line) @@ -2475,7 +2580,11 @@ def render_user_family(family, cw, prototype): cw.nl() cw.block_start(f'{symbol} = ') - cw.p(f'.name\t\t= "{family.name}",') + cw.p(f'.name\t\t= "{family.c_name}",') + if family.fixed_header: + cw.p(f'.hdr_len\t= sizeof(struct genlmsghdr) + sizeof(struct {c_lower(family.fixed_header)}),') + else: + cw.p('.hdr_len\t= sizeof(struct genlmsghdr),') if family.ntfs: cw.p(f".ntf_info\t= {family['name']}_ntf_info,") cw.p(f".ntf_info_size\t= MNL_ARRAY_SIZE({family['name']}_ntf_info),") @@ -2509,6 +2618,8 @@ def main(): parser.add_argument('--header', dest='header', action='store_true', default=None) parser.add_argument('--source', dest='header', action='store_false') parser.add_argument('--user-header', nargs='+', default=[]) + parser.add_argument('--cmp-out', action='store_true', default=None, + help='Do not overwrite the output file if the new output is identical to the old') parser.add_argument('--exclude-op', action='append', default=[]) parser.add_argument('-o', dest='out_file', type=str, default=None) args = parser.parse_args() @@ -2536,7 +2647,7 @@ def main(): print(f'Message enum-model {parsed.msg_id_model} not supported for {args.mode} generation') os.sys.exit(1) - cw = CodeWriter(BaseNlLib(), args.out_file) + cw = CodeWriter(BaseNlLib(), args.out_file, overwrite=(not args.cmp_out)) _, spec_kernel = find_kernel_root(args.spec) if args.mode == 'uapi' or args.header: @@ -2557,7 +2668,7 @@ def main(): render_uapi(parsed, cw) return - hdr_prot = f"_LINUX_{parsed.name.upper()}_GEN_H" + hdr_prot = f"_LINUX_{parsed.c_name.upper()}_GEN_H" if args.header: cw.p('#ifndef ' + hdr_prot) cw.p('#define ' + hdr_prot) @@ -2728,7 +2839,14 @@ def main(): put_enum_to_str(parsed, cw, const) cw.nl() + has_recursive_nests = False cw.p('/* Policies */') + for struct in parsed.pure_nested_structs.values(): + if struct.recursive: + put_typol_fwd(cw, struct) + has_recursive_nests = True + if has_recursive_nests: + cw.nl() for name in parsed.pure_nested_structs: struct = Struct(parsed, name) put_typol(cw, struct) @@ -2737,6 +2855,15 @@ def main(): put_typol(cw, struct) cw.p('/* Common nested types */') + if has_recursive_nests: + for attr_set, struct in parsed.pure_nested_structs.items(): + ri = RenderInfo(cw, parsed, args.mode, "", "", attr_set) + free_rsp_nested_prototype(ri) + if struct.request: + put_req_nested_prototype(ri, struct) + if struct.reply: + parse_rsp_nested_prototype(ri, struct) + cw.nl() for attr_set, struct in parsed.pure_nested_structs.items(): ri = RenderInfo(cw, parsed, args.mode, "", "", attr_set) @@ -2762,6 +2889,7 @@ def main(): ri = RenderInfo(cw, parsed, args.mode, op, "dump") if not ri.type_consistent: parse_rsp_msg(ri, deref=True) + print_req_free(ri) print_dump_type_free(ri) print_dump(ri) cw.nl() diff --git a/tools/net/ynl/ynl-gen-rst.py b/tools/net/ynl/ynl-gen-rst.py new file mode 100755 index 0000000000..262d88f886 --- /dev/null +++ b/tools/net/ynl/ynl-gen-rst.py @@ -0,0 +1,417 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0 +# -*- coding: utf-8; mode: python -*- + +""" + Script to auto generate the documentation for Netlink specifications. + + :copyright: Copyright (C) 2023 Breno Leitao + :license: GPL Version 2, June 1991 see linux/COPYING for details. + + This script performs extensive parsing to the Linux kernel's netlink YAML + spec files, in an effort to avoid needing to heavily mark up the original + YAML file. + + This code is split in three big parts: + 1) RST formatters: Use to convert a string to a RST output + 2) Parser helpers: Functions to parse the YAML data structure + 3) Main function and small helpers +""" + +from typing import Any, Dict, List +import os.path +import sys +import argparse +import logging +import yaml + + +SPACE_PER_LEVEL = 4 + + +# RST Formatters +# ============== +def headroom(level: int) -> str: + """Return space to format""" + return " " * (level * SPACE_PER_LEVEL) + + +def bold(text: str) -> str: + """Format bold text""" + return f"**{text}**" + + +def inline(text: str) -> str: + """Format inline text""" + return f"``{text}``" + + +def sanitize(text: str) -> str: + """Remove newlines and multiple spaces""" + # This is useful for some fields that are spread across multiple lines + return str(text).replace("\n", "").strip() + + +def rst_fields(key: str, value: str, level: int = 0) -> str: + """Return a RST formatted field""" + return headroom(level) + f":{key}: {value}" + + +def rst_definition(key: str, value: Any, level: int = 0) -> str: + """Format a single rst definition""" + return headroom(level) + key + "\n" + headroom(level + 1) + str(value) + + +def rst_paragraph(paragraph: str, level: int = 0) -> str: + """Return a formatted paragraph""" + return headroom(level) + paragraph + + +def rst_bullet(item: str, level: int = 0) -> str: + """Return a formatted a bullet""" + return headroom(level) + f"- {item}" + + +def rst_subsection(title: str) -> str: + """Add a sub-section to the document""" + return f"{title}\n" + "-" * len(title) + + +def rst_subsubsection(title: str) -> str: + """Add a sub-sub-section to the document""" + return f"{title}\n" + "~" * len(title) + + +def rst_section(title: str) -> str: + """Add a section to the document""" + return f"\n{title}\n" + "=" * len(title) + + +def rst_subtitle(title: str) -> str: + """Add a subtitle to the document""" + return "\n" + "-" * len(title) + f"\n{title}\n" + "-" * len(title) + "\n\n" + + +def rst_title(title: str) -> str: + """Add a title to the document""" + return "=" * len(title) + f"\n{title}\n" + "=" * len(title) + "\n\n" + + +def rst_list_inline(list_: List[str], level: int = 0) -> str: + """Format a list using inlines""" + return headroom(level) + "[" + ", ".join(inline(i) for i in list_) + "]" + + +def rst_header() -> str: + """The headers for all the auto generated RST files""" + lines = [] + + lines.append(rst_paragraph(".. SPDX-License-Identifier: GPL-2.0")) + lines.append(rst_paragraph(".. NOTE: This document was auto-generated.\n\n")) + + return "\n".join(lines) + + +def rst_toctree(maxdepth: int = 2) -> str: + """Generate a toctree RST primitive""" + lines = [] + + lines.append(".. toctree::") + lines.append(f" :maxdepth: {maxdepth}\n\n") + + return "\n".join(lines) + + +def rst_label(title: str) -> str: + """Return a formatted label""" + return f".. _{title}:\n\n" + + +# Parsers +# ======= + + +def parse_mcast_group(mcast_group: List[Dict[str, Any]]) -> str: + """Parse 'multicast' group list and return a formatted string""" + lines = [] + for group in mcast_group: + lines.append(rst_bullet(group["name"])) + + return "\n".join(lines) + + +def parse_do(do_dict: Dict[str, Any], level: int = 0) -> str: + """Parse 'do' section and return a formatted string""" + lines = [] + for key in do_dict.keys(): + lines.append(rst_paragraph(bold(key), level + 1)) + lines.append(parse_do_attributes(do_dict[key], level + 1) + "\n") + + return "\n".join(lines) + + +def parse_do_attributes(attrs: Dict[str, Any], level: int = 0) -> str: + """Parse 'attributes' section""" + if "attributes" not in attrs: + return "" + lines = [rst_fields("attributes", rst_list_inline(attrs["attributes"]), level + 1)] + + return "\n".join(lines) + + +def parse_operations(operations: List[Dict[str, Any]]) -> str: + """Parse operations block""" + preprocessed = ["name", "doc", "title", "do", "dump"] + lines = [] + + for operation in operations: + lines.append(rst_section(operation["name"])) + lines.append(rst_paragraph(sanitize(operation["doc"])) + "\n") + + for key in operation.keys(): + if key in preprocessed: + # Skip the special fields + continue + lines.append(rst_fields(key, operation[key], 0)) + + if "do" in operation: + lines.append(rst_paragraph(":do:", 0)) + lines.append(parse_do(operation["do"], 0)) + if "dump" in operation: + lines.append(rst_paragraph(":dump:", 0)) + lines.append(parse_do(operation["dump"], 0)) + + # New line after fields + lines.append("\n") + + return "\n".join(lines) + + +def parse_entries(entries: List[Dict[str, Any]], level: int) -> str: + """Parse a list of entries""" + lines = [] + for entry in entries: + if isinstance(entry, dict): + # entries could be a list or a dictionary + lines.append( + rst_fields(entry.get("name", ""), sanitize(entry.get("doc", "")), level) + ) + elif isinstance(entry, list): + lines.append(rst_list_inline(entry, level)) + else: + lines.append(rst_bullet(inline(sanitize(entry)), level)) + + lines.append("\n") + return "\n".join(lines) + + +def parse_definitions(defs: Dict[str, Any]) -> str: + """Parse definitions section""" + preprocessed = ["name", "entries", "members"] + ignored = ["render-max"] # This is not printed + lines = [] + + for definition in defs: + lines.append(rst_section(definition["name"])) + for k in definition.keys(): + if k in preprocessed + ignored: + continue + lines.append(rst_fields(k, sanitize(definition[k]), 0)) + + # Field list needs to finish with a new line + lines.append("\n") + if "entries" in definition: + lines.append(rst_paragraph(":entries:", 0)) + lines.append(parse_entries(definition["entries"], 1)) + if "members" in definition: + lines.append(rst_paragraph(":members:", 0)) + lines.append(parse_entries(definition["members"], 1)) + + return "\n".join(lines) + + +def parse_attr_sets(entries: List[Dict[str, Any]]) -> str: + """Parse attribute from attribute-set""" + preprocessed = ["name", "type"] + ignored = ["checks"] + lines = [] + + for entry in entries: + lines.append(rst_section(entry["name"])) + for attr in entry["attributes"]: + type_ = attr.get("type") + attr_line = attr["name"] + if type_: + # Add the attribute type in the same line + attr_line += f" ({inline(type_)})" + + lines.append(rst_subsubsection(attr_line)) + + for k in attr.keys(): + if k in preprocessed + ignored: + continue + lines.append(rst_fields(k, sanitize(attr[k]), 0)) + lines.append("\n") + + return "\n".join(lines) + + +def parse_sub_messages(entries: List[Dict[str, Any]]) -> str: + """Parse sub-message definitions""" + lines = [] + + for entry in entries: + lines.append(rst_section(entry["name"])) + for fmt in entry["formats"]: + value = fmt["value"] + + lines.append(rst_bullet(bold(value))) + for attr in ['fixed-header', 'attribute-set']: + if attr in fmt: + lines.append(rst_fields(attr, fmt[attr], 1)) + lines.append("\n") + + return "\n".join(lines) + + +def parse_yaml(obj: Dict[str, Any]) -> str: + """Format the whole YAML into a RST string""" + lines = [] + + # Main header + + lines.append(rst_header()) + + title = f"Family ``{obj['name']}`` netlink specification" + lines.append(rst_title(title)) + lines.append(rst_paragraph(".. contents::\n")) + + if "doc" in obj: + lines.append(rst_subtitle("Summary")) + lines.append(rst_paragraph(obj["doc"], 0)) + + # Operations + if "operations" in obj: + lines.append(rst_subtitle("Operations")) + lines.append(parse_operations(obj["operations"]["list"])) + + # Multicast groups + if "mcast-groups" in obj: + lines.append(rst_subtitle("Multicast groups")) + lines.append(parse_mcast_group(obj["mcast-groups"]["list"])) + + # Definitions + if "definitions" in obj: + lines.append(rst_subtitle("Definitions")) + lines.append(parse_definitions(obj["definitions"])) + + # Attributes set + if "attribute-sets" in obj: + lines.append(rst_subtitle("Attribute sets")) + lines.append(parse_attr_sets(obj["attribute-sets"])) + + # Sub-messages + if "sub-messages" in obj: + lines.append(rst_subtitle("Sub-messages")) + lines.append(parse_sub_messages(obj["sub-messages"])) + + return "\n".join(lines) + + +# Main functions +# ============== + + +def parse_arguments() -> argparse.Namespace: + """Parse arguments from user""" + parser = argparse.ArgumentParser(description="Netlink RST generator") + + parser.add_argument("-v", "--verbose", action="store_true") + parser.add_argument("-o", "--output", help="Output file name") + + # Index and input are mutually exclusive + group = parser.add_mutually_exclusive_group() + group.add_argument( + "-x", "--index", action="store_true", help="Generate the index page" + ) + group.add_argument("-i", "--input", help="YAML file name") + + args = parser.parse_args() + + if args.verbose: + logging.basicConfig(level=logging.DEBUG) + + if args.input and not os.path.isfile(args.input): + logging.warning("%s is not a valid file.", args.input) + sys.exit(-1) + + if not args.output: + logging.error("No output file specified.") + sys.exit(-1) + + if os.path.isfile(args.output): + logging.debug("%s already exists. Overwriting it.", args.output) + + return args + + +def parse_yaml_file(filename: str) -> str: + """Transform the YAML specified by filename into a rst-formmated string""" + with open(filename, "r", encoding="utf-8") as spec_file: + yaml_data = yaml.safe_load(spec_file) + content = parse_yaml(yaml_data) + + return content + + +def write_to_rstfile(content: str, filename: str) -> None: + """Write the generated content into an RST file""" + logging.debug("Saving RST file to %s", filename) + + with open(filename, "w", encoding="utf-8") as rst_file: + rst_file.write(content) + + +def generate_main_index_rst(output: str) -> None: + """Generate the `networking_spec/index` content and write to the file""" + lines = [] + + lines.append(rst_header()) + lines.append(rst_label("specs")) + lines.append(rst_title("Netlink Family Specifications")) + lines.append(rst_toctree(1)) + + index_dir = os.path.dirname(output) + logging.debug("Looking for .rst files in %s", index_dir) + for filename in sorted(os.listdir(index_dir)): + if not filename.endswith(".rst") or filename == "index.rst": + continue + lines.append(f" {filename.replace('.rst', '')}\n") + + logging.debug("Writing an index file at %s", output) + write_to_rstfile("".join(lines), output) + + +def main() -> None: + """Main function that reads the YAML files and generates the RST files""" + + args = parse_arguments() + + if args.input: + logging.debug("Parsing %s", args.input) + try: + content = parse_yaml_file(os.path.join(args.input)) + except Exception as exception: + logging.warning("Failed to parse %s.", args.input) + logging.warning(exception) + sys.exit(-1) + + write_to_rstfile(content, args.output) + + if args.index: + # Generate the index RST file + generate_main_index_rst(args.output) + + +if __name__ == "__main__": + main() diff --git a/tools/net/ynl/ynl-regen.sh b/tools/net/ynl/ynl-regen.sh index bdba24066c..a37304dcc8 100755 --- a/tools/net/ynl/ynl-regen.sh +++ b/tools/net/ynl/ynl-regen.sh @@ -30,8 +30,8 @@ for f in $files; do fi echo -e "\tGEN ${params[2]}\t$f" - $TOOL --mode ${params[2]} --${params[3]} --spec $KDIR/${params[0]} \ - $args -o $f + $TOOL --cmp-out --mode ${params[2]} --${params[3]} \ + --spec $KDIR/${params[0]} $args -o $f done popd >>/dev/null diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 167603f839..c4c2f75ead 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -291,7 +291,7 @@ static void init_insn_state(struct objtool_file *file, struct insn_state *state, static struct cfi_state *cfi_alloc(void) { - struct cfi_state *cfi = calloc(sizeof(struct cfi_state), 1); + struct cfi_state *cfi = calloc(1, sizeof(struct cfi_state)); if (!cfi) { WARN("calloc failed"); exit(1); diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore index f533e76fb4..f5b81d4393 100644 --- a/tools/perf/.gitignore +++ b/tools/perf/.gitignore @@ -39,6 +39,9 @@ trace/beauty/generated/ pmu-events/pmu-events.c pmu-events/jevents pmu-events/metric_test.log +tests/shell/*.shellcheck_log +tests/shell/coresight/*.shellcheck_log +tests/shell/lib/*.shellcheck_log feature/ libapi/ libbpf/ @@ -49,3 +52,4 @@ libtraceevent/ libtraceevent_plugins/ fixdep Documentation/doc.dep +python_ext_build/ diff --git a/tools/perf/Documentation/itrace.txt b/tools/perf/Documentation/itrace.txt index a97f95825b..19cc179be9 100644 --- a/tools/perf/Documentation/itrace.txt +++ b/tools/perf/Documentation/itrace.txt @@ -25,6 +25,7 @@ q quicker (less detailed) decoding A approximate IPC Z prefer to ignore timestamps (so-called "timeless" decoding) + T use the timestamp trace as kernel time The default is all events i.e. the same as --itrace=iybxwpe, except for perf script where it is --itrace=ce diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt index fe168e8165..b95524bea0 100644 --- a/tools/perf/Documentation/perf-annotate.txt +++ b/tools/perf/Documentation/perf-annotate.txt @@ -155,6 +155,17 @@ include::itrace.txt[] stdio or stdio2 (Default: 0). Note that this is about selection of functions to display, not about lines within the function. +--data-type[=TYPE_NAME]:: + Display data type annotation instead of code. It infers data type of + samples (if they are memory accessing instructions) using DWARF debug + information. It can take an optional argument of data type name. In + that case it'd show annotation for the type only, otherwise it'd show + all data types it finds. + +--type-stat:: + Show stats for the data type annotation. + + SEE ALSO -------- linkperf:perf-record[1], linkperf:perf-report[1] diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt index 0b4e79dbd3..379f9d7a8a 100644 --- a/tools/perf/Documentation/perf-config.txt +++ b/tools/perf/Documentation/perf-config.txt @@ -251,7 +251,8 @@ annotate.*:: addr2line binary to use for file names and line numbers. annotate.objdump:: - objdump binary to use for disassembly and annotations. + objdump binary to use for disassembly and annotations, + including in the 'perf test' command. annotate.disassembler_style:: Use this to change the default disassembler style to some other value @@ -722,7 +723,6 @@ session-.*:: Defines new record session for daemon. The value is record's command line without the 'record' keyword. - SEE ALSO -------- linkperf:perf[1] diff --git a/tools/perf/Documentation/perf-intel-pt.txt b/tools/perf/Documentation/perf-intel-pt.txt index 4c90cc176f..2109690b0d 100644 --- a/tools/perf/Documentation/perf-intel-pt.txt +++ b/tools/perf/Documentation/perf-intel-pt.txt @@ -683,7 +683,7 @@ Buffer handling ~~~~~~~~~~~~~~~ There may be buffer limitations (i.e. single ToPa entry) which means that actual -buffer sizes are limited to powers of 2 up to 4MiB (MAX_ORDER). In order to +buffer sizes are limited to powers of 2 up to 4MiB (MAX_PAGE_ORDER). In order to provide other sizes, and in particular an arbitrarily large size, multiple buffers are logically concatenated. However an interrupt must be used to switch between buffers. That has two potential problems: diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt index d5f78e125e..3b12595193 100644 --- a/tools/perf/Documentation/perf-list.txt +++ b/tools/perf/Documentation/perf-list.txt @@ -47,6 +47,10 @@ Print PMU events and metrics limited to the specific PMU name. --json:: Output in JSON format. +-o:: +--output=:: + Output file name. By default output is written to stdout. + [[EVENT_MODIFIERS]] EVENT MODIFIERS --------------- @@ -81,11 +85,13 @@ For Intel systems precise event sampling is implemented with PEBS which supports up to precise-level 2, and precise level 3 for some special cases -On AMD systems it is implemented using IBS (up to precise-level 2). -The precise modifier works with event types 0x76 (cpu-cycles, CPU -clocks not halted) and 0xC1 (micro-ops retired). Both events map to -IBS execution sampling (IBS op) with the IBS Op Counter Control bit -(IbsOpCntCtl) set respectively (see the +On AMD systems it is implemented using IBS OP (up to precise-level 2). +Unlike Intel PEBS which provides levels of precision, AMD core pmu is +inherently non-precise and IBS is inherently precise. (i.e. ibs_op//, +ibs_op//p, ibs_op//pp and ibs_op//ppp are all same). The precise modifier +works with event types 0x76 (cpu-cycles, CPU clocks not halted) and 0xC1 +(micro-ops retired). Both events map to IBS execution sampling (IBS op) +with the IBS Op Counter Control bit (IbsOpCntCtl) set respectively (see the Core Complex (CCX) -> Processor x86 Core -> Instruction Based Sampling (IBS) section of the [AMD Processor Programming Reference (PPR)] relevant to the family, model and stepping of the processor being used). diff --git a/tools/perf/Documentation/perf-lock.txt b/tools/perf/Documentation/perf-lock.txt index 503abcba14..f5938d616d 100644 --- a/tools/perf/Documentation/perf-lock.txt +++ b/tools/perf/Documentation/perf-lock.txt @@ -119,7 +119,7 @@ INFO OPTIONS CONTENTION OPTIONS --------------- +------------------ -k:: --key=:: diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 1889f66add..6015fdd08f 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -445,6 +445,10 @@ following filters are defined: 4th-Gen Xeon+ server), the save branch type is unconditionally enabled when the taken branch stack sampling is enabled. - priv: save privilege state during sampling in case binary is not available later + - counter: save occurrences of the event since the last branch entry. Currently, the + feature is only supported by a newer CPU, e.g., Intel Sierra Forest and + later platforms. An error out is expected if it's used on the unsupported + kernel or CPUs. + The option requires at least one branch type among any, any_call, any_ret, ind_call, cond. diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index af068b4f1e..38f59ac064 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt @@ -118,6 +118,9 @@ OPTIONS - retire_lat: On X86, this reports pipeline stall of this instruction compared to the previous instruction in cycles. And currently supported only on X86 - simd: Flags describing a SIMD operation. "e" for empty Arm SVE predicate. "p" for partial Arm SVE predicate + - type: Data type of sample memory access. + - typeoff: Offset in the data type of sample memory access. + - symoff: Offset in the symbol. By default, comm, dso and symbol keys are used. (i.e. --sort comm,dso,symbol) diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index 8f789fa124..5af2e432b5 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt @@ -422,7 +422,34 @@ See perf list output for the possible metrics and metricgroups. -A:: --no-aggr:: -Do not aggregate counts across all monitored CPUs. +--no-merge:: +Do not aggregate/merge counts across monitored CPUs or PMUs. + +When multiple events are created from a single event specification, +stat will, by default, aggregate the event counts and show the result +in a single row. This option disables that behavior and shows the +individual events and counts. + +Multiple events are created from a single event specification when: + +1. PID monitoring isn't requested and the system has more than one + CPU. For example, a system with 8 SMT threads will have one event + opened on each thread and aggregation is performed across them. + +2. Prefix or glob wildcard matching is used for the PMU name. For + example, multiple memory controller PMUs may exist typically with a + suffix of _0, _1, etc. By default the event counts will all be + combined if the PMU is specified without the suffix such as + uncore_imc rather than uncore_imc_0. + +3. Aliases, which are listed immediately after the Kernel PMU events + by perf list, are used. + +--hybrid-merge:: +Merge core event counts from all core PMUs. In hybrid or big.LITTLE +systems by default each core PMU will report its count +separately. This option forces core PMU counts to be combined to give +a behavior closer to having a single CPU type in the system. --topdown:: Print top-down metrics supported by the CPU. This allows to determine @@ -475,29 +502,6 @@ highlight 'tma_frontend_bound'. This metric may be drilled into with Error out if the input is higher than the supported max level. ---no-merge:: -Do not merge results from same PMUs. - -When multiple events are created from a single event specification, -stat will, by default, aggregate the event counts and show the result -in a single row. This option disables that behavior and shows -the individual events and counts. - -Multiple events are created from a single event specification when: -1. Prefix or glob matching is used for the PMU name. -2. Aliases, which are listed immediately after the Kernel PMU events - by perf list, are used. - ---hybrid-merge:: -Merge the hybrid event counts from all PMUs. - -For hybrid events, by default, the stat aggregates and reports the event -counts per PMU. But sometimes, it's also useful to aggregate event counts -from all PMUs. This option enables that behavior and reports the counts -without PMUs. - -For non-hybrid events, it should be no effect. - --smi-cost:: Measure SMI cost if msr/aperf/ and msr/smi/ events are supported. diff --git a/tools/perf/Documentation/perf.txt b/tools/perf/Documentation/perf.txt index ba3df49c16..a7cf7bc2f9 100644 --- a/tools/perf/Documentation/perf.txt +++ b/tools/perf/Documentation/perf.txt @@ -64,6 +64,9 @@ OPTIONS perf-event-open - Print perf_event_open() arguments and return value +--debug-file:: + Write debug output to a specified file. + DESCRIPTION ----------- Performance counters for Linux are a new kernel-based subsystem diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index b3e6ed10f4..aa55850fbc 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -476,6 +476,11 @@ else else CFLAGS += -DHAVE_DWARF_GETLOCATIONS_SUPPORT endif # dwarf_getlocations + ifneq ($(feature-dwarf_getcfi), 1) + msg := $(warning Old libdw.h, finding variables at given 'perf probe' point will not work, install elfutils-devel/libdw-dev >= 0.142); + else + CFLAGS += -DHAVE_DWARF_CFI_SUPPORT + endif # dwarf_getcfi endif # Dwarf support endif # libelf support endif # NO_LIBELF @@ -680,15 +685,15 @@ ifndef BUILD_BPF_SKEL endif ifeq ($(BUILD_BPF_SKEL),1) - ifeq ($(filter -DHAVE_LIBBPF_SUPPORT, $(CFLAGS)),) - dummy := $(warning Warning: Disabled BPF skeletons as libbpf is required) - BUILD_BPF_SKEL := 0 - else ifeq ($(filter -DHAVE_LIBELF_SUPPORT, $(CFLAGS)),) + ifeq ($(filter -DHAVE_LIBELF_SUPPORT, $(CFLAGS)),) dummy := $(warning Warning: Disabled BPF skeletons as libelf is required by bpftool) BUILD_BPF_SKEL := 0 else ifeq ($(filter -DHAVE_ZLIB_SUPPORT, $(CFLAGS)),) dummy := $(warning Warning: Disabled BPF skeletons as zlib is required by bpftool) BUILD_BPF_SKEL := 0 + else ifeq ($(filter -DHAVE_LIBBPF_SUPPORT, $(CFLAGS)),) + dummy := $(warning Warning: Disabled BPF skeletons as libbpf is required) + BUILD_BPF_SKEL := 0 else ifeq ($(call get-executable,$(CLANG)),) dummy := $(warning Warning: Disabled BPF skeletons as clang ($(CLANG)) is missing) BUILD_BPF_SKEL := 0 diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index af22d539f3..116db78744 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -134,6 +134,8 @@ include ../scripts/utilities.mak # x86 instruction decoder - new instructions test # # Define GEN_VMLINUX_H to generate vmlinux.h from the BTF. +# +# Define NO_SHELLCHECK if you do not want to run shellcheck during build # As per kernel Makefile, avoid funny character set dependencies unexport LC_ALL @@ -227,8 +229,25 @@ else force_fixdep := $(config) endif +# Runs shellcheck on perf test shell scripts +ifeq ($(NO_SHELLCHECK),1) + SHELLCHECK := +else + SHELLCHECK := $(shell which shellcheck 2> /dev/null) +endif + +# shellcheck is using in tools/perf/tests/Build with option -a/--check-sourced ( +# introduced in v0.4.7) and -S/--severity (introduced in v0.6.0). So make the +# minimal shellcheck version as v0.6.0. +ifneq ($(SHELLCHECK),) + ifeq ($(shell expr $(shell $(SHELLCHECK) --version | grep version: | \ + sed -e 's/.\+ \([0-9]\+\).\([0-9]\+\).\([0-9]\+\)/\1\2\3/g') \< 060), 1) + SHELLCHECK := + endif +endif + export srctree OUTPUT RM CC CXX LD AR CFLAGS CXXFLAGS V BISON FLEX AWK -export HOSTCC HOSTLD HOSTAR HOSTCFLAGS +export HOSTCC HOSTLD HOSTAR HOSTCFLAGS SHELLCHECK include $(srctree)/tools/build/Makefile.include @@ -1152,7 +1171,7 @@ bpf-skel-clean: clean:: $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clean $(LIBSYMBOL)-clean $(LIBPERF)-clean arm64-sysreg-defs-clean fixdep-clean python-clean bpf-skel-clean tests-coresight-targets-clean $(call QUIET_CLEAN, core-objs) $(RM) $(LIBPERF_A) $(OUTPUT)perf-archive $(OUTPUT)perf-iostat $(LANG_BINDINGS) - $(Q)find $(or $(OUTPUT),.) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete + $(Q)find $(or $(OUTPUT),.) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete -o -name '*.shellcheck_log' -delete $(Q)$(RM) $(OUTPUT).config-detected $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32 $(OUTPUT)$(LIBJVMTI).so $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)FEATURE-DUMP $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* \ diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c index 2cf873d71d..77e6663c17 100644 --- a/tools/perf/arch/arm/util/cs-etm.c +++ b/tools/perf/arch/arm/util/cs-etm.c @@ -199,7 +199,7 @@ static int cs_etm_validate_config(struct auxtrace_record *itr, { int i, err = -EINVAL; struct perf_cpu_map *event_cpus = evsel->evlist->core.user_requested_cpus; - struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL); + struct perf_cpu_map *online_cpus = perf_cpu_map__new_online_cpus(); /* Set option of each CPU we have */ for (i = 0; i < cpu__max_cpu().cpu; i++) { @@ -211,7 +211,7 @@ static int cs_etm_validate_config(struct auxtrace_record *itr, * program can run on any CPUs in this case, thus don't skip * validation. */ - if (!perf_cpu_map__empty(event_cpus) && + if (!perf_cpu_map__has_any_cpu_or_is_empty(event_cpus) && !perf_cpu_map__has(event_cpus, cpu)) continue; @@ -435,7 +435,7 @@ static int cs_etm_recording_options(struct auxtrace_record *itr, * Also the case of per-cpu mmaps, need the contextID in order to be notified * when a context switch happened. */ - if (!perf_cpu_map__empty(cpus)) { + if (!perf_cpu_map__has_any_cpu_or_is_empty(cpus)) { evsel__set_config_if_unset(cs_etm_pmu, cs_etm_evsel, "timestamp", 1); evsel__set_config_if_unset(cs_etm_pmu, cs_etm_evsel, @@ -461,7 +461,7 @@ static int cs_etm_recording_options(struct auxtrace_record *itr, evsel->core.attr.sample_period = 1; /* In per-cpu case, always need the time of mmap events etc */ - if (!perf_cpu_map__empty(cpus)) + if (!perf_cpu_map__has_any_cpu_or_is_empty(cpus)) evsel__set_sample_bit(evsel, TIME); err = cs_etm_validate_config(itr, cs_etm_evsel); @@ -536,10 +536,10 @@ cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused, int i; int etmv3 = 0, etmv4 = 0, ete = 0; struct perf_cpu_map *event_cpus = evlist->core.user_requested_cpus; - struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL); + struct perf_cpu_map *online_cpus = perf_cpu_map__new_online_cpus(); /* cpu map is not empty, we have specific CPUs to work with */ - if (!perf_cpu_map__empty(event_cpus)) { + if (!perf_cpu_map__has_any_cpu_or_is_empty(event_cpus)) { for (i = 0; i < cpu__max_cpu().cpu; i++) { struct perf_cpu cpu = { .cpu = i, }; @@ -802,7 +802,7 @@ static int cs_etm_info_fill(struct auxtrace_record *itr, u64 nr_cpu, type; struct perf_cpu_map *cpu_map; struct perf_cpu_map *event_cpus = session->evlist->core.user_requested_cpus; - struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL); + struct perf_cpu_map *online_cpus = perf_cpu_map__new_online_cpus(); struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr); struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; @@ -814,7 +814,7 @@ static int cs_etm_info_fill(struct auxtrace_record *itr, return -EINVAL; /* If the cpu_map is empty all online CPUs are involved */ - if (perf_cpu_map__empty(event_cpus)) { + if (perf_cpu_map__has_any_cpu_or_is_empty(event_cpus)) { cpu_map = online_cpus; } else { /* Make sure all specified CPUs are online */ diff --git a/tools/perf/arch/arm64/util/arm-spe.c b/tools/perf/arch/arm64/util/arm-spe.c index e3acc739bd..51ccbfd3d2 100644 --- a/tools/perf/arch/arm64/util/arm-spe.c +++ b/tools/perf/arch/arm64/util/arm-spe.c @@ -232,7 +232,7 @@ static int arm_spe_recording_options(struct auxtrace_record *itr, * In the case of per-cpu mmaps, sample CPU for AUX event; * also enable the timestamp tracing for samples correlation. */ - if (!perf_cpu_map__empty(cpus)) { + if (!perf_cpu_map__has_any_cpu_or_is_empty(cpus)) { evsel__set_sample_bit(arm_spe_evsel, CPU); evsel__set_config_if_unset(arm_spe_pmu, arm_spe_evsel, "ts_enable", 1); @@ -265,7 +265,7 @@ static int arm_spe_recording_options(struct auxtrace_record *itr, tracking_evsel->core.attr.sample_period = 1; /* In per-cpu case, always need the time of mmap events etc */ - if (!perf_cpu_map__empty(cpus)) { + if (!perf_cpu_map__has_any_cpu_or_is_empty(cpus)) { evsel__set_sample_bit(tracking_evsel, TIME); evsel__set_sample_bit(tracking_evsel, CPU); diff --git a/tools/perf/arch/arm64/util/header.c b/tools/perf/arch/arm64/util/header.c index a2eef9ec54..9703749915 100644 --- a/tools/perf/arch/arm64/util/header.c +++ b/tools/perf/arch/arm64/util/header.c @@ -57,7 +57,7 @@ static int _get_cpuid(char *buf, size_t sz, struct perf_cpu_map *cpus) int get_cpuid(char *buf, size_t sz) { - struct perf_cpu_map *cpus = perf_cpu_map__new(NULL); + struct perf_cpu_map *cpus = perf_cpu_map__new_online_cpus(); int ret; if (!cpus) diff --git a/tools/perf/arch/loongarch/annotate/instructions.c b/tools/perf/arch/loongarch/annotate/instructions.c index 98e19c5366..21cc7e4149 100644 --- a/tools/perf/arch/loongarch/annotate/instructions.c +++ b/tools/perf/arch/loongarch/annotate/instructions.c @@ -61,10 +61,10 @@ static int loongarch_jump__parse(struct arch *arch, struct ins_operands *ops, st const char *c = strchr(ops->raw, '#'); u64 start, end; - ops->raw_comment = strchr(ops->raw, arch->objdump.comment_char); - ops->raw_func_start = strchr(ops->raw, '<'); + ops->jump.raw_comment = strchr(ops->raw, arch->objdump.comment_char); + ops->jump.raw_func_start = strchr(ops->raw, '<'); - if (ops->raw_func_start && c > ops->raw_func_start) + if (ops->jump.raw_func_start && c > ops->jump.raw_func_start) c = NULL; if (c++ != NULL) diff --git a/tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl b/tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl index 116ff501bf..532b855df5 100644 --- a/tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl +++ b/tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl @@ -371,3 +371,8 @@ 454 n64 futex_wake sys_futex_wake 455 n64 futex_wait sys_futex_wait 456 n64 futex_requeue sys_futex_requeue +457 n64 statmount sys_statmount +458 n64 listmount sys_listmount +459 n64 lsm_get_self_attr sys_lsm_get_self_attr +460 n64 lsm_set_self_attr sys_lsm_set_self_attr +461 n64 lsm_list_modules sys_lsm_list_modules diff --git a/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl b/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl index 7fab411378..17173b82ca 100644 --- a/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl +++ b/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl @@ -543,3 +543,8 @@ 454 common futex_wake sys_futex_wake 455 common futex_wait sys_futex_wait 456 common futex_requeue sys_futex_requeue +457 common statmount sys_statmount +458 common listmount sys_listmount +459 common lsm_get_self_attr sys_lsm_get_self_attr +460 common lsm_set_self_attr sys_lsm_set_self_attr +461 common lsm_list_modules sys_lsm_list_modules diff --git a/tools/perf/arch/s390/entry/syscalls/syscall.tbl b/tools/perf/arch/s390/entry/syscalls/syscall.tbl index 86fec9b080..095bb86339 100644 --- a/tools/perf/arch/s390/entry/syscalls/syscall.tbl +++ b/tools/perf/arch/s390/entry/syscalls/syscall.tbl @@ -459,3 +459,8 @@ 454 common futex_wake sys_futex_wake sys_futex_wake 455 common futex_wait sys_futex_wait sys_futex_wait 456 common futex_requeue sys_futex_requeue sys_futex_requeue +457 common statmount sys_statmount sys_statmount +458 common listmount sys_listmount sys_listmount +459 common lsm_get_self_attr sys_lsm_get_self_attr sys_lsm_get_self_attr +460 common lsm_set_self_attr sys_lsm_set_self_attr sys_lsm_set_self_attr +461 common lsm_list_modules sys_lsm_list_modules sys_lsm_list_modules diff --git a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl index 8cb8bf6872..7e8d46f414 100644 --- a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl +++ b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl @@ -378,6 +378,11 @@ 454 common futex_wake sys_futex_wake 455 common futex_wait sys_futex_wait 456 common futex_requeue sys_futex_requeue +457 common statmount sys_statmount +458 common listmount sys_listmount +459 common lsm_get_self_attr sys_lsm_get_self_attr +460 common lsm_set_self_attr sys_lsm_set_self_attr +461 common lsm_list_modules sys_lsm_list_modules # # Due to a historical design error, certain syscalls are numbered differently diff --git a/tools/perf/arch/x86/tests/hybrid.c b/tools/perf/arch/x86/tests/hybrid.c index eb152770f1..40f5d17fed 100644 --- a/tools/perf/arch/x86/tests/hybrid.c +++ b/tools/perf/arch/x86/tests/hybrid.c @@ -47,7 +47,7 @@ static int test__hybrid_hw_group_event(struct evlist *evlist) evsel = evsel__next(evsel); TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW)); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_INSTRUCTIONS)); + TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_BRANCH_INSTRUCTIONS)); TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); return TEST_OK; } @@ -102,7 +102,7 @@ static int test__hybrid_group_modifier1(struct evlist *evlist) evsel = evsel__next(evsel); TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW)); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_INSTRUCTIONS)); + TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_BRANCH_INSTRUCTIONS)); TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); @@ -163,6 +163,24 @@ static int test__checkevent_pmu(struct evlist *evlist) return TEST_OK; } +static int test__hybrid_hw_group_event_2(struct evlist *evlist) +{ + struct evsel *evsel, *leader; + + evsel = leader = evlist__first(evlist); + TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); + TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW)); + TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); + + evsel = evsel__next(evsel); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); + TEST_ASSERT_VAL("wrong config", evsel->core.attr.config == 0x3c); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); + return TEST_OK; +} + struct evlist_test { const char *name; bool (*valid)(void); @@ -171,27 +189,27 @@ struct evlist_test { static const struct evlist_test test__hybrid_events[] = { { - .name = "cpu_core/cpu-cycles/", + .name = "cpu_core/cycles/", .check = test__hybrid_hw_event_with_pmu, /* 0 */ }, { - .name = "{cpu_core/cpu-cycles/,cpu_core/instructions/}", + .name = "{cpu_core/cycles/,cpu_core/branches/}", .check = test__hybrid_hw_group_event, /* 1 */ }, { - .name = "{cpu-clock,cpu_core/cpu-cycles/}", + .name = "{cpu-clock,cpu_core/cycles/}", .check = test__hybrid_sw_hw_group_event, /* 2 */ }, { - .name = "{cpu_core/cpu-cycles/,cpu-clock}", + .name = "{cpu_core/cycles/,cpu-clock}", .check = test__hybrid_hw_sw_group_event, /* 3 */ }, { - .name = "{cpu_core/cpu-cycles/k,cpu_core/instructions/u}", + .name = "{cpu_core/cycles/k,cpu_core/branches/u}", .check = test__hybrid_group_modifier1, /* 4 */ }, @@ -215,6 +233,11 @@ static const struct evlist_test test__hybrid_events[] = { .check = test__hybrid_cache_event, /* 8 */ }, + { + .name = "{cpu_core/cycles/,cpu_core/cpu-cycles/}", + .check = test__hybrid_hw_group_event_2, + /* 9 */ + }, }; static int test_event(const struct evlist_test *e) diff --git a/tools/perf/arch/x86/util/dwarf-regs.c b/tools/perf/arch/x86/util/dwarf-regs.c index 5309348057..399c4a0a29 100644 --- a/tools/perf/arch/x86/util/dwarf-regs.c +++ b/tools/perf/arch/x86/util/dwarf-regs.c @@ -113,3 +113,41 @@ int regs_query_register_offset(const char *name) return roff->offset; return -EINVAL; } + +struct dwarf_regs_idx { + const char *name; + int idx; +}; + +static const struct dwarf_regs_idx x86_regidx_table[] = { + { "rax", 0 }, { "eax", 0 }, { "ax", 0 }, { "al", 0 }, + { "rdx", 1 }, { "edx", 1 }, { "dx", 1 }, { "dl", 1 }, + { "rcx", 2 }, { "ecx", 2 }, { "cx", 2 }, { "cl", 2 }, + { "rbx", 3 }, { "edx", 3 }, { "bx", 3 }, { "bl", 3 }, + { "rsi", 4 }, { "esi", 4 }, { "si", 4 }, { "sil", 4 }, + { "rdi", 5 }, { "edi", 5 }, { "di", 5 }, { "dil", 5 }, + { "rbp", 6 }, { "ebp", 6 }, { "bp", 6 }, { "bpl", 6 }, + { "rsp", 7 }, { "esp", 7 }, { "sp", 7 }, { "spl", 7 }, + { "r8", 8 }, { "r8d", 8 }, { "r8w", 8 }, { "r8b", 8 }, + { "r9", 9 }, { "r9d", 9 }, { "r9w", 9 }, { "r9b", 9 }, + { "r10", 10 }, { "r10d", 10 }, { "r10w", 10 }, { "r10b", 10 }, + { "r11", 11 }, { "r11d", 11 }, { "r11w", 11 }, { "r11b", 11 }, + { "r12", 12 }, { "r12d", 12 }, { "r12w", 12 }, { "r12b", 12 }, + { "r13", 13 }, { "r13d", 13 }, { "r13w", 13 }, { "r13b", 13 }, + { "r14", 14 }, { "r14d", 14 }, { "r14w", 14 }, { "r14b", 14 }, + { "r15", 15 }, { "r15d", 15 }, { "r15w", 15 }, { "r15b", 15 }, + { "rip", DWARF_REG_PC }, +}; + +int get_arch_regnum(const char *name) +{ + unsigned int i; + + if (*name != '%') + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(x86_regidx_table); i++) + if (!strcmp(x86_regidx_table[i].name, name + 1)) + return x86_regidx_table[i].idx; + return -ENOENT; +} diff --git a/tools/perf/arch/x86/util/event.c b/tools/perf/arch/x86/util/event.c index 5741ffe473..e65b7dbe27 100644 --- a/tools/perf/arch/x86/util/event.c +++ b/tools/perf/arch/x86/util/event.c @@ -14,66 +14,79 @@ #if defined(__x86_64__) -int perf_event__synthesize_extra_kmaps(struct perf_tool *tool, - perf_event__handler_t process, - struct machine *machine) +struct perf_event__synthesize_extra_kmaps_cb_args { + struct perf_tool *tool; + perf_event__handler_t process; + struct machine *machine; + union perf_event *event; +}; + +static int perf_event__synthesize_extra_kmaps_cb(struct map *map, void *data) { - int rc = 0; - struct map_rb_node *pos; - struct maps *kmaps = machine__kernel_maps(machine); - union perf_event *event = zalloc(sizeof(event->mmap) + - machine->id_hdr_size); + struct perf_event__synthesize_extra_kmaps_cb_args *args = data; + union perf_event *event = args->event; + struct kmap *kmap; + size_t size; - if (!event) { - pr_debug("Not enough memory synthesizing mmap event " - "for extra kernel maps\n"); - return -1; - } + if (!__map__is_extra_kernel_map(map)) + return 0; - maps__for_each_entry(kmaps, pos) { - struct kmap *kmap; - size_t size; - struct map *map = pos->map; + kmap = map__kmap(map); - if (!__map__is_extra_kernel_map(map)) - continue; + size = sizeof(event->mmap) - sizeof(event->mmap.filename) + + PERF_ALIGN(strlen(kmap->name) + 1, sizeof(u64)) + + args->machine->id_hdr_size; - kmap = map__kmap(map); + memset(event, 0, size); - size = sizeof(event->mmap) - sizeof(event->mmap.filename) + - PERF_ALIGN(strlen(kmap->name) + 1, sizeof(u64)) + - machine->id_hdr_size; + event->mmap.header.type = PERF_RECORD_MMAP; - memset(event, 0, size); + /* + * kernel uses 0 for user space maps, see kernel/perf_event.c + * __perf_event_mmap + */ + if (machine__is_host(args->machine)) + event->header.misc = PERF_RECORD_MISC_KERNEL; + else + event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; - event->mmap.header.type = PERF_RECORD_MMAP; + event->mmap.header.size = size; - /* - * kernel uses 0 for user space maps, see kernel/perf_event.c - * __perf_event_mmap - */ - if (machine__is_host(machine)) - event->header.misc = PERF_RECORD_MISC_KERNEL; - else - event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; + event->mmap.start = map__start(map); + event->mmap.len = map__size(map); + event->mmap.pgoff = map__pgoff(map); + event->mmap.pid = args->machine->pid; - event->mmap.header.size = size; + strlcpy(event->mmap.filename, kmap->name, PATH_MAX); - event->mmap.start = map__start(map); - event->mmap.len = map__size(map); - event->mmap.pgoff = map__pgoff(map); - event->mmap.pid = machine->pid; + if (perf_tool__process_synth_event(args->tool, event, args->machine, args->process) != 0) + return -1; - strlcpy(event->mmap.filename, kmap->name, PATH_MAX); + return 0; +} - if (perf_tool__process_synth_event(tool, event, machine, - process) != 0) { - rc = -1; - break; - } +int perf_event__synthesize_extra_kmaps(struct perf_tool *tool, + perf_event__handler_t process, + struct machine *machine) +{ + int rc; + struct maps *kmaps = machine__kernel_maps(machine); + struct perf_event__synthesize_extra_kmaps_cb_args args = { + .tool = tool, + .process = process, + .machine = machine, + .event = zalloc(sizeof(args.event->mmap) + machine->id_hdr_size), + }; + + if (!args.event) { + pr_debug("Not enough memory synthesizing mmap event " + "for extra kernel maps\n"); + return -1; } - free(event); + rc = maps__for_each_map(kmaps, perf_event__synthesize_extra_kmaps_cb, &args); + + free(args.event); return rc; } diff --git a/tools/perf/arch/x86/util/intel-bts.c b/tools/perf/arch/x86/util/intel-bts.c index d2c8cac114..af8ae46475 100644 --- a/tools/perf/arch/x86/util/intel-bts.c +++ b/tools/perf/arch/x86/util/intel-bts.c @@ -143,7 +143,7 @@ static int intel_bts_recording_options(struct auxtrace_record *itr, if (!opts->full_auxtrace) return 0; - if (opts->full_auxtrace && !perf_cpu_map__empty(cpus)) { + if (opts->full_auxtrace && !perf_cpu_map__has_any_cpu_or_is_empty(cpus)) { pr_err(INTEL_BTS_PMU_NAME " does not support per-cpu recording\n"); return -EINVAL; } @@ -224,7 +224,7 @@ static int intel_bts_recording_options(struct auxtrace_record *itr, * In the case of per-cpu mmaps, we need the CPU on the * AUX event. */ - if (!perf_cpu_map__empty(cpus)) + if (!perf_cpu_map__has_any_cpu_or_is_empty(cpus)) evsel__set_sample_bit(intel_bts_evsel, CPU); } diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c index fa0c718b9e..d199619df3 100644 --- a/tools/perf/arch/x86/util/intel-pt.c +++ b/tools/perf/arch/x86/util/intel-pt.c @@ -369,7 +369,7 @@ static int intel_pt_info_fill(struct auxtrace_record *itr, ui__warning("Intel Processor Trace: TSC not available\n"); } - per_cpu_mmaps = !perf_cpu_map__empty(session->evlist->core.user_requested_cpus); + per_cpu_mmaps = !perf_cpu_map__has_any_cpu_or_is_empty(session->evlist->core.user_requested_cpus); auxtrace_info->type = PERF_AUXTRACE_INTEL_PT; auxtrace_info->priv[INTEL_PT_PMU_TYPE] = intel_pt_pmu->type; @@ -774,7 +774,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, * Per-cpu recording needs sched_switch events to distinguish different * threads. */ - if (have_timing_info && !perf_cpu_map__empty(cpus) && + if (have_timing_info && !perf_cpu_map__has_any_cpu_or_is_empty(cpus) && !record_opts__no_switch_events(opts)) { if (perf_can_record_switch_events()) { bool cpu_wide = !target__none(&opts->target) && @@ -832,7 +832,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, * In the case of per-cpu mmaps, we need the CPU on the * AUX event. */ - if (!perf_cpu_map__empty(cpus)) + if (!perf_cpu_map__has_any_cpu_or_is_empty(cpus)) evsel__set_sample_bit(intel_pt_evsel, CPU); } @@ -858,7 +858,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, tracking_evsel->immediate = true; /* In per-cpu case, always need the time of mmap events etc */ - if (!perf_cpu_map__empty(cpus)) { + if (!perf_cpu_map__has_any_cpu_or_is_empty(cpus)) { evsel__set_sample_bit(tracking_evsel, TIME); /* And the CPU for switch events */ evsel__set_sample_bit(tracking_evsel, CPU); @@ -870,7 +870,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, * Warn the user when we do not have enough information to decode i.e. * per-cpu with no sched_switch (except workload-only). */ - if (!ptr->have_sched_switch && !perf_cpu_map__empty(cpus) && + if (!ptr->have_sched_switch && !perf_cpu_map__has_any_cpu_or_is_empty(cpus) && !target__none(&opts->target) && !intel_pt_evsel->core.attr.exclude_user) ui__warning("Intel Processor Trace decoding will not be possible except for kernel tracing!\n"); diff --git a/tools/perf/bench/epoll-ctl.c b/tools/perf/bench/epoll-ctl.c index 6bfffe83dd..d3db73dac6 100644 --- a/tools/perf/bench/epoll-ctl.c +++ b/tools/perf/bench/epoll-ctl.c @@ -330,7 +330,7 @@ int bench_epoll_ctl(int argc, const char **argv) act.sa_sigaction = toggle_done; sigaction(SIGINT, &act, NULL); - cpu = perf_cpu_map__new(NULL); + cpu = perf_cpu_map__new_online_cpus(); if (!cpu) goto errmem; diff --git a/tools/perf/bench/epoll-wait.c b/tools/perf/bench/epoll-wait.c index cb5174b539..06bb318766 100644 --- a/tools/perf/bench/epoll-wait.c +++ b/tools/perf/bench/epoll-wait.c @@ -444,7 +444,7 @@ int bench_epoll_wait(int argc, const char **argv) act.sa_sigaction = toggle_done; sigaction(SIGINT, &act, NULL); - cpu = perf_cpu_map__new(NULL); + cpu = perf_cpu_map__new_online_cpus(); if (!cpu) goto errmem; diff --git a/tools/perf/bench/futex-hash.c b/tools/perf/bench/futex-hash.c index 2005a3fa30..0c69d20efa 100644 --- a/tools/perf/bench/futex-hash.c +++ b/tools/perf/bench/futex-hash.c @@ -138,7 +138,7 @@ int bench_futex_hash(int argc, const char **argv) exit(EXIT_FAILURE); } - cpu = perf_cpu_map__new(NULL); + cpu = perf_cpu_map__new_online_cpus(); if (!cpu) goto errmem; diff --git a/tools/perf/bench/futex-lock-pi.c b/tools/perf/bench/futex-lock-pi.c index 092cbd52db..7a49733461 100644 --- a/tools/perf/bench/futex-lock-pi.c +++ b/tools/perf/bench/futex-lock-pi.c @@ -172,7 +172,7 @@ int bench_futex_lock_pi(int argc, const char **argv) if (argc) goto err; - cpu = perf_cpu_map__new(NULL); + cpu = perf_cpu_map__new_online_cpus(); if (!cpu) err(EXIT_FAILURE, "calloc"); diff --git a/tools/perf/bench/futex-requeue.c b/tools/perf/bench/futex-requeue.c index c0035990a3..d9ad736c1a 100644 --- a/tools/perf/bench/futex-requeue.c +++ b/tools/perf/bench/futex-requeue.c @@ -174,7 +174,7 @@ int bench_futex_requeue(int argc, const char **argv) if (argc) goto err; - cpu = perf_cpu_map__new(NULL); + cpu = perf_cpu_map__new_online_cpus(); if (!cpu) err(EXIT_FAILURE, "cpu_map__new"); diff --git a/tools/perf/bench/futex-wake-parallel.c b/tools/perf/bench/futex-wake-parallel.c index 5ab0234d74..b66df553e5 100644 --- a/tools/perf/bench/futex-wake-parallel.c +++ b/tools/perf/bench/futex-wake-parallel.c @@ -264,7 +264,7 @@ int bench_futex_wake_parallel(int argc, const char **argv) err(EXIT_FAILURE, "mlockall"); } - cpu = perf_cpu_map__new(NULL); + cpu = perf_cpu_map__new_online_cpus(); if (!cpu) err(EXIT_FAILURE, "calloc"); diff --git a/tools/perf/bench/futex-wake.c b/tools/perf/bench/futex-wake.c index 18a5894af8..690fd6d3da 100644 --- a/tools/perf/bench/futex-wake.c +++ b/tools/perf/bench/futex-wake.c @@ -149,7 +149,7 @@ int bench_futex_wake(int argc, const char **argv) exit(EXIT_FAILURE); } - cpu = perf_cpu_map__new(NULL); + cpu = perf_cpu_map__new_online_cpus(); if (!cpu) err(EXIT_FAILURE, "calloc"); diff --git a/tools/perf/bench/sched-seccomp-notify.c b/tools/perf/bench/sched-seccomp-notify.c index a01c401314..269c1f4a68 100644 --- a/tools/perf/bench/sched-seccomp-notify.c +++ b/tools/perf/bench/sched-seccomp-notify.c @@ -32,7 +32,7 @@ static bool sync_mode; static const struct option options[] = { OPT_U64('l', "loop", &loops, "Specify number of loops"), OPT_BOOLEAN('s', "sync-mode", &sync_mode, - "Enable the synchronious mode for seccomp notifications"), + "Enable the synchronous mode for seccomp notifications"), OPT_END() }; diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index aeeb801f1e..6c1cc79769 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -20,6 +20,7 @@ #include "util/evlist.h" #include "util/evsel.h" #include "util/annotate.h" +#include "util/annotate-data.h" #include "util/event.h" #include #include "util/parse-events.h" @@ -45,7 +46,6 @@ struct perf_annotate { struct perf_tool tool; struct perf_session *session; - struct annotation_options opts; #ifdef HAVE_SLANG_SUPPORT bool use_tui; #endif @@ -56,9 +56,13 @@ struct perf_annotate { bool skip_missing; bool has_br_stack; bool group_set; + bool data_type; + bool type_stat; + bool insn_stat; float min_percent; const char *sym_hist_filter; const char *cpu_list; + const char *target_data_type; DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); }; @@ -94,6 +98,7 @@ static void process_basic_block(struct addr_map_symbol *start, struct annotation *notes = sym ? symbol__annotation(sym) : NULL; struct block_range_iter iter; struct block_range *entry; + struct annotated_branch *branch; /* * Sanity; NULL isn't executable and the CPU cannot execute backwards @@ -105,6 +110,8 @@ static void process_basic_block(struct addr_map_symbol *start, if (!block_range_iter__valid(&iter)) return; + branch = annotation__get_branch(notes); + /* * First block in range is a branch target. */ @@ -118,8 +125,8 @@ static void process_basic_block(struct addr_map_symbol *start, entry->coverage++; entry->sym = sym; - if (notes) - notes->max_coverage = max(notes->max_coverage, entry->coverage); + if (branch) + branch->max_coverage = max(branch->max_coverage, entry->coverage); } while (block_range_iter__next(&iter)); @@ -315,9 +322,153 @@ static int hist_entry__tty_annotate(struct hist_entry *he, struct perf_annotate *ann) { if (!ann->use_stdio2) - return symbol__tty_annotate(&he->ms, evsel, &ann->opts); + return symbol__tty_annotate(&he->ms, evsel); + + return symbol__tty_annotate2(&he->ms, evsel); +} + +static void print_annotated_data_header(struct hist_entry *he, struct evsel *evsel) +{ + struct dso *dso = map__dso(he->ms.map); + int nr_members = 1; + int nr_samples = he->stat.nr_events; + + if (evsel__is_group_event(evsel)) { + struct hist_entry *pair; + + list_for_each_entry(pair, &he->pairs.head, pairs.node) + nr_samples += pair->stat.nr_events; + } + + printf("Annotate type: '%s' in %s (%d samples):\n", + he->mem_type->self.type_name, dso->name, nr_samples); + + if (evsel__is_group_event(evsel)) { + struct evsel *pos; + int i = 0; + + for_each_group_evsel(pos, evsel) + printf(" event[%d] = %s\n", i++, pos->name); + + nr_members = evsel->core.nr_members; + } + + printf("============================================================================\n"); + printf("%*s %10s %10s %s\n", 11 * nr_members, "samples", "offset", "size", "field"); +} + +static void print_annotated_data_type(struct annotated_data_type *mem_type, + struct annotated_member *member, + struct evsel *evsel, int indent) +{ + struct annotated_member *child; + struct type_hist *h = mem_type->histograms[evsel->core.idx]; + int i, nr_events = 1, samples = 0; + + for (i = 0; i < member->size; i++) + samples += h->addr[member->offset + i].nr_samples; + printf(" %10d", samples); - return symbol__tty_annotate2(&he->ms, evsel, &ann->opts); + if (evsel__is_group_event(evsel)) { + struct evsel *pos; + + for_each_group_member(pos, evsel) { + h = mem_type->histograms[pos->core.idx]; + + samples = 0; + for (i = 0; i < member->size; i++) + samples += h->addr[member->offset + i].nr_samples; + printf(" %10d", samples); + } + nr_events = evsel->core.nr_members; + } + + printf(" %10d %10d %*s%s\t%s", + member->offset, member->size, indent, "", member->type_name, + member->var_name ?: ""); + + if (!list_empty(&member->children)) + printf(" {\n"); + + list_for_each_entry(child, &member->children, node) + print_annotated_data_type(mem_type, child, evsel, indent + 4); + + if (!list_empty(&member->children)) + printf("%*s}", 11 * nr_events + 24 + indent, ""); + printf(";\n"); +} + +static void print_annotate_data_stat(struct annotated_data_stat *s) +{ +#define PRINT_STAT(fld) if (s->fld) printf("%10d : %s\n", s->fld, #fld) + + int bad = s->no_sym + + s->no_insn + + s->no_insn_ops + + s->no_mem_ops + + s->no_reg + + s->no_dbginfo + + s->no_cuinfo + + s->no_var + + s->no_typeinfo + + s->invalid_size + + s->bad_offset; + int ok = s->total - bad; + + printf("Annotate data type stats:\n"); + printf("total %d, ok %d (%.1f%%), bad %d (%.1f%%)\n", + s->total, ok, 100.0 * ok / (s->total ?: 1), bad, 100.0 * bad / (s->total ?: 1)); + printf("-----------------------------------------------------------\n"); + PRINT_STAT(no_sym); + PRINT_STAT(no_insn); + PRINT_STAT(no_insn_ops); + PRINT_STAT(no_mem_ops); + PRINT_STAT(no_reg); + PRINT_STAT(no_dbginfo); + PRINT_STAT(no_cuinfo); + PRINT_STAT(no_var); + PRINT_STAT(no_typeinfo); + PRINT_STAT(invalid_size); + PRINT_STAT(bad_offset); + printf("\n"); + +#undef PRINT_STAT +} + +static void print_annotate_item_stat(struct list_head *head, const char *title) +{ + struct annotated_item_stat *istat, *pos, *iter; + int total_good, total_bad, total; + int sum1, sum2; + LIST_HEAD(tmp); + + /* sort the list by count */ + list_splice_init(head, &tmp); + total_good = total_bad = 0; + + list_for_each_entry_safe(istat, pos, &tmp, list) { + total_good += istat->good; + total_bad += istat->bad; + sum1 = istat->good + istat->bad; + + list_for_each_entry(iter, head, list) { + sum2 = iter->good + iter->bad; + if (sum1 > sum2) + break; + } + list_move_tail(&istat->list, &iter->list); + } + total = total_good + total_bad; + + printf("Annotate %s stats\n", title); + printf("total %d, ok %d (%.1f%%), bad %d (%.1f%%)\n\n", total, + total_good, 100.0 * total_good / (total ?: 1), + total_bad, 100.0 * total_bad / (total ?: 1)); + printf(" %-10s: %5s %5s\n", "Name", "Good", "Bad"); + printf("-----------------------------------------------------------\n"); + list_for_each_entry(istat, head, list) + printf(" %-10s: %5d %5d\n", istat->name, istat->good, istat->bad); + printf("\n"); } static void hists__find_annotations(struct hists *hists, @@ -327,6 +478,11 @@ static void hists__find_annotations(struct hists *hists, struct rb_node *nd = rb_first_cached(&hists->entries), *next; int key = K_RIGHT; + if (ann->type_stat) + print_annotate_data_stat(&ann_data_stat); + if (ann->insn_stat) + print_annotate_item_stat(&ann_insn_stat, "Instruction"); + while (nd) { struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); struct annotation *notes; @@ -359,11 +515,38 @@ find_next: continue; } + if (ann->data_type) { + /* skip unknown type */ + if (he->mem_type->histograms == NULL) + goto find_next; + + if (ann->target_data_type) { + const char *type_name = he->mem_type->self.type_name; + + /* skip 'struct ' prefix in the type name */ + if (strncmp(ann->target_data_type, "struct ", 7) && + !strncmp(type_name, "struct ", 7)) + type_name += 7; + + /* skip 'union ' prefix in the type name */ + if (strncmp(ann->target_data_type, "union ", 6) && + !strncmp(type_name, "union ", 6)) + type_name += 6; + + if (strcmp(ann->target_data_type, type_name)) + goto find_next; + } + + print_annotated_data_header(he, evsel); + print_annotated_data_type(he->mem_type, &he->mem_type->self, evsel, 0); + printf("\n"); + goto find_next; + } + if (use_browser == 2) { int ret; int (*annotate)(struct hist_entry *he, struct evsel *evsel, - struct annotation_options *options, struct hist_browser_timer *hbt); annotate = dlsym(perf_gtk_handle, @@ -373,14 +556,14 @@ find_next: return; } - ret = annotate(he, evsel, &ann->opts, NULL); + ret = annotate(he, evsel, NULL); if (!ret || !ann->skip_missing) return; /* skip missing symbols */ nd = rb_next(nd); } else if (use_browser == 1) { - key = hist_entry__tui_annotate(he, evsel, NULL, &ann->opts); + key = hist_entry__tui_annotate(he, evsel, NULL); switch (key) { case -1: @@ -422,9 +605,9 @@ static int __cmd_annotate(struct perf_annotate *ann) goto out; } - if (!ann->opts.objdump_path) { + if (!annotate_opts.objdump_path) { ret = perf_env__lookup_objdump(&session->header.env, - &ann->opts.objdump_path); + &annotate_opts.objdump_path); if (ret) goto out; } @@ -457,8 +640,20 @@ static int __cmd_annotate(struct perf_annotate *ann) evsel__reset_sample_bit(pos, CALLCHAIN); evsel__output_resort(pos, NULL); - if (symbol_conf.event_group && !evsel__is_group_leader(pos)) + /* + * An event group needs to display other events too. + * Let's delay printing until other events are processed. + */ + if (symbol_conf.event_group) { + if (!evsel__is_group_leader(pos)) { + struct hists *leader_hists; + + leader_hists = evsel__hists(evsel__leader(pos)); + hists__match(leader_hists, hists); + hists__link(leader_hists, hists); + } continue; + } hists__find_annotations(hists, pos, ann); } @@ -469,6 +664,20 @@ static int __cmd_annotate(struct perf_annotate *ann) goto out; } + /* Display group events together */ + evlist__for_each_entry(session->evlist, pos) { + struct hists *hists = evsel__hists(pos); + u32 nr_samples = hists->stats.nr_samples; + + if (nr_samples == 0) + continue; + + if (!symbol_conf.event_group || !evsel__is_group_leader(pos)) + continue; + + hists__find_annotations(hists, pos, ann); + } + if (use_browser == 2) { void (*show_annotations)(void); @@ -495,6 +704,17 @@ static int parse_percent_limit(const struct option *opt, const char *str, return 0; } +static int parse_data_type(const struct option *opt, const char *str, int unset) +{ + struct perf_annotate *ann = opt->value; + + ann->data_type = !unset; + if (str) + ann->target_data_type = strdup(str); + + return 0; +} + static const char * const annotate_usage[] = { "perf annotate []", NULL @@ -558,9 +778,9 @@ int cmd_annotate(int argc, const char **argv) "file", "vmlinux pathname"), OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, "load module symbols - WARNING: use only with -k and LIVE kernel"), - OPT_BOOLEAN('l', "print-line", &annotate.opts.print_lines, + OPT_BOOLEAN('l', "print-line", &annotate_opts.print_lines, "print matching source lines (may be slow)"), - OPT_BOOLEAN('P', "full-paths", &annotate.opts.full_path, + OPT_BOOLEAN('P', "full-paths", &annotate_opts.full_path, "Don't shorten the displayed pathnames"), OPT_BOOLEAN(0, "skip-missing", &annotate.skip_missing, "Skip symbols that cannot be annotated"), @@ -571,15 +791,15 @@ int cmd_annotate(int argc, const char **argv) OPT_CALLBACK(0, "symfs", NULL, "directory", "Look for files with symbols relative to this directory", symbol__config_symfs), - OPT_BOOLEAN(0, "source", &annotate.opts.annotate_src, + OPT_BOOLEAN(0, "source", &annotate_opts.annotate_src, "Interleave source code with assembly code (default)"), - OPT_BOOLEAN(0, "asm-raw", &annotate.opts.show_asm_raw, + OPT_BOOLEAN(0, "asm-raw", &annotate_opts.show_asm_raw, "Display raw encoding of assembly instructions (default)"), OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", "Specify disassembler style (e.g. -M intel for intel syntax)"), - OPT_STRING(0, "prefix", &annotate.opts.prefix, "prefix", + OPT_STRING(0, "prefix", &annotate_opts.prefix, "prefix", "Add prefix to source file path names in programs (with --prefix-strip)"), - OPT_STRING(0, "prefix-strip", &annotate.opts.prefix_strip, "N", + OPT_STRING(0, "prefix-strip", &annotate_opts.prefix_strip, "N", "Strip first N entries of source file path name in programs (with --prefix)"), OPT_STRING(0, "objdump", &objdump_path, "path", "objdump binary to use for disassembly and annotations"), @@ -598,7 +818,7 @@ 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", + OPT_CALLBACK(0, "percent-type", &annotate_opts, "local-period", "Set percent type local/global-period/hits", annotate_parse_percent_type), OPT_CALLBACK(0, "percent-limit", &annotate, "percent", @@ -606,7 +826,13 @@ int cmd_annotate(int argc, const char **argv) OPT_CALLBACK_OPTARG(0, "itrace", &itrace_synth_opts, NULL, "opts", "Instruction Tracing options\n" ITRACE_HELP, itrace_parse_synth_opts), - + OPT_CALLBACK_OPTARG(0, "data-type", &annotate, NULL, "name", + "Show data type annotate for the memory accesses", + parse_data_type), + OPT_BOOLEAN(0, "type-stat", &annotate.type_stat, + "Show stats for the data type annotation"), + OPT_BOOLEAN(0, "insn-stat", &annotate.insn_stat, + "Show instruction stats for the data type annotation"), OPT_END() }; int ret; @@ -614,13 +840,13 @@ int cmd_annotate(int argc, const char **argv) set_option_flag(options, 0, "show-total-period", PARSE_OPT_EXCLUSIVE); set_option_flag(options, 0, "show-nr-samples", PARSE_OPT_EXCLUSIVE); - annotation_options__init(&annotate.opts); + annotation_options__init(); ret = hists__init(); if (ret < 0) return ret; - annotation_config__init(&annotate.opts); + annotation_config__init(); argc = parse_options(argc, argv, options, annotate_usage, 0); if (argc) { @@ -635,13 +861,13 @@ int cmd_annotate(int argc, const char **argv) } if (disassembler_style) { - annotate.opts.disassembler_style = strdup(disassembler_style); - if (!annotate.opts.disassembler_style) + annotate_opts.disassembler_style = strdup(disassembler_style); + if (!annotate_opts.disassembler_style) return -ENOMEM; } if (objdump_path) { - annotate.opts.objdump_path = strdup(objdump_path); - if (!annotate.opts.objdump_path) + annotate_opts.objdump_path = strdup(objdump_path); + if (!annotate_opts.objdump_path) return -ENOMEM; } if (addr2line_path) { @@ -650,7 +876,7 @@ int cmd_annotate(int argc, const char **argv) return -ENOMEM; } - if (annotate_check_args(&annotate.opts) < 0) + if (annotate_check_args() < 0) return -EINVAL; #ifdef HAVE_GTK2_SUPPORT @@ -660,6 +886,13 @@ int cmd_annotate(int argc, const char **argv) } #endif +#ifndef HAVE_DWARF_GETLOCATIONS_SUPPORT + if (annotate.data_type) { + pr_err("Error: Data type profiling is disabled due to missing DWARF support\n"); + return -ENOTSUP; + } +#endif + ret = symbol__validate_sym_arguments(); if (ret) return ret; @@ -702,6 +935,14 @@ int cmd_annotate(int argc, const char **argv) use_browser = 2; #endif + /* FIXME: only support stdio for now */ + if (annotate.data_type) { + use_browser = 0; + annotate_opts.annotate_src = false; + symbol_conf.annotate_data_member = true; + symbol_conf.annotate_data_sample = true; + } + setup_browser(true); /* @@ -709,7 +950,10 @@ int cmd_annotate(int argc, const char **argv) * symbol, we do not care about the processes in annotate, * set sort order to avoid repeated output. */ - sort_order = "dso,symbol"; + if (annotate.data_type) + sort_order = "dso,type"; + else + sort_order = "dso,symbol"; /* * Set SORT_MODE__BRANCH so that annotate display IPC/Cycle @@ -731,7 +975,7 @@ out_delete: #ifndef NDEBUG perf_session__delete(annotate.session); #endif - annotation_options__exit(&annotate.opts); + annotation_options__exit(); return ret; } diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index a4cf9de7a7..f78eea9e21 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -2320,7 +2320,7 @@ static int setup_nodes(struct perf_session *session) nodes[node] = set; /* empty node, skip */ - if (perf_cpu_map__empty(map)) + if (perf_cpu_map__has_any_cpu_or_is_empty(map)) continue; perf_cpu_map__for_each_cpu(cpu, idx, map) { diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c index ac2e6c75f9..eb30c8eca4 100644 --- a/tools/perf/builtin-ftrace.c +++ b/tools/perf/builtin-ftrace.c @@ -333,7 +333,7 @@ static int set_tracing_func_irqinfo(struct perf_ftrace *ftrace) static int reset_tracing_cpu(void) { - struct perf_cpu_map *cpumap = perf_cpu_map__new(NULL); + struct perf_cpu_map *cpumap = perf_cpu_map__new_online_cpus(); int ret; ret = set_tracing_cpumask(cpumap); diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index c8cf2fdd9c..eb3ef5c24b 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -2265,6 +2265,12 @@ int cmd_inject(int argc, const char **argv) "perf inject []", NULL }; + + if (!inject.itrace_synth_opts.set) { + /* Disable eager loading of kernel symbols that adds overhead to perf inject. */ + symbol_conf.lazy_load_kernel_maps = true; + } + #ifndef HAVE_JITDUMP set_option_nobuild(options, 'j', "jit", "NO_LIBELF=1", true); #endif diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c index 61c2c96cc0..e27a1b1288 100644 --- a/tools/perf/builtin-list.c +++ b/tools/perf/builtin-list.c @@ -30,6 +30,8 @@ * functions. */ struct print_state { + /** @fp: File to write output to. */ + FILE *fp; /** * @pmu_glob: Optionally restrict PMU and metric matching to PMU or * debugfs subsystem name. @@ -66,13 +68,15 @@ static void default_print_start(void *ps) { struct print_state *print_state = ps; - if (!print_state->name_only && pager_in_use()) - printf("\nList of pre-defined events (to be used in -e or -M):\n\n"); + if (!print_state->name_only && pager_in_use()) { + fprintf(print_state->fp, + "\nList of pre-defined events (to be used in -e or -M):\n\n"); + } } static void default_print_end(void *print_state __maybe_unused) {} -static void wordwrap(const char *s, int start, int max, int corr) +static void wordwrap(FILE *fp, const char *s, int start, int max, int corr) { int column = start; int n; @@ -82,10 +86,10 @@ static void wordwrap(const char *s, int start, int max, int corr) int wlen = strcspn(s, " \t\n"); if ((column + wlen >= max && column > start) || saw_newline) { - printf("\n%*s", start, ""); + fprintf(fp, "\n%*s", start, ""); column = start + corr; } - n = printf("%s%.*s", column > start ? " " : "", wlen, s); + n = fprintf(fp, "%s%.*s", column > start ? " " : "", wlen, s); if (n <= 0) break; saw_newline = s[wlen] == '\n'; @@ -104,6 +108,7 @@ static void default_print_event(void *ps, const char *pmu_name, const char *topi { struct print_state *print_state = ps; int pos; + FILE *fp = print_state->fp; if (deprecated && !print_state->deprecated) return; @@ -119,30 +124,30 @@ static void default_print_event(void *ps, const char *pmu_name, const char *topi if (print_state->name_only) { if (event_alias && strlen(event_alias)) - printf("%s ", event_alias); + fprintf(fp, "%s ", event_alias); else - printf("%s ", event_name); + fprintf(fp, "%s ", event_name); return; } if (strcmp(print_state->last_topic, topic ?: "")) { if (topic) - printf("\n%s:\n", topic); + fprintf(fp, "\n%s:\n", topic); zfree(&print_state->last_topic); print_state->last_topic = strdup(topic ?: ""); } if (event_alias && strlen(event_alias)) - pos = printf(" %s OR %s", event_name, event_alias); + pos = fprintf(fp, " %s OR %s", event_name, event_alias); else - pos = printf(" %s", event_name); + pos = fprintf(fp, " %s", event_name); if (!topic && event_type_desc) { for (; pos < 53; pos++) - putchar(' '); - printf("[%s]\n", event_type_desc); + fputc(' ', fp); + fprintf(fp, "[%s]\n", event_type_desc); } else - putchar('\n'); + fputc('\n', fp); if (desc && print_state->desc) { char *desc_with_unit = NULL; @@ -155,22 +160,22 @@ static void default_print_event(void *ps, const char *pmu_name, const char *topi ? "%s. Unit: %s" : "%s Unit: %s", desc, pmu_name); } - printf("%*s", 8, "["); - wordwrap(desc_len > 0 ? desc_with_unit : desc, 8, pager_get_columns(), 0); - printf("]\n"); + fprintf(fp, "%*s", 8, "["); + wordwrap(fp, desc_len > 0 ? desc_with_unit : desc, 8, pager_get_columns(), 0); + fprintf(fp, "]\n"); free(desc_with_unit); } long_desc = long_desc ?: desc; if (long_desc && print_state->long_desc) { - printf("%*s", 8, "["); - wordwrap(long_desc, 8, pager_get_columns(), 0); - printf("]\n"); + fprintf(fp, "%*s", 8, "["); + wordwrap(fp, long_desc, 8, pager_get_columns(), 0); + fprintf(fp, "]\n"); } if (print_state->detailed && encoding_desc) { - printf("%*s", 8, ""); - wordwrap(encoding_desc, 8, pager_get_columns(), 0); - putchar('\n'); + fprintf(fp, "%*s", 8, ""); + wordwrap(fp, encoding_desc, 8, pager_get_columns(), 0); + fputc('\n', fp); } } @@ -184,6 +189,7 @@ static void default_print_metric(void *ps, const char *unit __maybe_unused) { struct print_state *print_state = ps; + FILE *fp = print_state->fp; if (print_state->event_glob && (!print_state->metrics || !name || !strglobmatch(name, print_state->event_glob)) && @@ -192,27 +198,27 @@ static void default_print_metric(void *ps, if (!print_state->name_only && !print_state->last_metricgroups) { if (print_state->metricgroups) { - printf("\nMetric Groups:\n"); + fprintf(fp, "\nMetric Groups:\n"); if (!print_state->metrics) - putchar('\n'); + fputc('\n', fp); } else { - printf("\nMetrics:\n\n"); + fprintf(fp, "\nMetrics:\n\n"); } } if (!print_state->last_metricgroups || strcmp(print_state->last_metricgroups, group ?: "")) { if (group && print_state->metricgroups) { if (print_state->name_only) - printf("%s ", group); + fprintf(fp, "%s ", group); else if (print_state->metrics) { const char *gdesc = describe_metricgroup(group); if (gdesc) - printf("\n%s: [%s]\n", group, gdesc); + fprintf(fp, "\n%s: [%s]\n", group, gdesc); else - printf("\n%s:\n", group); + fprintf(fp, "\n%s:\n", group); } else - printf("%s\n", group); + fprintf(fp, "%s\n", group); } zfree(&print_state->last_metricgroups); print_state->last_metricgroups = strdup(group ?: ""); @@ -223,53 +229,59 @@ static void default_print_metric(void *ps, if (print_state->name_only) { if (print_state->metrics && !strlist__has_entry(print_state->visited_metrics, name)) { - printf("%s ", name); + fprintf(fp, "%s ", name); strlist__add(print_state->visited_metrics, name); } return; } - printf(" %s\n", name); + fprintf(fp, " %s\n", name); if (desc && print_state->desc) { - printf("%*s", 8, "["); - wordwrap(desc, 8, pager_get_columns(), 0); - printf("]\n"); + fprintf(fp, "%*s", 8, "["); + wordwrap(fp, desc, 8, pager_get_columns(), 0); + fprintf(fp, "]\n"); } if (long_desc && print_state->long_desc) { - printf("%*s", 8, "["); - wordwrap(long_desc, 8, pager_get_columns(), 0); - printf("]\n"); + fprintf(fp, "%*s", 8, "["); + wordwrap(fp, long_desc, 8, pager_get_columns(), 0); + fprintf(fp, "]\n"); } if (expr && print_state->detailed) { - printf("%*s", 8, "["); - wordwrap(expr, 8, pager_get_columns(), 0); - printf("]\n"); + fprintf(fp, "%*s", 8, "["); + wordwrap(fp, expr, 8, pager_get_columns(), 0); + fprintf(fp, "]\n"); } if (threshold && print_state->detailed) { - printf("%*s", 8, "["); - wordwrap(threshold, 8, pager_get_columns(), 0); - printf("]\n"); + fprintf(fp, "%*s", 8, "["); + wordwrap(fp, threshold, 8, pager_get_columns(), 0); + fprintf(fp, "]\n"); } } struct json_print_state { + /** @fp: File to write output to. */ + FILE *fp; /** Should a separator be printed prior to the next item? */ bool need_sep; }; -static void json_print_start(void *print_state __maybe_unused) +static void json_print_start(void *ps) { - printf("[\n"); + struct json_print_state *print_state = ps; + FILE *fp = print_state->fp; + + fprintf(fp, "[\n"); } static void json_print_end(void *ps) { struct json_print_state *print_state = ps; + FILE *fp = print_state->fp; - printf("%s]\n", print_state->need_sep ? "\n" : ""); + fprintf(fp, "%s]\n", print_state->need_sep ? "\n" : ""); } -static void fix_escape_printf(struct strbuf *buf, const char *fmt, ...) +static void fix_escape_fprintf(FILE *fp, struct strbuf *buf, const char *fmt, ...) { va_list args; @@ -318,7 +330,7 @@ static void fix_escape_printf(struct strbuf *buf, const char *fmt, ...) } } va_end(args); - fputs(buf->buf, stdout); + fputs(buf->buf, fp); } static void json_print_event(void *ps, const char *pmu_name, const char *topic, @@ -330,60 +342,71 @@ static void json_print_event(void *ps, const char *pmu_name, const char *topic, { struct json_print_state *print_state = ps; bool need_sep = false; + FILE *fp = print_state->fp; struct strbuf buf; strbuf_init(&buf, 0); - printf("%s{\n", print_state->need_sep ? ",\n" : ""); + fprintf(fp, "%s{\n", print_state->need_sep ? ",\n" : ""); print_state->need_sep = true; if (pmu_name) { - fix_escape_printf(&buf, "\t\"Unit\": \"%S\"", pmu_name); + fix_escape_fprintf(fp, &buf, "\t\"Unit\": \"%S\"", pmu_name); need_sep = true; } if (topic) { - fix_escape_printf(&buf, "%s\t\"Topic\": \"%S\"", need_sep ? ",\n" : "", topic); + fix_escape_fprintf(fp, &buf, "%s\t\"Topic\": \"%S\"", + need_sep ? ",\n" : "", + topic); need_sep = true; } if (event_name) { - fix_escape_printf(&buf, "%s\t\"EventName\": \"%S\"", need_sep ? ",\n" : "", - event_name); + fix_escape_fprintf(fp, &buf, "%s\t\"EventName\": \"%S\"", + need_sep ? ",\n" : "", + event_name); need_sep = true; } if (event_alias && strlen(event_alias)) { - fix_escape_printf(&buf, "%s\t\"EventAlias\": \"%S\"", need_sep ? ",\n" : "", - event_alias); + fix_escape_fprintf(fp, &buf, "%s\t\"EventAlias\": \"%S\"", + need_sep ? ",\n" : "", + event_alias); need_sep = true; } if (scale_unit && strlen(scale_unit)) { - fix_escape_printf(&buf, "%s\t\"ScaleUnit\": \"%S\"", need_sep ? ",\n" : "", - scale_unit); + fix_escape_fprintf(fp, &buf, "%s\t\"ScaleUnit\": \"%S\"", + need_sep ? ",\n" : "", + scale_unit); need_sep = true; } if (event_type_desc) { - fix_escape_printf(&buf, "%s\t\"EventType\": \"%S\"", need_sep ? ",\n" : "", - event_type_desc); + fix_escape_fprintf(fp, &buf, "%s\t\"EventType\": \"%S\"", + need_sep ? ",\n" : "", + event_type_desc); need_sep = true; } if (deprecated) { - fix_escape_printf(&buf, "%s\t\"Deprecated\": \"%S\"", need_sep ? ",\n" : "", - deprecated ? "1" : "0"); + fix_escape_fprintf(fp, &buf, "%s\t\"Deprecated\": \"%S\"", + need_sep ? ",\n" : "", + deprecated ? "1" : "0"); need_sep = true; } if (desc) { - fix_escape_printf(&buf, "%s\t\"BriefDescription\": \"%S\"", need_sep ? ",\n" : "", - desc); + fix_escape_fprintf(fp, &buf, "%s\t\"BriefDescription\": \"%S\"", + need_sep ? ",\n" : "", + desc); need_sep = true; } if (long_desc) { - fix_escape_printf(&buf, "%s\t\"PublicDescription\": \"%S\"", need_sep ? ",\n" : "", - long_desc); + fix_escape_fprintf(fp, &buf, "%s\t\"PublicDescription\": \"%S\"", + need_sep ? ",\n" : "", + long_desc); need_sep = true; } if (encoding_desc) { - fix_escape_printf(&buf, "%s\t\"Encoding\": \"%S\"", need_sep ? ",\n" : "", - encoding_desc); + fix_escape_fprintf(fp, &buf, "%s\t\"Encoding\": \"%S\"", + need_sep ? ",\n" : "", + encoding_desc); need_sep = true; } - printf("%s}", need_sep ? "\n" : ""); + fprintf(fp, "%s}", need_sep ? "\n" : ""); strbuf_release(&buf); } @@ -394,43 +417,53 @@ static void json_print_metric(void *ps __maybe_unused, const char *group, { struct json_print_state *print_state = ps; bool need_sep = false; + FILE *fp = print_state->fp; struct strbuf buf; strbuf_init(&buf, 0); - printf("%s{\n", print_state->need_sep ? ",\n" : ""); + fprintf(fp, "%s{\n", print_state->need_sep ? ",\n" : ""); print_state->need_sep = true; if (group) { - fix_escape_printf(&buf, "\t\"MetricGroup\": \"%S\"", group); + fix_escape_fprintf(fp, &buf, "\t\"MetricGroup\": \"%S\"", group); need_sep = true; } if (name) { - fix_escape_printf(&buf, "%s\t\"MetricName\": \"%S\"", need_sep ? ",\n" : "", name); + fix_escape_fprintf(fp, &buf, "%s\t\"MetricName\": \"%S\"", + need_sep ? ",\n" : "", + name); need_sep = true; } if (expr) { - fix_escape_printf(&buf, "%s\t\"MetricExpr\": \"%S\"", need_sep ? ",\n" : "", expr); + fix_escape_fprintf(fp, &buf, "%s\t\"MetricExpr\": \"%S\"", + need_sep ? ",\n" : "", + expr); need_sep = true; } if (threshold) { - fix_escape_printf(&buf, "%s\t\"MetricThreshold\": \"%S\"", need_sep ? ",\n" : "", - threshold); + fix_escape_fprintf(fp, &buf, "%s\t\"MetricThreshold\": \"%S\"", + need_sep ? ",\n" : "", + threshold); need_sep = true; } if (unit) { - fix_escape_printf(&buf, "%s\t\"ScaleUnit\": \"%S\"", need_sep ? ",\n" : "", unit); + fix_escape_fprintf(fp, &buf, "%s\t\"ScaleUnit\": \"%S\"", + need_sep ? ",\n" : "", + unit); need_sep = true; } if (desc) { - fix_escape_printf(&buf, "%s\t\"BriefDescription\": \"%S\"", need_sep ? ",\n" : "", - desc); + fix_escape_fprintf(fp, &buf, "%s\t\"BriefDescription\": \"%S\"", + need_sep ? ",\n" : "", + desc); need_sep = true; } if (long_desc) { - fix_escape_printf(&buf, "%s\t\"PublicDescription\": \"%S\"", need_sep ? ",\n" : "", - long_desc); + fix_escape_fprintf(fp, &buf, "%s\t\"PublicDescription\": \"%S\"", + need_sep ? ",\n" : "", + long_desc); need_sep = true; } - printf("%s}", need_sep ? "\n" : ""); + fprintf(fp, "%s}", need_sep ? "\n" : ""); strbuf_release(&buf); } @@ -449,8 +482,12 @@ static bool default_skip_duplicate_pmus(void *ps) int cmd_list(int argc, const char **argv) { int i, ret = 0; - struct print_state default_ps = {}; - struct print_state json_ps = {}; + struct print_state default_ps = { + .fp = stdout, + }; + struct print_state json_ps = { + .fp = stdout, + }; void *ps = &default_ps; struct print_callbacks print_cb = { .print_start = default_print_start, @@ -461,6 +498,7 @@ int cmd_list(int argc, const char **argv) }; const char *cputype = NULL; const char *unit_name = NULL; + const char *output_path = NULL; bool json = false; struct option list_options[] = { OPT_BOOLEAN(0, "raw-dump", &default_ps.name_only, "Dump raw events"), @@ -471,6 +509,7 @@ int cmd_list(int argc, const char **argv) "Print longer event descriptions."), OPT_BOOLEAN(0, "details", &default_ps.detailed, "Print information on the perf event names and expressions used internally by events."), + OPT_STRING('o', "output", &output_path, "file", "output file name"), OPT_BOOLEAN(0, "deprecated", &default_ps.deprecated, "Print deprecated events."), OPT_STRING(0, "cputype", &cputype, "cpu type", @@ -497,6 +536,11 @@ int cmd_list(int argc, const char **argv) argc = parse_options(argc, argv, list_options, list_usage, PARSE_OPT_STOP_AT_NON_OPTION); + if (output_path) { + default_ps.fp = fopen(output_path, "w"); + json_ps.fp = default_ps.fp; + } + setup_pager(); if (!default_ps.name_only) @@ -618,5 +662,8 @@ out: free(default_ps.last_topic); free(default_ps.last_metricgroups); strlist__delete(default_ps.visited_metrics); + if (output_path) + fclose(default_ps.fp); + return ret; } diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index a3ff2f4edb..230461280e 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c @@ -2285,8 +2285,10 @@ setup_args: else ev_name = strdup(contention_tracepoints[j].name); - if (!ev_name) + if (!ev_name) { + free(rec_argv); return -ENOMEM; + } rec_argv[i++] = "-e"; rec_argv[i++] = ev_name; diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 5d86aa5ff5..3ddd4381ae 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -270,7 +270,7 @@ static int record__write(struct record *rec, struct mmap *map __maybe_unused, static int record__aio_enabled(struct record *rec); static int record__comp_enabled(struct record *rec); -static size_t zstd_compress(struct perf_session *session, struct mmap *map, +static ssize_t zstd_compress(struct perf_session *session, struct mmap *map, void *dst, size_t dst_size, void *src, size_t src_size); #ifdef HAVE_AIO_SUPPORT @@ -405,9 +405,13 @@ static int record__aio_pushfn(struct mmap *map, void *to, void *buf, size_t size */ if (record__comp_enabled(aio->rec)) { - size = zstd_compress(aio->rec->session, NULL, aio->data + aio->size, - mmap__mmap_len(map) - aio->size, - buf, size); + ssize_t compressed = zstd_compress(aio->rec->session, NULL, aio->data + aio->size, + mmap__mmap_len(map) - aio->size, + buf, size); + if (compressed < 0) + return (int)compressed; + + size = compressed; } else { memcpy(aio->data + aio->size, buf, size); } @@ -633,7 +637,13 @@ static int record__pushfn(struct mmap *map, void *to, void *bf, size_t size) struct record *rec = to; if (record__comp_enabled(rec)) { - size = zstd_compress(rec->session, map, map->data, mmap__mmap_len(map), bf, size); + ssize_t compressed = zstd_compress(rec->session, map, map->data, + mmap__mmap_len(map), bf, size); + + if (compressed < 0) + return (int)compressed; + + size = compressed; bf = map->data; } @@ -1350,7 +1360,7 @@ static int record__open(struct record *rec) evlist__for_each_entry(evlist, pos) { try_again: if (evsel__open(pos, pos->core.cpus, pos->core.threads) < 0) { - if (evsel__fallback(pos, errno, msg, sizeof(msg))) { + if (evsel__fallback(pos, &opts->target, errno, msg, sizeof(msg))) { if (verbose > 0) ui__warning("%s\n", msg); goto try_again; @@ -1527,10 +1537,10 @@ static size_t process_comp_header(void *record, size_t increment) return size; } -static size_t zstd_compress(struct perf_session *session, struct mmap *map, +static ssize_t zstd_compress(struct perf_session *session, struct mmap *map, void *dst, size_t dst_size, void *src, size_t src_size) { - size_t compressed; + ssize_t compressed; size_t max_record_size = PERF_SAMPLE_MAX_SIZE - sizeof(struct perf_record_compressed) - 1; struct zstd_data *zstd_data = &session->zstd_data; @@ -1539,6 +1549,8 @@ static size_t zstd_compress(struct perf_session *session, struct mmap *map, compressed = zstd_compress_stream_to_records(zstd_data, dst, dst_size, src, src_size, max_record_size, process_comp_header); + if (compressed < 0) + return compressed; if (map && map->file) { thread->bytes_transferred += src_size; @@ -1912,21 +1924,13 @@ static void __record__save_lost_samples(struct record *rec, struct evsel *evsel, static void record__read_lost_samples(struct record *rec) { struct perf_session *session = rec->session; - struct perf_record_lost_samples *lost; + struct perf_record_lost_samples *lost = NULL; struct evsel *evsel; /* there was an error during record__open */ if (session->evlist == NULL) return; - lost = zalloc(PERF_SAMPLE_MAX_SIZE); - if (lost == NULL) { - pr_debug("Memory allocation failed\n"); - return; - } - - lost->header.type = PERF_RECORD_LOST_SAMPLES; - evlist__for_each_entry(session->evlist, evsel) { struct xyarray *xy = evsel->core.sample_id; u64 lost_count; @@ -1949,6 +1953,15 @@ static void record__read_lost_samples(struct record *rec) } if (count.lost) { + if (!lost) { + lost = zalloc(sizeof(*lost) + + session->machines.host.id_hdr_size); + if (!lost) { + pr_debug("Memory allocation failed\n"); + return; + } + lost->header.type = PERF_RECORD_LOST_SAMPLES; + } __record__save_lost_samples(rec, evsel, lost, x, y, count.lost, 0); } @@ -1956,9 +1969,19 @@ static void record__read_lost_samples(struct record *rec) } lost_count = perf_bpf_filter__lost_count(evsel); - if (lost_count) + if (lost_count) { + if (!lost) { + lost = zalloc(sizeof(*lost) + + session->machines.host.id_hdr_size); + if (!lost) { + pr_debug("Memory allocation failed\n"); + return; + } + lost->header.type = PERF_RECORD_LOST_SAMPLES; + } __record__save_lost_samples(rec, evsel, lost, 0, 0, lost_count, PERF_RECORD_MISC_LOST_SAMPLES_BPF); + } } out: free(lost); @@ -3559,9 +3582,7 @@ static int record__mmap_cpu_mask_init(struct mmap_cpu_mask *mask, struct perf_cp if (cpu_map__is_dummy(cpus)) return 0; - perf_cpu_map__for_each_cpu(cpu, idx, cpus) { - if (cpu.cpu == -1) - continue; + perf_cpu_map__for_each_cpu_skip_any(cpu, idx, cpus) { /* Return ENODEV is input cpu is greater than max cpu */ if ((unsigned long)cpu.cpu > mask->nbits) return -ENODEV; @@ -3968,6 +3989,8 @@ int cmd_record(int argc, const char **argv) # undef set_nobuild #endif + /* Disable eager loading of kernel symbols that adds overhead to perf record. */ + symbol_conf.lazy_load_kernel_maps = true; rec->opts.affinity = PERF_AFFINITY_SYS; rec->evlist = evlist__new(); @@ -4062,8 +4085,8 @@ int cmd_record(int argc, const char **argv) } if (rec->switch_output.num_files) { - rec->switch_output.filenames = calloc(sizeof(char *), - rec->switch_output.num_files); + rec->switch_output.filenames = calloc(rec->switch_output.num_files, + sizeof(char *)); if (!rec->switch_output.filenames) { err = -EINVAL; goto out_opts; diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 9cb1da2dc0..f2ed2b7e80 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -96,9 +96,9 @@ struct report { bool stitch_lbr; bool disable_order; bool skip_empty; + bool data_type; int max_stack; struct perf_read_values show_threads_values; - struct annotation_options annotation_opts; const char *pretty_printing_style; const char *cpu_list; const char *symbol_filter_str; @@ -171,7 +171,7 @@ static int hist_iter__report_callback(struct hist_entry_iter *iter, struct mem_info *mi; struct branch_info *bi; - if (!ui__has_annotation() && !rep->symbol_ipc) + if (!ui__has_annotation() && !rep->symbol_ipc && !rep->data_type) return 0; if (sort__mode == SORT_MODE__BRANCH) { @@ -541,8 +541,7 @@ static int evlist__tui_block_hists_browse(struct evlist *evlist, struct report * evlist__for_each_entry(evlist, pos) { ret = report__browse_block_hists(&rep->block_reports[i++].hist, rep->min_percent, pos, - &rep->session->header.env, - &rep->annotation_opts); + &rep->session->header.env); if (ret != 0) return ret; } @@ -574,8 +573,7 @@ static int evlist__tty_browse_hists(struct evlist *evlist, struct report *rep, c if (rep->total_cycles_mode) { report__browse_block_hists(&rep->block_reports[i++].hist, - rep->min_percent, pos, - NULL, NULL); + rep->min_percent, pos, NULL); continue; } @@ -670,7 +668,7 @@ static int report__browse_hists(struct report *rep) } ret = evlist__tui_browse_hists(evlist, help, NULL, rep->min_percent, - &session->header.env, true, &rep->annotation_opts); + &session->header.env, true); /* * Usually "ret" is the last pressed key, and we only * care if the key notifies us to switch data file. @@ -745,7 +743,7 @@ static int hists__resort_cb(struct hist_entry *he, void *arg) if (rep->symbol_ipc && sym && !sym->annotate2) { struct evsel *evsel = hists_to_evsel(he->hists); - symbol__annotate2(&he->ms, evsel, &rep->annotation_opts, NULL); + symbol__annotate2(&he->ms, evsel, NULL); } return 0; @@ -859,27 +857,47 @@ static struct task *tasks_list(struct task *task, struct machine *machine) return tasks_list(parent_task, machine); } -static size_t maps__fprintf_task(struct maps *maps, int indent, FILE *fp) +struct maps__fprintf_task_args { + int indent; + FILE *fp; + size_t printed; +}; + +static int maps__fprintf_task_cb(struct map *map, void *data) { - size_t printed = 0; - struct map_rb_node *rb_node; + struct maps__fprintf_task_args *args = data; + const struct dso *dso = map__dso(map); + u32 prot = map__prot(map); + int ret; - maps__for_each_entry(maps, rb_node) { - struct map *map = rb_node->map; - const struct dso *dso = map__dso(map); - u32 prot = map__prot(map); + ret = fprintf(args->fp, + "%*s %" PRIx64 "-%" PRIx64 " %c%c%c%c %08" PRIx64 " %" PRIu64 " %s\n", + args->indent, "", map__start(map), map__end(map), + prot & PROT_READ ? 'r' : '-', + prot & PROT_WRITE ? 'w' : '-', + prot & PROT_EXEC ? 'x' : '-', + map__flags(map) ? 's' : 'p', + map__pgoff(map), + dso->id.ino, dso->name); - printed += fprintf(fp, "%*s %" PRIx64 "-%" PRIx64 " %c%c%c%c %08" PRIx64 " %" PRIu64 " %s\n", - indent, "", map__start(map), map__end(map), - prot & PROT_READ ? 'r' : '-', - prot & PROT_WRITE ? 'w' : '-', - prot & PROT_EXEC ? 'x' : '-', - map__flags(map) ? 's' : 'p', - map__pgoff(map), - dso->id.ino, dso->name); - } + if (ret < 0) + return ret; + + args->printed += ret; + return 0; +} + +static size_t maps__fprintf_task(struct maps *maps, int indent, FILE *fp) +{ + struct maps__fprintf_task_args args = { + .indent = indent, + .fp = fp, + .printed = 0, + }; - return printed; + maps__for_each_map(maps, maps__fprintf_task_cb, &args); + + return args.printed; } static void task__print_level(struct task *task, FILE *fp, int level) @@ -1341,15 +1359,15 @@ int cmd_report(int argc, const char **argv) "list of cpus to profile"), OPT_BOOLEAN('I', "show-info", &report.show_full_info, "Display extended information about perf.data file"), - OPT_BOOLEAN(0, "source", &report.annotation_opts.annotate_src, + OPT_BOOLEAN(0, "source", &annotate_opts.annotate_src, "Interleave source code with assembly code (default)"), - OPT_BOOLEAN(0, "asm-raw", &report.annotation_opts.show_asm_raw, + OPT_BOOLEAN(0, "asm-raw", &annotate_opts.show_asm_raw, "Display raw encoding of assembly instructions (default)"), OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", "Specify disassembler style (e.g. -M intel for intel syntax)"), - OPT_STRING(0, "prefix", &report.annotation_opts.prefix, "prefix", + OPT_STRING(0, "prefix", &annotate_opts.prefix, "prefix", "Add prefix to source file path names in programs (with --prefix-strip)"), - OPT_STRING(0, "prefix-strip", &report.annotation_opts.prefix_strip, "N", + OPT_STRING(0, "prefix-strip", &annotate_opts.prefix_strip, "N", "Strip first N entries of source file path name in programs (with --prefix)"), OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, "Show a column with the sum of periods"), @@ -1401,7 +1419,7 @@ 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", + OPT_CALLBACK(0, "percent-type", &annotate_opts, "local-period", "Set percent type local/global-period/hits", annotate_parse_percent_type), OPT_BOOLEAN(0, "ns", &symbol_conf.nanosecs, "Show times in nanosecs"), @@ -1426,7 +1444,14 @@ int cmd_report(int argc, const char **argv) if (ret < 0) goto exit; - annotation_options__init(&report.annotation_opts); + /* + * tasks_mode require access to exited threads to list those that are in + * the data file. Off-cpu events are synthesized after other events and + * reference exited threads. + */ + symbol_conf.keep_exited_threads = true; + + annotation_options__init(); ret = perf_config(report__config, &report); if (ret) @@ -1445,13 +1470,13 @@ int cmd_report(int argc, const char **argv) } if (disassembler_style) { - report.annotation_opts.disassembler_style = strdup(disassembler_style); - if (!report.annotation_opts.disassembler_style) + annotate_opts.disassembler_style = strdup(disassembler_style); + if (!annotate_opts.disassembler_style) return -ENOMEM; } if (objdump_path) { - report.annotation_opts.objdump_path = strdup(objdump_path); - if (!report.annotation_opts.objdump_path) + annotate_opts.objdump_path = strdup(objdump_path); + if (!annotate_opts.objdump_path) return -ENOMEM; } if (addr2line_path) { @@ -1460,7 +1485,7 @@ int cmd_report(int argc, const char **argv) return -ENOMEM; } - if (annotate_check_args(&report.annotation_opts) < 0) { + if (annotate_check_args() < 0) { ret = -EINVAL; goto exit; } @@ -1615,6 +1640,16 @@ repeat: sort_order = NULL; } + if (sort_order && strstr(sort_order, "type")) { + report.data_type = true; + annotate_opts.annotate_src = false; + +#ifndef HAVE_DWARF_GETLOCATIONS_SUPPORT + pr_err("Error: Data type profiling is disabled due to missing DWARF support\n"); + goto error; +#endif + } + if (strcmp(input_name, "-") != 0) setup_browser(true); else @@ -1673,7 +1708,7 @@ repeat: * so don't allocate extra space that won't be used in the stdio * implementation. */ - if (ui__has_annotation() || report.symbol_ipc || + if (ui__has_annotation() || report.symbol_ipc || report.data_type || report.total_cycles_mode) { ret = symbol__annotation_init(); if (ret < 0) @@ -1692,7 +1727,7 @@ repeat: */ symbol_conf.priv_size += sizeof(u32); } - annotation_config__init(&report.annotation_opts); + annotation_config__init(); } if (symbol__init(&session->header.env) < 0) @@ -1746,7 +1781,7 @@ error: zstd_fini(&(session->zstd_data)); perf_session__delete(session); exit: - annotation_options__exit(&report.annotation_opts); + annotation_options__exit(); free(sort_order_help); free(field_order_help); return ret; diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 78c1049221..5fe9abc6a5 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -653,7 +653,7 @@ static enum counter_recovery stat_handle_error(struct evsel *counter) if ((evsel__leader(counter) != counter) || !(counter->core.leader->nr_members > 1)) return COUNTER_SKIP; - } else if (evsel__fallback(counter, errno, msg, sizeof(msg))) { + } else if (evsel__fallback(counter, &target, errno, msg, sizeof(msg))) { if (verbose > 0) ui__warning("%s\n", msg); return COUNTER_RETRY; @@ -1204,8 +1204,9 @@ static struct option stat_options[] = { OPT_STRING('C', "cpu", &target.cpu_list, "cpu", "list of cpus to monitor in system-wide"), OPT_SET_UINT('A', "no-aggr", &stat_config.aggr_mode, - "disable CPU count aggregation", AGGR_NONE), - OPT_BOOLEAN(0, "no-merge", &stat_config.no_merge, "Do not merge identical named events"), + "disable aggregation across CPUs or PMUs", AGGR_NONE), + OPT_SET_UINT(0, "no-merge", &stat_config.aggr_mode, + "disable aggregation the same as -A or -no-aggr", AGGR_NONE), OPT_BOOLEAN(0, "hybrid-merge", &stat_config.hybrid_merge, "Merge identical named hybrid events"), OPT_STRING('x', "field-separator", &stat_config.csv_sep, "separator", @@ -1255,7 +1256,7 @@ static struct option stat_options[] = { OPT_BOOLEAN(0, "metric-no-merge", &stat_config.metric_no_merge, "don't try to share events between metrics in a group"), OPT_BOOLEAN(0, "metric-no-threshold", &stat_config.metric_no_threshold, - "don't try to share events between metrics in a group "), + "disable adding events for the metric threshold calculation"), OPT_BOOLEAN(0, "topdown", &topdown_run, "measure top-down statistics"), OPT_UINTEGER(0, "td-level", &stat_config.topdown_level, @@ -1316,7 +1317,7 @@ static int cpu__get_cache_id_from_map(struct perf_cpu cpu, char *map) * be the first online CPU in the cache domain else use the * first online CPU of the cache domain as the ID. */ - if (perf_cpu_map__empty(cpu_map)) + if (perf_cpu_map__has_any_cpu_or_is_empty(cpu_map)) id = cpu.cpu; else id = perf_cpu_map__cpu(cpu_map, 0).cpu; @@ -1622,7 +1623,7 @@ static int perf_stat_init_aggr_mode(void) * taking the highest cpu number to be the size of * the aggregation translate cpumap. */ - if (!perf_cpu_map__empty(evsel_list->core.user_requested_cpus)) + if (!perf_cpu_map__has_any_cpu_or_is_empty(evsel_list->core.user_requested_cpus)) nr = perf_cpu_map__max(evsel_list->core.user_requested_cpus).cpu; else nr = 0; @@ -2289,7 +2290,7 @@ int process_stat_config_event(struct perf_session *session, perf_event__read_stat_config(&stat_config, &event->stat_config); - if (perf_cpu_map__empty(st->cpus)) { + if (perf_cpu_map__has_any_cpu_or_is_empty(st->cpus)) { if (st->aggr_mode != AGGR_UNSET) pr_warning("warning: processing task data, aggregation mode not set\n"); } else if (st->aggr_mode != AGGR_UNSET) { diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index cd64ae44cc..5301d1badd 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -147,7 +147,7 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he) return err; } - err = symbol__annotate(&he->ms, evsel, &top->annotation_opts, NULL); + err = symbol__annotate(&he->ms, evsel, NULL); if (err == 0) { top->sym_filter_entry = he; } else { @@ -261,9 +261,9 @@ static void perf_top__show_details(struct perf_top *top) goto out_unlock; printf("Showing %s for %s\n", evsel__name(top->sym_evsel), symbol->name); - printf(" Events Pcnt (>=%d%%)\n", top->annotation_opts.min_pcnt); + printf(" Events Pcnt (>=%d%%)\n", annotate_opts.min_pcnt); - more = symbol__annotate_printf(&he->ms, top->sym_evsel, &top->annotation_opts); + more = symbol__annotate_printf(&he->ms, top->sym_evsel); if (top->evlist->enabled) { if (top->zero) @@ -357,7 +357,7 @@ static void perf_top__print_sym_table(struct perf_top *top) static void prompt_integer(int *target, const char *msg) { - char *buf = malloc(0), *p; + char *buf = NULL, *p; size_t dummy = 0; int tmp; @@ -450,7 +450,7 @@ static void perf_top__print_mapped_keys(struct perf_top *top) fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top->count_filter); - fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", top->annotation_opts.min_pcnt); + fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", annotate_opts.min_pcnt); fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); fprintf(stdout, "\t[S] stop annotation.\n"); @@ -553,7 +553,7 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c) prompt_integer(&top->count_filter, "Enter display event count filter"); break; case 'F': - prompt_percent(&top->annotation_opts.min_pcnt, + prompt_percent(&annotate_opts.min_pcnt, "Enter details display event filter (percent)"); break; case 'K': @@ -646,8 +646,7 @@ repeat: } ret = evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent, - &top->session->header.env, !top->record_opts.overwrite, - &top->annotation_opts); + &top->session->header.env, !top->record_opts.overwrite); if (ret == K_RELOAD) { top->zero = true; goto repeat; @@ -1044,7 +1043,7 @@ try_again: perf_top_overwrite_fallback(top, counter)) goto try_again; - if (evsel__fallback(counter, errno, msg, sizeof(msg))) { + if (evsel__fallback(counter, &opts->target, errno, msg, sizeof(msg))) { if (verbose > 0) ui__warning("%s\n", msg); goto try_again; @@ -1241,9 +1240,9 @@ static int __cmd_top(struct perf_top *top) pthread_t thread, thread_process; int ret; - if (!top->annotation_opts.objdump_path) { + if (!annotate_opts.objdump_path) { ret = perf_env__lookup_objdump(&top->session->header.env, - &top->annotation_opts.objdump_path); + &annotate_opts.objdump_path); if (ret) return ret; } @@ -1537,9 +1536,9 @@ int cmd_top(int argc, const char **argv) "only consider symbols in these comms"), OPT_STRING(0, "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", "only consider these symbols"), - OPT_BOOLEAN(0, "source", &top.annotation_opts.annotate_src, + OPT_BOOLEAN(0, "source", &annotate_opts.annotate_src, "Interleave source code with assembly code (default)"), - OPT_BOOLEAN(0, "asm-raw", &top.annotation_opts.show_asm_raw, + OPT_BOOLEAN(0, "asm-raw", &annotate_opts.show_asm_raw, "Display raw encoding of assembly instructions (default)"), OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel, "Enable kernel symbol demangling"), @@ -1550,9 +1549,9 @@ int cmd_top(int argc, const char **argv) "addr2line binary to use for line numbers"), OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", "Specify disassembler style (e.g. -M intel for intel syntax)"), - OPT_STRING(0, "prefix", &top.annotation_opts.prefix, "prefix", + OPT_STRING(0, "prefix", &annotate_opts.prefix, "prefix", "Add prefix to source file path names in programs (with --prefix-strip)"), - OPT_STRING(0, "prefix-strip", &top.annotation_opts.prefix_strip, "N", + OPT_STRING(0, "prefix-strip", &annotate_opts.prefix_strip, "N", "Strip first N entries of source file path name in programs (with --prefix)"), OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"), OPT_CALLBACK(0, "percent-limit", &top, "percent", @@ -1610,10 +1609,10 @@ int cmd_top(int argc, const char **argv) if (status < 0) return status; - annotation_options__init(&top.annotation_opts); + annotation_options__init(); - top.annotation_opts.min_pcnt = 5; - top.annotation_opts.context = 4; + annotate_opts.min_pcnt = 5; + annotate_opts.context = 4; top.evlist = evlist__new(); if (top.evlist == NULL) @@ -1643,13 +1642,13 @@ int cmd_top(int argc, const char **argv) usage_with_options(top_usage, options); if (disassembler_style) { - top.annotation_opts.disassembler_style = strdup(disassembler_style); - if (!top.annotation_opts.disassembler_style) + annotate_opts.disassembler_style = strdup(disassembler_style); + if (!annotate_opts.disassembler_style) return -ENOMEM; } if (objdump_path) { - top.annotation_opts.objdump_path = strdup(objdump_path); - if (!top.annotation_opts.objdump_path) + annotate_opts.objdump_path = strdup(objdump_path); + if (!annotate_opts.objdump_path) return -ENOMEM; } if (addr2line_path) { @@ -1662,7 +1661,7 @@ int cmd_top(int argc, const char **argv) if (status) goto out_delete_evlist; - if (annotate_check_args(&top.annotation_opts) < 0) + if (annotate_check_args() < 0) goto out_delete_evlist; if (!top.evlist->core.nr_entries) { @@ -1788,7 +1787,7 @@ int cmd_top(int argc, const char **argv) if (status < 0) goto out_delete_evlist; - annotation_config__init(&top.annotation_opts); + annotation_config__init(); symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); status = symbol__init(NULL); @@ -1841,7 +1840,7 @@ int cmd_top(int argc, const char **argv) out_delete_evlist: evlist__delete(top.evlist); perf_session__delete(top.session); - annotation_options__exit(&top.annotation_opts); + annotation_options__exit(); return status; } diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index e541d0e277..109b8e64fe 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -2470,9 +2470,8 @@ static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sam static const char *errno_to_name(struct evsel *evsel, int err) { struct perf_env *env = evsel__env(evsel); - const char *arch_name = perf_env__arch(env); - return arch_syscalls__strerrno(arch_name, err); + return perf_env__arch_strerrno(env, err); } static int trace__sys_exit(struct trace *trace, struct evsel *evsel, @@ -4264,12 +4263,11 @@ static size_t thread__dump_stats(struct thread_trace *ttrace, printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct); if (trace->errno_summary && stats->nr_failures) { - const char *arch_name = perf_env__arch(trace->host->env); int e; for (e = 0; e < stats->max_errno; ++e) { if (stats->errnos[e] != 0) - fprintf(fp, "\t\t\t\t%s: %d\n", arch_syscalls__strerrno(arch_name, e + 1), stats->errnos[e]); + fprintf(fp, "\t\t\t\t%s: %d\n", perf_env__arch_strerrno(trace->host->env, e + 1), stats->errnos[e]); } } } diff --git a/tools/perf/perf-archive.sh b/tools/perf/perf-archive.sh old mode 100644 new mode 100755 index 133f0eddbc..f94795794b --- a/tools/perf/perf-archive.sh +++ b/tools/perf/perf-archive.sh @@ -4,8 +4,73 @@ # Arnaldo Carvalho de Melo PERF_DATA=perf.data -if [ $# -ne 0 ] ; then - PERF_DATA=$1 +PERF_SYMBOLS=perf.symbols +PERF_ALL=perf.all +ALL=0 +UNPACK=0 + +while [ $# -gt 0 ] ; do + if [ $1 == "--all" ]; then + ALL=1 + shift + elif [ $1 == "--unpack" ]; then + UNPACK=1 + shift + else + PERF_DATA=$1 + UNPACK_TAR=$1 + shift + fi +done + +if [ $UNPACK -eq 1 ]; then + if [ ! -z "$UNPACK_TAR" ]; then # tar given as an argument + if [ ! -e "$UNPACK_TAR" ]; then + echo "Provided file $UNPACK_TAR does not exist" + exit 1 + fi + TARGET="$UNPACK_TAR" + else # search for perf tar in the current directory + TARGET=`find . -regex "\./perf.*\.tar\.bz2"` + TARGET_NUM=`echo -n "$TARGET" | grep -c '^'` + + if [ -z "$TARGET" -o $TARGET_NUM -gt 1 ]; then + echo -e "Error: $TARGET_NUM files found for unpacking:\n$TARGET" + echo "Provide the requested file as an argument" + exit 1 + else + echo "Found target file for unpacking: $TARGET" + fi + fi + + if [[ "$TARGET" =~ (\./)?$PERF_ALL.*.tar.bz2 ]]; then # perf tar generated by --all option + TAR_CONTENTS=`tar tvf "$TARGET" | tr -s " " | cut -d " " -f 6` + VALID_TAR=`echo "$TAR_CONTENTS" | grep "$PERF_SYMBOLS.tar.bz2" | wc -l` # check if it contains a sub-tar perf.symbols + if [ $VALID_TAR -ne 1 ]; then + echo "Error: $TARGET file is not valid (contains zero or multiple sub-tar files with debug symbols)" + exit 1 + fi + + INTERSECT=`comm -12 <(ls) <(echo "$TAR_CONTENTS") | tr "\n" " "` # check for overwriting + if [ ! -z "$INTERSECT" ]; then # prompt if file(s) already exist in the current directory + echo "File(s) ${INTERSECT::-1} already exist in the current directory." + while true; do + read -p 'Do you wish to overwrite them? ' yn + case $yn in + [Yy]* ) break;; + [Nn]* ) exit 1;; + * ) echo "Please answer yes or no.";; + esac + done + fi + + # unzip the perf.data file in the current working directory and debug symbols in ~/.debug directory + tar xvf $TARGET && tar xvf $PERF_SYMBOLS.tar.bz2 -C ~/.debug + + else # perf tar generated by perf archive (contains only debug symbols) + tar xvf $TARGET -C ~/.debug + fi + exit 0 fi # @@ -39,9 +104,18 @@ while read build_id ; do echo ${filename#$PERF_BUILDID_LINKDIR} >> $MANIFEST done -tar cjf $PERF_DATA.tar.bz2 -C $PERF_BUILDID_DIR -T $MANIFEST -rm $MANIFEST $BUILDIDS || true +if [ $ALL -eq 1 ]; then # pack perf.data file together with tar containing debug symbols + HOSTNAME=$(hostname) + DATE=$(date '+%Y%m%d-%H%M%S') + tar cjf $PERF_SYMBOLS.tar.bz2 -C $PERF_BUILDID_DIR -T $MANIFEST + tar cjf $PERF_ALL-$HOSTNAME-$DATE.tar.bz2 $PERF_DATA $PERF_SYMBOLS.tar.bz2 + rm $PERF_SYMBOLS.tar.bz2 $MANIFEST $BUILDIDS || true +else # pack only the debug symbols + tar cjf $PERF_DATA.tar.bz2 -C $PERF_BUILDID_DIR -T $MANIFEST + rm $MANIFEST $BUILDIDS || true +fi + echo -e "Now please run:\n" -echo -e "$ tar xvf $PERF_DATA.tar.bz2 -C ~/.debug\n" -echo "wherever you need to run 'perf report' on." +echo -e "$ perf archive --unpack\n" +echo "or unpack the tar manually wherever you need to run 'perf report' on." exit 0 diff --git a/tools/perf/perf.c b/tools/perf/perf.c index d3fc809041..921bee0a64 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -39,6 +39,7 @@ #include static int use_pager = -1; +static FILE *debug_fp = NULL; struct cmd_struct { const char *cmd; @@ -162,6 +163,19 @@ static void commit_pager_choice(void) } } +static int set_debug_file(const char *path) +{ + debug_fp = fopen(path, "w"); + if (!debug_fp) { + fprintf(stderr, "Open debug file '%s' failed: %s\n", + path, strerror(errno)); + return -1; + } + + debug_set_file(debug_fp); + return 0; +} + struct option options[] = { OPT_ARGUMENT("help", "help"), OPT_ARGUMENT("version", "version"), @@ -174,6 +188,7 @@ struct option options[] = { OPT_ARGUMENT("list-cmds", "list-cmds"), OPT_ARGUMENT("list-opts", "list-opts"), OPT_ARGUMENT("debug", "debug"), + OPT_ARGUMENT("debug-file", "debug-file"), OPT_END() }; @@ -287,6 +302,18 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) (*argv)++; (*argc)--; + } else if (!strcmp(cmd, "--debug-file")) { + if (*argc < 2) { + fprintf(stderr, "No path given for --debug-file.\n"); + usage(perf_usage_string); + } + + if (set_debug_file((*argv)[1])) + usage(perf_usage_string); + + (*argv)++; + (*argc)--; + } else { fprintf(stderr, "Unknown option: %s\n", cmd); usage(perf_usage_string); @@ -547,5 +574,8 @@ int main(int argc, const char **argv) fprintf(stderr, "Failed to run command '%s': %s\n", cmd, str_error_r(errno, sbuf, sizeof(sbuf))); out: + if (debug_fp) + fclose(debug_fp); + return 1; } diff --git a/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/branch.json b/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/branch.json new file mode 100644 index 0000000000..a632755fc0 --- /dev/null +++ b/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/branch.json @@ -0,0 +1,125 @@ +[ + { + "ArchStdEvent": "BR_IMMED_SPEC" + }, + { + "ArchStdEvent": "BR_RETURN_SPEC" + }, + { + "ArchStdEvent": "BR_INDIRECT_SPEC" + }, + { + "ArchStdEvent": "BR_MIS_PRED" + }, + { + "ArchStdEvent": "BR_PRED" + }, + { + "PublicDescription": "Instruction architecturally executed, branch not taken", + "EventCode": "0x8107", + "EventName": "BR_SKIP_RETIRED", + "BriefDescription": "Instruction architecturally executed, branch not taken" + }, + { + "PublicDescription": "Instruction architecturally executed, immediate branch taken", + "EventCode": "0x8108", + "EventName": "BR_IMMED_TAKEN_RETIRED", + "BriefDescription": "Instruction architecturally executed, immediate branch taken" + }, + { + "PublicDescription": "Instruction architecturally executed, indirect branch excluding return retired", + "EventCode": "0x810c", + "EventName": "BR_INDNR_TAKEN_RETIRED", + "BriefDescription": "Instruction architecturally executed, indirect branch excluding return retired" + }, + { + "PublicDescription": "Instruction architecturally executed, predicted immediate branch", + "EventCode": "0x8110", + "EventName": "BR_IMMED_PRED_RETIRED", + "BriefDescription": "Instruction architecturally executed, predicted immediate branch" + }, + { + "PublicDescription": "Instruction architecturally executed, mispredicted immediate branch", + "EventCode": "0x8111", + "EventName": "BR_IMMED_MIS_PRED_RETIRED", + "BriefDescription": "Instruction architecturally executed, mispredicted immediate branch" + }, + { + "PublicDescription": "Instruction architecturally executed, predicted indirect branch", + "EventCode": "0x8112", + "EventName": "BR_IND_PRED_RETIRED", + "BriefDescription": "Instruction architecturally executed, predicted indirect branch" + }, + { + "PublicDescription": "Instruction architecturally executed, mispredicted indirect branch", + "EventCode": "0x8113", + "EventName": "BR_IND_MIS_PRED_RETIRED", + "BriefDescription": "Instruction architecturally executed, mispredicted indirect branch" + }, + { + "PublicDescription": "Instruction architecturally executed, predicted procedure return", + "EventCode": "0x8114", + "EventName": "BR_RETURN_PRED_RETIRED", + "BriefDescription": "Instruction architecturally executed, predicted procedure return" + }, + { + "PublicDescription": "Instruction architecturally executed, mispredicted procedure return", + "EventCode": "0x8115", + "EventName": "BR_RETURN_MIS_PRED_RETIRED", + "BriefDescription": "Instruction architecturally executed, mispredicted procedure return" + }, + { + "PublicDescription": "Instruction architecturally executed, predicted indirect branch excluding return", + "EventCode": "0x8116", + "EventName": "BR_INDNR_PRED_RETIRED", + "BriefDescription": "Instruction architecturally executed, predicted indirect branch excluding return" + }, + { + "PublicDescription": "Instruction architecturally executed, mispredicted indirect branch excluding return", + "EventCode": "0x8117", + "EventName": "BR_INDNR_MIS_PRED_RETIRED", + "BriefDescription": "Instruction architecturally executed, mispredicted indirect branch excluding return" + }, + { + "PublicDescription": "Instruction architecturally executed, predicted branch, taken", + "EventCode": "0x8118", + "EventName": "BR_TAKEN_PRED_RETIRED", + "BriefDescription": "Instruction architecturally executed, predicted branch, taken" + }, + { + "PublicDescription": "Instruction architecturally executed, mispredicted branch, taken", + "EventCode": "0x8119", + "EventName": "BR_TAKEN_MIS_PRED_RETIRED", + "BriefDescription": "Instruction architecturally executed, mispredicted branch, taken" + }, + { + "PublicDescription": "Instruction architecturally executed, predicted branch, not taken", + "EventCode": "0x811a", + "EventName": "BR_SKIP_PRED_RETIRED", + "BriefDescription": "Instruction architecturally executed, predicted branch, not taken" + }, + { + "PublicDescription": "Instruction architecturally executed, mispredicted branch, not taken", + "EventCode": "0x811b", + "EventName": "BR_SKIP_MIS_PRED_RETIRED", + "BriefDescription": "Instruction architecturally executed, mispredicted branch, not taken" + }, + { + "PublicDescription": "Instruction architecturally executed, predicted branch", + "EventCode": "0x811c", + "EventName": "BR_PRED_RETIRED", + "BriefDescription": "Instruction architecturally executed, predicted branch" + }, + { + "PublicDescription": "Instruction architecturally executed, indirect branch", + "EventCode": "0x811d", + "EventName": "BR_IND_RETIRED", + "BriefDescription": "Instruction architecturally executed, indirect branch" + }, + { + "PublicDescription": "Branch Record captured.", + "EventCode": "0x811f", + "EventName": "BRB_FILTRATE", + "BriefDescription": "Branch Record captured." + } +] diff --git a/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/bus.json b/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/bus.json new file mode 100644 index 0000000000..2aeb990783 --- /dev/null +++ b/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/bus.json @@ -0,0 +1,20 @@ +[ + { + "ArchStdEvent": "CPU_CYCLES" + }, + { + "ArchStdEvent": "BUS_CYCLES" + }, + { + "ArchStdEvent": "BUS_ACCESS_RD" + }, + { + "ArchStdEvent": "BUS_ACCESS_WR" + }, + { + "ArchStdEvent": "BUS_ACCESS" + }, + { + "ArchStdEvent": "CNT_CYCLES" + } +] diff --git a/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/cache.json b/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/cache.json new file mode 100644 index 0000000000..c50d8e930b --- /dev/null +++ b/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/cache.json @@ -0,0 +1,206 @@ +[ + { + "ArchStdEvent": "L1D_CACHE_RD" + }, + { + "ArchStdEvent": "L1D_CACHE_WR" + }, + { + "ArchStdEvent": "L1D_CACHE_REFILL_RD" + }, + { + "ArchStdEvent": "L1D_CACHE_INVAL" + }, + { + "ArchStdEvent": "L1D_TLB_REFILL_RD" + }, + { + "ArchStdEvent": "L1D_TLB_REFILL_WR" + }, + { + "ArchStdEvent": "L2D_CACHE_RD" + }, + { + "ArchStdEvent": "L2D_CACHE_WR" + }, + { + "ArchStdEvent": "L2D_CACHE_REFILL_RD" + }, + { + "ArchStdEvent": "L2D_CACHE_REFILL_WR" + }, + { + "ArchStdEvent": "L2D_CACHE_WB_VICTIM" + }, + { + "ArchStdEvent": "L2D_CACHE_WB_CLEAN" + }, + { + "ArchStdEvent": "L2D_CACHE_INVAL" + }, + { + "ArchStdEvent": "L1I_CACHE_REFILL" + }, + { + "ArchStdEvent": "L1I_TLB_REFILL" + }, + { + "ArchStdEvent": "L1D_CACHE_REFILL" + }, + { + "ArchStdEvent": "L1D_CACHE" + }, + { + "ArchStdEvent": "L1D_TLB_REFILL" + }, + { + "ArchStdEvent": "L1I_CACHE" + }, + { + "ArchStdEvent": "L2D_CACHE" + }, + { + "ArchStdEvent": "L2D_CACHE_REFILL" + }, + { + "ArchStdEvent": "L2D_CACHE_WB" + }, + { + "ArchStdEvent": "L1D_TLB" + }, + { + "ArchStdEvent": "L1I_TLB" + }, + { + "ArchStdEvent": "L2D_TLB_REFILL" + }, + { + "ArchStdEvent": "L2I_TLB_REFILL" + }, + { + "ArchStdEvent": "L2D_TLB" + }, + { + "ArchStdEvent": "L2I_TLB" + }, + { + "ArchStdEvent": "DTLB_WALK" + }, + { + "ArchStdEvent": "ITLB_WALK" + }, + { + "ArchStdEvent": "L1D_CACHE_REFILL_WR" + }, + { + "ArchStdEvent": "L1D_CACHE_LMISS_RD" + }, + { + "ArchStdEvent": "L1I_CACHE_LMISS" + }, + { + "ArchStdEvent": "L2D_CACHE_LMISS_RD" + }, + { + "PublicDescription": "Level 1 data or unified cache demand access", + "EventCode": "0x8140", + "EventName": "L1D_CACHE_RW", + "BriefDescription": "Level 1 data or unified cache demand access" + }, + { + "PublicDescription": "Level 1 data or unified cache preload or prefetch", + "EventCode": "0x8142", + "EventName": "L1D_CACHE_PRFM", + "BriefDescription": "Level 1 data or unified cache preload or prefetch" + }, + { + "PublicDescription": "Level 1 data or unified cache refill, preload or prefetch", + "EventCode": "0x8146", + "EventName": "L1D_CACHE_REFILL_PRFM", + "BriefDescription": "Level 1 data or unified cache refill, preload or prefetch" + }, + { + "ArchStdEvent": "L1D_TLB_RD" + }, + { + "ArchStdEvent": "L1D_TLB_WR" + }, + { + "ArchStdEvent": "L2D_TLB_REFILL_RD" + }, + { + "ArchStdEvent": "L2D_TLB_REFILL_WR" + }, + { + "ArchStdEvent": "L2D_TLB_RD" + }, + { + "ArchStdEvent": "L2D_TLB_WR" + }, + { + "PublicDescription": "L1D TLB miss", + "EventCode": "0xD600", + "EventName": "L1D_TLB_MISS", + "BriefDescription": "L1D TLB miss" + }, + { + "PublicDescription": "Level 1 prefetcher, load prefetch requests generated", + "EventCode": "0xd606", + "EventName": "L1_PREFETCH_LD_GEN", + "BriefDescription": "Level 1 prefetcher, load prefetch requests generated" + }, + { + "PublicDescription": "Level 1 prefetcher, load prefetch fills into the level 1 cache", + "EventCode": "0xd607", + "EventName": "L1_PREFETCH_LD_FILL", + "BriefDescription": "Level 1 prefetcher, load prefetch fills into the level 1 cache" + }, + { + "PublicDescription": "Level 1 prefetcher, load prefetch to level 2 generated", + "EventCode": "0xd608", + "EventName": "L1_PREFETCH_L2_REQ", + "BriefDescription": "Level 1 prefetcher, load prefetch to level 2 generated" + }, + { + "PublicDescription": "L1 prefetcher, distance was reset", + "EventCode": "0xd609", + "EventName": "L1_PREFETCH_DIST_RST", + "BriefDescription": "L1 prefetcher, distance was reset" + }, + { + "PublicDescription": "L1 prefetcher, distance was increased", + "EventCode": "0xd60a", + "EventName": "L1_PREFETCH_DIST_INC", + "BriefDescription": "L1 prefetcher, distance was increased" + }, + { + "PublicDescription": "Level 1 prefetcher, table entry is trained", + "EventCode": "0xd60b", + "EventName": "L1_PREFETCH_ENTRY_TRAINED", + "BriefDescription": "Level 1 prefetcher, table entry is trained" + }, + { + "PublicDescription": "L1 data cache refill - Read or Write", + "EventCode": "0xd60e", + "EventName": "L1D_CACHE_REFILL_RW", + "BriefDescription": "L1 data cache refill - Read or Write" + }, + { + "PublicDescription": "Level 2 cache refill from instruction-side miss, including IMMU refills", + "EventCode": "0xD701", + "EventName": "L2C_INST_REFILL", + "BriefDescription": "Level 2 cache refill from instruction-side miss, including IMMU refills" + }, + { + "PublicDescription": "Level 2 cache refill from data-side miss, including DMMU refills", + "EventCode": "0xD702", + "EventName": "L2C_DATA_REFILL", + "BriefDescription": "Level 2 cache refill from data-side miss, including DMMU refills" + }, + { + "PublicDescription": "Level 2 cache prefetcher, load prefetch requests generated", + "EventCode": "0xD703", + "EventName": "L2_PREFETCH_REQ", + "BriefDescription": "Level 2 cache prefetcher, load prefetch requests generated" + } +] diff --git a/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/core-imp-def.json b/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/core-imp-def.json new file mode 100644 index 0000000000..eb5a2208d2 --- /dev/null +++ b/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/core-imp-def.json @@ -0,0 +1,464 @@ +[ + { + "PublicDescription": "Level 2 prefetch requests, refilled to L2 cache", + "EventCode": "0x10A", + "EventName": "L2_PREFETCH_REFILL", + "BriefDescription": "Level 2 prefetch requests, refilled to L2 cache" + }, + { + "PublicDescription": "Level 2 prefetch requests, late", + "EventCode": "0x10B", + "EventName": "L2_PREFETCH_UPGRADE", + "BriefDescription": "Level 2 prefetch requests, late" + }, + { + "PublicDescription": "Predictable branch speculatively executed that hit any level of BTB", + "EventCode": "0x110", + "EventName": "BPU_HIT_BTB", + "BriefDescription": "Predictable branch speculatively executed that hit any level of BTB" + }, + { + "PublicDescription": "Predictable conditional branch speculatively executed that hit any level of BTB", + "EventCode": "0x111", + "EventName": "BPU_CONDITIONAL_BRANCH_HIT_BTB", + "BriefDescription": "Predictable conditional branch speculatively executed that hit any level of BTB" + }, + { + "PublicDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the indirect predictor", + "EventCode": "0x112", + "EventName": "BPU_HIT_INDIRECT_PREDICTOR", + "BriefDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the indirect predictor" + }, + { + "PublicDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the return predictor", + "EventCode": "0x113", + "EventName": "BPU_HIT_RSB", + "BriefDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the return predictor" + }, + { + "PublicDescription": "Predictable unconditional branch speculatively executed that did not hit any level of BTB", + "EventCode": "0x114", + "EventName": "BPU_UNCONDITIONAL_BRANCH_MISS_BTB", + "BriefDescription": "Predictable unconditional branch speculatively executed that did not hit any level of BTB" + }, + { + "PublicDescription": "Predictable branch speculatively executed, unpredicted", + "EventCode": "0x115", + "EventName": "BPU_BRANCH_NO_HIT", + "BriefDescription": "Predictable branch speculatively executed, unpredicted" + }, + { + "PublicDescription": "Predictable branch speculatively executed that hit any level of BTB that mispredict", + "EventCode": "0x116", + "EventName": "BPU_HIT_BTB_AND_MISPREDICT", + "BriefDescription": "Predictable branch speculatively executed that hit any level of BTB that mispredict" + }, + { + "PublicDescription": "Predictable conditional branch speculatively executed that hit any level of BTB that (direction) mispredict", + "EventCode": "0x117", + "EventName": "BPU_CONDITIONAL_BRANCH_HIT_BTB_AND_MISPREDICT", + "BriefDescription": "Predictable conditional branch speculatively executed that hit any level of BTB that (direction) mispredict" + }, + { + "PublicDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the indirect predictor that mispredict", + "EventCode": "0x118", + "EventName": "BPU_INDIRECT_BRANCH_HIT_BTB_AND_MISPREDICT", + "BriefDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the indirect predictor that mispredict" + }, + { + "PublicDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the return predictor that mispredict", + "EventCode": "0x119", + "EventName": "BPU_HIT_RSB_AND_MISPREDICT", + "BriefDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the return predictor that mispredict" + }, + { + "PublicDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the overflow/underflow return predictor that mispredict", + "EventCode": "0x11a", + "EventName": "BPU_MISS_RSB_AND_MISPREDICT", + "BriefDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the overflow/underflow return predictor that mispredict" + }, + { + "PublicDescription": "Predictable branch speculatively executed, unpredicted, that mispredict", + "EventCode": "0x11b", + "EventName": "BPU_NO_PREDICTION_MISPREDICT", + "BriefDescription": "Predictable branch speculatively executed, unpredicted, that mispredict" + }, + { + "PublicDescription": "Preditable branch update the BTB region buffer entry", + "EventCode": "0x11c", + "EventName": "BPU_BTB_UPDATE", + "BriefDescription": "Preditable branch update the BTB region buffer entry" + }, + { + "PublicDescription": "Count predict pipe stalls due to speculative return address predictor full", + "EventCode": "0x11d", + "EventName": "BPU_RSB_FULL_STALL", + "BriefDescription": "Count predict pipe stalls due to speculative return address predictor full" + }, + { + "PublicDescription": "Macro-ops speculatively decoded", + "EventCode": "0x11f", + "EventName": "ICF_INST_SPEC_DECODE", + "BriefDescription": "Macro-ops speculatively decoded" + }, + { + "PublicDescription": "Flushes", + "EventCode": "0x120", + "EventName": "GPC_FLUSH", + "BriefDescription": "Flushes" + }, + { + "PublicDescription": "Flushes due to memory hazards", + "EventCode": "0x121", + "EventName": "GPC_FLUSH_MEM_FAULT", + "BriefDescription": "Flushes due to memory hazards" + }, + { + "PublicDescription": "ETM extout bit 0", + "EventCode": "0x141", + "EventName": "MSC_ETM_EXTOUT0", + "BriefDescription": "ETM extout bit 0" + }, + { + "PublicDescription": "ETM extout bit 1", + "EventCode": "0x142", + "EventName": "MSC_ETM_EXTOUT1", + "BriefDescription": "ETM extout bit 1" + }, + { + "PublicDescription": "ETM extout bit 2", + "EventCode": "0x143", + "EventName": "MSC_ETM_EXTOUT2", + "BriefDescription": "ETM extout bit 2" + }, + { + "PublicDescription": "ETM extout bit 3", + "EventCode": "0x144", + "EventName": "MSC_ETM_EXTOUT3", + "BriefDescription": "ETM extout bit 3" + }, + { + "PublicDescription": "Bus request sn", + "EventCode": "0x156", + "EventName": "L2C_SNOOP", + "BriefDescription": "Bus request sn" + }, + { + "PublicDescription": "L2 TXDAT LCRD blocked", + "EventCode": "0x169", + "EventName": "L2C_DAT_CRD_STALL", + "BriefDescription": "L2 TXDAT LCRD blocked" + }, + { + "PublicDescription": "L2 TXRSP LCRD blocked", + "EventCode": "0x16a", + "EventName": "L2C_RSP_CRD_STALL", + "BriefDescription": "L2 TXRSP LCRD blocked" + }, + { + "PublicDescription": "L2 TXREQ LCRD blocked", + "EventCode": "0x16b", + "EventName": "L2C_REQ_CRD_STALL", + "BriefDescription": "L2 TXREQ LCRD blocked" + }, + { + "PublicDescription": "Early mispredict", + "EventCode": "0xD100", + "EventName": "ICF_EARLY_MIS_PRED", + "BriefDescription": "Early mispredict" + }, + { + "PublicDescription": "FEQ full cycles", + "EventCode": "0xD101", + "EventName": "ICF_FEQ_FULL", + "BriefDescription": "FEQ full cycles" + }, + { + "PublicDescription": "Instruction FIFO Full", + "EventCode": "0xD102", + "EventName": "ICF_INST_FIFO_FULL", + "BriefDescription": "Instruction FIFO Full" + }, + { + "PublicDescription": "L1I TLB miss", + "EventCode": "0xD103", + "EventName": "L1I_TLB_MISS", + "BriefDescription": "L1I TLB miss" + }, + { + "PublicDescription": "ICF sent 0 instructions to IDR this cycle", + "EventCode": "0xD104", + "EventName": "ICF_STALL", + "BriefDescription": "ICF sent 0 instructions to IDR this cycle" + }, + { + "PublicDescription": "PC FIFO Full", + "EventCode": "0xD105", + "EventName": "ICF_PC_FIFO_FULL", + "BriefDescription": "PC FIFO Full" + }, + { + "PublicDescription": "Stall due to BOB ID", + "EventCode": "0xD200", + "EventName": "IDR_STALL_BOB_ID", + "BriefDescription": "Stall due to BOB ID" + }, + { + "PublicDescription": "Dispatch stall due to LOB entries", + "EventCode": "0xD201", + "EventName": "IDR_STALL_LOB_ID", + "BriefDescription": "Dispatch stall due to LOB entries" + }, + { + "PublicDescription": "Dispatch stall due to SOB entries", + "EventCode": "0xD202", + "EventName": "IDR_STALL_SOB_ID", + "BriefDescription": "Dispatch stall due to SOB entries" + }, + { + "PublicDescription": "Dispatch stall due to IXU scheduler entries", + "EventCode": "0xD203", + "EventName": "IDR_STALL_IXU_SCHED", + "BriefDescription": "Dispatch stall due to IXU scheduler entries" + }, + { + "PublicDescription": "Dispatch stall due to FSU scheduler entries", + "EventCode": "0xD204", + "EventName": "IDR_STALL_FSU_SCHED", + "BriefDescription": "Dispatch stall due to FSU scheduler entries" + }, + { + "PublicDescription": "Dispatch stall due to ROB entries", + "EventCode": "0xD205", + "EventName": "IDR_STALL_ROB_ID", + "BriefDescription": "Dispatch stall due to ROB entries" + }, + { + "PublicDescription": "Dispatch stall due to flush", + "EventCode": "0xD206", + "EventName": "IDR_STALL_FLUSH", + "BriefDescription": "Dispatch stall due to flush" + }, + { + "PublicDescription": "Dispatch stall due to WFI", + "EventCode": "0xD207", + "EventName": "IDR_STALL_WFI", + "BriefDescription": "Dispatch stall due to WFI" + }, + { + "PublicDescription": "Number of SWOB drains triggered by timeout", + "EventCode": "0xD208", + "EventName": "IDR_STALL_SWOB_TIMEOUT", + "BriefDescription": "Number of SWOB drains triggered by timeout" + }, + { + "PublicDescription": "Number of SWOB drains triggered by system register or special-purpose register read-after-write or specific special-purpose register writes that cause SWOB drain", + "EventCode": "0xD209", + "EventName": "IDR_STALL_SWOB_RAW", + "BriefDescription": "Number of SWOB drains triggered by system register or special-purpose register read-after-write or specific special-purpose register writes that cause SWOB drain" + }, + { + "PublicDescription": "Number of SWOB drains triggered by system register write when SWOB full", + "EventCode": "0xD20A", + "EventName": "IDR_STALL_SWOB_FULL", + "BriefDescription": "Number of SWOB drains triggered by system register write when SWOB full" + }, + { + "PublicDescription": "Dispatch stall due to L1 instruction cache miss", + "EventCode": "0xD20B", + "EventName": "STALL_FRONTEND_CACHE", + "BriefDescription": "Dispatch stall due to L1 instruction cache miss" + }, + { + "PublicDescription": "Dispatch stall due to L1 data cache miss", + "EventCode": "0xD20D", + "EventName": "STALL_BACKEND_CACHE", + "BriefDescription": "Dispatch stall due to L1 data cache miss" + }, + { + "PublicDescription": "Dispatch stall due to lack of any core resource", + "EventCode": "0xD20F", + "EventName": "STALL_BACKEND_RESOURCE", + "BriefDescription": "Dispatch stall due to lack of any core resource" + }, + { + "PublicDescription": "Instructions issued by the scheduler", + "EventCode": "0xD300", + "EventName": "IXU_NUM_UOPS_ISSUED", + "BriefDescription": "Instructions issued by the scheduler" + }, + { + "PublicDescription": "Any uop issued was canceled for any reason", + "EventCode": "0xD301", + "EventName": "IXU_ISSUE_CANCEL", + "BriefDescription": "Any uop issued was canceled for any reason" + }, + { + "PublicDescription": "A load wakeup to the scheduler has been canceled", + "EventCode": "0xD302", + "EventName": "IXU_LOAD_CANCEL", + "BriefDescription": "A load wakeup to the scheduler has been canceled" + }, + { + "PublicDescription": "The scheduler had to cancel one slow Uop due to resource conflict", + "EventCode": "0xD303", + "EventName": "IXU_SLOW_CANCEL", + "BriefDescription": "The scheduler had to cancel one slow Uop due to resource conflict" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXA", + "EventCode": "0xD304", + "EventName": "IXU_IXA_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXA" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXA Par 0", + "EventCode": "0xD305", + "EventName": "IXU_IXA_PAR0_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXA Par 0" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXA Par 1", + "EventCode": "0xD306", + "EventName": "IXU_IXA_PAR1_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXA Par 1" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXB", + "EventCode": "0xD307", + "EventName": "IXU_IXB_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXB" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXB Par 0", + "EventCode": "0xD308", + "EventName": "IXU_IXB_PAR0_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXB Par 0" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXB Par 1", + "EventCode": "0xD309", + "EventName": "IXU_IXB_PAR1_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXB Par 1" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXC", + "EventCode": "0xD30A", + "EventName": "IXU_IXC_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXC" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXC Par 0", + "EventCode": "0xD30B", + "EventName": "IXU_IXC_PAR0_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXC Par 0" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXC Par 1", + "EventCode": "0xD30C", + "EventName": "IXU_IXC_PAR1_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXC Par 1" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXD", + "EventCode": "0xD30D", + "EventName": "IXU_IXD_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXD" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXD Par 0", + "EventCode": "0xD30E", + "EventName": "IXU_IXD_PAR0_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXD Par 0" + }, + { + "PublicDescription": "Uops issued by the scheduler on IXD Par 1", + "EventCode": "0xD30F", + "EventName": "IXU_IXD_PAR1_ISSUED", + "BriefDescription": "Uops issued by the scheduler on IXD Par 1" + }, + { + "PublicDescription": "Uops issued by the FSU scheduler", + "EventCode": "0xD400", + "EventName": "FSU_ISSUED", + "BriefDescription": "Uops issued by the FSU scheduler" + }, + { + "PublicDescription": "Uops issued by the scheduler on FSX", + "EventCode": "0xD401", + "EventName": "FSU_FSX_ISSUED", + "BriefDescription": "Uops issued by the scheduler on FSX" + }, + { + "PublicDescription": "Uops issued by the scheduler on FSY", + "EventCode": "0xD402", + "EventName": "FSU_FSY_ISSUED", + "BriefDescription": "Uops issued by the scheduler on FSY" + }, + { + "PublicDescription": "Uops issued by the scheduler on FSZ", + "EventCode": "0xD403", + "EventName": "FSU_FSZ_ISSUED", + "BriefDescription": "Uops issued by the scheduler on FSZ" + }, + { + "PublicDescription": "Uops canceled (load cancels)", + "EventCode": "0xD404", + "EventName": "FSU_CANCEL", + "BriefDescription": "Uops canceled (load cancels)" + }, + { + "PublicDescription": "Count scheduler stalls due to divide/sqrt", + "EventCode": "0xD405", + "EventName": "FSU_DIV_SQRT_STALL", + "BriefDescription": "Count scheduler stalls due to divide/sqrt" + }, + { + "PublicDescription": "Number of SWOB drains", + "EventCode": "0xD500", + "EventName": "GPC_SWOB_DRAIN", + "BriefDescription": "Number of SWOB drains" + }, + { + "PublicDescription": "GPC detected a Breakpoint instruction match", + "EventCode": "0xD501", + "EventName": "BREAKPOINT_MATCH", + "BriefDescription": "GPC detected a Breakpoint instruction match" + }, + { + "PublicDescription": "Core progress monitor triggered", + "EventCode": "0xd502", + "EventName": "GPC_CPM_TRIGGER", + "BriefDescription": "Core progress monitor triggered" + }, + { + "PublicDescription": "Fill buffer full", + "EventCode": "0xD601", + "EventName": "OFB_FULL", + "BriefDescription": "Fill buffer full" + }, + { + "PublicDescription": "Load satisified from store forwarded data", + "EventCode": "0xD605", + "EventName": "LD_FROM_ST_FWD", + "BriefDescription": "Load satisified from store forwarded data" + }, + { + "PublicDescription": "Store retirement pipe stall", + "EventCode": "0xD60C", + "EventName": "LSU_ST_RETIRE_STALL", + "BriefDescription": "Store retirement pipe stall" + }, + { + "PublicDescription": "LSU detected a Watchpoint data match", + "EventCode": "0xD60D", + "EventName": "WATCHPOINT_MATCH", + "BriefDescription": "LSU detected a Watchpoint data match" + }, + { + "PublicDescription": "Counts cycles that MSC is telling GPC to stall commit due to ETM ISTALL feature", + "EventCode": "0xda00", + "EventName": "MSC_ETM_COMMIT_STALL", + "BriefDescription": "Counts cycles that MSC is telling GPC to stall commit due to ETM ISTALL feature" + } +] diff --git a/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/exception.json b/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/exception.json new file mode 100644 index 0000000000..bd59ba7b74 --- /dev/null +++ b/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/exception.json @@ -0,0 +1,47 @@ +[ + { + "ArchStdEvent": "EXC_UNDEF" + }, + { + "ArchStdEvent": "EXC_SVC" + }, + { + "ArchStdEvent": "EXC_PABORT" + }, + { + "ArchStdEvent": "EXC_DABORT" + }, + { + "ArchStdEvent": "EXC_IRQ" + }, + { + "ArchStdEvent": "EXC_FIQ" + }, + { + "ArchStdEvent": "EXC_HVC" + }, + { + "ArchStdEvent": "EXC_TRAP_PABORT" + }, + { + "ArchStdEvent": "EXC_TRAP_DABORT" + }, + { + "ArchStdEvent": "EXC_TRAP_OTHER" + }, + { + "ArchStdEvent": "EXC_TRAP_IRQ" + }, + { + "ArchStdEvent": "EXC_TRAP_FIQ" + }, + { + "ArchStdEvent": "EXC_TAKEN" + }, + { + "ArchStdEvent": "EXC_RETURN" + }, + { + "ArchStdEvent": "EXC_SMC" + } +] diff --git a/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/instruction.json b/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/instruction.json new file mode 100644 index 0000000000..a6a20f541e --- /dev/null +++ b/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/instruction.json @@ -0,0 +1,128 @@ +[ + { + "ArchStdEvent": "SW_INCR" + }, + { + "ArchStdEvent": "ST_RETIRED" + }, + { + "ArchStdEvent": "LD_SPEC" + }, + { + "ArchStdEvent": "ST_SPEC" + }, + { + "ArchStdEvent": "LDST_SPEC" + }, + { + "ArchStdEvent": "DP_SPEC" + }, + { + "ArchStdEvent": "ASE_SPEC" + }, + { + "ArchStdEvent": "VFP_SPEC" + }, + { + "ArchStdEvent": "PC_WRITE_SPEC" + }, + { + "ArchStdEvent": "BR_IMMED_RETIRED" + }, + { + "ArchStdEvent": "BR_RETURN_RETIRED" + }, + { + "ArchStdEvent": "CRYPTO_SPEC" + }, + { + "ArchStdEvent": "ISB_SPEC" + }, + { + "ArchStdEvent": "DSB_SPEC" + }, + { + "ArchStdEvent": "DMB_SPEC" + }, + { + "ArchStdEvent": "RC_LD_SPEC" + }, + { + "ArchStdEvent": "RC_ST_SPEC" + }, + { + "ArchStdEvent": "INST_RETIRED" + }, + { + "ArchStdEvent": "CID_WRITE_RETIRED" + }, + { + "ArchStdEvent": "PC_WRITE_RETIRED" + }, + { + "ArchStdEvent": "INST_SPEC" + }, + { + "ArchStdEvent": "TTBR_WRITE_RETIRED" + }, + { + "ArchStdEvent": "BR_RETIRED" + }, + { + "ArchStdEvent": "BR_MIS_PRED_RETIRED" + }, + { + "ArchStdEvent": "OP_RETIRED" + }, + { + "ArchStdEvent": "OP_SPEC" + }, + { + "PublicDescription": "Operation speculatively executed - ASE Scalar", + "EventCode": "0xd210", + "EventName": "ASE_SCALAR_SPEC", + "BriefDescription": "Operation speculatively executed - ASE Scalar" + }, + { + "PublicDescription": "Operation speculatively executed - ASE Vector", + "EventCode": "0xd211", + "EventName": "ASE_VECTOR_SPEC", + "BriefDescription": "Operation speculatively executed - ASE Vector" + }, + { + "PublicDescription": "Barrier speculatively executed, CSDB", + "EventCode": "0x7f", + "EventName": "CSDB_SPEC", + "BriefDescription": "Barrier speculatively executed, CSDB" + }, + { + "PublicDescription": "Prefetch sent to L2.", + "EventCode": "0xd106", + "EventName": "ICF_PREFETCH_DISPATCH", + "BriefDescription": "Prefetch sent to L2." + }, + { + "PublicDescription": "Prefetch response received but was dropped since we don't support inflight upgrades.", + "EventCode": "0xd107", + "EventName": "ICF_PREFETCH_DROPPED_NO_UPGRADE", + "BriefDescription": "Prefetch response received but was dropped since we don't support inflight upgrades." + }, + { + "PublicDescription": "Prefetch request missed TLB.", + "EventCode": "0xd108", + "EventName": "ICF_PREFETCH_DROPPED_TLB_MISS", + "BriefDescription": "Prefetch request missed TLB." + }, + { + "PublicDescription": "Prefetch request dropped since duplicate was found in TLB.", + "EventCode": "0xd109", + "EventName": "ICF_PREFETCH_DROPPED_DUPLICATE", + "BriefDescription": "Prefetch request dropped since duplicate was found in TLB." + }, + { + "PublicDescription": "Prefetch request dropped since it was found in cache.", + "EventCode": "0xd10a", + "EventName": "ICF_PREFETCH_DROPPED_CACHE_HIT", + "BriefDescription": "Prefetch request dropped since it was found in cache." + } +] diff --git a/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/intrinsic.json b/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/intrinsic.json new file mode 100644 index 0000000000..7ecffb989a --- /dev/null +++ b/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/intrinsic.json @@ -0,0 +1,14 @@ +[ + { + "ArchStdEvent": "LDREX_SPEC" + }, + { + "ArchStdEvent": "STREX_PASS_SPEC" + }, + { + "ArchStdEvent": "STREX_FAIL_SPEC" + }, + { + "ArchStdEvent": "STREX_SPEC" + } +] diff --git a/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/memory.json b/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/memory.json new file mode 100644 index 0000000000..a211d94aac --- /dev/null +++ b/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/memory.json @@ -0,0 +1,41 @@ +[ + { + "ArchStdEvent": "LD_RETIRED" + }, + { + "ArchStdEvent": "MEM_ACCESS_RD" + }, + { + "ArchStdEvent": "MEM_ACCESS_WR" + }, + { + "ArchStdEvent": "LD_ALIGN_LAT" + }, + { + "ArchStdEvent": "ST_ALIGN_LAT" + }, + { + "ArchStdEvent": "MEM_ACCESS" + }, + { + "ArchStdEvent": "MEMORY_ERROR" + }, + { + "ArchStdEvent": "LDST_ALIGN_LAT" + }, + { + "ArchStdEvent": "MEM_ACCESS_CHECKED" + }, + { + "ArchStdEvent": "MEM_ACCESS_CHECKED_RD" + }, + { + "ArchStdEvent": "MEM_ACCESS_CHECKED_WR" + }, + { + "PublicDescription": "Flushes due to memory hazards", + "EventCode": "0x121", + "EventName": "BPU_FLUSH_MEM_FAULT", + "BriefDescription": "Flushes due to memory hazards" + } +] diff --git a/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/metrics.json b/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/metrics.json new file mode 100644 index 0000000000..c5d1d22bd0 --- /dev/null +++ b/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/metrics.json @@ -0,0 +1,442 @@ +[ + { + "MetricName": "branch_miss_pred_rate", + "MetricExpr": "BR_MIS_PRED / BR_PRED", + "BriefDescription": "Branch predictor misprediction rate. May not count branches that are never resolved because they are in the misprediction shadow of an earlier branch", + "MetricGroup": "branch", + "ScaleUnit": "100%" + }, + { + "MetricName": "bus_utilization", + "MetricExpr": "BUS_ACCESS / (BUS_CYCLES * 1)", + "BriefDescription": "Core-to-uncore bus utilization", + "MetricGroup": "Bus", + "ScaleUnit": "100percent of bus cycles" + }, + { + "MetricName": "l1d_cache_miss_ratio", + "MetricExpr": "L1D_CACHE_REFILL / L1D_CACHE", + "BriefDescription": "This metric measures the ratio of level 1 data cache accesses missed to the total number of level 1 data cache accesses. This gives an indication of the effectiveness of the level 1 data cache.", + "MetricGroup": "Miss_Ratio;L1D_Cache_Effectiveness", + "ScaleUnit": "1per cache access" + }, + { + "MetricName": "l1i_cache_miss_ratio", + "MetricExpr": "L1I_CACHE_REFILL / L1I_CACHE", + "BriefDescription": "This metric measures the ratio of level 1 instruction cache accesses missed to the total number of level 1 instruction cache accesses. This gives an indication of the effectiveness of the level 1 instruction cache.", + "MetricGroup": "Miss_Ratio;L1I_Cache_Effectiveness", + "ScaleUnit": "1per cache access" + }, + { + "MetricName": "Miss_Ratio;l1d_cache_read_miss", + "MetricExpr": "L1D_CACHE_LMISS_RD / L1D_CACHE_RD", + "BriefDescription": "L1D cache read miss rate", + "MetricGroup": "Cache", + "ScaleUnit": "1per cache read access" + }, + { + "MetricName": "l2_cache_miss_ratio", + "MetricExpr": "L2D_CACHE_REFILL / L2D_CACHE", + "BriefDescription": "This metric measures the ratio of level 2 cache accesses missed to the total number of level 2 cache accesses. This gives an indication of the effectiveness of the level 2 cache, which is a unified cache that stores both data and instruction. Note that cache accesses in this cache are either data memory access or instruction fetch as this is a unified cache.", + "MetricGroup": "Miss_Ratio;L2_Cache_Effectiveness", + "ScaleUnit": "1per cache access" + }, + { + "MetricName": "l1i_cache_read_miss_rate", + "MetricExpr": "L1I_CACHE_LMISS / L1I_CACHE", + "BriefDescription": "L1I cache read miss rate", + "MetricGroup": "Cache", + "ScaleUnit": "1per cache access" + }, + { + "MetricName": "l2d_cache_read_miss_rate", + "MetricExpr": "L2D_CACHE_LMISS_RD / L2D_CACHE_RD", + "BriefDescription": "L2 cache read miss rate", + "MetricGroup": "Cache", + "ScaleUnit": "1per cache read access" + }, + { + "MetricName": "l1d_cache_miss_mpki", + "MetricExpr": "(L1D_CACHE_LMISS_RD * 1e3) / INST_RETIRED", + "BriefDescription": "Misses per thousand instructions (data)", + "MetricGroup": "Cache", + "ScaleUnit": "1MPKI" + }, + { + "MetricName": "l1i_cache_miss_mpki", + "MetricExpr": "(L1I_CACHE_LMISS * 1e3) / INST_RETIRED", + "BriefDescription": "Misses per thousand instructions (instruction)", + "MetricGroup": "Cache", + "ScaleUnit": "1MPKI" + }, + { + "MetricName": "simd_percentage", + "MetricExpr": "ASE_SPEC / INST_SPEC", + "BriefDescription": "This metric measures advanced SIMD operations as a percentage of total operations speculatively executed.", + "MetricGroup": "Operation_Mix", + "ScaleUnit": "100percent of operations" + }, + { + "MetricName": "crypto_percentage", + "MetricExpr": "CRYPTO_SPEC / INST_SPEC", + "BriefDescription": "This metric measures crypto operations as a percentage of operations speculatively executed.", + "MetricGroup": "Operation_Mix", + "ScaleUnit": "100percent of operations" + }, + { + "MetricName": "gflops", + "MetricExpr": "VFP_SPEC / (duration_time * 1e9)", + "BriefDescription": "Giga-floating point operations per second", + "MetricGroup": "InstructionMix" + }, + { + "MetricName": "integer_dp_percentage", + "MetricExpr": "DP_SPEC / INST_SPEC", + "BriefDescription": "This metric measures scalar integer operations as a percentage of operations speculatively executed.", + "MetricGroup": "Operation_Mix", + "ScaleUnit": "100percent of operations" + }, + { + "MetricName": "ipc", + "MetricExpr": "INST_RETIRED / CPU_CYCLES", + "BriefDescription": "This metric measures the number of instructions retired per cycle.", + "MetricGroup": "General", + "ScaleUnit": "1per cycle" + }, + { + "MetricName": "load_percentage", + "MetricExpr": "LD_SPEC / INST_SPEC", + "BriefDescription": "This metric measures load operations as a percentage of operations speculatively executed.", + "MetricGroup": "Operation_Mix", + "ScaleUnit": "100percent of operations" + }, + { + "MetricName": "load_store_spec_rate", + "MetricExpr": "LDST_SPEC / INST_SPEC", + "BriefDescription": "The rate of load or store instructions speculatively executed to overall instructions speclatively executed", + "MetricGroup": "Operation_Mix", + "ScaleUnit": "100percent of operations" + }, + { + "MetricName": "retired_mips", + "MetricExpr": "INST_RETIRED / (duration_time * 1e6)", + "BriefDescription": "Millions of instructions per second", + "MetricGroup": "InstructionMix" + }, + { + "MetricName": "spec_utilization_mips", + "MetricExpr": "INST_SPEC / (duration_time * 1e6)", + "BriefDescription": "Millions of instructions per second", + "MetricGroup": "PEutilization" + }, + { + "MetricName": "pc_write_spec_rate", + "MetricExpr": "PC_WRITE_SPEC / INST_SPEC", + "BriefDescription": "The rate of software change of the PC speculatively executed to overall instructions speclatively executed", + "MetricGroup": "Operation_Mix", + "ScaleUnit": "100percent of operations" + }, + { + "MetricName": "store_percentage", + "MetricExpr": "ST_SPEC / INST_SPEC", + "BriefDescription": "This metric measures store operations as a percentage of operations speculatively executed.", + "MetricGroup": "Operation_Mix", + "ScaleUnit": "100percent of operations" + }, + { + "MetricName": "scalar_fp_percentage", + "MetricExpr": "VFP_SPEC / INST_SPEC", + "BriefDescription": "This metric measures scalar floating point operations as a percentage of operations speculatively executed.", + "MetricGroup": "Operation_Mix", + "ScaleUnit": "100percent of operations" + }, + { + "MetricName": "retired_rate", + "MetricExpr": "OP_RETIRED / OP_SPEC", + "BriefDescription": "Of all the micro-operations issued, what percentage are retired(committed)", + "MetricGroup": "General", + "ScaleUnit": "100%" + }, + { + "MetricName": "wasted", + "MetricExpr": "1 - (OP_RETIRED / (CPU_CYCLES * #slots))", + "BriefDescription": "Of all the micro-operations issued, what proportion are lost", + "MetricGroup": "General", + "ScaleUnit": "100%" + }, + { + "MetricName": "wasted_rate", + "MetricExpr": "1 - OP_RETIRED / OP_SPEC", + "BriefDescription": "Of all the micro-operations issued, what percentage are not retired(committed)", + "MetricGroup": "General", + "ScaleUnit": "100%" + }, + { + "MetricName": "stall_backend_cache_rate", + "MetricExpr": "STALL_BACKEND_CACHE / CPU_CYCLES", + "BriefDescription": "Proportion of cycles stalled and no operations issued to backend and cache miss", + "MetricGroup": "Stall", + "ScaleUnit": "100percent of cycles" + }, + { + "MetricName": "stall_backend_resource_rate", + "MetricExpr": "STALL_BACKEND_RESOURCE / CPU_CYCLES", + "BriefDescription": "Proportion of cycles stalled and no operations issued to backend and resource full", + "MetricGroup": "Stall", + "ScaleUnit": "100percent of cycles" + }, + { + "MetricName": "stall_backend_tlb_rate", + "MetricExpr": "STALL_BACKEND_TLB / CPU_CYCLES", + "BriefDescription": "Proportion of cycles stalled and no operations issued to backend and TLB miss", + "MetricGroup": "Stall", + "ScaleUnit": "100percent of cycles" + }, + { + "MetricName": "stall_frontend_cache_rate", + "MetricExpr": "STALL_FRONTEND_CACHE / CPU_CYCLES", + "BriefDescription": "Proportion of cycles stalled and no ops delivered from frontend and cache miss", + "MetricGroup": "Stall", + "ScaleUnit": "100percent of cycles" + }, + { + "MetricName": "stall_frontend_tlb_rate", + "MetricExpr": "STALL_FRONTEND_TLB / CPU_CYCLES", + "BriefDescription": "Proportion of cycles stalled and no ops delivered from frontend and TLB miss", + "MetricGroup": "Stall", + "ScaleUnit": "100percent of cycles" + }, + { + "MetricName": "dtlb_walk_ratio", + "MetricExpr": "DTLB_WALK / L1D_TLB", + "BriefDescription": "This metric measures the ratio of data TLB Walks to the total number of data TLB accesses. This gives an indication of the effectiveness of the data TLB accesses.", + "MetricGroup": "Miss_Ratio;DTLB_Effectiveness", + "ScaleUnit": "1per TLB access" + }, + { + "MetricName": "itlb_walk_ratio", + "MetricExpr": "ITLB_WALK / L1I_TLB", + "BriefDescription": "This metric measures the ratio of instruction TLB Walks to the total number of instruction TLB accesses. This gives an indication of the effectiveness of the instruction TLB accesses.", + "MetricGroup": "Miss_Ratio;ITLB_Effectiveness", + "ScaleUnit": "1per TLB access" + }, + { + "ArchStdEvent": "backend_bound" + }, + { + "ArchStdEvent": "frontend_bound", + "MetricExpr": "100 - (retired_fraction + slots_lost_misspeculation_fraction + backend_bound)" + }, + { + "MetricName": "slots_lost_misspeculation_fraction", + "MetricExpr": "(OP_SPEC - OP_RETIRED) / (CPU_CYCLES * #slots)", + "BriefDescription": "Fraction of slots lost due to misspeculation", + "DefaultMetricgroupName": "TopdownL1", + "MetricGroup": "Default;TopdownL1", + "ScaleUnit": "100percent of slots" + }, + { + "MetricName": "retired_fraction", + "MetricExpr": "OP_RETIRED / (CPU_CYCLES * #slots)", + "BriefDescription": "Fraction of slots retiring, useful work", + "DefaultMetricgroupName": "TopdownL1", + "MetricGroup": "Default;TopdownL1", + "ScaleUnit": "100percent of slots" + }, + { + "MetricName": "backend_core", + "MetricExpr": "(backend_bound / 100) - backend_memory", + "BriefDescription": "Fraction of slots the CPU was stalled due to backend non-memory subsystem issues", + "MetricGroup": "TopdownL2", + "ScaleUnit": "100%" + }, + { + "MetricName": "backend_memory", + "MetricExpr": "(STALL_BACKEND_TLB + STALL_BACKEND_CACHE) / CPU_CYCLES", + "BriefDescription": "Fraction of slots the CPU was stalled due to backend memory subsystem issues (cache/tlb miss)", + "MetricGroup": "TopdownL2", + "ScaleUnit": "100%" + }, + { + "MetricName": "branch_mispredict", + "MetricExpr": "(BR_MIS_PRED_RETIRED / GPC_FLUSH) * slots_lost_misspeculation_fraction", + "BriefDescription": "Fraction of slots lost due to branch misprediciton", + "MetricGroup": "TopdownL2", + "ScaleUnit": "1percent of slots" + }, + { + "MetricName": "frontend_bandwidth", + "MetricExpr": "frontend_bound - frontend_latency", + "BriefDescription": "Fraction of slots the CPU did not dispatch at full bandwidth - able to dispatch partial slots only (1, 2, or 3 uops)", + "MetricGroup": "TopdownL2", + "ScaleUnit": "1percent of slots" + }, + { + "MetricName": "frontend_latency", + "MetricExpr": "(STALL_FRONTEND - ((STALL_SLOT_FRONTEND - ((frontend_bound / 100) * CPU_CYCLES * #slots)) / #slots)) / CPU_CYCLES", + "BriefDescription": "Fraction of slots the CPU was stalled due to frontend latency issues (cache/tlb miss); nothing to dispatch", + "MetricGroup": "TopdownL2", + "ScaleUnit": "100percent of slots" + }, + { + "MetricName": "other_miss_pred", + "MetricExpr": "slots_lost_misspeculation_fraction - branch_mispredict", + "BriefDescription": "Fraction of slots lost due to other/non-branch misprediction misspeculation", + "MetricGroup": "TopdownL2", + "ScaleUnit": "1percent of slots" + }, + { + "MetricName": "pipe_utilization", + "MetricExpr": "100 * ((IXU_NUM_UOPS_ISSUED + FSU_ISSUED) / (CPU_CYCLES * 6))", + "BriefDescription": "Fraction of execute slots utilized", + "MetricGroup": "TopdownL2", + "ScaleUnit": "1percent of slots" + }, + { + "MetricName": "d_cache_l2_miss_rate", + "MetricExpr": "STALL_BACKEND_MEM / CPU_CYCLES", + "BriefDescription": "Fraction of cycles the CPU was stalled due to data L2 cache miss", + "MetricGroup": "TopdownL3", + "ScaleUnit": "100percent of cycles" + }, + { + "MetricName": "d_cache_miss_rate", + "MetricExpr": "STALL_BACKEND_CACHE / CPU_CYCLES", + "BriefDescription": "Fraction of cycles the CPU was stalled due to data cache miss", + "MetricGroup": "TopdownL3", + "ScaleUnit": "100percent of cycles" + }, + { + "MetricName": "d_tlb_miss_rate", + "MetricExpr": "STALL_BACKEND_TLB / CPU_CYCLES", + "BriefDescription": "Fraction of cycles the CPU was stalled due to data TLB miss", + "MetricGroup": "TopdownL3", + "ScaleUnit": "100percent of cycles" + }, + { + "MetricName": "fsu_pipe_utilization", + "MetricExpr": "FSU_ISSUED / (CPU_CYCLES * 2)", + "BriefDescription": "Fraction of FSU execute slots utilized", + "MetricGroup": "TopdownL3", + "ScaleUnit": "100percent of slots" + }, + { + "MetricName": "i_cache_miss_rate", + "MetricExpr": "STALL_FRONTEND_CACHE / CPU_CYCLES", + "BriefDescription": "Fraction of cycles the CPU was stalled due to instruction cache miss", + "MetricGroup": "TopdownL3", + "ScaleUnit": "100percent of slots" + }, + { + "MetricName": "i_tlb_miss_rate", + "MetricExpr": "STALL_FRONTEND_TLB / CPU_CYCLES", + "BriefDescription": "Fraction of cycles the CPU was stalled due to instruction TLB miss", + "MetricGroup": "TopdownL3", + "ScaleUnit": "100percent of slots" + }, + { + "MetricName": "ixu_pipe_utilization", + "MetricExpr": "IXU_NUM_UOPS_ISSUED / (CPU_CYCLES * #slots)", + "BriefDescription": "Fraction of IXU execute slots utilized", + "MetricGroup": "TopdownL3", + "ScaleUnit": "100percent of slots" + }, + { + "MetricName": "stall_recovery_rate", + "MetricExpr": "IDR_STALL_FLUSH / CPU_CYCLES", + "BriefDescription": "Fraction of cycles the CPU was stalled due to flush recovery", + "MetricGroup": "TopdownL3", + "ScaleUnit": "100percent of slots" + }, + { + "MetricName": "stall_fsu_sched_rate", + "MetricExpr": "IDR_STALL_FSU_SCHED / CPU_CYCLES", + "BriefDescription": "Fraction of cycles the CPU was stalled and FSU was full", + "MetricGroup": "TopdownL4", + "ScaleUnit": "100percent of cycles" + }, + { + "MetricName": "stall_ixu_sched_rate", + "MetricExpr": "IDR_STALL_IXU_SCHED / CPU_CYCLES", + "BriefDescription": "Fraction of cycles the CPU was stalled and IXU was full", + "MetricGroup": "TopdownL4", + "ScaleUnit": "100percent of cycles" + }, + { + "MetricName": "stall_lob_id_rate", + "MetricExpr": "IDR_STALL_LOB_ID / CPU_CYCLES", + "BriefDescription": "Fraction of cycles the CPU was stalled and LOB was full", + "MetricGroup": "TopdownL4", + "ScaleUnit": "100percent of cycles" + }, + { + "MetricName": "stall_rob_id_rate", + "MetricExpr": "IDR_STALL_ROB_ID / CPU_CYCLES", + "BriefDescription": "Fraction of cycles the CPU was stalled and ROB was full", + "MetricGroup": "TopdownL4", + "ScaleUnit": "100percent of cycles" + }, + { + "MetricName": "stall_sob_id_rate", + "MetricExpr": "IDR_STALL_SOB_ID / CPU_CYCLES", + "BriefDescription": "Fraction of cycles the CPU was stalled and SOB was full", + "MetricGroup": "TopdownL4", + "ScaleUnit": "100percent of cycles" + }, + { + "MetricName": "l1d_cache_access_demand", + "MetricExpr": "L1D_CACHE_RW / L1D_CACHE", + "BriefDescription": "L1D cache access - demand", + "MetricGroup": "Cache", + "ScaleUnit": "100percent of cache acceses" + }, + { + "MetricName": "l1d_cache_access_prefetces", + "MetricExpr": "L1D_CACHE_PRFM / L1D_CACHE", + "BriefDescription": "L1D cache access - prefetch", + "MetricGroup": "Cache", + "ScaleUnit": "100percent of cache acceses" + }, + { + "MetricName": "l1d_cache_demand_misses", + "MetricExpr": "L1D_CACHE_REFILL_RW / L1D_CACHE", + "BriefDescription": "L1D cache demand misses", + "MetricGroup": "Cache", + "ScaleUnit": "100percent of cache acceses" + }, + { + "MetricName": "l1d_cache_demand_misses_read", + "MetricExpr": "L1D_CACHE_REFILL_RD / L1D_CACHE", + "BriefDescription": "L1D cache demand misses - read", + "MetricGroup": "Cache", + "ScaleUnit": "100percent of cache acceses" + }, + { + "MetricName": "l1d_cache_demand_misses_write", + "MetricExpr": "L1D_CACHE_REFILL_WR / L1D_CACHE", + "BriefDescription": "L1D cache demand misses - write", + "MetricGroup": "Cache", + "ScaleUnit": "100percent of cache acceses" + }, + { + "MetricName": "l1d_cache_prefetch_misses", + "MetricExpr": "L1D_CACHE_REFILL_PRFM / L1D_CACHE", + "BriefDescription": "L1D cache prefetch misses", + "MetricGroup": "Cache", + "ScaleUnit": "100percent of cache acceses" + }, + { + "MetricName": "ase_scalar_mix", + "MetricExpr": "ASE_SCALAR_SPEC / OP_SPEC", + "BriefDescription": "Proportion of advanced SIMD data processing operations (excluding DP_SPEC/LD_SPEC) scalar operations", + "MetricGroup": "Instructions", + "ScaleUnit": "100percent of cache acceses" + }, + { + "MetricName": "ase_vector_mix", + "MetricExpr": "ASE_VECTOR_SPEC / OP_SPEC", + "BriefDescription": "Proportion of advanced SIMD data processing operations (excluding DP_SPEC/LD_SPEC) vector operations", + "MetricGroup": "Instructions", + "ScaleUnit": "100percent of cache acceses" + } +] diff --git a/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/mmu.json b/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/mmu.json new file mode 100644 index 0000000000..66d83b6806 --- /dev/null +++ b/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/mmu.json @@ -0,0 +1,170 @@ +[ + { + "PublicDescription": "Level 2 data translation buffer allocation", + "EventCode": "0xD800", + "EventName": "MMU_D_OTB_ALLOC", + "BriefDescription": "Level 2 data translation buffer allocation" + }, + { + "PublicDescription": "Data TLB translation cache hit on S1L2 walk cache entry", + "EventCode": "0xd801", + "EventName": "MMU_D_TRANS_CACHE_HIT_S1L2_WALK", + "BriefDescription": "Data TLB translation cache hit on S1L2 walk cache entry" + }, + { + "PublicDescription": "Data TLB translation cache hit on S1L1 walk cache entry", + "EventCode": "0xd802", + "EventName": "MMU_D_TRANS_CACHE_HIT_S1L1_WALK", + "BriefDescription": "Data TLB translation cache hit on S1L1 walk cache entry" + }, + { + "PublicDescription": "Data TLB translation cache hit on S1L0 walk cache entry", + "EventCode": "0xd803", + "EventName": "MMU_D_TRANS_CACHE_HIT_S1L0_WALK", + "BriefDescription": "Data TLB translation cache hit on S1L0 walk cache entry" + }, + { + "PublicDescription": "Data TLB translation cache hit on S2L2 walk cache entry", + "EventCode": "0xd804", + "EventName": "MMU_D_TRANS_CACHE_HIT_S2L2_WALK", + "BriefDescription": "Data TLB translation cache hit on S2L2 walk cache entry" + }, + { + "PublicDescrition": "Data TLB translation cache hit on S2L1 walk cache entry", + "EventCode": "0xd805", + "EventName": "MMU_D_TRANS_CACHE_HIT_S2L1_WALK", + "BriefDescription": "Data TLB translation cache hit on S2L1 walk cache entry" + }, + { + "PublicDescrition": "Data TLB translation cache hit on S2L0 walk cache entry", + "EventCode": "0xd806", + "EventName": "MMU_D_TRANS_CACHE_HIT_S2L0_WALK", + "BriefDescription": "Data TLB translation cache hit on S2L0 walk cache entry" + }, + { + "PublicDescrition": "Data-side S1 page walk cache lookup", + "EventCode": "0xd807", + "EventName": "MMU_D_S1_WALK_CACHE_LOOKUP", + "BriefDescription": "Data-side S1 page walk cache lookup" + }, + { + "PublicDescrition": "Data-side S1 page walk cache refill", + "EventCode": "0xd808", + "EventName": "MMU_D_S1_WALK_CACHE_REFILL", + "BriefDescription": "Data-side S1 page walk cache refill" + }, + { + "PublicDescrition": "Data-side S2 page walk cache lookup", + "EventCode": "0xd809", + "EventName": "MMU_D_S2_WALK_CACHE_LOOKUP", + "BriefDescription": "Data-side S2 page walk cache lookup" + }, + { + "PublicDescrition": "Data-side S2 page walk cache refill", + "EventCode": "0xd80a", + "EventName": "MMU_D_S2_WALK_CACHE_REFILL", + "BriefDescription": "Data-side S2 page walk cache refill" + }, + { + "PublicDescription": "Data-side S1 table walk fault", + "EventCode": "0xD80B", + "EventName": "MMU_D_S1_WALK_FAULT", + "BriefDescription": "Data-side S1 table walk fault" + }, + { + "PublicDescription": "Data-side S2 table walk fault", + "EventCode": "0xD80C", + "EventName": "MMU_D_S2_WALK_FAULT", + "BriefDescription": "Data-side S2 table walk fault" + }, + { + "PublicDescription": "Data-side table walk steps or descriptor fetches", + "EventCode": "0xD80D", + "EventName": "MMU_D_WALK_STEPS", + "BriefDescription": "Data-side table walk steps or descriptor fetches" + }, + { + "PublicDescription": "Level 2 instruction translation buffer allocation", + "EventCode": "0xD900", + "EventName": "MMU_I_OTB_ALLOC", + "BriefDescription": "Level 2 instruction translation buffer allocation" + }, + { + "PublicDescrition": "Instruction TLB translation cache hit on S1L2 walk cache entry", + "EventCode": "0xd901", + "EventName": "MMU_I_TRANS_CACHE_HIT_S1L2_WALK", + "BriefDescription": "Instruction TLB translation cache hit on S1L2 walk cache entry" + }, + { + "PublicDescrition": "Instruction TLB translation cache hit on S1L1 walk cache entry", + "EventCode": "0xd902", + "EventName": "MMU_I_TRANS_CACHE_HIT_S1L1_WALK", + "BriefDescription": "Instruction TLB translation cache hit on S1L1 walk cache entry" + }, + { + "PublicDescrition": "Instruction TLB translation cache hit on S1L0 walk cache entry", + "EventCode": "0xd903", + "EventName": "MMU_I_TRANS_CACHE_HIT_S1L0_WALK", + "BriefDescription": "Instruction TLB translation cache hit on S1L0 walk cache entry" + }, + { + "PublicDescrition": "Instruction TLB translation cache hit on S2L2 walk cache entry", + "EventCode": "0xd904", + "EventName": "MMU_I_TRANS_CACHE_HIT_S2L2_WALK", + "BriefDescription": "Instruction TLB translation cache hit on S2L2 walk cache entry" + }, + { + "PublicDescrition": "Instruction TLB translation cache hit on S2L1 walk cache entry", + "EventCode": "0xd905", + "EventName": "MMU_I_TRANS_CACHE_HIT_S2L1_WALK", + "BriefDescription": "Instruction TLB translation cache hit on S2L1 walk cache entry" + }, + { + "PublicDescrition": "Instruction TLB translation cache hit on S2L0 walk cache entry", + "EventCode": "0xd906", + "EventName": "MMU_I_TRANS_CACHE_HIT_S2L0_WALK", + "BriefDescription": "Instruction TLB translation cache hit on S2L0 walk cache entry" + }, + { + "PublicDescrition": "Instruction-side S1 page walk cache lookup", + "EventCode": "0xd907", + "EventName": "MMU_I_S1_WALK_CACHE_LOOKUP", + "BriefDescription": "Instruction-side S1 page walk cache lookup" + }, + { + "PublicDescrition": "Instruction-side S1 page walk cache refill", + "EventCode": "0xd908", + "EventName": "MMU_I_S1_WALK_CACHE_REFILL", + "BriefDescription": "Instruction-side S1 page walk cache refill" + }, + { + "PublicDescrition": "Instruction-side S2 page walk cache lookup", + "EventCode": "0xd909", + "EventName": "MMU_I_S2_WALK_CACHE_LOOKUP", + "BriefDescription": "Instruction-side S2 page walk cache lookup" + }, + { + "PublicDescrition": "Instruction-side S2 page walk cache refill", + "EventCode": "0xd90a", + "EventName": "MMU_I_S2_WALK_CACHE_REFILL", + "BriefDescription": "Instruction-side S2 page walk cache refill" + }, + { + "PublicDescription": "Instruction-side S1 table walk fault", + "EventCode": "0xD90B", + "EventName": "MMU_I_S1_WALK_FAULT", + "BriefDescription": "Instruction-side S1 table walk fault" + }, + { + "PublicDescription": "Instruction-side S2 table walk fault", + "EventCode": "0xD90C", + "EventName": "MMU_I_S2_WALK_FAULT", + "BriefDescription": "Instruction-side S2 table walk fault" + }, + { + "PublicDescription": "Instruction-side table walk steps or descriptor fetches", + "EventCode": "0xD90D", + "EventName": "MMU_I_WALK_STEPS", + "BriefDescription": "Instruction-side table walk steps or descriptor fetches" + } +] diff --git a/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/pipeline.json b/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/pipeline.json new file mode 100644 index 0000000000..2fb2d1f183 --- /dev/null +++ b/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/pipeline.json @@ -0,0 +1,41 @@ +[ + { + "ArchStdEvent": "STALL_FRONTEND", + "Errata": "Errata AC03_CPU_29", + "BriefDescription": "Impacted by errata, use metrics instead -" + }, + { + "ArchStdEvent": "STALL_BACKEND" + }, + { + "ArchStdEvent": "STALL", + "Errata": "Errata AC03_CPU_29", + "BriefDescription": "Impacted by errata, use metrics instead -" + }, + { + "ArchStdEvent": "STALL_SLOT_BACKEND" + }, + { + "ArchStdEvent": "STALL_SLOT_FRONTEND", + "Errata": "Errata AC03_CPU_29", + "BriefDescription": "Impacted by errata, use metrics instead -" + }, + { + "ArchStdEvent": "STALL_SLOT" + }, + { + "ArchStdEvent": "STALL_BACKEND_MEM" + }, + { + "PublicDescription": "Frontend stall cycles, TLB", + "EventCode": "0x815c", + "EventName": "STALL_FRONTEND_TLB", + "BriefDescription": "Frontend stall cycles, TLB" + }, + { + "PublicDescription": "Backend stall cycles, TLB", + "EventCode": "0x8167", + "EventName": "STALL_BACKEND_TLB", + "BriefDescription": "Backend stall cycles, TLB" + } +] diff --git a/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/spe.json b/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/spe.json new file mode 100644 index 0000000000..20f2165c85 --- /dev/null +++ b/tools/perf/pmu-events/arch/arm64/ampere/ampereonex/spe.json @@ -0,0 +1,14 @@ +[ + { + "ArchStdEvent": "SAMPLE_POP" + }, + { + "ArchStdEvent": "SAMPLE_FEED" + }, + { + "ArchStdEvent": "SAMPLE_FILTRATE" + }, + { + "ArchStdEvent": "SAMPLE_COLLISION" + } +] diff --git a/tools/perf/pmu-events/arch/arm64/mapfile.csv b/tools/perf/pmu-events/arch/arm64/mapfile.csv index 5b58db5032..f4d1ca4d14 100644 --- a/tools/perf/pmu-events/arch/arm64/mapfile.csv +++ b/tools/perf/pmu-events/arch/arm64/mapfile.csv @@ -42,3 +42,4 @@ 0x00000000480fd010,v1,hisilicon/hip08,core 0x00000000500f0000,v1,ampere/emag,core 0x00000000c00fac30,v1,ampere/ampereone,core +0x00000000c00fac40,v1,ampere/ampereonex,core diff --git a/tools/perf/pmu-events/arch/powerpc/mapfile.csv b/tools/perf/pmu-events/arch/powerpc/mapfile.csv index f4908af7ad..599a588dbe 100644 --- a/tools/perf/pmu-events/arch/powerpc/mapfile.csv +++ b/tools/perf/pmu-events/arch/powerpc/mapfile.csv @@ -11,8 +11,7 @@ # # Multiple PVRs could map to a single JSON file. # - -# Power8 entries 0x004[bcd][[:xdigit:]]{4},1,power8,core +0x0066[[:xdigit:]]{4},1,power8,core 0x004e[[:xdigit:]]{4},1,power9,core 0x0080[[:xdigit:]]{4},1,power10,core diff --git a/tools/perf/pmu-events/arch/riscv/mapfile.csv b/tools/perf/pmu-events/arch/riscv/mapfile.csv index c61b3d6ef6..cfc449b198 100644 --- a/tools/perf/pmu-events/arch/riscv/mapfile.csv +++ b/tools/perf/pmu-events/arch/riscv/mapfile.csv @@ -15,3 +15,5 @@ # #MVENDORID-MARCHID-MIMPID,Version,Filename,EventType 0x489-0x8000000000000007-0x[[:xdigit:]]+,v1,sifive/u74,core +0x5b7-0x0-0x0,v1,thead/c900-legacy,core +0x67e-0x80000000db0000[89]0-0x[[:xdigit:]]+,v1,starfive/dubhe-80,core diff --git a/tools/perf/pmu-events/arch/riscv/starfive/dubhe-80/common.json b/tools/perf/pmu-events/arch/riscv/starfive/dubhe-80/common.json new file mode 100644 index 0000000000..fbffcacb2a --- /dev/null +++ b/tools/perf/pmu-events/arch/riscv/starfive/dubhe-80/common.json @@ -0,0 +1,172 @@ +[ + { + "EventName": "ACCESS_MMU_STLB", + "EventCode": "0x1", + "BriefDescription": "access MMU STLB" + }, + { + "EventName": "MISS_MMU_STLB", + "EventCode": "0x2", + "BriefDescription": "miss MMU STLB" + }, + { + "EventName": "ACCESS_MMU_PTE_C", + "EventCode": "0x3", + "BriefDescription": "access MMU PTE-Cache" + }, + { + "EventName": "MISS_MMU_PTE_C", + "EventCode": "0x4", + "BriefDescription": "miss MMU PTE-Cache" + }, + { + "EventName": "ROB_FLUSH", + "EventCode": "0x5", + "BriefDescription": "ROB flush (all kinds of exceptions)" + }, + { + "EventName": "BTB_PREDICTION_MISS", + "EventCode": "0x6", + "BriefDescription": "BTB prediction miss" + }, + { + "EventName": "ITLB_MISS", + "EventCode": "0x7", + "BriefDescription": "ITLB miss" + }, + { + "EventName": "SYNC_DEL_FETCH_G", + "EventCode": "0x8", + "BriefDescription": "SYNC delivery a fetch-group" + }, + { + "EventName": "ICACHE_MISS", + "EventCode": "0x9", + "BriefDescription": "ICache miss" + }, + { + "EventName": "BPU_BR_RETIRE", + "EventCode": "0xA", + "BriefDescription": "condition branch instruction retire" + }, + { + "EventName": "BPU_BR_MISS", + "EventCode": "0xB", + "BriefDescription": "condition branch instruction miss" + }, + { + "EventName": "RET_INS_RETIRE", + "EventCode": "0xC", + "BriefDescription": "return instruction retire" + }, + { + "EventName": "RET_INS_MISS", + "EventCode": "0xD", + "BriefDescription": "return instruction miss" + }, + { + "EventName": "INDIRECT_JR_MISS", + "EventCode": "0xE", + "BriefDescription": "indirect JR instruction miss (inlcude without target)" + }, + { + "EventName": "IBUF_VAL_ID_NORDY", + "EventCode": "0xF", + "BriefDescription": "IBUF valid while ID not ready" + }, + { + "EventName": "IBUF_NOVAL_ID_RDY", + "EventCode": "0x10", + "BriefDescription": "IBUF not valid while ID ready" + }, + { + "EventName": "REN_INT_PHY_REG_NORDY", + "EventCode": "0x11", + "BriefDescription": "REN integer physical register file is not ready" + }, + { + "EventName": "REN_FP_PHY_REG_NORDY", + "EventCode": "0x12", + "BriefDescription": "REN floating point physical register file is not ready" + }, + { + "EventName": "REN_CP_NORDY", + "EventCode": "0x13", + "BriefDescription": "REN checkpoint is not ready" + }, + { + "EventName": "DEC_VAL_ROB_NORDY", + "EventCode": "0x14", + "BriefDescription": "DEC is valid and ROB is not ready" + }, + { + "EventName": "OOD_FLUSH_LS_DEP", + "EventCode": "0x15", + "BriefDescription": "out of order flush due to load/store dependency" + }, + { + "EventName": "BRU_RET_IJR_INS", + "EventCode": "0x16", + "BriefDescription": "BRU retire an IJR instruction" + }, + { + "EventName": "ACCESS_DTLB", + "EventCode": "0x17", + "BriefDescription": "access DTLB" + }, + { + "EventName": "MISS_DTLB", + "EventCode": "0x18", + "BriefDescription": "miss DTLB" + }, + { + "EventName": "LOAD_INS_DCACHE", + "EventCode": "0x19", + "BriefDescription": "load instruction access DCache" + }, + { + "EventName": "LOAD_INS_MISS_DCACHE", + "EventCode": "0x1A", + "BriefDescription": "load instruction miss DCache" + }, + { + "EventName": "STORE_INS_DCACHE", + "EventCode": "0x1B", + "BriefDescription": "store/amo instruction access DCache" + }, + { + "EventName": "STORE_INS_MISS_DCACHE", + "EventCode": "0x1C", + "BriefDescription": "store/amo instruction miss DCache" + }, + { + "EventName": "LOAD_SCACHE", + "EventCode": "0x1D", + "BriefDescription": "load access SCache" + }, + { + "EventName": "STORE_SCACHE", + "EventCode": "0x1E", + "BriefDescription": "store access SCache" + }, + { + "EventName": "LOAD_MISS_SCACHE", + "EventCode": "0x1F", + "BriefDescription": "load miss SCache" + }, + { + "EventName": "STORE_MISS_SCACHE", + "EventCode": "0x20", + "BriefDescription": "store miss SCache" + }, + { + "EventName": "L2C_PF_REQ", + "EventCode": "0x21", + "BriefDescription": "L2C data-prefetcher request" + }, + { + "EventName": "L2C_PF_HIT", + "EventCode": "0x22", + "BriefDescription": "L2C data-prefetcher hit" + } +] diff --git a/tools/perf/pmu-events/arch/riscv/starfive/dubhe-80/firmware.json b/tools/perf/pmu-events/arch/riscv/starfive/dubhe-80/firmware.json new file mode 100644 index 0000000000..9b4a032186 --- /dev/null +++ b/tools/perf/pmu-events/arch/riscv/starfive/dubhe-80/firmware.json @@ -0,0 +1,68 @@ +[ + { + "ArchStdEvent": "FW_MISALIGNED_LOAD" + }, + { + "ArchStdEvent": "FW_MISALIGNED_STORE" + }, + { + "ArchStdEvent": "FW_ACCESS_LOAD" + }, + { + "ArchStdEvent": "FW_ACCESS_STORE" + }, + { + "ArchStdEvent": "FW_ILLEGAL_INSN" + }, + { + "ArchStdEvent": "FW_SET_TIMER" + }, + { + "ArchStdEvent": "FW_IPI_SENT" + }, + { + "ArchStdEvent": "FW_IPI_RECEIVED" + }, + { + "ArchStdEvent": "FW_FENCE_I_SENT" + }, + { + "ArchStdEvent": "FW_FENCE_I_RECEIVED" + }, + { + "ArchStdEvent": "FW_SFENCE_VMA_SENT" + }, + { + "ArchStdEvent": "FW_SFENCE_VMA_RECEIVED" + }, + { + "ArchStdEvent": "FW_SFENCE_VMA_RECEIVED" + }, + { + "ArchStdEvent": "FW_SFENCE_VMA_ASID_RECEIVED" + }, + { + "ArchStdEvent": "FW_HFENCE_GVMA_SENT" + }, + { + "ArchStdEvent": "FW_HFENCE_GVMA_RECEIVED" + }, + { + "ArchStdEvent": "FW_HFENCE_GVMA_VMID_SENT" + }, + { + "ArchStdEvent": "FW_HFENCE_GVMA_VMID_RECEIVED" + }, + { + "ArchStdEvent": "FW_HFENCE_VVMA_SENT" + }, + { + "ArchStdEvent": "FW_HFENCE_VVMA_RECEIVED" + }, + { + "ArchStdEvent": "FW_HFENCE_VVMA_ASID_SENT" + }, + { + "ArchStdEvent": "FW_HFENCE_VVMA_ASID_RECEIVED" + } +] diff --git a/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/cache.json b/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/cache.json new file mode 100644 index 0000000000..2b142348d6 --- /dev/null +++ b/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/cache.json @@ -0,0 +1,67 @@ +[ + { + "EventName": "L1_ICACHE_ACCESS", + "EventCode": "0x00000001", + "BriefDescription": "L1 instruction cache access" + }, + { + "EventName": "L1_ICACHE_MISS", + "EventCode": "0x00000002", + "BriefDescription": "L1 instruction cache miss" + }, + { + "EventName": "ITLB_MISS", + "EventCode": "0x00000003", + "BriefDescription": "I-UTLB miss" + }, + { + "EventName": "DTLB_MISS", + "EventCode": "0x00000004", + "BriefDescription": "D-UTLB miss" + }, + { + "EventName": "JTLB_MISS", + "EventCode": "0x00000005", + "BriefDescription": "JTLB miss" + }, + { + "EventName": "L1_DCACHE_READ_ACCESS", + "EventCode": "0x0000000c", + "BriefDescription": "L1 data cache read access" + }, + { + "EventName": "L1_DCACHE_READ_MISS", + "EventCode": "0x0000000d", + "BriefDescription": "L1 data cache read miss" + }, + { + "EventName": "L1_DCACHE_WRITE_ACCESS", + "EventCode": "0x0000000e", + "BriefDescription": "L1 data cache write access" + }, + { + "EventName": "L1_DCACHE_WRITE_MISS", + "EventCode": "0x0000000f", + "BriefDescription": "L1 data cache write miss" + }, + { + "EventName": "LL_CACHE_READ_ACCESS", + "EventCode": "0x00000010", + "BriefDescription": "LL Cache read access" + }, + { + "EventName": "LL_CACHE_READ_MISS", + "EventCode": "0x00000011", + "BriefDescription": "LL Cache read miss" + }, + { + "EventName": "LL_CACHE_WRITE_ACCESS", + "EventCode": "0x00000012", + "BriefDescription": "LL Cache write access" + }, + { + "EventName": "LL_CACHE_WRITE_MISS", + "EventCode": "0x00000013", + "BriefDescription": "LL Cache write miss" + } +] diff --git a/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/firmware.json b/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/firmware.json new file mode 100644 index 0000000000..9b4a032186 --- /dev/null +++ b/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/firmware.json @@ -0,0 +1,68 @@ +[ + { + "ArchStdEvent": "FW_MISALIGNED_LOAD" + }, + { + "ArchStdEvent": "FW_MISALIGNED_STORE" + }, + { + "ArchStdEvent": "FW_ACCESS_LOAD" + }, + { + "ArchStdEvent": "FW_ACCESS_STORE" + }, + { + "ArchStdEvent": "FW_ILLEGAL_INSN" + }, + { + "ArchStdEvent": "FW_SET_TIMER" + }, + { + "ArchStdEvent": "FW_IPI_SENT" + }, + { + "ArchStdEvent": "FW_IPI_RECEIVED" + }, + { + "ArchStdEvent": "FW_FENCE_I_SENT" + }, + { + "ArchStdEvent": "FW_FENCE_I_RECEIVED" + }, + { + "ArchStdEvent": "FW_SFENCE_VMA_SENT" + }, + { + "ArchStdEvent": "FW_SFENCE_VMA_RECEIVED" + }, + { + "ArchStdEvent": "FW_SFENCE_VMA_RECEIVED" + }, + { + "ArchStdEvent": "FW_SFENCE_VMA_ASID_RECEIVED" + }, + { + "ArchStdEvent": "FW_HFENCE_GVMA_SENT" + }, + { + "ArchStdEvent": "FW_HFENCE_GVMA_RECEIVED" + }, + { + "ArchStdEvent": "FW_HFENCE_GVMA_VMID_SENT" + }, + { + "ArchStdEvent": "FW_HFENCE_GVMA_VMID_RECEIVED" + }, + { + "ArchStdEvent": "FW_HFENCE_VVMA_SENT" + }, + { + "ArchStdEvent": "FW_HFENCE_VVMA_RECEIVED" + }, + { + "ArchStdEvent": "FW_HFENCE_VVMA_ASID_SENT" + }, + { + "ArchStdEvent": "FW_HFENCE_VVMA_ASID_RECEIVED" + } +] diff --git a/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/instruction.json b/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/instruction.json new file mode 100644 index 0000000000..c822b53733 --- /dev/null +++ b/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/instruction.json @@ -0,0 +1,72 @@ +[ + { + "EventName": "INST_BRANCH_MISPREDICT", + "EventCode": "0x00000006", + "BriefDescription": "Mispredicted branch instructions" + }, + { + "EventName": "INST_BRANCH", + "EventCode": "0x00000007", + "BriefDescription": "Retired branch instructions" + }, + { + "EventName": "INST_JMP_MISPREDICT", + "EventCode": "0x00000008", + "BriefDescription": "Indirect branch mispredict" + }, + { + "EventName": "INST_JMP", + "EventCode": "0x00000009", + "BriefDescription": "Retired jmp instructions" + }, + { + "EventName": "INST_STORE", + "EventCode": "0x0000000b", + "BriefDescription": "Retired store instructions" + }, + { + "EventName": "INST_ALU", + "EventCode": "0x0000001d", + "BriefDescription": "Retired ALU instructions" + }, + { + "EventName": "INST_LDST", + "EventCode": "0x0000001e", + "BriefDescription": "Retired Load/Store instructions" + }, + { + "EventName": "INST_VECTOR", + "EventCode": "0x0000001f", + "BriefDescription": "Retired Vector instructions" + }, + { + "EventName": "INST_CSR", + "EventCode": "0x00000020", + "BriefDescription": "Retired CSR instructions" + }, + { + "EventName": "INST_SYNC", + "EventCode": "0x00000021", + "BriefDescription": "Retired sync instructions (AMO/LR/SC instructions)" + }, + { + "EventName": "INST_UNALIGNED_ACCESS", + "EventCode": "0x00000022", + "BriefDescription": "Retired Store/Load instructions with unaligned memory access" + }, + { + "EventName": "INST_ECALL", + "EventCode": "0x00000025", + "BriefDescription": "Retired ecall instructions" + }, + { + "EventName": "INST_LONG_JP", + "EventCode": "0x00000026", + "BriefDescription": "Retired long jump instructions" + }, + { + "EventName": "INST_FP", + "EventCode": "0x0000002a", + "BriefDescription": "Retired FPU instructions" + } +] diff --git a/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/microarch.json b/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/microarch.json new file mode 100644 index 0000000000..0ab6f288af --- /dev/null +++ b/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/microarch.json @@ -0,0 +1,80 @@ +[ + { + "EventName": "LSU_SPEC_FAIL", + "EventCode": "0x0000000a", + "BriefDescription": "LSU speculation fail" + }, + { + "EventName": "IDU_RF_PIPE_FAIL", + "EventCode": "0x00000014", + "BriefDescription": "Instruction decode unit launch pipeline failed in RF state" + }, + { + "EventName": "IDU_RF_REG_FAIL", + "EventCode": "0x00000015", + "BriefDescription": "Instruction decode unit launch register file fail in RF state" + }, + { + "EventName": "IDU_RF_INSTRUCTION", + "EventCode": "0x00000016", + "BriefDescription": "retired instruction count of Instruction decode unit in RF (Register File) stage" + }, + { + "EventName": "LSU_4K_STALL", + "EventCode": "0x00000017", + "BriefDescription": "LSU stall times for long distance data access (Over 4K)", + "PublicDescription": "This stall occurs when translate virtual address with page offset over 4k" + }, + { + "EventName": "LSU_OTHER_STALL", + "EventCode": "0x00000018", + "BriefDescription": "LSU stall times for other reasons (except the 4k stall)" + }, + { + "EventName": "LSU_SQ_OTHER_DIS", + "EventCode": "0x00000019", + "BriefDescription": "LSU store queue discard others" + }, + { + "EventName": "LSU_SQ_DATA_DISCARD", + "EventCode": "0x0000001a", + "BriefDescription": "LSU store queue discard data (uops)" + }, + { + "EventName": "BRANCH_DIRECTION_MISPREDICTION", + "EventCode": "0x0000001b", + "BriefDescription": "Branch misprediction in BTB" + }, + { + "EventName": "BRANCH_DIRECTION_PREDICTION", + "EventCode": "0x0000001c", + "BriefDescription": "All branch prediction in BTB", + "PublicDescription": "This event including both successful prediction and failed prediction in BTB" + }, + { + "EventName": "INTERRUPT_ACK_COUNT", + "EventCode": "0x00000023", + "BriefDescription": "acknowledged interrupt count" + }, + { + "EventName": "INTERRUPT_OFF_CYCLE", + "EventCode": "0x00000024", + "BriefDescription": "PLIC arbitration time when the interrupt is not responded", + "PublicDescription": "The arbitration time is recorded while meeting any of the following:\n- CPU is M-mode and MIE == 0\n- CPU is S-mode and delegation and SIE == 0\n" + }, + { + "EventName": "IFU_STALLED_CYCLE", + "EventCode": "0x00000027", + "BriefDescription": "Number of stall cycles of the instruction fetch unit (IFU)." + }, + { + "EventName": "IDU_STALLED_CYCLE", + "EventCode": "0x00000028", + "BriefDescription": "hpcp_backend_stall Number of stall cycles of the instruction decoding unit (IDU) and next-level pipeline unit." + }, + { + "EventName": "SYNC_STALL", + "EventCode": "0x00000029", + "BriefDescription": "Sync instruction stall cycle fence/fence.i/sync/sfence" + } +] diff --git a/tools/perf/pmu-events/arch/x86/alderlake/adl-metrics.json b/tools/perf/pmu-events/arch/x86/alderlake/adl-metrics.json index 3388b58b8f..bbfa3883e5 100644 --- a/tools/perf/pmu-events/arch/x86/alderlake/adl-metrics.json +++ b/tools/perf/pmu-events/arch/x86/alderlake/adl-metrics.json @@ -69,12 +69,6 @@ "MetricName": "C9_Pkg_Residency", "ScaleUnit": "100%" }, - { - "BriefDescription": "Uncore frequency per die [GHZ]", - "MetricExpr": "tma_info_system_socket_clks / #num_dies / duration_time / 1e9", - "MetricGroup": "SoC", - "MetricName": "UNCORE_FREQ" - }, { "BriefDescription": "Percentage of cycles spent in System Management Interrupts.", "MetricExpr": "((msr@aperf@ - cycles) / msr@aperf@ if msr@smi@ > 0 else 0)", @@ -120,7 +114,7 @@ }, { "BriefDescription": "Counts the number of issue slots that were not consumed by the backend due to certain allocation restrictions.", - "MetricExpr": "TOPDOWN_BE_BOUND.ALLOC_RESTRICTIONS / tma_info_core_slots", + "MetricExpr": "cpu_atom@TOPDOWN_BE_BOUND.ALLOC_RESTRICTIONS@ / tma_info_core_slots", "MetricGroup": "TopdownL3;tma_L3_group;tma_resource_bound_group", "MetricName": "tma_alloc_restriction", "MetricThreshold": "tma_alloc_restriction > 0.1", @@ -130,7 +124,7 @@ { "BriefDescription": "Counts the total number of issue slots that were not consumed by the backend due to backend stalls", "DefaultMetricgroupName": "TopdownL1", - "MetricExpr": "TOPDOWN_BE_BOUND.ALL / tma_info_core_slots", + "MetricExpr": "cpu_atom@TOPDOWN_BE_BOUND.ALL@ / tma_info_core_slots", "MetricGroup": "Default;TopdownL1;tma_L1_group", "MetricName": "tma_backend_bound", "MetricThreshold": "tma_backend_bound > 0.1", @@ -175,7 +169,7 @@ }, { "BriefDescription": "Counts the number of issue slots that were not delivered by the frontend due to BACLEARS, which occurs when the Branch Target Buffer (BTB) prediction or lack thereof, was corrected by a later branch predictor in the frontend", - "MetricExpr": "TOPDOWN_FE_BOUND.BRANCH_DETECT / tma_info_core_slots", + "MetricExpr": "cpu_atom@TOPDOWN_FE_BOUND.BRANCH_DETECT@ / tma_info_core_slots", "MetricGroup": "TopdownL3;tma_L3_group;tma_fetch_latency_group", "MetricName": "tma_branch_detect", "MetricThreshold": "tma_branch_detect > 0.05", @@ -185,7 +179,7 @@ }, { "BriefDescription": "Counts the number of issue slots that were not consumed by the backend due to branch mispredicts.", - "MetricExpr": "TOPDOWN_BAD_SPECULATION.MISPREDICT / tma_info_core_slots", + "MetricExpr": "cpu_atom@TOPDOWN_BAD_SPECULATION.MISPREDICT@ / tma_info_core_slots", "MetricGroup": "TopdownL2;tma_L2_group;tma_bad_speculation_group", "MetricName": "tma_branch_mispredicts", "MetricThreshold": "tma_branch_mispredicts > 0.05", @@ -195,7 +189,7 @@ }, { "BriefDescription": "Counts the number of issue slots that were not delivered by the frontend due to BTCLEARS, which occurs when the Branch Target Buffer (BTB) predicts a taken branch.", - "MetricExpr": "TOPDOWN_FE_BOUND.BRANCH_RESTEER / tma_info_core_slots", + "MetricExpr": "cpu_atom@TOPDOWN_FE_BOUND.BRANCH_RESTEER@ / tma_info_core_slots", "MetricGroup": "TopdownL3;tma_L3_group;tma_fetch_latency_group", "MetricName": "tma_branch_resteer", "MetricThreshold": "tma_branch_resteer > 0.05", @@ -204,7 +198,7 @@ }, { "BriefDescription": "Counts the number of issue slots that were not delivered by the frontend due to the microcode sequencer (MS).", - "MetricExpr": "TOPDOWN_FE_BOUND.CISC / tma_info_core_slots", + "MetricExpr": "cpu_atom@TOPDOWN_FE_BOUND.CISC@ / tma_info_core_slots", "MetricGroup": "TopdownL3;tma_L3_group;tma_fetch_bandwidth_group", "MetricName": "tma_cisc", "MetricThreshold": "tma_cisc > 0.05", @@ -223,7 +217,7 @@ }, { "BriefDescription": "Counts the number of issue slots that were not delivered by the frontend due to decode stalls.", - "MetricExpr": "TOPDOWN_FE_BOUND.DECODE / tma_info_core_slots", + "MetricExpr": "cpu_atom@TOPDOWN_FE_BOUND.DECODE@ / tma_info_core_slots", "MetricGroup": "TopdownL3;tma_L3_group;tma_fetch_bandwidth_group", "MetricName": "tma_decode", "MetricThreshold": "tma_decode > 0.05", @@ -241,7 +235,6 @@ }, { "BriefDescription": "Counts the number of cycles the core is stalled due to a demand load miss which hit in DRAM or MMIO (Non-DRAM).", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "cpu_atom@MEM_BOUND_STALLS.LOAD_DRAM_HIT@ / tma_info_core_clks - max((cpu_atom@MEM_BOUND_STALLS.LOAD@ - cpu_atom@LD_HEAD.L1_MISS_AT_RET@) / tma_info_core_clks, 0) * cpu_atom@MEM_BOUND_STALLS.LOAD_DRAM_HIT@ / cpu_atom@MEM_BOUND_STALLS.LOAD@", "MetricGroup": "TopdownL3;tma_L3_group;tma_memory_bound_group", "MetricName": "tma_dram_bound", @@ -251,7 +244,7 @@ }, { "BriefDescription": "Counts the number of issue slots that were not consumed by the backend due to a machine clear classified as a fast nuke due to memory ordering, memory disambiguation and memory renaming.", - "MetricExpr": "TOPDOWN_BAD_SPECULATION.FASTNUKE / tma_info_core_slots", + "MetricExpr": "cpu_atom@TOPDOWN_BAD_SPECULATION.FASTNUKE@ / tma_info_core_slots", "MetricGroup": "TopdownL3;tma_L3_group;tma_machine_clears_group", "MetricName": "tma_fast_nuke", "MetricThreshold": "tma_fast_nuke > 0.05", @@ -260,7 +253,7 @@ }, { "BriefDescription": "Counts the number of issue slots that were not delivered by the frontend due to frontend bandwidth restrictions due to decode, predecode, cisc, and other limitations.", - "MetricExpr": "TOPDOWN_FE_BOUND.FRONTEND_BANDWIDTH / tma_info_core_slots", + "MetricExpr": "cpu_atom@TOPDOWN_FE_BOUND.FRONTEND_BANDWIDTH@ / tma_info_core_slots", "MetricGroup": "TopdownL2;tma_L2_group;tma_frontend_bound_group", "MetricName": "tma_fetch_bandwidth", "MetricThreshold": "tma_fetch_bandwidth > 0.1", @@ -270,7 +263,7 @@ }, { "BriefDescription": "Counts the number of issue slots that were not delivered by the frontend due to frontend bandwidth restrictions due to decode, predecode, cisc, and other limitations.", - "MetricExpr": "TOPDOWN_FE_BOUND.FRONTEND_LATENCY / tma_info_core_slots", + "MetricExpr": "cpu_atom@TOPDOWN_FE_BOUND.FRONTEND_LATENCY@ / tma_info_core_slots", "MetricGroup": "TopdownL2;tma_L2_group;tma_frontend_bound_group", "MetricName": "tma_fetch_latency", "MetricThreshold": "tma_fetch_latency > 0.15", @@ -289,7 +282,7 @@ }, { "BriefDescription": "Counts the number of floating point divide operations per uop.", - "MetricExpr": "UOPS_RETIRED.FPDIV / tma_info_core_slots", + "MetricExpr": "cpu_atom@UOPS_RETIRED.FPDIV@ / tma_info_core_slots", "MetricGroup": "TopdownL3;tma_L3_group;tma_base_group", "MetricName": "tma_fpdiv_uops", "MetricThreshold": "tma_fpdiv_uops > 0.2", @@ -299,7 +292,7 @@ { "BriefDescription": "Counts the number of issue slots that were not consumed by the backend due to frontend stalls.", "DefaultMetricgroupName": "TopdownL1", - "MetricExpr": "TOPDOWN_FE_BOUND.ALL / tma_info_core_slots", + "MetricExpr": "cpu_atom@TOPDOWN_FE_BOUND.ALL@ / tma_info_core_slots", "MetricGroup": "Default;TopdownL1;tma_L1_group", "MetricName": "tma_frontend_bound", "MetricThreshold": "tma_frontend_bound > 0.2", @@ -309,7 +302,7 @@ }, { "BriefDescription": "Counts the number of issue slots that were not delivered by the frontend due to instruction cache misses.", - "MetricExpr": "TOPDOWN_FE_BOUND.ICACHE / tma_info_core_slots", + "MetricExpr": "cpu_atom@TOPDOWN_FE_BOUND.ICACHE@ / tma_info_core_slots", "MetricGroup": "TopdownL3;tma_L3_group;tma_fetch_latency_group", "MetricName": "tma_icache_misses", "MetricThreshold": "tma_icache_misses > 0.05", @@ -336,7 +329,7 @@ }, { "BriefDescription": "Instructions Per Cycle", - "MetricExpr": "INST_RETIRED.ANY / tma_info_core_clks", + "MetricExpr": "cpu_atom@INST_RETIRED.ANY@ / tma_info_core_clks", "MetricName": "tma_info_core_ipc", "Unit": "cpu_atom" }, @@ -348,7 +341,7 @@ }, { "BriefDescription": "Uops Per Instruction", - "MetricExpr": "UOPS_RETIRED.ALL / INST_RETIRED.ANY", + "MetricExpr": "cpu_atom@UOPS_RETIRED.ALL@ / INST_RETIRED.ANY", "MetricName": "tma_info_core_upi", "Unit": "cpu_atom" }, @@ -372,13 +365,13 @@ }, { "BriefDescription": "Ratio of all branches which mispredict", - "MetricExpr": "BR_MISP_RETIRED.ALL_BRANCHES / BR_INST_RETIRED.ALL_BRANCHES", + "MetricExpr": "cpu_atom@BR_MISP_RETIRED.ALL_BRANCHES@ / BR_INST_RETIRED.ALL_BRANCHES", "MetricName": "tma_info_inst_mix_branch_mispredict_ratio", "Unit": "cpu_atom" }, { "BriefDescription": "Ratio between Mispredicted branches and unknown branches", - "MetricExpr": "BR_MISP_RETIRED.ALL_BRANCHES / BACLEARS.ANY", + "MetricExpr": "cpu_atom@BR_MISP_RETIRED.ALL_BRANCHES@ / BACLEARS.ANY", "MetricName": "tma_info_inst_mix_branch_mispredict_to_unknown_branch_ratio", "Unit": "cpu_atom" }, @@ -396,61 +389,61 @@ }, { "BriefDescription": "Instructions per Branch (lower number means higher occurrence rate)", - "MetricExpr": "INST_RETIRED.ANY / BR_INST_RETIRED.ALL_BRANCHES", + "MetricExpr": "cpu_atom@INST_RETIRED.ANY@ / BR_INST_RETIRED.ALL_BRANCHES", "MetricName": "tma_info_inst_mix_ipbranch", "Unit": "cpu_atom" }, { "BriefDescription": "Instruction per (near) call (lower number means higher occurrence rate)", - "MetricExpr": "INST_RETIRED.ANY / BR_INST_RETIRED.CALL", + "MetricExpr": "cpu_atom@INST_RETIRED.ANY@ / BR_INST_RETIRED.CALL", "MetricName": "tma_info_inst_mix_ipcall", "Unit": "cpu_atom" }, { "BriefDescription": "Instructions per Far Branch", - "MetricExpr": "INST_RETIRED.ANY / (cpu_atom@BR_INST_RETIRED.FAR_BRANCH@ / 2)", + "MetricExpr": "cpu_atom@INST_RETIRED.ANY@ / (cpu_atom@BR_INST_RETIRED.FAR_BRANCH@ / 2)", "MetricName": "tma_info_inst_mix_ipfarbranch", "Unit": "cpu_atom" }, { "BriefDescription": "Instructions per Load", - "MetricExpr": "INST_RETIRED.ANY / MEM_UOPS_RETIRED.ALL_LOADS", + "MetricExpr": "cpu_atom@INST_RETIRED.ANY@ / MEM_UOPS_RETIRED.ALL_LOADS", "MetricName": "tma_info_inst_mix_ipload", "Unit": "cpu_atom" }, { "BriefDescription": "Instructions per retired conditional Branch Misprediction where the branch was not taken", - "MetricExpr": "INST_RETIRED.ANY / (cpu_atom@BR_MISP_RETIRED.COND@ - cpu_atom@BR_MISP_RETIRED.COND_TAKEN@)", + "MetricExpr": "cpu_atom@INST_RETIRED.ANY@ / (cpu_atom@BR_MISP_RETIRED.COND@ - cpu_atom@BR_MISP_RETIRED.COND_TAKEN@)", "MetricName": "tma_info_inst_mix_ipmisp_cond_ntaken", "Unit": "cpu_atom" }, { "BriefDescription": "Instructions per retired conditional Branch Misprediction where the branch was taken", - "MetricExpr": "INST_RETIRED.ANY / BR_MISP_RETIRED.COND_TAKEN", + "MetricExpr": "cpu_atom@INST_RETIRED.ANY@ / BR_MISP_RETIRED.COND_TAKEN", "MetricName": "tma_info_inst_mix_ipmisp_cond_taken", "Unit": "cpu_atom" }, { "BriefDescription": "Instructions per retired indirect call or jump Branch Misprediction", - "MetricExpr": "INST_RETIRED.ANY / BR_MISP_RETIRED.INDIRECT", + "MetricExpr": "cpu_atom@INST_RETIRED.ANY@ / BR_MISP_RETIRED.INDIRECT", "MetricName": "tma_info_inst_mix_ipmisp_indirect", "Unit": "cpu_atom" }, { "BriefDescription": "Instructions per retired return Branch Misprediction", - "MetricExpr": "INST_RETIRED.ANY / BR_MISP_RETIRED.RETURN", + "MetricExpr": "cpu_atom@INST_RETIRED.ANY@ / BR_MISP_RETIRED.RETURN", "MetricName": "tma_info_inst_mix_ipmisp_ret", "Unit": "cpu_atom" }, { "BriefDescription": "Instructions per retired Branch Misprediction", - "MetricExpr": "INST_RETIRED.ANY / BR_MISP_RETIRED.ALL_BRANCHES", + "MetricExpr": "cpu_atom@INST_RETIRED.ANY@ / BR_MISP_RETIRED.ALL_BRANCHES", "MetricName": "tma_info_inst_mix_ipmispredict", "Unit": "cpu_atom" }, { "BriefDescription": "Instructions per Store", - "MetricExpr": "INST_RETIRED.ANY / MEM_UOPS_RETIRED.ALL_STORES", + "MetricExpr": "cpu_atom@INST_RETIRED.ANY@ / MEM_UOPS_RETIRED.ALL_STORES", "MetricName": "tma_info_inst_mix_ipstore", "Unit": "cpu_atom" }, @@ -486,19 +479,19 @@ }, { "BriefDescription": "Cycle cost per DRAM hit", - "MetricExpr": "MEM_BOUND_STALLS.LOAD_DRAM_HIT / MEM_LOAD_UOPS_RETIRED.DRAM_HIT", + "MetricExpr": "cpu_atom@MEM_BOUND_STALLS.LOAD_DRAM_HIT@ / MEM_LOAD_UOPS_RETIRED.DRAM_HIT", "MetricName": "tma_info_memory_cycles_per_demand_load_dram_hit", "Unit": "cpu_atom" }, { "BriefDescription": "Cycle cost per L2 hit", - "MetricExpr": "MEM_BOUND_STALLS.LOAD_L2_HIT / MEM_LOAD_UOPS_RETIRED.L2_HIT", + "MetricExpr": "cpu_atom@MEM_BOUND_STALLS.LOAD_L2_HIT@ / MEM_LOAD_UOPS_RETIRED.L2_HIT", "MetricName": "tma_info_memory_cycles_per_demand_load_l2_hit", "Unit": "cpu_atom" }, { "BriefDescription": "Cycle cost per LLC hit", - "MetricExpr": "MEM_BOUND_STALLS.LOAD_LLC_HIT / MEM_LOAD_UOPS_RETIRED.L3_HIT", + "MetricExpr": "cpu_atom@MEM_BOUND_STALLS.LOAD_LLC_HIT@ / MEM_LOAD_UOPS_RETIRED.L3_HIT", "MetricName": "tma_info_memory_cycles_per_demand_load_l3_hit", "Unit": "cpu_atom" }, @@ -510,7 +503,7 @@ }, { "BriefDescription": "Average CPU Utilization", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / TSC", + "MetricExpr": "cpu_atom@CPU_CLK_UNHALTED.REF_TSC@ / TSC", "MetricName": "tma_info_system_cpu_utilization", "Unit": "cpu_atom" }, @@ -530,7 +523,7 @@ }, { "BriefDescription": "Counts the number of issue slots that were not delivered by the frontend due to Instruction Table Lookaside Buffer (ITLB) misses.", - "MetricExpr": "TOPDOWN_FE_BOUND.ITLB / tma_info_core_slots", + "MetricExpr": "cpu_atom@TOPDOWN_FE_BOUND.ITLB@ / tma_info_core_slots", "MetricGroup": "TopdownL3;tma_L3_group;tma_fetch_latency_group", "MetricName": "tma_itlb_misses", "MetricThreshold": "tma_itlb_misses > 0.05", @@ -539,7 +532,7 @@ }, { "BriefDescription": "Counts the number of cycles that the oldest load of the load buffer is stalled at retirement due to a load block.", - "MetricExpr": "LD_HEAD.L1_BOUND_AT_RET / tma_info_core_clks", + "MetricExpr": "cpu_atom@LD_HEAD.L1_BOUND_AT_RET@ / tma_info_core_clks", "MetricGroup": "TopdownL3;tma_L3_group;tma_memory_bound_group", "MetricName": "tma_l1_bound", "MetricThreshold": "tma_l1_bound > 0.1", @@ -548,7 +541,6 @@ }, { "BriefDescription": "Counts the number of cycles a core is stalled due to a demand load which hit in the L2 Cache.", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "cpu_atom@MEM_BOUND_STALLS.LOAD_L2_HIT@ / tma_info_core_clks - max((cpu_atom@MEM_BOUND_STALLS.LOAD@ - cpu_atom@LD_HEAD.L1_MISS_AT_RET@) / tma_info_core_clks, 0) * cpu_atom@MEM_BOUND_STALLS.LOAD_L2_HIT@ / cpu_atom@MEM_BOUND_STALLS.LOAD@", "MetricGroup": "TopdownL3;tma_L3_group;tma_memory_bound_group", "MetricName": "tma_l2_bound", @@ -558,7 +550,6 @@ }, { "BriefDescription": "Counts the number of cycles a core is stalled due to a demand load which hit in the Last Level Cache (LLC) or other core with HITE/F/M.", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "cpu_atom@MEM_BOUND_STALLS.LOAD_LLC_HIT@ / tma_info_core_clks - max((cpu_atom@MEM_BOUND_STALLS.LOAD@ - cpu_atom@LD_HEAD.L1_MISS_AT_RET@) / tma_info_core_clks, 0) * cpu_atom@MEM_BOUND_STALLS.LOAD_LLC_HIT@ / cpu_atom@MEM_BOUND_STALLS.LOAD@", "MetricGroup": "TopdownL3;tma_L3_group;tma_memory_bound_group", "MetricName": "tma_l3_bound", @@ -577,7 +568,7 @@ }, { "BriefDescription": "Counts the total number of issue slots that were not consumed by the backend because allocation is stalled due to a machine clear (nuke) of any kind including memory ordering and memory disambiguation.", - "MetricExpr": "TOPDOWN_BAD_SPECULATION.MACHINE_CLEARS / tma_info_core_slots", + "MetricExpr": "cpu_atom@TOPDOWN_BAD_SPECULATION.MACHINE_CLEARS@ / tma_info_core_slots", "MetricGroup": "TopdownL2;tma_L2_group;tma_bad_speculation_group", "MetricName": "tma_machine_clears", "MetricThreshold": "tma_machine_clears > 0.05", @@ -587,7 +578,7 @@ }, { "BriefDescription": "Counts the number of issue slots that were not consumed by the backend due to memory reservation stalls in which a scheduler is not able to accept uops.", - "MetricExpr": "TOPDOWN_BE_BOUND.MEM_SCHEDULER / tma_info_core_slots", + "MetricExpr": "cpu_atom@TOPDOWN_BE_BOUND.MEM_SCHEDULER@ / tma_info_core_slots", "MetricGroup": "TopdownL3;tma_L3_group;tma_resource_bound_group", "MetricName": "tma_mem_scheduler", "MetricThreshold": "tma_mem_scheduler > 0.1", @@ -596,7 +587,7 @@ }, { "BriefDescription": "Counts the number of cycles the core is stalled due to stores or loads.", - "MetricExpr": "min(cpu_atom@TOPDOWN_BE_BOUND.ALL@ / tma_info_core_slots, cpu_atom@LD_HEAD.ANY_AT_RET@ / tma_info_core_clks + tma_store_bound)", + "MetricExpr": "min(tma_backend_bound, cpu_atom@LD_HEAD.ANY_AT_RET@ / tma_info_core_clks + tma_store_bound)", "MetricGroup": "TopdownL2;tma_L2_group;tma_backend_bound_group", "MetricName": "tma_memory_bound", "MetricThreshold": "tma_memory_bound > 0.2", @@ -615,7 +606,7 @@ }, { "BriefDescription": "Counts the number of uops that are from the complex flows issued by the micro-sequencer (MS)", - "MetricExpr": "UOPS_RETIRED.MS / tma_info_core_slots", + "MetricExpr": "cpu_atom@UOPS_RETIRED.MS@ / tma_info_core_slots", "MetricGroup": "TopdownL2;tma_L2_group;tma_retiring_group", "MetricName": "tma_ms_uops", "MetricThreshold": "tma_ms_uops > 0.05", @@ -626,7 +617,7 @@ }, { "BriefDescription": "Counts the number of issue slots that were not consumed by the backend due to IEC or FPC RAT stalls, which can be due to FIQ or IEC reservation stalls in which the integer, floating point or SIMD scheduler is not able to accept uops.", - "MetricExpr": "TOPDOWN_BE_BOUND.NON_MEM_SCHEDULER / tma_info_core_slots", + "MetricExpr": "cpu_atom@TOPDOWN_BE_BOUND.NON_MEM_SCHEDULER@ / tma_info_core_slots", "MetricGroup": "TopdownL3;tma_L3_group;tma_resource_bound_group", "MetricName": "tma_non_mem_scheduler", "MetricThreshold": "tma_non_mem_scheduler > 0.1", @@ -635,7 +626,7 @@ }, { "BriefDescription": "Counts the number of issue slots that were not consumed by the backend due to a machine clear (slow nuke).", - "MetricExpr": "TOPDOWN_BAD_SPECULATION.NUKE / tma_info_core_slots", + "MetricExpr": "cpu_atom@TOPDOWN_BAD_SPECULATION.NUKE@ / tma_info_core_slots", "MetricGroup": "TopdownL3;tma_L3_group;tma_machine_clears_group", "MetricName": "tma_nuke", "MetricThreshold": "tma_nuke > 0.05", @@ -644,7 +635,7 @@ }, { "BriefDescription": "Counts the number of issue slots that were not delivered by the frontend due to other common frontend stalls not categorized.", - "MetricExpr": "TOPDOWN_FE_BOUND.OTHER / tma_info_core_slots", + "MetricExpr": "cpu_atom@TOPDOWN_FE_BOUND.OTHER@ / tma_info_core_slots", "MetricGroup": "TopdownL3;tma_L3_group;tma_fetch_bandwidth_group", "MetricName": "tma_other_fb", "MetricThreshold": "tma_other_fb > 0.05", @@ -653,7 +644,7 @@ }, { "BriefDescription": "Counts the number of cycles that the oldest load of the load buffer is stalled at retirement due to a number of other load blocks.", - "MetricExpr": "LD_HEAD.OTHER_AT_RET / tma_info_core_clks", + "MetricExpr": "cpu_atom@LD_HEAD.OTHER_AT_RET@ / tma_info_core_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_other_l1", "MetricThreshold": "tma_other_l1 > 0.05", @@ -689,7 +680,7 @@ }, { "BriefDescription": "Counts the number of issue slots that were not delivered by the frontend due to wrong predecodes.", - "MetricExpr": "TOPDOWN_FE_BOUND.PREDECODE / tma_info_core_slots", + "MetricExpr": "cpu_atom@TOPDOWN_FE_BOUND.PREDECODE@ / tma_info_core_slots", "MetricGroup": "TopdownL3;tma_L3_group;tma_fetch_bandwidth_group", "MetricName": "tma_predecode", "MetricThreshold": "tma_predecode > 0.05", @@ -698,7 +689,7 @@ }, { "BriefDescription": "Counts the number of issue slots that were not consumed by the backend due to the physical register file unable to accept an entry (marble stalls).", - "MetricExpr": "TOPDOWN_BE_BOUND.REGISTER / tma_info_core_slots", + "MetricExpr": "cpu_atom@TOPDOWN_BE_BOUND.REGISTER@ / tma_info_core_slots", "MetricGroup": "TopdownL3;tma_L3_group;tma_resource_bound_group", "MetricName": "tma_register", "MetricThreshold": "tma_register > 0.1", @@ -707,7 +698,7 @@ }, { "BriefDescription": "Counts the number of issue slots that were not consumed by the backend due to the reorder buffer being full (ROB stalls).", - "MetricExpr": "TOPDOWN_BE_BOUND.REORDER_BUFFER / tma_info_core_slots", + "MetricExpr": "cpu_atom@TOPDOWN_BE_BOUND.REORDER_BUFFER@ / tma_info_core_slots", "MetricGroup": "TopdownL3;tma_L3_group;tma_resource_bound_group", "MetricName": "tma_reorder_buffer", "MetricThreshold": "tma_reorder_buffer > 0.1", @@ -728,7 +719,7 @@ { "BriefDescription": "Counts the number of issue slots that result in retirement slots.", "DefaultMetricgroupName": "TopdownL1", - "MetricExpr": "TOPDOWN_RETIRING.ALL / tma_info_core_slots", + "MetricExpr": "cpu_atom@TOPDOWN_RETIRING.ALL@ / tma_info_core_slots", "MetricGroup": "Default;TopdownL1;tma_L1_group", "MetricName": "tma_retiring", "MetricThreshold": "tma_retiring > 0.75", @@ -747,7 +738,7 @@ }, { "BriefDescription": "Counts the number of issue slots that were not consumed by the backend due to scoreboards from the instruction queue (IQ), jump execution unit (JEU), or microcode sequencer (MS).", - "MetricExpr": "TOPDOWN_BE_BOUND.SERIALIZATION / tma_info_core_slots", + "MetricExpr": "cpu_atom@TOPDOWN_BE_BOUND.SERIALIZATION@ / tma_info_core_slots", "MetricGroup": "TopdownL3;tma_L3_group;tma_resource_bound_group", "MetricName": "tma_serialization", "MetricThreshold": "tma_serialization > 0.1", @@ -774,7 +765,7 @@ }, { "BriefDescription": "Counts the number of cycles that the oldest load of the load buffer is stalled at retirement due to a first level TLB miss.", - "MetricExpr": "LD_HEAD.DTLB_MISS_AT_RET / tma_info_core_clks", + "MetricExpr": "cpu_atom@LD_HEAD.DTLB_MISS_AT_RET@ / tma_info_core_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_stlb_hit", "MetricThreshold": "tma_stlb_hit > 0.05", @@ -783,7 +774,7 @@ }, { "BriefDescription": "Counts the number of cycles that the oldest load of the load buffer is stalled at retirement due to a second level TLB miss requiring a page walk.", - "MetricExpr": "LD_HEAD.PGWALK_AT_RET / tma_info_core_clks", + "MetricExpr": "cpu_atom@LD_HEAD.PGWALK_AT_RET@ / tma_info_core_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_stlb_miss", "MetricThreshold": "tma_stlb_miss > 0.05", @@ -801,14 +792,20 @@ }, { "BriefDescription": "Counts the number of cycles that the oldest load of the load buffer is stalled at retirement due to a store forward block.", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", - "MetricExpr": "LD_HEAD.ST_ADDR_AT_RET / tma_info_core_clks", + "MetricExpr": "cpu_atom@LD_HEAD.ST_ADDR_AT_RET@ / tma_info_core_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_store_fwd_blk", "MetricThreshold": "tma_store_fwd_blk > 0.05", "ScaleUnit": "100%", "Unit": "cpu_atom" }, + { + "BriefDescription": "Uncore frequency per die [GHZ]", + "MetricExpr": "tma_info_system_socket_clks / #num_dies / duration_time / 1e9", + "MetricGroup": "SoC", + "MetricName": "UNCORE_FREQ", + "Unit": "cpu_core" + }, { "BriefDescription": "This metric represents Core fraction of cycles CPU dispatched uops on execution ports for ALU operations.", "MetricExpr": "(cpu_core@UOPS_DISPATCHED.PORT_0@ + cpu_core@UOPS_DISPATCHED.PORT_1@ + cpu_core@UOPS_DISPATCHED.PORT_5_11@ + cpu_core@UOPS_DISPATCHED.PORT_6@) / (5 * tma_info_core_core_clks)", @@ -874,7 +871,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to Branch Resteers", - "MetricExpr": "INT_MISC.CLEAR_RESTEER_CYCLES / tma_info_thread_clks + tma_unknown_branches", + "MetricExpr": "cpu_core@INT_MISC.CLEAR_RESTEER_CYCLES@ / tma_info_thread_clks + tma_unknown_branches", "MetricGroup": "FetchLat;TopdownL3;tma_L3_group;tma_fetch_latency_group", "MetricName": "tma_branch_resteers", "MetricThreshold": "tma_branch_resteers > 0.05 & (tma_fetch_latency > 0.1 & tma_frontend_bound > 0.15)", @@ -904,7 +901,6 @@ }, { "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to contested accesses", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(25 * tma_info_system_average_frequency * (cpu_core@MEM_LOAD_L3_HIT_RETIRED.XSNP_FWD@ * (cpu_core@OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HITM@ / (cpu_core@OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HITM@ + cpu_core@OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HIT_WITH_FWD@))) + 24 * tma_info_system_average_frequency * cpu_core@MEM_LOAD_L3_HIT_RETIRED.XSNP_MISS@) * (1 + cpu_core@MEM_LOAD_RETIRED.FB_HIT@ / cpu_core@MEM_LOAD_RETIRED.L1_MISS@ / 2) / tma_info_thread_clks", "MetricGroup": "DataSharing;Offcore;Snoop;TopdownL4;tma_L4_group;tma_issueSyncxn;tma_l3_bound_group", "MetricName": "tma_contested_accesses", @@ -926,7 +922,6 @@ }, { "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to data-sharing accesses", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "24 * tma_info_system_average_frequency * (cpu_core@MEM_LOAD_L3_HIT_RETIRED.XSNP_NO_FWD@ + cpu_core@MEM_LOAD_L3_HIT_RETIRED.XSNP_FWD@ * (1 - cpu_core@OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HITM@ / (cpu_core@OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HITM@ + cpu_core@OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HIT_WITH_FWD@))) * (1 + cpu_core@MEM_LOAD_RETIRED.FB_HIT@ / cpu_core@MEM_LOAD_RETIRED.L1_MISS@ / 2) / tma_info_thread_clks", "MetricGroup": "Offcore;Snoop;TopdownL4;tma_L4_group;tma_issueSyncxn;tma_l3_bound_group", "MetricName": "tma_data_sharing", @@ -947,7 +942,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles where the Divider unit was active", - "MetricExpr": "ARITH.DIV_ACTIVE / tma_info_thread_clks", + "MetricExpr": "cpu_core@ARITH.DIV_ACTIVE@ / tma_info_thread_clks", "MetricGroup": "TopdownL3;tma_L3_group;tma_core_bound_group", "MetricName": "tma_divider", "MetricThreshold": "tma_divider > 0.2 & (tma_core_bound > 0.1 & tma_backend_bound > 0.2)", @@ -957,7 +952,6 @@ }, { "BriefDescription": "This metric estimates how often the CPU was stalled on accesses to external memory (DRAM) by loads", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "cpu_core@MEMORY_ACTIVITY.STALLS_L3_MISS@ / tma_info_thread_clks", "MetricGroup": "MemoryBound;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", "MetricName": "tma_dram_bound", @@ -978,7 +972,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to switches from DSB to MITE pipelines", - "MetricExpr": "DSB2MITE_SWITCHES.PENALTY_CYCLES / tma_info_thread_clks", + "MetricExpr": "cpu_core@DSB2MITE_SWITCHES.PENALTY_CYCLES@ / tma_info_thread_clks", "MetricGroup": "DSBmiss;FetchLat;TopdownL3;tma_L3_group;tma_fetch_latency_group;tma_issueFB", "MetricName": "tma_dsb_switches", "MetricThreshold": "tma_dsb_switches > 0.05 & (tma_fetch_latency > 0.1 & tma_frontend_bound > 0.15)", @@ -1018,7 +1012,7 @@ }, { "BriefDescription": "This metric does a *rough estimation* of how often L1D Fill Buffer unavailability limited additional L1D miss memory access requests to proceed", - "MetricExpr": "L1D_PEND_MISS.FB_FULL / tma_info_thread_clks", + "MetricExpr": "cpu_core@L1D_PEND_MISS.FB_FULL@ / tma_info_thread_clks", "MetricGroup": "MemoryBW;TopdownL4;tma_L4_group;tma_issueBW;tma_issueSL;tma_issueSmSt;tma_l1_bound_group", "MetricName": "tma_fb_full", "MetricThreshold": "tma_fb_full > 0.3", @@ -1153,7 +1147,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to instruction cache misses", - "MetricExpr": "ICACHE_DATA.STALLS / tma_info_thread_clks", + "MetricExpr": "cpu_core@ICACHE_DATA.STALLS@ / tma_info_thread_clks", "MetricGroup": "BigFoot;FetchLat;IcMiss;TopdownL3;tma_L3_group;tma_fetch_latency_group", "MetricName": "tma_icache_misses", "MetricThreshold": "tma_icache_misses > 0.05 & (tma_fetch_latency > 0.1 & tma_frontend_bound > 0.15)", @@ -1163,7 +1157,6 @@ }, { "BriefDescription": "Branch Misprediction Cost: Fraction of TMA slots wasted per non-speculative branch misprediction (retired JEClear)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(tma_branch_mispredicts + tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches)) * tma_info_thread_slots / BR_MISP_RETIRED.ALL_BRANCHES", "MetricGroup": "Bad;BrMispredicts;tma_issueBM", "MetricName": "tma_info_bad_spec_branch_misprediction_cost", @@ -1172,7 +1165,7 @@ }, { "BriefDescription": "Instructions per retired mispredicts for conditional non-taken branches (lower number means higher occurrence rate).", - "MetricExpr": "INST_RETIRED.ANY / BR_MISP_RETIRED.COND_NTAKEN", + "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / BR_MISP_RETIRED.COND_NTAKEN", "MetricGroup": "Bad;BrMispredicts", "MetricName": "tma_info_bad_spec_ipmisp_cond_ntaken", "MetricThreshold": "tma_info_bad_spec_ipmisp_cond_ntaken < 200", @@ -1180,7 +1173,7 @@ }, { "BriefDescription": "Instructions per retired mispredicts for conditional taken branches (lower number means higher occurrence rate).", - "MetricExpr": "INST_RETIRED.ANY / BR_MISP_RETIRED.COND_TAKEN", + "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / BR_MISP_RETIRED.COND_TAKEN", "MetricGroup": "Bad;BrMispredicts", "MetricName": "tma_info_bad_spec_ipmisp_cond_taken", "MetricThreshold": "tma_info_bad_spec_ipmisp_cond_taken < 200", @@ -1196,7 +1189,7 @@ }, { "BriefDescription": "Instructions per retired mispredicts for return branches (lower number means higher occurrence rate).", - "MetricExpr": "INST_RETIRED.ANY / BR_MISP_RETIRED.RET", + "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / BR_MISP_RETIRED.RET", "MetricGroup": "Bad;BrMispredicts", "MetricName": "tma_info_bad_spec_ipmisp_ret", "MetricThreshold": "tma_info_bad_spec_ipmisp_ret < 500", @@ -1204,7 +1197,7 @@ }, { "BriefDescription": "Number of Instructions per non-speculative Branch Misprediction (JEClear) (lower number means higher occurrence rate)", - "MetricExpr": "INST_RETIRED.ANY / BR_MISP_RETIRED.ALL_BRANCHES", + "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / BR_MISP_RETIRED.ALL_BRANCHES", "MetricGroup": "Bad;BadSpec;BrMispredicts", "MetricName": "tma_info_bad_spec_ipmispredict", "MetricThreshold": "tma_info_bad_spec_ipmispredict < 200", @@ -1212,7 +1205,6 @@ }, { "BriefDescription": "Probability of Core Bound bottleneck hidden by SMT-profiling artifacts", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(100 * (1 - tma_core_bound / tma_ports_utilization if tma_core_bound < tma_ports_utilization else 1) if tma_info_system_smt_2t_utilization > 0.5 else 0)", "MetricGroup": "Cor;SMT", "MetricName": "tma_info_botlnk_l0_core_bound_likely", @@ -1221,7 +1213,6 @@ }, { "BriefDescription": "Total pipeline cost of DSB (uop cache) misses - subset of the Instruction_Fetch_BW Bottleneck", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_fetch_latency * tma_dsb_switches / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_fetch_bandwidth * tma_mite / (tma_dsb + tma_lsd + tma_mite))", "MetricGroup": "DSBmiss;Fed;tma_issueFB", "MetricName": "tma_info_botlnk_l2_dsb_misses", @@ -1231,7 +1222,6 @@ }, { "BriefDescription": "Total pipeline cost of Instruction Cache misses - subset of the Big_Code Bottleneck", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_fetch_latency * tma_icache_misses / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches))", "MetricGroup": "Fed;FetchLat;IcMiss;tma_issueFL", "MetricName": "tma_info_botlnk_l2_ic_misses", @@ -1241,7 +1231,6 @@ }, { "BriefDescription": "Total pipeline cost of instruction fetch related bottlenecks by large code footprint programs (i-side cache; TLB and BTB misses)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * tma_fetch_latency * (tma_itlb_misses + tma_icache_misses + tma_unknown_branches) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches)", "MetricGroup": "BigFoot;Fed;Frontend;IcMiss;MemoryTLB;tma_issueBC", "MetricName": "tma_info_bottleneck_big_code", @@ -1260,7 +1249,6 @@ }, { "BriefDescription": "Total pipeline cost of instruction fetch bandwidth related bottlenecks", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_frontend_bound - tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches)) - tma_info_bottleneck_big_code", "MetricGroup": "Fed;FetchBW;Frontend", "MetricName": "tma_info_bottleneck_instruction_fetch_bw", @@ -1269,7 +1257,6 @@ }, { "BriefDescription": "Total pipeline cost of (external) Memory Bandwidth related bottlenecks", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full))) + tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_fb_full / (tma_dtlb_load + tma_fb_full + tma_lock_latency + tma_split_loads + tma_store_fwd_blk))", "MetricGroup": "Mem;MemoryBW;Offcore;tma_issueBW", "MetricName": "tma_info_bottleneck_memory_bandwidth", @@ -1279,7 +1266,6 @@ }, { "BriefDescription": "Total pipeline cost of Memory Address Translation related bottlenecks (data-side TLBs)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * tma_memory_bound * (tma_l1_bound / max(tma_memory_bound, tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_dtlb_load / max(tma_l1_bound, tma_dtlb_load + tma_fb_full + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_dtlb_store / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", "MetricGroup": "Mem;MemoryTLB;Offcore;tma_issueTLB", "MetricName": "tma_info_bottleneck_memory_data_tlbs", @@ -1289,7 +1275,6 @@ }, { "BriefDescription": "Total pipeline cost of Memory Latency related bottlenecks (external memory and off-core caches)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_l2_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound))", "MetricGroup": "Mem;MemoryLat;Offcore;tma_issueLat", "MetricName": "tma_info_bottleneck_memory_latency", @@ -1299,7 +1284,6 @@ }, { "BriefDescription": "Total pipeline cost of Branch Misprediction related bottlenecks", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_branch_mispredicts + tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches))", "MetricGroup": "Bad;BadSpec;BrMispredicts;tma_issueBM", "MetricName": "tma_info_bottleneck_mispredictions", @@ -1316,14 +1300,14 @@ }, { "BriefDescription": "Fraction of branches that are non-taken conditionals", - "MetricExpr": "BR_INST_RETIRED.COND_NTAKEN / BR_INST_RETIRED.ALL_BRANCHES", + "MetricExpr": "cpu_core@BR_INST_RETIRED.COND_NTAKEN@ / BR_INST_RETIRED.ALL_BRANCHES", "MetricGroup": "Bad;Branches;CodeGen;PGO", "MetricName": "tma_info_branches_cond_nt", "Unit": "cpu_core" }, { "BriefDescription": "Fraction of branches that are taken conditionals", - "MetricExpr": "BR_INST_RETIRED.COND_TAKEN / BR_INST_RETIRED.ALL_BRANCHES", + "MetricExpr": "cpu_core@BR_INST_RETIRED.COND_TAKEN@ / BR_INST_RETIRED.ALL_BRANCHES", "MetricGroup": "Bad;Branches;CodeGen;PGO", "MetricName": "tma_info_branches_cond_tk", "Unit": "cpu_core" @@ -1351,7 +1335,7 @@ }, { "BriefDescription": "Instructions Per Cycle across hyper-threads (per physical core)", - "MetricExpr": "INST_RETIRED.ANY / tma_info_core_core_clks", + "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / tma_info_core_core_clks", "MetricGroup": "Ret;SMT;TmaL1;tma_L1_group", "MetricName": "tma_info_core_coreipc", "Unit": "cpu_core" @@ -1373,14 +1357,14 @@ }, { "BriefDescription": "Instruction-Level-Parallelism (average number of uops executed when there is execution) per-core", - "MetricExpr": "UOPS_EXECUTED.THREAD / (cpu_core@UOPS_EXECUTED.CORE_CYCLES_GE_1@ / 2 if #SMT_on else cpu_core@UOPS_EXECUTED.CORE_CYCLES_GE_1@)", + "MetricExpr": "cpu_core@UOPS_EXECUTED.THREAD@ / (cpu_core@UOPS_EXECUTED.CORE_CYCLES_GE_1@ / 2 if #SMT_on else cpu_core@UOPS_EXECUTED.CORE_CYCLES_GE_1@)", "MetricGroup": "Backend;Cor;Pipeline;PortsUtil", "MetricName": "tma_info_core_ilp", "Unit": "cpu_core" }, { "BriefDescription": "Fraction of Uops delivered by the DSB (aka Decoded ICache; or Uop Cache)", - "MetricExpr": "IDQ.DSB_UOPS / cpu_core@UOPS_ISSUED.ANY@", + "MetricExpr": "cpu_core@IDQ.DSB_UOPS@ / cpu_core@UOPS_ISSUED.ANY@", "MetricGroup": "DSB;Fed;FetchBW;tma_issueFB", "MetricName": "tma_info_frontend_dsb_coverage", "MetricThreshold": "tma_info_frontend_dsb_coverage < 0.7 & tma_info_thread_ipc / 6 > 0.35", @@ -1389,28 +1373,28 @@ }, { "BriefDescription": "Average number of cycles of a switch from the DSB fetch-unit to MITE fetch unit - see DSB_Switches tree node for details.", - "MetricExpr": "DSB2MITE_SWITCHES.PENALTY_CYCLES / cpu_core@DSB2MITE_SWITCHES.PENALTY_CYCLES\\,cmask\\=1\\,edge@", + "MetricExpr": "cpu_core@DSB2MITE_SWITCHES.PENALTY_CYCLES@ / cpu_core@DSB2MITE_SWITCHES.PENALTY_CYCLES\\,cmask\\=1\\,edge@", "MetricGroup": "DSBmiss", "MetricName": "tma_info_frontend_dsb_switch_cost", "Unit": "cpu_core" }, { "BriefDescription": "Average number of Uops issued by front-end when it issued something", - "MetricExpr": "UOPS_ISSUED.ANY / cpu_core@UOPS_ISSUED.ANY\\,cmask\\=1@", + "MetricExpr": "cpu_core@UOPS_ISSUED.ANY@ / cpu_core@UOPS_ISSUED.ANY\\,cmask\\=1@", "MetricGroup": "Fed;FetchBW", "MetricName": "tma_info_frontend_fetch_upc", "Unit": "cpu_core" }, { "BriefDescription": "Average Latency for L1 instruction cache misses", - "MetricExpr": "ICACHE_DATA.STALLS / cpu_core@ICACHE_DATA.STALLS\\,cmask\\=1\\,edge@", + "MetricExpr": "cpu_core@ICACHE_DATA.STALLS@ / cpu_core@ICACHE_DATA.STALLS\\,cmask\\=1\\,edge@", "MetricGroup": "Fed;FetchLat;IcMiss", "MetricName": "tma_info_frontend_icache_miss_latency", "Unit": "cpu_core" }, { "BriefDescription": "Instructions per non-speculative DSB miss (lower number means higher occurrence rate)", - "MetricExpr": "INST_RETIRED.ANY / FRONTEND_RETIRED.ANY_DSB_MISS", + "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / FRONTEND_RETIRED.ANY_DSB_MISS", "MetricGroup": "DSBmiss;Fed", "MetricName": "tma_info_frontend_ipdsb_miss_ret", "MetricThreshold": "tma_info_frontend_ipdsb_miss_ret < 50", @@ -1439,14 +1423,14 @@ }, { "BriefDescription": "Fraction of Uops delivered by the LSD (Loop Stream Detector; aka Loop Cache)", - "MetricExpr": "LSD.UOPS / cpu_core@UOPS_ISSUED.ANY@", + "MetricExpr": "cpu_core@LSD.UOPS@ / cpu_core@UOPS_ISSUED.ANY@", "MetricGroup": "Fed;LSD", "MetricName": "tma_info_frontend_lsd_coverage", "Unit": "cpu_core" }, { "BriefDescription": "Branch instructions per taken branch.", - "MetricExpr": "BR_INST_RETIRED.ALL_BRANCHES / BR_INST_RETIRED.NEAR_TAKEN", + "MetricExpr": "cpu_core@BR_INST_RETIRED.ALL_BRANCHES@ / BR_INST_RETIRED.NEAR_TAKEN", "MetricGroup": "Branches;Fed;PGO", "MetricName": "tma_info_inst_mix_bptkbranch", "Unit": "cpu_core" @@ -1461,7 +1445,7 @@ }, { "BriefDescription": "Instructions per FP Arithmetic instruction (lower number means higher occurrence rate)", - "MetricExpr": "INST_RETIRED.ANY / (cpu_core@FP_ARITH_INST_RETIRED.SCALAR_SINGLE\\,umask\\=0x03@ + cpu_core@FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE\\,umask\\=0x3c@)", + "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / (cpu_core@FP_ARITH_INST_RETIRED.SCALAR_SINGLE\\,umask\\=0x03@ + cpu_core@FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE\\,umask\\=0x3c@)", "MetricGroup": "Flops;InsType", "MetricName": "tma_info_inst_mix_iparith", "MetricThreshold": "tma_info_inst_mix_iparith < 10", @@ -1470,7 +1454,7 @@ }, { "BriefDescription": "Instructions per FP Arithmetic AVX/SSE 128-bit instruction (lower number means higher occurrence rate)", - "MetricExpr": "INST_RETIRED.ANY / (cpu_core@FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE@ + cpu_core@FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE@)", + "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / (cpu_core@FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE@ + cpu_core@FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE@)", "MetricGroup": "Flops;FpVector;InsType", "MetricName": "tma_info_inst_mix_iparith_avx128", "MetricThreshold": "tma_info_inst_mix_iparith_avx128 < 10", @@ -1479,7 +1463,7 @@ }, { "BriefDescription": "Instructions per FP Arithmetic AVX* 256-bit instruction (lower number means higher occurrence rate)", - "MetricExpr": "INST_RETIRED.ANY / (cpu_core@FP_ARITH_INST_RETIRED.256B_PACKED_DOUBLE@ + cpu_core@FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE@)", + "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / (cpu_core@FP_ARITH_INST_RETIRED.256B_PACKED_DOUBLE@ + cpu_core@FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE@)", "MetricGroup": "Flops;FpVector;InsType", "MetricName": "tma_info_inst_mix_iparith_avx256", "MetricThreshold": "tma_info_inst_mix_iparith_avx256 < 10", @@ -1488,7 +1472,7 @@ }, { "BriefDescription": "Instructions per FP Arithmetic Scalar Double-Precision instruction (lower number means higher occurrence rate)", - "MetricExpr": "INST_RETIRED.ANY / FP_ARITH_INST_RETIRED.SCALAR_DOUBLE", + "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / FP_ARITH_INST_RETIRED.SCALAR_DOUBLE", "MetricGroup": "Flops;FpScalar;InsType", "MetricName": "tma_info_inst_mix_iparith_scalar_dp", "MetricThreshold": "tma_info_inst_mix_iparith_scalar_dp < 10", @@ -1497,7 +1481,7 @@ }, { "BriefDescription": "Instructions per FP Arithmetic Scalar Single-Precision instruction (lower number means higher occurrence rate)", - "MetricExpr": "INST_RETIRED.ANY / FP_ARITH_INST_RETIRED.SCALAR_SINGLE", + "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / FP_ARITH_INST_RETIRED.SCALAR_SINGLE", "MetricGroup": "Flops;FpScalar;InsType", "MetricName": "tma_info_inst_mix_iparith_scalar_sp", "MetricThreshold": "tma_info_inst_mix_iparith_scalar_sp < 10", @@ -1506,7 +1490,7 @@ }, { "BriefDescription": "Instructions per Branch (lower number means higher occurrence rate)", - "MetricExpr": "INST_RETIRED.ANY / BR_INST_RETIRED.ALL_BRANCHES", + "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / BR_INST_RETIRED.ALL_BRANCHES", "MetricGroup": "Branches;Fed;InsType", "MetricName": "tma_info_inst_mix_ipbranch", "MetricThreshold": "tma_info_inst_mix_ipbranch < 8", @@ -1514,7 +1498,7 @@ }, { "BriefDescription": "Instructions per (near) call (lower number means higher occurrence rate)", - "MetricExpr": "INST_RETIRED.ANY / BR_INST_RETIRED.NEAR_CALL", + "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / BR_INST_RETIRED.NEAR_CALL", "MetricGroup": "Branches;Fed;PGO", "MetricName": "tma_info_inst_mix_ipcall", "MetricThreshold": "tma_info_inst_mix_ipcall < 200", @@ -1522,7 +1506,7 @@ }, { "BriefDescription": "Instructions per Floating Point (FP) Operation (lower number means higher occurrence rate)", - "MetricExpr": "INST_RETIRED.ANY / (cpu_core@FP_ARITH_INST_RETIRED.SCALAR_SINGLE@ + cpu_core@FP_ARITH_INST_RETIRED.SCALAR_DOUBLE@ + 2 * cpu_core@FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE@ + 4 * (cpu_core@FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE@ + cpu_core@FP_ARITH_INST_RETIRED.256B_PACKED_DOUBLE@) + 8 * cpu_core@FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE@)", + "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / (cpu_core@FP_ARITH_INST_RETIRED.SCALAR_SINGLE@ + cpu_core@FP_ARITH_INST_RETIRED.SCALAR_DOUBLE@ + 2 * cpu_core@FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE@ + 4 * (cpu_core@FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE@ + cpu_core@FP_ARITH_INST_RETIRED.256B_PACKED_DOUBLE@) + 8 * cpu_core@FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE@)", "MetricGroup": "Flops;InsType", "MetricName": "tma_info_inst_mix_ipflop", "MetricThreshold": "tma_info_inst_mix_ipflop < 10", @@ -1530,7 +1514,7 @@ }, { "BriefDescription": "Instructions per Load (lower number means higher occurrence rate)", - "MetricExpr": "INST_RETIRED.ANY / MEM_INST_RETIRED.ALL_LOADS", + "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / MEM_INST_RETIRED.ALL_LOADS", "MetricGroup": "InsType", "MetricName": "tma_info_inst_mix_ipload", "MetricThreshold": "tma_info_inst_mix_ipload < 3", @@ -1538,7 +1522,7 @@ }, { "BriefDescription": "Instructions per Store (lower number means higher occurrence rate)", - "MetricExpr": "INST_RETIRED.ANY / MEM_INST_RETIRED.ALL_STORES", + "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / MEM_INST_RETIRED.ALL_STORES", "MetricGroup": "InsType", "MetricName": "tma_info_inst_mix_ipstore", "MetricThreshold": "tma_info_inst_mix_ipstore < 8", @@ -1546,7 +1530,7 @@ }, { "BriefDescription": "Instructions per Software prefetch instruction (of any type: NTA/T0/T1/T2/Prefetch) (lower number means higher occurrence rate)", - "MetricExpr": "INST_RETIRED.ANY / cpu_core@SW_PREFETCH_ACCESS.T0\\,umask\\=0xF@", + "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / cpu_core@SW_PREFETCH_ACCESS.T0\\,umask\\=0xF@", "MetricGroup": "Prefetches", "MetricName": "tma_info_inst_mix_ipswpf", "MetricThreshold": "tma_info_inst_mix_ipswpf < 100", @@ -1554,7 +1538,7 @@ }, { "BriefDescription": "Instruction per taken branch", - "MetricExpr": "INST_RETIRED.ANY / BR_INST_RETIRED.NEAR_TAKEN", + "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / BR_INST_RETIRED.NEAR_TAKEN", "MetricGroup": "Branches;Fed;FetchBW;Frontend;PGO;tma_issueFB", "MetricName": "tma_info_inst_mix_iptb", "MetricThreshold": "tma_info_inst_mix_iptb < 13", @@ -1654,14 +1638,14 @@ }, { "BriefDescription": "Actual Average Latency for L1 data-cache miss demand load operations (in core cycles)", - "MetricExpr": "L1D_PEND_MISS.PENDING / MEM_LOAD_COMPLETED.L1_MISS_ANY", + "MetricExpr": "cpu_core@L1D_PEND_MISS.PENDING@ / MEM_LOAD_COMPLETED.L1_MISS_ANY", "MetricGroup": "Mem;MemoryBound;MemoryLat", "MetricName": "tma_info_memory_load_miss_real_latency", "Unit": "cpu_core" }, { "BriefDescription": "Memory-Level-Parallelism (average number of L1 miss demand load when there is at least one such miss", - "MetricExpr": "L1D_PEND_MISS.PENDING / L1D_PEND_MISS.PENDING_CYCLES", + "MetricExpr": "cpu_core@L1D_PEND_MISS.PENDING@ / L1D_PEND_MISS.PENDING_CYCLES", "MetricGroup": "Mem;MemoryBW;MemoryBound", "MetricName": "tma_info_memory_mlp", "PublicDescription": "Memory-Level-Parallelism (average number of L1 miss demand load when there is at least one such miss. Per-Logical Processor)", @@ -1669,28 +1653,28 @@ }, { "BriefDescription": "Average Parallel L2 cache miss data reads", - "MetricExpr": "OFFCORE_REQUESTS_OUTSTANDING.ALL_DATA_RD / OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DATA_RD", + "MetricExpr": "cpu_core@OFFCORE_REQUESTS_OUTSTANDING.ALL_DATA_RD@ / OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DATA_RD", "MetricGroup": "Memory_BW;Offcore", "MetricName": "tma_info_memory_oro_data_l2_mlp", "Unit": "cpu_core" }, { "BriefDescription": "Average Latency for L2 cache miss demand Loads", - "MetricExpr": "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_DATA_RD / OFFCORE_REQUESTS.DEMAND_DATA_RD", + "MetricExpr": "cpu_core@OFFCORE_REQUESTS_OUTSTANDING.DEMAND_DATA_RD@ / OFFCORE_REQUESTS.DEMAND_DATA_RD", "MetricGroup": "Memory_Lat;Offcore", "MetricName": "tma_info_memory_oro_load_l2_miss_latency", "Unit": "cpu_core" }, { "BriefDescription": "Average Parallel L2 cache miss demand Loads", - "MetricExpr": "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_DATA_RD / cpu_core@OFFCORE_REQUESTS_OUTSTANDING.DEMAND_DATA_RD\\,cmask\\=1@", + "MetricExpr": "cpu_core@OFFCORE_REQUESTS_OUTSTANDING.DEMAND_DATA_RD@ / cpu_core@OFFCORE_REQUESTS_OUTSTANDING.DEMAND_DATA_RD\\,cmask\\=1@", "MetricGroup": "Memory_BW;Offcore", "MetricName": "tma_info_memory_oro_load_l2_mlp", "Unit": "cpu_core" }, { "BriefDescription": "Average Latency for L3 cache miss demand Loads", - "MetricExpr": "OFFCORE_REQUESTS_OUTSTANDING.L3_MISS_DEMAND_DATA_RD / OFFCORE_REQUESTS.L3_MISS_DEMAND_DATA_RD", + "MetricExpr": "cpu_core@OFFCORE_REQUESTS_OUTSTANDING.L3_MISS_DEMAND_DATA_RD@ / OFFCORE_REQUESTS.L3_MISS_DEMAND_DATA_RD", "MetricGroup": "Memory_Lat;Offcore", "MetricName": "tma_info_memory_oro_load_l3_miss_latency", "Unit": "cpu_core" @@ -1754,14 +1738,14 @@ }, { "BriefDescription": "Instruction-Level-Parallelism (average number of uops executed when there is execution) per-thread", - "MetricExpr": "UOPS_EXECUTED.THREAD / cpu_core@UOPS_EXECUTED.THREAD\\,cmask\\=1@", + "MetricExpr": "cpu_core@UOPS_EXECUTED.THREAD@ / cpu_core@UOPS_EXECUTED.THREAD\\,cmask\\=1@", "MetricGroup": "Cor;Pipeline;PortsUtil;SMT", "MetricName": "tma_info_pipeline_execute", "Unit": "cpu_core" }, { "BriefDescription": "Instructions per a microcode Assist invocation", - "MetricExpr": "INST_RETIRED.ANY / cpu_core@ASSISTS.ANY\\,umask\\=0x1B@", + "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / cpu_core@ASSISTS.ANY\\,umask\\=0x1B@", "MetricGroup": "Pipeline;Ret;Retire", "MetricName": "tma_info_pipeline_ipassist", "MetricThreshold": "tma_info_pipeline_ipassist < 100e3", @@ -1777,7 +1761,7 @@ }, { "BriefDescription": "Estimated fraction of retirement-cycles dealing with repeat instructions", - "MetricExpr": "INST_RETIRED.REP_ITERATION / cpu_core@UOPS_RETIRED.SLOTS\\,cmask\\=1@", + "MetricExpr": "cpu_core@INST_RETIRED.REP_ITERATION@ / cpu_core@UOPS_RETIRED.SLOTS\\,cmask\\=1@", "MetricGroup": "Pipeline;Ret", "MetricName": "tma_info_pipeline_strings_cycles", "MetricThreshold": "tma_info_pipeline_strings_cycles > 0.1", @@ -1792,7 +1776,7 @@ }, { "BriefDescription": "Average CPU Utilization", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC / TSC", + "MetricExpr": "cpu_core@CPU_CLK_UNHALTED.REF_TSC@ / TSC", "MetricGroup": "HPC;Summary", "MetricName": "tma_info_system_cpu_utilization", "Unit": "cpu_core" @@ -1815,7 +1799,7 @@ }, { "BriefDescription": "Instructions per Far Branch ( Far Branches apply upon transition from application to operating system, handling interrupts, exceptions) [lower number means higher occurrence rate]", - "MetricExpr": "INST_RETIRED.ANY / cpu_core@BR_INST_RETIRED.FAR_BRANCH@u", + "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / cpu_core@BR_INST_RETIRED.FAR_BRANCH@u", "MetricGroup": "Branches;OS", "MetricName": "tma_info_system_ipfarbranch", "MetricThreshold": "tma_info_system_ipfarbranch < 1e6", @@ -1838,7 +1822,7 @@ }, { "BriefDescription": "Average number of parallel data read requests to external memory", - "MetricExpr": "UNC_ARB_DAT_OCCUPANCY.RD / cpu_core@UNC_ARB_DAT_OCCUPANCY.RD\\,cmask\\=1@", + "MetricExpr": "UNC_ARB_DAT_OCCUPANCY.RD / UNC_ARB_DAT_OCCUPANCY.RD@cmask\\=1@", "MetricGroup": "Mem;MemoryBW;SoC", "MetricName": "tma_info_system_mem_parallel_reads", "PublicDescription": "Average number of parallel data read requests to external memory. Accounts for demand loads and L1/L2 prefetches", @@ -1846,6 +1830,7 @@ }, { "BriefDescription": "Average latency of data read request to external memory (in nanoseconds)", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(UNC_ARB_TRK_OCCUPANCY.RD + UNC_ARB_DAT_OCCUPANCY.RD) / UNC_ARB_TRK_REQUESTS.RD", "MetricGroup": "Mem;MemoryLat;SoC", "MetricName": "tma_info_system_mem_read_latency", @@ -1854,6 +1839,7 @@ }, { "BriefDescription": "Average latency of all requests to external memory (in Uncore cycles)", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(UNC_ARB_TRK_OCCUPANCY.ALL + UNC_ARB_DAT_OCCUPANCY.RD) / UNC_ARB_TRK_REQUESTS.ALL", "MetricGroup": "Mem;SoC", "MetricName": "tma_info_system_mem_request_latency", @@ -1896,7 +1882,7 @@ }, { "BriefDescription": "The ratio of Executed- by Issued-Uops", - "MetricExpr": "UOPS_EXECUTED.THREAD / UOPS_ISSUED.ANY", + "MetricExpr": "cpu_core@UOPS_EXECUTED.THREAD@ / UOPS_ISSUED.ANY", "MetricGroup": "Cor;Pipeline", "MetricName": "tma_info_thread_execute_per_issue", "PublicDescription": "The ratio of Executed- by Issued-Uops. Ratio > 1 suggests high rate of uop micro-fusions. Ratio < 1 suggest high rate of \"execute\" at rename stage.", @@ -1904,7 +1890,7 @@ }, { "BriefDescription": "Instructions Per Cycle (per Logical Processor)", - "MetricExpr": "INST_RETIRED.ANY / tma_info_thread_clks", + "MetricExpr": "cpu_core@INST_RETIRED.ANY@ / tma_info_thread_clks", "MetricGroup": "Ret;Summary", "MetricName": "tma_info_thread_ipc", "Unit": "cpu_core" @@ -1971,7 +1957,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to Instruction TLB (ITLB) misses", - "MetricExpr": "ICACHE_TAG.STALLS / tma_info_thread_clks", + "MetricExpr": "cpu_core@ICACHE_TAG.STALLS@ / tma_info_thread_clks", "MetricGroup": "BigFoot;FetchLat;MemoryTLB;TopdownL3;tma_L3_group;tma_fetch_latency_group", "MetricName": "tma_itlb_misses", "MetricThreshold": "tma_itlb_misses > 0.05 & (tma_fetch_latency > 0.1 & tma_frontend_bound > 0.15)", @@ -1991,7 +1977,6 @@ }, { "BriefDescription": "This metric estimates how often the CPU was stalled due to L2 cache accesses by loads", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(cpu_core@MEMORY_ACTIVITY.STALLS_L1D_MISS@ - cpu_core@MEMORY_ACTIVITY.STALLS_L2_MISS@) / tma_info_thread_clks", "MetricGroup": "CacheMisses;MemoryBound;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", "MetricName": "tma_l2_bound", @@ -2002,7 +1987,6 @@ }, { "BriefDescription": "This metric estimates how often the CPU was stalled due to loads accesses to L3 cache or contended with a sibling Core", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "(cpu_core@MEMORY_ACTIVITY.STALLS_L2_MISS@ - cpu_core@MEMORY_ACTIVITY.STALLS_L3_MISS@) / tma_info_thread_clks", "MetricGroup": "CacheMisses;MemoryBound;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", "MetricName": "tma_l3_bound", @@ -2023,7 +2007,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU was stalled due to Length Changing Prefixes (LCPs)", - "MetricExpr": "DECODE.LCP / tma_info_thread_clks", + "MetricExpr": "cpu_core@DECODE.LCP@ / tma_info_thread_clks", "MetricGroup": "FetchLat;TopdownL3;tma_L3_group;tma_fetch_latency_group;tma_issueFB", "MetricName": "tma_lcp", "MetricThreshold": "tma_lcp > 0.05 & (tma_fetch_latency > 0.1 & tma_frontend_bound > 0.15)", @@ -2044,7 +2028,7 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles CPU dispatched uops on execution port for Load operations", - "MetricExpr": "UOPS_DISPATCHED.PORT_2_3_10 / (3 * tma_info_core_core_clks)", + "MetricExpr": "cpu_core@UOPS_DISPATCHED.PORT_2_3_10@ / (3 * tma_info_core_core_clks)", "MetricGroup": "TopdownL5;tma_L5_group;tma_ports_utilized_3m_group", "MetricName": "tma_load_op_utilization", "MetricThreshold": "tma_load_op_utilization > 0.6", @@ -2063,7 +2047,7 @@ }, { "BriefDescription": "This metric estimates the fraction of cycles where the Second-level TLB (STLB) was missed by load accesses, performing a hardware page walk", - "MetricExpr": "DTLB_LOAD_MISSES.WALK_ACTIVE / tma_info_thread_clks", + "MetricExpr": "cpu_core@DTLB_LOAD_MISSES.WALK_ACTIVE@ / tma_info_thread_clks", "MetricGroup": "MemoryTLB;TopdownL5;tma_L5_group;tma_dtlb_load_group", "MetricName": "tma_load_stlb_miss", "MetricThreshold": "tma_load_stlb_miss > 0.05 & (tma_dtlb_load > 0.1 & (tma_l1_bound > 0.1 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)))", @@ -2072,7 +2056,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU spent handling cache misses due to lock operations", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(16 * max(0, cpu_core@MEM_INST_RETIRED.LOCK_LOADS@ - cpu_core@L2_RQSTS.ALL_RFO@) + cpu_core@MEM_INST_RETIRED.LOCK_LOADS@ / cpu_core@MEM_INST_RETIRED.ALL_STORES@ * (10 * cpu_core@L2_RQSTS.RFO_HIT@ + min(cpu_core@CPU_CLK_UNHALTED.THREAD@, cpu_core@OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_RFO@))) / tma_info_thread_clks", "MetricGroup": "Offcore;TopdownL4;tma_L4_group;tma_issueRFO;tma_l1_bound_group", "MetricName": "tma_lock_latency", @@ -2135,6 +2118,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to LFENCE Instructions.", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "13 * cpu_core@MISC2_RETIRED.LFENCE@ / tma_info_thread_clks", "MetricGroup": "TopdownL6;tma_L6_group;tma_serializing_operation_group", "MetricName": "tma_memory_fence", @@ -2144,7 +2128,6 @@ }, { "BriefDescription": "This metric represents fraction of slots where the CPU was retiring memory operations -- uops for memory load or store accesses.", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "tma_light_operations * cpu_core@MEM_UOP_RETIRED.ANY@ / (tma_retiring * tma_info_thread_slots)", "MetricGroup": "Pipeline;TopdownL3;tma_L3_group;tma_light_operations_group", "MetricName": "tma_memory_operations", @@ -2154,7 +2137,7 @@ }, { "BriefDescription": "This metric represents fraction of slots the CPU was retiring uops fetched by the Microcode Sequencer (MS) unit", - "MetricExpr": "UOPS_RETIRED.MS / tma_info_thread_slots", + "MetricExpr": "cpu_core@UOPS_RETIRED.MS@ / tma_info_thread_slots", "MetricGroup": "MicroSeq;TopdownL3;tma_L3_group;tma_heavy_operations_group;tma_issueMC;tma_issueMS", "MetricName": "tma_microcode_sequencer", "MetricThreshold": "tma_microcode_sequencer > 0.05 & tma_heavy_operations > 0.1", @@ -2224,7 +2207,6 @@ }, { "BriefDescription": "This metric represents the remaining light uops fraction the CPU has executed - remaining means not covered by other sibling nodes", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "max(0, tma_light_operations - (tma_fp_arith + tma_int_operations + tma_memory_operations + tma_fused_instructions + tma_non_fused_branches + tma_nop_instructions))", "MetricGroup": "Pipeline;TopdownL3;tma_L3_group;tma_light_operations_group", "MetricName": "tma_other_light_ops", @@ -2245,7 +2227,7 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles CPU dispatched uops on execution port 0 ([SNB+] ALU; [HSW+] ALU and 2nd branch)", - "MetricExpr": "UOPS_DISPATCHED.PORT_0 / tma_info_core_core_clks", + "MetricExpr": "cpu_core@UOPS_DISPATCHED.PORT_0@ / tma_info_core_core_clks", "MetricGroup": "Compute;TopdownL6;tma_L6_group;tma_alu_op_utilization_group;tma_issue2P", "MetricName": "tma_port_0", "MetricThreshold": "tma_port_0 > 0.6", @@ -2255,7 +2237,7 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles CPU dispatched uops on execution port 1 (ALU)", - "MetricExpr": "UOPS_DISPATCHED.PORT_1 / tma_info_core_core_clks", + "MetricExpr": "cpu_core@UOPS_DISPATCHED.PORT_1@ / tma_info_core_core_clks", "MetricGroup": "TopdownL6;tma_L6_group;tma_alu_op_utilization_group;tma_issue2P", "MetricName": "tma_port_1", "MetricThreshold": "tma_port_1 > 0.6", @@ -2265,7 +2247,7 @@ }, { "BriefDescription": "This metric represents Core fraction of cycles CPU dispatched uops on execution port 6 ([HSW+]Primary Branch and simple ALU)", - "MetricExpr": "UOPS_DISPATCHED.PORT_6 / tma_info_core_core_clks", + "MetricExpr": "cpu_core@UOPS_DISPATCHED.PORT_6@ / tma_info_core_core_clks", "MetricGroup": "TopdownL6;tma_L6_group;tma_alu_op_utilization_group;tma_issue2P", "MetricName": "tma_port_6", "MetricThreshold": "tma_port_6 > 0.6", @@ -2295,7 +2277,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles where the CPU executed total of 1 uop per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricExpr": "EXE_ACTIVITY.1_PORTS_UTIL / tma_info_thread_clks", + "MetricExpr": "cpu_core@EXE_ACTIVITY.1_PORTS_UTIL@ / tma_info_thread_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_issueL1;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_1", "MetricThreshold": "tma_ports_utilized_1 > 0.2 & (tma_ports_utilization > 0.15 & (tma_core_bound > 0.1 & tma_backend_bound > 0.2))", @@ -2305,7 +2287,8 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed total of 2 uops per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricExpr": "EXE_ACTIVITY.2_PORTS_UTIL / tma_info_thread_clks", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", + "MetricExpr": "cpu_core@EXE_ACTIVITY.2_PORTS_UTIL@ / tma_info_thread_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_issue2P;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_2", "MetricThreshold": "tma_ports_utilized_2 > 0.15 & (tma_ports_utilization > 0.15 & (tma_core_bound > 0.1 & tma_backend_bound > 0.2))", @@ -2315,7 +2298,8 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed total of 3 or more uops per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", - "MetricExpr": "UOPS_EXECUTED.CYCLES_GE_3 / tma_info_thread_clks", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", + "MetricExpr": "cpu_core@UOPS_EXECUTED.CYCLES_GE_3@ / tma_info_thread_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_3m", "MetricThreshold": "tma_ports_utilized_3m > 0.7 & (tma_ports_utilization > 0.15 & (tma_core_bound > 0.1 & tma_backend_bound > 0.2))", @@ -2337,7 +2321,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU issue-pipeline was stalled due to serializing operations", - "MetricExpr": "RESOURCE_STALLS.SCOREBOARD / tma_info_thread_clks", + "MetricExpr": "cpu_core@RESOURCE_STALLS.SCOREBOARD@ / tma_info_thread_clks", "MetricGroup": "PortsUtil;TopdownL5;tma_L5_group;tma_issueSO;tma_ports_utilized_0_group", "MetricName": "tma_serializing_operation", "MetricThreshold": "tma_serializing_operation > 0.1 & (tma_ports_utilized_0 > 0.2 & (tma_ports_utilization > 0.15 & (tma_core_bound > 0.1 & tma_backend_bound > 0.2)))", @@ -2347,7 +2331,7 @@ }, { "BriefDescription": "This metric represents Shuffle (cross \"vector lane\" data transfers) uops fraction the CPU has retired.", - "MetricExpr": "INT_VEC_RETIRED.SHUFFLES / (tma_retiring * tma_info_thread_slots)", + "MetricExpr": "cpu_core@INT_VEC_RETIRED.SHUFFLES@ / (tma_retiring * tma_info_thread_slots)", "MetricGroup": "HPC;Pipeline;TopdownL4;tma_L4_group;tma_int_operations_group", "MetricName": "tma_shuffles", "MetricThreshold": "tma_shuffles > 0.1 & (tma_int_operations > 0.1 & tma_light_operations > 0.6)", @@ -2356,7 +2340,8 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to PAUSE Instructions", - "MetricExpr": "CPU_CLK_UNHALTED.PAUSE / tma_info_thread_clks", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", + "MetricExpr": "cpu_core@CPU_CLK_UNHALTED.PAUSE@ / tma_info_thread_clks", "MetricGroup": "TopdownL6;tma_L6_group;tma_serializing_operation_group", "MetricName": "tma_slow_pause", "MetricThreshold": "tma_slow_pause > 0.05 & (tma_serializing_operation > 0.1 & (tma_ports_utilized_0 > 0.2 & (tma_ports_utilization > 0.15 & (tma_core_bound > 0.1 & tma_backend_bound > 0.2))))", @@ -2376,8 +2361,7 @@ }, { "BriefDescription": "This metric represents rate of split store accesses", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", - "MetricExpr": "MEM_INST_RETIRED.SPLIT_STORES / tma_info_core_core_clks", + "MetricExpr": "cpu_core@MEM_INST_RETIRED.SPLIT_STORES@ / tma_info_core_core_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_issueSpSt;tma_store_bound_group", "MetricName": "tma_split_stores", "MetricThreshold": "tma_split_stores > 0.2 & (tma_store_bound > 0.2 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2))", @@ -2397,7 +2381,7 @@ }, { "BriefDescription": "This metric estimates how often CPU was stalled due to RFO store memory accesses; RFO store issue a read-for-ownership request before the write", - "MetricExpr": "EXE_ACTIVITY.BOUND_ON_STORES / tma_info_thread_clks", + "MetricExpr": "cpu_core@EXE_ACTIVITY.BOUND_ON_STORES@ / tma_info_thread_clks", "MetricGroup": "MemoryBound;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", "MetricName": "tma_store_bound", "MetricThreshold": "tma_store_bound > 0.2 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)", @@ -2407,7 +2391,6 @@ }, { "BriefDescription": "This metric roughly estimates fraction of cycles when the memory subsystem had loads blocked since they could not forward data from earlier (in program order) overlapping stores", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "13 * cpu_core@LD_BLOCKS.STORE_FORWARD@ / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_store_fwd_blk", @@ -2447,7 +2430,7 @@ }, { "BriefDescription": "This metric estimates the fraction of cycles where the STLB was missed by store accesses, performing a hardware page walk", - "MetricExpr": "DTLB_STORE_MISSES.WALK_ACTIVE / tma_info_core_core_clks", + "MetricExpr": "cpu_core@DTLB_STORE_MISSES.WALK_ACTIVE@ / tma_info_core_core_clks", "MetricGroup": "MemoryTLB;TopdownL5;tma_L5_group;tma_dtlb_store_group", "MetricName": "tma_store_stlb_miss", "MetricThreshold": "tma_store_stlb_miss > 0.05 & (tma_dtlb_store > 0.05 & (tma_store_bound > 0.2 & (tma_memory_bound > 0.2 & tma_backend_bound > 0.2)))", @@ -2466,7 +2449,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to new branch address clears", - "MetricExpr": "INT_MISC.UNKNOWN_BRANCH_CYCLES / tma_info_thread_clks", + "MetricExpr": "cpu_core@INT_MISC.UNKNOWN_BRANCH_CYCLES@ / tma_info_thread_clks", "MetricGroup": "BigFoot;FetchLat;TopdownL4;tma_L4_group;tma_branch_resteers_group", "MetricName": "tma_unknown_branches", "MetricThreshold": "tma_unknown_branches > 0.05 & (tma_branch_resteers > 0.05 & (tma_fetch_latency > 0.1 & tma_frontend_bound > 0.15))", diff --git a/tools/perf/pmu-events/arch/x86/alderlaken/adln-metrics.json b/tools/perf/pmu-events/arch/x86/alderlaken/adln-metrics.json index c150c14ac6..a35edf7d86 100644 --- a/tools/perf/pmu-events/arch/x86/alderlaken/adln-metrics.json +++ b/tools/perf/pmu-events/arch/x86/alderlaken/adln-metrics.json @@ -195,7 +195,6 @@ }, { "BriefDescription": "Counts the number of cycles the core is stalled due to a demand load miss which hit in DRAM or MMIO (Non-DRAM).", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "MEM_BOUND_STALLS.LOAD_DRAM_HIT / tma_info_core_clks - max((MEM_BOUND_STALLS.LOAD - LD_HEAD.L1_MISS_AT_RET) / tma_info_core_clks, 0) * MEM_BOUND_STALLS.LOAD_DRAM_HIT / MEM_BOUND_STALLS.LOAD", "MetricGroup": "TopdownL3;tma_L3_group;tma_memory_bound_group", "MetricName": "tma_dram_bound", @@ -457,7 +456,6 @@ }, { "BriefDescription": "Counts the number of cycles a core is stalled due to a demand load which hit in the L2 Cache.", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "MEM_BOUND_STALLS.LOAD_L2_HIT / tma_info_core_clks - max((MEM_BOUND_STALLS.LOAD - LD_HEAD.L1_MISS_AT_RET) / tma_info_core_clks, 0) * MEM_BOUND_STALLS.LOAD_L2_HIT / MEM_BOUND_STALLS.LOAD", "MetricGroup": "TopdownL3;tma_L3_group;tma_memory_bound_group", "MetricName": "tma_l2_bound", @@ -466,7 +464,6 @@ }, { "BriefDescription": "Counts the number of cycles a core is stalled due to a demand load which hit in the Last Level Cache (LLC) or other core with HITE/F/M.", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "MEM_BOUND_STALLS.LOAD_LLC_HIT / tma_info_core_clks - max((MEM_BOUND_STALLS.LOAD - LD_HEAD.L1_MISS_AT_RET) / tma_info_core_clks, 0) * MEM_BOUND_STALLS.LOAD_LLC_HIT / MEM_BOUND_STALLS.LOAD", "MetricGroup": "TopdownL3;tma_L3_group;tma_memory_bound_group", "MetricName": "tma_l3_bound", @@ -683,7 +680,6 @@ }, { "BriefDescription": "Counts the number of cycles that the oldest load of the load buffer is stalled at retirement due to a store forward block.", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "LD_HEAD.ST_ADDR_AT_RET / tma_info_core_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_store_fwd_blk", diff --git a/tools/perf/pmu-events/arch/x86/amdzen4/cache.json b/tools/perf/pmu-events/arch/x86/amdzen4/cache.json index ecbe9660b2..e6d710cf3c 100644 --- a/tools/perf/pmu-events/arch/x86/amdzen4/cache.json +++ b/tools/perf/pmu-events/arch/x86/amdzen4/cache.json @@ -676,6 +676,10 @@ "EventCode": "0xac", "BriefDescription": "Average sampled latency when data is sourced from DRAM in the same NUMA node.", "UMask": "0x01", + "EnAllCores": "0x1", + "EnAllSlices": "0x1", + "SliceId": "0x3", + "ThreadMask": "0x3", "Unit": "L3PMC" }, { @@ -683,6 +687,10 @@ "EventCode": "0xac", "BriefDescription": "Average sampled latency when data is sourced from DRAM in a different NUMA node.", "UMask": "0x02", + "EnAllCores": "0x1", + "EnAllSlices": "0x1", + "SliceId": "0x3", + "ThreadMask": "0x3", "Unit": "L3PMC" }, { @@ -690,6 +698,10 @@ "EventCode": "0xac", "BriefDescription": "Average sampled latency when data is sourced from another CCX's cache when the address was in the same NUMA node.", "UMask": "0x04", + "EnAllCores": "0x1", + "EnAllSlices": "0x1", + "SliceId": "0x3", + "ThreadMask": "0x3", "Unit": "L3PMC" }, { @@ -697,6 +709,10 @@ "EventCode": "0xac", "BriefDescription": "Average sampled latency when data is sourced from another CCX's cache when the address was in a different NUMA node.", "UMask": "0x08", + "EnAllCores": "0x1", + "EnAllSlices": "0x1", + "SliceId": "0x3", + "ThreadMask": "0x3", "Unit": "L3PMC" }, { @@ -704,6 +720,10 @@ "EventCode": "0xac", "BriefDescription": "Average sampled latency when data is sourced from extension memory (CXL) in the same NUMA node.", "UMask": "0x10", + "EnAllCores": "0x1", + "EnAllSlices": "0x1", + "SliceId": "0x3", + "ThreadMask": "0x3", "Unit": "L3PMC" }, { @@ -711,6 +731,10 @@ "EventCode": "0xac", "BriefDescription": "Average sampled latency when data is sourced from extension memory (CXL) in a different NUMA node.", "UMask": "0x20", + "EnAllCores": "0x1", + "EnAllSlices": "0x1", + "SliceId": "0x3", + "ThreadMask": "0x3", "Unit": "L3PMC" }, { @@ -718,6 +742,10 @@ "EventCode": "0xac", "BriefDescription": "Average sampled latency from all data sources.", "UMask": "0x3f", + "EnAllCores": "0x1", + "EnAllSlices": "0x1", + "SliceId": "0x3", + "ThreadMask": "0x3", "Unit": "L3PMC" }, { @@ -725,6 +753,10 @@ "EventCode": "0xad", "BriefDescription": "L3 cache fill requests sourced from DRAM in the same NUMA node.", "UMask": "0x01", + "EnAllCores": "0x1", + "EnAllSlices": "0x1", + "SliceId": "0x3", + "ThreadMask": "0x3", "Unit": "L3PMC" }, { @@ -732,6 +764,10 @@ "EventCode": "0xad", "BriefDescription": "L3 cache fill requests sourced from DRAM in a different NUMA node.", "UMask": "0x02", + "EnAllCores": "0x1", + "EnAllSlices": "0x1", + "SliceId": "0x3", + "ThreadMask": "0x3", "Unit": "L3PMC" }, { @@ -739,6 +775,10 @@ "EventCode": "0xad", "BriefDescription": "L3 cache fill requests sourced from another CCX's cache when the address was in the same NUMA node.", "UMask": "0x04", + "EnAllCores": "0x1", + "EnAllSlices": "0x1", + "SliceId": "0x3", + "ThreadMask": "0x3", "Unit": "L3PMC" }, { @@ -746,6 +786,10 @@ "EventCode": "0xad", "BriefDescription": "L3 cache fill requests sourced from another CCX's cache when the address was in a different NUMA node.", "UMask": "0x08", + "EnAllCores": "0x1", + "EnAllSlices": "0x1", + "SliceId": "0x3", + "ThreadMask": "0x3", "Unit": "L3PMC" }, { @@ -753,6 +797,10 @@ "EventCode": "0xad", "BriefDescription": "L3 cache fill requests sourced from extension memory (CXL) in the same NUMA node.", "UMask": "0x10", + "EnAllCores": "0x1", + "EnAllSlices": "0x1", + "SliceId": "0x3", + "ThreadMask": "0x3", "Unit": "L3PMC" }, { @@ -760,6 +808,10 @@ "EventCode": "0xad", "BriefDescription": "L3 cache fill requests sourced from extension memory (CXL) in a different NUMA node.", "UMask": "0x20", + "EnAllCores": "0x1", + "EnAllSlices": "0x1", + "SliceId": "0x3", + "ThreadMask": "0x3", "Unit": "L3PMC" }, { @@ -767,6 +819,10 @@ "EventCode": "0xad", "BriefDescription": "L3 cache fill requests sourced from all data sources.", "UMask": "0x3f", + "EnAllCores": "0x1", + "EnAllSlices": "0x1", + "SliceId": "0x3", + "ThreadMask": "0x3", "Unit": "L3PMC" } ] diff --git a/tools/perf/pmu-events/arch/x86/amdzen4/memory-controller.json b/tools/perf/pmu-events/arch/x86/amdzen4/memory-controller.json new file mode 100644 index 0000000000..55263e5e4f --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/amdzen4/memory-controller.json @@ -0,0 +1,101 @@ +[ + { + "EventName": "umc_mem_clk", + "PublicDescription": "Number of memory clock cycles.", + "EventCode": "0x00", + "PerPkg": "1", + "Unit": "UMCPMC" + }, + { + "EventName": "umc_act_cmd.all", + "PublicDescription": "Number of ACTIVATE commands sent.", + "EventCode": "0x05", + "PerPkg": "1", + "Unit": "UMCPMC" + }, + { + "EventName": "umc_act_cmd.rd", + "PublicDescription": "Number of ACTIVATE commands sent for reads.", + "EventCode": "0x05", + "RdWrMask": "0x1", + "PerPkg": "1", + "Unit": "UMCPMC" + }, + { + "EventName": "umc_act_cmd.wr", + "PublicDescription": "Number of ACTIVATE commands sent for writes.", + "EventCode": "0x05", + "RdWrMask": "0x2", + "PerPkg": "1", + "Unit": "UMCPMC" + }, + { + "EventName": "umc_pchg_cmd.all", + "PublicDescription": "Number of PRECHARGE commands sent.", + "EventCode": "0x06", + "PerPkg": "1", + "Unit": "UMCPMC" + }, + { + "EventName": "umc_pchg_cmd.rd", + "PublicDescription": "Number of PRECHARGE commands sent for reads.", + "EventCode": "0x06", + "RdWrMask": "0x1", + "PerPkg": "1", + "Unit": "UMCPMC" + }, + { + "EventName": "umc_pchg_cmd.wr", + "PublicDescription": "Number of PRECHARGE commands sent for writes.", + "EventCode": "0x06", + "RdWrMask": "0x2", + "PerPkg": "1", + "Unit": "UMCPMC" + }, + { + "EventName": "umc_cas_cmd.all", + "PublicDescription": "Number of CAS commands sent.", + "EventCode": "0x0a", + "PerPkg": "1", + "Unit": "UMCPMC" + }, + { + "EventName": "umc_cas_cmd.rd", + "PublicDescription": "Number of CAS commands sent for reads.", + "EventCode": "0x0a", + "RdWrMask": "0x1", + "PerPkg": "1", + "Unit": "UMCPMC" + }, + { + "EventName": "umc_cas_cmd.wr", + "PublicDescription": "Number of CAS commands sent for writes.", + "EventCode": "0x0a", + "RdWrMask": "0x2", + "PerPkg": "1", + "Unit": "UMCPMC" + }, + { + "EventName": "umc_data_slot_clks.all", + "PublicDescription": "Number of clocks used by the data bus.", + "EventCode": "0x14", + "PerPkg": "1", + "Unit": "UMCPMC" + }, + { + "EventName": "umc_data_slot_clks.rd", + "PublicDescription": "Number of clocks used by the data bus for reads.", + "EventCode": "0x14", + "RdWrMask": "0x1", + "PerPkg": "1", + "Unit": "UMCPMC" + }, + { + "EventName": "umc_data_slot_clks.wr", + "PublicDescription": "Number of clocks used by the data bus for writes.", + "EventCode": "0x14", + "RdWrMask": "0x2", + "PerPkg": "1", + "Unit": "UMCPMC" + } +] diff --git a/tools/perf/pmu-events/arch/x86/amdzen4/recommended.json b/tools/perf/pmu-events/arch/x86/amdzen4/recommended.json index 5e6a793acf..96e06401c6 100644 --- a/tools/perf/pmu-events/arch/x86/amdzen4/recommended.json +++ b/tools/perf/pmu-events/arch/x86/amdzen4/recommended.json @@ -330,5 +330,89 @@ "MetricGroup": "data_fabric", "PerPkg": "1", "ScaleUnit": "6.103515625e-5MiB" + }, + { + "MetricName": "umc_data_bus_utilization", + "BriefDescription": "Memory controller data bus utilization.", + "MetricExpr": "d_ratio(umc_data_slot_clks.all / 2, umc_mem_clk)", + "MetricGroup": "memory_controller", + "PerPkg": "1", + "ScaleUnit": "100%" + }, + { + "MetricName": "umc_cas_cmd_rate", + "BriefDescription": "Memory controller CAS command rate.", + "MetricExpr": "d_ratio(umc_cas_cmd.all * 1000, umc_mem_clk)", + "MetricGroup": "memory_controller", + "PerPkg": "1" + }, + { + "MetricName": "umc_cas_cmd_read_ratio", + "BriefDescription": "Ratio of memory controller CAS commands for reads.", + "MetricExpr": "d_ratio(umc_cas_cmd.rd, umc_cas_cmd.all)", + "MetricGroup": "memory_controller", + "PerPkg": "1", + "ScaleUnit": "100%" + }, + { + "MetricName": "umc_cas_cmd_write_ratio", + "BriefDescription": "Ratio of memory controller CAS commands for writes.", + "MetricExpr": "d_ratio(umc_cas_cmd.wr, umc_cas_cmd.all)", + "MetricGroup": "memory_controller", + "PerPkg": "1", + "ScaleUnit": "100%" + }, + { + "MetricName": "umc_mem_read_bandwidth", + "BriefDescription": "Estimated memory read bandwidth.", + "MetricExpr": "(umc_cas_cmd.rd * 64) / 1e6 / duration_time", + "MetricGroup": "memory_controller", + "PerPkg": "1", + "ScaleUnit": "1MB/s" + }, + { + "MetricName": "umc_mem_write_bandwidth", + "BriefDescription": "Estimated memory write bandwidth.", + "MetricExpr": "(umc_cas_cmd.wr * 64) / 1e6 / duration_time", + "MetricGroup": "memory_controller", + "PerPkg": "1", + "ScaleUnit": "1MB/s" + }, + { + "MetricName": "umc_mem_bandwidth", + "BriefDescription": "Estimated combined memory bandwidth.", + "MetricExpr": "(umc_cas_cmd.all * 64) / 1e6 / duration_time", + "MetricGroup": "memory_controller", + "PerPkg": "1", + "ScaleUnit": "1MB/s" + }, + { + "MetricName": "umc_cas_cmd_read_ratio", + "BriefDescription": "Ratio of memory controller CAS commands for reads.", + "MetricExpr": "d_ratio(umc_cas_cmd.rd, umc_cas_cmd.all)", + "MetricGroup": "memory_controller", + "PerPkg": "1", + "ScaleUnit": "100%" + }, + { + "MetricName": "umc_cas_cmd_rate", + "BriefDescription": "Memory controller CAS command rate.", + "MetricExpr": "d_ratio(umc_cas_cmd.all * 1000, umc_mem_clk)", + "MetricGroup": "memory_controller", + "PerPkg": "1" + }, + { + "MetricName": "umc_activate_cmd_rate", + "BriefDescription": "Memory controller ACTIVATE command rate.", + "MetricExpr": "d_ratio(umc_act_cmd.all * 1000, umc_mem_clk)", + "MetricGroup": "memory_controller", + "PerPkg": "1" + }, + { + "MetricName": "umc_precharge_cmd_rate", + "BriefDescription": "Memory controller PRECHARGE command rate.", + "MetricExpr": "d_ratio(umc_pchg_cmd.all * 1000, umc_mem_clk)", + "MetricGroup": "memory_controller", + "PerPkg": "1" } ] diff --git a/tools/perf/pmu-events/arch/x86/cascadelakex/clx-metrics.json b/tools/perf/pmu-events/arch/x86/cascadelakex/clx-metrics.json index 84c132af3d..8bc6c07078 100644 --- a/tools/perf/pmu-events/arch/x86/cascadelakex/clx-metrics.json +++ b/tools/perf/pmu-events/arch/x86/cascadelakex/clx-metrics.json @@ -1862,6 +1862,12 @@ "MetricName": "uncore_frequency", "ScaleUnit": "1GHz" }, + { + "BriefDescription": "Intel(R) Ultra Path Interconnect (UPI) data receive bandwidth (MB/sec)", + "MetricExpr": "UNC_UPI_RxL_FLITS.ALL_DATA * 7.111111111111111 / 1e6 / duration_time", + "MetricName": "upi_data_receive_bw", + "ScaleUnit": "1MB/s" + }, { "BriefDescription": "Intel(R) Ultra Path Interconnect (UPI) data transmit bandwidth (MB/sec)", "MetricExpr": "UNC_UPI_TxL_FLITS.ALL_DATA * 7.111111111111111 / 1e6 / duration_time", diff --git a/tools/perf/pmu-events/arch/x86/emeraldrapids/floating-point.json b/tools/perf/pmu-events/arch/x86/emeraldrapids/floating-point.json index 4a9d211e9d..1bdefaf962 100644 --- a/tools/perf/pmu-events/arch/x86/emeraldrapids/floating-point.json +++ b/tools/perf/pmu-events/arch/x86/emeraldrapids/floating-point.json @@ -23,26 +23,47 @@ "UMask": "0x10" }, { - "BriefDescription": "FP_ARITH_DISPATCHED.PORT_0", + "BriefDescription": "FP_ARITH_DISPATCHED.PORT_0 [This event is alias to FP_ARITH_DISPATCHED.V0]", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.PORT_0", "SampleAfterValue": "2000003", "UMask": "0x1" }, { - "BriefDescription": "FP_ARITH_DISPATCHED.PORT_1", + "BriefDescription": "FP_ARITH_DISPATCHED.PORT_1 [This event is alias to FP_ARITH_DISPATCHED.V1]", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.PORT_1", "SampleAfterValue": "2000003", "UMask": "0x2" }, { - "BriefDescription": "FP_ARITH_DISPATCHED.PORT_5", + "BriefDescription": "FP_ARITH_DISPATCHED.PORT_5 [This event is alias to FP_ARITH_DISPATCHED.V2]", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.PORT_5", "SampleAfterValue": "2000003", "UMask": "0x4" }, + { + "BriefDescription": "FP_ARITH_DISPATCHED.V0 [This event is alias to FP_ARITH_DISPATCHED.PORT_0]", + "EventCode": "0xb3", + "EventName": "FP_ARITH_DISPATCHED.V0", + "SampleAfterValue": "2000003", + "UMask": "0x1" + }, + { + "BriefDescription": "FP_ARITH_DISPATCHED.V1 [This event is alias to FP_ARITH_DISPATCHED.PORT_1]", + "EventCode": "0xb3", + "EventName": "FP_ARITH_DISPATCHED.V1", + "SampleAfterValue": "2000003", + "UMask": "0x2" + }, + { + "BriefDescription": "FP_ARITH_DISPATCHED.V2 [This event is alias to FP_ARITH_DISPATCHED.PORT_5]", + "EventCode": "0xb3", + "EventName": "FP_ARITH_DISPATCHED.V2", + "SampleAfterValue": "2000003", + "UMask": "0x4" + }, { "BriefDescription": "Counts number of SSE/AVX computational 128-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.", "EventCode": "0xc7", diff --git a/tools/perf/pmu-events/arch/x86/emeraldrapids/pipeline.json b/tools/perf/pmu-events/arch/x86/emeraldrapids/pipeline.json index 6dcf3b763a..1f8200fb89 100644 --- a/tools/perf/pmu-events/arch/x86/emeraldrapids/pipeline.json +++ b/tools/perf/pmu-events/arch/x86/emeraldrapids/pipeline.json @@ -1,20 +1,4 @@ [ - { - "BriefDescription": "AMX retired arithmetic BF16 operations.", - "EventCode": "0xce", - "EventName": "AMX_OPS_RETIRED.BF16", - "PublicDescription": "Number of AMX-based retired arithmetic bfloat16 (BF16) floating-point operations. Counts TDPBF16PS FP instructions. SW to use operation multiplier of 4", - "SampleAfterValue": "1000003", - "UMask": "0x2" - }, - { - "BriefDescription": "AMX retired arithmetic integer 8-bit operations.", - "EventCode": "0xce", - "EventName": "AMX_OPS_RETIRED.INT8", - "PublicDescription": "Number of AMX-based retired arithmetic integer operations of 8-bit width source operands. Counts TDPB[SS,UU,US,SU]D instructions. SW should use operation multiplier of 8.", - "SampleAfterValue": "1000003", - "UMask": "0x1" - }, { "BriefDescription": "This event is deprecated. Refer to new event ARITH.DIV_ACTIVE", "CounterMask": "1", @@ -505,7 +489,7 @@ "UMask": "0x1" }, { - "BriefDescription": "INT_MISC.UNKNOWN_BRANCH_CYCLES", + "BriefDescription": "Bubble cycles of BAClear (Unknown Branch).", "EventCode": "0xad", "EventName": "INT_MISC.UNKNOWN_BRANCH_CYCLES", "MSRIndex": "0x3F7", diff --git a/tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-interconnect.json b/tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-interconnect.json index 09d840c7da..65d088556b 100644 --- a/tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-interconnect.json +++ b/tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-interconnect.json @@ -4825,11 +4825,11 @@ "Unit": "M3UPI" }, { - "BriefDescription": "Number of allocations into the CRS Egress used to queue up requests destined to the mesh (AD Bouncable)", + "BriefDescription": "Number of allocations into the CRS Egress used to queue up requests destined to the mesh (AD Bounceable)", "EventCode": "0x47", "EventName": "UNC_MDF_CRS_TxR_INSERTS.AD_BNC", "PerPkg": "1", - "PublicDescription": "AD Bouncable : Number of allocations into the CRS Egress", + "PublicDescription": "AD Bounceable : Number of allocations into the CRS Egress", "UMask": "0x1", "Unit": "MDF" }, @@ -4861,11 +4861,11 @@ "Unit": "MDF" }, { - "BriefDescription": "Number of allocations into the CRS Egress used to queue up requests destined to the mesh (BL Bouncable)", + "BriefDescription": "Number of allocations into the CRS Egress used to queue up requests destined to the mesh (BL Bounceable)", "EventCode": "0x47", "EventName": "UNC_MDF_CRS_TxR_INSERTS.BL_BNC", "PerPkg": "1", - "PublicDescription": "BL Bouncable : Number of allocations into the CRS Egress", + "PublicDescription": "BL Bounceable : Number of allocations into the CRS Egress", "UMask": "0x4", "Unit": "MDF" }, diff --git a/tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-io.json b/tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-io.json index 557080b74e..0761980c34 100644 --- a/tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-io.json +++ b/tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-io.json @@ -1185,6 +1185,36 @@ "UMask": "0x70ff010", "Unit": "IIO" }, + { + "BriefDescription": ": IOTLB Hits to a 1G Page", + "EventCode": "0x40", + "EventName": "UNC_IIO_IOMMU0.1G_HITS", + "PerPkg": "1", + "PortMask": "0x0000", + "PublicDescription": ": IOTLB Hits to a 1G Page : Counts if a transaction to a 1G page, on its first lookup, hits the IOTLB.", + "UMask": "0x10", + "Unit": "IIO" + }, + { + "BriefDescription": ": IOTLB Hits to a 2M Page", + "EventCode": "0x40", + "EventName": "UNC_IIO_IOMMU0.2M_HITS", + "PerPkg": "1", + "PortMask": "0x0000", + "PublicDescription": ": IOTLB Hits to a 2M Page : Counts if a transaction to a 2M page, on its first lookup, hits the IOTLB.", + "UMask": "0x8", + "Unit": "IIO" + }, + { + "BriefDescription": ": IOTLB Hits to a 4K Page", + "EventCode": "0x40", + "EventName": "UNC_IIO_IOMMU0.4K_HITS", + "PerPkg": "1", + "PortMask": "0x0000", + "PublicDescription": ": IOTLB Hits to a 4K Page : Counts if a transaction to a 4K page, on its first lookup, hits the IOTLB.", + "UMask": "0x4", + "Unit": "IIO" + }, { "BriefDescription": ": Context cache hits", "EventCode": "0x40", diff --git a/tools/perf/pmu-events/arch/x86/icelakex/icx-metrics.json b/tools/perf/pmu-events/arch/x86/icelakex/icx-metrics.json index e98602c667..71d78a7841 100644 --- a/tools/perf/pmu-events/arch/x86/icelakex/icx-metrics.json +++ b/tools/perf/pmu-events/arch/x86/icelakex/icx-metrics.json @@ -1846,6 +1846,12 @@ "MetricName": "uncore_frequency", "ScaleUnit": "1GHz" }, + { + "BriefDescription": "Intel(R) Ultra Path Interconnect (UPI) data receive bandwidth (MB/sec)", + "MetricExpr": "UNC_UPI_RxL_FLITS.ALL_DATA * 7.111111111111111 / 1e6 / duration_time", + "MetricName": "upi_data_receive_bw", + "ScaleUnit": "1MB/s" + }, { "BriefDescription": "Intel(R) Ultra Path Interconnect (UPI) data transmit bandwidth (MB/sec)", "MetricExpr": "UNC_UPI_TxL_FLITS.ALL_DATA * 7.111111111111111 / 1e6 / duration_time", diff --git a/tools/perf/pmu-events/arch/x86/icelakex/other.json b/tools/perf/pmu-events/arch/x86/icelakex/other.json index 63d5faf2fc..11810daaf1 100644 --- a/tools/perf/pmu-events/arch/x86/icelakex/other.json +++ b/tools/perf/pmu-events/arch/x86/icelakex/other.json @@ -19,7 +19,7 @@ "BriefDescription": "Core cycles where the core was running in a manner where Turbo may be clipped to the AVX512 turbo schedule.", "EventCode": "0x28", "EventName": "CORE_POWER.LVL2_TURBO_LICENSE", - "PublicDescription": "Core cycles where the core was running with power-delivery for license level 2 (introduced in Skylake Server microarchtecture). This includes high current AVX 512-bit instructions.", + "PublicDescription": "Core cycles where the core was running with power-delivery for license level 2 (introduced in Skylake Server microarchitecture). This includes high current AVX 512-bit instructions.", "SampleAfterValue": "200003", "UMask": "0x20" }, diff --git a/tools/perf/pmu-events/arch/x86/icelakex/pipeline.json b/tools/perf/pmu-events/arch/x86/icelakex/pipeline.json index 176e5ef2a2..45ee6bceba 100644 --- a/tools/perf/pmu-events/arch/x86/icelakex/pipeline.json +++ b/tools/perf/pmu-events/arch/x86/icelakex/pipeline.json @@ -519,7 +519,7 @@ "BriefDescription": "Cycles when Reservation Station (RS) is empty for the thread", "EventCode": "0x5e", "EventName": "RS_EVENTS.EMPTY_CYCLES", - "PublicDescription": "Counts cycles during which the reservation station (RS) is empty for this logical processor. This is usually caused when the front-end pipeline runs into stravation periods (e.g. branch mispredictions or i-cache misses)", + "PublicDescription": "Counts cycles during which the reservation station (RS) is empty for this logical processor. This is usually caused when the front-end pipeline runs into starvation periods (e.g. branch mispredictions or i-cache misses)", "SampleAfterValue": "1000003", "UMask": "0x1" }, diff --git a/tools/perf/pmu-events/arch/x86/icelakex/uncore-interconnect.json b/tools/perf/pmu-events/arch/x86/icelakex/uncore-interconnect.json index f87ea3f66d..a066a009c5 100644 --- a/tools/perf/pmu-events/arch/x86/icelakex/uncore-interconnect.json +++ b/tools/perf/pmu-events/arch/x86/icelakex/uncore-interconnect.json @@ -38,7 +38,7 @@ "EventCode": "0x10", "EventName": "UNC_I_COHERENT_OPS.CLFLUSH", "PerPkg": "1", - "PublicDescription": "Coherent Ops : CLFlush : Counts the number of coherency related operations servied by the IRP", + "PublicDescription": "Coherent Ops : CLFlush : Counts the number of coherency related operations serviced by the IRP", "UMask": "0x80", "Unit": "IRP" }, @@ -65,7 +65,7 @@ "EventCode": "0x10", "EventName": "UNC_I_COHERENT_OPS.WBMTOI", "PerPkg": "1", - "PublicDescription": "Coherent Ops : WbMtoI : Counts the number of coherency related operations servied by the IRP", + "PublicDescription": "Coherent Ops : WbMtoI : Counts the number of coherency related operations serviced by the IRP", "UMask": "0x40", "Unit": "IRP" }, @@ -454,7 +454,7 @@ "EventCode": "0x11", "EventName": "UNC_I_TRANSACTIONS.WRITES", "PerPkg": "1", - "PublicDescription": "Inbound Transaction Count : Writes : Counts the number of Inbound transactions from the IRP to the Uncore. This can be filtered based on request type in addition to the source queue. Note the special filtering equation. We do OR-reduction on the request type. If the SOURCE bit is set, then we also do AND qualification based on the source portID. : Trackes only write requests. Each write request should have a prefetch, so there is no need to explicitly track these requests. For writes that are tickled and have to retry, the counter will be incremented for each retry.", + "PublicDescription": "Inbound Transaction Count : Writes : Counts the number of Inbound transactions from the IRP to the Uncore. This can be filtered based on request type in addition to the source queue. Note the special filtering equation. We do OR-reduction on the request type. If the SOURCE bit is set, then we also do AND qualification based on the source portID. : Tracks only write requests. Each write request should have a prefetch, so there is no need to explicitly track these requests. For writes that are tickled and have to retry, the counter will be incremented for each retry.", "UMask": "0x2", "Unit": "IRP" }, diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index e571683f59..4d1deed443 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -7,7 +7,7 @@ GenuineIntel-6-56,v11,broadwellde,core GenuineIntel-6-4F,v22,broadwellx,core GenuineIntel-6-55-[56789ABCDEF],v1.20,cascadelakex,core GenuineIntel-6-9[6C],v1.04,elkhartlake,core -GenuineIntel-6-CF,v1.01,emeraldrapids,core +GenuineIntel-6-CF,v1.02,emeraldrapids,core GenuineIntel-6-5[CF],v13,goldmont,core GenuineIntel-6-7A,v1.01,goldmontplus,core GenuineIntel-6-B6,v1.00,grandridge,core @@ -15,7 +15,7 @@ GenuineIntel-6-A[DE],v1.01,graniterapids,core GenuineIntel-6-(3C|45|46),v33,haswell,core GenuineIntel-6-3F,v28,haswellx,core GenuineIntel-6-7[DE],v1.19,icelake,core -GenuineIntel-6-6[AC],v1.21,icelakex,core +GenuineIntel-6-6[AC],v1.23,icelakex,core GenuineIntel-6-3A,v24,ivybridge,core GenuineIntel-6-3E,v24,ivytown,core GenuineIntel-6-2D,v24,jaketown,core @@ -26,7 +26,7 @@ GenuineIntel-6-1[AEF],v4,nehalemep,core GenuineIntel-6-2E,v4,nehalemex,core GenuineIntel-6-A7,v1.01,rocketlake,core GenuineIntel-6-2A,v19,sandybridge,core -GenuineIntel-6-8F,v1.16,sapphirerapids,core +GenuineIntel-6-8F,v1.17,sapphirerapids,core GenuineIntel-6-AF,v1.00,sierraforest,core GenuineIntel-6-(37|4A|4C|4D|5A),v15,silvermont,core GenuineIntel-6-(4E|5E|8E|9E|A5|A6),v57,skylake,core diff --git a/tools/perf/pmu-events/arch/x86/rocketlake/rkl-metrics.json b/tools/perf/pmu-events/arch/x86/rocketlake/rkl-metrics.json index 0c880e4156..27433fc15e 100644 --- a/tools/perf/pmu-events/arch/x86/rocketlake/rkl-metrics.json +++ b/tools/perf/pmu-events/arch/x86/rocketlake/rkl-metrics.json @@ -985,7 +985,7 @@ }, { "BriefDescription": "Average number of parallel data read requests to external memory", - "MetricExpr": "UNC_ARB_DAT_OCCUPANCY.RD / cpu@UNC_ARB_DAT_OCCUPANCY.RD\\,cmask\\=1@", + "MetricExpr": "UNC_ARB_DAT_OCCUPANCY.RD / UNC_ARB_DAT_OCCUPANCY.RD@cmask\\=1@", "MetricGroup": "Mem;MemoryBW;SoC", "MetricName": "tma_info_system_mem_parallel_reads", "PublicDescription": "Average number of parallel data read requests to external memory. Accounts for demand loads and L1/L2 prefetches" diff --git a/tools/perf/pmu-events/arch/x86/sapphirerapids/floating-point.json b/tools/perf/pmu-events/arch/x86/sapphirerapids/floating-point.json index 4a9d211e9d..1bdefaf962 100644 --- a/tools/perf/pmu-events/arch/x86/sapphirerapids/floating-point.json +++ b/tools/perf/pmu-events/arch/x86/sapphirerapids/floating-point.json @@ -23,26 +23,47 @@ "UMask": "0x10" }, { - "BriefDescription": "FP_ARITH_DISPATCHED.PORT_0", + "BriefDescription": "FP_ARITH_DISPATCHED.PORT_0 [This event is alias to FP_ARITH_DISPATCHED.V0]", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.PORT_0", "SampleAfterValue": "2000003", "UMask": "0x1" }, { - "BriefDescription": "FP_ARITH_DISPATCHED.PORT_1", + "BriefDescription": "FP_ARITH_DISPATCHED.PORT_1 [This event is alias to FP_ARITH_DISPATCHED.V1]", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.PORT_1", "SampleAfterValue": "2000003", "UMask": "0x2" }, { - "BriefDescription": "FP_ARITH_DISPATCHED.PORT_5", + "BriefDescription": "FP_ARITH_DISPATCHED.PORT_5 [This event is alias to FP_ARITH_DISPATCHED.V2]", "EventCode": "0xb3", "EventName": "FP_ARITH_DISPATCHED.PORT_5", "SampleAfterValue": "2000003", "UMask": "0x4" }, + { + "BriefDescription": "FP_ARITH_DISPATCHED.V0 [This event is alias to FP_ARITH_DISPATCHED.PORT_0]", + "EventCode": "0xb3", + "EventName": "FP_ARITH_DISPATCHED.V0", + "SampleAfterValue": "2000003", + "UMask": "0x1" + }, + { + "BriefDescription": "FP_ARITH_DISPATCHED.V1 [This event is alias to FP_ARITH_DISPATCHED.PORT_1]", + "EventCode": "0xb3", + "EventName": "FP_ARITH_DISPATCHED.V1", + "SampleAfterValue": "2000003", + "UMask": "0x2" + }, + { + "BriefDescription": "FP_ARITH_DISPATCHED.V2 [This event is alias to FP_ARITH_DISPATCHED.PORT_5]", + "EventCode": "0xb3", + "EventName": "FP_ARITH_DISPATCHED.V2", + "SampleAfterValue": "2000003", + "UMask": "0x4" + }, { "BriefDescription": "Counts number of SSE/AVX computational 128-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.", "EventCode": "0xc7", diff --git a/tools/perf/pmu-events/arch/x86/sapphirerapids/pipeline.json b/tools/perf/pmu-events/arch/x86/sapphirerapids/pipeline.json index 6dcf3b763a..2cfe814d20 100644 --- a/tools/perf/pmu-events/arch/x86/sapphirerapids/pipeline.json +++ b/tools/perf/pmu-events/arch/x86/sapphirerapids/pipeline.json @@ -505,7 +505,7 @@ "UMask": "0x1" }, { - "BriefDescription": "INT_MISC.UNKNOWN_BRANCH_CYCLES", + "BriefDescription": "Bubble cycles of BAClear (Unknown Branch).", "EventCode": "0xad", "EventName": "INT_MISC.UNKNOWN_BRANCH_CYCLES", "MSRIndex": "0x3F7", diff --git a/tools/perf/pmu-events/arch/x86/sapphirerapids/spr-metrics.json b/tools/perf/pmu-events/arch/x86/sapphirerapids/spr-metrics.json index 06c6d67cb7..56e54babcc 100644 --- a/tools/perf/pmu-events/arch/x86/sapphirerapids/spr-metrics.json +++ b/tools/perf/pmu-events/arch/x86/sapphirerapids/spr-metrics.json @@ -400,7 +400,6 @@ }, { "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to contested accesses", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(76 * tma_info_system_average_frequency * (MEM_LOAD_L3_HIT_RETIRED.XSNP_FWD * (OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HITM / (OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HITM + OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HIT_WITH_FWD))) + 75.5 * tma_info_system_average_frequency * MEM_LOAD_L3_HIT_RETIRED.XSNP_MISS) * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS / 2) / tma_info_thread_clks", "MetricGroup": "DataSharing;Offcore;Snoop;TopdownL4;tma_L4_group;tma_issueSyncxn;tma_l3_bound_group", "MetricName": "tma_contested_accesses", @@ -421,7 +420,6 @@ }, { "BriefDescription": "This metric estimates fraction of cycles while the memory subsystem was handling synchronizations due to data-sharing accesses", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "75.5 * tma_info_system_average_frequency * (MEM_LOAD_L3_HIT_RETIRED.XSNP_NO_FWD + MEM_LOAD_L3_HIT_RETIRED.XSNP_FWD * (1 - OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HITM / (OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HITM + OCR.DEMAND_DATA_RD.L3_HIT.SNOOP_HIT_WITH_FWD))) * (1 + MEM_LOAD_RETIRED.FB_HIT / MEM_LOAD_RETIRED.L1_MISS / 2) / tma_info_thread_clks", "MetricGroup": "Offcore;Snoop;TopdownL4;tma_L4_group;tma_issueSyncxn;tma_l3_bound_group", "MetricName": "tma_data_sharing", @@ -449,7 +447,6 @@ }, { "BriefDescription": "This metric estimates how often the CPU was stalled on accesses to external memory (DRAM) by loads", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(MEMORY_ACTIVITY.STALLS_L3_MISS / tma_info_thread_clks - tma_pmm_bound if #has_pmem > 0 else MEMORY_ACTIVITY.STALLS_L3_MISS / tma_info_thread_clks)", "MetricGroup": "MemoryBound;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", "MetricName": "tma_dram_bound", @@ -656,7 +653,6 @@ }, { "BriefDescription": "Branch Misprediction Cost: Fraction of TMA slots wasted per non-speculative branch misprediction (retired JEClear)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(tma_branch_mispredicts + tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches)) * tma_info_thread_slots / BR_MISP_RETIRED.ALL_BRANCHES", "MetricGroup": "Bad;BrMispredicts;tma_issueBM", "MetricName": "tma_info_bad_spec_branch_misprediction_cost", @@ -699,7 +695,6 @@ }, { "BriefDescription": "Probability of Core Bound bottleneck hidden by SMT-profiling artifacts", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(100 * (1 - tma_core_bound / tma_ports_utilization if tma_core_bound < tma_ports_utilization else 1) if tma_info_system_smt_2t_utilization > 0.5 else 0)", "MetricGroup": "Cor;SMT", "MetricName": "tma_info_botlnk_l0_core_bound_likely", @@ -707,7 +702,6 @@ }, { "BriefDescription": "Total pipeline cost of DSB (uop cache) misses - subset of the Instruction_Fetch_BW Bottleneck", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_fetch_latency * tma_dsb_switches / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches) + tma_fetch_bandwidth * tma_mite / (tma_dsb + tma_mite))", "MetricGroup": "DSBmiss;Fed;tma_issueFB", "MetricName": "tma_info_botlnk_l2_dsb_misses", @@ -716,7 +710,6 @@ }, { "BriefDescription": "Total pipeline cost of Instruction Cache misses - subset of the Big_Code Bottleneck", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_fetch_latency * tma_icache_misses / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches))", "MetricGroup": "Fed;FetchLat;IcMiss;tma_issueFL", "MetricName": "tma_info_botlnk_l2_ic_misses", @@ -725,7 +718,6 @@ }, { "BriefDescription": "Total pipeline cost of instruction fetch related bottlenecks by large code footprint programs (i-side cache; TLB and BTB misses)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * tma_fetch_latency * (tma_itlb_misses + tma_icache_misses + tma_unknown_branches) / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches)", "MetricGroup": "BigFoot;Fed;Frontend;IcMiss;MemoryTLB;tma_issueBC", "MetricName": "tma_info_bottleneck_big_code", @@ -742,7 +734,6 @@ }, { "BriefDescription": "Total pipeline cost of instruction fetch bandwidth related bottlenecks", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_frontend_bound - tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches)) - tma_info_bottleneck_big_code", "MetricGroup": "Fed;FetchBW;Frontend", "MetricName": "tma_info_bottleneck_instruction_fetch_bw", @@ -750,7 +741,6 @@ }, { "BriefDescription": "Total pipeline cost of (external) Memory Bandwidth related bottlenecks", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_pmm_bound + tma_store_bound) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_pmm_bound + tma_store_bound) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full))) + tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_pmm_bound + tma_store_bound) * (tma_fb_full / (tma_dtlb_load + tma_fb_full + tma_lock_latency + tma_split_loads + tma_store_fwd_blk))", "MetricGroup": "Mem;MemoryBW;Offcore;tma_issueBW", "MetricName": "tma_info_bottleneck_memory_bandwidth", @@ -759,7 +749,6 @@ }, { "BriefDescription": "Total pipeline cost of Memory Address Translation related bottlenecks (data-side TLBs)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * tma_memory_bound * (tma_l1_bound / max(tma_memory_bound, tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_pmm_bound + tma_store_bound) * (tma_dtlb_load / max(tma_l1_bound, tma_dtlb_load + tma_fb_full + tma_lock_latency + tma_split_loads + tma_store_fwd_blk)) + tma_store_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_pmm_bound + tma_store_bound) * (tma_dtlb_store / (tma_dtlb_store + tma_false_sharing + tma_split_stores + tma_store_latency + tma_streaming_stores)))", "MetricGroup": "Mem;MemoryTLB;Offcore;tma_issueTLB", "MetricName": "tma_info_bottleneck_memory_data_tlbs", @@ -768,7 +757,6 @@ }, { "BriefDescription": "Total pipeline cost of Memory Latency related bottlenecks (external memory and off-core caches)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_pmm_bound + tma_store_bound) * (tma_mem_latency / (tma_mem_bandwidth + tma_mem_latency)) + tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_pmm_bound + tma_store_bound) * (tma_l3_hit_latency / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full)) + tma_l2_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_pmm_bound + tma_store_bound))", "MetricGroup": "Mem;MemoryLat;Offcore;tma_issueLat", "MetricName": "tma_info_bottleneck_memory_latency", @@ -777,7 +765,6 @@ }, { "BriefDescription": "Total pipeline cost of Branch Misprediction related bottlenecks", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_branch_mispredicts + tma_fetch_latency * tma_mispredicts_resteers / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches))", "MetricGroup": "Bad;BadSpec;BrMispredicts;tma_issueBM", "MetricName": "tma_info_bottleneck_mispredictions", @@ -1301,6 +1288,7 @@ }, { "BriefDescription": "Average latency of data read request to external memory (in nanoseconds)", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "1e9 * (UNC_CHA_TOR_OCCUPANCY.IA_MISS_DRD / UNC_CHA_TOR_INSERTS.IA_MISS_DRD) / (tma_info_system_socket_clks / duration_time)", "MetricGroup": "Mem;MemoryLat;SoC", "MetricName": "tma_info_system_mem_read_latency", @@ -1455,7 +1443,6 @@ }, { "BriefDescription": "This metric estimates how often the CPU was stalled due to L2 cache accesses by loads", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(MEMORY_ACTIVITY.STALLS_L1D_MISS - MEMORY_ACTIVITY.STALLS_L2_MISS) / tma_info_thread_clks", "MetricGroup": "CacheMisses;MemoryBound;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", "MetricName": "tma_l2_bound", @@ -1465,7 +1452,6 @@ }, { "BriefDescription": "This metric estimates how often the CPU was stalled due to loads accesses to L3 cache or contended with a sibling Core", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "(MEMORY_ACTIVITY.STALLS_L2_MISS - MEMORY_ACTIVITY.STALLS_L3_MISS) / tma_info_thread_clks", "MetricGroup": "CacheMisses;MemoryBound;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", "MetricName": "tma_l3_bound", @@ -1538,7 +1524,6 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU spent handling cache misses due to lock operations", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(16 * max(0, MEM_INST_RETIRED.LOCK_LOADS - L2_RQSTS.ALL_RFO) + MEM_INST_RETIRED.LOCK_LOADS / MEM_INST_RETIRED.ALL_STORES * (10 * L2_RQSTS.RFO_HIT + min(CPU_CLK_UNHALTED.THREAD, OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_RFO))) / tma_info_thread_clks", "MetricGroup": "Offcore;TopdownL4;tma_L4_group;tma_issueRFO;tma_l1_bound_group", "MetricName": "tma_lock_latency", @@ -1596,6 +1581,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to LFENCE Instructions.", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "13 * MISC2_RETIRED.LFENCE / tma_info_thread_clks", "MetricGroup": "TopdownL6;tma_L6_group;tma_serializing_operation_group", "MetricName": "tma_memory_fence", @@ -1604,7 +1590,6 @@ }, { "BriefDescription": "This metric represents fraction of slots where the CPU was retiring memory operations -- uops for memory load or store accesses.", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "tma_light_operations * MEM_UOP_RETIRED.ANY / (tma_retiring * tma_info_thread_slots)", "MetricGroup": "Pipeline;TopdownL3;tma_L3_group;tma_light_operations_group", "MetricName": "tma_memory_operations", @@ -1676,7 +1661,6 @@ }, { "BriefDescription": "This metric represents the remaining light uops fraction the CPU has executed - remaining means not covered by other sibling nodes", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "max(0, tma_light_operations - (tma_fp_arith + tma_int_operations + tma_memory_operations + tma_fused_instructions + tma_non_fused_branches + tma_nop_instructions))", "MetricGroup": "Pipeline;TopdownL3;tma_L3_group;tma_light_operations_group", "MetricName": "tma_other_light_ops", @@ -1758,6 +1742,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed total of 2 uops per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "EXE_ACTIVITY.2_PORTS_UTIL / tma_info_thread_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_issue2P;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_2", @@ -1767,6 +1752,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles CPU executed total of 3 or more uops per cycle on all execution ports (Logical Processor cycles since ICL, Physical Core cycles otherwise)", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "UOPS_EXECUTED.CYCLES_GE_3 / tma_info_thread_clks", "MetricGroup": "PortsUtil;TopdownL4;tma_L4_group;tma_ports_utilization_group", "MetricName": "tma_ports_utilized_3m", @@ -1822,6 +1808,7 @@ }, { "BriefDescription": "This metric represents fraction of cycles the CPU was stalled due to PAUSE Instructions", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "CPU_CLK_UNHALTED.PAUSE / tma_info_thread_clks", "MetricGroup": "TopdownL6;tma_L6_group;tma_serializing_operation_group", "MetricName": "tma_slow_pause", @@ -1840,7 +1827,6 @@ }, { "BriefDescription": "This metric represents rate of split store accesses", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "MEM_INST_RETIRED.SPLIT_STORES / tma_info_core_core_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_issueSpSt;tma_store_bound_group", "MetricName": "tma_split_stores", @@ -1868,7 +1854,6 @@ }, { "BriefDescription": "This metric roughly estimates fraction of cycles when the memory subsystem had loads blocked since they could not forward data from earlier (in program order) overlapping stores", - "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "13 * LD_BLOCKS.STORE_FORWARD / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_store_fwd_blk", @@ -1964,6 +1949,12 @@ "MetricName": "uncore_frequency", "ScaleUnit": "1GHz" }, + { + "BriefDescription": "Intel(R) Ultra Path Interconnect (UPI) data receive bandwidth (MB/sec)", + "MetricExpr": "UNC_UPI_RxL_FLITS.ALL_DATA * 7.111111111111111 / 1e6 / duration_time", + "MetricName": "upi_data_receive_bw", + "ScaleUnit": "1MB/s" + }, { "BriefDescription": "Intel(R) Ultra Path Interconnect (UPI) data transmit bandwidth (MB/sec)", "MetricExpr": "UNC_UPI_TxL_FLITS.ALL_DATA * 7.111111111111111 / 1e6 / duration_time", diff --git a/tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-interconnect.json b/tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-interconnect.json index 09d840c7da..65d088556b 100644 --- a/tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-interconnect.json +++ b/tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-interconnect.json @@ -4825,11 +4825,11 @@ "Unit": "M3UPI" }, { - "BriefDescription": "Number of allocations into the CRS Egress used to queue up requests destined to the mesh (AD Bouncable)", + "BriefDescription": "Number of allocations into the CRS Egress used to queue up requests destined to the mesh (AD Bounceable)", "EventCode": "0x47", "EventName": "UNC_MDF_CRS_TxR_INSERTS.AD_BNC", "PerPkg": "1", - "PublicDescription": "AD Bouncable : Number of allocations into the CRS Egress", + "PublicDescription": "AD Bounceable : Number of allocations into the CRS Egress", "UMask": "0x1", "Unit": "MDF" }, @@ -4861,11 +4861,11 @@ "Unit": "MDF" }, { - "BriefDescription": "Number of allocations into the CRS Egress used to queue up requests destined to the mesh (BL Bouncable)", + "BriefDescription": "Number of allocations into the CRS Egress used to queue up requests destined to the mesh (BL Bounceable)", "EventCode": "0x47", "EventName": "UNC_MDF_CRS_TxR_INSERTS.BL_BNC", "PerPkg": "1", - "PublicDescription": "BL Bouncable : Number of allocations into the CRS Egress", + "PublicDescription": "BL Bounceable : Number of allocations into the CRS Egress", "UMask": "0x4", "Unit": "MDF" }, diff --git a/tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-io.json b/tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-io.json index 8b5f54fed1..03596db877 100644 --- a/tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-io.json +++ b/tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-io.json @@ -1249,6 +1249,36 @@ "UMask": "0x70ff010", "Unit": "IIO" }, + { + "BriefDescription": ": IOTLB Hits to a 1G Page", + "EventCode": "0x40", + "EventName": "UNC_IIO_IOMMU0.1G_HITS", + "PerPkg": "1", + "PortMask": "0x0000", + "PublicDescription": ": IOTLB Hits to a 1G Page : Counts if a transaction to a 1G page, on its first lookup, hits the IOTLB.", + "UMask": "0x10", + "Unit": "IIO" + }, + { + "BriefDescription": ": IOTLB Hits to a 2M Page", + "EventCode": "0x40", + "EventName": "UNC_IIO_IOMMU0.2M_HITS", + "PerPkg": "1", + "PortMask": "0x0000", + "PublicDescription": ": IOTLB Hits to a 2M Page : Counts if a transaction to a 2M page, on its first lookup, hits the IOTLB.", + "UMask": "0x8", + "Unit": "IIO" + }, + { + "BriefDescription": ": IOTLB Hits to a 4K Page", + "EventCode": "0x40", + "EventName": "UNC_IIO_IOMMU0.4K_HITS", + "PerPkg": "1", + "PortMask": "0x0000", + "PublicDescription": ": IOTLB Hits to a 4K Page : Counts if a transaction to a 4K page, on its first lookup, hits the IOTLB.", + "UMask": "0x4", + "Unit": "IIO" + }, { "BriefDescription": ": Context cache hits", "EventCode": "0x40", diff --git a/tools/perf/pmu-events/arch/x86/skylakex/skx-metrics.json b/tools/perf/pmu-events/arch/x86/skylakex/skx-metrics.json index 4a8f8eeb75..ec3aa5ef00 100644 --- a/tools/perf/pmu-events/arch/x86/skylakex/skx-metrics.json +++ b/tools/perf/pmu-events/arch/x86/skylakex/skx-metrics.json @@ -1806,6 +1806,12 @@ "MetricName": "uncore_frequency", "ScaleUnit": "1GHz" }, + { + "BriefDescription": "Intel(R) Ultra Path Interconnect (UPI) data receive bandwidth (MB/sec)", + "MetricExpr": "UNC_UPI_RxL_FLITS.ALL_DATA * 7.111111111111111 / 1e6 / duration_time", + "MetricName": "upi_data_receive_bw", + "ScaleUnit": "1MB/s" + }, { "BriefDescription": "Intel(R) Ultra Path Interconnect (UPI) data transmit bandwidth (MB/sec)", "MetricExpr": "UNC_UPI_TxL_FLITS.ALL_DATA * 7.111111111111111 / 1e6 / duration_time", diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py index 3c091ab753..ce846f29c0 100755 --- a/tools/perf/pmu-events/jevents.py +++ b/tools/perf/pmu-events/jevents.py @@ -83,7 +83,7 @@ def c_len(s: str) -> int: """Return the length of s a C string This doesn't handle all escape characters properly. It first assumes - all \ are for escaping, it then adjusts as it will have over counted + all \\ are for escaping, it then adjusts as it will have over counted \\. The code uses \000 rather than \0 as a terminator as an adjacent number would be folded into a string of \0 (ie. "\0" + "5" doesn't equal a terminator followed by the number 5 but the escape of @@ -286,6 +286,7 @@ class JsonEvent: 'imx8_ddr': 'imx8_ddr', 'L3PMC': 'amd_l3', 'DFPMC': 'amd_df', + 'UMCPMC': 'amd_umc', 'cpu_core': 'cpu_core', 'cpu_atom': 'cpu_atom', 'ali_drw': 'ali_drw', @@ -354,6 +355,11 @@ class JsonEvent: ('SampleAfterValue', 'period='), ('UMask', 'umask='), ('NodeType', 'type='), + ('RdWrMask', 'rdwrmask='), + ('EnAllCores', 'enallcores='), + ('EnAllSlices', 'enallslices='), + ('SliceId', 'sliceid='), + ('ThreadMask', 'threadmask='), ] for key, value in event_fields: if key in jd and jd[key] != '0': diff --git a/tools/perf/scripts/python/arm-cs-trace-disasm.py b/tools/perf/scripts/python/arm-cs-trace-disasm.py index d59ff53f1d..d973c2baed 100755 --- a/tools/perf/scripts/python/arm-cs-trace-disasm.py +++ b/tools/perf/scripts/python/arm-cs-trace-disasm.py @@ -45,8 +45,8 @@ parser = OptionParser(option_list=option_list) # Initialize global dicts and regular expression disasm_cache = dict() cpu_data = dict() -disasm_re = re.compile("^\s*([0-9a-fA-F]+):") -disasm_func_re = re.compile("^\s*([0-9a-fA-F]+)\s.*:") +disasm_re = re.compile(r"^\s*([0-9a-fA-F]+):") +disasm_func_re = re.compile(r"^\s*([0-9a-fA-F]+)\s.*:") cache_size = 64*1024 glb_source_file_name = None @@ -188,6 +188,17 @@ def process_event(param_dict): dso_end = get_optional(param_dict, "dso_map_end") symbol = get_optional(param_dict, "symbol") + cpu = sample["cpu"] + ip = sample["ip"] + addr = sample["addr"] + + # Initialize CPU data if it's empty, and directly return back + # if this is the first tracing event for this CPU. + if (cpu_data.get(str(cpu) + 'addr') == None): + cpu_data[str(cpu) + 'addr'] = addr + return + + if (options.verbose == True): print("Event type: %s" % name) print_sample(sample) @@ -209,16 +220,6 @@ def process_event(param_dict): if (name[0:8] != "branches"): return - cpu = sample["cpu"] - ip = sample["ip"] - addr = sample["addr"] - - # Initialize CPU data if it's empty, and directly return back - # if this is the first tracing event for this CPU. - if (cpu_data.get(str(cpu) + 'addr') == None): - cpu_data[str(cpu) + 'addr'] = addr - return - # The format for packet is: # # +------------+------------+------------+ @@ -258,8 +259,9 @@ def process_event(param_dict): if (options.objdump_name != None): # It doesn't need to decrease virtual memory offset for disassembly - # for kernel dso, so in this case we set vm_start to zero. - if (dso == "[kernel.kallsyms]"): + # for kernel dso and executable file dso, so in this case we set + # vm_start to zero. + if (dso == "[kernel.kallsyms]" or dso_start == 0x400000): dso_vm_start = 0 else: dso_vm_start = int(dso_start) diff --git a/tools/perf/scripts/python/compaction-times.py b/tools/perf/scripts/python/compaction-times.py index 2560a042dc..9401f7c147 100644 --- a/tools/perf/scripts/python/compaction-times.py +++ b/tools/perf/scripts/python/compaction-times.py @@ -260,7 +260,7 @@ def pr_help(): comm_re = None pid_re = None -pid_regex = "^(\d*)-(\d*)$|^(\d*)$" +pid_regex = r"^(\d*)-(\d*)$|^(\d*)$" opt_proc = popt.DISP_DFL opt_disp = topt.DISP_ALL diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py index 13f2d8a816..121cf61ba1 100755 --- a/tools/perf/scripts/python/exported-sql-viewer.py +++ b/tools/perf/scripts/python/exported-sql-viewer.py @@ -677,8 +677,8 @@ class CallGraphModelBase(TreeModel): # sqlite supports GLOB (text only) which uses * and ? and is case sensitive if not self.glb.dbref.is_sqlite3: # Escape % and _ - s = value.replace("%", "\%") - s = s.replace("_", "\_") + s = value.replace("%", "\\%") + s = s.replace("_", "\\_") # Translate * and ? into SQL LIKE pattern characters % and _ trans = string.maketrans("*?", "%_") match = " LIKE '" + str(s).translate(trans) + "'" diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build index 2b45ffa462..53ba9c3e20 100644 --- a/tools/perf/tests/Build +++ b/tools/perf/tests/Build @@ -77,3 +77,17 @@ CFLAGS_python-use.o += -DPYTHONPATH="BUILD_STR($(OUTPUT)python)" -DPYTHON="BUI CFLAGS_dwarf-unwind.o += -fno-optimize-sibling-calls perf-y += workloads/ + +ifdef SHELLCHECK + SHELL_TESTS := $(shell find tests/shell -executable -type f -name '*.sh') + TEST_LOGS := $(SHELL_TESTS:tests/shell/%=shell/%.shellcheck_log) +else + SHELL_TESTS := + TEST_LOGS := +endif + +$(OUTPUT)%.shellcheck_log: % + $(call rule_mkdir) + $(Q)$(call echo-cmd,test)shellcheck -a -S warning "$<" > $@ || (cat $@ && rm $@ && false) + +perf-y += $(TEST_LOGS) diff --git a/tools/perf/tests/attr.c b/tools/perf/tests/attr.c index 61186d0d1c..97e1bdd6ec 100644 --- a/tools/perf/tests/attr.c +++ b/tools/perf/tests/attr.c @@ -188,7 +188,7 @@ static int test__attr(struct test_suite *test __maybe_unused, int subtest __mayb if (perf_pmus__num_core_pmus() > 1) { /* * TODO: Attribute tests hard code the PMU type. If there are >1 - * core PMU then each PMU will have a different type whic + * core PMU then each PMU will have a different type which * requires additional support. */ pr_debug("Skip test on hybrid systems"); diff --git a/tools/perf/tests/attr/base-record b/tools/perf/tests/attr/base-record index 27c21271a1..b44e4e6e44 100644 --- a/tools/perf/tests/attr/base-record +++ b/tools/perf/tests/attr/base-record @@ -6,7 +6,7 @@ flags=0|8 cpu=* type=0|1 size=136 -config=0 +config=0|1 sample_period=* sample_type=263 read_format=0|4|20 diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index cb6f1dd00d..4a5973f9bb 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -14,6 +14,7 @@ #include #include #include "builtin.h" +#include "config.h" #include "hist.h" #include "intlist.h" #include "tests.h" @@ -32,6 +33,7 @@ static bool dont_fork; const char *dso_to_test; +const char *test_objdump_path = "objdump"; /* * List of architecture specific tests. Not a weak symbol as the array length is @@ -60,8 +62,6 @@ static struct test_suite *generic_tests[] = { &suite__pmu, &suite__pmu_events, &suite__dso_data, - &suite__dso_data_cache, - &suite__dso_data_reopen, &suite__perf_evsel__roundtrip_name_test, #ifdef HAVE_LIBTRACEEVENT &suite__perf_evsel__tp_sched_test, @@ -513,6 +513,15 @@ static int run_workload(const char *work, int argc, const char **argv) return -1; } +static int perf_test__config(const char *var, const char *value, + void *data __maybe_unused) +{ + if (!strcmp(var, "annotate.objdump")) + test_objdump_path = value; + + return 0; +} + int cmd_test(int argc, const char **argv) { const char *test_usage[] = { @@ -529,6 +538,8 @@ int cmd_test(int argc, const char **argv) "Do not fork for testcase"), OPT_STRING('w', "workload", &workload, "work", "workload to run for testing"), OPT_STRING(0, "dso", &dso_to_test, "dso", "dso to test"), + OPT_STRING(0, "objdump", &test_objdump_path, "path", + "objdump binary to use for disassembly and annotations"), OPT_END() }; const char * const test_subcommands[] = { "list", NULL }; @@ -538,6 +549,8 @@ int cmd_test(int argc, const char **argv) if (ret < 0) return ret; + perf_config(perf_test__config, NULL); + /* Unbuffered output */ setvbuf(stdout, NULL, _IONBF, 0); diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index 3af8101201..7a3a7bbbec 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c @@ -185,7 +185,7 @@ static int read_via_objdump(const char *filename, u64 addr, void *buf, int ret; fmt = "%s -z -d --start-address=0x%"PRIx64" --stop-address=0x%"PRIx64" %s"; - ret = snprintf(cmd, sizeof(cmd), fmt, "objdump", addr, addr + len, + ret = snprintf(cmd, sizeof(cmd), fmt, test_objdump_path, addr, addr + len, filename); if (ret <= 0 || (size_t)ret >= sizeof(cmd)) return -1; @@ -511,38 +511,6 @@ static void fs_something(void) } } -#ifdef __s390x__ -#include "header.h" // for get_cpuid() -#endif - -static const char *do_determine_event(bool excl_kernel) -{ - const char *event = excl_kernel ? "cycles:u" : "cycles"; - -#ifdef __s390x__ - char cpuid[128], model[16], model_c[16], cpum_cf_v[16]; - unsigned int family; - int ret, cpum_cf_a; - - if (get_cpuid(cpuid, sizeof(cpuid))) - goto out_clocks; - ret = sscanf(cpuid, "%*[^,],%u,%[^,],%[^,],%[^,],%x", &family, model_c, - model, cpum_cf_v, &cpum_cf_a); - if (ret != 5) /* Not available */ - goto out_clocks; - if (excl_kernel && (cpum_cf_a & 4)) - return event; - if (!excl_kernel && (cpum_cf_a & 2)) - return event; - - /* Fall through: missing authorization */ -out_clocks: - event = excl_kernel ? "cpu-clock:u" : "cpu-clock"; - -#endif - return event; -} - static void do_something(void) { fs_something(); @@ -583,8 +551,10 @@ static int do_test_code_reading(bool try_kcore) int err = -1, ret; pid_t pid; struct map *map; - bool have_vmlinux, have_kcore, excl_kernel = false; + bool have_vmlinux, have_kcore; struct dso *dso; + const char *events[] = { "cycles", "cycles:u", "cpu-clock", "cpu-clock:u", NULL }; + int evidx = 0; pid = getpid(); @@ -618,7 +588,7 @@ static int do_test_code_reading(bool try_kcore) /* No point getting kernel events if there is no kernel object */ if (!have_vmlinux && !have_kcore) - excl_kernel = true; + evidx++; threads = thread_map__new_by_tid(pid); if (!threads) { @@ -640,13 +610,13 @@ static int do_test_code_reading(bool try_kcore) goto out_put; } - cpus = perf_cpu_map__new(NULL); + cpus = perf_cpu_map__new_online_cpus(); if (!cpus) { pr_debug("perf_cpu_map__new failed\n"); goto out_put; } - while (1) { + while (events[evidx]) { const char *str; evlist = evlist__new(); @@ -657,7 +627,7 @@ static int do_test_code_reading(bool try_kcore) perf_evlist__set_maps(&evlist->core, cpus, threads); - str = do_determine_event(excl_kernel); + str = events[evidx]; pr_debug("Parsing event '%s'\n", str); ret = parse_event(evlist, str); if (ret < 0) { @@ -675,32 +645,32 @@ static int do_test_code_reading(bool try_kcore) ret = evlist__open(evlist); if (ret < 0) { - if (!excl_kernel) { - excl_kernel = true; - /* - * Both cpus and threads are now owned by evlist - * and will be freed by following perf_evlist__set_maps - * call. Getting reference to keep them alive. - */ - perf_cpu_map__get(cpus); - perf_thread_map__get(threads); - perf_evlist__set_maps(&evlist->core, NULL, NULL); - evlist__delete(evlist); - evlist = NULL; - continue; - } + evidx++; - if (verbose > 0) { + if (events[evidx] == NULL && verbose > 0) { char errbuf[512]; evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf)); pr_debug("perf_evlist__open() failed!\n%s\n", errbuf); } - goto out_put; + /* + * Both cpus and threads are now owned by evlist + * and will be freed by following perf_evlist__set_maps + * call. Getting reference to keep them alive. + */ + perf_cpu_map__get(cpus); + perf_thread_map__get(threads); + perf_evlist__set_maps(&evlist->core, NULL, NULL); + evlist__delete(evlist); + evlist = NULL; + continue; } break; } + if (events[evidx] == NULL) + goto out_put; + ret = evlist__mmap(evlist, UINT_MAX); if (ret < 0) { pr_debug("evlist__mmap failed\n"); @@ -721,7 +691,7 @@ static int do_test_code_reading(bool try_kcore) err = TEST_CODE_READING_NO_KERNEL_OBJ; else if (!have_vmlinux && !try_kcore) err = TEST_CODE_READING_NO_VMLINUX; - else if (excl_kernel) + else if (strstr(events[evidx], ":u")) err = TEST_CODE_READING_NO_ACCESS; else err = TEST_CODE_READING_OK; diff --git a/tools/perf/tests/cpumap.c b/tools/perf/tests/cpumap.c index 7730fc2ab4..bd8e396f3e 100644 --- a/tools/perf/tests/cpumap.c +++ b/tools/perf/tests/cpumap.c @@ -213,7 +213,7 @@ static int test__cpu_map_intersect(struct test_suite *test __maybe_unused, static int test__cpu_map_equal(struct test_suite *test __maybe_unused, int subtest __maybe_unused) { - struct perf_cpu_map *any = perf_cpu_map__dummy_new(); + struct perf_cpu_map *any = perf_cpu_map__new_any_cpu(); struct perf_cpu_map *one = perf_cpu_map__new("1"); struct perf_cpu_map *two = perf_cpu_map__new("2"); struct perf_cpu_map *empty = perf_cpu_map__intersect(one, two); diff --git a/tools/perf/tests/dso-data.c b/tools/perf/tests/dso-data.c index 3419a4ab55..2d67422c12 100644 --- a/tools/perf/tests/dso-data.c +++ b/tools/perf/tests/dso-data.c @@ -394,6 +394,15 @@ static int test__dso_data_reopen(struct test_suite *test __maybe_unused, int sub return 0; } -DEFINE_SUITE("DSO data read", dso_data); -DEFINE_SUITE("DSO data cache", dso_data_cache); -DEFINE_SUITE("DSO data reopen", dso_data_reopen); + +static struct test_case tests__dso_data[] = { + TEST_CASE("read", dso_data), + TEST_CASE("cache", dso_data_cache), + TEST_CASE("reopen", dso_data_reopen), + { .name = NULL, } +}; + +struct test_suite suite__dso_data = { + .desc = "DSO data tests", + .test_cases = tests__dso_data, +}; diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c index 8f4f9b632e..5a3b2bed07 100644 --- a/tools/perf/tests/keep-tracking.c +++ b/tools/perf/tests/keep-tracking.c @@ -81,7 +81,7 @@ static int test__keep_tracking(struct test_suite *test __maybe_unused, int subte threads = thread_map__new(-1, getpid(), UINT_MAX); CHECK_NOT_NULL__(threads); - cpus = perf_cpu_map__new(NULL); + cpus = perf_cpu_map__new_online_cpus(); CHECK_NOT_NULL__(cpus); evlist = evlist__new(); diff --git a/tools/perf/tests/make b/tools/perf/tests/make index d9945ed25b..8a4da7eb63 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make @@ -183,7 +183,7 @@ run += make_install_prefix_slash # run += make_install_pdf run += make_minimal -old_libbpf := $(shell echo '\#include ' | $(CC) -E -dM -x c -| egrep -q "define[[:space:]]+LIBBPF_MAJOR_VERSION[[:space:]]+0{1}") +old_libbpf := $(shell echo '\#include ' | $(CC) -E -dM -x c -| grep -q -E "define[[:space:]]+LIBBPF_MAJOR_VERSION[[:space:]]+0{1}") ifneq ($(old_libbpf),) run += make_libbpf_dynamic diff --git a/tools/perf/tests/maps.c b/tools/perf/tests/maps.c index 5bb1123a91..bb3fbfe5a7 100644 --- a/tools/perf/tests/maps.c +++ b/tools/perf/tests/maps.c @@ -14,44 +14,59 @@ struct map_def { u64 end; }; +struct check_maps_cb_args { + struct map_def *merged; + unsigned int i; +}; + +static int check_maps_cb(struct map *map, void *data) +{ + struct check_maps_cb_args *args = data; + struct map_def *merged = &args->merged[args->i]; + + if (map__start(map) != merged->start || + map__end(map) != merged->end || + strcmp(map__dso(map)->name, merged->name) || + refcount_read(map__refcnt(map)) != 1) { + return 1; + } + args->i++; + return 0; +} + +static int failed_cb(struct map *map, void *data __maybe_unused) +{ + pr_debug("\tstart: %" PRIu64 " end: %" PRIu64 " name: '%s' refcnt: %d\n", + map__start(map), + map__end(map), + map__dso(map)->name, + refcount_read(map__refcnt(map))); + + return 0; +} + static int check_maps(struct map_def *merged, unsigned int size, struct maps *maps) { - struct map_rb_node *rb_node; - unsigned int i = 0; bool failed = false; if (maps__nr_maps(maps) != size) { pr_debug("Expected %d maps, got %d", size, maps__nr_maps(maps)); failed = true; } else { - maps__for_each_entry(maps, rb_node) { - struct map *map = rb_node->map; - - if (map__start(map) != merged[i].start || - map__end(map) != merged[i].end || - strcmp(map__dso(map)->name, merged[i].name) || - refcount_read(map__refcnt(map)) != 1) { - failed = true; - } - i++; - } + struct check_maps_cb_args args = { + .merged = merged, + .i = 0, + }; + failed = maps__for_each_map(maps, check_maps_cb, &args); } if (failed) { pr_debug("Expected:\n"); - for (i = 0; i < size; i++) { + for (unsigned int i = 0; i < size; i++) { pr_debug("\tstart: %" PRIu64 " end: %" PRIu64 " name: '%s' refcnt: 1\n", merged[i].start, merged[i].end, merged[i].name); } pr_debug("Got:\n"); - maps__for_each_entry(maps, rb_node) { - struct map *map = rb_node->map; - - pr_debug("\tstart: %" PRIu64 " end: %" PRIu64 " name: '%s' refcnt: %d\n", - map__start(map), - map__end(map), - map__dso(map)->name, - refcount_read(map__refcnt(map))); - } + maps__for_each_map(maps, failed_cb, NULL); } return failed ? TEST_FAIL : TEST_OK; } diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c index 886a13a77a..012c8ae439 100644 --- a/tools/perf/tests/mmap-basic.c +++ b/tools/perf/tests/mmap-basic.c @@ -52,7 +52,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest return -1; } - cpus = perf_cpu_map__new(NULL); + cpus = perf_cpu_map__new_online_cpus(); if (cpus == NULL) { pr_debug("perf_cpu_map__new\n"); goto out_free_threads; diff --git a/tools/perf/tests/openat-syscall-all-cpus.c b/tools/perf/tests/openat-syscall-all-cpus.c index f3275be83a..fb114118c8 100644 --- a/tools/perf/tests/openat-syscall-all-cpus.c +++ b/tools/perf/tests/openat-syscall-all-cpus.c @@ -37,7 +37,7 @@ static int test__openat_syscall_event_on_all_cpus(struct test_suite *test __mayb return -1; } - cpus = perf_cpu_map__new(NULL); + cpus = perf_cpu_map__new_online_cpus(); if (cpus == NULL) { pr_debug("perf_cpu_map__new\n"); goto out_thread_map_delete; diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index f78be21a59..fbdf710d5e 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -162,6 +162,22 @@ static int test__checkevent_numeric(struct evlist *evlist) return TEST_OK; } + +static int assert_hw(struct perf_evsel *evsel, enum perf_hw_id id, const char *name) +{ + struct perf_pmu *pmu; + + if (evsel->attr.type == PERF_TYPE_HARDWARE) { + TEST_ASSERT_VAL("wrong config", test_perf_config(evsel, id)); + return 0; + } + pmu = perf_pmus__find_by_type(evsel->attr.type); + + TEST_ASSERT_VAL("unexpected PMU type", pmu); + TEST_ASSERT_VAL("PMU missing event", perf_pmu__have_event(pmu, name)); + return 0; +} + static int test__checkevent_symbolic_name(struct evlist *evlist) { struct perf_evsel *evsel; @@ -169,10 +185,12 @@ static int test__checkevent_symbolic_name(struct evlist *evlist) TEST_ASSERT_VAL("wrong number of entries", 0 != evlist->core.nr_entries); perf_evlist__for_each_evsel(&evlist->core, evsel) { - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); - TEST_ASSERT_VAL("wrong config", - test_perf_config(evsel, PERF_COUNT_HW_INSTRUCTIONS)); + int ret = assert_hw(evsel, PERF_COUNT_HW_INSTRUCTIONS, "instructions"); + + if (ret) + return ret; } + return TEST_OK; } @@ -183,8 +201,10 @@ static int test__checkevent_symbolic_name_config(struct evlist *evlist) TEST_ASSERT_VAL("wrong number of entries", 0 != evlist->core.nr_entries); perf_evlist__for_each_evsel(&evlist->core, evsel) { - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); - TEST_ASSERT_VAL("wrong config", test_perf_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); + int ret = assert_hw(evsel, PERF_COUNT_HW_CPU_CYCLES, "cycles"); + + if (ret) + return ret; /* * The period value gets configured within evlist__config, * while this test executes only parse events method. @@ -861,10 +881,14 @@ static int test__group1(struct evlist *evlist) evlist__nr_groups(evlist) == num_core_entries()); for (int i = 0; i < num_core_entries(); i++) { + int ret; + /* instructions:k */ evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel)); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_INSTRUCTIONS)); + ret = assert_hw(&evsel->core, PERF_COUNT_HW_INSTRUCTIONS, "instructions"); + if (ret) + return ret; + TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); @@ -878,8 +902,10 @@ static int test__group1(struct evlist *evlist) /* cycles:upp */ evsel = evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); + ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); + if (ret) + return ret; + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); @@ -907,6 +933,8 @@ static int test__group2(struct evlist *evlist) TEST_ASSERT_VAL("wrong number of groups", 1 == evlist__nr_groups(evlist)); evlist__for_each_entry(evlist, evsel) { + int ret; + if (evsel->core.attr.type == PERF_TYPE_SOFTWARE) { /* faults + :ku modifier */ leader = evsel; @@ -939,8 +967,10 @@ static int test__group2(struct evlist *evlist) continue; } /* cycles:k */ - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); + ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); + if (ret) + return ret; + TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); @@ -957,6 +987,7 @@ static int test__group2(struct evlist *evlist) static int test__group3(struct evlist *evlist __maybe_unused) { struct evsel *evsel, *group1_leader = NULL, *group2_leader = NULL; + int ret; TEST_ASSERT_VAL("wrong number of entries", evlist->core.nr_entries == (3 * perf_pmus__num_core_pmus() + 2)); @@ -1045,8 +1076,10 @@ static int test__group3(struct evlist *evlist __maybe_unused) continue; } /* instructions:u */ - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_INSTRUCTIONS)); + ret = assert_hw(&evsel->core, PERF_COUNT_HW_INSTRUCTIONS, "instructions"); + if (ret) + return ret; + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); @@ -1070,10 +1103,14 @@ static int test__group4(struct evlist *evlist __maybe_unused) num_core_entries() == evlist__nr_groups(evlist)); for (int i = 0; i < num_core_entries(); i++) { + int ret; + /* cycles:u + p */ evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel)); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); + ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); + if (ret) + return ret; + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); @@ -1089,8 +1126,10 @@ static int test__group4(struct evlist *evlist __maybe_unused) /* instructions:kp + p */ evsel = evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_INSTRUCTIONS)); + ret = assert_hw(&evsel->core, PERF_COUNT_HW_INSTRUCTIONS, "instructions"); + if (ret) + return ret; + TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); @@ -1108,6 +1147,7 @@ static int test__group4(struct evlist *evlist __maybe_unused) static int test__group5(struct evlist *evlist __maybe_unused) { struct evsel *evsel = NULL, *leader; + int ret; TEST_ASSERT_VAL("wrong number of entries", evlist->core.nr_entries == (5 * num_core_entries())); @@ -1117,8 +1157,10 @@ static int test__group5(struct evlist *evlist __maybe_unused) for (int i = 0; i < num_core_entries(); i++) { /* cycles + G */ evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel)); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); + ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); + if (ret) + return ret; + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); @@ -1133,8 +1175,10 @@ static int test__group5(struct evlist *evlist __maybe_unused) /* instructions + G */ evsel = evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_INSTRUCTIONS)); + ret = assert_hw(&evsel->core, PERF_COUNT_HW_INSTRUCTIONS, "instructions"); + if (ret) + return ret; + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); @@ -1148,8 +1192,10 @@ static int test__group5(struct evlist *evlist __maybe_unused) for (int i = 0; i < num_core_entries(); i++) { /* cycles:G */ evsel = leader = evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); + ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); + if (ret) + return ret; + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); @@ -1164,8 +1210,10 @@ static int test__group5(struct evlist *evlist __maybe_unused) /* instructions:G */ evsel = evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_INSTRUCTIONS)); + ret = assert_hw(&evsel->core, PERF_COUNT_HW_INSTRUCTIONS, "instructions"); + if (ret) + return ret; + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); @@ -1178,8 +1226,10 @@ static int test__group5(struct evlist *evlist __maybe_unused) for (int i = 0; i < num_core_entries(); i++) { /* cycles */ evsel = evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); + ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); + if (ret) + return ret; + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); @@ -1201,10 +1251,14 @@ static int test__group_gh1(struct evlist *evlist) evlist__nr_groups(evlist) == num_core_entries()); for (int i = 0; i < num_core_entries(); i++) { + int ret; + /* cycles + :H group modifier */ evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel)); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); + ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); + if (ret) + return ret; + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); @@ -1218,8 +1272,10 @@ static int test__group_gh1(struct evlist *evlist) /* cache-misses:G + :H group modifier */ evsel = evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CACHE_MISSES)); + ret = assert_hw(&evsel->core, PERF_COUNT_HW_CACHE_MISSES, "cache-misses"); + if (ret) + return ret; + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); @@ -1242,10 +1298,14 @@ static int test__group_gh2(struct evlist *evlist) evlist__nr_groups(evlist) == num_core_entries()); for (int i = 0; i < num_core_entries(); i++) { + int ret; + /* cycles + :G group modifier */ evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel)); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); + ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); + if (ret) + return ret; + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); @@ -1259,8 +1319,10 @@ static int test__group_gh2(struct evlist *evlist) /* cache-misses:H + :G group modifier */ evsel = evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CACHE_MISSES)); + ret = assert_hw(&evsel->core, PERF_COUNT_HW_CACHE_MISSES, "cache-misses"); + if (ret) + return ret; + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); @@ -1283,10 +1345,14 @@ static int test__group_gh3(struct evlist *evlist) evlist__nr_groups(evlist) == num_core_entries()); for (int i = 0; i < num_core_entries(); i++) { + int ret; + /* cycles:G + :u group modifier */ evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel)); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); + ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); + if (ret) + return ret; + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); @@ -1300,8 +1366,10 @@ static int test__group_gh3(struct evlist *evlist) /* cache-misses:H + :u group modifier */ evsel = evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CACHE_MISSES)); + ret = assert_hw(&evsel->core, PERF_COUNT_HW_CACHE_MISSES, "cache-misses"); + if (ret) + return ret; + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); @@ -1324,10 +1392,14 @@ static int test__group_gh4(struct evlist *evlist) evlist__nr_groups(evlist) == num_core_entries()); for (int i = 0; i < num_core_entries(); i++) { + int ret; + /* cycles:G + :uG group modifier */ evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel)); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); + ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); + if (ret) + return ret; + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); @@ -1341,8 +1413,10 @@ static int test__group_gh4(struct evlist *evlist) /* cache-misses:H + :uG group modifier */ evsel = evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CACHE_MISSES)); + ret = assert_hw(&evsel->core, PERF_COUNT_HW_CACHE_MISSES, "cache-misses"); + if (ret) + return ret; + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); @@ -1363,10 +1437,14 @@ static int test__leader_sample1(struct evlist *evlist) evlist->core.nr_entries == (3 * num_core_entries())); for (int i = 0; i < num_core_entries(); i++) { + int ret; + /* cycles - sampling group leader */ evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel)); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); + ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); + if (ret) + return ret; + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); @@ -1379,8 +1457,10 @@ static int test__leader_sample1(struct evlist *evlist) /* cache-misses - not sampling */ evsel = evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CACHE_MISSES)); + ret = assert_hw(&evsel->core, PERF_COUNT_HW_CACHE_MISSES, "cache-misses"); + if (ret) + return ret; + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); @@ -1392,8 +1472,10 @@ static int test__leader_sample1(struct evlist *evlist) /* branch-misses - not sampling */ evsel = evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_BRANCH_MISSES)); + ret = assert_hw(&evsel->core, PERF_COUNT_HW_BRANCH_MISSES, "branch-misses"); + if (ret) + return ret; + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); @@ -1415,10 +1497,14 @@ static int test__leader_sample2(struct evlist *evlist __maybe_unused) evlist->core.nr_entries == (2 * num_core_entries())); for (int i = 0; i < num_core_entries(); i++) { + int ret; + /* instructions - sampling group leader */ evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel)); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_INSTRUCTIONS)); + ret = assert_hw(&evsel->core, PERF_COUNT_HW_INSTRUCTIONS, "instructions"); + if (ret) + return ret; + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); @@ -1431,8 +1517,10 @@ static int test__leader_sample2(struct evlist *evlist __maybe_unused) /* branch-misses - not sampling */ evsel = evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_BRANCH_MISSES)); + ret = assert_hw(&evsel->core, PERF_COUNT_HW_BRANCH_MISSES, "branch-misses"); + if (ret) + return ret; + TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); @@ -1472,10 +1560,14 @@ static int test__pinned_group(struct evlist *evlist) evlist->core.nr_entries == (3 * num_core_entries())); for (int i = 0; i < num_core_entries(); i++) { + int ret; + /* cycles - group leader */ evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel)); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); + ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); + if (ret) + return ret; + TEST_ASSERT_VAL("wrong group name", !evsel->group_name); TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); /* TODO: The group modifier is not copied to the split group leader. */ @@ -1484,13 +1576,18 @@ static int test__pinned_group(struct evlist *evlist) /* cache-misses - can not be pinned, but will go on with the leader */ evsel = evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CACHE_MISSES)); + ret = assert_hw(&evsel->core, PERF_COUNT_HW_CACHE_MISSES, "cache-misses"); + if (ret) + return ret; + TEST_ASSERT_VAL("wrong pinned", !evsel->core.attr.pinned); /* branch-misses - ditto */ evsel = evsel__next(evsel); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_BRANCH_MISSES)); + ret = assert_hw(&evsel->core, PERF_COUNT_HW_BRANCH_MISSES, "branch-misses"); + if (ret) + return ret; + TEST_ASSERT_VAL("wrong pinned", !evsel->core.attr.pinned); } return TEST_OK; @@ -1517,10 +1614,14 @@ static int test__exclusive_group(struct evlist *evlist) evlist->core.nr_entries == 3 * num_core_entries()); for (int i = 0; i < num_core_entries(); i++) { + int ret; + /* cycles - group leader */ evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel)); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); + ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); + if (ret) + return ret; + TEST_ASSERT_VAL("wrong group name", !evsel->group_name); TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); /* TODO: The group modifier is not copied to the split group leader. */ @@ -1529,13 +1630,18 @@ static int test__exclusive_group(struct evlist *evlist) /* cache-misses - can not be pinned, but will go on with the leader */ evsel = evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CACHE_MISSES)); + ret = assert_hw(&evsel->core, PERF_COUNT_HW_CACHE_MISSES, "cache-misses"); + if (ret) + return ret; + TEST_ASSERT_VAL("wrong exclusive", !evsel->core.attr.exclusive); /* branch-misses - ditto */ evsel = evsel__next(evsel); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_BRANCH_MISSES)); + ret = assert_hw(&evsel->core, PERF_COUNT_HW_BRANCH_MISSES, "branch-misses"); + if (ret) + return ret; + TEST_ASSERT_VAL("wrong exclusive", !evsel->core.attr.exclusive); } return TEST_OK; @@ -1677,9 +1783,11 @@ static int test__checkevent_raw_pmu(struct evlist *evlist) static int test__sym_event_slash(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); + int ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); + + if (ret) + return ret; - TEST_ASSERT_VAL("wrong type", evsel->core.attr.type == PERF_TYPE_HARDWARE); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); return TEST_OK; } @@ -1687,9 +1795,11 @@ static int test__sym_event_slash(struct evlist *evlist) static int test__sym_event_dc(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); + int ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); + + if (ret) + return ret; - TEST_ASSERT_VAL("wrong type", evsel->core.attr.type == PERF_TYPE_HARDWARE); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); return TEST_OK; } @@ -1697,9 +1807,11 @@ static int test__sym_event_dc(struct evlist *evlist) static int test__term_equal_term(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); + int ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); + + if (ret) + return ret; - TEST_ASSERT_VAL("wrong type", evsel->core.attr.type == PERF_TYPE_HARDWARE); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "name") == 0); return TEST_OK; } @@ -1707,9 +1819,11 @@ static int test__term_equal_term(struct evlist *evlist) static int test__term_equal_legacy(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); + int ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); + + if (ret) + return ret; - TEST_ASSERT_VAL("wrong type", evsel->core.attr.type == PERF_TYPE_HARDWARE); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "l1d") == 0); return TEST_OK; } @@ -2549,7 +2663,7 @@ static int test__pmu_events(struct test_suite *test __maybe_unused, int subtest if (strchr(ent->d_name, '.')) continue; - /* exclude parametrized ones (name contains '?') */ + /* exclude parameterized ones (name contains '?') */ n = snprintf(pmu_event, sizeof(pmu_event), "%s%s", path, ent->d_name); if (n >= PATH_MAX) { pr_err("pmu event name crossed PATH_MAX(%d) size\n", PATH_MAX); @@ -2578,7 +2692,7 @@ static int test__pmu_events(struct test_suite *test __maybe_unused, int subtest fclose(file); if (is_event_parameterized == 1) { - pr_debug("skipping parametrized PMU event: %s which contains ?\n", pmu_event); + pr_debug("skipping parameterized PMU event: %s which contains ?\n", pmu_event); continue; } diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c index efcd71c273..bbe2ddeb9b 100644 --- a/tools/perf/tests/perf-time-to-tsc.c +++ b/tools/perf/tests/perf-time-to-tsc.c @@ -93,7 +93,7 @@ static int test__perf_time_to_tsc(struct test_suite *test __maybe_unused, int su threads = thread_map__new(-1, getpid(), UINT_MAX); CHECK_NOT_NULL__(threads); - cpus = perf_cpu_map__new(NULL); + cpus = perf_cpu_map__new_online_cpus(); CHECK_NOT_NULL__(cpus); evlist = evlist__new(); diff --git a/tools/perf/tests/shell/coresight/memcpy_thread/memcpy_thread.c b/tools/perf/tests/shell/coresight/memcpy_thread/memcpy_thread.c index a7e169d1bf..5f886cd09e 100644 --- a/tools/perf/tests/shell/coresight/memcpy_thread/memcpy_thread.c +++ b/tools/perf/tests/shell/coresight/memcpy_thread/memcpy_thread.c @@ -42,7 +42,6 @@ static pthread_t new_thr(void *(*fn) (void *arg), void *arg) int main(int argc, char **argv) { unsigned long i, len, size, thr; - pthread_t threads[256]; struct args args[256]; long long v; diff --git a/tools/perf/tests/shell/coresight/thread_loop/thread_loop.c b/tools/perf/tests/shell/coresight/thread_loop/thread_loop.c index c0158fac7d..e05a559253 100644 --- a/tools/perf/tests/shell/coresight/thread_loop/thread_loop.c +++ b/tools/perf/tests/shell/coresight/thread_loop/thread_loop.c @@ -57,7 +57,6 @@ static pthread_t new_thr(void *(*fn) (void *arg), void *arg) int main(int argc, char **argv) { unsigned int i, len, thr; - pthread_t threads[256]; struct args args[256]; if (argc < 3) { diff --git a/tools/perf/tests/shell/coresight/unroll_loop_thread/unroll_loop_thread.c b/tools/perf/tests/shell/coresight/unroll_loop_thread/unroll_loop_thread.c index 8f6d384208..0fc7bf1a25 100644 --- a/tools/perf/tests/shell/coresight/unroll_loop_thread/unroll_loop_thread.c +++ b/tools/perf/tests/shell/coresight/unroll_loop_thread/unroll_loop_thread.c @@ -51,7 +51,6 @@ static pthread_t new_thr(void *(*fn) (void *arg), void *arg) int main(int argc, char **argv) { unsigned int i, thr; - pthread_t threads[256]; struct args args[256]; if (argc < 2) { diff --git a/tools/perf/tests/shell/daemon.sh b/tools/perf/tests/shell/daemon.sh index 4c598cfc5a..e5fa8d6f9e 100755 --- a/tools/perf/tests/shell/daemon.sh +++ b/tools/perf/tests/shell/daemon.sh @@ -414,16 +414,30 @@ EOF # start daemon daemon_start ${config} test - # send 2 signals - perf daemon signal --config ${config} --session test - perf daemon signal --config ${config} - - # stop daemon - daemon_exit ${config} - - # count is 2 perf.data for signals and 1 for perf record finished - count=`ls ${base}/session-test/*perf.data* | wc -l` - if [ ${count} -ne 3 ]; then + # send 2 signals then exit. Do this in a loop watching the number of + # files to avoid races. If the loop retries more than 600 times then + # give up. + local retries=0 + local signals=0 + local success=0 + while [ ${retries} -lt 600 ] && [ ${success} -eq 0 ]; do + local files + files=`ls ${base}/session-test/*perf.data* 2> /dev/null | wc -l` + if [ ${signals} -eq 0 ]; then + perf daemon signal --config ${config} --session test + signals=1 + elif [ ${signals} -eq 1 ] && [ $files -ge 1 ]; then + perf daemon signal --config ${config} + signals=2 + elif [ ${signals} -eq 2 ] && [ $files -ge 2 ]; then + daemon_exit ${config} + signals=3 + elif [ ${signals} -eq 3 ] && [ $files -ge 3 ]; then + success=1 + fi + retries=$((${retries} +1)) + done + if [ ${success} -eq 0 ]; then error=1 echo "FAILED: perf data no generated" fi diff --git a/tools/perf/tests/shell/diff.sh b/tools/perf/tests/shell/diff.sh new file mode 100755 index 0000000000..14b87af887 --- /dev/null +++ b/tools/perf/tests/shell/diff.sh @@ -0,0 +1,108 @@ +#!/bin/sh +# perf diff tests +# SPDX-License-Identifier: GPL-2.0 + +set -e + +err=0 +perfdata1=$(mktemp /tmp/__perf_test.perf.data.XXXXX) +perfdata2=$(mktemp /tmp/__perf_test.perf.data.XXXXX) +perfdata3=$(mktemp /tmp/__perf_test.perf.data.XXXXX) +testprog="perf test -w thloop" + +shelldir=$(dirname "$0") +# shellcheck source=lib/perf_has_symbol.sh +. "${shelldir}"/lib/perf_has_symbol.sh + +testsym="test_loop" + +skip_test_missing_symbol ${testsym} + +cleanup() { + rm -rf "${perfdata1}" + rm -rf "${perfdata1}".old + rm -rf "${perfdata2}" + rm -rf "${perfdata2}".old + rm -rf "${perfdata3}" + rm -rf "${perfdata3}".old + + trap - EXIT TERM INT +} + +trap_cleanup() { + cleanup + exit 1 +} +trap trap_cleanup EXIT TERM INT + +make_data() { + file="$1" + if ! perf record -o "${file}" ${testprog} 2> /dev/null + then + echo "Workload record [Failed record]" + echo 1 + return + fi + if ! perf report -i "${file}" -q | grep -q "${testsym}" + then + echo "Workload record [Failed missing output]" + echo 1 + return + fi + echo 0 +} + +test_two_files() { + echo "Basic two file diff test" + err=$(make_data "${perfdata1}") + if [ $err != 0 ] + then + return + fi + err=$(make_data "${perfdata2}") + if [ $err != 0 ] + then + return + fi + + if ! perf diff "${perfdata1}" "${perfdata2}" | grep -q "${testsym}" + then + echo "Basic two file diff test [Failed diff]" + err=1 + return + fi + echo "Basic two file diff test [Success]" +} + +test_three_files() { + echo "Basic three file diff test" + err=$(make_data "${perfdata1}") + if [ $err != 0 ] + then + return + fi + err=$(make_data "${perfdata2}") + if [ $err != 0 ] + then + return + fi + err=$(make_data "${perfdata3}") + if [ $err != 0 ] + then + return + fi + + if ! perf diff "${perfdata1}" "${perfdata2}" "${perfdata3}" | grep -q "${testsym}" + then + echo "Basic three file diff test [Failed diff]" + err=1 + return + fi + echo "Basic three file diff test [Success]" +} + +test_two_files +test_three_files + +cleanup +exit $err diff --git a/tools/perf/tests/shell/lib/perf_has_symbol.sh b/tools/perf/tests/shell/lib/perf_has_symbol.sh new file mode 100644 index 0000000000..5d59c32ae3 --- /dev/null +++ b/tools/perf/tests/shell/lib/perf_has_symbol.sh @@ -0,0 +1,21 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 + +perf_has_symbol() +{ + if perf test -vv "Symbols" 2>&1 | grep "[[:space:]]$1$"; then + echo "perf does have symbol '$1'" + return 0 + fi + echo "perf does not have symbol '$1'" + return 1 +} + +skip_test_missing_symbol() +{ + if ! perf_has_symbol "$1" ; then + echo "perf is missing symbols - skipping test" + exit 2 + fi + return 0 +} diff --git a/tools/perf/tests/shell/lib/setup_python.sh b/tools/perf/tests/shell/lib/setup_python.sh new file mode 100644 index 0000000000..c2fce17935 --- /dev/null +++ b/tools/perf/tests/shell/lib/setup_python.sh @@ -0,0 +1,16 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 + +if [ "x$PYTHON" = "x" ] +then + python3 --version >/dev/null 2>&1 && PYTHON=python3 +fi +if [ "x$PYTHON" = "x" ] +then + python --version >/dev/null 2>&1 && PYTHON=python +fi +if [ "x$PYTHON" = "x" ] +then + echo Skipping test, python not detected please set environment variable PYTHON. + exit 2 +fi diff --git a/tools/perf/tests/shell/list.sh b/tools/perf/tests/shell/list.sh new file mode 100755 index 0000000000..8a868ae645 --- /dev/null +++ b/tools/perf/tests/shell/list.sh @@ -0,0 +1,34 @@ +#!/bin/sh +# perf list tests +# SPDX-License-Identifier: GPL-2.0 + +set -e + +shelldir=$(dirname "$0") +# shellcheck source=lib/setup_python.sh +. "${shelldir}"/lib/setup_python.sh + +list_output=$(mktemp /tmp/__perf_test.list_output.json.XXXXX) + +cleanup() { + rm -f "${list_output}" + + trap - EXIT TERM INT +} + +trap_cleanup() { + cleanup + exit 1 +} +trap trap_cleanup EXIT TERM INT + +test_list_json() { + echo "Json output test" + perf list -j -o "${list_output}" + $PYTHON -m json.tool "${list_output}" + echo "Json output test [Success]" +} + +test_list_json +cleanup +exit 0 diff --git a/tools/perf/tests/shell/pipe_test.sh b/tools/perf/tests/shell/pipe_test.sh index 8dd115dd35..a78d35d2cf 100755 --- a/tools/perf/tests/shell/pipe_test.sh +++ b/tools/perf/tests/shell/pipe_test.sh @@ -2,10 +2,17 @@ # perf pipe recording and injection test # SPDX-License-Identifier: GPL-2.0 +shelldir=$(dirname "$0") +# shellcheck source=lib/perf_has_symbol.sh +. "${shelldir}"/lib/perf_has_symbol.sh + +sym="noploop" + +skip_test_missing_symbol ${sym} + data=$(mktemp /tmp/perf.data.XXXXXX) prog="perf test -w noploop" task="perf" -sym="noploop" if ! perf record -e task-clock:u -o - ${prog} | perf report -i - --task | grep ${task}; then echo "cannot find the test file in the perf report" 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 eebeea6bdc..72c65570db 100755 --- a/tools/perf/tests/shell/record+probe_libc_inet_pton.sh +++ b/tools/perf/tests/shell/record+probe_libc_inet_pton.sh @@ -45,7 +45,10 @@ trace_libc_inet_pton_backtrace() { ;; ppc64|ppc64le) eventattr='max-stack=4' - echo "gaih_inet.*\+0x[[:xdigit:]]+[[:space:]]\($libc\)$" >> $expected + # Add gaih_inet to expected backtrace only if it is part of libc. + if nm $libc | grep -F -q gaih_inet.; then + echo "gaih_inet.*\+0x[[:xdigit:]]+[[:space:]]\($libc\)$" >> $expected + fi echo "getaddrinfo\+0x[[:xdigit:]]+[[:space:]]\($libc\)$" >> $expected echo ".*(\+0x[[:xdigit:]]+|\[unknown\])[[:space:]]\(.*/bin/ping.*\)$" >> $expected ;; diff --git a/tools/perf/tests/shell/record.sh b/tools/perf/tests/shell/record.sh index 29443b8e88..3d1a7759a7 100755 --- a/tools/perf/tests/shell/record.sh +++ b/tools/perf/tests/shell/record.sh @@ -8,10 +8,19 @@ shelldir=$(dirname "$0") # shellcheck source=lib/waiting.sh . "${shelldir}"/lib/waiting.sh +# shellcheck source=lib/perf_has_symbol.sh +. "${shelldir}"/lib/perf_has_symbol.sh + +testsym="test_loop" + +skip_test_missing_symbol ${testsym} + err=0 perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX) testprog="perf test -w thloop" -testsym="test_loop" +cpu_pmu_dir="/sys/bus/event_source/devices/cpu*" +br_cntr_file="/caps/branch_counter_nr" +br_cntr_output="branch stack counters" cleanup() { rm -rf "${perfdata}" @@ -155,10 +164,37 @@ test_workload() { echo "Basic target workload test [Success]" } +test_branch_counter() { + echo "Basic branch counter test" + # Check if the branch counter feature is supported + for dir in $cpu_pmu_dir + do + if [ ! -e "$dir$br_cntr_file" ] + then + echo "branch counter feature not supported on all core PMUs ($dir) [Skipped]" + return + fi + done + if ! perf record -o "${perfdata}" -j any,counter ${testprog} 2> /dev/null + then + echo "Basic branch counter test [Failed record]" + err=1 + return + fi + if ! perf report -i "${perfdata}" -D -q | grep -q "$br_cntr_output" + then + echo "Basic branch record test [Failed missing output]" + err=1 + return + fi + echo "Basic branch counter test [Success]" +} + test_per_thread test_register_capture test_system_wide test_workload +test_branch_counter cleanup exit $err diff --git a/tools/perf/tests/shell/record_offcpu.sh b/tools/perf/tests/shell/record_offcpu.sh index a1ef8f0d2b..67c925f3a1 100755 --- a/tools/perf/tests/shell/record_offcpu.sh +++ b/tools/perf/tests/shell/record_offcpu.sh @@ -77,9 +77,9 @@ test_offcpu_child() { err=1 return fi - # each process waits for read and write, so it should be more than 800 events + # each process waits at least for poll, so it should be more than 400 events if ! perf report -i ${perfdata} -s comm -q -n -t ';' --percent-limit=90 | \ - awk -F ";" '{ if (NF > 3 && int($3) < 800) exit 1; }' + awk -F ";" '{ if (NF > 3 && int($3) < 400) exit 1; }' then echo "Child task off-cpu test [Failed invalid output]" err=1 diff --git a/tools/perf/tests/shell/script.sh b/tools/perf/tests/shell/script.sh index 2973adab44..fa4d71e2e7 100755 --- a/tools/perf/tests/shell/script.sh +++ b/tools/perf/tests/shell/script.sh @@ -36,8 +36,7 @@ test_db() echo "DB test" # Check if python script is supported - libpython=$(perf version --build-options | grep python | grep -cv OFF) - if [ "${libpython}" != "1" ] ; then + if perf version --build-options | grep python | grep -q OFF ; then echo "SKIP: python scripting is not supported" err=2 return diff --git a/tools/perf/tests/shell/stat+json_output.sh b/tools/perf/tests/shell/stat+json_output.sh index 196e22672c..3bc900533a 100755 --- a/tools/perf/tests/shell/stat+json_output.sh +++ b/tools/perf/tests/shell/stat+json_output.sh @@ -8,20 +8,10 @@ set -e skip_test=0 +shelldir=$(dirname "$0") +# shellcheck source=lib/setup_python.sh +. "${shelldir}"/lib/setup_python.sh pythonchecker=$(dirname $0)/lib/perf_json_output_lint.py -if [ "x$PYTHON" == "x" ] -then - if which python3 > /dev/null - then - PYTHON=python3 - elif which python > /dev/null - then - PYTHON=python - else - echo Skipping test, python not detected please set environment variable PYTHON. - exit 2 - fi -fi stat_output=$(mktemp /tmp/__perf_test.stat_output.json.XXXXX) diff --git a/tools/perf/tests/shell/stat_all_pmu.sh b/tools/perf/tests/shell/stat_all_pmu.sh index c779554191..d2a3506e0d 100755 --- a/tools/perf/tests/shell/stat_all_pmu.sh +++ b/tools/perf/tests/shell/stat_all_pmu.sh @@ -4,7 +4,7 @@ set -e -# Test all PMU events; however exclude parametrized ones (name contains '?') +# Test all PMU events; however exclude parameterized ones (name contains '?') for p in $(perf list --raw-dump pmu | sed 's/[[:graph:]]\+?[[:graph:]]\+[[:space:]]//g'); do echo "Testing $p" result=$(perf stat -e "$p" true 2>&1) diff --git a/tools/perf/tests/shell/stat_metrics_values.sh b/tools/perf/tests/shell/stat_metrics_values.sh index ad94c936de..7ca172599a 100755 --- a/tools/perf/tests/shell/stat_metrics_values.sh +++ b/tools/perf/tests/shell/stat_metrics_values.sh @@ -1,16 +1,10 @@ #!/bin/bash # perf metrics value validation # SPDX-License-Identifier: GPL-2.0 -if [ "x$PYTHON" == "x" ] -then - if which python3 > /dev/null - then - PYTHON=python3 - else - echo Skipping test, python3 not detected please set environment variable PYTHON. - exit 2 - fi -fi + +shelldir=$(dirname "$0") +# shellcheck source=lib/setup_python.sh +. "${shelldir}"/lib/setup_python.sh grep -q GenuineIntel /proc/cpuinfo || { echo Skipping non-Intel; exit 2; } diff --git a/tools/perf/tests/shell/test_arm_callgraph_fp.sh b/tools/perf/tests/shell/test_arm_callgraph_fp.sh index 66dfdfdad5..e342e6c8aa 100755 --- a/tools/perf/tests/shell/test_arm_callgraph_fp.sh +++ b/tools/perf/tests/shell/test_arm_callgraph_fp.sh @@ -2,8 +2,14 @@ # Check Arm64 callgraphs are complete in fp mode # SPDX-License-Identifier: GPL-2.0 +shelldir=$(dirname "$0") +# shellcheck source=lib/perf_has_symbol.sh +. "${shelldir}"/lib/perf_has_symbol.sh + lscpu | grep -q "aarch64" || exit 2 +skip_test_missing_symbol leafloop + PERF_DATA=$(mktemp /tmp/__perf_test.perf.data.XXXXX) TEST_PROGRAM="perf test -w leafloop" diff --git a/tools/perf/tests/shell/test_brstack.sh b/tools/perf/tests/shell/test_brstack.sh index 09908d71c9..5f14d0cb01 100755 --- a/tools/perf/tests/shell/test_brstack.sh +++ b/tools/perf/tests/shell/test_brstack.sh @@ -4,6 +4,10 @@ # SPDX-License-Identifier: GPL-2.0 # German Gomez , 2022 +shelldir=$(dirname "$0") +# shellcheck source=lib/perf_has_symbol.sh +. "${shelldir}"/lib/perf_has_symbol.sh + # skip the test if the hardware doesn't support branch stack sampling # and if the architecture doesn't support filter types: any,save_type,u if ! perf record -o- --no-buildid --branch-filter any,save_type,u -- true > /dev/null 2>&1 ; then @@ -11,6 +15,8 @@ if ! perf record -o- --no-buildid --branch-filter any,save_type,u -- true > /dev exit 2 fi +skip_test_missing_symbol brstack_bench + TMPDIR=$(mktemp -d /tmp/__perf_test.program.XXXXX) TESTPROG="perf test -w brstack" diff --git a/tools/perf/tests/shell/test_data_symbol.sh b/tools/perf/tests/shell/test_data_symbol.sh index 69bb6fe86c..3dfa91832a 100755 --- a/tools/perf/tests/shell/test_data_symbol.sh +++ b/tools/perf/tests/shell/test_data_symbol.sh @@ -4,6 +4,13 @@ # SPDX-License-Identifier: GPL-2.0 # Leo Yan , 2022 +shelldir=$(dirname "$0") +# shellcheck source=lib/waiting.sh +. "${shelldir}"/lib/waiting.sh + +# shellcheck source=lib/perf_has_symbol.sh +. "${shelldir}"/lib/perf_has_symbol.sh + skip_if_no_mem_event() { perf mem record -e list 2>&1 | grep -E -q 'available' && return 0 return 2 @@ -11,8 +18,11 @@ skip_if_no_mem_event() { skip_if_no_mem_event || exit 2 +skip_test_missing_symbol buf1 + TEST_PROGRAM="perf test -w datasym" PERF_DATA=$(mktemp /tmp/__perf_test.perf.data.XXXXX) +ERR_FILE=$(mktemp /tmp/__perf_test.stderr.XXXXX) check_result() { # The memory report format is as below: @@ -50,13 +60,15 @@ echo "Recording workload..." # specific CPU and test in per-CPU mode. is_amd=$(grep -E -c 'vendor_id.*AuthenticAMD' /proc/cpuinfo) if (($is_amd >= 1)); then - perf mem record -o ${PERF_DATA} -C 0 -- taskset -c 0 $TEST_PROGRAM & + perf mem record -vvv -o ${PERF_DATA} -C 0 -- taskset -c 0 $TEST_PROGRAM 2>"${ERR_FILE}" & else - perf mem record --all-user -o ${PERF_DATA} -- $TEST_PROGRAM & + perf mem record -vvv --all-user -o ${PERF_DATA} -- $TEST_PROGRAM 2>"${ERR_FILE}" & fi PERFPID=$! +wait_for_perf_to_start ${PERFPID} "${ERR_FILE}" + sleep 1 kill $PERFPID diff --git a/tools/perf/tests/shell/test_perf_data_converter_json.sh b/tools/perf/tests/shell/test_perf_data_converter_json.sh index 6ded58f98f..c4f1b59d11 100755 --- a/tools/perf/tests/shell/test_perf_data_converter_json.sh +++ b/tools/perf/tests/shell/test_perf_data_converter_json.sh @@ -6,16 +6,9 @@ set -e err=0 -if [ "$PYTHON" = "" ] ; then - if which python3 > /dev/null ; then - PYTHON=python3 - elif which python > /dev/null ; then - PYTHON=python - else - echo Skipping test, python not detected please set environment variable PYTHON. - exit 2 - fi -fi +shelldir=$(dirname "$0") +# shellcheck source=lib/setup_python.sh +. "${shelldir}"/lib/setup_python.sh perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX) result=$(mktemp /tmp/__perf_test.output.json.XXXXX) diff --git a/tools/perf/tests/sigtrap.c b/tools/perf/tests/sigtrap.c index 1de7478ec1..e6fd934b02 100644 --- a/tools/perf/tests/sigtrap.c +++ b/tools/perf/tests/sigtrap.c @@ -57,36 +57,79 @@ static struct perf_event_attr make_event_attr(void) #ifdef HAVE_BPF_SKEL #include -static bool attr_has_sigtrap(void) +static struct btf *btf; + +static bool btf__available(void) { - bool ret = false; - struct btf *btf; - const struct btf_type *t; + if (btf == NULL) + btf = btf__load_vmlinux_btf(); + + return btf != NULL; +} + +static void btf__exit(void) +{ + btf__free(btf); + btf = NULL; +} + +static const struct btf_member *__btf_type__find_member_by_name(int type_id, const char *member_name) +{ + const struct btf_type *t = btf__type_by_id(btf, type_id); const struct btf_member *m; - const char *name; - int i, id; + int i; + + for (i = 0, m = btf_members(t); i < btf_vlen(t); i++, m++) { + const char *current_member_name = btf__name_by_offset(btf, m->name_off); + if (!strcmp(current_member_name, member_name)) + return m; + } - btf = btf__load_vmlinux_btf(); - if (btf == NULL) { + return NULL; +} + +static bool attr_has_sigtrap(void) +{ + int id; + + if (!btf__available()) { /* should be an old kernel */ return false; } id = btf__find_by_name_kind(btf, "perf_event_attr", BTF_KIND_STRUCT); if (id < 0) - goto out; + return false; - t = btf__type_by_id(btf, id); - for (i = 0, m = btf_members(t); i < btf_vlen(t); i++, m++) { - name = btf__name_by_offset(btf, m->name_off); - if (!strcmp(name, "sigtrap")) { - ret = true; - break; - } - } -out: - btf__free(btf); - return ret; + return __btf_type__find_member_by_name(id, "sigtrap") != NULL; +} + +static bool kernel_with_sleepable_spinlocks(void) +{ + const struct btf_member *member; + const struct btf_type *type; + const char *type_name; + int id; + + if (!btf__available()) + return false; + + id = btf__find_by_name_kind(btf, "spinlock", BTF_KIND_STRUCT); + if (id < 0) + return false; + + // Only RT has a "lock" member for "struct spinlock" + member = __btf_type__find_member_by_name(id, "lock"); + if (member == NULL) + return false; + + // But check its type as well + type = btf__type_by_id(btf, member->type); + if (!type || !btf_is_struct(type)) + return false; + + type_name = btf__name_by_offset(btf, type->name_off); + return type_name && !strcmp(type_name, "rt_mutex_base"); } #else /* !HAVE_BPF_SKEL */ static bool attr_has_sigtrap(void) @@ -109,6 +152,15 @@ static bool attr_has_sigtrap(void) return ret; } + +static bool kernel_with_sleepable_spinlocks(void) +{ + return false; +} + +static void btf__exit(void) +{ +} #endif /* HAVE_BPF_SKEL */ static void @@ -147,7 +199,7 @@ static int run_test_threads(pthread_t *threads, pthread_barrier_t *barrier) static int run_stress_test(int fd, pthread_t *threads, pthread_barrier_t *barrier) { - int ret; + int ret, expected_sigtraps; ctx.iterate_on = 3000; @@ -156,7 +208,16 @@ static int run_stress_test(int fd, pthread_t *threads, pthread_barrier_t *barrie ret = run_test_threads(threads, barrier); TEST_ASSERT_EQUAL("disable failed", ioctl(fd, PERF_EVENT_IOC_DISABLE, 0), 0); - TEST_ASSERT_EQUAL("unexpected sigtraps", ctx.signal_count, NUM_THREADS * ctx.iterate_on); + expected_sigtraps = NUM_THREADS * ctx.iterate_on; + + if (ctx.signal_count < expected_sigtraps && kernel_with_sleepable_spinlocks()) { + pr_debug("Expected %d sigtraps, got %d, running on a kernel with sleepable spinlocks.\n", + expected_sigtraps, ctx.signal_count); + pr_debug("See https://lore.kernel.org/all/e368f2c848d77fbc8d259f44e2055fe469c219cf.camel@gmx.de/\n"); + return TEST_SKIP; + } else + TEST_ASSERT_EQUAL("unexpected sigtraps", ctx.signal_count, expected_sigtraps); + TEST_ASSERT_EQUAL("missing signals or incorrectly delivered", ctx.tids_want_signal, 0); TEST_ASSERT_VAL("unexpected si_addr", ctx.first_siginfo.si_addr == &ctx.iterate_on); #if 0 /* FIXME: enable when libc's signal.h has si_perf_{type,data} */ @@ -221,6 +282,7 @@ out_restore_sigaction: sigaction(SIGTRAP, &oldact, NULL); out: pthread_barrier_destroy(&barrier); + btf__exit(); return ret; } diff --git a/tools/perf/tests/sw-clock.c b/tools/perf/tests/sw-clock.c index 4d7493fa01..290716783a 100644 --- a/tools/perf/tests/sw-clock.c +++ b/tools/perf/tests/sw-clock.c @@ -62,7 +62,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id) } evlist__add(evlist, evsel); - cpus = perf_cpu_map__dummy_new(); + cpus = perf_cpu_map__new_any_cpu(); threads = thread_map__new_by_tid(getpid()); if (!cpus || !threads) { err = -ENOMEM; diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c index e52b031bed..5cab17a194 100644 --- a/tools/perf/tests/switch-tracking.c +++ b/tools/perf/tests/switch-tracking.c @@ -351,7 +351,7 @@ static int test__switch_tracking(struct test_suite *test __maybe_unused, int sub goto out_err; } - cpus = perf_cpu_map__new(NULL); + cpus = perf_cpu_map__new_online_cpus(); if (!cpus) { pr_debug("perf_cpu_map__new failed!\n"); goto out_err; diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c index 968dddde6d..d33d095202 100644 --- a/tools/perf/tests/task-exit.c +++ b/tools/perf/tests/task-exit.c @@ -70,7 +70,7 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _ * evlist__prepare_workload we'll fill in the only thread * we're monitoring, the one forked there. */ - cpus = perf_cpu_map__dummy_new(); + cpus = perf_cpu_map__new_any_cpu(); threads = thread_map__new_by_tid(-1); if (!cpus || !threads) { err = -ENOMEM; diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index b394f3ac2d..dad3d74141 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -207,5 +207,6 @@ DECLARE_WORKLOAD(brstack); DECLARE_WORKLOAD(datasym); extern const char *dso_to_test; +extern const char *test_objdump_path; #endif /* TESTS_H */ diff --git a/tools/perf/tests/topology.c b/tools/perf/tests/topology.c index 9dee63734e..2a842f53fb 100644 --- a/tools/perf/tests/topology.c +++ b/tools/perf/tests/topology.c @@ -215,7 +215,7 @@ static int test__session_topology(struct test_suite *test __maybe_unused, int su if (session_write_header(path)) goto free_path; - map = perf_cpu_map__new(NULL); + map = perf_cpu_map__new_online_cpus(); if (map == NULL) { pr_debug("failed to get system cpumap\n"); goto free_path; diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c index 1078a93b01..822f893e67 100644 --- a/tools/perf/tests/vmlinux-kallsyms.c +++ b/tools/perf/tests/vmlinux-kallsyms.c @@ -112,18 +112,92 @@ static bool is_ignored_symbol(const char *name, char type) return false; } +struct test__vmlinux_matches_kallsyms_cb_args { + struct machine kallsyms; + struct map *vmlinux_map; + bool header_printed; +}; + +static int test__vmlinux_matches_kallsyms_cb1(struct map *map, void *data) +{ + struct test__vmlinux_matches_kallsyms_cb_args *args = data; + struct dso *dso = map__dso(map); + /* + * If it is the kernel, kallsyms is always "[kernel.kallsyms]", while + * the kernel will have the path for the vmlinux file being used, so use + * the short name, less descriptive but the same ("[kernel]" in both + * cases. + */ + struct map *pair = maps__find_by_name(args->kallsyms.kmaps, + (dso->kernel ? dso->short_name : dso->name)); + + if (pair) + map__set_priv(pair, 1); + else { + if (!args->header_printed) { + pr_info("WARN: Maps only in vmlinux:\n"); + args->header_printed = true; + } + map__fprintf(map, stderr); + } + return 0; +} + +static int test__vmlinux_matches_kallsyms_cb2(struct map *map, void *data) +{ + struct test__vmlinux_matches_kallsyms_cb_args *args = data; + struct map *pair; + u64 mem_start = map__unmap_ip(args->vmlinux_map, map__start(map)); + u64 mem_end = map__unmap_ip(args->vmlinux_map, map__end(map)); + + pair = maps__find(args->kallsyms.kmaps, mem_start); + if (pair == NULL || map__priv(pair)) + return 0; + + if (map__start(pair) == mem_start) { + struct dso *dso = map__dso(map); + + if (!args->header_printed) { + pr_info("WARN: Maps in vmlinux with a different name in kallsyms:\n"); + args->header_printed = true; + } + + pr_info("WARN: %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as", + map__start(map), map__end(map), map__pgoff(map), dso->name); + if (mem_end != map__end(pair)) + pr_info(":\nWARN: *%" PRIx64 "-%" PRIx64 " %" PRIx64, + map__start(pair), map__end(pair), map__pgoff(pair)); + pr_info(" %s\n", dso->name); + map__set_priv(pair, 1); + } + return 0; +} + +static int test__vmlinux_matches_kallsyms_cb3(struct map *map, void *data) +{ + struct test__vmlinux_matches_kallsyms_cb_args *args = data; + + if (!map__priv(map)) { + if (!args->header_printed) { + pr_info("WARN: Maps only in kallsyms:\n"); + args->header_printed = true; + } + map__fprintf(map, stderr); + } + return 0; +} + static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused, int subtest __maybe_unused) { int err = TEST_FAIL; struct rb_node *nd; struct symbol *sym; - struct map *kallsyms_map, *vmlinux_map; - struct map_rb_node *rb_node; - struct machine kallsyms, vmlinux; + struct map *kallsyms_map; + struct machine vmlinux; struct maps *maps; u64 mem_start, mem_end; - bool header_printed; + struct test__vmlinux_matches_kallsyms_cb_args args; /* * Step 1: @@ -131,7 +205,7 @@ static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused * Init the machines that will hold kernel, modules obtained from * both vmlinux + .ko files and from /proc/kallsyms split by modules. */ - machine__init(&kallsyms, "", HOST_KERNEL_ID); + machine__init(&args.kallsyms, "", HOST_KERNEL_ID); machine__init(&vmlinux, "", HOST_KERNEL_ID); maps = machine__kernel_maps(&vmlinux); @@ -143,7 +217,7 @@ static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused * load /proc/kallsyms. Also create the modules maps from /proc/modules * and find the .ko files that match them in /lib/modules/`uname -r`/. */ - if (machine__create_kernel_maps(&kallsyms) < 0) { + if (machine__create_kernel_maps(&args.kallsyms) < 0) { pr_debug("machine__create_kernel_maps failed"); err = TEST_SKIP; goto out; @@ -160,7 +234,7 @@ static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused * be compacted against the list of modules found in the "vmlinux" * code and with the one got from /proc/modules from the "kallsyms" code. */ - if (machine__load_kallsyms(&kallsyms, "/proc/kallsyms") <= 0) { + if (machine__load_kallsyms(&args.kallsyms, "/proc/kallsyms") <= 0) { pr_debug("machine__load_kallsyms failed"); err = TEST_SKIP; goto out; @@ -174,7 +248,7 @@ static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused * to see if the running kernel was relocated by checking if it has the * same value in the vmlinux file we load. */ - kallsyms_map = machine__kernel_map(&kallsyms); + kallsyms_map = machine__kernel_map(&args.kallsyms); /* * Step 5: @@ -186,7 +260,7 @@ static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused goto out; } - vmlinux_map = machine__kernel_map(&vmlinux); + args.vmlinux_map = machine__kernel_map(&vmlinux); /* * Step 6: @@ -213,7 +287,7 @@ static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused * in the kallsyms dso. For the ones that are in both, check its names and * end addresses too. */ - map__for_each_symbol(vmlinux_map, sym, nd) { + map__for_each_symbol(args.vmlinux_map, sym, nd) { struct symbol *pair, *first_pair; sym = rb_entry(nd, struct symbol, rb_node); @@ -221,10 +295,10 @@ static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused if (sym->start == sym->end) continue; - mem_start = map__unmap_ip(vmlinux_map, sym->start); - mem_end = map__unmap_ip(vmlinux_map, sym->end); + mem_start = map__unmap_ip(args.vmlinux_map, sym->start); + mem_end = map__unmap_ip(args.vmlinux_map, sym->end); - first_pair = machine__find_kernel_symbol(&kallsyms, mem_start, NULL); + first_pair = machine__find_kernel_symbol(&args.kallsyms, mem_start, NULL); pair = first_pair; if (pair && UM(pair->start) == mem_start) { @@ -253,7 +327,8 @@ next_pair: */ continue; } else { - pair = machine__find_kernel_symbol_by_name(&kallsyms, sym->name, NULL); + pair = machine__find_kernel_symbol_by_name(&args.kallsyms, + sym->name, NULL); if (pair) { if (UM(pair->start) == mem_start) goto next_pair; @@ -267,7 +342,7 @@ next_pair: continue; } - } else if (mem_start == map__end(kallsyms.vmlinux_map)) { + } else if (mem_start == map__end(args.kallsyms.vmlinux_map)) { /* * Ignore aliases to _etext, i.e. to the end of the kernel text area, * such as __indirect_thunk_end. @@ -289,78 +364,18 @@ next_pair: if (verbose <= 0) goto out; - header_printed = false; - - maps__for_each_entry(maps, rb_node) { - struct map *map = rb_node->map; - struct dso *dso = map__dso(map); - /* - * If it is the kernel, kallsyms is always "[kernel.kallsyms]", while - * the kernel will have the path for the vmlinux file being used, - * so use the short name, less descriptive but the same ("[kernel]" in - * both cases. - */ - struct map *pair = maps__find_by_name(kallsyms.kmaps, (dso->kernel ? - dso->short_name : - dso->name)); - if (pair) { - map__set_priv(pair, 1); - } else { - if (!header_printed) { - pr_info("WARN: Maps only in vmlinux:\n"); - header_printed = true; - } - map__fprintf(map, stderr); - } - } - - header_printed = false; - - maps__for_each_entry(maps, rb_node) { - struct map *pair, *map = rb_node->map; - - mem_start = map__unmap_ip(vmlinux_map, map__start(map)); - mem_end = map__unmap_ip(vmlinux_map, map__end(map)); + args.header_printed = false; + maps__for_each_map(maps, test__vmlinux_matches_kallsyms_cb1, &args); - pair = maps__find(kallsyms.kmaps, mem_start); - if (pair == NULL || map__priv(pair)) - continue; - - if (map__start(pair) == mem_start) { - struct dso *dso = map__dso(map); - - if (!header_printed) { - pr_info("WARN: Maps in vmlinux with a different name in kallsyms:\n"); - header_printed = true; - } - - pr_info("WARN: %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as", - map__start(map), map__end(map), map__pgoff(map), dso->name); - if (mem_end != map__end(pair)) - pr_info(":\nWARN: *%" PRIx64 "-%" PRIx64 " %" PRIx64, - map__start(pair), map__end(pair), map__pgoff(pair)); - pr_info(" %s\n", dso->name); - map__set_priv(pair, 1); - } - } - - header_printed = false; - - maps = machine__kernel_maps(&kallsyms); + args.header_printed = false; + maps__for_each_map(maps, test__vmlinux_matches_kallsyms_cb2, &args); - maps__for_each_entry(maps, rb_node) { - struct map *map = rb_node->map; + args.header_printed = false; + maps = machine__kernel_maps(&args.kallsyms); + maps__for_each_map(maps, test__vmlinux_matches_kallsyms_cb3, &args); - if (!map__priv(map)) { - if (!header_printed) { - pr_info("WARN: Maps only in kallsyms:\n"); - header_printed = true; - } - map__fprintf(map, stderr); - } - } out: - machine__exit(&kallsyms); + machine__exit(&args.kallsyms); machine__exit(&vmlinux); return err; } diff --git a/tools/perf/trace/beauty/arch_errno_names.sh b/tools/perf/trace/beauty/arch_errno_names.sh index cc09dcaa89..7df4bf5b55 100755 --- a/tools/perf/trace/beauty/arch_errno_names.sh +++ b/tools/perf/trace/beauty/arch_errno_names.sh @@ -57,13 +57,13 @@ create_arch_errno_table_func() archlist="$1" default="$2" - printf 'const char *arch_syscalls__strerrno(const char *arch, int err)\n' + printf 'arch_syscalls__strerrno_t *arch_syscalls__strerrno_function(const char *arch)\n' printf '{\n' for arch in $archlist; do printf '\tif (!strcmp(arch, "%s"))\n' $(arch_string "$arch") - printf '\t\treturn errno_to_name__%s(err);\n' $(arch_string "$arch") + printf '\t\treturn errno_to_name__%s;\n' $(arch_string "$arch") done - printf '\treturn errno_to_name__%s(err);\n' $(arch_string "$default") + printf '\treturn errno_to_name__%s;\n' $(arch_string "$default") printf '}\n' } @@ -76,7 +76,9 @@ EoHEADER # Create list of architectures that have a specific errno.h. archlist="" -for arch in $(find $toolsdir/arch -maxdepth 1 -mindepth 1 -type d -printf "%f\n" | sort -r); do +for f in $toolsdir/arch/*/include/uapi/asm/errno.h; do + d=${f%/include/uapi/asm/errno.h} + arch="${d##*/}" test -f $toolsdir/arch/$arch/include/uapi/asm/errno.h && archlist="$archlist $arch" done diff --git a/tools/perf/trace/beauty/beauty.h b/tools/perf/trace/beauty/beauty.h index 788e8f6bd9..9feb794f5c 100644 --- a/tools/perf/trace/beauty/beauty.h +++ b/tools/perf/trace/beauty/beauty.h @@ -251,6 +251,4 @@ size_t open__scnprintf_flags(unsigned long flags, char *bf, size_t size, bool sh void syscall_arg__set_ret_scnprintf(struct syscall_arg *arg, size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg)); -const char *arch_syscalls__strerrno(const char *arch, int err); - #endif /* _PERF_TRACE_BEAUTY_H */ diff --git a/tools/perf/trace/beauty/prctl_option.sh b/tools/perf/trace/beauty/prctl_option.sh index 8059342ca4..9455d9672f 100755 --- a/tools/perf/trace/beauty/prctl_option.sh +++ b/tools/perf/trace/beauty/prctl_option.sh @@ -4,9 +4,9 @@ [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ printf "static const char *prctl_options[] = {\n" -regex='^#define[[:space:]]{1}PR_(\w+)[[:space:]]*([[:xdigit:]]+)([[:space:]]*\/.*)?$' +regex='^#define[[:space:]]{1}PR_(\w+)[[:space:]]*([[:xdigit:]]+)([[:space:]]*/.*)?$' grep -E $regex ${header_dir}/prctl.h | grep -v PR_SET_PTRACER | \ - sed -r "s/$regex/\2 \1/g" | \ + sed -E "s%$regex%\2 \1%g" | \ sort -n | xargs printf "\t[%s] = \"%s\",\n" printf "};\n" diff --git a/tools/perf/trace/beauty/socket.sh b/tools/perf/trace/beauty/socket.sh index 8bc7ba6220..670c6db298 100755 --- a/tools/perf/trace/beauty/socket.sh +++ b/tools/perf/trace/beauty/socket.sh @@ -18,10 +18,10 @@ grep -E $ipproto_regex ${uapi_header_dir}/in.h | \ printf "};\n\n" printf "static const char *socket_level[] = {\n" -socket_level_regex='^#define[[:space:]]+SOL_(\w+)[[:space:]]+([[:digit:]]+)([[:space:]]+\/.*)?' +socket_level_regex='^#define[[:space:]]+SOL_(\w+)[[:space:]]+([[:digit:]]+)([[:space:]]+/.*)?' grep -E $socket_level_regex ${beauty_header_dir}/socket.h | \ - sed -r "s/$socket_level_regex/\2 \1/g" | \ + sed -E "s%$socket_level_regex%\2 \1%g" | \ sort -n | xargs printf "\t[%s] = \"%s\",\n" printf "};\n\n" diff --git a/tools/perf/trace/beauty/statx.c b/tools/perf/trace/beauty/statx.c index 5f5320f7c6..dc5943a635 100644 --- a/tools/perf/trace/beauty/statx.c +++ b/tools/perf/trace/beauty/statx.c @@ -67,6 +67,7 @@ size_t syscall_arg__scnprintf_statx_mask(char *bf, size_t size, struct syscall_a P_FLAG(BTIME); P_FLAG(MNT_ID); P_FLAG(DIOALIGN); + P_FLAG(MNT_ID_UNIQUE); #undef P_FLAG diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index ccdb2cd11f..4790c73559 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -27,7 +27,6 @@ struct annotate_browser { struct rb_node *curr_hot; struct annotation_line *selection; struct arch *arch; - struct annotation_options *opts; bool searching_backwards; char search_bf[128]; }; @@ -38,11 +37,10 @@ static inline struct annotation *browser__annotation(struct ui_browser *browser) return symbol__annotation(ms->sym); } -static bool disasm_line__filter(struct ui_browser *browser, void *entry) +static bool disasm_line__filter(struct ui_browser *browser __maybe_unused, void *entry) { - struct annotation *notes = browser__annotation(browser); struct annotation_line *al = list_entry(entry, struct annotation_line, node); - return annotation_line__filter(al, notes); + return annotation_line__filter(al); } static int ui_browser__jumps_percent_color(struct ui_browser *browser, int nr, bool current) @@ -97,7 +95,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int struct annotation_write_ops ops = { .first_line = row == 0, .current_entry = is_current_entry, - .change_color = (!notes->options->hide_src_code && + .change_color = (!annotate_opts.hide_src_code && (!is_current_entry || (browser->use_navkeypressed && !browser->navkeypressed))), @@ -114,7 +112,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, ab->opts); + annotation_line__write(al, notes, &ops); if (ops.current_entry) ab->selection = al; @@ -128,7 +126,7 @@ static int is_fused(struct annotate_browser *ab, struct disasm_line *cursor) while (pos && pos->al.offset == -1) { pos = list_prev_entry(pos, al.node); - if (!ab->opts->hide_src_code) + if (!annotate_opts.hide_src_code) diff++; } @@ -188,14 +186,14 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser) * name right after the '<' token and probably treating this like a * 'call' instruction. */ - target = notes->offsets[cursor->ops.target.offset]; + target = notes->src->offsets[cursor->ops.target.offset]; if (target == NULL) { ui_helpline__printf("WARN: jump target inconsistency, press 'o', notes->offsets[%#x] = NULL\n", cursor->ops.target.offset); return; } - if (notes->options->hide_src_code) { + if (annotate_opts.hide_src_code) { from = cursor->al.idx_asm; to = target->idx_asm; } else { @@ -224,7 +222,7 @@ static unsigned int annotate_browser__refresh(struct ui_browser *browser) int ret = ui_browser__list_head_refresh(browser); int pcnt_width = annotation__pcnt_width(notes); - if (notes->options->jump_arrows) + if (annotate_opts.jump_arrows) annotate_browser__draw_current_jump(browser); ui_browser__set_color(browser, HE_COLORSET_NORMAL); @@ -258,7 +256,7 @@ static void disasm_rb_tree__insert(struct annotate_browser *browser, parent = *p; l = rb_entry(parent, struct annotation_line, rb_node); - if (disasm__cmp(al, l, browser->opts->percent_type) < 0) + if (disasm__cmp(al, l, annotate_opts.percent_type) < 0) p = &(*p)->rb_left; else p = &(*p)->rb_right; @@ -270,7 +268,6 @@ static void disasm_rb_tree__insert(struct annotate_browser *browser, static void annotate_browser__set_top(struct annotate_browser *browser, struct annotation_line *pos, u32 idx) { - struct annotation *notes = browser__annotation(&browser->b); unsigned back; ui_browser__refresh_dimensions(&browser->b); @@ -280,7 +277,7 @@ static void annotate_browser__set_top(struct annotate_browser *browser, while (browser->b.top_idx != 0 && back != 0) { pos = list_entry(pos->node.prev, struct annotation_line, node); - if (annotation_line__filter(pos, notes)) + if (annotation_line__filter(pos)) continue; --browser->b.top_idx; @@ -294,11 +291,10 @@ static void annotate_browser__set_top(struct annotate_browser *browser, static void annotate_browser__set_rb_top(struct annotate_browser *browser, struct rb_node *nd) { - struct annotation *notes = browser__annotation(&browser->b); struct annotation_line * pos = rb_entry(nd, struct annotation_line, rb_node); u32 idx = pos->idx; - if (notes->options->hide_src_code) + if (annotate_opts.hide_src_code) idx = pos->idx_asm; annotate_browser__set_top(browser, pos, idx); browser->curr_hot = nd; @@ -331,13 +327,13 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser, double percent; percent = annotation_data__percent(&pos->al.data[i], - browser->opts->percent_type); + annotate_opts.percent_type); if (max_percent < percent) max_percent = percent; } - if (max_percent < 0.01 && pos->al.ipc == 0) { + if (max_percent < 0.01 && (!pos->al.cycles || pos->al.cycles->ipc == 0)) { RB_CLEAR_NODE(&pos->al.rb_node); continue; } @@ -380,12 +376,12 @@ static bool annotate_browser__toggle_source(struct annotate_browser *browser) browser->b.seek(&browser->b, offset, SEEK_CUR); al = list_entry(browser->b.top, struct annotation_line, node); - if (notes->options->hide_src_code) { + if (annotate_opts.hide_src_code) { if (al->idx_asm < offset) offset = al->idx; - browser->b.nr_entries = notes->nr_entries; - notes->options->hide_src_code = false; + browser->b.nr_entries = notes->src->nr_entries; + annotate_opts.hide_src_code = false; browser->b.seek(&browser->b, -offset, SEEK_CUR); browser->b.top_idx = al->idx - offset; browser->b.index = al->idx; @@ -402,8 +398,8 @@ static bool annotate_browser__toggle_source(struct annotate_browser *browser) if (al->idx_asm < offset) offset = al->idx_asm; - browser->b.nr_entries = notes->nr_asm_entries; - notes->options->hide_src_code = true; + browser->b.nr_entries = notes->src->nr_asm_entries; + annotate_opts.hide_src_code = true; browser->b.seek(&browser->b, -offset, SEEK_CUR); browser->b.top_idx = al->idx_asm - offset; browser->b.index = al->idx_asm; @@ -435,7 +431,7 @@ static void ui_browser__init_asm_mode(struct ui_browser *browser) { struct annotation *notes = browser__annotation(browser); ui_browser__reset_index(browser); - browser->nr_entries = notes->nr_asm_entries; + browser->nr_entries = notes->src->nr_asm_entries; } static int sym_title(struct symbol *sym, struct map *map, char *title, @@ -483,8 +479,8 @@ static bool annotate_browser__callq(struct annotate_browser *browser, target_ms.map = ms->map; target_ms.sym = dl->ops.target.sym; annotation__unlock(notes); - symbol__tui_annotate(&target_ms, evsel, hbt, browser->opts); - sym_title(ms->sym, ms->map, title, sizeof(title), browser->opts->percent_type); + symbol__tui_annotate(&target_ms, evsel, hbt); + sym_title(ms->sym, ms->map, title, sizeof(title), annotate_opts.percent_type); ui_browser__show_title(&browser->b, title); return true; } @@ -500,7 +496,7 @@ struct disasm_line *annotate_browser__find_offset(struct annotate_browser *brows list_for_each_entry(pos, ¬es->src->source, al.node) { if (pos->al.offset == offset) return pos; - if (!annotation_line__filter(&pos->al, notes)) + if (!annotation_line__filter(&pos->al)) ++*idx; } @@ -544,7 +540,7 @@ struct annotation_line *annotate_browser__find_string(struct annotate_browser *b *idx = browser->b.index; list_for_each_entry_continue(al, ¬es->src->source, node) { - if (annotation_line__filter(al, notes)) + if (annotation_line__filter(al)) continue; ++*idx; @@ -581,7 +577,7 @@ struct annotation_line *annotate_browser__find_string_reverse(struct annotate_br *idx = browser->b.index; list_for_each_entry_continue_reverse(al, ¬es->src->source, node) { - if (annotation_line__filter(al, notes)) + if (annotation_line__filter(al)) continue; --*idx; @@ -659,7 +655,6 @@ 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]; @@ -667,7 +662,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), ab->opts->percent_type); + sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso), annotate_opts.percent_type); ui_browser__gotorc_title(browser, 0, 0); ui_browser__set_color(browser, HE_COLORSET_ROOT); @@ -809,7 +804,7 @@ static int annotate_browser__run(struct annotate_browser *browser, annotate_browser__show(&browser->b, title, help); continue; case 'k': - notes->options->show_linenr = !notes->options->show_linenr; + annotate_opts.show_linenr = !annotate_opts.show_linenr; continue; case 'l': annotate_browser__show_full_location (&browser->b); @@ -822,18 +817,18 @@ static int annotate_browser__run(struct annotate_browser *browser, ui_helpline__puts(help); continue; case 'o': - notes->options->use_offset = !notes->options->use_offset; + annotate_opts.use_offset = !annotate_opts.use_offset; annotation__update_column_widths(notes); continue; case 'O': - if (++notes->options->offset_level > ANNOTATION__MAX_OFFSET_LEVEL) - notes->options->offset_level = ANNOTATION__MIN_OFFSET_LEVEL; + if (++annotate_opts.offset_level > ANNOTATION__MAX_OFFSET_LEVEL) + annotate_opts.offset_level = ANNOTATION__MIN_OFFSET_LEVEL; continue; case 'j': - notes->options->jump_arrows = !notes->options->jump_arrows; + annotate_opts.jump_arrows = !annotate_opts.jump_arrows; continue; case 'J': - notes->options->show_nr_jumps = !notes->options->show_nr_jumps; + annotate_opts.show_nr_jumps = !annotate_opts.show_nr_jumps; annotation__update_column_widths(notes); continue; case '/': @@ -860,7 +855,7 @@ show_help: browser->b.height, browser->b.index, browser->b.top_idx, - notes->nr_asm_entries); + notes->src->nr_asm_entries); } continue; case K_ENTER: @@ -884,7 +879,7 @@ show_sup_ins: continue; } case 'P': - map_symbol__annotation_dump(ms, evsel, browser->opts); + map_symbol__annotation_dump(ms, evsel); continue; case 't': if (symbol_conf.show_total_period) { @@ -897,15 +892,15 @@ show_sup_ins: annotation__update_column_widths(notes); continue; case 'c': - if (notes->options->show_minmax_cycle) - notes->options->show_minmax_cycle = false; + if (annotate_opts.show_minmax_cycle) + annotate_opts.show_minmax_cycle = false; else - notes->options->show_minmax_cycle = true; + annotate_opts.show_minmax_cycle = true; annotation__update_column_widths(notes); continue; case 'p': case 'b': - switch_percent_type(browser->opts, key == 'b'); + switch_percent_type(&annotate_opts, key == 'b'); hists__scnprintf_title(hists, title, sizeof(title)); annotate_browser__show(&browser->b, title, help); continue; @@ -932,26 +927,24 @@ out: } int map_symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, - struct hist_browser_timer *hbt, - struct annotation_options *opts) + struct hist_browser_timer *hbt) { - return symbol__tui_annotate(ms, evsel, hbt, opts); + return symbol__tui_annotate(ms, evsel, hbt); } int hist_entry__tui_annotate(struct hist_entry *he, struct evsel *evsel, - struct hist_browser_timer *hbt, - struct annotation_options *opts) + struct hist_browser_timer *hbt) { /* reset abort key so that it can get Ctrl-C as a key */ SLang_reset_tty(); SLang_init_tty(0, 0, 0); + SLtty_set_suspend_state(true); - return map_symbol__tui_annotate(&he->ms, evsel, hbt, opts); + return map_symbol__tui_annotate(&he->ms, evsel, hbt); } int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, - struct hist_browser_timer *hbt, - struct annotation_options *opts) + struct hist_browser_timer *hbt) { struct symbol *sym = ms->sym; struct annotation *notes = symbol__annotation(sym); @@ -965,7 +958,6 @@ int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, .priv = ms, .use_navkeypressed = true, }, - .opts = opts, }; struct dso *dso; int ret = -1, err; @@ -978,8 +970,8 @@ int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, if (dso->annotate_warned) return -1; - if (not_annotated) { - err = symbol__annotate2(ms, evsel, opts, &browser.arch); + if (not_annotated || !sym->annotate2) { + err = symbol__annotate2(ms, evsel, &browser.arch); if (err) { char msg[BUFSIZ]; dso->annotate_warned = true; @@ -991,12 +983,12 @@ int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, ui_helpline__push("Press ESC to exit"); - browser.b.width = notes->max_line_len; - browser.b.nr_entries = notes->nr_entries; + browser.b.width = notes->src->max_line_len; + browser.b.nr_entries = notes->src->nr_entries; browser.b.entries = ¬es->src->source, browser.b.width += 18; /* Percentage */ - if (notes->options->hide_src_code) + if (annotate_opts.hide_src_code) ui_browser__init_asm_mode(&browser.b); ret = annotate_browser__run(&browser, evsel, hbt); @@ -1006,6 +998,6 @@ int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, out_free_offsets: if(not_annotated) - zfree(¬es->offsets); + zfree(¬es->src->offsets); return ret; } diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index f4812b2268..0c02b3a8e1 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -2250,8 +2250,7 @@ struct hist_browser *hist_browser__new(struct hists *hists) static struct hist_browser * perf_evsel_browser__new(struct evsel *evsel, struct hist_browser_timer *hbt, - struct perf_env *env, - struct annotation_options *annotation_opts) + struct perf_env *env) { struct hist_browser *browser = hist_browser__new(evsel__hists(evsel)); @@ -2259,7 +2258,6 @@ perf_evsel_browser__new(struct evsel *evsel, browser->hbt = hbt; browser->env = env; browser->title = hists_browser__scnprintf_title; - browser->annotation_opts = annotation_opts; } return browser; } @@ -2432,8 +2430,8 @@ do_annotate(struct hist_browser *browser, struct popup_action *act) struct hist_entry *he; int err; - if (!browser->annotation_opts->objdump_path && - perf_env__lookup_objdump(browser->env, &browser->annotation_opts->objdump_path)) + if (!annotate_opts.objdump_path && + perf_env__lookup_objdump(browser->env, &annotate_opts.objdump_path)) return 0; notes = symbol__annotation(act->ms.sym); @@ -2445,8 +2443,7 @@ do_annotate(struct hist_browser *browser, struct popup_action *act) else evsel = hists_to_evsel(browser->hists); - err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt, - browser->annotation_opts); + err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt); he = hist_browser__selected_entry(browser); /* * offer option to annotate the other branch source or target @@ -2943,11 +2940,10 @@ next: static int evsel__hists_browse(struct evsel *evsel, int nr_events, const char *helpline, bool left_exits, struct hist_browser_timer *hbt, float min_pcnt, - struct perf_env *env, bool warn_lost_event, - struct annotation_options *annotation_opts) + struct perf_env *env, bool warn_lost_event) { struct hists *hists = evsel__hists(evsel); - struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env, annotation_opts); + struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env); struct branch_info *bi = NULL; #define MAX_OPTIONS 16 char *options[MAX_OPTIONS]; @@ -3004,6 +3000,7 @@ static int evsel__hists_browse(struct evsel *evsel, int nr_events, const char *h /* reset abort key so that it can get Ctrl-C as a key */ SLang_reset_tty(); SLang_init_tty(0, 0, 0); + SLtty_set_suspend_state(true); if (min_pcnt) browser->min_pcnt = min_pcnt; @@ -3398,7 +3395,6 @@ out: struct evsel_menu { struct ui_browser b; struct evsel *selection; - struct annotation_options *annotation_opts; bool lost_events, lost_events_warned; float min_pcnt; struct perf_env *env; @@ -3499,8 +3495,7 @@ browse_hists: hbt->timer(hbt->arg); key = evsel__hists_browse(pos, nr_events, help, true, hbt, menu->min_pcnt, menu->env, - warn_lost_event, - menu->annotation_opts); + warn_lost_event); ui_browser__show_title(&menu->b, title); switch (key) { case K_TAB: @@ -3557,7 +3552,7 @@ static bool filter_group_entries(struct ui_browser *browser __maybe_unused, static int __evlist__tui_browse_hists(struct evlist *evlist, int nr_entries, const char *help, struct hist_browser_timer *hbt, float min_pcnt, struct perf_env *env, - bool warn_lost_event, struct annotation_options *annotation_opts) + bool warn_lost_event) { struct evsel *pos; struct evsel_menu menu = { @@ -3572,7 +3567,6 @@ static int __evlist__tui_browse_hists(struct evlist *evlist, int nr_entries, con }, .min_pcnt = min_pcnt, .env = env, - .annotation_opts = annotation_opts, }; ui_helpline__push("Press ESC to exit"); @@ -3607,8 +3601,7 @@ static bool evlist__single_entry(struct evlist *evlist) } int evlist__tui_browse_hists(struct evlist *evlist, const char *help, struct hist_browser_timer *hbt, - float min_pcnt, struct perf_env *env, bool warn_lost_event, - struct annotation_options *annotation_opts) + float min_pcnt, struct perf_env *env, bool warn_lost_event) { int nr_entries = evlist->core.nr_entries; @@ -3617,7 +3610,7 @@ single_entry: { struct evsel *first = evlist__first(evlist); return evsel__hists_browse(first, nr_entries, help, false, hbt, min_pcnt, - env, warn_lost_event, annotation_opts); + env, warn_lost_event); } } @@ -3635,7 +3628,7 @@ single_entry: { } return __evlist__tui_browse_hists(evlist, nr_entries, help, hbt, min_pcnt, env, - warn_lost_event, annotation_opts); + warn_lost_event); } static int block_hists_browser__title(struct hist_browser *browser, char *bf, @@ -3654,8 +3647,7 @@ static int block_hists_browser__title(struct hist_browser *browser, char *bf, } int block_hists_tui_browse(struct block_hist *bh, struct evsel *evsel, - float min_percent, struct perf_env *env, - struct annotation_options *annotation_opts) + float min_percent, struct perf_env *env) { struct hists *hists = &bh->block_hists; struct hist_browser *browser; @@ -3672,11 +3664,11 @@ int block_hists_tui_browse(struct block_hist *bh, struct evsel *evsel, browser->title = block_hists_browser__title; browser->min_pcnt = min_percent; browser->env = env; - browser->annotation_opts = annotation_opts; /* reset abort key so that it can get Ctrl-C as a key */ SLang_reset_tty(); SLang_init_tty(0, 0, 0); + SLtty_set_suspend_state(true); memset(&action, 0, sizeof(action)); diff --git a/tools/perf/ui/browsers/hists.h b/tools/perf/ui/browsers/hists.h index 1e938d9ffa..de46f6c56b 100644 --- a/tools/perf/ui/browsers/hists.h +++ b/tools/perf/ui/browsers/hists.h @@ -4,7 +4,6 @@ #include "ui/browser.h" -struct annotation_options; struct evsel; struct hist_browser { @@ -15,7 +14,6 @@ struct hist_browser { struct hist_browser_timer *hbt; struct pstack *pstack; struct perf_env *env; - struct annotation_options *annotation_opts; struct evsel *block_evsel; int print_seq; bool show_dso; diff --git a/tools/perf/ui/browsers/scripts.c b/tools/perf/ui/browsers/scripts.c index 47d2c7a8cb..50d45054ed 100644 --- a/tools/perf/ui/browsers/scripts.c +++ b/tools/perf/ui/browsers/scripts.c @@ -166,6 +166,7 @@ void run_script(char *cmd) printf("\033[c\033[H\033[J"); fflush(stdout); SLang_init_tty(0, 0, 0); + SLtty_set_suspend_state(true); SLsmg_refresh(); } diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c index 2effac77ca..394861245f 100644 --- a/tools/perf/ui/gtk/annotate.c +++ b/tools/perf/ui/gtk/annotate.c @@ -162,7 +162,6 @@ static int perf_gtk__annotate_symbol(GtkWidget *window, struct map_symbol *ms, } static int symbol__gtk_annotate(struct map_symbol *ms, struct evsel *evsel, - struct annotation_options *options, struct hist_browser_timer *hbt) { struct dso *dso = map__dso(ms->map); @@ -176,7 +175,7 @@ static int symbol__gtk_annotate(struct map_symbol *ms, struct evsel *evsel, if (dso->annotate_warned) return -1; - err = symbol__annotate(ms, evsel, options, NULL); + err = symbol__annotate(ms, evsel, NULL); if (err) { char msg[BUFSIZ]; dso->annotate_warned = true; @@ -244,10 +243,9 @@ static int symbol__gtk_annotate(struct map_symbol *ms, struct evsel *evsel, int hist_entry__gtk_annotate(struct hist_entry *he, struct evsel *evsel, - struct annotation_options *options, struct hist_browser_timer *hbt) { - return symbol__gtk_annotate(&he->ms, evsel, options, hbt); + return symbol__gtk_annotate(&he->ms, evsel, hbt); } void perf_gtk__show_annotations(void) diff --git a/tools/perf/ui/gtk/gtk.h b/tools/perf/ui/gtk/gtk.h index 1e84dceb52..a2b497f03f 100644 --- a/tools/perf/ui/gtk/gtk.h +++ b/tools/perf/ui/gtk/gtk.h @@ -56,13 +56,11 @@ struct evsel; struct evlist; struct hist_entry; struct hist_browser_timer; -struct annotation_options; int evlist__gtk_browse_hists(struct evlist *evlist, const char *help, struct hist_browser_timer *hbt, float min_pcnt); int hist_entry__gtk_annotate(struct hist_entry *he, struct evsel *evsel, - struct annotation_options *options, struct hist_browser_timer *hbt); void perf_gtk__show_annotations(void); diff --git a/tools/perf/ui/tui/setup.c b/tools/perf/ui/tui/setup.c index 605d9e175e..16c6eff4d2 100644 --- a/tools/perf/ui/tui/setup.c +++ b/tools/perf/ui/tui/setup.c @@ -2,12 +2,14 @@ #include #include #include +#include #include #include #ifdef HAVE_BACKTRACE_SUPPORT #include #endif +#include "../../util/color.h" #include "../../util/debug.h" #include "../browser.h" #include "../helpline.h" @@ -121,6 +123,23 @@ static void ui__signal(int sig) exit(0); } +static void ui__sigcont(int sig) +{ + static struct termios tty; + + if (sig == SIGTSTP) { + while (tcgetattr(SLang_TT_Read_FD, &tty) == -1 && errno == EINTR) + ; + while (write(SLang_TT_Read_FD, PERF_COLOR_RESET, sizeof(PERF_COLOR_RESET) - 1) == -1 && errno == EINTR) + ; + raise(SIGSTOP); + } else { + while (tcsetattr(SLang_TT_Read_FD, TCSADRAIN, &tty) == -1 && errno == EINTR) + ; + raise(SIGWINCH); + } +} + int ui__init(void) { int err; @@ -135,6 +154,7 @@ int ui__init(void) err = SLang_init_tty(-1, 0, 0); if (err < 0) goto out; + SLtty_set_suspend_state(true); err = SLkp_init(); if (err < 0) { @@ -149,6 +169,8 @@ int ui__init(void) signal(SIGINT, ui__signal); signal(SIGQUIT, ui__signal); signal(SIGTERM, ui__signal); + signal(SIGTSTP, ui__sigcont); + signal(SIGCONT, ui__sigcont); perf_error__register(&perf_tui_eops); diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 988473bf90..8027f450fa 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -195,6 +195,8 @@ endif perf-$(CONFIG_DWARF) += probe-finder.o perf-$(CONFIG_DWARF) += dwarf-aux.o perf-$(CONFIG_DWARF) += dwarf-regs.o +perf-$(CONFIG_DWARF) += debuginfo.o +perf-$(CONFIG_DWARF) += annotate-data.o perf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o perf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind-local.o diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c new file mode 100644 index 0000000000..f22b4f1827 --- /dev/null +++ b/tools/perf/util/annotate-data.c @@ -0,0 +1,405 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Convert sample address to data type using DWARF debug info. + * + * Written by Namhyung Kim + */ + +#include +#include +#include + +#include "annotate-data.h" +#include "debuginfo.h" +#include "debug.h" +#include "dso.h" +#include "evsel.h" +#include "evlist.h" +#include "map.h" +#include "map_symbol.h" +#include "strbuf.h" +#include "symbol.h" +#include "symbol_conf.h" + +/* + * Compare type name and size to maintain them in a tree. + * I'm not sure if DWARF would have information of a single type in many + * different places (compilation units). If not, it could compare the + * offset of the type entry in the .debug_info section. + */ +static int data_type_cmp(const void *_key, const struct rb_node *node) +{ + const struct annotated_data_type *key = _key; + struct annotated_data_type *type; + + type = rb_entry(node, struct annotated_data_type, node); + + if (key->self.size != type->self.size) + return key->self.size - type->self.size; + return strcmp(key->self.type_name, type->self.type_name); +} + +static bool data_type_less(struct rb_node *node_a, const struct rb_node *node_b) +{ + struct annotated_data_type *a, *b; + + a = rb_entry(node_a, struct annotated_data_type, node); + b = rb_entry(node_b, struct annotated_data_type, node); + + if (a->self.size != b->self.size) + return a->self.size < b->self.size; + return strcmp(a->self.type_name, b->self.type_name) < 0; +} + +/* Recursively add new members for struct/union */ +static int __add_member_cb(Dwarf_Die *die, void *arg) +{ + struct annotated_member *parent = arg; + struct annotated_member *member; + Dwarf_Die member_type, die_mem; + Dwarf_Word size, loc; + Dwarf_Attribute attr; + struct strbuf sb; + int tag; + + if (dwarf_tag(die) != DW_TAG_member) + return DIE_FIND_CB_SIBLING; + + member = zalloc(sizeof(*member)); + if (member == NULL) + return DIE_FIND_CB_END; + + strbuf_init(&sb, 32); + die_get_typename(die, &sb); + + die_get_real_type(die, &member_type); + if (dwarf_aggregate_size(&member_type, &size) < 0) + size = 0; + + if (!dwarf_attr_integrate(die, DW_AT_data_member_location, &attr)) + loc = 0; + else + dwarf_formudata(&attr, &loc); + + member->type_name = strbuf_detach(&sb, NULL); + /* member->var_name can be NULL */ + if (dwarf_diename(die)) + member->var_name = strdup(dwarf_diename(die)); + member->size = size; + member->offset = loc + parent->offset; + INIT_LIST_HEAD(&member->children); + list_add_tail(&member->node, &parent->children); + + tag = dwarf_tag(&member_type); + switch (tag) { + case DW_TAG_structure_type: + case DW_TAG_union_type: + die_find_child(&member_type, __add_member_cb, member, &die_mem); + break; + default: + break; + } + return DIE_FIND_CB_SIBLING; +} + +static void add_member_types(struct annotated_data_type *parent, Dwarf_Die *type) +{ + Dwarf_Die die_mem; + + die_find_child(type, __add_member_cb, &parent->self, &die_mem); +} + +static void delete_members(struct annotated_member *member) +{ + struct annotated_member *child, *tmp; + + list_for_each_entry_safe(child, tmp, &member->children, node) { + list_del(&child->node); + delete_members(child); + free(child->type_name); + free(child->var_name); + free(child); + } +} + +static struct annotated_data_type *dso__findnew_data_type(struct dso *dso, + Dwarf_Die *type_die) +{ + struct annotated_data_type *result = NULL; + struct annotated_data_type key; + struct rb_node *node; + struct strbuf sb; + char *type_name; + Dwarf_Word size; + + strbuf_init(&sb, 32); + if (die_get_typename_from_type(type_die, &sb) < 0) + strbuf_add(&sb, "(unknown type)", 14); + type_name = strbuf_detach(&sb, NULL); + dwarf_aggregate_size(type_die, &size); + + /* Check existing nodes in dso->data_types tree */ + key.self.type_name = type_name; + key.self.size = size; + node = rb_find(&key, &dso->data_types, data_type_cmp); + if (node) { + result = rb_entry(node, struct annotated_data_type, node); + free(type_name); + return result; + } + + /* If not, add a new one */ + result = zalloc(sizeof(*result)); + if (result == NULL) { + free(type_name); + return NULL; + } + + result->self.type_name = type_name; + result->self.size = size; + INIT_LIST_HEAD(&result->self.children); + + if (symbol_conf.annotate_data_member) + add_member_types(result, type_die); + + rb_add(&result->node, &dso->data_types, data_type_less); + return result; +} + +static bool find_cu_die(struct debuginfo *di, u64 pc, Dwarf_Die *cu_die) +{ + Dwarf_Off off, next_off; + size_t header_size; + + if (dwarf_addrdie(di->dbg, pc, cu_die) != NULL) + return cu_die; + + /* + * There are some kernels don't have full aranges and contain only a few + * aranges entries. Fallback to iterate all CU entries in .debug_info + * in case it's missing. + */ + off = 0; + while (dwarf_nextcu(di->dbg, off, &next_off, &header_size, + NULL, NULL, NULL) == 0) { + if (dwarf_offdie(di->dbg, off + header_size, cu_die) && + dwarf_haspc(cu_die, pc)) + return true; + + off = next_off; + } + return false; +} + +/* The type info will be saved in @type_die */ +static int check_variable(Dwarf_Die *var_die, Dwarf_Die *type_die, int offset) +{ + Dwarf_Word size; + + /* Get the type of the variable */ + if (die_get_real_type(var_die, type_die) == NULL) { + pr_debug("variable has no type\n"); + ann_data_stat.no_typeinfo++; + return -1; + } + + /* + * It expects a pointer type for a memory access. + * Convert to a real type it points to. + */ + if (dwarf_tag(type_die) != DW_TAG_pointer_type || + die_get_real_type(type_die, type_die) == NULL) { + pr_debug("no pointer or no type\n"); + ann_data_stat.no_typeinfo++; + return -1; + } + + /* Get the size of the actual type */ + if (dwarf_aggregate_size(type_die, &size) < 0) { + pr_debug("type size is unknown\n"); + ann_data_stat.invalid_size++; + return -1; + } + + /* Minimal sanity check */ + if ((unsigned)offset >= size) { + pr_debug("offset: %d is bigger than size: %" PRIu64 "\n", offset, size); + ann_data_stat.bad_offset++; + return -1; + } + + return 0; +} + +/* The result will be saved in @type_die */ +static int find_data_type_die(struct debuginfo *di, u64 pc, + int reg, int offset, Dwarf_Die *type_die) +{ + Dwarf_Die cu_die, var_die; + Dwarf_Die *scopes = NULL; + int ret = -1; + int i, nr_scopes; + + /* Get a compile_unit for this address */ + if (!find_cu_die(di, pc, &cu_die)) { + pr_debug("cannot find CU for address %" PRIx64 "\n", pc); + ann_data_stat.no_cuinfo++; + return -1; + } + + /* Get a list of nested scopes - i.e. (inlined) functions and blocks. */ + nr_scopes = die_get_scopes(&cu_die, pc, &scopes); + + /* Search from the inner-most scope to the outer */ + for (i = nr_scopes - 1; i >= 0; i--) { + /* Look up variables/parameters in this scope */ + if (!die_find_variable_by_reg(&scopes[i], pc, reg, &var_die)) + continue; + + /* Found a variable, see if it's correct */ + ret = check_variable(&var_die, type_die, offset); + goto out; + } + if (ret < 0) + ann_data_stat.no_var++; + +out: + free(scopes); + return ret; +} + +/** + * find_data_type - Return a data type at the location + * @ms: map and symbol at the location + * @ip: instruction address of the memory access + * @reg: register that holds the base address + * @offset: offset from the base address + * + * This functions searches the debug information of the binary to get the data + * type it accesses. The exact location is expressed by (ip, reg, offset). + * It return %NULL if not found. + */ +struct annotated_data_type *find_data_type(struct map_symbol *ms, u64 ip, + int reg, int offset) +{ + struct annotated_data_type *result = NULL; + struct dso *dso = map__dso(ms->map); + struct debuginfo *di; + Dwarf_Die type_die; + u64 pc; + + di = debuginfo__new(dso->long_name); + if (di == NULL) { + pr_debug("cannot get the debug info\n"); + return NULL; + } + + /* + * IP is a relative instruction address from the start of the map, as + * it can be randomized/relocated, it needs to translate to PC which is + * a file address for DWARF processing. + */ + pc = map__rip_2objdump(ms->map, ip); + if (find_data_type_die(di, pc, reg, offset, &type_die) < 0) + goto out; + + result = dso__findnew_data_type(dso, &type_die); + +out: + debuginfo__delete(di); + return result; +} + +static int alloc_data_type_histograms(struct annotated_data_type *adt, int nr_entries) +{ + int i; + size_t sz = sizeof(struct type_hist); + + sz += sizeof(struct type_hist_entry) * adt->self.size; + + /* Allocate a table of pointers for each event */ + adt->nr_histograms = nr_entries; + adt->histograms = calloc(nr_entries, sizeof(*adt->histograms)); + if (adt->histograms == NULL) + return -ENOMEM; + + /* + * Each histogram is allocated for the whole size of the type. + * TODO: Probably we can move the histogram to members. + */ + for (i = 0; i < nr_entries; i++) { + adt->histograms[i] = zalloc(sz); + if (adt->histograms[i] == NULL) + goto err; + } + return 0; + +err: + while (--i >= 0) + free(adt->histograms[i]); + free(adt->histograms); + return -ENOMEM; +} + +static void delete_data_type_histograms(struct annotated_data_type *adt) +{ + for (int i = 0; i < adt->nr_histograms; i++) + free(adt->histograms[i]); + free(adt->histograms); +} + +void annotated_data_type__tree_delete(struct rb_root *root) +{ + struct annotated_data_type *pos; + + while (!RB_EMPTY_ROOT(root)) { + struct rb_node *node = rb_first(root); + + rb_erase(node, root); + pos = rb_entry(node, struct annotated_data_type, node); + delete_members(&pos->self); + delete_data_type_histograms(pos); + free(pos->self.type_name); + free(pos); + } +} + +/** + * annotated_data_type__update_samples - Update histogram + * @adt: Data type to update + * @evsel: Event to update + * @offset: Offset in the type + * @nr_samples: Number of samples at this offset + * @period: Event count at this offset + * + * This function updates type histogram at @ofs for @evsel. Samples are + * aggregated before calling this function so it can be called with more + * than one samples at a certain offset. + */ +int annotated_data_type__update_samples(struct annotated_data_type *adt, + struct evsel *evsel, int offset, + int nr_samples, u64 period) +{ + struct type_hist *h; + + if (adt == NULL) + return 0; + + if (adt->histograms == NULL) { + int nr = evsel->evlist->core.nr_entries; + + if (alloc_data_type_histograms(adt, nr) < 0) + return -1; + } + + if (offset < 0 || offset >= adt->self.size) + return -1; + + h = adt->histograms[evsel->core.idx]; + + h->nr_samples += nr_samples; + h->addr[offset].nr_samples += nr_samples; + h->period += period; + h->addr[offset].period += period; + return 0; +} diff --git a/tools/perf/util/annotate-data.h b/tools/perf/util/annotate-data.h new file mode 100644 index 0000000000..8e73096c01 --- /dev/null +++ b/tools/perf/util/annotate-data.h @@ -0,0 +1,143 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _PERF_ANNOTATE_DATA_H +#define _PERF_ANNOTATE_DATA_H + +#include +#include +#include +#include + +struct evsel; +struct map_symbol; + +/** + * struct annotated_member - Type of member field + * @node: List entry in the parent list + * @children: List head for child nodes + * @type_name: Name of the member type + * @var_name: Name of the member variable + * @offset: Offset from the outer data type + * @size: Size of the member field + * + * This represents a member type in a data type. + */ +struct annotated_member { + struct list_head node; + struct list_head children; + char *type_name; + char *var_name; + int offset; + int size; +}; + +/** + * struct type_hist_entry - Histogram entry per offset + * @nr_samples: Number of samples + * @period: Count of event + */ +struct type_hist_entry { + int nr_samples; + u64 period; +}; + +/** + * struct type_hist - Type histogram for each event + * @nr_samples: Total number of samples in this data type + * @period: Total count of the event in this data type + * @offset: Array of histogram entry + */ +struct type_hist { + u64 nr_samples; + u64 period; + struct type_hist_entry addr[]; +}; + +/** + * struct annotated_data_type - Data type to profile + * @node: RB-tree node for dso->type_tree + * @self: Actual type information + * @nr_histogram: Number of histogram entries + * @histograms: An array of pointers to histograms + * + * This represents a data type accessed by samples in the profile data. + */ +struct annotated_data_type { + struct rb_node node; + struct annotated_member self; + int nr_histograms; + struct type_hist **histograms; +}; + +extern struct annotated_data_type unknown_type; + +/** + * struct annotated_data_stat - Debug statistics + * @total: Total number of entry + * @no_sym: No symbol or map found + * @no_insn: Failed to get disasm line + * @no_insn_ops: The instruction has no operands + * @no_mem_ops: The instruction has no memory operands + * @no_reg: Failed to extract a register from the operand + * @no_dbginfo: The binary has no debug information + * @no_cuinfo: Failed to find a compile_unit + * @no_var: Failed to find a matching variable + * @no_typeinfo: Failed to get a type info for the variable + * @invalid_size: Failed to get a size info of the type + * @bad_offset: The access offset is out of the type + */ +struct annotated_data_stat { + int total; + int no_sym; + int no_insn; + int no_insn_ops; + int no_mem_ops; + int no_reg; + int no_dbginfo; + int no_cuinfo; + int no_var; + int no_typeinfo; + int invalid_size; + int bad_offset; +}; +extern struct annotated_data_stat ann_data_stat; + +#ifdef HAVE_DWARF_SUPPORT + +/* Returns data type at the location (ip, reg, offset) */ +struct annotated_data_type *find_data_type(struct map_symbol *ms, u64 ip, + int reg, int offset); + +/* Update type access histogram at the given offset */ +int annotated_data_type__update_samples(struct annotated_data_type *adt, + struct evsel *evsel, int offset, + int nr_samples, u64 period); + +/* Release all data type information in the tree */ +void annotated_data_type__tree_delete(struct rb_root *root); + +#else /* HAVE_DWARF_SUPPORT */ + +static inline struct annotated_data_type * +find_data_type(struct map_symbol *ms __maybe_unused, u64 ip __maybe_unused, + int reg __maybe_unused, int offset __maybe_unused) +{ + return NULL; +} + +static inline int +annotated_data_type__update_samples(struct annotated_data_type *adt __maybe_unused, + struct evsel *evsel __maybe_unused, + int offset __maybe_unused, + int nr_samples __maybe_unused, + u64 period __maybe_unused) +{ + return -1; +} + +static inline void annotated_data_type__tree_delete(struct rb_root *root __maybe_unused) +{ +} + +#endif /* HAVE_DWARF_SUPPORT */ + +#endif /* _PERF_ANNOTATE_DATA_H */ diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 82956adf99..86a996290e 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -25,12 +25,14 @@ #include "units.h" #include "debug.h" #include "annotate.h" +#include "annotate-data.h" #include "evsel.h" #include "evlist.h" #include "bpf-event.h" #include "bpf-utils.h" #include "block-range.h" #include "string2.h" +#include "dwarf-regs.h" #include "util/event.h" #include "util/sharded_mutex.h" #include "arch/common.h" @@ -57,6 +59,9 @@ #include +/* global annotation options */ +struct annotation_options annotate_opts; + static regex_t file_lineno; static struct ins_ops *ins__find(struct arch *arch, const char *name); @@ -85,6 +90,8 @@ struct arch { struct { char comment_char; char skip_functions_char; + char register_char; + char memory_ref_char; } objdump; }; @@ -96,6 +103,10 @@ static struct ins_ops nop_ops; static struct ins_ops lock_ops; static struct ins_ops ret_ops; +/* Data type collection debug statistics */ +struct annotated_data_stat ann_data_stat; +LIST_HEAD(ann_insn_stat); + static int arch__grow_instructions(struct arch *arch) { struct ins *new_instructions; @@ -188,6 +199,8 @@ static struct arch architectures[] = { .insn_suffix = "bwlq", .objdump = { .comment_char = '#', + .register_char = '%', + .memory_ref_char = '(', }, }, { @@ -340,10 +353,10 @@ bool ins__is_call(const struct ins *ins) */ static inline const char *validate_comma(const char *c, struct ins_operands *ops) { - if (ops->raw_comment && c > ops->raw_comment) + if (ops->jump.raw_comment && c > ops->jump.raw_comment) return NULL; - if (ops->raw_func_start && c > ops->raw_func_start) + if (ops->jump.raw_func_start && c > ops->jump.raw_func_start) return NULL; return c; @@ -359,8 +372,8 @@ static int jump__parse(struct arch *arch, struct ins_operands *ops, struct map_s const char *c = strchr(ops->raw, ','); u64 start, end; - ops->raw_comment = strchr(ops->raw, arch->objdump.comment_char); - ops->raw_func_start = strchr(ops->raw, '<'); + ops->jump.raw_comment = strchr(ops->raw, arch->objdump.comment_char); + ops->jump.raw_func_start = strchr(ops->raw, '<'); c = validate_comma(c, ops); @@ -462,7 +475,16 @@ static int jump__scnprintf(struct ins *ins, char *bf, size_t size, ops->target.offset); } +static void jump__delete(struct ins_operands *ops __maybe_unused) +{ + /* + * The ops->jump.raw_comment and ops->jump.raw_func_start belong to the + * raw string, don't free them. + */ +} + static struct ins_ops jump_ops = { + .free = jump__delete, .parse = jump__parse, .scnprintf = jump__scnprintf, }; @@ -557,6 +579,34 @@ static struct ins_ops lock_ops = { .scnprintf = lock__scnprintf, }; +/* + * Check if the operand has more than one registers like x86 SIB addressing: + * 0x1234(%rax, %rbx, 8) + * + * But it doesn't care segment selectors like %gs:0x5678(%rcx), so just check + * the input string after 'memory_ref_char' if exists. + */ +static bool check_multi_regs(struct arch *arch, const char *op) +{ + int count = 0; + + if (arch->objdump.register_char == 0) + return false; + + if (arch->objdump.memory_ref_char) { + op = strchr(op, arch->objdump.memory_ref_char); + if (op == NULL) + return false; + } + + while ((op = strchr(op, arch->objdump.register_char)) != NULL) { + count++; + op++; + } + + return count > 1; +} + static int mov__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms __maybe_unused) { char *s = strchr(ops->raw, ','), *target, *comment, prev; @@ -584,6 +634,8 @@ static int mov__parse(struct arch *arch, struct ins_operands *ops, struct map_sy if (ops->source.raw == NULL) return -1; + ops->source.multi_regs = check_multi_regs(arch, ops->source.raw); + target = skip_spaces(++s); comment = strchr(s, arch->objdump.comment_char); @@ -604,6 +656,8 @@ static int mov__parse(struct arch *arch, struct ins_operands *ops, struct map_sy if (ops->target.raw == NULL) goto out_free_source; + ops->target.multi_regs = check_multi_regs(arch, ops->target.raw); + if (comment == NULL) return 0; @@ -795,6 +849,11 @@ static struct arch *arch__find(const char *name) return bsearch(name, architectures, nmemb, sizeof(struct arch), arch__key_cmp); } +bool arch__is(struct arch *arch, const char *name) +{ + return !strcmp(arch->name, name); +} + static struct annotated_source *annotated_source__new(void) { struct annotated_source *src = zalloc(sizeof(*src)); @@ -810,7 +869,6 @@ static __maybe_unused void annotated_source__delete(struct annotated_source *src if (src == NULL) return; zfree(&src->histograms); - zfree(&src->cycles_hist); free(src); } @@ -845,18 +903,6 @@ static int annotated_source__alloc_histograms(struct annotated_source *src, return src->histograms ? 0 : -1; } -/* The cycles histogram is lazily allocated. */ -static int symbol__alloc_hist_cycles(struct symbol *sym) -{ - struct annotation *notes = symbol__annotation(sym); - const size_t size = symbol__size(sym); - - notes->src->cycles_hist = calloc(size, sizeof(struct cyc_hist)); - if (notes->src->cycles_hist == NULL) - return -1; - return 0; -} - void symbol__annotate_zero_histograms(struct symbol *sym) { struct annotation *notes = symbol__annotation(sym); @@ -865,9 +911,10 @@ void symbol__annotate_zero_histograms(struct symbol *sym) if (notes->src != NULL) { memset(notes->src->histograms, 0, notes->src->nr_histograms * notes->src->sizeof_sym_hist); - if (notes->src->cycles_hist) - memset(notes->src->cycles_hist, 0, - symbol__size(sym) * sizeof(struct cyc_hist)); + } + if (notes->branch && notes->branch->cycles_hist) { + memset(notes->branch->cycles_hist, 0, + symbol__size(sym) * sizeof(struct cyc_hist)); } annotation__unlock(notes); } @@ -958,23 +1005,33 @@ static int __symbol__inc_addr_samples(struct map_symbol *ms, return 0; } +struct annotated_branch *annotation__get_branch(struct annotation *notes) +{ + if (notes == NULL) + return NULL; + + if (notes->branch == NULL) + notes->branch = zalloc(sizeof(*notes->branch)); + + return notes->branch; +} + static struct cyc_hist *symbol__cycles_hist(struct symbol *sym) { struct annotation *notes = symbol__annotation(sym); + struct annotated_branch *branch; - if (notes->src == NULL) { - notes->src = annotated_source__new(); - if (notes->src == NULL) - return NULL; - goto alloc_cycles_hist; - } + branch = annotation__get_branch(notes); + if (branch == NULL) + return NULL; - if (!notes->src->cycles_hist) { -alloc_cycles_hist: - symbol__alloc_hist_cycles(sym); + if (branch->cycles_hist == NULL) { + const size_t size = symbol__size(sym); + + branch->cycles_hist = calloc(size, sizeof(struct cyc_hist)); } - return notes->src->cycles_hist; + return branch->cycles_hist; } struct annotated_source *symbol__hists(struct symbol *sym, int nr_hists) @@ -1077,12 +1134,20 @@ static unsigned annotation__count_insn(struct annotation *notes, u64 start, u64 u64 offset; for (offset = start; offset <= end; offset++) { - if (notes->offsets[offset]) + if (notes->src->offsets[offset]) n_insn++; } return n_insn; } +static void annotated_branch__delete(struct annotated_branch *branch) +{ + if (branch) { + zfree(&branch->cycles_hist); + free(branch); + } +} + static void annotation__count_and_fill(struct annotation *notes, u64 start, u64 end, struct cyc_hist *ch) { unsigned n_insn; @@ -1091,6 +1156,7 @@ static void annotation__count_and_fill(struct annotation *notes, u64 start, u64 n_insn = annotation__count_insn(notes, start, end); if (n_insn && ch->num && ch->cycles) { + struct annotated_branch *branch; float ipc = n_insn / ((double)ch->cycles / (double)ch->num); /* Hide data when there are too many overlaps. */ @@ -1098,54 +1164,76 @@ static void annotation__count_and_fill(struct annotation *notes, u64 start, u64 return; for (offset = start; offset <= end; offset++) { - struct annotation_line *al = notes->offsets[offset]; + struct annotation_line *al = notes->src->offsets[offset]; - if (al && al->ipc == 0.0) { - al->ipc = ipc; + if (al && al->cycles && al->cycles->ipc == 0.0) { + al->cycles->ipc = ipc; cover_insn++; } } - if (cover_insn) { - notes->hit_cycles += ch->cycles; - notes->hit_insn += n_insn * ch->num; - notes->cover_insn += cover_insn; + branch = annotation__get_branch(notes); + if (cover_insn && branch) { + branch->hit_cycles += ch->cycles; + branch->hit_insn += n_insn * ch->num; + branch->cover_insn += cover_insn; } } } -void annotation__compute_ipc(struct annotation *notes, size_t size) +static int annotation__compute_ipc(struct annotation *notes, size_t size) { + int err = 0; s64 offset; - if (!notes->src || !notes->src->cycles_hist) - return; + if (!notes->branch || !notes->branch->cycles_hist) + return 0; - notes->total_insn = annotation__count_insn(notes, 0, size - 1); - notes->hit_cycles = 0; - notes->hit_insn = 0; - notes->cover_insn = 0; + notes->branch->total_insn = annotation__count_insn(notes, 0, size - 1); + notes->branch->hit_cycles = 0; + notes->branch->hit_insn = 0; + notes->branch->cover_insn = 0; annotation__lock(notes); for (offset = size - 1; offset >= 0; --offset) { struct cyc_hist *ch; - ch = ¬es->src->cycles_hist[offset]; + ch = ¬es->branch->cycles_hist[offset]; if (ch && ch->cycles) { struct annotation_line *al; + al = notes->src->offsets[offset]; + if (al && al->cycles == NULL) { + al->cycles = zalloc(sizeof(*al->cycles)); + if (al->cycles == NULL) { + err = ENOMEM; + break; + } + } if (ch->have_start) annotation__count_and_fill(notes, ch->start, offset, ch); - al = notes->offsets[offset]; if (al && ch->num_aggr) { - al->cycles = ch->cycles_aggr / ch->num_aggr; - al->cycles_max = ch->cycles_max; - al->cycles_min = ch->cycles_min; + al->cycles->avg = ch->cycles_aggr / ch->num_aggr; + al->cycles->max = ch->cycles_max; + al->cycles->min = ch->cycles_min; + } + } + } + + if (err) { + while (++offset < (s64)size) { + struct cyc_hist *ch = ¬es->branch->cycles_hist[offset]; + + if (ch && ch->cycles) { + struct annotation_line *al = notes->src->offsets[offset]; + if (al) + zfree(&al->cycles); } - notes->have_cycles = true; } } + annotation__unlock(notes); + return 0; } int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample, @@ -1225,6 +1313,7 @@ static void annotation_line__exit(struct annotation_line *al) { zfree_srcline(&al->path); zfree(&al->line); + zfree(&al->cycles); } static size_t disasm_line_size(int nr) @@ -1299,6 +1388,7 @@ int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool r void annotation__exit(struct annotation *notes) { annotated_source__delete(notes->src); + annotated_branch__delete(notes->branch); } static struct sharded_mutex *sharded_mutex; @@ -1817,7 +1907,6 @@ static int symbol__disassemble_bpf(struct symbol *sym, struct annotate_args *args) { struct annotation *notes = symbol__annotation(sym); - struct annotation_options *opts = args->options; struct bpf_prog_linfo *prog_linfo = NULL; struct bpf_prog_info_node *info_node; int len = sym->end - sym->start; @@ -1927,7 +2016,7 @@ static int symbol__disassemble_bpf(struct symbol *sym, prev_buf_size = buf_size; fflush(s); - if (!opts->hide_src_code && srcline) { + if (!annotate_opts.hide_src_code && srcline) { args->offset = -1; args->line = strdup(srcline); args->line_nr = 0; @@ -2050,7 +2139,7 @@ static char *expand_tabs(char *line, char **storage, size_t *storage_len) static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) { - struct annotation_options *opts = args->options; + struct annotation_options *opts = &annotate_opts; struct map *map = args->ms.map; struct dso *dso = map__dso(map); char *command; @@ -2113,12 +2202,13 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) err = asprintf(&command, "%s %s%s --start-address=0x%016" PRIx64 " --stop-address=0x%016" PRIx64 - " -l -d %s %s %s %c%s%c %s%s -C \"$1\"", + " %s -d %s %s %s %c%s%c %s%s -C \"$1\"", opts->objdump_path ?: "objdump", opts->disassembler_style ? "-M " : "", opts->disassembler_style ?: "", map__rip_2objdump(map, sym->start), map__rip_2objdump(map, sym->end), + opts->show_linenr ? "-l" : "", opts->show_asm_raw ? "" : "--no-show-raw-insn", opts->annotate_src ? "-S" : "", opts->prefix ? "--prefix " : "", @@ -2299,15 +2389,8 @@ void symbol__calc_percent(struct symbol *sym, struct evsel *evsel) annotation__calc_percent(notes, evsel, symbol__size(sym)); } -int symbol__annotate(struct map_symbol *ms, struct evsel *evsel, - struct annotation_options *options, struct arch **parch) +static int evsel__get_arch(struct evsel *evsel, struct arch **parch) { - struct symbol *sym = ms->sym; - struct annotation *notes = symbol__annotation(sym); - struct annotate_args args = { - .evsel = evsel, - .options = options, - }; struct perf_env *env = evsel__env(evsel); const char *arch_name = perf_env__arch(env); struct arch *arch; @@ -2316,25 +2399,48 @@ int symbol__annotate(struct map_symbol *ms, struct evsel *evsel, if (!arch_name) return errno; - args.arch = arch = arch__find(arch_name); + *parch = arch = arch__find(arch_name); if (arch == NULL) { pr_err("%s: unsupported arch %s\n", __func__, arch_name); return ENOTSUP; } - if (parch) - *parch = arch; - if (arch->init) { err = arch->init(arch, env ? env->cpuid : NULL); if (err) { - pr_err("%s: failed to initialize %s arch priv area\n", __func__, arch->name); + pr_err("%s: failed to initialize %s arch priv area\n", + __func__, arch->name); return err; } } + return 0; +} +int symbol__annotate(struct map_symbol *ms, struct evsel *evsel, + struct arch **parch) +{ + struct symbol *sym = ms->sym; + struct annotation *notes = symbol__annotation(sym); + struct annotate_args args = { + .evsel = evsel, + .options = &annotate_opts, + }; + struct arch *arch = NULL; + int err; + + err = evsel__get_arch(evsel, &arch); + if (err < 0) + return err; + + if (parch) + *parch = arch; + + if (!list_empty(¬es->src->source)) + return 0; + + args.arch = arch; args.ms = *ms; - if (notes->options && notes->options->full_addr) + if (annotate_opts.full_addr) notes->start = map__objdump_2mem(ms->map, ms->sym->start); else notes->start = map__rip_2objdump(ms->map, ms->sym->start); @@ -2342,12 +2448,12 @@ int symbol__annotate(struct map_symbol *ms, struct evsel *evsel, return symbol__disassemble(sym, &args); } -static void insert_source_line(struct rb_root *root, struct annotation_line *al, - struct annotation_options *opts) +static void insert_source_line(struct rb_root *root, struct annotation_line *al) { struct annotation_line *iter; struct rb_node **p = &root->rb_node; struct rb_node *parent = NULL; + unsigned int percent_type = annotate_opts.percent_type; int i, ret; while (*p != NULL) { @@ -2358,7 +2464,7 @@ static void insert_source_line(struct rb_root *root, struct annotation_line *al, if (ret == 0) { for (i = 0; i < al->data_nr; i++) { iter->data[i].percent_sum += annotation_data__percent(&al->data[i], - opts->percent_type); + percent_type); } return; } @@ -2371,7 +2477,7 @@ static void insert_source_line(struct rb_root *root, struct annotation_line *al, for (i = 0; i < al->data_nr; i++) { al->data[i].percent_sum = annotation_data__percent(&al->data[i], - opts->percent_type); + percent_type); } rb_link_node(&al->rb_node, parent, p); @@ -2493,8 +2599,7 @@ static int annotated_source__addr_fmt_width(struct list_head *lines, u64 start) return 0; } -int symbol__annotate_printf(struct map_symbol *ms, struct evsel *evsel, - struct annotation_options *opts) +int symbol__annotate_printf(struct map_symbol *ms, struct evsel *evsel) { struct map *map = ms->map; struct symbol *sym = ms->sym; @@ -2505,6 +2610,7 @@ int symbol__annotate_printf(struct map_symbol *ms, struct evsel *evsel, struct annotation *notes = symbol__annotation(sym); struct sym_hist *h = annotation__histogram(notes, evsel->core.idx); struct annotation_line *pos, *queue = NULL; + struct annotation_options *opts = &annotate_opts; u64 start = map__rip_2objdump(map, sym->start); int printed = 2, queue_len = 0, addr_fmt_width; int more = 0; @@ -2633,8 +2739,7 @@ static void FILE__write_graph(void *fp, int graph) fputs(s, fp); } -static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp, - struct annotation_options *opts) +static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp) { struct annotation *notes = symbol__annotation(sym); struct annotation_write_ops wops = { @@ -2649,9 +2754,9 @@ static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp, struct annotation_line *al; list_for_each_entry(al, ¬es->src->source, node) { - if (annotation_line__filter(al, notes)) + if (annotation_line__filter(al)) continue; - annotation_line__write(al, notes, &wops, opts); + annotation_line__write(al, notes, &wops); fputc('\n', fp); wops.first_line = false; } @@ -2659,8 +2764,7 @@ static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp, return 0; } -int map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel, - struct annotation_options *opts) +int map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel) { const char *ev_name = evsel__name(evsel); char buf[1024]; @@ -2682,7 +2786,7 @@ int map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel, fprintf(fp, "%s() %s\nEvent: %s\n\n", ms->sym->name, map__dso(ms->map)->long_name, ev_name); - symbol__annotate_fprintf2(ms->sym, fp, opts); + symbol__annotate_fprintf2(ms->sym, fp); fclose(fp); err = 0; @@ -2769,7 +2873,7 @@ void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym) return; for (offset = 0; offset < size; ++offset) { - struct annotation_line *al = notes->offsets[offset]; + struct annotation_line *al = notes->src->offsets[offset]; struct disasm_line *dl; dl = disasm_line(al); @@ -2777,7 +2881,7 @@ void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym) if (!disasm_line__is_valid_local_jump(dl, sym)) continue; - al = notes->offsets[dl->ops.target.offset]; + al = notes->src->offsets[dl->ops.target.offset]; /* * FIXME: Oops, no jump target? Buggy disassembler? Or do we @@ -2794,19 +2898,20 @@ void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym) void annotation__set_offsets(struct annotation *notes, s64 size) { struct annotation_line *al; + struct annotated_source *src = notes->src; - notes->max_line_len = 0; - notes->nr_entries = 0; - notes->nr_asm_entries = 0; + src->max_line_len = 0; + src->nr_entries = 0; + src->nr_asm_entries = 0; - list_for_each_entry(al, ¬es->src->source, node) { + list_for_each_entry(al, &src->source, node) { size_t line_len = strlen(al->line); - if (notes->max_line_len < line_len) - notes->max_line_len = line_len; - al->idx = notes->nr_entries++; + if (src->max_line_len < line_len) + src->max_line_len = line_len; + al->idx = src->nr_entries++; if (al->offset != -1) { - al->idx_asm = notes->nr_asm_entries++; + al->idx_asm = src->nr_asm_entries++; /* * FIXME: short term bandaid to cope with assembly * routines that comes with labels in the same column @@ -2815,7 +2920,7 @@ void annotation__set_offsets(struct annotation *notes, s64 size) * E.g. copy_user_generic_unrolled */ if (al->offset < size) - notes->offsets[al->offset] = al; + notes->src->offsets[al->offset] = al; } else al->idx_asm = -1; } @@ -2858,24 +2963,24 @@ void annotation__init_column_widths(struct annotation *notes, struct symbol *sym void annotation__update_column_widths(struct annotation *notes) { - if (notes->options->use_offset) + if (annotate_opts.use_offset) notes->widths.target = notes->widths.min_addr; - else if (notes->options->full_addr) + else if (annotate_opts.full_addr) notes->widths.target = BITS_PER_LONG / 4; else notes->widths.target = notes->widths.max_addr; notes->widths.addr = notes->widths.target; - if (notes->options->show_nr_jumps) + if (annotate_opts.show_nr_jumps) notes->widths.addr += notes->widths.jumps + 1; } void annotation__toggle_full_addr(struct annotation *notes, struct map_symbol *ms) { - notes->options->full_addr = !notes->options->full_addr; + annotate_opts.full_addr = !annotate_opts.full_addr; - if (notes->options->full_addr) + if (annotate_opts.full_addr) notes->start = map__objdump_2mem(ms->map, ms->sym->start); else notes->start = map__rip_2objdump(ms->map, ms->sym->start); @@ -2884,8 +2989,7 @@ void annotation__toggle_full_addr(struct annotation *notes, struct map_symbol *m } static void annotation__calc_lines(struct annotation *notes, struct map *map, - struct rb_root *root, - struct annotation_options *opts) + struct rb_root *root) { struct annotation_line *al; struct rb_root tmp_root = RB_ROOT; @@ -2898,7 +3002,7 @@ static void annotation__calc_lines(struct annotation *notes, struct map *map, double percent; percent = annotation_data__percent(&al->data[i], - opts->percent_type); + annotate_opts.percent_type); if (percent > percent_max) percent_max = percent; @@ -2909,22 +3013,20 @@ static void annotation__calc_lines(struct annotation *notes, struct map *map, al->path = get_srcline(map__dso(map), notes->start + al->offset, NULL, false, true, notes->start + al->offset); - insert_source_line(&tmp_root, al, opts); + insert_source_line(&tmp_root, al); } resort_source_line(root, &tmp_root); } -static void symbol__calc_lines(struct map_symbol *ms, struct rb_root *root, - struct annotation_options *opts) +static void symbol__calc_lines(struct map_symbol *ms, struct rb_root *root) { struct annotation *notes = symbol__annotation(ms->sym); - annotation__calc_lines(notes, ms->map, root, opts); + annotation__calc_lines(notes, ms->map, root); } -int symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel, - struct annotation_options *opts) +int symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel) { struct dso *dso = map__dso(ms->map); struct symbol *sym = ms->sym; @@ -2933,7 +3035,7 @@ int symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel, char buf[1024]; int err; - err = symbol__annotate2(ms, evsel, opts, NULL); + err = symbol__annotate2(ms, evsel, NULL); if (err) { char msg[BUFSIZ]; @@ -2943,31 +3045,31 @@ int symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel, return -1; } - if (opts->print_lines) { - srcline_full_filename = opts->full_path; - symbol__calc_lines(ms, &source_line, opts); + if (annotate_opts.print_lines) { + srcline_full_filename = annotate_opts.full_path; + symbol__calc_lines(ms, &source_line); print_summary(&source_line, dso->long_name); } 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); + buf, percent_type_str(annotate_opts.percent_type), sym->name, + dso->long_name); + symbol__annotate_fprintf2(sym, stdout); annotated_source__purge(symbol__annotation(sym)->src); return 0; } -int symbol__tty_annotate(struct map_symbol *ms, struct evsel *evsel, - struct annotation_options *opts) +int symbol__tty_annotate(struct map_symbol *ms, struct evsel *evsel) { struct dso *dso = map__dso(ms->map); struct symbol *sym = ms->sym; struct rb_root source_line = RB_ROOT; int err; - err = symbol__annotate(ms, evsel, opts, NULL); + err = symbol__annotate(ms, evsel, NULL); if (err) { char msg[BUFSIZ]; @@ -2979,13 +3081,13 @@ int symbol__tty_annotate(struct map_symbol *ms, struct evsel *evsel, symbol__calc_percent(sym, evsel); - if (opts->print_lines) { - srcline_full_filename = opts->full_path; - symbol__calc_lines(ms, &source_line, opts); + if (annotate_opts.print_lines) { + srcline_full_filename = annotate_opts.full_path; + symbol__calc_lines(ms, &source_line); print_summary(&source_line, dso->long_name); } - symbol__annotate_printf(ms, evsel, opts); + symbol__annotate_printf(ms, evsel); annotated_source__purge(symbol__annotation(sym)->src); @@ -3046,19 +3148,20 @@ call_like: obj__printf(obj, " "); } - disasm_line__scnprintf(dl, bf, size, !notes->options->use_offset, notes->widths.max_ins_name); + disasm_line__scnprintf(dl, bf, size, !annotate_opts.use_offset, notes->widths.max_ins_name); } static void ipc_coverage_string(char *bf, int size, struct annotation *notes) { double ipc = 0.0, coverage = 0.0; + struct annotated_branch *branch = annotation__get_branch(notes); - if (notes->hit_cycles) - ipc = notes->hit_insn / ((double)notes->hit_cycles); + if (branch && branch->hit_cycles) + ipc = branch->hit_insn / ((double)branch->hit_cycles); - if (notes->total_insn) { - coverage = notes->cover_insn * 100.0 / - ((double)notes->total_insn); + if (branch && branch->total_insn) { + coverage = branch->cover_insn * 100.0 / + ((double)branch->total_insn); } scnprintf(bf, size, "(Average IPC: %.2f, IPC Coverage: %.1f%%)", @@ -3083,8 +3186,8 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati int printed; if (first_line && (al->offset == -1 || percent_max == 0.0)) { - if (notes->have_cycles) { - if (al->ipc == 0.0 && al->cycles == 0) + if (notes->branch && al->cycles) { + if (al->cycles->ipc == 0.0 && al->cycles->avg == 0) show_title = true; } else show_title = true; @@ -3120,18 +3223,18 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati } } - if (notes->have_cycles) { - if (al->ipc) - obj__printf(obj, "%*.2f ", ANNOTATION__IPC_WIDTH - 1, al->ipc); + if (notes->branch) { + if (al->cycles && al->cycles->ipc) + obj__printf(obj, "%*.2f ", ANNOTATION__IPC_WIDTH - 1, al->cycles->ipc); else if (!show_title) obj__printf(obj, "%*s", ANNOTATION__IPC_WIDTH, " "); else obj__printf(obj, "%*s ", ANNOTATION__IPC_WIDTH - 1, "IPC"); - if (!notes->options->show_minmax_cycle) { - if (al->cycles) + if (!annotate_opts.show_minmax_cycle) { + if (al->cycles && al->cycles->avg) obj__printf(obj, "%*" PRIu64 " ", - ANNOTATION__CYCLES_WIDTH - 1, al->cycles); + ANNOTATION__CYCLES_WIDTH - 1, al->cycles->avg); else if (!show_title) obj__printf(obj, "%*s", ANNOTATION__CYCLES_WIDTH, " "); @@ -3145,8 +3248,8 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati scnprintf(str, sizeof(str), "%" PRIu64 "(%" PRIu64 "/%" PRIu64 ")", - al->cycles, al->cycles_min, - al->cycles_max); + al->cycles->avg, al->cycles->min, + al->cycles->max); obj__printf(obj, "%*s ", ANNOTATION__MINMAX_CYCLES_WIDTH - 1, @@ -3172,7 +3275,7 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati if (!*al->line) obj__printf(obj, "%-*s", width - pcnt_width - cycles_width, " "); else if (al->offset == -1) { - if (al->line_nr && notes->options->show_linenr) + if (al->line_nr && annotate_opts.show_linenr) printed = scnprintf(bf, sizeof(bf), "%-*d ", notes->widths.addr + 1, al->line_nr); else printed = scnprintf(bf, sizeof(bf), "%-*s ", notes->widths.addr, " "); @@ -3182,15 +3285,15 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati u64 addr = al->offset; int color = -1; - if (!notes->options->use_offset) + if (!annotate_opts.use_offset) addr += notes->start; - if (!notes->options->use_offset) { + if (!annotate_opts.use_offset) { printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr); } else { if (al->jump_sources && - notes->options->offset_level >= ANNOTATION__OFFSET_JUMP_TARGETS) { - if (notes->options->show_nr_jumps) { + annotate_opts.offset_level >= ANNOTATION__OFFSET_JUMP_TARGETS) { + if (annotate_opts.show_nr_jumps) { int prev; printed = scnprintf(bf, sizeof(bf), "%*d ", notes->widths.jumps, @@ -3204,9 +3307,9 @@ print_addr: printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ", notes->widths.target, addr); } else if (ins__is_call(&disasm_line(al)->ins) && - notes->options->offset_level >= ANNOTATION__OFFSET_CALL) { + annotate_opts.offset_level >= ANNOTATION__OFFSET_CALL) { goto print_addr; - } else if (notes->options->offset_level == ANNOTATION__MAX_OFFSET_LEVEL) { + } else if (annotate_opts.offset_level == ANNOTATION__MAX_OFFSET_LEVEL) { goto print_addr; } else { printed = scnprintf(bf, sizeof(bf), "%-*s ", @@ -3228,43 +3331,44 @@ print_addr: } void annotation_line__write(struct annotation_line *al, struct annotation *notes, - struct annotation_write_ops *wops, - struct annotation_options *opts) + struct annotation_write_ops *wops) { __annotation_line__write(al, notes, wops->first_line, wops->current_entry, wops->change_color, wops->width, wops->obj, - opts->percent_type, + annotate_opts.percent_type, wops->set_color, wops->set_percent_color, wops->set_jumps_percent_color, wops->printf, wops->write_graph); } int symbol__annotate2(struct map_symbol *ms, struct evsel *evsel, - struct annotation_options *options, struct arch **parch) + struct arch **parch) { struct symbol *sym = ms->sym; struct annotation *notes = symbol__annotation(sym); size_t size = symbol__size(sym); int nr_pcnt = 1, err; - notes->offsets = zalloc(size * sizeof(struct annotation_line *)); - if (notes->offsets == NULL) + notes->src->offsets = zalloc(size * sizeof(struct annotation_line *)); + if (notes->src->offsets == NULL) return ENOMEM; if (evsel__is_group_event(evsel)) nr_pcnt = evsel->core.nr_members; - err = symbol__annotate(ms, evsel, options, parch); + err = symbol__annotate(ms, evsel, parch); if (err) goto out_free_offsets; - notes->options = options; - symbol__calc_percent(sym, evsel); annotation__set_offsets(notes, size); annotation__mark_jump_targets(notes, sym); - annotation__compute_ipc(notes, size); + + err = annotation__compute_ipc(notes, size); + if (err) + goto out_free_offsets; + annotation__init_column_widths(notes, sym); notes->nr_events = nr_pcnt; @@ -3274,7 +3378,7 @@ int symbol__annotate2(struct map_symbol *ms, struct evsel *evsel, return 0; out_free_offsets: - zfree(¬es->offsets); + zfree(¬es->src->offsets); return err; } @@ -3337,8 +3441,10 @@ static int annotation__config(const char *var, const char *value, void *data) return 0; } -void annotation_options__init(struct annotation_options *opt) +void annotation_options__init(void) { + struct annotation_options *opt = &annotate_opts; + memset(opt, 0, sizeof(*opt)); /* Default values. */ @@ -3349,16 +3455,15 @@ void annotation_options__init(struct annotation_options *opt) opt->percent_type = PERCENT_PERIOD_LOCAL; } - -void annotation_options__exit(struct annotation_options *opt) +void annotation_options__exit(void) { - zfree(&opt->disassembler_style); - zfree(&opt->objdump_path); + zfree(&annotate_opts.disassembler_style); + zfree(&annotate_opts.objdump_path); } -void annotation_config__init(struct annotation_options *opt) +void annotation_config__init(void) { - perf_config(annotation__config, opt); + perf_config(annotation__config, &annotate_opts); } static unsigned int parse_percent_type(char *str1, char *str2) @@ -3382,10 +3487,9 @@ static unsigned int parse_percent_type(char *str1, char *str2) return type; } -int annotate_parse_percent_type(const struct option *opt, const char *_str, +int annotate_parse_percent_type(const struct option *opt __maybe_unused, const char *_str, int unset __maybe_unused) { - struct annotation_options *opts = opt->value; unsigned int type; char *str1, *str2; int err = -1; @@ -3404,7 +3508,7 @@ int annotate_parse_percent_type(const struct option *opt, const char *_str, if (type == (unsigned int) -1) type = parse_percent_type(str2, str1); if (type != (unsigned int) -1) { - opts->percent_type = type; + annotate_opts.percent_type = type; err = 0; } @@ -3413,11 +3517,267 @@ out: return err; } -int annotate_check_args(struct annotation_options *args) +int annotate_check_args(void) { + struct annotation_options *args = &annotate_opts; + if (args->prefix_strip && !args->prefix) { pr_err("--prefix-strip requires --prefix\n"); return -1; } return 0; } + +/* + * Get register number and access offset from the given instruction. + * It assumes AT&T x86 asm format like OFFSET(REG). Maybe it needs + * to revisit the format when it handles different architecture. + * Fills @reg and @offset when return 0. + */ +static int extract_reg_offset(struct arch *arch, const char *str, + struct annotated_op_loc *op_loc) +{ + char *p; + char *regname; + + if (arch->objdump.register_char == 0) + return -1; + + /* + * It should start from offset, but it's possible to skip 0 + * in the asm. So 0(%rax) should be same as (%rax). + * + * However, it also start with a segment select register like + * %gs:0x18(%rbx). In that case it should skip the part. + */ + if (*str == arch->objdump.register_char) { + while (*str && !isdigit(*str) && + *str != arch->objdump.memory_ref_char) + str++; + } + + op_loc->offset = strtol(str, &p, 0); + + p = strchr(p, arch->objdump.register_char); + if (p == NULL) + return -1; + + regname = strdup(p); + if (regname == NULL) + return -1; + + op_loc->reg = get_dwarf_regnum(regname, 0); + free(regname); + return 0; +} + +/** + * annotate_get_insn_location - Get location of instruction + * @arch: the architecture info + * @dl: the target instruction + * @loc: a buffer to save the data + * + * Get detailed location info (register and offset) in the instruction. + * It needs both source and target operand and whether it accesses a + * memory location. The offset field is meaningful only when the + * corresponding mem flag is set. + * + * Some examples on x86: + * + * mov (%rax), %rcx # src_reg = rax, src_mem = 1, src_offset = 0 + * # dst_reg = rcx, dst_mem = 0 + * + * mov 0x18, %r8 # src_reg = -1, dst_reg = r8 + */ +int annotate_get_insn_location(struct arch *arch, struct disasm_line *dl, + struct annotated_insn_loc *loc) +{ + struct ins_operands *ops; + struct annotated_op_loc *op_loc; + int i; + + if (!strcmp(dl->ins.name, "lock")) + ops = dl->ops.locked.ops; + else + ops = &dl->ops; + + if (ops == NULL) + return -1; + + memset(loc, 0, sizeof(*loc)); + + for_each_insn_op_loc(loc, i, op_loc) { + const char *insn_str = ops->source.raw; + + if (i == INSN_OP_TARGET) + insn_str = ops->target.raw; + + /* Invalidate the register by default */ + op_loc->reg = -1; + + if (insn_str == NULL) + continue; + + if (strchr(insn_str, arch->objdump.memory_ref_char)) { + op_loc->mem_ref = true; + extract_reg_offset(arch, insn_str, op_loc); + } else { + char *s = strdup(insn_str); + + if (s) { + op_loc->reg = get_dwarf_regnum(s, 0); + free(s); + } + } + } + + return 0; +} + +static void symbol__ensure_annotate(struct map_symbol *ms, struct evsel *evsel) +{ + struct disasm_line *dl, *tmp_dl; + struct annotation *notes; + + notes = symbol__annotation(ms->sym); + if (!list_empty(¬es->src->source)) + return; + + if (symbol__annotate(ms, evsel, NULL) < 0) + return; + + /* remove non-insn disasm lines for simplicity */ + list_for_each_entry_safe(dl, tmp_dl, ¬es->src->source, al.node) { + if (dl->al.offset == -1) { + list_del(&dl->al.node); + free(dl); + } + } +} + +static struct disasm_line *find_disasm_line(struct symbol *sym, u64 ip) +{ + struct disasm_line *dl; + struct annotation *notes; + + notes = symbol__annotation(sym); + + list_for_each_entry(dl, ¬es->src->source, al.node) { + if (sym->start + dl->al.offset == ip) + return dl; + } + return NULL; +} + +static struct annotated_item_stat *annotate_data_stat(struct list_head *head, + const char *name) +{ + struct annotated_item_stat *istat; + + list_for_each_entry(istat, head, list) { + if (!strcmp(istat->name, name)) + return istat; + } + + istat = zalloc(sizeof(*istat)); + if (istat == NULL) + return NULL; + + istat->name = strdup(name); + if (istat->name == NULL) { + free(istat); + return NULL; + } + + list_add_tail(&istat->list, head); + return istat; +} + +/** + * hist_entry__get_data_type - find data type for given hist entry + * @he: hist entry + * + * This function first annotates the instruction at @he->ip and extracts + * register and offset info from it. Then it searches the DWARF debug + * info to get a variable and type information using the address, register, + * and offset. + */ +struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he) +{ + struct map_symbol *ms = &he->ms; + struct evsel *evsel = hists_to_evsel(he->hists); + struct arch *arch; + struct disasm_line *dl; + struct annotated_insn_loc loc; + struct annotated_op_loc *op_loc; + struct annotated_data_type *mem_type; + struct annotated_item_stat *istat; + u64 ip = he->ip; + int i; + + ann_data_stat.total++; + + if (ms->map == NULL || ms->sym == NULL) { + ann_data_stat.no_sym++; + return NULL; + } + + if (!symbol_conf.init_annotation) { + ann_data_stat.no_sym++; + return NULL; + } + + if (evsel__get_arch(evsel, &arch) < 0) { + ann_data_stat.no_insn++; + return NULL; + } + + /* Make sure it runs objdump to get disasm of the function */ + symbol__ensure_annotate(ms, evsel); + + /* + * Get a disasm to extract the location from the insn. + * This is too slow... + */ + dl = find_disasm_line(ms->sym, ip); + if (dl == NULL) { + ann_data_stat.no_insn++; + return NULL; + } + + istat = annotate_data_stat(&ann_insn_stat, dl->ins.name); + if (istat == NULL) { + ann_data_stat.no_insn++; + return NULL; + } + + if (annotate_get_insn_location(arch, dl, &loc) < 0) { + ann_data_stat.no_insn_ops++; + istat->bad++; + return NULL; + } + + for_each_insn_op_loc(&loc, i, op_loc) { + if (!op_loc->mem_ref) + continue; + + mem_type = find_data_type(ms, ip, op_loc->reg, op_loc->offset); + if (mem_type) + istat->good++; + else + istat->bad++; + + if (symbol_conf.annotate_data_sample) { + annotated_data_type__update_samples(mem_type, evsel, + op_loc->offset, + he->stat.nr_events, + he->stat.period); + } + he->mem_type_off = op_loc->offset; + return mem_type; + } + + ann_data_stat.no_mem_ops++; + istat->bad++; + return NULL; +} diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 9627805591..dba50762c6 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -23,6 +23,7 @@ struct option; struct perf_sample; struct evsel; struct symbol; +struct annotated_data_type; struct ins { const char *name; @@ -31,8 +32,6 @@ struct ins { struct ins_operands { char *raw; - char *raw_comment; - char *raw_func_start; struct { char *raw; char *name; @@ -41,22 +40,30 @@ struct ins_operands { s64 offset; bool offset_avail; bool outside; + bool multi_regs; } target; union { struct { char *raw; char *name; u64 addr; + bool multi_regs; } source; struct { struct ins ins; struct ins_operands *ops; } locked; + struct { + char *raw_comment; + char *raw_func_start; + } jump; }; }; struct arch; +bool arch__is(struct arch *arch, const char *name); + struct ins_ops { void (*free)(struct ins_operands *ops); int (*parse)(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms); @@ -101,6 +108,8 @@ struct annotation_options { unsigned int percent_type; }; +extern struct annotation_options annotate_opts; + enum { ANNOTATION__OFFSET_JUMP_TARGETS = 1, ANNOTATION__OFFSET_CALL, @@ -130,6 +139,13 @@ struct annotation_data { struct sym_hist_entry he; }; +struct cycles_info { + float ipc; + u64 avg; + u64 max; + u64 min; +}; + struct annotation_line { struct list_head node; struct rb_node rb_node; @@ -137,12 +153,9 @@ struct annotation_line { char *line; int line_nr; char *fileloc; - int jump_sources; - float ipc; - u64 cycles; - u64 cycles_max; - u64 cycles_min; char *path; + struct cycles_info *cycles; + int jump_sources; u32 idx; int idx_asm; int data_nr; @@ -214,8 +227,7 @@ struct annotation_write_ops { }; void annotation_line__write(struct annotation_line *al, struct annotation *notes, - struct annotation_write_ops *ops, - struct annotation_options *opts); + struct annotation_write_ops *ops); int __annotation__scnprintf_samples_period(struct annotation *notes, char *bf, size_t size, @@ -264,27 +276,29 @@ struct cyc_hist { * returns. */ struct annotated_source { - struct list_head source; - int nr_histograms; - size_t sizeof_sym_hist; - struct cyc_hist *cycles_hist; - struct sym_hist *histograms; + struct list_head source; + size_t sizeof_sym_hist; + struct sym_hist *histograms; + struct annotation_line **offsets; + int nr_histograms; + int nr_entries; + int nr_asm_entries; + u16 max_line_len; }; -struct LOCKABLE annotation { - u64 max_coverage; - u64 start; +struct annotated_branch { u64 hit_cycles; u64 hit_insn; unsigned int total_insn; unsigned int cover_insn; - struct annotation_options *options; - struct annotation_line **offsets; + struct cyc_hist *cycles_hist; + u64 max_coverage; +}; + +struct LOCKABLE annotation { + u64 start; int nr_events; int max_jump_sources; - int nr_entries; - int nr_asm_entries; - u16 max_line_len; struct { u8 addr; u8 jumps; @@ -293,8 +307,8 @@ struct LOCKABLE annotation { u8 max_addr; u8 max_ins_name; } widths; - bool have_cycles; struct annotated_source *src; + struct annotated_branch *branch; }; static inline void annotation__init(struct annotation *notes __maybe_unused) @@ -308,10 +322,10 @@ bool annotation__trylock(struct annotation *notes) EXCLUSIVE_TRYLOCK_FUNCTION(tr static inline int annotation__cycles_width(struct annotation *notes) { - if (notes->have_cycles && notes->options->show_minmax_cycle) + if (notes->branch && annotate_opts.show_minmax_cycle) return ANNOTATION__IPC_WIDTH + ANNOTATION__MINMAX_CYCLES_WIDTH; - return notes->have_cycles ? ANNOTATION__IPC_WIDTH + ANNOTATION__CYCLES_WIDTH : 0; + return notes->branch ? ANNOTATION__IPC_WIDTH + ANNOTATION__CYCLES_WIDTH : 0; } static inline int annotation__pcnt_width(struct annotation *notes) @@ -319,13 +333,12 @@ static inline int annotation__pcnt_width(struct annotation *notes) return (symbol_conf.show_total_period ? 12 : 7) * notes->nr_events; } -static inline bool annotation_line__filter(struct annotation_line *al, struct annotation *notes) +static inline bool annotation_line__filter(struct annotation_line *al) { - return notes->options->hide_src_code && al->offset == -1; + return annotate_opts.hide_src_code && al->offset == -1; } void annotation__set_offsets(struct annotation *notes, s64 size); -void annotation__compute_ipc(struct annotation *notes, size_t size); void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym); void annotation__update_column_widths(struct annotation *notes); void annotation__init_column_widths(struct annotation *notes, struct symbol *sym); @@ -349,6 +362,8 @@ static inline struct annotation *symbol__annotation(struct symbol *sym) int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample, struct evsel *evsel); +struct annotated_branch *annotation__get_branch(struct annotation *notes); + int addr_map_symbol__account_cycles(struct addr_map_symbol *ams, struct addr_map_symbol *start, unsigned cycles); @@ -361,11 +376,9 @@ void symbol__annotate_zero_histograms(struct symbol *sym); int symbol__annotate(struct map_symbol *ms, struct evsel *evsel, - struct annotation_options *options, struct arch **parch); int symbol__annotate2(struct map_symbol *ms, struct evsel *evsel, - struct annotation_options *options, struct arch **parch); enum symbol_disassemble_errno { @@ -392,43 +405,86 @@ enum symbol_disassemble_errno { int symbol__strerror_disassemble(struct map_symbol *ms, int errnum, char *buf, size_t buflen); -int symbol__annotate_printf(struct map_symbol *ms, struct evsel *evsel, - struct annotation_options *options); +int symbol__annotate_printf(struct map_symbol *ms, struct evsel *evsel); 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 evsel *evsel, - struct annotation_options *opts); +int map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel); bool ui__has_annotation(void); -int symbol__tty_annotate(struct map_symbol *ms, struct evsel *evsel, struct annotation_options *opts); +int symbol__tty_annotate(struct map_symbol *ms, struct evsel *evsel); -int symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel, struct annotation_options *opts); +int symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel); #ifdef HAVE_SLANG_SUPPORT int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, - struct hist_browser_timer *hbt, - struct annotation_options *opts); + struct hist_browser_timer *hbt); #else static inline int symbol__tui_annotate(struct map_symbol *ms __maybe_unused, struct evsel *evsel __maybe_unused, - struct hist_browser_timer *hbt __maybe_unused, - struct annotation_options *opts __maybe_unused) + struct hist_browser_timer *hbt __maybe_unused) { return 0; } #endif -void annotation_options__init(struct annotation_options *opt); -void annotation_options__exit(struct annotation_options *opt); +void annotation_options__init(void); +void annotation_options__exit(void); -void annotation_config__init(struct annotation_options *opt); +void annotation_config__init(void); int annotate_parse_percent_type(const struct option *opt, const char *_str, int unset); -int annotate_check_args(struct annotation_options *args); +int annotate_check_args(void); + +/** + * struct annotated_op_loc - Location info of instruction operand + * @reg: Register in the operand + * @offset: Memory access offset in the operand + * @mem_ref: Whether the operand accesses memory + */ +struct annotated_op_loc { + int reg; + int offset; + bool mem_ref; +}; + +enum annotated_insn_ops { + INSN_OP_SOURCE = 0, + INSN_OP_TARGET = 1, + + INSN_OP_MAX, +}; + +/** + * struct annotated_insn_loc - Location info of instruction + * @ops: Array of location info for source and target operands + */ +struct annotated_insn_loc { + struct annotated_op_loc ops[INSN_OP_MAX]; +}; + +#define for_each_insn_op_loc(insn_loc, i, op_loc) \ + for (i = INSN_OP_SOURCE, op_loc = &(insn_loc)->ops[i]; \ + i < INSN_OP_MAX; \ + i++, op_loc++) + +/* Get detailed location info in the instruction */ +int annotate_get_insn_location(struct arch *arch, struct disasm_line *dl, + struct annotated_insn_loc *loc); + +/* Returns a data type from the sample instruction (if any) */ +struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he); + +struct annotated_item_stat { + struct list_head list; + char *name; + int good; + int bad; +}; +extern struct list_head ann_insn_stat; #endif /* __PERF_ANNOTATE_H */ diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index a0368202a7..3684e6009b 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c @@ -174,7 +174,7 @@ void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp, struct evlist *evlist, struct evsel *evsel, int idx) { - bool per_cpu = !perf_cpu_map__empty(evlist->core.user_requested_cpus); + bool per_cpu = !perf_cpu_map__has_any_cpu_or_is_empty(evlist->core.user_requested_cpus); mp->mmap_needed = evsel->needs_auxtrace_mmap; @@ -648,7 +648,7 @@ int auxtrace_parse_snapshot_options(struct auxtrace_record *itr, static int evlist__enable_event_idx(struct evlist *evlist, struct evsel *evsel, int idx) { - bool per_cpu_mmaps = !perf_cpu_map__empty(evlist->core.user_requested_cpus); + bool per_cpu_mmaps = !perf_cpu_map__has_any_cpu_or_is_empty(evlist->core.user_requested_cpus); if (per_cpu_mmaps) { struct perf_cpu evlist_cpu = perf_cpu_map__cpu(evlist->core.all_cpus, idx); @@ -1638,6 +1638,9 @@ int itrace_do_parse_synth_opts(struct itrace_synth_opts *synth_opts, case 'Z': synth_opts->timeless_decoding = true; break; + case 'T': + synth_opts->use_timestamp = true; + break; case ' ': case ',': break; diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h index 29eb82dff5..55702215a8 100644 --- a/tools/perf/util/auxtrace.h +++ b/tools/perf/util/auxtrace.h @@ -99,6 +99,7 @@ enum itrace_period_type { * @remote_access: whether to synthesize remote access events * @mem: whether to synthesize memory events * @timeless_decoding: prefer "timeless" decoding i.e. ignore timestamps + * @use_timestamp: use the timestamp trace as kernel time * @vm_time_correlation: perform VM Time Correlation * @vm_tm_corr_dry_run: VM Time Correlation dry-run * @vm_tm_corr_args: VM Time Correlation implementation-specific arguments @@ -146,6 +147,7 @@ struct itrace_synth_opts { bool remote_access; bool mem; bool timeless_decoding; + bool use_timestamp; bool vm_time_correlation; bool vm_tm_corr_dry_run; char *vm_tm_corr_args; @@ -678,6 +680,7 @@ bool auxtrace__evsel_is_auxtrace(struct perf_session *session, " q: quicker (less detailed) decoding\n" \ " A: approximate IPC\n" \ " Z: prefer to ignore timestamps (so-called \"timeless\" decoding)\n" \ +" T: use the timestamp trace as kernel time\n" \ " PERIOD[ns|us|ms|i|t]: specify period to sample stream\n" \ " concatenate multiple options. Default is iybxwpe or cewp\n" diff --git a/tools/perf/util/block-info.c b/tools/perf/util/block-info.c index 591fc1edd3..dec9109897 100644 --- a/tools/perf/util/block-info.c +++ b/tools/perf/util/block-info.c @@ -129,9 +129,9 @@ int block_info__process_sym(struct hist_entry *he, struct block_hist *bh, al.sym = he->ms.sym; notes = symbol__annotation(he->ms.sym); - if (!notes || !notes->src || !notes->src->cycles_hist) + if (!notes || !notes->branch || !notes->branch->cycles_hist) return 0; - ch = notes->src->cycles_hist; + ch = notes->branch->cycles_hist; for (unsigned int i = 0; i < symbol__size(he->ms.sym); i++) { if (ch[i].num_aggr) { struct block_info *bi; @@ -464,8 +464,7 @@ void block_info__free_report(struct block_report *reps, int nr_reps) } int report__browse_block_hists(struct block_hist *bh, float min_percent, - struct evsel *evsel, struct perf_env *env, - struct annotation_options *annotation_opts) + struct evsel *evsel, struct perf_env *env) { int ret; @@ -477,8 +476,7 @@ int report__browse_block_hists(struct block_hist *bh, float min_percent, return 0; case 1: symbol_conf.report_individual_block = true; - ret = block_hists_tui_browse(bh, evsel, min_percent, - env, annotation_opts); + ret = block_hists_tui_browse(bh, evsel, min_percent, env); return ret; default: return -1; diff --git a/tools/perf/util/block-info.h b/tools/perf/util/block-info.h index 42e9dcc4cf..96f53e8979 100644 --- a/tools/perf/util/block-info.h +++ b/tools/perf/util/block-info.h @@ -78,8 +78,7 @@ struct block_report *block_info__create_report(struct evlist *evlist, void block_info__free_report(struct block_report *reps, int nr_reps); int report__browse_block_hists(struct block_hist *bh, float min_percent, - struct evsel *evsel, struct perf_env *env, - struct annotation_options *annotation_opts); + struct evsel *evsel, struct perf_env *env); float block_info__total_cycles_percent(struct hist_entry *he); diff --git a/tools/perf/util/block-range.c b/tools/perf/util/block-range.c index 680e92774d..15c42196c2 100644 --- a/tools/perf/util/block-range.c +++ b/tools/perf/util/block-range.c @@ -311,6 +311,7 @@ done: double block_range__coverage(struct block_range *br) { struct symbol *sym; + struct annotated_branch *branch; if (!br) { if (block_ranges.blocks) @@ -323,5 +324,9 @@ double block_range__coverage(struct block_range *br) if (!sym) return -1; - return (double)br->coverage / symbol__annotation(sym)->max_coverage; + branch = symbol__annotation(sym)->branch; + if (!branch) + return -1; + + return (double)br->coverage / branch->max_coverage; } diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c index b00b5a2634..3573e0b7ef 100644 --- a/tools/perf/util/bpf-event.c +++ b/tools/perf/util/bpf-event.c @@ -386,6 +386,9 @@ int perf_event__synthesize_bpf_events(struct perf_session *session, int err; int fd; + if (opts->no_bpf_event) + return 0; + event = malloc(sizeof(event->bpf) + KSYM_NAME_LEN + machine->id_hdr_size); if (!event) return -1; diff --git a/tools/perf/util/bpf_counter.c b/tools/perf/util/bpf_counter.c index 7f9b0e46e0..7a8af60e0f 100644 --- a/tools/perf/util/bpf_counter.c +++ b/tools/perf/util/bpf_counter.c @@ -455,7 +455,7 @@ static int bperf__load(struct evsel *evsel, struct target *target) return -1; if (!all_cpu_map) { - all_cpu_map = perf_cpu_map__new(NULL); + all_cpu_map = perf_cpu_map__new_online_cpus(); if (!all_cpu_map) return -1; } diff --git a/tools/perf/util/bpf_lock_contention.c b/tools/perf/util/bpf_lock_contention.c index f1716c089c..31ff19afc2 100644 --- a/tools/perf/util/bpf_lock_contention.c +++ b/tools/perf/util/bpf_lock_contention.c @@ -318,7 +318,7 @@ int lock_contention_read(struct lock_contention *con) } /* make sure it loads the kernel map */ - map__load(maps__first(machine->kmaps)->map); + maps__load_first(machine->kmaps); prev_key = NULL; while (!bpf_map_get_next_key(fd, prev_key, &key)) { diff --git a/tools/perf/util/bpf_skel/lock_contention.bpf.c b/tools/perf/util/bpf_skel/lock_contention.bpf.c index 95cd8414f6..e5d78565f4 100644 --- a/tools/perf/util/bpf_skel/lock_contention.bpf.c +++ b/tools/perf/util/bpf_skel/lock_contention.bpf.c @@ -289,6 +289,7 @@ static inline __u32 check_lock_type(__u64 lock, __u32 flags) struct task_struct *curr; struct mm_struct___old *mm_old; struct mm_struct___new *mm_new; + struct sighand_struct *sighand; switch (flags) { case LCB_F_READ: /* rwsem */ @@ -310,7 +311,9 @@ static inline __u32 check_lock_type(__u64 lock, __u32 flags) break; case LCB_F_SPIN: /* spinlock */ curr = bpf_get_current_task_btf(); - if (&curr->sighand->siglock == (void *)lock) + sighand = curr->sighand; + + if (sighand && &sighand->siglock == (void *)lock) return LCD_F_SIGHAND_LOCK; break; default: diff --git a/tools/perf/util/compress.h b/tools/perf/util/compress.h index 0cd3369af2..b29109cd36 100644 --- a/tools/perf/util/compress.h +++ b/tools/perf/util/compress.h @@ -3,6 +3,8 @@ #define PERF_COMPRESS_H #include +#include +#include #ifdef HAVE_ZSTD_SUPPORT #include #endif @@ -21,6 +23,7 @@ struct zstd_data { #ifdef HAVE_ZSTD_SUPPORT ZSTD_CStream *cstream; ZSTD_DStream *dstream; + int comp_level; #endif }; @@ -29,7 +32,7 @@ struct zstd_data { int zstd_init(struct zstd_data *data, int level); int zstd_fini(struct zstd_data *data); -size_t zstd_compress_stream_to_records(struct zstd_data *data, void *dst, size_t dst_size, +ssize_t zstd_compress_stream_to_records(struct zstd_data *data, void *dst, size_t dst_size, void *src, size_t src_size, size_t max_record_size, size_t process_header(void *record, size_t increment)); @@ -48,7 +51,7 @@ static inline int zstd_fini(struct zstd_data *data __maybe_unused) } static inline -size_t zstd_compress_stream_to_records(struct zstd_data *data __maybe_unused, +ssize_t zstd_compress_stream_to_records(struct zstd_data *data __maybe_unused, void *dst __maybe_unused, size_t dst_size __maybe_unused, void *src __maybe_unused, size_t src_size __maybe_unused, size_t max_record_size __maybe_unused, diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index 0e090e8bc3..0581ee0fa5 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c @@ -672,7 +672,7 @@ struct perf_cpu_map *cpu_map__online(void) /* thread unsafe */ static struct perf_cpu_map *online; if (!online) - online = perf_cpu_map__new(NULL); /* from /sys/devices/system/cpu/online */ + online = perf_cpu_map__new_online_cpus(); /* from /sys/devices/system/cpu/online */ return online; } diff --git a/tools/perf/util/cputopo.c b/tools/perf/util/cputopo.c index 81cfc85f46..8bbeb2dc76 100644 --- a/tools/perf/util/cputopo.c +++ b/tools/perf/util/cputopo.c @@ -267,7 +267,7 @@ struct cpu_topology *cpu_topology__new(void) ncpus = cpu__max_present_cpu().cpu; /* build online CPU map */ - map = perf_cpu_map__new(NULL); + map = perf_cpu_map__new_online_cpus(); if (map == NULL) { pr_debug("failed to get system cpumap\n"); return NULL; diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c index a9873d14c6..d65d748588 100644 --- a/tools/perf/util/cs-etm.c +++ b/tools/perf/util/cs-etm.c @@ -3346,12 +3346,27 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event, etm->metadata = metadata; etm->auxtrace_type = auxtrace_info->type; - /* Use virtual timestamps if all ETMs report ts_source = 1 */ - etm->has_virtual_ts = cs_etm__has_virtual_ts(metadata, num_cpu); + if (etm->synth_opts.use_timestamp) + /* + * Prior to Armv8.4, Arm CPUs don't support FEAT_TRF feature, + * therefore the decoder cannot know if the timestamp trace is + * same with the kernel time. + * + * If a user has knowledge for the working platform and can + * specify itrace option 'T' to tell decoder to forcely use the + * traced timestamp as the kernel time. + */ + etm->has_virtual_ts = true; + else + /* Use virtual timestamps if all ETMs report ts_source = 1 */ + etm->has_virtual_ts = cs_etm__has_virtual_ts(metadata, num_cpu); if (!etm->has_virtual_ts) ui__warning("Virtual timestamps are not enabled, or not supported by the traced system.\n" - "The time field of the samples will not be set accurately.\n\n"); + "The time field of the samples will not be set accurately.\n" + "For Arm CPUs prior to Armv8.4 or without support FEAT_TRF,\n" + "you can specify the itrace option 'T' for timestamp decoding\n" + "if the Coresight timestamp on the platform is same with the kernel time.\n\n"); etm->auxtrace.process_event = cs_etm__process_event; etm->auxtrace.process_auxtrace_event = cs_etm__process_auxtrace_event; diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index 88378c4c5d..e282b4ceb4 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c @@ -38,12 +38,21 @@ bool dump_trace = false, quiet = false; int debug_ordered_events; static int redirect_to_stderr; int debug_data_convert; -static FILE *debug_file; +static FILE *_debug_file; bool debug_display_time; +FILE *debug_file(void) +{ + if (!_debug_file) { + pr_warning_once("debug_file not set"); + debug_set_file(stderr); + } + return _debug_file; +} + void debug_set_file(FILE *file) { - debug_file = file; + _debug_file = file; } void debug_set_display_time(bool set) @@ -78,8 +87,8 @@ int veprintf(int level, int var, const char *fmt, va_list args) if (use_browser >= 1 && !redirect_to_stderr) { ui_helpline__vshow(fmt, args); } else { - ret = fprintf_time(debug_file); - ret += vfprintf(debug_file, fmt, args); + ret = fprintf_time(debug_file()); + ret += vfprintf(debug_file(), fmt, args); } } @@ -107,9 +116,8 @@ static int veprintf_time(u64 t, const char *fmt, va_list args) nsecs -= secs * NSEC_PER_SEC; usecs = nsecs / NSEC_PER_USEC; - ret = fprintf(stderr, "[%13" PRIu64 ".%06" PRIu64 "] ", - secs, usecs); - ret += vfprintf(stderr, fmt, args); + ret = fprintf(debug_file(), "[%13" PRIu64 ".%06" PRIu64 "] ", secs, usecs); + ret += vfprintf(debug_file(), fmt, args); return ret; } diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index f99468a7f6..de8870980d 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h @@ -77,6 +77,7 @@ int eprintf_time(int level, int var, u64 t, const char *fmt, ...) __printf(4, 5) int veprintf(int level, int var, const char *fmt, va_list args); int perf_debug_option(const char *str); +FILE *debug_file(void); void debug_set_file(FILE *file); void debug_set_display_time(bool set); void perf_debug_setup(void); diff --git a/tools/perf/util/debuginfo.c b/tools/perf/util/debuginfo.c new file mode 100644 index 0000000000..19acf4775d --- /dev/null +++ b/tools/perf/util/debuginfo.c @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * DWARF debug information handling code. Copied from probe-finder.c. + * + * Written by Masami Hiramatsu + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "build-id.h" +#include "dso.h" +#include "debug.h" +#include "debuginfo.h" +#include "symbol.h" + +#ifdef HAVE_DEBUGINFOD_SUPPORT +#include +#endif + +/* Dwarf FL wrappers */ +static char *debuginfo_path; /* Currently dummy */ + +static const Dwfl_Callbacks offline_callbacks = { + .find_debuginfo = dwfl_standard_find_debuginfo, + .debuginfo_path = &debuginfo_path, + + .section_address = dwfl_offline_section_address, + + /* We use this table for core files too. */ + .find_elf = dwfl_build_id_find_elf, +}; + +/* Get a Dwarf from offline image */ +static int debuginfo__init_offline_dwarf(struct debuginfo *dbg, + const char *path) +{ + GElf_Addr dummy; + int fd; + + fd = open(path, O_RDONLY); + if (fd < 0) + return fd; + + dbg->dwfl = dwfl_begin(&offline_callbacks); + if (!dbg->dwfl) + goto error; + + dwfl_report_begin(dbg->dwfl); + dbg->mod = dwfl_report_offline(dbg->dwfl, "", "", fd); + if (!dbg->mod) + goto error; + + dbg->dbg = dwfl_module_getdwarf(dbg->mod, &dbg->bias); + if (!dbg->dbg) + goto error; + + dwfl_module_build_id(dbg->mod, &dbg->build_id, &dummy); + + dwfl_report_end(dbg->dwfl, NULL, NULL); + + return 0; +error: + if (dbg->dwfl) + dwfl_end(dbg->dwfl); + else + close(fd); + memset(dbg, 0, sizeof(*dbg)); + + return -ENOENT; +} + +static struct debuginfo *__debuginfo__new(const char *path) +{ + struct debuginfo *dbg = zalloc(sizeof(*dbg)); + if (!dbg) + return NULL; + + if (debuginfo__init_offline_dwarf(dbg, path) < 0) + zfree(&dbg); + if (dbg) + pr_debug("Open Debuginfo file: %s\n", path); + return dbg; +} + +enum dso_binary_type distro_dwarf_types[] = { + DSO_BINARY_TYPE__FEDORA_DEBUGINFO, + DSO_BINARY_TYPE__UBUNTU_DEBUGINFO, + DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO, + DSO_BINARY_TYPE__BUILDID_DEBUGINFO, + DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO, + DSO_BINARY_TYPE__NOT_FOUND, +}; + +struct debuginfo *debuginfo__new(const char *path) +{ + enum dso_binary_type *type; + char buf[PATH_MAX], nil = '\0'; + struct dso *dso; + struct debuginfo *dinfo = NULL; + struct build_id bid; + + /* Try to open distro debuginfo files */ + dso = dso__new(path); + if (!dso) + goto out; + + /* Set the build id for DSO_BINARY_TYPE__BUILDID_DEBUGINFO */ + if (is_regular_file(path) && filename__read_build_id(path, &bid) > 0) + dso__set_build_id(dso, &bid); + + for (type = distro_dwarf_types; + !dinfo && *type != DSO_BINARY_TYPE__NOT_FOUND; + type++) { + if (dso__read_binary_type_filename(dso, *type, &nil, + buf, PATH_MAX) < 0) + continue; + dinfo = __debuginfo__new(buf); + } + dso__put(dso); + +out: + /* if failed to open all distro debuginfo, open given binary */ + return dinfo ? : __debuginfo__new(path); +} + +void debuginfo__delete(struct debuginfo *dbg) +{ + if (dbg) { + if (dbg->dwfl) + dwfl_end(dbg->dwfl); + free(dbg); + } +} + +/* For the kernel module, we need a special code to get a DIE */ +int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs, + bool adjust_offset) +{ + int n, i; + Elf32_Word shndx; + Elf_Scn *scn; + Elf *elf; + GElf_Shdr mem, *shdr; + const char *p; + + elf = dwfl_module_getelf(dbg->mod, &dbg->bias); + if (!elf) + return -EINVAL; + + /* Get the number of relocations */ + n = dwfl_module_relocations(dbg->mod); + if (n < 0) + return -ENOENT; + /* Search the relocation related .text section */ + for (i = 0; i < n; i++) { + p = dwfl_module_relocation_info(dbg->mod, i, &shndx); + if (strcmp(p, ".text") == 0) { + /* OK, get the section header */ + scn = elf_getscn(elf, shndx); + if (!scn) + return -ENOENT; + shdr = gelf_getshdr(scn, &mem); + if (!shdr) + return -ENOENT; + *offs = shdr->sh_addr; + if (adjust_offset) + *offs -= shdr->sh_offset; + } + } + return 0; +} + +#ifdef HAVE_DEBUGINFOD_SUPPORT +int get_source_from_debuginfod(const char *raw_path, + const char *sbuild_id, char **new_path) +{ + debuginfod_client *c = debuginfod_begin(); + const char *p = raw_path; + int fd; + + if (!c) + return -ENOMEM; + + fd = debuginfod_find_source(c, (const unsigned char *)sbuild_id, + 0, p, new_path); + pr_debug("Search %s from debuginfod -> %d\n", p, fd); + if (fd >= 0) + close(fd); + debuginfod_end(c); + if (fd < 0) { + pr_debug("Failed to find %s in debuginfod (%s)\n", + raw_path, sbuild_id); + return -ENOENT; + } + pr_debug("Got a source %s\n", *new_path); + + return 0; +} +#endif /* HAVE_DEBUGINFOD_SUPPORT */ diff --git a/tools/perf/util/debuginfo.h b/tools/perf/util/debuginfo.h new file mode 100644 index 0000000000..4d65b8c605 --- /dev/null +++ b/tools/perf/util/debuginfo.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef _PERF_DEBUGINFO_H +#define _PERF_DEBUGINFO_H + +#include +#include + +#ifdef HAVE_DWARF_SUPPORT + +#include "dwarf-aux.h" + +/* debug information structure */ +struct debuginfo { + Dwarf *dbg; + Dwfl_Module *mod; + Dwfl *dwfl; + Dwarf_Addr bias; + const unsigned char *build_id; +}; + +/* This also tries to open distro debuginfo */ +struct debuginfo *debuginfo__new(const char *path); +void debuginfo__delete(struct debuginfo *dbg); + +int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs, + bool adjust_offset); + +#else /* HAVE_DWARF_SUPPORT */ + +/* dummy debug information structure */ +struct debuginfo { +}; + +static inline struct debuginfo *debuginfo__new(const char *path __maybe_unused) +{ + return NULL; +} + +static inline void debuginfo__delete(struct debuginfo *dbg __maybe_unused) +{ +} + +static inline int debuginfo__get_text_offset(struct debuginfo *dbg __maybe_unused, + Dwarf_Addr *offs __maybe_unused, + bool adjust_offset __maybe_unused) +{ + return -EINVAL; +} + +#endif /* HAVE_DWARF_SUPPORT */ + +#ifdef HAVE_DEBUGINFOD_SUPPORT +int get_source_from_debuginfod(const char *raw_path, const char *sbuild_id, + char **new_path); +#else /* HAVE_DEBUGINFOD_SUPPORT */ +static inline int get_source_from_debuginfod(const char *raw_path __maybe_unused, + const char *sbuild_id __maybe_unused, + char **new_path __maybe_unused) +{ + return -ENOTSUP; +} +#endif /* HAVE_DEBUGINFOD_SUPPORT */ + +#endif /* _PERF_DEBUGINFO_H */ diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index 1f629b6fb7..22fd5fa806 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -31,6 +31,7 @@ #include "debug.h" #include "string2.h" #include "vdso.h" +#include "annotate-data.h" static const char * const debuglink_paths[] = { "%.0s%s", @@ -1327,6 +1328,7 @@ struct dso *dso__new_id(const char *name, struct dso_id *id) dso->data.cache = RB_ROOT; dso->inlined_nodes = RB_ROOT_CACHED; dso->srclines = RB_ROOT_CACHED; + dso->data_types = RB_ROOT; dso->data.fd = -1; dso->data.status = DSO_DATA_STATUS_UNKNOWN; dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; @@ -1370,6 +1372,8 @@ void dso__delete(struct dso *dso) symbols__delete(&dso->symbols); dso->symbol_names_len = 0; zfree(&dso->symbol_names); + annotated_data_type__tree_delete(&dso->data_types); + if (dso->short_name_allocated) { zfree((char **)&dso->short_name); dso->short_name_allocated = false; diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index 3759de8c22..ce9f3849a7 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h @@ -154,6 +154,8 @@ struct dso { size_t symbol_names_len; struct rb_root_cached inlined_nodes; struct rb_root_cached srclines; + struct rb_root data_types; + struct { u64 addr; struct symbol *symbol; diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index 2941d88f21..7aa5fee0da 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c @@ -1051,32 +1051,28 @@ Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name, } /** - * die_get_typename - Get the name of given variable DIE - * @vr_die: a variable DIE + * die_get_typename_from_type - Get the name of given type DIE + * @type_die: a type DIE * @buf: a strbuf for result type name * - * Get the name of @vr_die and stores it to @buf. Return 0 if succeeded. + * Get the name of @type_die and stores it to @buf. Return 0 if succeeded. * and Return -ENOENT if failed to find type name. * Note that the result will stores typedef name if possible, and stores * "*(function_type)" if the type is a function pointer. */ -int die_get_typename(Dwarf_Die *vr_die, struct strbuf *buf) +int die_get_typename_from_type(Dwarf_Die *type_die, struct strbuf *buf) { - Dwarf_Die type; int tag, ret; const char *tmp = ""; - if (__die_get_real_type(vr_die, &type) == NULL) - return -ENOENT; - - tag = dwarf_tag(&type); + tag = dwarf_tag(type_die); if (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type) tmp = "*"; else if (tag == DW_TAG_subroutine_type) { /* Function pointer */ return strbuf_add(buf, "(function_type)", 15); } else { - const char *name = dwarf_diename(&type); + const char *name = dwarf_diename(type_die); if (tag == DW_TAG_union_type) tmp = "union "; @@ -1089,8 +1085,35 @@ int die_get_typename(Dwarf_Die *vr_die, struct strbuf *buf) /* Write a base name */ return strbuf_addf(buf, "%s%s", tmp, name ?: ""); } - ret = die_get_typename(&type, buf); - return ret ? ret : strbuf_addstr(buf, tmp); + ret = die_get_typename(type_die, buf); + if (ret < 0) { + /* void pointer has no type attribute */ + if (tag == DW_TAG_pointer_type && ret == -ENOENT) + return strbuf_addf(buf, "void*"); + + return ret; + } + return strbuf_addstr(buf, tmp); +} + +/** + * die_get_typename - Get the name of given variable DIE + * @vr_die: a variable DIE + * @buf: a strbuf for result type name + * + * Get the name of @vr_die and stores it to @buf. Return 0 if succeeded. + * and Return -ENOENT if failed to find type name. + * Note that the result will stores typedef name if possible, and stores + * "*(function_type)" if the type is a function pointer. + */ +int die_get_typename(Dwarf_Die *vr_die, struct strbuf *buf) +{ + Dwarf_Die type; + + if (__die_get_real_type(vr_die, &type) == NULL) + return -ENOENT; + + return die_get_typename_from_type(&type, buf); } /** @@ -1238,12 +1261,151 @@ int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf) out: return ret; } -#else -int die_get_var_range(Dwarf_Die *sp_die __maybe_unused, - Dwarf_Die *vr_die __maybe_unused, - struct strbuf *buf __maybe_unused) + +/* Interval parameters for __die_find_var_reg_cb() */ +struct find_var_data { + /* Target instruction address */ + Dwarf_Addr pc; + /* Target memory address (for global data) */ + Dwarf_Addr addr; + /* Target register */ + unsigned reg; + /* Access offset, set for global data */ + int offset; +}; + +/* Max number of registers DW_OP_regN supports */ +#define DWARF_OP_DIRECT_REGS 32 + +/* Only checks direct child DIEs in the given scope. */ +static int __die_find_var_reg_cb(Dwarf_Die *die_mem, void *arg) +{ + struct find_var_data *data = arg; + int tag = dwarf_tag(die_mem); + ptrdiff_t off = 0; + Dwarf_Attribute attr; + Dwarf_Addr base, start, end; + Dwarf_Op *ops; + size_t nops; + + if (tag != DW_TAG_variable && tag != DW_TAG_formal_parameter) + return DIE_FIND_CB_SIBLING; + + if (dwarf_attr(die_mem, DW_AT_location, &attr) == NULL) + return DIE_FIND_CB_SIBLING; + + while ((off = dwarf_getlocations(&attr, off, &base, &start, &end, &ops, &nops)) > 0) { + /* Assuming the location list is sorted by address */ + if (end < data->pc) + continue; + if (start > data->pc) + break; + + /* Only match with a simple case */ + if (data->reg < DWARF_OP_DIRECT_REGS) { + if (ops->atom == (DW_OP_reg0 + data->reg) && nops == 1) + return DIE_FIND_CB_END; + } else { + if (ops->atom == DW_OP_regx && ops->number == data->reg && + nops == 1) + return DIE_FIND_CB_END; + } + } + return DIE_FIND_CB_SIBLING; +} + +/** + * die_find_variable_by_reg - Find a variable saved in a register + * @sc_die: a scope DIE + * @pc: the program address to find + * @reg: the register number to find + * @die_mem: a buffer to save the resulting DIE + * + * Find the variable DIE accessed by the given register. + */ +Dwarf_Die *die_find_variable_by_reg(Dwarf_Die *sc_die, Dwarf_Addr pc, int reg, + Dwarf_Die *die_mem) +{ + struct find_var_data data = { + .pc = pc, + .reg = reg, + }; + return die_find_child(sc_die, __die_find_var_reg_cb, &data, die_mem); +} + +/* Only checks direct child DIEs in the given scope */ +static int __die_find_var_addr_cb(Dwarf_Die *die_mem, void *arg) +{ + struct find_var_data *data = arg; + int tag = dwarf_tag(die_mem); + ptrdiff_t off = 0; + Dwarf_Attribute attr; + Dwarf_Addr base, start, end; + Dwarf_Word size; + Dwarf_Die type_die; + Dwarf_Op *ops; + size_t nops; + + if (tag != DW_TAG_variable) + return DIE_FIND_CB_SIBLING; + + if (dwarf_attr(die_mem, DW_AT_location, &attr) == NULL) + return DIE_FIND_CB_SIBLING; + + while ((off = dwarf_getlocations(&attr, off, &base, &start, &end, &ops, &nops)) > 0) { + if (ops->atom != DW_OP_addr) + continue; + + if (data->addr < ops->number) + continue; + + if (data->addr == ops->number) { + /* Update offset relative to the start of the variable */ + data->offset = 0; + return DIE_FIND_CB_END; + } + + if (die_get_real_type(die_mem, &type_die) == NULL) + continue; + + if (dwarf_aggregate_size(&type_die, &size) < 0) + continue; + + if (data->addr >= ops->number + size) + continue; + + /* Update offset relative to the start of the variable */ + data->offset = data->addr - ops->number; + return DIE_FIND_CB_END; + } + return DIE_FIND_CB_SIBLING; +} + +/** + * die_find_variable_by_addr - Find variable located at given address + * @sc_die: a scope DIE + * @pc: the program address to find + * @addr: the data address to find + * @die_mem: a buffer to save the resulting DIE + * @offset: the offset in the resulting type + * + * Find the variable DIE located at the given address (in PC-relative mode). + * This is usually for global variables. + */ +Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die, Dwarf_Addr pc, + Dwarf_Addr addr, Dwarf_Die *die_mem, + int *offset) { - return -ENOTSUP; + struct find_var_data data = { + .pc = pc, + .addr = addr, + }; + Dwarf_Die *result; + + result = die_find_child(sc_die, __die_find_var_addr_cb, &data, die_mem); + if (result) + *offset = data.offset; + return result; } #endif @@ -1425,3 +1587,56 @@ void die_skip_prologue(Dwarf_Die *sp_die, Dwarf_Die *cu_die, *entrypc = postprologue_addr; } + +/* Internal parameters for __die_find_scope_cb() */ +struct find_scope_data { + /* Target instruction address */ + Dwarf_Addr pc; + /* Number of scopes found [output] */ + int nr; + /* Array of scopes found, 0 for the outermost one. [output] */ + Dwarf_Die *scopes; +}; + +static int __die_find_scope_cb(Dwarf_Die *die_mem, void *arg) +{ + struct find_scope_data *data = arg; + + if (dwarf_haspc(die_mem, data->pc)) { + Dwarf_Die *tmp; + + tmp = realloc(data->scopes, (data->nr + 1) * sizeof(*tmp)); + if (tmp == NULL) + return DIE_FIND_CB_END; + + memcpy(tmp + data->nr, die_mem, sizeof(*die_mem)); + data->scopes = tmp; + data->nr++; + return DIE_FIND_CB_CHILD; + } + return DIE_FIND_CB_SIBLING; +} + +/** + * die_get_scopes - Return a list of scopes including the address + * @cu_die: a compile unit DIE + * @pc: the address to find + * @scopes: the array of DIEs for scopes (result) + * + * This function does the same as the dwarf_getscopes() but doesn't follow + * the origins of inlined functions. It returns the number of scopes saved + * in the @scopes argument. The outer scope will be saved first (index 0) and + * the last one is the innermost scope at the @pc. + */ +int die_get_scopes(Dwarf_Die *cu_die, Dwarf_Addr pc, Dwarf_Die **scopes) +{ + struct find_scope_data data = { + .pc = pc, + }; + Dwarf_Die die_mem; + + die_find_child(cu_die, __die_find_scope_cb, &data, &die_mem); + + *scopes = data.scopes; + return data.nr; +} diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h index 7ec8bc1083..4e64caac6d 100644 --- a/tools/perf/util/dwarf-aux.h +++ b/tools/perf/util/dwarf-aux.h @@ -116,12 +116,14 @@ Dwarf_Die *die_find_variable_at(Dwarf_Die *sp_die, const char *name, Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name, Dwarf_Die *die_mem); +/* Get the name of given type DIE */ +int die_get_typename_from_type(Dwarf_Die *type_die, struct strbuf *buf); + /* Get the name of given variable DIE */ int die_get_typename(Dwarf_Die *vr_die, struct strbuf *buf); /* Get the name and type of given variable DIE, stored as "type\tname" */ int die_get_varname(Dwarf_Die *vr_die, struct strbuf *buf); -int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf); /* Check if target program is compiled with optimization */ bool die_is_optimized_target(Dwarf_Die *cu_die); @@ -130,4 +132,49 @@ bool die_is_optimized_target(Dwarf_Die *cu_die); void die_skip_prologue(Dwarf_Die *sp_die, Dwarf_Die *cu_die, Dwarf_Addr *entrypc); -#endif +/* Get the list of including scopes */ +int die_get_scopes(Dwarf_Die *cu_die, Dwarf_Addr pc, Dwarf_Die **scopes); + +#ifdef HAVE_DWARF_GETLOCATIONS_SUPPORT + +/* Get byte offset range of given variable DIE */ +int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf); + +/* Find a variable saved in the 'reg' at given address */ +Dwarf_Die *die_find_variable_by_reg(Dwarf_Die *sc_die, Dwarf_Addr pc, int reg, + Dwarf_Die *die_mem); + +/* Find a (global) variable located in the 'addr' */ +Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die, Dwarf_Addr pc, + Dwarf_Addr addr, Dwarf_Die *die_mem, + int *offset); + +#else /* HAVE_DWARF_GETLOCATIONS_SUPPORT */ + +static inline int die_get_var_range(Dwarf_Die *sp_die __maybe_unused, + Dwarf_Die *vr_die __maybe_unused, + struct strbuf *buf __maybe_unused) +{ + return -ENOTSUP; +} + +static inline Dwarf_Die *die_find_variable_by_reg(Dwarf_Die *sc_die __maybe_unused, + Dwarf_Addr pc __maybe_unused, + int reg __maybe_unused, + Dwarf_Die *die_mem __maybe_unused) +{ + return NULL; +} + +static inline Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die __maybe_unused, + Dwarf_Addr pc __maybe_unused, + Dwarf_Addr addr __maybe_unused, + Dwarf_Die *die_mem __maybe_unused, + int *offset __maybe_unused) +{ + return NULL; +} + +#endif /* HAVE_DWARF_GETLOCATIONS_SUPPORT */ + +#endif /* _DWARF_AUX_H */ diff --git a/tools/perf/util/dwarf-regs.c b/tools/perf/util/dwarf-regs.c index 69cfaa5953..5b7f86c006 100644 --- a/tools/perf/util/dwarf-regs.c +++ b/tools/perf/util/dwarf-regs.c @@ -5,9 +5,12 @@ * Written by: Masami Hiramatsu */ +#include +#include #include #include #include +#include #include #ifndef EM_AARCH64 @@ -68,3 +71,34 @@ const char *get_dwarf_regstr(unsigned int n, unsigned int machine) } return NULL; } + +__weak int get_arch_regnum(const char *name __maybe_unused) +{ + return -ENOTSUP; +} + +/* Return DWARF register number from architecture register name */ +int get_dwarf_regnum(const char *name, unsigned int machine) +{ + char *regname = strdup(name); + int reg = -1; + char *p; + + if (regname == NULL) + return -EINVAL; + + /* For convenience, remove trailing characters */ + p = strpbrk(regname, " ,)"); + if (p) + *p = '\0'; + + switch (machine) { + case EM_NONE: /* Generic arch - use host arch */ + reg = get_arch_regnum(regname); + break; + default: + pr_err("ELF MACHINE %x is not supported.\n", machine); + } + free(regname); + return reg; +} diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c index 8da0e2c763..a459374d0a 100644 --- a/tools/perf/util/env.c +++ b/tools/perf/util/env.c @@ -3,6 +3,7 @@ #include "debug.h" #include "env.h" #include "util/header.h" +#include "linux/compiler.h" #include #include #include "cgroup.h" @@ -12,6 +13,7 @@ #include #include "pmus.h" #include "strbuf.h" +#include "trace/beauty/beauty.h" struct perf_env perf_env; @@ -467,6 +469,18 @@ const char *perf_env__arch(struct perf_env *env) return normalize_arch(arch_name); } +const char *perf_env__arch_strerrno(struct perf_env *env __maybe_unused, int err __maybe_unused) +{ +#if defined(HAVE_SYSCALL_TABLE_SUPPORT) && defined(HAVE_LIBTRACEEVENT) + if (env->arch_strerrno == NULL) + env->arch_strerrno = arch_syscalls__strerrno_function(perf_env__arch(env)); + + return env->arch_strerrno ? env->arch_strerrno(err) : "no arch specific strerrno function"; +#else + return "!(HAVE_SYSCALL_TABLE_SUPPORT && HAVE_LIBTRACEEVENT)"; +#endif +} + const char *perf_env__cpuid(struct perf_env *env) { int status; @@ -545,6 +559,24 @@ int perf_env__numa_node(struct perf_env *env, struct perf_cpu cpu) return cpu.cpu >= 0 && cpu.cpu < env->nr_numa_map ? env->numa_map[cpu.cpu] : -1; } +bool perf_env__has_pmu_mapping(struct perf_env *env, const char *pmu_name) +{ + char *pmu_mapping = env->pmu_mappings, *colon; + + for (int i = 0; i < env->nr_pmu_mappings; ++i) { + if (strtoul(pmu_mapping, &colon, 0) == ULONG_MAX || *colon != ':') + goto out_error; + + pmu_mapping = colon + 1; + if (strcmp(pmu_mapping, pmu_name) == 0) + return true; + + pmu_mapping += strlen(pmu_mapping) + 1; + } +out_error: + return false; +} + char *perf_env__find_pmu_cap(struct perf_env *env, const char *pmu_name, const char *cap) { diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h index 359eff51cb..7c527e65c1 100644 --- a/tools/perf/util/env.h +++ b/tools/perf/util/env.h @@ -46,10 +46,17 @@ struct hybrid_node { struct pmu_caps { int nr_caps; unsigned int max_branches; + unsigned int br_cntr_nr; + unsigned int br_cntr_width; + char **caps; char *pmu_name; }; +typedef const char *(arch_syscalls__strerrno_t)(int err); + +arch_syscalls__strerrno_t *arch_syscalls__strerrno_function(const char *arch); + struct perf_env { char *hostname; char *os_release; @@ -62,6 +69,8 @@ struct perf_env { unsigned long long total_mem; unsigned int msr_pmu_type; unsigned int max_branches; + unsigned int br_cntr_nr; + unsigned int br_cntr_width; int kernel_is_64_bit; int nr_cmdline; @@ -130,6 +139,7 @@ struct perf_env { */ bool enabled; } clock; + arch_syscalls__strerrno_t *arch_strerrno; }; enum perf_compress_type { @@ -159,6 +169,7 @@ int perf_env__read_cpu_topology_map(struct perf_env *env); void cpu_cache_level__free(struct cpu_cache_level *cache); const char *perf_env__arch(struct perf_env *env); +const char *perf_env__arch_strerrno(struct perf_env *env, int err); const char *perf_env__cpuid(struct perf_env *env); const char *perf_env__raw_arch(struct perf_env *env); int perf_env__nr_cpus_avail(struct perf_env *env); @@ -178,4 +189,6 @@ struct btf_node *__perf_env__find_btf(struct perf_env *env, __u32 btf_id); int perf_env__numa_node(struct perf_env *env, struct perf_cpu cpu); char *perf_env__find_pmu_cap(struct perf_env *env, const char *pmu_name, const char *cap); + +bool perf_env__has_pmu_mapping(struct perf_env *env, const char *pmu_name); #endif /* __PERF_ENV_H */ diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 923c0fb151..68f45e9e63 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -617,13 +617,13 @@ struct map *thread__find_map(struct thread *thread, u8 cpumode, u64 addr, if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) { al->level = 'k'; maps = machine__kernel_maps(machine); - load_map = true; + load_map = !symbol_conf.lazy_load_kernel_maps; } else if (cpumode == PERF_RECORD_MISC_USER && perf_host) { al->level = '.'; } else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) { al->level = 'g'; maps = machine__kernel_maps(machine); - load_map = true; + load_map = !symbol_conf.lazy_load_kernel_maps; } else if (cpumode == PERF_RECORD_MISC_GUEST_USER && perf_guest) { al->level = 'u'; } else { diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index eb1dd29c53..55a300a097 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -1063,7 +1063,7 @@ int evlist__create_maps(struct evlist *evlist, struct target *target) return -1; if (target__uses_dummy_map(target)) - cpus = perf_cpu_map__dummy_new(); + cpus = perf_cpu_map__new_any_cpu(); else cpus = perf_cpu_map__new(target->cpu_list); @@ -1359,7 +1359,7 @@ static int evlist__create_syswide_maps(struct evlist *evlist) * error, and we may not want to do that fallback to a * default cpu identity map :-\ */ - cpus = perf_cpu_map__new(NULL); + cpus = perf_cpu_map__new_online_cpus(); if (!cpus) goto out; @@ -2528,9 +2528,8 @@ void evlist__warn_user_requested_cpus(struct evlist *evlist, const char *cpu_lis void evlist__uniquify_name(struct evlist *evlist) { + char *new_name, empty_attributes[2] = ":", *attributes; struct evsel *pos; - char *new_name; - int ret; if (perf_pmus__num_core_pmus() == 1) return; @@ -2542,11 +2541,17 @@ void evlist__uniquify_name(struct evlist *evlist) if (strchr(pos->name, '/')) continue; - ret = asprintf(&new_name, "%s/%s/", - pos->pmu_name, pos->name); - if (ret) { + attributes = strchr(pos->name, ':'); + if (attributes) + *attributes = '\0'; + else + attributes = empty_attributes; + + if (asprintf(&new_name, "%s/%s/%s", pos->pmu_name, pos->name, attributes + 1)) { free(pos->name); pos->name = new_name; + } else { + *attributes = ':'; } } } diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 1fb24ca8ae..727dae445d 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -1801,7 +1801,7 @@ static int __evsel__prepare_open(struct evsel *evsel, struct perf_cpu_map *cpus, if (cpus == NULL) { if (empty_cpu_map == NULL) { - empty_cpu_map = perf_cpu_map__dummy_new(); + empty_cpu_map = perf_cpu_map__new_any_cpu(); if (empty_cpu_map == NULL) return -ENOMEM; } @@ -1832,6 +1832,8 @@ static int __evsel__prepare_open(struct evsel *evsel, struct perf_cpu_map *cpus, static void evsel__disable_missing_features(struct evsel *evsel) { + if (perf_missing_features.branch_counters) + evsel->core.attr.branch_sample_type &= ~PERF_SAMPLE_BRANCH_COUNTERS; if (perf_missing_features.read_lost) evsel->core.attr.read_format &= ~PERF_FORMAT_LOST; if (perf_missing_features.weight_struct) { @@ -1885,7 +1887,12 @@ bool evsel__detect_missing_features(struct evsel *evsel) * Must probe features in the order they were added to the * perf_event_attr interface. */ - if (!perf_missing_features.read_lost && + if (!perf_missing_features.branch_counters && + (evsel->core.attr.branch_sample_type & PERF_SAMPLE_BRANCH_COUNTERS)) { + perf_missing_features.branch_counters = true; + pr_debug2("switching off branch counters support\n"); + return true; + } else if (!perf_missing_features.read_lost && (evsel->core.attr.read_format & PERF_FORMAT_LOST)) { perf_missing_features.read_lost = true; pr_debug2("switching off PERF_FORMAT_LOST support\n"); @@ -2318,6 +2325,22 @@ u64 evsel__bitfield_swap_branch_flags(u64 value) return new_val; } +static inline bool evsel__has_branch_counters(const struct evsel *evsel) +{ + struct evsel *cur, *leader = evsel__leader(evsel); + + /* The branch counters feature only supports group */ + if (!leader || !evsel->evlist) + return false; + + evlist__for_each_entry(evsel->evlist, cur) { + if ((leader == evsel__leader(cur)) && + (cur->core.attr.branch_sample_type & PERF_SAMPLE_BRANCH_COUNTERS)) + return true; + } + return false; +} + int evsel__parse_sample(struct evsel *evsel, union perf_event *event, struct perf_sample *data) { @@ -2550,6 +2573,16 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event, OVERFLOW_CHECK(array, sz, max_size); array = (void *)array + sz; + + if (evsel__has_branch_counters(evsel)) { + OVERFLOW_CHECK_u64(array); + + data->branch_stack_cntr = (u64 *)array; + sz = data->branch_stack->nr * sizeof(u64); + + OVERFLOW_CHECK(array, sz, max_size); + array = (void *)array + sz; + } } if (type & PERF_SAMPLE_REGS_USER) { @@ -2819,7 +2852,8 @@ u64 evsel__intval_common(struct evsel *evsel, struct perf_sample *sample, const #endif -bool evsel__fallback(struct evsel *evsel, int err, char *msg, size_t msgsize) +bool evsel__fallback(struct evsel *evsel, struct target *target, int err, + char *msg, size_t msgsize) { int paranoid; @@ -2827,18 +2861,19 @@ bool evsel__fallback(struct evsel *evsel, int err, char *msg, size_t msgsize) evsel->core.attr.type == PERF_TYPE_HARDWARE && evsel->core.attr.config == PERF_COUNT_HW_CPU_CYCLES) { /* - * If it's cycles then fall back to hrtimer based - * cpu-clock-tick sw counter, which is always available even if - * no PMU support. + * If it's cycles then fall back to hrtimer based cpu-clock sw + * counter, which is always available even if no PMU support. * * PPC returns ENXIO until 2.6.37 (behavior changed with commit * b0a873e). */ - scnprintf(msg, msgsize, "%s", -"The cycles event is not supported, trying to fall back to cpu-clock-ticks"); - evsel->core.attr.type = PERF_TYPE_SOFTWARE; - evsel->core.attr.config = PERF_COUNT_SW_CPU_CLOCK; + evsel->core.attr.config = target__has_cpu(target) + ? PERF_COUNT_SW_CPU_CLOCK + : PERF_COUNT_SW_TASK_CLOCK; + scnprintf(msg, msgsize, + "The cycles event is not supported, trying to fall back to %s", + target__has_cpu(target) ? "cpu-clock" : "task-clock"); zfree(&evsel->name); return true; diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index d791316a17..efbb6e8482 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -191,6 +191,7 @@ struct perf_missing_features { bool code_page_size; bool weight_struct; bool read_lost; + bool branch_counters; }; extern struct perf_missing_features perf_missing_features; @@ -459,7 +460,8 @@ static inline bool evsel__is_clock(const struct evsel *evsel) evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK); } -bool evsel__fallback(struct evsel *evsel, int err, char *msg, size_t msgsize); +bool evsel__fallback(struct evsel *evsel, struct target *target, int err, + char *msg, size_t msgsize); int evsel__open_strerror(struct evsel *evsel, struct target *target, int err, char *msg, size_t size); diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 8b274ccab7..3fe28edc3d 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -2147,6 +2147,14 @@ static void print_pmu_caps(struct feat_fd *ff, FILE *fp) __print_pmu_caps(fp, pmu_caps->nr_caps, pmu_caps->caps, pmu_caps->pmu_name); } + + if (strcmp(perf_env__arch(&ff->ph->env), "x86") == 0 && + perf_env__has_pmu_mapping(&ff->ph->env, "ibs_op")) { + char *max_precise = perf_env__find_pmu_cap(&ff->ph->env, "cpu", "max_precise"); + + if (max_precise != NULL && atoi(max_precise) == 0) + fprintf(fp, "# AMD systems uses ibs_op// PMU for some precise events, e.g.: cycles:p, see the 'perf list' man page for further details.\n"); + } } static void print_pmu_mappings(struct feat_fd *ff, FILE *fp) @@ -3261,7 +3269,9 @@ static int process_compressed(struct feat_fd *ff, } static int __process_pmu_caps(struct feat_fd *ff, int *nr_caps, - char ***caps, unsigned int *max_branches) + char ***caps, unsigned int *max_branches, + unsigned int *br_cntr_nr, + unsigned int *br_cntr_width) { char *name, *value, *ptr; u32 nr_pmu_caps, i; @@ -3296,6 +3306,12 @@ static int __process_pmu_caps(struct feat_fd *ff, int *nr_caps, if (!strcmp(name, "branches")) *max_branches = atoi(value); + if (!strcmp(name, "branch_counter_nr")) + *br_cntr_nr = atoi(value); + + if (!strcmp(name, "branch_counter_width")) + *br_cntr_width = atoi(value); + free(value); free(name); } @@ -3320,7 +3336,9 @@ static int process_cpu_pmu_caps(struct feat_fd *ff, { int ret = __process_pmu_caps(ff, &ff->ph->env.nr_cpu_pmu_caps, &ff->ph->env.cpu_pmu_caps, - &ff->ph->env.max_branches); + &ff->ph->env.max_branches, + &ff->ph->env.br_cntr_nr, + &ff->ph->env.br_cntr_width); if (!ret && !ff->ph->env.cpu_pmu_caps) pr_debug("cpu pmu capabilities not available\n"); @@ -3349,7 +3367,9 @@ static int process_pmu_caps(struct feat_fd *ff, void *data __maybe_unused) for (i = 0; i < nr_pmu; i++) { ret = __process_pmu_caps(ff, &pmu_caps[i].nr_caps, &pmu_caps[i].caps, - &pmu_caps[i].max_branches); + &pmu_caps[i].max_branches, + &pmu_caps[i].br_cntr_nr, + &pmu_caps[i].br_cntr_width); if (ret) goto err; diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 0888b7163b..fa359180eb 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -491,8 +491,8 @@ static int hist_entry__init(struct hist_entry *he, } if (symbol_conf.res_sample) { - he->res_samples = calloc(sizeof(struct res_sample), - symbol_conf.res_sample); + he->res_samples = calloc(symbol_conf.res_sample, + sizeof(struct res_sample)); if (!he->res_samples) goto err_srcline; } diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index afc9f1c7f4..4a0aea0c9e 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -82,6 +82,9 @@ enum hist_column { HISTC_ADDR_TO, HISTC_ADDR, HISTC_SIMD, + HISTC_TYPE, + HISTC_TYPE_OFFSET, + HISTC_SYMBOL_OFFSET, HISTC_NR_COLS, /* Last entry */ }; @@ -457,7 +460,6 @@ struct hist_browser_timer { int refresh; }; -struct annotation_options; struct res_sample; enum rstype { @@ -473,16 +475,13 @@ struct block_hist; void attr_to_script(char *buf, struct perf_event_attr *attr); int map_symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, - struct hist_browser_timer *hbt, - struct annotation_options *annotation_opts); + struct hist_browser_timer *hbt); int hist_entry__tui_annotate(struct hist_entry *he, struct evsel *evsel, - struct hist_browser_timer *hbt, - struct annotation_options *annotation_opts); + struct hist_browser_timer *hbt); int evlist__tui_browse_hists(struct evlist *evlist, const char *help, struct hist_browser_timer *hbt, - float min_pcnt, struct perf_env *env, bool warn_lost_event, - struct annotation_options *annotation_options); + float min_pcnt, struct perf_env *env, bool warn_lost_event); int script_browse(const char *script_opt, struct evsel *evsel); @@ -492,8 +491,7 @@ int res_sample_browse(struct res_sample *res_samples, int num_res, void res_sample_init(void); int block_hists_tui_browse(struct block_hist *bh, struct evsel *evsel, - float min_percent, struct perf_env *env, - struct annotation_options *annotation_opts); + float min_percent, struct perf_env *env); #else static inline int evlist__tui_browse_hists(struct evlist *evlist __maybe_unused, @@ -501,23 +499,20 @@ int evlist__tui_browse_hists(struct evlist *evlist __maybe_unused, struct hist_browser_timer *hbt __maybe_unused, float min_pcnt __maybe_unused, struct perf_env *env __maybe_unused, - bool warn_lost_event __maybe_unused, - struct annotation_options *annotation_options __maybe_unused) + bool warn_lost_event __maybe_unused) { return 0; } static inline int map_symbol__tui_annotate(struct map_symbol *ms __maybe_unused, struct evsel *evsel __maybe_unused, - struct hist_browser_timer *hbt __maybe_unused, - struct annotation_options *annotation_options __maybe_unused) + struct hist_browser_timer *hbt __maybe_unused) { return 0; } static inline int hist_entry__tui_annotate(struct hist_entry *he __maybe_unused, struct evsel *evsel __maybe_unused, - struct hist_browser_timer *hbt __maybe_unused, - struct annotation_options *annotation_opts __maybe_unused) + struct hist_browser_timer *hbt __maybe_unused) { return 0; } @@ -541,8 +536,7 @@ static inline void res_sample_init(void) {} static inline int block_hists_tui_browse(struct block_hist *bh __maybe_unused, struct evsel *evsel __maybe_unused, float min_percent __maybe_unused, - struct perf_env *env __maybe_unused, - struct annotation_options *annotation_opts __maybe_unused) + struct perf_env *env __maybe_unused) { return 0; } diff --git a/tools/perf/util/include/dwarf-regs.h b/tools/perf/util/include/dwarf-regs.h index 7d99a084e8..01fb25a115 100644 --- a/tools/perf/util/include/dwarf-regs.h +++ b/tools/perf/util/include/dwarf-regs.h @@ -2,6 +2,9 @@ #ifndef _PERF_DWARF_REGS_H_ #define _PERF_DWARF_REGS_H_ +#define DWARF_REG_PC 0xd3af9c /* random number */ +#define DWARF_REG_FB 0xd3affb /* random number */ + #ifdef HAVE_DWARF_SUPPORT const char *get_arch_regstr(unsigned int n); /* @@ -10,6 +13,22 @@ const char *get_arch_regstr(unsigned int n); * machine: ELF machine signature (EM_*) */ const char *get_dwarf_regstr(unsigned int n, unsigned int machine); + +int get_arch_regnum(const char *name); +/* + * get_dwarf_regnum - Returns DWARF regnum from register name + * name: architecture register name + * machine: ELF machine signature (EM_*) + */ +int get_dwarf_regnum(const char *name, unsigned int machine); + +#else /* HAVE_DWARF_SUPPORT */ + +static inline int get_dwarf_regnum(const char *name __maybe_unused, + unsigned int machine __maybe_unused) +{ + return -1; +} #endif #ifdef HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET diff --git a/tools/perf/util/include/linux/linkage.h b/tools/perf/util/include/linux/linkage.h index 75e2248416..178b00205f 100644 --- a/tools/perf/util/include/linux/linkage.h +++ b/tools/perf/util/include/linux/linkage.h @@ -115,6 +115,10 @@ SYM_ALIAS(alias, name, SYM_T_FUNC, SYM_L_WEAK) #endif +#ifndef SYM_FUNC_ALIAS_MEMFUNC +#define SYM_FUNC_ALIAS_MEMFUNC SYM_FUNC_ALIAS +#endif + // In the kernel sources (include/linux/cfi_types.h), this has a different // definition when CONFIG_CFI_CLANG is used, for tools/ just use the !clang // definition: diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 90c750150b..b397a76900 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -453,7 +453,7 @@ static struct thread *findnew_guest_code(struct machine *machine, * Guest code can be found in hypervisor process at the same address * so copy host maps. */ - err = maps__clone(thread, thread__maps(host_thread)); + err = maps__copy_from(thread__maps(thread), thread__maps(host_thread)); thread__put(host_thread); if (err) goto out_err; @@ -1285,33 +1285,46 @@ static u64 find_entry_trampoline(struct dso *dso) #define X86_64_CPU_ENTRY_AREA_SIZE 0x2c000 #define X86_64_ENTRY_TRAMPOLINE 0x6000 +struct machine__map_x86_64_entry_trampolines_args { + struct maps *kmaps; + bool found; +}; + +static int machine__map_x86_64_entry_trampolines_cb(struct map *map, void *data) +{ + struct machine__map_x86_64_entry_trampolines_args *args = data; + struct map *dest_map; + struct kmap *kmap = __map__kmap(map); + + if (!kmap || !is_entry_trampoline(kmap->name)) + return 0; + + dest_map = maps__find(args->kmaps, map__pgoff(map)); + if (dest_map != map) + map__set_pgoff(map, map__map_ip(dest_map, map__pgoff(map))); + + args->found = true; + return 0; +} + /* Map x86_64 PTI entry trampolines */ int machine__map_x86_64_entry_trampolines(struct machine *machine, struct dso *kernel) { - struct maps *kmaps = machine__kernel_maps(machine); + struct machine__map_x86_64_entry_trampolines_args args = { + .kmaps = machine__kernel_maps(machine), + .found = false, + }; int nr_cpus_avail, cpu; - bool found = false; - struct map_rb_node *rb_node; u64 pgoff; /* * In the vmlinux case, pgoff is a virtual address which must now be * mapped to a vmlinux offset. */ - maps__for_each_entry(kmaps, rb_node) { - struct map *dest_map, *map = rb_node->map; - struct kmap *kmap = __map__kmap(map); - - if (!kmap || !is_entry_trampoline(kmap->name)) - continue; + maps__for_each_map(args.kmaps, machine__map_x86_64_entry_trampolines_cb, &args); - dest_map = maps__find(kmaps, map__pgoff(map)); - if (dest_map != map) - map__set_pgoff(map, map__map_ip(dest_map, map__pgoff(map))); - found = true; - } - if (found || machine->trampolines_mapped) + if (args.found || machine->trampolines_mapped) return 0; pgoff = find_entry_trampoline(kernel); @@ -1359,8 +1372,7 @@ __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) if (machine->vmlinux_map == NULL) return -ENOMEM; - map__set_map_ip(machine->vmlinux_map, identity__map_ip); - map__set_unmap_ip(machine->vmlinux_map, identity__map_ip); + map__set_mapping_type(machine->vmlinux_map, MAPPING_TYPE__IDENTITY); return maps__insert(machine__kernel_maps(machine), machine->vmlinux_map); } @@ -1750,12 +1762,11 @@ int machine__create_kernel_maps(struct machine *machine) if (end == ~0ULL) { /* update end address of the kernel map using adjacent module address */ - struct map_rb_node *rb_node = maps__find_node(machine__kernel_maps(machine), - machine__kernel_map(machine)); - struct map_rb_node *next = map_rb_node__next(rb_node); + struct map *next = maps__find_next_entry(machine__kernel_maps(machine), + machine__kernel_map(machine)); if (next) - machine__set_kernel_mmap(machine, start, map__start(next->map)); + machine__set_kernel_mmap(machine, start, map__start(next)); } out_put: @@ -2157,9 +2168,13 @@ int machine__process_exit_event(struct machine *machine, union perf_event *event if (dump_trace) perf_event__fprintf_task(event, stdout); - if (thread != NULL) - thread__put(thread); - + if (thread != NULL) { + if (symbol_conf.keep_exited_threads) + thread__set_exited(thread, /*exited=*/true); + else + machine__remove_thread(machine, thread); + } + thread__put(thread); return 0; } @@ -3395,16 +3410,8 @@ int machine__for_each_dso(struct machine *machine, machine__dso_t fn, void *priv int machine__for_each_kernel_map(struct machine *machine, machine__map_t fn, void *priv) { struct maps *maps = machine__kernel_maps(machine); - struct map_rb_node *pos; - int err = 0; - maps__for_each_entry(maps, pos) { - err = fn(pos->map, priv); - if (err != 0) { - break; - } - } - return err; + return maps__for_each_map(maps, fn, priv); } bool machine__is_lock_function(struct machine *machine, u64 addr) diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index f64b830044..54c67cb7ec 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -109,8 +109,7 @@ void map__init(struct map *map, u64 start, u64 end, u64 pgoff, struct dso *dso) map__set_pgoff(map, pgoff); map__set_reloc(map, 0); map__set_dso(map, dso__get(dso)); - map__set_map_ip(map, map__dso_map_ip); - map__set_unmap_ip(map, map__dso_unmap_ip); + map__set_mapping_type(map, MAPPING_TYPE__DSO); map__set_erange_warned(map, false); refcount_set(map__refcnt(map), 1); } @@ -172,7 +171,7 @@ struct map *map__new(struct machine *machine, u64 start, u64 len, map__init(result, start, start + len, pgoff, dso); if (anon || no_dso) { - map->map_ip = map->unmap_ip = identity__map_ip; + map->mapping_type = MAPPING_TYPE__IDENTITY; /* * Set memory without DSO as loaded. All map__find_* @@ -630,18 +629,3 @@ struct maps *map__kmaps(struct map *map) } return kmap->kmaps; } - -u64 map__dso_map_ip(const struct map *map, u64 ip) -{ - return ip - map__start(map) + map__pgoff(map); -} - -u64 map__dso_unmap_ip(const struct map *map, u64 ip) -{ - return ip + map__start(map) - map__pgoff(map); -} - -u64 identity__map_ip(const struct map *map __maybe_unused, u64 ip) -{ - return ip; -} diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 1b53d53adc..49756716cb 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -16,23 +16,25 @@ struct dso; struct maps; struct machine; +enum mapping_type { + /* map__map_ip/map__unmap_ip are given as offsets in the DSO. */ + MAPPING_TYPE__DSO, + /* map__map_ip/map__unmap_ip are just the given ip value. */ + MAPPING_TYPE__IDENTITY, +}; + DECLARE_RC_STRUCT(map) { u64 start; u64 end; - bool erange_warned:1; - bool priv:1; - u32 prot; u64 pgoff; u64 reloc; - - /* ip -> dso rip */ - u64 (*map_ip)(const struct map *, u64); - /* dso rip -> ip */ - u64 (*unmap_ip)(const struct map *, u64); - struct dso *dso; refcount_t refcnt; + u32 prot; u32 flags; + enum mapping_type mapping_type:8; + bool erange_warned; + bool priv; }; struct kmap; @@ -41,38 +43,11 @@ struct kmap *__map__kmap(struct map *map); struct kmap *map__kmap(struct map *map); struct maps *map__kmaps(struct map *map); -/* ip -> dso rip */ -u64 map__dso_map_ip(const struct map *map, u64 ip); -/* dso rip -> ip */ -u64 map__dso_unmap_ip(const struct map *map, u64 ip); -/* Returns ip */ -u64 identity__map_ip(const struct map *map __maybe_unused, u64 ip); - static inline struct dso *map__dso(const struct map *map) { return RC_CHK_ACCESS(map)->dso; } -static inline u64 map__map_ip(const struct map *map, u64 ip) -{ - return RC_CHK_ACCESS(map)->map_ip(map, ip); -} - -static inline u64 map__unmap_ip(const struct map *map, u64 ip) -{ - return RC_CHK_ACCESS(map)->unmap_ip(map, ip); -} - -static inline void *map__map_ip_ptr(struct map *map) -{ - return RC_CHK_ACCESS(map)->map_ip; -} - -static inline void* map__unmap_ip_ptr(struct map *map) -{ - return RC_CHK_ACCESS(map)->unmap_ip; -} - static inline u64 map__start(const struct map *map) { return RC_CHK_ACCESS(map)->start; @@ -123,6 +98,34 @@ static inline size_t map__size(const struct map *map) return map__end(map) - map__start(map); } +/* ip -> dso rip */ +static inline u64 map__dso_map_ip(const struct map *map, u64 ip) +{ + return ip - map__start(map) + map__pgoff(map); +} + +/* dso rip -> ip */ +static inline u64 map__dso_unmap_ip(const struct map *map, u64 rip) +{ + return rip + map__start(map) - map__pgoff(map); +} + +static inline u64 map__map_ip(const struct map *map, u64 ip_or_rip) +{ + if ((RC_CHK_ACCESS(map)->mapping_type) == MAPPING_TYPE__DSO) + return map__dso_map_ip(map, ip_or_rip); + else + return ip_or_rip; +} + +static inline u64 map__unmap_ip(const struct map *map, u64 ip_or_rip) +{ + if ((RC_CHK_ACCESS(map)->mapping_type) == MAPPING_TYPE__DSO) + return map__dso_unmap_ip(map, ip_or_rip); + else + return ip_or_rip; +} + /* rip/ip <-> addr suitable for passing to `objdump --start-address=` */ u64 map__rip_2objdump(struct map *map, u64 rip); @@ -294,13 +297,13 @@ static inline void map__set_dso(struct map *map, struct dso *dso) RC_CHK_ACCESS(map)->dso = dso; } -static inline void map__set_map_ip(struct map *map, u64 (*map_ip)(const struct map *map, u64 ip)) +static inline void map__set_mapping_type(struct map *map, enum mapping_type type) { - RC_CHK_ACCESS(map)->map_ip = map_ip; + RC_CHK_ACCESS(map)->mapping_type = type; } -static inline void map__set_unmap_ip(struct map *map, u64 (*unmap_ip)(const struct map *map, u64 rip)) +static inline enum mapping_type map__mapping_type(struct map *map) { - RC_CHK_ACCESS(map)->unmap_ip = unmap_ip; + return RC_CHK_ACCESS(map)->mapping_type; } #endif /* __PERF_MAP_H */ diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c index 233438c95b..0334fc18d9 100644 --- a/tools/perf/util/maps.c +++ b/tools/perf/util/maps.c @@ -10,6 +10,68 @@ #include "ui/ui.h" #include "unwind.h" +struct map_rb_node { + struct rb_node rb_node; + struct map *map; +}; + +#define maps__for_each_entry(maps, map) \ + for (map = maps__first(maps); map; map = map_rb_node__next(map)) + +#define maps__for_each_entry_safe(maps, map, next) \ + for (map = maps__first(maps), next = map_rb_node__next(map); map; \ + map = next, next = map_rb_node__next(map)) + +static struct rb_root *maps__entries(struct maps *maps) +{ + return &RC_CHK_ACCESS(maps)->entries; +} + +static struct rw_semaphore *maps__lock(struct maps *maps) +{ + return &RC_CHK_ACCESS(maps)->lock; +} + +static struct map **maps__maps_by_name(struct maps *maps) +{ + return RC_CHK_ACCESS(maps)->maps_by_name; +} + +static struct map_rb_node *maps__first(struct maps *maps) +{ + struct rb_node *first = rb_first(maps__entries(maps)); + + if (first) + return rb_entry(first, struct map_rb_node, rb_node); + return NULL; +} + +static struct map_rb_node *map_rb_node__next(struct map_rb_node *node) +{ + struct rb_node *next; + + if (!node) + return NULL; + + next = rb_next(&node->rb_node); + + if (!next) + return NULL; + + return rb_entry(next, struct map_rb_node, rb_node); +} + +static struct map_rb_node *maps__find_node(struct maps *maps, struct map *map) +{ + struct map_rb_node *rb_node; + + maps__for_each_entry(maps, rb_node) { + if (rb_node->RC_CHK_ACCESS(map) == RC_CHK_ACCESS(map)) + return rb_node; + } + return NULL; +} + static void maps__init(struct maps *maps, struct machine *machine) { refcount_set(maps__refcnt(maps), 1); @@ -196,6 +258,41 @@ void maps__put(struct maps *maps) RC_CHK_PUT(maps); } +int maps__for_each_map(struct maps *maps, int (*cb)(struct map *map, void *data), void *data) +{ + struct map_rb_node *pos; + int ret = 0; + + down_read(maps__lock(maps)); + maps__for_each_entry(maps, pos) { + ret = cb(pos->map, data); + if (ret) + break; + } + up_read(maps__lock(maps)); + return ret; +} + +void maps__remove_maps(struct maps *maps, bool (*cb)(struct map *map, void *data), void *data) +{ + struct map_rb_node *pos, *next; + unsigned int start_nr_maps; + + down_write(maps__lock(maps)); + + start_nr_maps = maps__nr_maps(maps); + maps__for_each_entry_safe(maps, pos, next) { + if (cb(pos->map, data)) { + __maps__remove(maps, pos); + --RC_CHK_ACCESS(maps)->nr_maps; + } + } + if (maps__maps_by_name(maps) && start_nr_maps != maps__nr_maps(maps)) + __maps__free_maps_by_name(maps); + + up_write(maps__lock(maps)); +} + struct symbol *maps__find_symbol(struct maps *maps, u64 addr, struct map **mapp) { struct map *map = maps__find(maps, addr); @@ -210,31 +307,40 @@ struct symbol *maps__find_symbol(struct maps *maps, u64 addr, struct map **mapp) return NULL; } -struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name, struct map **mapp) -{ +struct maps__find_symbol_by_name_args { + struct map **mapp; + const char *name; struct symbol *sym; - struct map_rb_node *pos; +}; - down_read(maps__lock(maps)); +static int maps__find_symbol_by_name_cb(struct map *map, void *data) +{ + struct maps__find_symbol_by_name_args *args = data; - maps__for_each_entry(maps, pos) { - sym = map__find_symbol_by_name(pos->map, name); + args->sym = map__find_symbol_by_name(map, args->name); + if (!args->sym) + return 0; - if (sym == NULL) - continue; - if (!map__contains_symbol(pos->map, sym)) { - sym = NULL; - continue; - } - if (mapp != NULL) - *mapp = pos->map; - goto out; + if (!map__contains_symbol(map, args->sym)) { + args->sym = NULL; + return 0; } - sym = NULL; -out: - up_read(maps__lock(maps)); - return sym; + if (args->mapp != NULL) + *args->mapp = map__get(map); + return 1; +} + +struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name, struct map **mapp) +{ + struct maps__find_symbol_by_name_args args = { + .mapp = mapp, + .name = name, + .sym = NULL, + }; + + maps__for_each_map(maps, maps__find_symbol_by_name_cb, &args); + return args.sym; } int maps__find_ams(struct maps *maps, struct addr_map_symbol *ams) @@ -253,41 +359,46 @@ int maps__find_ams(struct maps *maps, struct addr_map_symbol *ams) return ams->ms.sym ? 0 : -1; } -size_t maps__fprintf(struct maps *maps, FILE *fp) -{ - size_t printed = 0; - struct map_rb_node *pos; +struct maps__fprintf_args { + FILE *fp; + size_t printed; +}; - down_read(maps__lock(maps)); +static int maps__fprintf_cb(struct map *map, void *data) +{ + struct maps__fprintf_args *args = data; - maps__for_each_entry(maps, pos) { - printed += fprintf(fp, "Map:"); - printed += map__fprintf(pos->map, fp); - if (verbose > 2) { - printed += dso__fprintf(map__dso(pos->map), fp); - printed += fprintf(fp, "--\n"); - } + args->printed += fprintf(args->fp, "Map:"); + args->printed += map__fprintf(map, args->fp); + if (verbose > 2) { + args->printed += dso__fprintf(map__dso(map), args->fp); + args->printed += fprintf(args->fp, "--\n"); } + return 0; +} - up_read(maps__lock(maps)); +size_t maps__fprintf(struct maps *maps, FILE *fp) +{ + struct maps__fprintf_args args = { + .fp = fp, + .printed = 0, + }; + + maps__for_each_map(maps, maps__fprintf_cb, &args); - return printed; + return args.printed; } -int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) +/* + * Find first map where end > map->start. + * Same as find_vma() in kernel. + */ +static struct rb_node *first_ending_after(struct maps *maps, const struct map *map) { struct rb_root *root; struct rb_node *next, *first; - int err = 0; - - down_write(maps__lock(maps)); root = maps__entries(maps); - - /* - * Find first map where end > map->start. - * Same as find_vma() in kernel. - */ next = root->rb_node; first = NULL; while (next) { @@ -301,8 +412,23 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) } else next = next->rb_right; } + return first; +} - next = first; +/* + * Adds new to maps, if new overlaps existing entries then the existing maps are + * adjusted or removed so that new fits without overlapping any entries. + */ +int maps__fixup_overlap_and_insert(struct maps *maps, struct map *new) +{ + + struct rb_node *next; + int err = 0; + FILE *fp = debug_file(); + + down_write(maps__lock(maps)); + + next = first_ending_after(maps, new); while (next && !err) { struct map_rb_node *pos = rb_entry(next, struct map_rb_node, rb_node); next = rb_next(&pos->rb_node); @@ -311,27 +437,27 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) * Stop if current map starts after map->end. * Maps are ordered by start: next will not overlap for sure. */ - if (map__start(pos->map) >= map__end(map)) + if (map__start(pos->map) >= map__end(new)) break; if (verbose >= 2) { if (use_browser) { pr_debug("overlapping maps in %s (disable tui for more info)\n", - map__dso(map)->name); + map__dso(new)->name); } else { - fputs("overlapping maps:\n", fp); - map__fprintf(map, fp); + pr_debug("overlapping maps:\n"); + map__fprintf(new, fp); map__fprintf(pos->map, fp); } } - rb_erase_init(&pos->rb_node, root); + rb_erase_init(&pos->rb_node, maps__entries(maps)); /* * Now check if we need to create new maps for areas not * overlapped by the new map: */ - if (map__start(map) > map__start(pos->map)) { + if (map__start(new) > map__start(pos->map)) { struct map *before = map__clone(pos->map); if (before == NULL) { @@ -339,7 +465,7 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) goto put_map; } - map__set_end(before, map__start(map)); + map__set_end(before, map__start(new)); err = __maps__insert(maps, before); if (err) { map__put(before); @@ -351,7 +477,7 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) map__put(before); } - if (map__end(map) < map__end(pos->map)) { + if (map__end(new) < map__end(pos->map)) { struct map *after = map__clone(pos->map); if (after == NULL) { @@ -359,10 +485,10 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) goto put_map; } - map__set_start(after, map__end(map)); - map__add_pgoff(after, map__end(map) - map__start(pos->map)); - assert(map__map_ip(pos->map, map__end(map)) == - map__map_ip(after, map__end(map))); + map__set_start(after, map__end(new)); + map__add_pgoff(after, map__end(new) - map__start(pos->map)); + assert(map__map_ip(pos->map, map__end(new)) == + map__map_ip(after, map__end(new))); err = __maps__insert(maps, after); if (err) { map__put(after); @@ -376,16 +502,14 @@ put_map: map__put(pos->map); free(pos); } + /* Add the map. */ + err = __maps__insert(maps, new); up_write(maps__lock(maps)); return err; } -/* - * XXX This should not really _copy_ te maps, but refcount them. - */ -int maps__clone(struct thread *thread, struct maps *parent) +int maps__copy_from(struct maps *maps, struct maps *parent) { - struct maps *maps = thread__maps(thread); int err; struct map_rb_node *rb_node; @@ -416,17 +540,6 @@ out_unlock: return err; } -struct map_rb_node *maps__find_node(struct maps *maps, struct map *map) -{ - struct map_rb_node *rb_node; - - maps__for_each_entry(maps, rb_node) { - if (rb_node->RC_CHK_ACCESS(map) == RC_CHK_ACCESS(map)) - return rb_node; - } - return NULL; -} - struct map *maps__find(struct maps *maps, u64 ip) { struct rb_node *p; @@ -452,26 +565,275 @@ out: return m ? m->map : NULL; } -struct map_rb_node *maps__first(struct maps *maps) +static int map__strcmp(const void *a, const void *b) { - struct rb_node *first = rb_first(maps__entries(maps)); + const struct map *map_a = *(const struct map **)a; + const struct map *map_b = *(const struct map **)b; + const struct dso *dso_a = map__dso(map_a); + const struct dso *dso_b = map__dso(map_b); + int ret = strcmp(dso_a->short_name, dso_b->short_name); - if (first) - return rb_entry(first, struct map_rb_node, rb_node); - return NULL; + if (ret == 0 && map_a != map_b) { + /* + * Ensure distinct but name equal maps have an order in part to + * aid reference counting. + */ + ret = (int)map__start(map_a) - (int)map__start(map_b); + if (ret == 0) + ret = (int)((intptr_t)map_a - (intptr_t)map_b); + } + + return ret; } -struct map_rb_node *map_rb_node__next(struct map_rb_node *node) +static int map__strcmp_name(const void *name, const void *b) { - struct rb_node *next; + const struct dso *dso = map__dso(*(const struct map **)b); - if (!node) - return NULL; + return strcmp(name, dso->short_name); +} - next = rb_next(&node->rb_node); +void __maps__sort_by_name(struct maps *maps) +{ + qsort(maps__maps_by_name(maps), maps__nr_maps(maps), sizeof(struct map *), map__strcmp); +} - if (!next) +static int map__groups__sort_by_name_from_rbtree(struct maps *maps) +{ + struct map_rb_node *rb_node; + struct map **maps_by_name = realloc(maps__maps_by_name(maps), + maps__nr_maps(maps) * sizeof(struct map *)); + int i = 0; + + if (maps_by_name == NULL) + return -1; + + up_read(maps__lock(maps)); + down_write(maps__lock(maps)); + + RC_CHK_ACCESS(maps)->maps_by_name = maps_by_name; + RC_CHK_ACCESS(maps)->nr_maps_allocated = maps__nr_maps(maps); + + maps__for_each_entry(maps, rb_node) + maps_by_name[i++] = map__get(rb_node->map); + + __maps__sort_by_name(maps); + + up_write(maps__lock(maps)); + down_read(maps__lock(maps)); + + return 0; +} + +static struct map *__maps__find_by_name(struct maps *maps, const char *name) +{ + struct map **mapp; + + if (maps__maps_by_name(maps) == NULL && + map__groups__sort_by_name_from_rbtree(maps)) return NULL; - return rb_entry(next, struct map_rb_node, rb_node); + mapp = bsearch(name, maps__maps_by_name(maps), maps__nr_maps(maps), + sizeof(*mapp), map__strcmp_name); + if (mapp) + return *mapp; + return NULL; +} + +struct map *maps__find_by_name(struct maps *maps, const char *name) +{ + struct map_rb_node *rb_node; + struct map *map; + + down_read(maps__lock(maps)); + + + if (RC_CHK_ACCESS(maps)->last_search_by_name) { + const struct dso *dso = map__dso(RC_CHK_ACCESS(maps)->last_search_by_name); + + if (strcmp(dso->short_name, name) == 0) { + map = RC_CHK_ACCESS(maps)->last_search_by_name; + goto out_unlock; + } + } + /* + * If we have maps->maps_by_name, then the name isn't in the rbtree, + * as maps->maps_by_name mirrors the rbtree when lookups by name are + * made. + */ + map = __maps__find_by_name(maps, name); + if (map || maps__maps_by_name(maps) != NULL) + goto out_unlock; + + /* Fallback to traversing the rbtree... */ + maps__for_each_entry(maps, rb_node) { + struct dso *dso; + + map = rb_node->map; + dso = map__dso(map); + if (strcmp(dso->short_name, name) == 0) { + RC_CHK_ACCESS(maps)->last_search_by_name = map; + goto out_unlock; + } + } + map = NULL; + +out_unlock: + up_read(maps__lock(maps)); + return map; +} + +struct map *maps__find_next_entry(struct maps *maps, struct map *map) +{ + struct map_rb_node *rb_node = maps__find_node(maps, map); + struct map_rb_node *next = map_rb_node__next(rb_node); + + if (next) + return next->map; + + return NULL; +} + +void maps__fixup_end(struct maps *maps) +{ + struct map_rb_node *prev = NULL, *curr; + + down_write(maps__lock(maps)); + + maps__for_each_entry(maps, curr) { + if (prev && (!map__end(prev->map) || map__end(prev->map) > map__start(curr->map))) + map__set_end(prev->map, map__start(curr->map)); + + prev = curr; + } + + /* + * We still haven't the actual symbols, so guess the + * last map final address. + */ + if (curr && !map__end(curr->map)) + map__set_end(curr->map, ~0ULL); + + up_write(maps__lock(maps)); +} + +/* + * Merges map into maps by splitting the new map within the existing map + * regions. + */ +int maps__merge_in(struct maps *kmaps, struct map *new_map) +{ + struct map_rb_node *rb_node; + struct rb_node *first; + bool overlaps; + LIST_HEAD(merged); + int err = 0; + + down_read(maps__lock(kmaps)); + first = first_ending_after(kmaps, new_map); + rb_node = first ? rb_entry(first, struct map_rb_node, rb_node) : NULL; + overlaps = rb_node && map__start(rb_node->map) < map__end(new_map); + up_read(maps__lock(kmaps)); + + if (!overlaps) + return maps__insert(kmaps, new_map); + + maps__for_each_entry(kmaps, rb_node) { + struct map *old_map = rb_node->map; + + /* no overload with this one */ + if (map__end(new_map) < map__start(old_map) || + map__start(new_map) >= map__end(old_map)) + continue; + + if (map__start(new_map) < map__start(old_map)) { + /* + * |new...... + * |old.... + */ + if (map__end(new_map) < map__end(old_map)) { + /* + * |new......| -> |new..| + * |old....| -> |old....| + */ + map__set_end(new_map, map__start(old_map)); + } else { + /* + * |new.............| -> |new..| |new..| + * |old....| -> |old....| + */ + struct map_list_node *m = map_list_node__new(); + + if (!m) { + err = -ENOMEM; + goto out; + } + + m->map = map__clone(new_map); + if (!m->map) { + free(m); + err = -ENOMEM; + goto out; + } + + map__set_end(m->map, map__start(old_map)); + list_add_tail(&m->node, &merged); + map__add_pgoff(new_map, map__end(old_map) - map__start(new_map)); + map__set_start(new_map, map__end(old_map)); + } + } else { + /* + * |new...... + * |old.... + */ + if (map__end(new_map) < map__end(old_map)) { + /* + * |new..| -> x + * |old.........| -> |old.........| + */ + map__put(new_map); + new_map = NULL; + break; + } else { + /* + * |new......| -> |new...| + * |old....| -> |old....| + */ + map__add_pgoff(new_map, map__end(old_map) - map__start(new_map)); + map__set_start(new_map, map__end(old_map)); + } + } + } + +out: + while (!list_empty(&merged)) { + struct map_list_node *old_node; + + old_node = list_entry(merged.next, struct map_list_node, node); + list_del_init(&old_node->node); + if (!err) + err = maps__insert(kmaps, old_node->map); + map__put(old_node->map); + free(old_node); + } + + if (new_map) { + if (!err) + err = maps__insert(kmaps, new_map); + map__put(new_map); + } + return err; +} + +void maps__load_first(struct maps *maps) +{ + struct map_rb_node *first; + + down_read(maps__lock(maps)); + + first = maps__first(maps); + if (first) + map__load(first->map); + + up_read(maps__lock(maps)); } diff --git a/tools/perf/util/maps.h b/tools/perf/util/maps.h index 83144e0645..d836d04c94 100644 --- a/tools/perf/util/maps.h +++ b/tools/perf/util/maps.h @@ -14,24 +14,18 @@ struct ref_reloc_sym; struct machine; struct map; struct maps; -struct thread; -struct map_rb_node { - struct rb_node rb_node; +struct map_list_node { + struct list_head node; struct map *map; }; -struct map_rb_node *maps__first(struct maps *maps); -struct map_rb_node *map_rb_node__next(struct map_rb_node *node); -struct map_rb_node *maps__find_node(struct maps *maps, struct map *map); -struct map *maps__find(struct maps *maps, u64 addr); - -#define maps__for_each_entry(maps, map) \ - for (map = maps__first(maps); map; map = map_rb_node__next(map)) +static inline struct map_list_node *map_list_node__new(void) +{ + return malloc(sizeof(struct map_list_node)); +} -#define maps__for_each_entry_safe(maps, map, next) \ - for (map = maps__first(maps), next = map_rb_node__next(map); map; \ - map = next, next = map_rb_node__next(map)) +struct map *maps__find(struct maps *maps, u64 addr); DECLARE_RC_STRUCT(maps) { struct rb_root entries; @@ -58,7 +52,7 @@ struct kmap { struct maps *maps__new(struct machine *machine); bool maps__empty(struct maps *maps); -int maps__clone(struct thread *thread, struct maps *parent); +int maps__copy_from(struct maps *maps, struct maps *parent); struct maps *maps__get(struct maps *maps); void maps__put(struct maps *maps); @@ -71,26 +65,16 @@ static inline void __maps__zput(struct maps **map) #define maps__zput(map) __maps__zput(&map) -static inline struct rb_root *maps__entries(struct maps *maps) -{ - return &RC_CHK_ACCESS(maps)->entries; -} +/* Iterate over map calling cb for each entry. */ +int maps__for_each_map(struct maps *maps, int (*cb)(struct map *map, void *data), void *data); +/* Iterate over map removing an entry if cb returns true. */ +void maps__remove_maps(struct maps *maps, bool (*cb)(struct map *map, void *data), void *data); static inline struct machine *maps__machine(struct maps *maps) { return RC_CHK_ACCESS(maps)->machine; } -static inline struct rw_semaphore *maps__lock(struct maps *maps) -{ - return &RC_CHK_ACCESS(maps)->lock; -} - -static inline struct map **maps__maps_by_name(struct maps *maps) -{ - return RC_CHK_ACCESS(maps)->maps_by_name; -} - static inline unsigned int maps__nr_maps(const struct maps *maps) { return RC_CHK_ACCESS(maps)->nr_maps; @@ -125,12 +109,18 @@ struct addr_map_symbol; int maps__find_ams(struct maps *maps, struct addr_map_symbol *ams); -int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp); +int maps__fixup_overlap_and_insert(struct maps *maps, struct map *new); struct map *maps__find_by_name(struct maps *maps, const char *name); +struct map *maps__find_next_entry(struct maps *maps, struct map *map); + int maps__merge_in(struct maps *kmaps, struct map *new_map); void __maps__sort_by_name(struct maps *maps); +void maps__fixup_end(struct maps *maps); + +void maps__load_first(struct maps *maps); + #endif // __PERF_MAPS_H diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c index ca3e0404f1..966cca5a3e 100644 --- a/tools/perf/util/metricgroup.c +++ b/tools/perf/util/metricgroup.c @@ -286,7 +286,7 @@ static int setup_metric_events(const char *pmu, struct hashmap *ids, *out_metric_events = NULL; ids_size = hashmap__size(ids); - metric_events = calloc(sizeof(void *), ids_size + 1); + metric_events = calloc(ids_size + 1, sizeof(void *)); if (!metric_events) return -ENOMEM; diff --git a/tools/perf/util/mmap.c b/tools/perf/util/mmap.c index 49093b21ee..122ee198a8 100644 --- a/tools/perf/util/mmap.c +++ b/tools/perf/util/mmap.c @@ -295,15 +295,14 @@ int mmap__mmap(struct mmap *map, struct mmap_params *mp, int fd, struct perf_cpu map->core.flush = mp->flush; - map->comp_level = mp->comp_level; #ifndef PYTHON_PERF - if (zstd_init(&map->zstd_data, map->comp_level)) { + if (zstd_init(&map->zstd_data, mp->comp_level)) { pr_debug2("failed to init mmap compressor, error %d\n", errno); return -1; } #endif - if (map->comp_level && !perf_mmap__aio_enabled(map)) { + if (mp->comp_level && !perf_mmap__aio_enabled(map)) { map->data = mmap(NULL, mmap__mmap_len(map), PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); if (map->data == MAP_FAILED) { diff --git a/tools/perf/util/mmap.h b/tools/perf/util/mmap.h index f944c3cd5e..0df6e1621c 100644 --- a/tools/perf/util/mmap.h +++ b/tools/perf/util/mmap.h @@ -39,7 +39,6 @@ struct mmap { #endif struct mmap_cpu_mask affinity_mask; void *data; - int comp_level; struct perf_data_file *file; struct zstd_data zstd_data; }; diff --git a/tools/perf/util/parse-branch-options.c b/tools/perf/util/parse-branch-options.c index fd67d204d7..f7f7aff3d8 100644 --- a/tools/perf/util/parse-branch-options.c +++ b/tools/perf/util/parse-branch-options.c @@ -36,6 +36,7 @@ static const struct branch_mode branch_modes[] = { BRANCH_OPT("stack", PERF_SAMPLE_BRANCH_CALL_STACK), BRANCH_OPT("hw_index", PERF_SAMPLE_BRANCH_HW_INDEX), BRANCH_OPT("priv", PERF_SAMPLE_BRANCH_PRIV_SAVE), + BRANCH_OPT("counter", PERF_SAMPLE_BRANCH_COUNTERS), BRANCH_END }; diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index aa2f5c6fc7..66eabcea42 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -976,7 +976,7 @@ static int config_term_pmu(struct perf_event_attr *attr, struct parse_events_error *err) { if (term->type_term == PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE) { - const struct perf_pmu *pmu = perf_pmus__find_by_type(attr->type); + struct perf_pmu *pmu = perf_pmus__find_by_type(attr->type); if (!pmu) { char *err_str; @@ -986,15 +986,23 @@ static int config_term_pmu(struct perf_event_attr *attr, err_str, /*help=*/NULL); return -EINVAL; } - if (perf_pmu__supports_legacy_cache(pmu)) { + /* + * Rewrite the PMU event to a legacy cache one unless the PMU + * doesn't support legacy cache events or the event is present + * within the PMU. + */ + if (perf_pmu__supports_legacy_cache(pmu) && + !perf_pmu__have_event(pmu, term->config)) { attr->type = PERF_TYPE_HW_CACHE; return parse_events__decode_legacy_cache(term->config, pmu->type, &attr->config); - } else + } else { term->type_term = PARSE_EVENTS__TERM_TYPE_USER; + term->no_value = true; + } } if (term->type_term == PARSE_EVENTS__TERM_TYPE_HARDWARE) { - const struct perf_pmu *pmu = perf_pmus__find_by_type(attr->type); + struct perf_pmu *pmu = perf_pmus__find_by_type(attr->type); if (!pmu) { char *err_str; @@ -1004,10 +1012,19 @@ static int config_term_pmu(struct perf_event_attr *attr, err_str, /*help=*/NULL); return -EINVAL; } - attr->type = PERF_TYPE_HARDWARE; - attr->config = term->val.num; - if (perf_pmus__supports_extended_type()) - attr->config |= (__u64)pmu->type << PERF_PMU_TYPE_SHIFT; + /* + * If the PMU has a sysfs or json event prefer it over + * legacy. ARM requires this. + */ + if (perf_pmu__have_event(pmu, term->config)) { + term->type_term = PARSE_EVENTS__TERM_TYPE_USER; + term->no_value = true; + } else { + attr->type = PERF_TYPE_HARDWARE; + attr->config = term->val.num; + if (perf_pmus__supports_extended_type()) + attr->config |= (__u64)pmu->type << PERF_PMU_TYPE_SHIFT; + } return 0; } if (term->type_term == PARSE_EVENTS__TERM_TYPE_USER || @@ -1381,6 +1398,7 @@ int parse_events_add_pmu(struct parse_events_state *parse_state, YYLTYPE *loc = loc_; LIST_HEAD(config_terms); struct parse_events_terms parsed_terms; + bool alias_rewrote_terms = false; pmu = parse_state->fake_pmu ?: perf_pmus__find(name); @@ -1433,7 +1451,15 @@ int parse_events_add_pmu(struct parse_events_state *parse_state, return evsel ? 0 : -ENOMEM; } - if (!parse_state->fake_pmu && perf_pmu__check_alias(pmu, &parsed_terms, &info, err)) { + /* Configure attr/terms with a known PMU, this will set hardcoded terms. */ + if (config_attr(&attr, &parsed_terms, parse_state->error, config_term_pmu)) { + parse_events_terms__exit(&parsed_terms); + return -EINVAL; + } + + /* Look for event names in the terms and rewrite into format based terms. */ + if (!parse_state->fake_pmu && perf_pmu__check_alias(pmu, &parsed_terms, + &info, &alias_rewrote_terms, err)) { parse_events_terms__exit(&parsed_terms); return -EINVAL; } @@ -1447,11 +1473,9 @@ int parse_events_add_pmu(struct parse_events_state *parse_state, strbuf_release(&sb); } - /* - * Configure hardcoded terms first, no need to check - * return value when called with fail == 0 ;) - */ - if (config_attr(&attr, &parsed_terms, parse_state->error, config_term_pmu)) { + /* Configure attr/terms again if an alias was expanded. */ + if (alias_rewrote_terms && + config_attr(&attr, &parsed_terms, parse_state->error, config_term_pmu)) { parse_events_terms__exit(&parsed_terms); return -EINVAL; } diff --git a/tools/perf/util/perf_api_probe.c b/tools/perf/util/perf_api_probe.c index e1e2d70159..1de3b69cdf 100644 --- a/tools/perf/util/perf_api_probe.c +++ b/tools/perf/util/perf_api_probe.c @@ -64,7 +64,7 @@ static bool perf_probe_api(setup_probe_fn_t fn) struct perf_cpu cpu; int ret, i = 0; - cpus = perf_cpu_map__new(NULL); + cpus = perf_cpu_map__new_online_cpus(); if (!cpus) return false; cpu = perf_cpu_map__cpu(cpus, 0); @@ -140,7 +140,7 @@ bool perf_can_record_cpu_wide(void) struct perf_cpu cpu; int fd; - cpus = perf_cpu_map__new(NULL); + cpus = perf_cpu_map__new_online_cpus(); if (!cpus) return false; diff --git a/tools/perf/util/perf_event_attr_fprintf.c b/tools/perf/util/perf_event_attr_fprintf.c index 2247991451..8f04d3b7f3 100644 --- a/tools/perf/util/perf_event_attr_fprintf.c +++ b/tools/perf/util/perf_event_attr_fprintf.c @@ -55,6 +55,7 @@ static void __p_branch_sample_type(char *buf, size_t size, u64 value) bit_name(COND), bit_name(CALL_STACK), bit_name(IND_JUMP), bit_name(CALL), bit_name(NO_FLAGS), bit_name(NO_CYCLES), bit_name(TYPE_SAVE), bit_name(HW_INDEX), bit_name(PRIV_SAVE), + bit_name(COUNTERS), { .name = NULL, } }; #undef bit_name diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index aaa013af52..6b82f4759c 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -1493,12 +1493,14 @@ static int check_info_data(struct perf_pmu *pmu, * defined for the alias */ int perf_pmu__check_alias(struct perf_pmu *pmu, struct parse_events_terms *head_terms, - struct perf_pmu_info *info, struct parse_events_error *err) + struct perf_pmu_info *info, bool *rewrote_terms, + struct parse_events_error *err) { struct parse_events_term *term, *h; struct perf_pmu_alias *alias; int ret; + *rewrote_terms = false; info->per_pkg = false; /* @@ -1520,7 +1522,7 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct parse_events_terms *head_ NULL); return ret; } - + *rewrote_terms = true; ret = check_info_data(pmu, alias, info, err, term->err_term); if (ret) return ret; @@ -1614,6 +1616,8 @@ bool perf_pmu__auto_merge_stats(const struct perf_pmu *pmu) bool perf_pmu__have_event(struct perf_pmu *pmu, const char *name) { + if (!name) + return false; if (perf_pmu__find_alias(pmu, name, /*load=*/ true) != NULL) return true; if (pmu->cpu_aliases_added || !pmu->events_table) diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index d2895d415f..424c3fee09 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -201,7 +201,8 @@ int perf_pmu__config_terms(const struct perf_pmu *pmu, __u64 perf_pmu__format_bits(struct perf_pmu *pmu, const char *name); int perf_pmu__format_type(struct perf_pmu *pmu, const char *name); int perf_pmu__check_alias(struct perf_pmu *pmu, struct parse_events_terms *head_terms, - struct perf_pmu_info *info, struct parse_events_error *err); + struct perf_pmu_info *info, bool *rewrote_terms, + struct parse_events_error *err); int perf_pmu__find_event(struct perf_pmu *pmu, const char *event, void *state, pmu_event_callback cb); int perf_pmu__format_parse(struct perf_pmu *pmu, int dirfd, bool eager_load); diff --git a/tools/perf/util/print-events.c b/tools/perf/util/print-events.c index 4f67e8f00a..b14d1a894a 100644 --- a/tools/perf/util/print-events.c +++ b/tools/perf/util/print-events.c @@ -66,7 +66,7 @@ void print_tracepoint_events(const struct print_callbacks *print_cb __maybe_unus put_tracing_file(events_path); if (events_fd < 0) { - printf("Error: failed to open tracing events directory\n"); + pr_err("Error: failed to open tracing events directory\n"); return; } diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 1a5b7fa459..a1a7960436 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -149,10 +149,32 @@ static int kernel_get_symbol_address_by_name(const char *name, u64 *addr, return 0; } +struct kernel_get_module_map_cb_args { + const char *module; + struct map *result; +}; + +static int kernel_get_module_map_cb(struct map *map, void *data) +{ + struct kernel_get_module_map_cb_args *args = data; + struct dso *dso = map__dso(map); + const char *short_name = dso->short_name; /* short_name is "[module]" */ + u16 short_name_len = dso->short_name_len; + + if (strncmp(short_name + 1, args->module, short_name_len - 2) == 0 && + args->module[short_name_len - 2] == '\0') { + args->result = map__get(map); + return 1; + } + return 0; +} + static struct map *kernel_get_module_map(const char *module) { - struct maps *maps = machine__kernel_maps(host_machine); - struct map_rb_node *pos; + struct kernel_get_module_map_cb_args args = { + .module = module, + .result = NULL, + }; /* A file path -- this is an offline module */ if (module && strchr(module, '/')) @@ -164,19 +186,9 @@ static struct map *kernel_get_module_map(const char *module) return map__get(map); } - maps__for_each_entry(maps, pos) { - /* short_name is "[module]" */ - struct dso *dso = map__dso(pos->map); - const char *short_name = dso->short_name; - u16 short_name_len = dso->short_name_len; + maps__for_each_map(machine__kernel_maps(host_machine), kernel_get_module_map_cb, &args); - if (strncmp(short_name + 1, module, - short_name_len - 2) == 0 && - module[short_name_len - 2] == '\0') { - return map__get(pos->map); - } - } - return NULL; + return args.result; } struct map *get_target_map(const char *target, struct nsinfo *nsi, bool user) diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index f171360b0e..c8923375e3 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -23,6 +23,7 @@ #include "event.h" #include "dso.h" #include "debug.h" +#include "debuginfo.h" #include "intlist.h" #include "strbuf.h" #include "strlist.h" @@ -31,128 +32,9 @@ #include "probe-file.h" #include "string2.h" -#ifdef HAVE_DEBUGINFOD_SUPPORT -#include -#endif - /* Kprobe tracer basic type is up to u64 */ #define MAX_BASIC_TYPE_BITS 64 -/* Dwarf FL wrappers */ -static char *debuginfo_path; /* Currently dummy */ - -static const Dwfl_Callbacks offline_callbacks = { - .find_debuginfo = dwfl_standard_find_debuginfo, - .debuginfo_path = &debuginfo_path, - - .section_address = dwfl_offline_section_address, - - /* We use this table for core files too. */ - .find_elf = dwfl_build_id_find_elf, -}; - -/* Get a Dwarf from offline image */ -static int debuginfo__init_offline_dwarf(struct debuginfo *dbg, - const char *path) -{ - GElf_Addr dummy; - int fd; - - fd = open(path, O_RDONLY); - if (fd < 0) - return fd; - - dbg->dwfl = dwfl_begin(&offline_callbacks); - if (!dbg->dwfl) - goto error; - - dwfl_report_begin(dbg->dwfl); - dbg->mod = dwfl_report_offline(dbg->dwfl, "", "", fd); - if (!dbg->mod) - goto error; - - dbg->dbg = dwfl_module_getdwarf(dbg->mod, &dbg->bias); - if (!dbg->dbg) - goto error; - - dwfl_module_build_id(dbg->mod, &dbg->build_id, &dummy); - - dwfl_report_end(dbg->dwfl, NULL, NULL); - - return 0; -error: - if (dbg->dwfl) - dwfl_end(dbg->dwfl); - else - close(fd); - memset(dbg, 0, sizeof(*dbg)); - - return -ENOENT; -} - -static struct debuginfo *__debuginfo__new(const char *path) -{ - struct debuginfo *dbg = zalloc(sizeof(*dbg)); - if (!dbg) - return NULL; - - if (debuginfo__init_offline_dwarf(dbg, path) < 0) - zfree(&dbg); - if (dbg) - pr_debug("Open Debuginfo file: %s\n", path); - return dbg; -} - -enum dso_binary_type distro_dwarf_types[] = { - DSO_BINARY_TYPE__FEDORA_DEBUGINFO, - DSO_BINARY_TYPE__UBUNTU_DEBUGINFO, - DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO, - DSO_BINARY_TYPE__BUILDID_DEBUGINFO, - DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO, - DSO_BINARY_TYPE__NOT_FOUND, -}; - -struct debuginfo *debuginfo__new(const char *path) -{ - enum dso_binary_type *type; - char buf[PATH_MAX], nil = '\0'; - struct dso *dso; - struct debuginfo *dinfo = NULL; - struct build_id bid; - - /* Try to open distro debuginfo files */ - dso = dso__new(path); - if (!dso) - goto out; - - /* Set the build id for DSO_BINARY_TYPE__BUILDID_DEBUGINFO */ - if (is_regular_file(path) && filename__read_build_id(path, &bid) > 0) - dso__set_build_id(dso, &bid); - - for (type = distro_dwarf_types; - !dinfo && *type != DSO_BINARY_TYPE__NOT_FOUND; - type++) { - if (dso__read_binary_type_filename(dso, *type, &nil, - buf, PATH_MAX) < 0) - continue; - dinfo = __debuginfo__new(buf); - } - dso__put(dso); - -out: - /* if failed to open all distro debuginfo, open given binary */ - return dinfo ? : __debuginfo__new(path); -} - -void debuginfo__delete(struct debuginfo *dbg) -{ - if (dbg) { - if (dbg->dwfl) - dwfl_end(dbg->dwfl); - free(dbg); - } -} - /* * Probe finder related functions */ @@ -722,7 +604,7 @@ static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf) ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); if (ret <= 0 || nops == 0) { pf->fb_ops = NULL; -#if _ELFUTILS_PREREQ(0, 142) +#ifdef HAVE_DWARF_CFI_SUPPORT } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa && (pf->cfi_eh != NULL || pf->cfi_dbg != NULL)) { if ((dwarf_cfi_addrframe(pf->cfi_eh, pf->addr, &frame) != 0 && @@ -733,7 +615,7 @@ static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf) free(frame); return -ENOENT; } -#endif +#endif /* HAVE_DWARF_CFI_SUPPORT */ } /* Call finder's callback handler */ @@ -1258,7 +1140,7 @@ static int debuginfo__find_probes(struct debuginfo *dbg, pf->machine = ehdr.e_machine; -#if _ELFUTILS_PREREQ(0, 142) +#ifdef HAVE_DWARF_CFI_SUPPORT do { GElf_Shdr shdr; @@ -1268,7 +1150,7 @@ static int debuginfo__find_probes(struct debuginfo *dbg, pf->cfi_dbg = dwarf_getcfi(dbg->dbg); } while (0); -#endif +#endif /* HAVE_DWARF_CFI_SUPPORT */ ret = debuginfo__find_probe_location(dbg, pf); return ret; @@ -1677,44 +1559,6 @@ int debuginfo__find_available_vars_at(struct debuginfo *dbg, return (ret < 0) ? ret : af.nvls; } -/* For the kernel module, we need a special code to get a DIE */ -int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs, - bool adjust_offset) -{ - int n, i; - Elf32_Word shndx; - Elf_Scn *scn; - Elf *elf; - GElf_Shdr mem, *shdr; - const char *p; - - elf = dwfl_module_getelf(dbg->mod, &dbg->bias); - if (!elf) - return -EINVAL; - - /* Get the number of relocations */ - n = dwfl_module_relocations(dbg->mod); - if (n < 0) - return -ENOENT; - /* Search the relocation related .text section */ - for (i = 0; i < n; i++) { - p = dwfl_module_relocation_info(dbg->mod, i, &shndx); - if (strcmp(p, ".text") == 0) { - /* OK, get the section header */ - scn = elf_getscn(elf, shndx); - if (!scn) - return -ENOENT; - shdr = gelf_getshdr(scn, &mem); - if (!shdr) - return -ENOENT; - *offs = shdr->sh_addr; - if (adjust_offset) - *offs -= shdr->sh_offset; - } - } - return 0; -} - /* Reverse search */ int debuginfo__find_probe_point(struct debuginfo *dbg, u64 addr, struct perf_probe_point *ppt) @@ -2009,41 +1853,6 @@ found: return (ret < 0) ? ret : lf.found; } -#ifdef HAVE_DEBUGINFOD_SUPPORT -/* debuginfod doesn't require the comp_dir but buildid is required */ -static int get_source_from_debuginfod(const char *raw_path, - const char *sbuild_id, char **new_path) -{ - debuginfod_client *c = debuginfod_begin(); - const char *p = raw_path; - int fd; - - if (!c) - return -ENOMEM; - - fd = debuginfod_find_source(c, (const unsigned char *)sbuild_id, - 0, p, new_path); - pr_debug("Search %s from debuginfod -> %d\n", p, fd); - if (fd >= 0) - close(fd); - debuginfod_end(c); - if (fd < 0) { - pr_debug("Failed to find %s in debuginfod (%s)\n", - raw_path, sbuild_id); - return -ENOENT; - } - pr_debug("Got a source %s\n", *new_path); - - return 0; -} -#else -static inline int get_source_from_debuginfod(const char *raw_path __maybe_unused, - const char *sbuild_id __maybe_unused, - char **new_path __maybe_unused) -{ - return -ENOTSUP; -} -#endif /* * Find a src file from a DWARF tag path. Prepend optional source path prefix * and chop off leading directories that do not exist. Result is passed back as diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h index 8bc1c80d3c..3add5ff516 100644 --- a/tools/perf/util/probe-finder.h +++ b/tools/perf/util/probe-finder.h @@ -24,21 +24,7 @@ static inline int is_c_varname(const char *name) #ifdef HAVE_DWARF_SUPPORT #include "dwarf-aux.h" - -/* TODO: export debuginfo data structure even if no dwarf support */ - -/* debug information structure */ -struct debuginfo { - Dwarf *dbg; - Dwfl_Module *mod; - Dwfl *dwfl; - Dwarf_Addr bias; - const unsigned char *build_id; -}; - -/* This also tries to open distro debuginfo */ -struct debuginfo *debuginfo__new(const char *path); -void debuginfo__delete(struct debuginfo *dbg); +#include "debuginfo.h" /* Find probe_trace_events specified by perf_probe_event from debuginfo */ int debuginfo__find_trace_events(struct debuginfo *dbg, @@ -49,9 +35,6 @@ int debuginfo__find_trace_events(struct debuginfo *dbg, int debuginfo__find_probe_point(struct debuginfo *dbg, u64 addr, struct perf_probe_point *ppt); -int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs, - bool adjust_offset); - /* Find a line range */ int debuginfo__find_line_range(struct debuginfo *dbg, struct line_range *lr); diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c index 9eb5c6a089..87e817b3cf 100644 --- a/tools/perf/util/record.c +++ b/tools/perf/util/record.c @@ -237,8 +237,8 @@ bool evlist__can_select_event(struct evlist *evlist, const char *str) evsel = evlist__last(temp_evlist); - if (!evlist || perf_cpu_map__empty(evlist->core.user_requested_cpus)) { - struct perf_cpu_map *cpus = perf_cpu_map__new(NULL); + if (!evlist || perf_cpu_map__has_any_cpu_or_is_empty(evlist->core.user_requested_cpus)) { + struct perf_cpu_map *cpus = perf_cpu_map__new_online_cpus(); if (cpus) cpu = perf_cpu_map__cpu(cpus, 0); diff --git a/tools/perf/util/s390-cpumcf-kernel.h b/tools/perf/util/s390-cpumcf-kernel.h index f55ca07f3c..74b36644e3 100644 --- a/tools/perf/util/s390-cpumcf-kernel.h +++ b/tools/perf/util/s390-cpumcf-kernel.h @@ -12,6 +12,8 @@ #define S390_CPUMCF_DIAG_DEF 0xfeef /* Counter diagnostic entry ID */ #define PERF_EVENT_CPUM_CF_DIAG 0xBC000 /* Event: Counter sets */ #define PERF_EVENT_CPUM_SF_DIAG 0xBD000 /* Event: Combined-sampling */ +#define PERF_EVENT_PAI_CRYPTO_ALL 0x1000 /* Event: CRYPTO_ALL */ +#define PERF_EVENT_PAI_NNPA_ALL 0x1800 /* Event: NNPA_ALL */ struct cf_ctrset_entry { /* CPU-M CF counter set entry (8 byte) */ unsigned int def:16; /* 0-15 Data Entry Format */ diff --git a/tools/perf/util/s390-sample-raw.c b/tools/perf/util/s390-sample-raw.c index 115b16edb4..53383e97ec 100644 --- a/tools/perf/util/s390-sample-raw.c +++ b/tools/perf/util/s390-sample-raw.c @@ -51,8 +51,6 @@ static bool s390_cpumcfdg_testctr(struct perf_sample *sample) struct cf_trailer_entry *te; struct cf_ctrset_entry *cep, ce; - if (!len) - return false; while (offset < len) { cep = (struct cf_ctrset_entry *)(buf + offset); ce.def = be16_to_cpu(cep->def); @@ -125,6 +123,9 @@ static int get_counterset_start(int setnr) return 128; case CPUMF_CTR_SET_MT_DIAG: /* Diagnostic counter set */ return 448; + case PERF_EVENT_PAI_NNPA_ALL: /* PAI NNPA counter set */ + case PERF_EVENT_PAI_CRYPTO_ALL: /* PAI CRYPTO counter set */ + return setnr; default: return -1; } @@ -212,27 +213,120 @@ static void s390_cpumcfdg_dump(struct perf_pmu *pmu, struct perf_sample *sample) } } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpacked" +#pragma GCC diagnostic ignored "-Wattributes" +/* + * Check for consistency of PAI_CRYPTO/PAI_NNPA raw data. + */ +struct pai_data { /* Event number and value */ + u16 event_nr; + u64 event_val; +} __packed; + +#pragma GCC diagnostic pop + +/* + * Test for valid raw data. At least one PAI event should be in the raw + * data section. + */ +static bool s390_pai_all_test(struct perf_sample *sample) +{ + size_t len = sample->raw_size; + + if (len < 0xa) + return false; + return true; +} + +static void s390_pai_all_dump(struct evsel *evsel, struct perf_sample *sample) +{ + size_t len = sample->raw_size, offset = 0; + unsigned char *p = sample->raw_data; + const char *color = PERF_COLOR_BLUE; + struct pai_data pai_data; + char *ev_name; + + while (offset < len) { + memcpy(&pai_data.event_nr, p, sizeof(pai_data.event_nr)); + pai_data.event_nr = be16_to_cpu(pai_data.event_nr); + p += sizeof(pai_data.event_nr); + offset += sizeof(pai_data.event_nr); + + memcpy(&pai_data.event_val, p, sizeof(pai_data.event_val)); + pai_data.event_val = be64_to_cpu(pai_data.event_val); + p += sizeof(pai_data.event_val); + offset += sizeof(pai_data.event_val); + + ev_name = get_counter_name(evsel->core.attr.config, + pai_data.event_nr, evsel->pmu); + color_fprintf(stdout, color, "\tCounter:%03d %s Value:%#018lx\n", + pai_data.event_nr, ev_name ?: "", + pai_data.event_val); + free(ev_name); + + if (offset + 0xa > len) + break; + } + color_fprintf(stdout, color, "\n"); +} + /* S390 specific trace event function. Check for PERF_RECORD_SAMPLE events - * and if the event was triggered by a counter set diagnostic event display - * its raw data. + * and if the event was triggered by a + * - counter set diagnostic event + * - processor activity assist (PAI) crypto counter event + * - processor activity assist (PAI) neural network processor assist (NNPA) + * counter event + * display its raw data. * The function is only invoked when the dump flag -D is set. + * + * Function evlist__s390_sample_raw() is defined as call back after it has + * been verified that the perf.data file was created on s390 platform. */ -void evlist__s390_sample_raw(struct evlist *evlist, union perf_event *event, struct perf_sample *sample) +void evlist__s390_sample_raw(struct evlist *evlist, union perf_event *event, + struct perf_sample *sample) { + const char *pai_name; struct evsel *evsel; if (event->header.type != PERF_RECORD_SAMPLE) return; evsel = evlist__event2evsel(evlist, event); - if (evsel == NULL || - evsel->core.attr.config != PERF_EVENT_CPUM_CF_DIAG) + if (!evsel) + return; + + /* Check for raw data in sample */ + if (!sample->raw_size || !sample->raw_data) return; /* Display raw data on screen */ - if (!s390_cpumcfdg_testctr(sample)) { - pr_err("Invalid counter set data encountered\n"); + if (evsel->core.attr.config == PERF_EVENT_CPUM_CF_DIAG) { + if (!evsel->pmu) + evsel->pmu = perf_pmus__find("cpum_cf"); + if (!s390_cpumcfdg_testctr(sample)) + pr_err("Invalid counter set data encountered\n"); + else + s390_cpumcfdg_dump(evsel->pmu, sample); + return; + } + + switch (evsel->core.attr.config) { + case PERF_EVENT_PAI_NNPA_ALL: + pai_name = "NNPA_ALL"; + break; + case PERF_EVENT_PAI_CRYPTO_ALL: + pai_name = "CRYPTO_ALL"; + break; + default: return; } - s390_cpumcfdg_dump(evsel->pmu, sample); + + if (!s390_pai_all_test(sample)) { + pr_err("Invalid %s raw data encountered\n", pai_name); + } else { + if (!evsel->pmu) + evsel->pmu = perf_pmus__find_by_type(evsel->core.attr.type); + s390_pai_all_dump(evsel, sample); + } } diff --git a/tools/perf/util/sample.h b/tools/perf/util/sample.h index c92ad0f51e..70b2c31355 100644 --- a/tools/perf/util/sample.h +++ b/tools/perf/util/sample.h @@ -113,6 +113,7 @@ struct perf_sample { void *raw_data; struct ip_callchain *callchain; struct branch_stack *branch_stack; + u64 *branch_stack_cntr; struct regs_dump user_regs; struct regs_dump intr_regs; struct stack_dump user_stack; diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index 603091317b..b072ac5d3b 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c @@ -490,6 +490,9 @@ static int perl_start_script(const char *script, int argc, const char **argv, scripting_context->session = session; command_line = malloc((argc + 2) * sizeof(const char *)); + if (!command_line) + return -ENOMEM; + command_line[0] = ""; command_line[1] = script; for (i = 2; i < argc + 2; i++) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 9431274144..860e1837ba 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -353,6 +353,8 @@ static PyObject *get_field_numeric_entry(struct tep_event *event, if (is_array) { list = PyList_New(field->arraylen); + if (!list) + Py_FatalError("couldn't create Python list"); item_size = field->size / field->arraylen; n_items = field->arraylen; } else { @@ -754,7 +756,7 @@ static void regs_map(struct regs_dump *regs, uint64_t mask, const char *arch, ch } } -static void set_regs_in_dict(PyObject *dict, +static int set_regs_in_dict(PyObject *dict, struct perf_sample *sample, struct evsel *evsel) { @@ -770,6 +772,8 @@ static void set_regs_in_dict(PyObject *dict, */ int size = __sw_hweight64(attr->sample_regs_intr) * 28; char *bf = malloc(size); + if (!bf) + return -1; regs_map(&sample->intr_regs, attr->sample_regs_intr, arch, bf, size); @@ -781,6 +785,8 @@ static void set_regs_in_dict(PyObject *dict, pydict_set_item_string_decref(dict, "uregs", _PyUnicode_FromString(bf)); free(bf); + + return 0; } static void set_sym_in_dict(PyObject *dict, struct addr_location *al, @@ -920,7 +926,8 @@ static PyObject *get_perf_sample_dict(struct perf_sample *sample, PyLong_FromUnsignedLongLong(sample->cyc_cnt)); } - set_regs_in_dict(dict, sample, evsel); + if (set_regs_in_dict(dict, sample, evsel)) + Py_FatalError("Failed to setting regs in dict"); return dict; } @@ -1918,12 +1925,18 @@ static int python_start_script(const char *script, int argc, const char **argv, scripting_context->session = session; #if PY_MAJOR_VERSION < 3 command_line = malloc((argc + 1) * sizeof(const char *)); + if (!command_line) + return -1; + command_line[0] = script; for (i = 1; i < argc + 1; i++) command_line[i] = argv[i - 1]; PyImport_AppendInittab(name, initperf_trace_context); #else command_line = malloc((argc + 1) * sizeof(wchar_t *)); + if (!command_line) + return -1; + command_line[0] = Py_DecodeLocale(script, NULL); for (i = 1; i < argc + 1; i++) command_line[i] = Py_DecodeLocale(argv[i - 1], NULL); diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 1e9aa8ed15..199d3e8df3 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -115,6 +115,11 @@ static int perf_session__open(struct perf_session *session, int repipe_fd) return -1; } + if (perf_header__has_feat(&session->header, HEADER_AUXTRACE)) { + /* Auxiliary events may reference exited threads, hold onto dead ones. */ + symbol_conf.keep_exited_threads = true; + } + if (perf_data__is_pipe(data)) return 0; @@ -1150,9 +1155,13 @@ static void callchain__printf(struct evsel *evsel, i, callchain->ips[i]); } -static void branch_stack__printf(struct perf_sample *sample, bool callstack) +static void branch_stack__printf(struct perf_sample *sample, + struct evsel *evsel) { struct branch_entry *entries = perf_sample__branch_entries(sample); + bool callstack = evsel__has_branch_callstack(evsel); + u64 *branch_stack_cntr = sample->branch_stack_cntr; + struct perf_env *env = evsel__env(evsel); uint64_t i; if (!callstack) { @@ -1194,6 +1203,13 @@ static void branch_stack__printf(struct perf_sample *sample, bool callstack) } } } + + if (branch_stack_cntr) { + printf("... branch stack counters: nr:%" PRIu64 " (counter width: %u max counter nr:%u)\n", + sample->branch_stack->nr, env->br_cntr_width, env->br_cntr_nr); + for (i = 0; i < sample->branch_stack->nr; i++) + printf("..... %2"PRIu64": %016" PRIx64 "\n", i, branch_stack_cntr[i]); + } } static void regs_dump__printf(u64 mask, u64 *regs, const char *arch) @@ -1355,7 +1371,7 @@ static void dump_sample(struct evsel *evsel, union perf_event *event, callchain__printf(evsel, sample); if (evsel__has_br_stack(evsel)) - branch_stack__printf(sample, evsel__has_branch_callstack(evsel)); + branch_stack__printf(sample, evsel); if (sample_type & PERF_SAMPLE_REGS_USER) regs_user__printf(sample, arch); diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 80e4f61327..30254eb637 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -24,6 +24,7 @@ #include "strbuf.h" #include "mem-events.h" #include "annotate.h" +#include "annotate-data.h" #include "event.h" #include "time-utils.h" #include "cgroup.h" @@ -418,6 +419,52 @@ struct sort_entry sort_sym = { .se_width_idx = HISTC_SYMBOL, }; +/* --sort symoff */ + +static int64_t +sort__symoff_cmp(struct hist_entry *left, struct hist_entry *right) +{ + int64_t ret; + + ret = sort__sym_cmp(left, right); + if (ret) + return ret; + + return left->ip - right->ip; +} + +static int64_t +sort__symoff_sort(struct hist_entry *left, struct hist_entry *right) +{ + int64_t ret; + + ret = sort__sym_sort(left, right); + if (ret) + return ret; + + return left->ip - right->ip; +} + +static int +hist_entry__symoff_snprintf(struct hist_entry *he, char *bf, size_t size, unsigned int width) +{ + struct symbol *sym = he->ms.sym; + + if (sym == NULL) + return repsep_snprintf(bf, size, "[%c] %-#.*llx", he->level, width - 4, he->ip); + + return repsep_snprintf(bf, size, "[%c] %s+0x%llx", he->level, sym->name, he->ip - sym->start); +} + +struct sort_entry sort_sym_offset = { + .se_header = "Symbol Offset", + .se_cmp = sort__symoff_cmp, + .se_sort = sort__symoff_sort, + .se_snprintf = hist_entry__symoff_snprintf, + .se_filter = hist_entry__sym_filter, + .se_width_idx = HISTC_SYMBOL_OFFSET, +}; + /* --sort srcline */ char *hist_entry__srcline(struct hist_entry *he) @@ -583,21 +630,21 @@ static int hist_entry__sym_ipc_snprintf(struct hist_entry *he, char *bf, { struct symbol *sym = he->ms.sym; - struct annotation *notes; + struct annotated_branch *branch; double ipc = 0.0, coverage = 0.0; char tmp[64]; if (!sym) return repsep_snprintf(bf, size, "%-*s", width, "-"); - notes = symbol__annotation(sym); + branch = symbol__annotation(sym)->branch; - if (notes->hit_cycles) - ipc = notes->hit_insn / ((double)notes->hit_cycles); + if (branch && branch->hit_cycles) + ipc = branch->hit_insn / ((double)branch->hit_cycles); - if (notes->total_insn) { - coverage = notes->cover_insn * 100.0 / - ((double)notes->total_insn); + if (branch && branch->total_insn) { + coverage = branch->cover_insn * 100.0 / + ((double)branch->total_insn); } snprintf(tmp, sizeof(tmp), "%-5.2f [%5.1f%%]", ipc, coverage); @@ -2094,7 +2141,7 @@ struct sort_entry sort_dso_size = { .se_width_idx = HISTC_DSO_SIZE, }; -/* --sort dso_size */ +/* --sort addr */ static int64_t sort__addr_cmp(struct hist_entry *left, struct hist_entry *right) @@ -2131,6 +2178,152 @@ struct sort_entry sort_addr = { .se_width_idx = HISTC_ADDR, }; +/* --sort type */ + +struct annotated_data_type unknown_type = { + .self = { + .type_name = (char *)"(unknown)", + .children = LIST_HEAD_INIT(unknown_type.self.children), + }, +}; + +static int64_t +sort__type_cmp(struct hist_entry *left, struct hist_entry *right) +{ + return sort__addr_cmp(left, right); +} + +static void sort__type_init(struct hist_entry *he) +{ + if (he->mem_type) + return; + + he->mem_type = hist_entry__get_data_type(he); + if (he->mem_type == NULL) { + he->mem_type = &unknown_type; + he->mem_type_off = 0; + } +} + +static int64_t +sort__type_collapse(struct hist_entry *left, struct hist_entry *right) +{ + struct annotated_data_type *left_type = left->mem_type; + struct annotated_data_type *right_type = right->mem_type; + + if (!left_type) { + sort__type_init(left); + left_type = left->mem_type; + } + + if (!right_type) { + sort__type_init(right); + right_type = right->mem_type; + } + + return strcmp(left_type->self.type_name, right_type->self.type_name); +} + +static int64_t +sort__type_sort(struct hist_entry *left, struct hist_entry *right) +{ + return sort__type_collapse(left, right); +} + +static int hist_entry__type_snprintf(struct hist_entry *he, char *bf, + size_t size, unsigned int width) +{ + return repsep_snprintf(bf, size, "%-*s", width, he->mem_type->self.type_name); +} + +struct sort_entry sort_type = { + .se_header = "Data Type", + .se_cmp = sort__type_cmp, + .se_collapse = sort__type_collapse, + .se_sort = sort__type_sort, + .se_init = sort__type_init, + .se_snprintf = hist_entry__type_snprintf, + .se_width_idx = HISTC_TYPE, +}; + +/* --sort typeoff */ + +static int64_t +sort__typeoff_sort(struct hist_entry *left, struct hist_entry *right) +{ + struct annotated_data_type *left_type = left->mem_type; + struct annotated_data_type *right_type = right->mem_type; + int64_t ret; + + if (!left_type) { + sort__type_init(left); + left_type = left->mem_type; + } + + if (!right_type) { + sort__type_init(right); + right_type = right->mem_type; + } + + ret = strcmp(left_type->self.type_name, right_type->self.type_name); + if (ret) + return ret; + return left->mem_type_off - right->mem_type_off; +} + +static void fill_member_name(char *buf, size_t sz, struct annotated_member *m, + int offset, bool first) +{ + struct annotated_member *child; + + if (list_empty(&m->children)) + return; + + list_for_each_entry(child, &m->children, node) { + if (child->offset <= offset && offset < child->offset + child->size) { + int len = 0; + + /* It can have anonymous struct/union members */ + if (child->var_name) { + len = scnprintf(buf, sz, "%s%s", + first ? "" : ".", child->var_name); + first = false; + } + + fill_member_name(buf + len, sz - len, child, offset, first); + return; + } + } +} + +static int hist_entry__typeoff_snprintf(struct hist_entry *he, char *bf, + size_t size, unsigned int width __maybe_unused) +{ + struct annotated_data_type *he_type = he->mem_type; + char buf[4096]; + + buf[0] = '\0'; + if (list_empty(&he_type->self.children)) + snprintf(buf, sizeof(buf), "no field"); + else + fill_member_name(buf, sizeof(buf), &he_type->self, + he->mem_type_off, true); + buf[4095] = '\0'; + + return repsep_snprintf(bf, size, "%s %+d (%s)", he_type->self.type_name, + he->mem_type_off, buf); +} + +struct sort_entry sort_type_offset = { + .se_header = "Data Type Offset", + .se_cmp = sort__type_cmp, + .se_collapse = sort__typeoff_sort, + .se_sort = sort__typeoff_sort, + .se_init = sort__type_init, + .se_snprintf = hist_entry__typeoff_snprintf, + .se_width_idx = HISTC_TYPE_OFFSET, +}; + struct sort_dimension { const char *name; @@ -2185,7 +2378,10 @@ static struct sort_dimension common_sort_dimensions[] = { DIM(SORT_ADDR, "addr", sort_addr), DIM(SORT_LOCAL_RETIRE_LAT, "local_retire_lat", sort_local_p_stage_cyc), DIM(SORT_GLOBAL_RETIRE_LAT, "retire_lat", sort_global_p_stage_cyc), - DIM(SORT_SIMD, "simd", sort_simd) + DIM(SORT_SIMD, "simd", sort_simd), + DIM(SORT_ANNOTATE_DATA_TYPE, "type", sort_type), + DIM(SORT_ANNOTATE_DATA_TYPE_OFFSET, "typeoff", sort_type_offset), + DIM(SORT_SYM_OFFSET, "symoff", sort_sym_offset), }; #undef DIM @@ -3205,6 +3401,8 @@ int sort_dimension__add(struct perf_hpp_list *list, const char *tok, list->thread = 1; } else if (sd->entry == &sort_comm) { list->comm = 1; + } else if (sd->entry == &sort_type_offset) { + symbol_conf.annotate_data_member = true; } return __sort_dimension__add(sd, list, level); diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index ecfb7f1359..6f6b4189a3 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -15,6 +15,7 @@ struct option; struct thread; +struct annotated_data_type; extern regex_t parent_regex; extern const char *sort_order; @@ -34,6 +35,7 @@ extern struct sort_entry sort_dso_to; extern struct sort_entry sort_sym_from; extern struct sort_entry sort_sym_to; extern struct sort_entry sort_srcline; +extern struct sort_entry sort_type; extern const char default_mem_sort_order[]; extern bool chk_double_cl; @@ -111,6 +113,7 @@ struct hist_entry { u64 p_stage_cyc; u8 cpumode; u8 depth; + int mem_type_off; struct simd_flags simd_flags; /* We are added by hists__add_dummy_entry. */ @@ -154,6 +157,7 @@ struct hist_entry { struct perf_hpp_list *hpp_list; struct hist_entry *parent_he; struct hist_entry_ops *ops; + struct annotated_data_type *mem_type; union { /* this is for hierarchical entry structure */ struct { @@ -243,6 +247,9 @@ enum sort_type { SORT_LOCAL_RETIRE_LAT, SORT_GLOBAL_RETIRE_LAT, SORT_SIMD, + SORT_ANNOTATE_DATA_TYPE, + SORT_ANNOTATE_DATA_TYPE_OFFSET, + SORT_SYM_OFFSET, /* branch stack specific sort keys */ __SORT_BRANCH_STACK, diff --git a/tools/perf/util/stat-display.c b/tools/perf/util/stat-display.c index 969ce40096..b7d00a538d 100644 --- a/tools/perf/util/stat-display.c +++ b/tools/perf/util/stat-display.c @@ -898,7 +898,7 @@ static bool hybrid_uniquify(struct evsel *evsel, struct perf_stat_config *config static void uniquify_counter(struct perf_stat_config *config, struct evsel *counter) { - if (config->no_merge || hybrid_uniquify(counter, config)) + if (config->aggr_mode == AGGR_NONE || hybrid_uniquify(counter, config)) uniquify_event_name(counter); } diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index ec35060422..b0bcf92f0f 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -315,7 +315,7 @@ static int check_per_pkg(struct evsel *counter, struct perf_counts_values *vals, if (!counter->per_pkg) return 0; - if (perf_cpu_map__empty(cpus)) + if (perf_cpu_map__has_any_cpu_or_is_empty(cpus)) return 0; if (!mask) { @@ -592,7 +592,7 @@ void perf_stat_merge_counters(struct perf_stat_config *config, struct evlist *ev { struct evsel *evsel; - if (config->no_merge) + if (config->aggr_mode == AGGR_NONE) return; evlist__for_each_entry(evlist, evsel) diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index 325d0fad18..4357ba1148 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h @@ -76,7 +76,6 @@ struct perf_stat_config { bool null_run; bool ru_display; bool big_num; - bool no_merge; bool hybrid_merge; bool walltime_run_table; bool all_kernel; diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 9e7eeaf616..4b934ed3bf 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -1392,8 +1392,7 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map, map__set_start(map, shdr->sh_addr + ref_reloc(kmap)); map__set_end(map, map__start(map) + shdr->sh_size); map__set_pgoff(map, shdr->sh_offset); - map__set_map_ip(map, map__dso_map_ip); - map__set_unmap_ip(map, map__dso_unmap_ip); + map__set_mapping_type(map, MAPPING_TYPE__DSO); /* Ensure maps are correctly ordered */ if (kmaps) { int err; @@ -1455,8 +1454,7 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map, map__set_end(curr_map, map__start(curr_map) + shdr->sh_size); map__set_pgoff(curr_map, shdr->sh_offset); } else { - map__set_map_ip(curr_map, identity__map_ip); - map__set_unmap_ip(curr_map, identity__map_ip); + map__set_mapping_type(curr_map, MAPPING_TYPE__IDENTITY); } curr_dso->symtab_type = dso->symtab_type; if (maps__insert(kmaps, curr_map)) diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c index a81a14769b..1da8b71350 100644 --- a/tools/perf/util/symbol-minimal.c +++ b/tools/perf/util/symbol-minimal.c @@ -159,9 +159,10 @@ int filename__read_build_id(const char *filename, struct build_id *bid) goto out_free; ret = read_build_id(buf, buf_size, bid, need_swap); - if (ret == 0) + if (ret == 0) { ret = bid->size; - break; + break; + } } } else { Elf64_Ehdr ehdr; @@ -210,9 +211,10 @@ int filename__read_build_id(const char *filename, struct build_id *bid) goto out_free; ret = read_build_id(buf, buf_size, bid, need_swap); - if (ret == 0) + if (ret == 0) { ret = bid->size; - break; + break; + } } } out_free: diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 82cc74b935..be212ba157 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -48,11 +48,6 @@ static bool symbol__is_idle(const char *name); int vmlinux_path__nr_entries; char **vmlinux_path; -struct map_list_node { - struct list_head node; - struct map *map; -}; - struct symbol_conf symbol_conf = { .nanosecs = false, .use_modules = true, @@ -90,11 +85,6 @@ static enum dso_binary_type binary_type_symtab[] = { #define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab) -static struct map_list_node *map_list_node__new(void) -{ - return malloc(sizeof(struct map_list_node)); -} - static bool symbol_type__filter(char symbol_type) { symbol_type = toupper(symbol_type); @@ -270,29 +260,6 @@ void symbols__fixup_end(struct rb_root_cached *symbols, bool is_kallsyms) curr->end = roundup(curr->start, 4096) + 4096; } -void maps__fixup_end(struct maps *maps) -{ - struct map_rb_node *prev = NULL, *curr; - - down_write(maps__lock(maps)); - - maps__for_each_entry(maps, curr) { - if (prev != NULL && !map__end(prev->map)) - map__set_end(prev->map, map__start(curr->map)); - - prev = curr; - } - - /* - * We still haven't the actual symbols, so guess the - * last map final address. - */ - if (curr && !map__end(curr->map)) - map__set_end(curr->map, ~0ULL); - - up_write(maps__lock(maps)); -} - struct symbol *symbol__new(u64 start, u64 len, u8 binding, u8 type, const char *name) { size_t namelen = strlen(name) + 1; @@ -956,8 +923,7 @@ static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta, return -1; } - map__set_map_ip(curr_map, identity__map_ip); - map__set_unmap_ip(curr_map, identity__map_ip); + map__set_mapping_type(curr_map, MAPPING_TYPE__IDENTITY); if (maps__insert(kmaps, curr_map)) { dso__put(ndso); return -1; @@ -1148,33 +1114,35 @@ out_delete_from: return ret; } +static int do_validate_kcore_modules_cb(struct map *old_map, void *data) +{ + struct rb_root *modules = data; + struct module_info *mi; + struct dso *dso; + + if (!__map__is_kmodule(old_map)) + return 0; + + dso = map__dso(old_map); + /* Module must be in memory at the same address */ + mi = find_module(dso->short_name, modules); + if (!mi || mi->start != map__start(old_map)) + return -EINVAL; + + return 0; +} + static int do_validate_kcore_modules(const char *filename, struct maps *kmaps) { struct rb_root modules = RB_ROOT; - struct map_rb_node *old_node; int err; err = read_proc_modules(filename, &modules); if (err) return err; - maps__for_each_entry(kmaps, old_node) { - struct map *old_map = old_node->map; - struct module_info *mi; - struct dso *dso; + err = maps__for_each_map(kmaps, do_validate_kcore_modules_cb, &modules); - if (!__map__is_kmodule(old_map)) { - continue; - } - dso = map__dso(old_map); - /* Module must be in memory at the same address */ - mi = find_module(dso->short_name, &modules); - if (!mi || mi->start != map__start(old_map)) { - err = -EINVAL; - goto out; - } - } -out: delete_modules(&modules); return err; } @@ -1271,101 +1239,15 @@ static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data) return 0; } -/* - * Merges map into maps by splitting the new map within the existing map - * regions. - */ -int maps__merge_in(struct maps *kmaps, struct map *new_map) +static bool remove_old_maps(struct map *map, void *data) { - struct map_rb_node *rb_node; - LIST_HEAD(merged); - int err = 0; - - maps__for_each_entry(kmaps, rb_node) { - struct map *old_map = rb_node->map; - - /* no overload with this one */ - if (map__end(new_map) < map__start(old_map) || - map__start(new_map) >= map__end(old_map)) - continue; - - if (map__start(new_map) < map__start(old_map)) { - /* - * |new...... - * |old.... - */ - if (map__end(new_map) < map__end(old_map)) { - /* - * |new......| -> |new..| - * |old....| -> |old....| - */ - map__set_end(new_map, map__start(old_map)); - } else { - /* - * |new.............| -> |new..| |new..| - * |old....| -> |old....| - */ - struct map_list_node *m = map_list_node__new(); - - if (!m) { - err = -ENOMEM; - goto out; - } - - m->map = map__clone(new_map); - if (!m->map) { - free(m); - err = -ENOMEM; - goto out; - } - - map__set_end(m->map, map__start(old_map)); - list_add_tail(&m->node, &merged); - map__add_pgoff(new_map, map__end(old_map) - map__start(new_map)); - map__set_start(new_map, map__end(old_map)); - } - } else { - /* - * |new...... - * |old.... - */ - if (map__end(new_map) < map__end(old_map)) { - /* - * |new..| -> x - * |old.........| -> |old.........| - */ - map__put(new_map); - new_map = NULL; - break; - } else { - /* - * |new......| -> |new...| - * |old....| -> |old....| - */ - map__add_pgoff(new_map, map__end(old_map) - map__start(new_map)); - map__set_start(new_map, map__end(old_map)); - } - } - } - -out: - while (!list_empty(&merged)) { - struct map_list_node *old_node; - - old_node = list_entry(merged.next, struct map_list_node, node); - list_del_init(&old_node->node); - if (!err) - err = maps__insert(kmaps, old_node->map); - map__put(old_node->map); - free(old_node); - } + const struct map *map_to_save = data; - if (new_map) { - if (!err) - err = maps__insert(kmaps, new_map); - map__put(new_map); - } - return err; + /* + * We need to preserve eBPF maps even if they are covered by kcore, + * because we need to access eBPF dso for source data. + */ + return !RC_CHK_EQUAL(map, map_to_save) && !__map__is_bpf_prog(map); } static int dso__load_kcore(struct dso *dso, struct map *map, @@ -1374,7 +1256,6 @@ static int dso__load_kcore(struct dso *dso, struct map *map, struct maps *kmaps = map__kmaps(map); struct kcore_mapfn_data md; struct map *replacement_map = NULL; - struct map_rb_node *old_node, *next; struct machine *machine; bool is_64_bit; int err, fd; @@ -1421,17 +1302,7 @@ static int dso__load_kcore(struct dso *dso, struct map *map, } /* Remove old maps */ - maps__for_each_entry_safe(kmaps, old_node, next) { - struct map *old_map = old_node->map; - - /* - * We need to preserve eBPF maps even if they are - * covered by kcore, because we need to access - * eBPF dso for source data. - */ - if (old_map != map && !__map__is_bpf_prog(old_map)) - maps__remove(kmaps, old_map); - } + maps__remove_maps(kmaps, remove_old_maps, map); machine->trampolines_mapped = false; /* Find the kernel map using the '_stext' symbol */ @@ -1475,8 +1346,7 @@ static int dso__load_kcore(struct dso *dso, struct map *map, map__set_start(map, map__start(new_map)); map__set_end(map, map__end(new_map)); map__set_pgoff(map, map__pgoff(new_map)); - map__set_map_ip(map, map__map_ip_ptr(new_map)); - map__set_unmap_ip(map, map__unmap_ip_ptr(new_map)); + map__set_mapping_type(map, map__mapping_type(new_map)); /* Ensure maps are correctly ordered */ map_ref = map__get(map); maps__remove(kmaps, map_ref); @@ -2067,124 +1937,6 @@ out: return ret; } -static int map__strcmp(const void *a, const void *b) -{ - const struct map *map_a = *(const struct map **)a; - const struct map *map_b = *(const struct map **)b; - const struct dso *dso_a = map__dso(map_a); - const struct dso *dso_b = map__dso(map_b); - int ret = strcmp(dso_a->short_name, dso_b->short_name); - - if (ret == 0 && map_a != map_b) { - /* - * Ensure distinct but name equal maps have an order in part to - * aid reference counting. - */ - ret = (int)map__start(map_a) - (int)map__start(map_b); - if (ret == 0) - ret = (int)((intptr_t)map_a - (intptr_t)map_b); - } - - return ret; -} - -static int map__strcmp_name(const void *name, const void *b) -{ - const struct dso *dso = map__dso(*(const struct map **)b); - - return strcmp(name, dso->short_name); -} - -void __maps__sort_by_name(struct maps *maps) -{ - qsort(maps__maps_by_name(maps), maps__nr_maps(maps), sizeof(struct map *), map__strcmp); -} - -static int map__groups__sort_by_name_from_rbtree(struct maps *maps) -{ - struct map_rb_node *rb_node; - struct map **maps_by_name = realloc(maps__maps_by_name(maps), - maps__nr_maps(maps) * sizeof(struct map *)); - int i = 0; - - if (maps_by_name == NULL) - return -1; - - up_read(maps__lock(maps)); - down_write(maps__lock(maps)); - - RC_CHK_ACCESS(maps)->maps_by_name = maps_by_name; - RC_CHK_ACCESS(maps)->nr_maps_allocated = maps__nr_maps(maps); - - maps__for_each_entry(maps, rb_node) - maps_by_name[i++] = map__get(rb_node->map); - - __maps__sort_by_name(maps); - - up_write(maps__lock(maps)); - down_read(maps__lock(maps)); - - return 0; -} - -static struct map *__maps__find_by_name(struct maps *maps, const char *name) -{ - struct map **mapp; - - if (maps__maps_by_name(maps) == NULL && - map__groups__sort_by_name_from_rbtree(maps)) - return NULL; - - mapp = bsearch(name, maps__maps_by_name(maps), maps__nr_maps(maps), - sizeof(*mapp), map__strcmp_name); - if (mapp) - return *mapp; - return NULL; -} - -struct map *maps__find_by_name(struct maps *maps, const char *name) -{ - struct map_rb_node *rb_node; - struct map *map; - - down_read(maps__lock(maps)); - - - if (RC_CHK_ACCESS(maps)->last_search_by_name) { - const struct dso *dso = map__dso(RC_CHK_ACCESS(maps)->last_search_by_name); - - if (strcmp(dso->short_name, name) == 0) { - map = RC_CHK_ACCESS(maps)->last_search_by_name; - goto out_unlock; - } - } - /* - * If we have maps->maps_by_name, then the name isn't in the rbtree, - * as maps->maps_by_name mirrors the rbtree when lookups by name are - * made. - */ - map = __maps__find_by_name(maps, name); - if (map || maps__maps_by_name(maps) != NULL) - goto out_unlock; - - /* Fallback to traversing the rbtree... */ - maps__for_each_entry(maps, rb_node) { - struct dso *dso; - - map = rb_node->map; - dso = map__dso(map); - if (strcmp(dso->short_name, name) == 0) { - RC_CHK_ACCESS(maps)->last_search_by_name = map; - goto out_unlock; - } - } - map = NULL; - -out_unlock: - up_read(maps__lock(maps)); - return map; -} - int dso__load_vmlinux(struct dso *dso, struct map *map, const char *vmlinux, bool vmlinux_allocated) { diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index af87c46b3f..071837ddce 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -189,7 +189,6 @@ void __symbols__insert(struct rb_root_cached *symbols, struct symbol *sym, void symbols__insert(struct rb_root_cached *symbols, struct symbol *sym); void symbols__fixup_duplicate(struct rb_root_cached *symbols); void symbols__fixup_end(struct rb_root_cached *symbols, bool is_kallsyms); -void maps__fixup_end(struct maps *maps); typedef int (*mapfn_t)(u64 start, u64 len, u64 pgoff, void *data); int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data, diff --git a/tools/perf/util/symbol_conf.h b/tools/perf/util/symbol_conf.h index 0b589570d1..c114bbceef 100644 --- a/tools/perf/util/symbol_conf.h +++ b/tools/perf/util/symbol_conf.h @@ -42,7 +42,11 @@ struct symbol_conf { inline_name, disable_add2line_warn, buildid_mmap2, - guest_code; + guest_code, + lazy_load_kernel_maps, + keep_exited_threads, + annotate_data_member, + annotate_data_sample; const char *vmlinux_name, *kallsyms_name, *source_prefix, diff --git a/tools/perf/util/synthetic-events.c b/tools/perf/util/synthetic-events.c index a0579c7d7b..2a0289c149 100644 --- a/tools/perf/util/synthetic-events.c +++ b/tools/perf/util/synthetic-events.c @@ -665,18 +665,74 @@ int perf_event__synthesize_cgroups(struct perf_tool *tool __maybe_unused, } #endif +struct perf_event__synthesize_modules_maps_cb_args { + struct perf_tool *tool; + perf_event__handler_t process; + struct machine *machine; + union perf_event *event; +}; + +static int perf_event__synthesize_modules_maps_cb(struct map *map, void *data) +{ + struct perf_event__synthesize_modules_maps_cb_args *args = data; + union perf_event *event = args->event; + struct dso *dso; + size_t size; + + if (!__map__is_kmodule(map)) + return 0; + + dso = map__dso(map); + if (symbol_conf.buildid_mmap2) { + size = PERF_ALIGN(dso->long_name_len + 1, sizeof(u64)); + event->mmap2.header.type = PERF_RECORD_MMAP2; + event->mmap2.header.size = (sizeof(event->mmap2) - + (sizeof(event->mmap2.filename) - size)); + memset(event->mmap2.filename + size, 0, args->machine->id_hdr_size); + event->mmap2.header.size += args->machine->id_hdr_size; + event->mmap2.start = map__start(map); + event->mmap2.len = map__size(map); + event->mmap2.pid = args->machine->pid; + + memcpy(event->mmap2.filename, dso->long_name, dso->long_name_len + 1); + + perf_record_mmap2__read_build_id(&event->mmap2, args->machine, false); + } else { + size = PERF_ALIGN(dso->long_name_len + 1, sizeof(u64)); + event->mmap.header.type = PERF_RECORD_MMAP; + event->mmap.header.size = (sizeof(event->mmap) - + (sizeof(event->mmap.filename) - size)); + memset(event->mmap.filename + size, 0, args->machine->id_hdr_size); + event->mmap.header.size += args->machine->id_hdr_size; + event->mmap.start = map__start(map); + event->mmap.len = map__size(map); + event->mmap.pid = args->machine->pid; + + memcpy(event->mmap.filename, dso->long_name, dso->long_name_len + 1); + } + + if (perf_tool__process_synth_event(args->tool, event, args->machine, args->process) != 0) + return -1; + + return 0; +} + int perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine) { - int rc = 0; - struct map_rb_node *pos; + int rc; struct maps *maps = machine__kernel_maps(machine); - union perf_event *event; - size_t size = symbol_conf.buildid_mmap2 ? - sizeof(event->mmap2) : sizeof(event->mmap); + struct perf_event__synthesize_modules_maps_cb_args args = { + .tool = tool, + .process = process, + .machine = machine, + }; + size_t size = symbol_conf.buildid_mmap2 + ? sizeof(args.event->mmap2) + : sizeof(args.event->mmap); - event = zalloc(size + machine->id_hdr_size); - if (event == NULL) { + args.event = zalloc(size + machine->id_hdr_size); + if (args.event == NULL) { pr_debug("Not enough memory synthesizing mmap event " "for kernel modules\n"); return -1; @@ -687,53 +743,13 @@ int perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t * __perf_event_mmap */ if (machine__is_host(machine)) - event->header.misc = PERF_RECORD_MISC_KERNEL; + args.event->header.misc = PERF_RECORD_MISC_KERNEL; else - event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; - - maps__for_each_entry(maps, pos) { - struct map *map = pos->map; - struct dso *dso; + args.event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; - if (!__map__is_kmodule(map)) - continue; + rc = maps__for_each_map(maps, perf_event__synthesize_modules_maps_cb, &args); - dso = map__dso(map); - if (symbol_conf.buildid_mmap2) { - size = PERF_ALIGN(dso->long_name_len + 1, sizeof(u64)); - event->mmap2.header.type = PERF_RECORD_MMAP2; - event->mmap2.header.size = (sizeof(event->mmap2) - - (sizeof(event->mmap2.filename) - size)); - memset(event->mmap2.filename + size, 0, machine->id_hdr_size); - event->mmap2.header.size += machine->id_hdr_size; - event->mmap2.start = map__start(map); - event->mmap2.len = map__size(map); - event->mmap2.pid = machine->pid; - - memcpy(event->mmap2.filename, dso->long_name, dso->long_name_len + 1); - - perf_record_mmap2__read_build_id(&event->mmap2, machine, false); - } else { - size = PERF_ALIGN(dso->long_name_len + 1, sizeof(u64)); - event->mmap.header.type = PERF_RECORD_MMAP; - event->mmap.header.size = (sizeof(event->mmap) - - (sizeof(event->mmap.filename) - size)); - memset(event->mmap.filename + size, 0, machine->id_hdr_size); - event->mmap.header.size += machine->id_hdr_size; - event->mmap.start = map__start(map); - event->mmap.len = map__size(map); - event->mmap.pid = machine->pid; - - memcpy(event->mmap.filename, dso->long_name, dso->long_name_len + 1); - } - - if (perf_tool__process_synth_event(tool, event, machine, process) != 0) { - rc = -1; - break; - } - } - - free(event); + free(args.event); return rc; } @@ -1039,11 +1055,11 @@ int perf_event__synthesize_threads(struct perf_tool *tool, if (thread_nr > n) thread_nr = n; - synthesize_threads = calloc(sizeof(pthread_t), thread_nr); + synthesize_threads = calloc(thread_nr, sizeof(pthread_t)); if (synthesize_threads == NULL) goto free_dirent; - args = calloc(sizeof(*args), thread_nr); + args = calloc(thread_nr, sizeof(*args)); if (args == NULL) goto free_threads; diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index fe5e6991ae..89c47a5098 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -345,38 +345,36 @@ int thread__insert_map(struct thread *thread, struct map *map) if (ret) return ret; - maps__fixup_overlappings(thread__maps(thread), map, stderr); - return maps__insert(thread__maps(thread), map); + return maps__fixup_overlap_and_insert(thread__maps(thread), map); } -static int __thread__prepare_access(struct thread *thread) +struct thread__prepare_access_maps_cb_args { + int err; + struct maps *maps; +}; + +static int thread__prepare_access_maps_cb(struct map *map, void *data) { bool initialized = false; - int err = 0; - struct maps *maps = thread__maps(thread); - struct map_rb_node *rb_node; - - down_read(maps__lock(maps)); - - maps__for_each_entry(maps, rb_node) { - err = unwind__prepare_access(thread__maps(thread), rb_node->map, &initialized); - if (err || initialized) - break; - } + struct thread__prepare_access_maps_cb_args *args = data; - up_read(maps__lock(maps)); + args->err = unwind__prepare_access(args->maps, map, &initialized); - return err; + return (args->err || initialized) ? 1 : 0; } static int thread__prepare_access(struct thread *thread) { - int err = 0; + struct thread__prepare_access_maps_cb_args args = { + .err = 0, + }; - if (dwarf_callchain_users) - err = __thread__prepare_access(thread); + if (dwarf_callchain_users) { + args.maps = thread__maps(thread); + maps__for_each_map(thread__maps(thread), thread__prepare_access_maps_cb, &args); + } - return err; + return args.err; } static int thread__clone_maps(struct thread *thread, struct thread *parent, bool do_maps_clone) @@ -385,14 +383,14 @@ static int thread__clone_maps(struct thread *thread, struct thread *parent, bool if (thread__pid(thread) == thread__pid(parent)) return thread__prepare_access(thread); - if (thread__maps(thread) == thread__maps(parent)) { + if (RC_CHK_EQUAL(thread__maps(thread), thread__maps(parent))) { pr_debug("broken map groups on thread %d/%d parent %d/%d\n", thread__pid(thread), thread__tid(thread), thread__pid(parent), thread__tid(parent)); return 0; } /* But this one is new process, copy maps. */ - return do_maps_clone ? maps__clone(thread, thread__maps(parent)) : 0; + return do_maps_clone ? maps__copy_from(thread__maps(thread), thread__maps(parent)) : 0; } int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp, bool do_maps_clone) diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index e79225a0ea..0df775b5c1 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -36,13 +36,22 @@ struct thread_rb_node { }; DECLARE_RC_STRUCT(thread) { + /** @maps: mmaps associated with this thread. */ struct maps *maps; pid_t pid_; /* Not all tools update this */ + /** @tid: thread ID number unique to a machine. */ pid_t tid; + /** @ppid: parent process of the process this thread belongs to. */ pid_t ppid; int cpu; int guest_cpu; /* For QEMU thread */ refcount_t refcnt; + /** + * @exited: Has the thread had an exit event. Such threads are usually + * removed from the machine's threads but some events/tools require + * access to dead threads. + */ + bool exited; bool comm_set; int comm_len; struct list_head namespaces_list; @@ -189,6 +198,11 @@ static inline refcount_t *thread__refcnt(struct thread *thread) return &RC_CHK_ACCESS(thread)->refcnt; } +static inline void thread__set_exited(struct thread *thread, bool exited) +{ + RC_CHK_ACCESS(thread)->exited = exited; +} + static inline bool thread__comm_set(const struct thread *thread) { return RC_CHK_ACCESS(thread)->comm_set; diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c index be7157de04..4db3d1bd68 100644 --- a/tools/perf/util/top.c +++ b/tools/perf/util/top.c @@ -28,6 +28,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) struct record_opts *opts = &top->record_opts; struct target *target = &opts->target; size_t ret = 0; + int nr_cpus; if (top->samples) { samples_per_sec = top->samples / top->delay_secs; @@ -93,19 +94,17 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) else ret += SNPRINTF(bf + ret, size - ret, " (all"); + nr_cpus = perf_cpu_map__nr(top->evlist->core.user_requested_cpus); if (target->cpu_list) ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)", - perf_cpu_map__nr(top->evlist->core.user_requested_cpus) > 1 - ? "s" : "", + nr_cpus > 1 ? "s" : "", target->cpu_list); else { if (target->tid) ret += SNPRINTF(bf + ret, size - ret, ")"); else ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)", - perf_cpu_map__nr(top->evlist->core.user_requested_cpus), - perf_cpu_map__nr(top->evlist->core.user_requested_cpus) > 1 - ? "s" : ""); + nr_cpus, nr_cpus > 1 ? "s" : ""); } perf_top__reset_sample_counters(top); diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index a8b0d79bd9..4c5588dbb1 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h @@ -21,7 +21,6 @@ struct perf_top { struct perf_tool tool; struct evlist *evlist, *sb_evlist; struct record_opts record_opts; - struct annotation_options annotation_opts; struct evswitch evswitch; /* * Symbols will be added here in perf_event__process_sample and will diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c index 5e5c3395a4..dac536e283 100644 --- a/tools/perf/util/unwind-libunwind-local.c +++ b/tools/perf/util/unwind-libunwind-local.c @@ -302,12 +302,31 @@ static int unwind_spec_ehframe(struct dso *dso, struct machine *machine, return 0; } +struct read_unwind_spec_eh_frame_maps_cb_args { + struct dso *dso; + u64 base_addr; +}; + +static int read_unwind_spec_eh_frame_maps_cb(struct map *map, void *data) +{ + + struct read_unwind_spec_eh_frame_maps_cb_args *args = data; + + if (map__dso(map) == args->dso && map__start(map) - map__pgoff(map) < args->base_addr) + args->base_addr = map__start(map) - map__pgoff(map); + + return 0; +} + + static int read_unwind_spec_eh_frame(struct dso *dso, struct unwind_info *ui, u64 *table_data, u64 *segbase, u64 *fde_count) { - struct map_rb_node *map_node; - u64 base_addr = UINT64_MAX; + struct read_unwind_spec_eh_frame_maps_cb_args args = { + .dso = dso, + .base_addr = UINT64_MAX, + }; int ret, fd; if (dso->data.eh_frame_hdr_offset == 0) { @@ -325,16 +344,11 @@ static int read_unwind_spec_eh_frame(struct dso *dso, struct unwind_info *ui, return -EINVAL; } - maps__for_each_entry(thread__maps(ui->thread), map_node) { - struct map *map = map_node->map; - u64 start = map__start(map) - map__pgoff(map); + maps__for_each_map(thread__maps(ui->thread), read_unwind_spec_eh_frame_maps_cb, &args); - if (map__dso(map) == dso && start < base_addr) - base_addr = start; - } - base_addr -= dso->data.elf_base_addr; + args.base_addr -= dso->data.elf_base_addr; /* Address of .eh_frame_hdr */ - *segbase = base_addr + dso->data.eh_frame_hdr_addr; + *segbase = args.base_addr + dso->data.eh_frame_hdr_addr; ret = unwind_spec_ehframe(dso, ui->machine, dso->data.eh_frame_hdr_offset, table_data, fde_count); if (ret) diff --git a/tools/perf/util/vdso.c b/tools/perf/util/vdso.c index ae3eee69b6..df89637961 100644 --- a/tools/perf/util/vdso.c +++ b/tools/perf/util/vdso.c @@ -140,23 +140,34 @@ static struct dso *__machine__addnew_vdso(struct machine *machine, const char *s return dso; } +struct machine__thread_dso_type_maps_cb_args { + struct machine *machine; + enum dso_type dso_type; +}; + +static int machine__thread_dso_type_maps_cb(struct map *map, void *data) +{ + struct machine__thread_dso_type_maps_cb_args *args = data; + struct dso *dso = map__dso(map); + + if (!dso || dso->long_name[0] != '/') + return 0; + + args->dso_type = dso__type(dso, args->machine); + return (args->dso_type != DSO__TYPE_UNKNOWN) ? 1 : 0; +} + static enum dso_type machine__thread_dso_type(struct machine *machine, struct thread *thread) { - enum dso_type dso_type = DSO__TYPE_UNKNOWN; - struct map_rb_node *rb_node; - - maps__for_each_entry(thread__maps(thread), rb_node) { - struct dso *dso = map__dso(rb_node->map); + struct machine__thread_dso_type_maps_cb_args args = { + .machine = machine, + .dso_type = DSO__TYPE_UNKNOWN, + }; - if (!dso || dso->long_name[0] != '/') - continue; - dso_type = dso__type(dso, machine); - if (dso_type != DSO__TYPE_UNKNOWN) - break; - } + maps__for_each_map(thread__maps(thread), machine__thread_dso_type_maps_cb, &args); - return dso_type; + return args.dso_type; } #if BITS_PER_LONG == 64 diff --git a/tools/perf/util/zstd.c b/tools/perf/util/zstd.c index 48dd2b018c..57027e0ac7 100644 --- a/tools/perf/util/zstd.c +++ b/tools/perf/util/zstd.c @@ -7,35 +7,9 @@ int zstd_init(struct zstd_data *data, int level) { - size_t ret; - - data->dstream = ZSTD_createDStream(); - if (data->dstream == NULL) { - pr_err("Couldn't create decompression stream.\n"); - return -1; - } - - ret = ZSTD_initDStream(data->dstream); - if (ZSTD_isError(ret)) { - pr_err("Failed to initialize decompression stream: %s\n", ZSTD_getErrorName(ret)); - return -1; - } - - if (!level) - return 0; - - data->cstream = ZSTD_createCStream(); - if (data->cstream == NULL) { - pr_err("Couldn't create compression stream.\n"); - return -1; - } - - ret = ZSTD_initCStream(data->cstream, level); - if (ZSTD_isError(ret)) { - pr_err("Failed to initialize compression stream: %s\n", ZSTD_getErrorName(ret)); - return -1; - } - + data->comp_level = level; + data->dstream = NULL; + data->cstream = NULL; return 0; } @@ -54,7 +28,7 @@ int zstd_fini(struct zstd_data *data) return 0; } -size_t zstd_compress_stream_to_records(struct zstd_data *data, void *dst, size_t dst_size, +ssize_t zstd_compress_stream_to_records(struct zstd_data *data, void *dst, size_t dst_size, void *src, size_t src_size, size_t max_record_size, size_t process_header(void *record, size_t increment)) { @@ -63,6 +37,21 @@ size_t zstd_compress_stream_to_records(struct zstd_data *data, void *dst, size_t ZSTD_outBuffer output; void *record; + if (!data->cstream) { + data->cstream = ZSTD_createCStream(); + if (data->cstream == NULL) { + pr_err("Couldn't create compression stream.\n"); + return -1; + } + + ret = ZSTD_initCStream(data->cstream, data->comp_level); + if (ZSTD_isError(ret)) { + pr_err("Failed to initialize compression stream: %s\n", + ZSTD_getErrorName(ret)); + return -1; + } + } + while (input.pos < input.size) { record = dst; size = process_header(record, 0); @@ -96,6 +85,20 @@ size_t zstd_decompress_stream(struct zstd_data *data, void *src, size_t src_size ZSTD_inBuffer input = { src, src_size, 0 }; ZSTD_outBuffer output = { dst, dst_size, 0 }; + if (!data->dstream) { + data->dstream = ZSTD_createDStream(); + if (data->dstream == NULL) { + pr_err("Couldn't create decompression stream.\n"); + return 0; + } + + ret = ZSTD_initDStream(data->dstream); + if (ZSTD_isError(ret)) { + pr_err("Failed to initialize decompression stream: %s\n", + ZSTD_getErrorName(ret)); + return 0; + } + } while (input.pos < input.size) { ret = ZSTD_decompressStream(data->dstream, &output, &input); if (ZSTD_isError(ret)) { diff --git a/tools/power/cpupower/bench/Makefile b/tools/power/cpupower/bench/Makefile index d9d9923af8..a4b902f9e1 100644 --- a/tools/power/cpupower/bench/Makefile +++ b/tools/power/cpupower/bench/Makefile @@ -15,7 +15,7 @@ LIBS = -L../ -L$(OUTPUT) -lm -lcpupower OBJS = $(OUTPUT)main.o $(OUTPUT)parse.o $(OUTPUT)system.o $(OUTPUT)benchmark.o endif -CFLAGS += -D_GNU_SOURCE -I../lib -DDEFAULT_CONFIG_FILE=\"$(confdir)/cpufreq-bench.conf\" +override CFLAGS += -D_GNU_SOURCE -I../lib -DDEFAULT_CONFIG_FILE=\"$(confdir)/cpufreq-bench.conf\" $(OUTPUT)%.o : %.c $(ECHO) " CC " $@ diff --git a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c index 5fd9e59407..ebda9c366b 100644 --- a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c +++ b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c @@ -1241,6 +1241,7 @@ unsigned int get_pkg_num(int cpu) retval = fscanf(fp, "%d\n", &pkg); if (retval != 1) errx(1, "%s: failed to parse", pathname); + fclose(fp); return pkg; } diff --git a/tools/testing/cxl/Kbuild b/tools/testing/cxl/Kbuild index 95dc58b941..030b388800 100644 --- a/tools/testing/cxl/Kbuild +++ b/tools/testing/cxl/Kbuild @@ -13,6 +13,7 @@ ldflags-y += --wrap=cxl_hdm_decode_init ldflags-y += --wrap=cxl_dvsec_rr_decode ldflags-y += --wrap=devm_cxl_add_rch_dport ldflags-y += --wrap=cxl_rcd_component_reg_phys +ldflags-y += --wrap=cxl_endpoint_parse_cdat DRIVERS := ../../../drivers CXL_SRC := $(DRIVERS)/cxl @@ -58,10 +59,13 @@ cxl_core-y += $(CXL_CORE_SRC)/mbox.o cxl_core-y += $(CXL_CORE_SRC)/pci.o cxl_core-y += $(CXL_CORE_SRC)/hdm.o cxl_core-y += $(CXL_CORE_SRC)/pmu.o +cxl_core-y += $(CXL_CORE_SRC)/cdat.o cxl_core-$(CONFIG_TRACING) += $(CXL_CORE_SRC)/trace.o cxl_core-$(CONFIG_CXL_REGION) += $(CXL_CORE_SRC)/region.o cxl_core-y += config_check.o cxl_core-y += cxl_core_test.o cxl_core-y += cxl_core_exports.o +KBUILD_CFLAGS := $(filter-out -Wmissing-prototypes -Wmissing-declarations, $(KBUILD_CFLAGS)) + obj-m += test/ diff --git a/tools/testing/cxl/test/Kbuild b/tools/testing/cxl/test/Kbuild index 61d5f7bcdd..6b19278978 100644 --- a/tools/testing/cxl/test/Kbuild +++ b/tools/testing/cxl/test/Kbuild @@ -8,3 +8,5 @@ obj-m += cxl_mock_mem.o cxl_test-y := cxl.o cxl_mock-y := mock.o cxl_mock_mem-y := mem.o + +KBUILD_CFLAGS := $(filter-out -Wmissing-prototypes -Wmissing-declarations, $(KBUILD_CFLAGS)) diff --git a/tools/testing/cxl/test/cxl.c b/tools/testing/cxl/test/cxl.c index f4e517a0c7..908e0d0839 100644 --- a/tools/testing/cxl/test/cxl.c +++ b/tools/testing/cxl/test/cxl.c @@ -15,6 +15,8 @@ static int interleave_arithmetic; +#define FAKE_QTG_ID 42 + #define NR_CXL_HOST_BRIDGES 2 #define NR_CXL_SINGLE_HOST 1 #define NR_CXL_RCH 1 @@ -68,15 +70,19 @@ static struct acpi_device acpi0017_mock; static struct acpi_device host_bridge[NR_BRIDGES] = { [0] = { .handle = &host_bridge[0], + .pnp.unique_id = "0", }, [1] = { .handle = &host_bridge[1], + .pnp.unique_id = "1", }, [2] = { .handle = &host_bridge[2], + .pnp.unique_id = "2", }, [3] = { .handle = &host_bridge[3], + .pnp.unique_id = "3", }, }; @@ -205,7 +211,7 @@ static struct { .granularity = 4, .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 | ACPI_CEDT_CFMWS_RESTRICT_VOLATILE, - .qtg_id = 0, + .qtg_id = FAKE_QTG_ID, .window_size = SZ_256M * 4UL, }, .target = { 0 }, @@ -220,7 +226,7 @@ static struct { .granularity = 4, .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 | ACPI_CEDT_CFMWS_RESTRICT_VOLATILE, - .qtg_id = 1, + .qtg_id = FAKE_QTG_ID, .window_size = SZ_256M * 8UL, }, .target = { 0, 1, }, @@ -235,7 +241,7 @@ static struct { .granularity = 4, .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 | ACPI_CEDT_CFMWS_RESTRICT_PMEM, - .qtg_id = 2, + .qtg_id = FAKE_QTG_ID, .window_size = SZ_256M * 4UL, }, .target = { 0 }, @@ -250,7 +256,7 @@ static struct { .granularity = 4, .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 | ACPI_CEDT_CFMWS_RESTRICT_PMEM, - .qtg_id = 3, + .qtg_id = FAKE_QTG_ID, .window_size = SZ_256M * 8UL, }, .target = { 0, 1, }, @@ -265,7 +271,7 @@ static struct { .granularity = 4, .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 | ACPI_CEDT_CFMWS_RESTRICT_PMEM, - .qtg_id = 4, + .qtg_id = FAKE_QTG_ID, .window_size = SZ_256M * 4UL, }, .target = { 2 }, @@ -280,7 +286,7 @@ static struct { .granularity = 4, .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 | ACPI_CEDT_CFMWS_RESTRICT_VOLATILE, - .qtg_id = 5, + .qtg_id = FAKE_QTG_ID, .window_size = SZ_256M, }, .target = { 3 }, @@ -297,7 +303,7 @@ static struct { .granularity = 4, .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 | ACPI_CEDT_CFMWS_RESTRICT_PMEM, - .qtg_id = 0, + .qtg_id = FAKE_QTG_ID, .window_size = SZ_256M * 8UL, }, .target = { 0, }, @@ -313,7 +319,7 @@ static struct { .granularity = 0, .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 | ACPI_CEDT_CFMWS_RESTRICT_PMEM, - .qtg_id = 1, + .qtg_id = FAKE_QTG_ID, .window_size = SZ_256M * 8UL, }, .target = { 0, 1, }, @@ -329,7 +335,7 @@ static struct { .granularity = 0, .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 | ACPI_CEDT_CFMWS_RESTRICT_PMEM, - .qtg_id = 0, + .qtg_id = FAKE_QTG_ID, .window_size = SZ_256M * 16UL, }, .target = { 0, 1, 0, 1, }, @@ -972,6 +978,48 @@ static int mock_cxl_port_enumerate_dports(struct cxl_port *port) return 0; } +/* + * Faking the cxl_dpa_perf for the memdev when appropriate. + */ +static void dpa_perf_setup(struct cxl_port *endpoint, struct range *range, + struct cxl_dpa_perf *dpa_perf) +{ + dpa_perf->qos_class = FAKE_QTG_ID; + dpa_perf->dpa_range = *range; + dpa_perf->coord.read_latency = 500; + dpa_perf->coord.write_latency = 500; + dpa_perf->coord.read_bandwidth = 1000; + dpa_perf->coord.write_bandwidth = 1000; +} + +static void mock_cxl_endpoint_parse_cdat(struct cxl_port *port) +{ + struct cxl_root *cxl_root __free(put_cxl_root) = + find_cxl_root(port); + struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport_dev); + struct cxl_dev_state *cxlds = cxlmd->cxlds; + struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds); + struct range pmem_range = { + .start = cxlds->pmem_res.start, + .end = cxlds->pmem_res.end, + }; + struct range ram_range = { + .start = cxlds->ram_res.start, + .end = cxlds->ram_res.end, + }; + + if (!cxl_root) + return; + + if (range_len(&ram_range)) + dpa_perf_setup(port, &ram_range, &mds->ram_perf); + + if (range_len(&pmem_range)) + dpa_perf_setup(port, &pmem_range, &mds->pmem_perf); + + cxl_memdev_update_perf(cxlmd); +} + static struct cxl_mock_ops cxl_mock_ops = { .is_mock_adev = is_mock_adev, .is_mock_bridge = is_mock_bridge, @@ -985,6 +1033,7 @@ static struct cxl_mock_ops cxl_mock_ops = { .devm_cxl_setup_hdm = mock_cxl_setup_hdm, .devm_cxl_add_passthrough_decoder = mock_cxl_add_passthrough_decoder, .devm_cxl_enumerate_decoders = mock_cxl_enumerate_decoders, + .cxl_endpoint_parse_cdat = mock_cxl_endpoint_parse_cdat, .list = LIST_HEAD_INIT(cxl_mock_ops.list), }; diff --git a/tools/testing/cxl/test/mem.c b/tools/testing/cxl/test/mem.c index ee61fa3a24..35ee41e435 100644 --- a/tools/testing/cxl/test/mem.c +++ b/tools/testing/cxl/test/mem.c @@ -251,7 +251,8 @@ static int mock_get_event(struct device *dev, struct cxl_mbox_cmd *cmd) for (i = 0; i < CXL_TEST_EVENT_CNT && !event_log_empty(log); i++) { memcpy(&pl->records[i], event_get_current(log), sizeof(pl->records[i])); - pl->records[i].hdr.handle = event_get_cur_event_handle(log); + pl->records[i].event.generic.hdr.handle = + event_get_cur_event_handle(log); log->cur_idx++; } @@ -337,87 +338,109 @@ static void cxl_mock_event_trigger(struct device *dev) } struct cxl_event_record_raw maint_needed = { - .hdr = { - .id = UUID_INIT(0xBA5EBA11, 0xABCD, 0xEFEB, - 0xa5, 0x5a, 0xa5, 0x5a, 0xa5, 0xa5, 0x5a, 0xa5), - .length = sizeof(struct cxl_event_record_raw), - .flags[0] = CXL_EVENT_RECORD_FLAG_MAINT_NEEDED, - /* .handle = Set dynamically */ - .related_handle = cpu_to_le16(0xa5b6), + .id = UUID_INIT(0xBA5EBA11, 0xABCD, 0xEFEB, + 0xa5, 0x5a, 0xa5, 0x5a, 0xa5, 0xa5, 0x5a, 0xa5), + .event.generic = { + .hdr = { + .length = sizeof(struct cxl_event_record_raw), + .flags[0] = CXL_EVENT_RECORD_FLAG_MAINT_NEEDED, + /* .handle = Set dynamically */ + .related_handle = cpu_to_le16(0xa5b6), + }, + .data = { 0xDE, 0xAD, 0xBE, 0xEF }, }, - .data = { 0xDE, 0xAD, 0xBE, 0xEF }, }; struct cxl_event_record_raw hardware_replace = { - .hdr = { - .id = UUID_INIT(0xABCDEFEB, 0xBA11, 0xBA5E, - 0xa5, 0x5a, 0xa5, 0x5a, 0xa5, 0xa5, 0x5a, 0xa5), - .length = sizeof(struct cxl_event_record_raw), - .flags[0] = CXL_EVENT_RECORD_FLAG_HW_REPLACE, - /* .handle = Set dynamically */ - .related_handle = cpu_to_le16(0xb6a5), + .id = UUID_INIT(0xABCDEFEB, 0xBA11, 0xBA5E, + 0xa5, 0x5a, 0xa5, 0x5a, 0xa5, 0xa5, 0x5a, 0xa5), + .event.generic = { + .hdr = { + .length = sizeof(struct cxl_event_record_raw), + .flags[0] = CXL_EVENT_RECORD_FLAG_HW_REPLACE, + /* .handle = Set dynamically */ + .related_handle = cpu_to_le16(0xb6a5), + }, + .data = { 0xDE, 0xAD, 0xBE, 0xEF }, }, - .data = { 0xDE, 0xAD, 0xBE, 0xEF }, }; -struct cxl_event_gen_media gen_media = { - .hdr = { - .id = UUID_INIT(0xfbcd0a77, 0xc260, 0x417f, - 0x85, 0xa9, 0x08, 0x8b, 0x16, 0x21, 0xeb, 0xa6), - .length = sizeof(struct cxl_event_gen_media), - .flags[0] = CXL_EVENT_RECORD_FLAG_PERMANENT, - /* .handle = Set dynamically */ - .related_handle = cpu_to_le16(0), +struct cxl_test_gen_media { + uuid_t id; + struct cxl_event_gen_media rec; +} __packed; + +struct cxl_test_gen_media gen_media = { + .id = CXL_EVENT_GEN_MEDIA_UUID, + .rec = { + .hdr = { + .length = sizeof(struct cxl_test_gen_media), + .flags[0] = CXL_EVENT_RECORD_FLAG_PERMANENT, + /* .handle = Set dynamically */ + .related_handle = cpu_to_le16(0), + }, + .phys_addr = cpu_to_le64(0x2000), + .descriptor = CXL_GMER_EVT_DESC_UNCORECTABLE_EVENT, + .type = CXL_GMER_MEM_EVT_TYPE_DATA_PATH_ERROR, + .transaction_type = CXL_GMER_TRANS_HOST_WRITE, + /* .validity_flags = */ + .channel = 1, + .rank = 30 }, - .phys_addr = cpu_to_le64(0x2000), - .descriptor = CXL_GMER_EVT_DESC_UNCORECTABLE_EVENT, - .type = CXL_GMER_MEM_EVT_TYPE_DATA_PATH_ERROR, - .transaction_type = CXL_GMER_TRANS_HOST_WRITE, - /* .validity_flags = */ - .channel = 1, - .rank = 30 }; -struct cxl_event_dram dram = { - .hdr = { - .id = UUID_INIT(0x601dcbb3, 0x9c06, 0x4eab, - 0xb8, 0xaf, 0x4e, 0x9b, 0xfb, 0x5c, 0x96, 0x24), - .length = sizeof(struct cxl_event_dram), - .flags[0] = CXL_EVENT_RECORD_FLAG_PERF_DEGRADED, - /* .handle = Set dynamically */ - .related_handle = cpu_to_le16(0), +struct cxl_test_dram { + uuid_t id; + struct cxl_event_dram rec; +} __packed; + +struct cxl_test_dram dram = { + .id = CXL_EVENT_DRAM_UUID, + .rec = { + .hdr = { + .length = sizeof(struct cxl_test_dram), + .flags[0] = CXL_EVENT_RECORD_FLAG_PERF_DEGRADED, + /* .handle = Set dynamically */ + .related_handle = cpu_to_le16(0), + }, + .phys_addr = cpu_to_le64(0x8000), + .descriptor = CXL_GMER_EVT_DESC_THRESHOLD_EVENT, + .type = CXL_GMER_MEM_EVT_TYPE_INV_ADDR, + .transaction_type = CXL_GMER_TRANS_INTERNAL_MEDIA_SCRUB, + /* .validity_flags = */ + .channel = 1, + .bank_group = 5, + .bank = 2, + .column = {0xDE, 0xAD}, }, - .phys_addr = cpu_to_le64(0x8000), - .descriptor = CXL_GMER_EVT_DESC_THRESHOLD_EVENT, - .type = CXL_GMER_MEM_EVT_TYPE_INV_ADDR, - .transaction_type = CXL_GMER_TRANS_INTERNAL_MEDIA_SCRUB, - /* .validity_flags = */ - .channel = 1, - .bank_group = 5, - .bank = 2, - .column = {0xDE, 0xAD}, }; -struct cxl_event_mem_module mem_module = { - .hdr = { - .id = UUID_INIT(0xfe927475, 0xdd59, 0x4339, - 0xa5, 0x86, 0x79, 0xba, 0xb1, 0x13, 0xb7, 0x74), - .length = sizeof(struct cxl_event_mem_module), - /* .handle = Set dynamically */ - .related_handle = cpu_to_le16(0), +struct cxl_test_mem_module { + uuid_t id; + struct cxl_event_mem_module rec; +} __packed; + +struct cxl_test_mem_module mem_module = { + .id = CXL_EVENT_MEM_MODULE_UUID, + .rec = { + .hdr = { + .length = sizeof(struct cxl_test_mem_module), + /* .handle = Set dynamically */ + .related_handle = cpu_to_le16(0), + }, + .event_type = CXL_MMER_TEMP_CHANGE, + .info = { + .health_status = CXL_DHI_HS_PERFORMANCE_DEGRADED, + .media_status = CXL_DHI_MS_ALL_DATA_LOST, + .add_status = (CXL_DHI_AS_CRITICAL << 2) | + (CXL_DHI_AS_WARNING << 4) | + (CXL_DHI_AS_WARNING << 5), + .device_temp = { 0xDE, 0xAD}, + .dirty_shutdown_cnt = { 0xde, 0xad, 0xbe, 0xef }, + .cor_vol_err_cnt = { 0xde, 0xad, 0xbe, 0xef }, + .cor_per_err_cnt = { 0xde, 0xad, 0xbe, 0xef }, + } }, - .event_type = CXL_MMER_TEMP_CHANGE, - .info = { - .health_status = CXL_DHI_HS_PERFORMANCE_DEGRADED, - .media_status = CXL_DHI_MS_ALL_DATA_LOST, - .add_status = (CXL_DHI_AS_CRITICAL << 2) | - (CXL_DHI_AS_WARNING << 4) | - (CXL_DHI_AS_WARNING << 5), - .device_temp = { 0xDE, 0xAD}, - .dirty_shutdown_cnt = { 0xde, 0xad, 0xbe, 0xef }, - .cor_vol_err_cnt = { 0xde, 0xad, 0xbe, 0xef }, - .cor_per_err_cnt = { 0xde, 0xad, 0xbe, 0xef }, - } }; static int mock_set_timestamp(struct cxl_dev_state *cxlds, @@ -439,11 +462,11 @@ static int mock_set_timestamp(struct cxl_dev_state *cxlds, static void cxl_mock_add_event_logs(struct mock_event_store *mes) { put_unaligned_le16(CXL_GMER_VALID_CHANNEL | CXL_GMER_VALID_RANK, - &gen_media.validity_flags); + &gen_media.rec.validity_flags); put_unaligned_le16(CXL_DER_VALID_CHANNEL | CXL_DER_VALID_BANK_GROUP | CXL_DER_VALID_BANK | CXL_DER_VALID_COLUMN, - &dram.validity_flags); + &dram.rec.validity_flags); mes_add_event(mes, CXL_EVENT_TYPE_INFO, &maint_needed); mes_add_event(mes, CXL_EVENT_TYPE_INFO, diff --git a/tools/testing/cxl/test/mock.c b/tools/testing/cxl/test/mock.c index 1a61e68e30..6f737941dc 100644 --- a/tools/testing/cxl/test/mock.c +++ b/tools/testing/cxl/test/mock.c @@ -285,6 +285,20 @@ resource_size_t __wrap_cxl_rcd_component_reg_phys(struct device *dev, } EXPORT_SYMBOL_NS_GPL(__wrap_cxl_rcd_component_reg_phys, CXL); +void __wrap_cxl_endpoint_parse_cdat(struct cxl_port *port) +{ + int index; + struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); + struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport_dev); + + if (ops && ops->is_mock_dev(cxlmd->dev.parent)) + ops->cxl_endpoint_parse_cdat(port); + else + cxl_endpoint_parse_cdat(port); + put_cxl_mock_ops(index); +} +EXPORT_SYMBOL_NS_GPL(__wrap_cxl_endpoint_parse_cdat, CXL); + MODULE_LICENSE("GPL v2"); MODULE_IMPORT_NS(ACPI); MODULE_IMPORT_NS(CXL); diff --git a/tools/testing/cxl/test/mock.h b/tools/testing/cxl/test/mock.h index a942237503..d1b0271d28 100644 --- a/tools/testing/cxl/test/mock.h +++ b/tools/testing/cxl/test/mock.h @@ -25,6 +25,7 @@ struct cxl_mock_ops { int (*devm_cxl_add_passthrough_decoder)(struct cxl_port *port); int (*devm_cxl_enumerate_decoders)( struct cxl_hdm *hdm, struct cxl_endpoint_dvsec_info *info); + void (*cxl_endpoint_parse_cdat)(struct cxl_port *port); }; void register_cxl_mock_ops(struct cxl_mock_ops *ops); diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 829f5bdfd2..24451f8f42 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -843,6 +843,7 @@ sub set_value { if ($lvalue =~ /^(TEST|BISECT|CONFIG_BISECT)_TYPE(\[.*\])?$/ && $prvalue !~ /^(config_|)bisect$/ && $prvalue !~ /^build$/ && + $prvalue !~ /^make_warnings_file$/ && $buildonly) { # Note if a test is something other than build, then we diff --git a/tools/testing/kunit/kunit_tool_test.py b/tools/testing/kunit/kunit_tool_test.py index b28c1510be..2beb7327e5 100755 --- a/tools/testing/kunit/kunit_tool_test.py +++ b/tools/testing/kunit/kunit_tool_test.py @@ -331,6 +331,22 @@ class KUnitParserTest(unittest.TestCase): kunit_parser.parse_run_tests(file.readlines()) self.print_mock.assert_any_call(StrContains('suite (1 subtest)')) + def test_parse_attributes(self): + ktap_log = test_data_path('test_parse_attributes.log') + with open(ktap_log) as file: + result = kunit_parser.parse_run_tests(file.readlines()) + + # Test should pass with no errors + self.assertEqual(result.counts, kunit_parser.TestCounts(passed=1, errors=0)) + self.assertEqual(kunit_parser.TestStatus.SUCCESS, result.status) + + # Ensure suite header is parsed correctly + self.print_mock.assert_any_call(StrContains('suite (1 subtest)')) + + # Ensure attributes in correct test log + self.assertContains('# module: example', result.subtests[0].log) + self.assertContains('# test.speed: slow', result.subtests[0].subtests[0].log) + def test_show_test_output_on_failure(self): output = """ KTAP version 1 diff --git a/tools/testing/kunit/test_data/test_parse_attributes.log b/tools/testing/kunit/test_data/test_parse_attributes.log new file mode 100644 index 0000000000..1a13c371fe --- /dev/null +++ b/tools/testing/kunit/test_data/test_parse_attributes.log @@ -0,0 +1,9 @@ +KTAP version 1 +1..1 + KTAP version 1 + # Subtest: suite + # module: example + 1..1 + # test.speed: slow + ok 1 test +ok 1 suite \ No newline at end of file diff --git a/tools/testing/memblock/linux/mmzone.h b/tools/testing/memblock/linux/mmzone.h index 134f8eab07..71546e15bd 100644 --- a/tools/testing/memblock/linux/mmzone.h +++ b/tools/testing/memblock/linux/mmzone.h @@ -17,10 +17,10 @@ enum zone_type { }; #define MAX_NR_ZONES __MAX_NR_ZONES -#define MAX_ORDER 10 -#define MAX_ORDER_NR_PAGES (1 << MAX_ORDER) +#define MAX_PAGE_ORDER 10 +#define MAX_ORDER_NR_PAGES (1 << MAX_PAGE_ORDER) -#define pageblock_order MAX_ORDER +#define pageblock_order MAX_PAGE_ORDER #define pageblock_nr_pages BIT(pageblock_order) #define pageblock_align(pfn) ALIGN((pfn), pageblock_nr_pages) #define pageblock_start_pfn(pfn) ALIGN_DOWN((pfn), pageblock_nr_pages) diff --git a/tools/testing/nvdimm/Kbuild b/tools/testing/nvdimm/Kbuild index 8153251ea3..91a3627f30 100644 --- a/tools/testing/nvdimm/Kbuild +++ b/tools/testing/nvdimm/Kbuild @@ -82,4 +82,6 @@ libnvdimm-$(CONFIG_NVDIMM_KEYS) += $(NVDIMM_SRC)/security.o libnvdimm-y += libnvdimm_test.o libnvdimm-y += config_check.o +KBUILD_CFLAGS := $(filter-out -Wmissing-prototypes -Wmissing-declarations, $(KBUILD_CFLAGS)) + obj-m += test/ diff --git a/tools/testing/nvdimm/test/Kbuild b/tools/testing/nvdimm/test/Kbuild index 197bcb2b7f..003d48f5f2 100644 --- a/tools/testing/nvdimm/test/Kbuild +++ b/tools/testing/nvdimm/test/Kbuild @@ -7,6 +7,7 @@ obj-m += nfit_test_iomap.o ifeq ($(CONFIG_ACPI_NFIT),m) nfit_test-y := nfit.o + obj-m += ndtest.o else nfit_test-y := ndtest.o endif diff --git a/tools/testing/radix-tree/linux.c b/tools/testing/radix-tree/linux.c index 61fe2601cb..4eb442206d 100644 --- a/tools/testing/radix-tree/linux.c +++ b/tools/testing/radix-tree/linux.c @@ -93,13 +93,9 @@ void *kmem_cache_alloc_lru(struct kmem_cache *cachep, struct list_lru *lru, return p; } -void kmem_cache_free_locked(struct kmem_cache *cachep, void *objp) +void __kmem_cache_free_locked(struct kmem_cache *cachep, void *objp) { assert(objp); - uatomic_dec(&nr_allocated); - uatomic_dec(&cachep->nr_allocated); - if (kmalloc_verbose) - printf("Freeing %p to slab\n", objp); if (cachep->nr_objs > 10 || cachep->align) { memset(objp, POISON_FREE, cachep->size); free(objp); @@ -111,6 +107,15 @@ void kmem_cache_free_locked(struct kmem_cache *cachep, void *objp) } } +void kmem_cache_free_locked(struct kmem_cache *cachep, void *objp) +{ + uatomic_dec(&nr_allocated); + uatomic_dec(&cachep->nr_allocated); + if (kmalloc_verbose) + printf("Freeing %p to slab\n", objp); + __kmem_cache_free_locked(cachep, objp); +} + void kmem_cache_free(struct kmem_cache *cachep, void *objp) { pthread_mutex_lock(&cachep->lock); @@ -141,18 +146,17 @@ int kmem_cache_alloc_bulk(struct kmem_cache *cachep, gfp_t gfp, size_t size, if (kmalloc_verbose) pr_debug("Bulk alloc %lu\n", size); - if (!(gfp & __GFP_DIRECT_RECLAIM)) { - if (cachep->non_kernel < size) - return 0; - - cachep->non_kernel -= size; - } - pthread_mutex_lock(&cachep->lock); if (cachep->nr_objs >= size) { struct radix_tree_node *node; for (i = 0; i < size; i++) { + if (!(gfp & __GFP_DIRECT_RECLAIM)) { + if (!cachep->non_kernel) + break; + cachep->non_kernel--; + } + node = cachep->objs; cachep->nr_objs--; cachep->objs = node->parent; @@ -163,11 +167,19 @@ int kmem_cache_alloc_bulk(struct kmem_cache *cachep, gfp_t gfp, size_t size, } else { pthread_mutex_unlock(&cachep->lock); for (i = 0; i < size; i++) { + if (!(gfp & __GFP_DIRECT_RECLAIM)) { + if (!cachep->non_kernel) + break; + cachep->non_kernel--; + } + if (cachep->align) { posix_memalign(&p[i], cachep->align, cachep->size); } else { p[i] = malloc(cachep->size); + if (!p[i]) + break; } if (cachep->ctor) cachep->ctor(p[i]); @@ -176,6 +188,15 @@ int kmem_cache_alloc_bulk(struct kmem_cache *cachep, gfp_t gfp, size_t size, } } + if (i < size) { + size = i; + pthread_mutex_lock(&cachep->lock); + for (i = 0; i < size; i++) + __kmem_cache_free_locked(cachep, p[i]); + pthread_mutex_unlock(&cachep->lock); + return 0; + } + for (i = 0; i < size; i++) { uatomic_inc(&nr_allocated); uatomic_inc(&cachep->nr_allocated); diff --git a/tools/testing/radix-tree/linux/maple_tree.h b/tools/testing/radix-tree/linux/maple_tree.h index 7d8d1f445b..06c89bdcc5 100644 --- a/tools/testing/radix-tree/linux/maple_tree.h +++ b/tools/testing/radix-tree/linux/maple_tree.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0+ */ #define atomic_t int32_t -#include "../../../../include/linux/maple_tree.h" #define atomic_inc(x) uatomic_inc(x) #define atomic_read(x) uatomic_read(x) #define atomic_set(x, y) do {} while (0) #define U8_MAX UCHAR_MAX +#include "../../../../include/linux/maple_tree.h" diff --git a/tools/testing/radix-tree/maple.c b/tools/testing/radix-tree/maple.c index 76a8990bb1..f1caf4bcf9 100644 --- a/tools/testing/radix-tree/maple.c +++ b/tools/testing/radix-tree/maple.c @@ -118,6 +118,7 @@ static noinline void __init check_new_node(struct maple_tree *mt) MT_BUG_ON(mt, mas.alloc == NULL); MT_BUG_ON(mt, mas.alloc->slot[0] == NULL); mas_push_node(&mas, mn); + mas_reset(&mas); mas_nomem(&mas, GFP_KERNEL); /* free */ mtree_unlock(mt); @@ -141,7 +142,7 @@ static noinline void __init check_new_node(struct maple_tree *mt) mn->parent = ma_parent_ptr(mn); ma_free_rcu(mn); - mas.node = MAS_START; + mas.status = ma_start; mas_nomem(&mas, GFP_KERNEL); /* Allocate 3 nodes, will fail. */ mas_node_count(&mas, 3); @@ -158,6 +159,7 @@ static noinline void __init check_new_node(struct maple_tree *mt) /* Ensure we counted 3. */ MT_BUG_ON(mt, mas_allocated(&mas) != 3); /* Free. */ + mas_reset(&mas); mas_nomem(&mas, GFP_KERNEL); /* Set allocation request to 1. */ @@ -272,6 +274,7 @@ static noinline void __init check_new_node(struct maple_tree *mt) ma_free_rcu(mn); MT_BUG_ON(mt, mas_allocated(&mas) != i - j - 1); } + mas_reset(&mas); MT_BUG_ON(mt, mas_nomem(&mas, GFP_KERNEL)); } @@ -294,6 +297,7 @@ static noinline void __init check_new_node(struct maple_tree *mt) smn = smn->slot[0]; /* next. */ } MT_BUG_ON(mt, mas_allocated(&mas) != total); + mas_reset(&mas); mas_nomem(&mas, GFP_KERNEL); /* Free. */ MT_BUG_ON(mt, mas_allocated(&mas) != 0); @@ -441,7 +445,7 @@ static noinline void __init check_new_node(struct maple_tree *mt) mas.node = MA_ERROR(-ENOMEM); mas_node_count(&mas, 10); /* Request */ mas_nomem(&mas, GFP_KERNEL); /* Fill request */ - mas.node = MAS_START; + mas.status = ma_start; MT_BUG_ON(mt, mas_allocated(&mas) != 10); mas_destroy(&mas); @@ -452,7 +456,7 @@ static noinline void __init check_new_node(struct maple_tree *mt) mas.node = MA_ERROR(-ENOMEM); mas_node_count(&mas, 10 + MAPLE_ALLOC_SLOTS - 1); /* Request */ mas_nomem(&mas, GFP_KERNEL); /* Fill request */ - mas.node = MAS_START; + mas.status = ma_start; MT_BUG_ON(mt, mas_allocated(&mas) != 10 + MAPLE_ALLOC_SLOTS - 1); mas_destroy(&mas); @@ -941,10 +945,11 @@ retry: ret = mas_descend_walk(mas, range_min, range_max); if (unlikely(mte_dead_node(mas->node))) { - mas->node = MAS_START; + mas->status = ma_start; goto retry; } + mas->end = mas_data_end(mas); return ret; not_found: @@ -960,17 +965,19 @@ static inline void *mas_range_load(struct ma_state *mas, unsigned long index = mas->index; if (mas_is_none(mas) || mas_is_paused(mas)) - mas->node = MAS_START; + mas->status = ma_start; retry: if (mas_tree_walk(mas, range_min, range_max)) - if (unlikely(mas->node == MAS_ROOT)) + if (unlikely(mas->status == ma_root)) return mas_root(mas); if (likely(mas->offset != MAPLE_NODE_SLOTS)) entry = mas_get_slot(mas, mas->offset); - if (mas_dead_node(mas, index)) + if (mas_is_active(mas) && mte_dead_node(mas->node)) { + mas_set(mas, index); goto retry; + } return entry; } @@ -34132,7 +34139,7 @@ STORE, 140501948112896, 140501948116991, mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE); check_erase2_testset(mt, set27, ARRAY_SIZE(set27)); rcu_barrier(); - MT_BUG_ON(mt, 0 != mtree_load(mt, 140415537422336)); + MT_BUG_ON(mt, NULL != mtree_load(mt, 140415537422336)); mt_set_non_kernel(0); mt_validate(mt); mtree_destroy(mt); @@ -34256,7 +34263,7 @@ STORE, 140501948112896, 140501948116991, mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE); check_erase2_testset(mt, set37, ARRAY_SIZE(set37)); rcu_barrier(); - MT_BUG_ON(mt, 0 != mtree_load(mt, 94637033459712)); + MT_BUG_ON(mt, NULL != mtree_load(mt, 94637033459712)); mt_validate(mt); mtree_destroy(mt); @@ -34264,7 +34271,7 @@ STORE, 140501948112896, 140501948116991, mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE); check_erase2_testset(mt, set38, ARRAY_SIZE(set38)); rcu_barrier(); - MT_BUG_ON(mt, 0 != mtree_load(mt, 94637033459712)); + MT_BUG_ON(mt, NULL != mtree_load(mt, 94637033459712)); mt_validate(mt); mtree_destroy(mt); @@ -35336,7 +35343,7 @@ static void mas_dfs_preorder(struct ma_state *mas) unsigned char end, slot = 0; unsigned long *pivots; - if (mas->node == MAS_START) { + if (mas->status == ma_start) { mas_start(mas); return; } @@ -35373,7 +35380,7 @@ walk_up: return; done: - mas->node = MAS_NONE; + mas->status = ma_none; } @@ -35832,7 +35839,7 @@ static noinline void __init check_nomem(struct maple_tree *mt) mas_store(&ms, &ms); /* insert 1 -> &ms, fails. */ MT_BUG_ON(mt, ms.node != MA_ERROR(-ENOMEM)); mas_nomem(&ms, GFP_KERNEL); /* Node allocated in here. */ - MT_BUG_ON(mt, ms.node != MAS_START); + MT_BUG_ON(mt, ms.status != ma_start); mtree_unlock(mt); MT_BUG_ON(mt, mtree_insert(mt, 2, mt, GFP_KERNEL) != 0); mtree_lock(mt); @@ -35857,6 +35864,363 @@ static noinline void __init check_locky(struct maple_tree *mt) mt_clear_in_rcu(mt); } +/* + * Compares two nodes except for the addresses stored in the nodes. + * Returns zero if they are the same, otherwise returns non-zero. + */ +static int __init compare_node(struct maple_enode *enode_a, + struct maple_enode *enode_b) +{ + struct maple_node *node_a, *node_b; + struct maple_node a, b; + void **slots_a, **slots_b; /* Do not use the rcu tag. */ + enum maple_type type; + int i; + + if (((unsigned long)enode_a & MAPLE_NODE_MASK) != + ((unsigned long)enode_b & MAPLE_NODE_MASK)) { + pr_err("The lower 8 bits of enode are different.\n"); + return -1; + } + + type = mte_node_type(enode_a); + node_a = mte_to_node(enode_a); + node_b = mte_to_node(enode_b); + a = *node_a; + b = *node_b; + + /* Do not compare addresses. */ + if (ma_is_root(node_a) || ma_is_root(node_b)) { + a.parent = (struct maple_pnode *)((unsigned long)a.parent & + MA_ROOT_PARENT); + b.parent = (struct maple_pnode *)((unsigned long)b.parent & + MA_ROOT_PARENT); + } else { + a.parent = (struct maple_pnode *)((unsigned long)a.parent & + MAPLE_NODE_MASK); + b.parent = (struct maple_pnode *)((unsigned long)b.parent & + MAPLE_NODE_MASK); + } + + if (a.parent != b.parent) { + pr_err("The lower 8 bits of parents are different. %p %p\n", + a.parent, b.parent); + return -1; + } + + /* + * If it is a leaf node, the slots do not contain the node address, and + * no special processing of slots is required. + */ + if (ma_is_leaf(type)) + goto cmp; + + slots_a = ma_slots(&a, type); + slots_b = ma_slots(&b, type); + + for (i = 0; i < mt_slots[type]; i++) { + if (!slots_a[i] && !slots_b[i]) + break; + + if (!slots_a[i] || !slots_b[i]) { + pr_err("The number of slots is different.\n"); + return -1; + } + + /* Do not compare addresses in slots. */ + ((unsigned long *)slots_a)[i] &= MAPLE_NODE_MASK; + ((unsigned long *)slots_b)[i] &= MAPLE_NODE_MASK; + } + +cmp: + /* + * Compare all contents of two nodes, including parent (except address), + * slots (except address), pivots, gaps and metadata. + */ + return memcmp(&a, &b, sizeof(struct maple_node)); +} + +/* + * Compare two trees and return 0 if they are the same, non-zero otherwise. + */ +static int __init compare_tree(struct maple_tree *mt_a, struct maple_tree *mt_b) +{ + MA_STATE(mas_a, mt_a, 0, 0); + MA_STATE(mas_b, mt_b, 0, 0); + + if (mt_a->ma_flags != mt_b->ma_flags) { + pr_err("The flags of the two trees are different.\n"); + return -1; + } + + mas_dfs_preorder(&mas_a); + mas_dfs_preorder(&mas_b); + + if (mas_is_ptr(&mas_a) || mas_is_ptr(&mas_b)) { + if (!(mas_is_ptr(&mas_a) && mas_is_ptr(&mas_b))) { + pr_err("One is ma_root and the other is not.\n"); + return -1; + } + return 0; + } + + while (!mas_is_none(&mas_a) || !mas_is_none(&mas_b)) { + + if (mas_is_none(&mas_a) || mas_is_none(&mas_b)) { + pr_err("One is ma_none and the other is not.\n"); + return -1; + } + + if (mas_a.min != mas_b.min || + mas_a.max != mas_b.max) { + pr_err("mas->min, mas->max do not match.\n"); + return -1; + } + + if (compare_node(mas_a.node, mas_b.node)) { + pr_err("The contents of nodes %p and %p are different.\n", + mas_a.node, mas_b.node); + mt_dump(mt_a, mt_dump_dec); + mt_dump(mt_b, mt_dump_dec); + return -1; + } + + mas_dfs_preorder(&mas_a); + mas_dfs_preorder(&mas_b); + } + + return 0; +} + +static __init void mas_subtree_max_range(struct ma_state *mas) +{ + unsigned long limit = mas->max; + MA_STATE(newmas, mas->tree, 0, 0); + void *entry; + + mas_for_each(mas, entry, limit) { + if (mas->last - mas->index >= + newmas.last - newmas.index) { + newmas = *mas; + } + } + + *mas = newmas; +} + +/* + * build_full_tree() - Build a full tree. + * @mt: The tree to build. + * @flags: Use @flags to build the tree. + * @height: The height of the tree to build. + * + * Build a tree with full leaf nodes and internal nodes. Note that the height + * should not exceed 3, otherwise it will take a long time to build. + * Return: zero if the build is successful, non-zero if it fails. + */ +static __init int build_full_tree(struct maple_tree *mt, unsigned int flags, + int height) +{ + MA_STATE(mas, mt, 0, 0); + unsigned long step; + int ret = 0, cnt = 1; + enum maple_type type; + + mt_init_flags(mt, flags); + mtree_insert_range(mt, 0, ULONG_MAX, xa_mk_value(5), GFP_KERNEL); + + mtree_lock(mt); + + while (1) { + mas_set(&mas, 0); + if (mt_height(mt) < height) { + mas.max = ULONG_MAX; + goto store; + } + + while (1) { + mas_dfs_preorder(&mas); + if (mas_is_none(&mas)) + goto unlock; + + type = mte_node_type(mas.node); + if (mas_data_end(&mas) + 1 < mt_slots[type]) { + mas_set(&mas, mas.min); + goto store; + } + } +store: + mas_subtree_max_range(&mas); + step = mas.last - mas.index; + if (step < 1) { + ret = -1; + goto unlock; + } + + step /= 2; + mas.last = mas.index + step; + mas_store_gfp(&mas, xa_mk_value(5), + GFP_KERNEL); + ++cnt; + } +unlock: + mtree_unlock(mt); + + MT_BUG_ON(mt, mt_height(mt) != height); + /* pr_info("height:%u number of elements:%d\n", mt_height(mt), cnt); */ + return ret; +} + +static noinline void __init check_mtree_dup(struct maple_tree *mt) +{ + DEFINE_MTREE(new); + int i, j, ret, count = 0; + unsigned int rand_seed = 17, rand; + + /* store a value at [0, 0] */ + mt_init_flags(mt, 0); + mtree_store_range(mt, 0, 0, xa_mk_value(0), GFP_KERNEL); + ret = mtree_dup(mt, &new, GFP_KERNEL); + MT_BUG_ON(&new, ret); + mt_validate(&new); + if (compare_tree(mt, &new)) + MT_BUG_ON(&new, 1); + + mtree_destroy(mt); + mtree_destroy(&new); + + /* The two trees have different attributes. */ + mt_init_flags(mt, 0); + mt_init_flags(&new, MT_FLAGS_ALLOC_RANGE); + ret = mtree_dup(mt, &new, GFP_KERNEL); + MT_BUG_ON(&new, ret != -EINVAL); + mtree_destroy(mt); + mtree_destroy(&new); + + /* The new tree is not empty */ + mt_init_flags(mt, 0); + mt_init_flags(&new, 0); + mtree_store(&new, 5, xa_mk_value(5), GFP_KERNEL); + ret = mtree_dup(mt, &new, GFP_KERNEL); + MT_BUG_ON(&new, ret != -EINVAL); + mtree_destroy(mt); + mtree_destroy(&new); + + /* Test for duplicating full trees. */ + for (i = 1; i <= 3; i++) { + ret = build_full_tree(mt, 0, i); + MT_BUG_ON(mt, ret); + mt_init_flags(&new, 0); + + ret = mtree_dup(mt, &new, GFP_KERNEL); + MT_BUG_ON(&new, ret); + mt_validate(&new); + if (compare_tree(mt, &new)) + MT_BUG_ON(&new, 1); + + mtree_destroy(mt); + mtree_destroy(&new); + } + + for (i = 1; i <= 3; i++) { + ret = build_full_tree(mt, MT_FLAGS_ALLOC_RANGE, i); + MT_BUG_ON(mt, ret); + mt_init_flags(&new, MT_FLAGS_ALLOC_RANGE); + + ret = mtree_dup(mt, &new, GFP_KERNEL); + MT_BUG_ON(&new, ret); + mt_validate(&new); + if (compare_tree(mt, &new)) + MT_BUG_ON(&new, 1); + + mtree_destroy(mt); + mtree_destroy(&new); + } + + /* Test for normal duplicating. */ + for (i = 0; i < 1000; i += 3) { + if (i & 1) { + mt_init_flags(mt, 0); + mt_init_flags(&new, 0); + } else { + mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE); + mt_init_flags(&new, MT_FLAGS_ALLOC_RANGE); + } + + for (j = 0; j < i; j++) { + mtree_store_range(mt, j * 10, j * 10 + 5, + xa_mk_value(j), GFP_KERNEL); + } + + ret = mtree_dup(mt, &new, GFP_KERNEL); + MT_BUG_ON(&new, ret); + mt_validate(&new); + if (compare_tree(mt, &new)) + MT_BUG_ON(&new, 1); + + mtree_destroy(mt); + mtree_destroy(&new); + } + + /* Test memory allocation failed. */ + mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE); + for (i = 0; i < 30; i += 3) { + mtree_store_range(mt, j * 10, j * 10 + 5, + xa_mk_value(j), GFP_KERNEL); + } + + /* Failed at the first node. */ + mt_init_flags(&new, MT_FLAGS_ALLOC_RANGE); + mt_set_non_kernel(0); + ret = mtree_dup(mt, &new, GFP_NOWAIT); + mt_set_non_kernel(0); + MT_BUG_ON(&new, ret != -ENOMEM); + mtree_destroy(mt); + mtree_destroy(&new); + + /* Random maple tree fails at a random node. */ + for (i = 0; i < 1000; i += 3) { + if (i & 1) { + mt_init_flags(mt, 0); + mt_init_flags(&new, 0); + } else { + mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE); + mt_init_flags(&new, MT_FLAGS_ALLOC_RANGE); + } + + for (j = 0; j < i; j++) { + mtree_store_range(mt, j * 10, j * 10 + 5, + xa_mk_value(j), GFP_KERNEL); + } + /* + * The rand() library function is not used, so we can generate + * the same random numbers on any platform. + */ + rand_seed = rand_seed * 1103515245 + 12345; + rand = rand_seed / 65536 % 128; + mt_set_non_kernel(rand); + + ret = mtree_dup(mt, &new, GFP_NOWAIT); + mt_set_non_kernel(0); + if (ret != 0) { + MT_BUG_ON(&new, ret != -ENOMEM); + count++; + mtree_destroy(mt); + continue; + } + + mt_validate(&new); + if (compare_tree(mt, &new)) + MT_BUG_ON(&new, 1); + + mtree_destroy(mt); + mtree_destroy(&new); + } + + /* pr_info("mtree_dup() fail %d times\n", count); */ + BUG_ON(!count); +} + extern void test_kmem_cache_bulk(void); void farmer_tests(void) @@ -35904,6 +36268,10 @@ void farmer_tests(void) check_null_expand(&tree); mtree_destroy(&tree); + mt_init_flags(&tree, 0); + check_mtree_dup(&tree); + mtree_destroy(&tree); + /* RCU testing */ mt_init_flags(&tree, 0); check_erase_testset(&tree); @@ -35938,7 +36306,9 @@ void farmer_tests(void) void maple_tree_tests(void) { +#if !defined(BENCH) farmer_tests(); +#endif maple_tree_seed(); maple_tree_harvest(); } diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 8247a7c69c..15b6a111c3 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -26,6 +26,8 @@ TARGETS += filesystems TARGETS += filesystems/binderfs TARGETS += filesystems/epoll TARGETS += filesystems/fat +TARGETS += filesystems/overlayfs +TARGETS += filesystems/statmount TARGETS += firmware TARGETS += fpu TARGETS += ftrace @@ -43,6 +45,7 @@ TARGETS += landlock TARGETS += lib TARGETS += livepatch TARGETS += lkdtm +TARGETS += lsm TARGETS += membarrier TARGETS += memfd TARGETS += memory-hotplug @@ -58,6 +61,7 @@ TARGETS += net/forwarding TARGETS += net/hsr TARGETS += net/mptcp TARGETS += net/openvswitch +TARGETS += net/tcp_ao TARGETS += netfilter TARGETS += nsfs TARGETS += perf_events diff --git a/tools/testing/selftests/alsa/mixer-test.c b/tools/testing/selftests/alsa/mixer-test.c index df942149c6..1c04e5f638 100644 --- a/tools/testing/selftests/alsa/mixer-test.c +++ b/tools/testing/selftests/alsa/mixer-test.c @@ -347,7 +347,7 @@ static bool ctl_value_index_valid(struct ctl_data *ctl, } if (int_val >= snd_ctl_elem_info_get_items(ctl->info)) { - ksft_print_msg("%s.%d value %ld more than item count %ld\n", + ksft_print_msg("%s.%d value %ld more than item count %u\n", ctl->name, index, int_val, snd_ctl_elem_info_get_items(ctl->info)); return false; diff --git a/tools/testing/selftests/arm64/abi/tpidr2.c b/tools/testing/selftests/arm64/abi/tpidr2.c index 351a098b50..02ee3a91b7 100644 --- a/tools/testing/selftests/arm64/abi/tpidr2.c +++ b/tools/testing/selftests/arm64/abi/tpidr2.c @@ -254,6 +254,12 @@ static int write_clone_read(void) putnum(++tests_run); \ putstr(" " #name "\n"); +#define skip_test(name) \ + tests_skipped++; \ + putstr("ok "); \ + putnum(++tests_run); \ + putstr(" # SKIP " #name "\n"); + int main(int argc, char **argv) { int ret, i; @@ -283,13 +289,11 @@ int main(int argc, char **argv) } else { putstr("# SME support not present\n"); - for (i = 0; i < EXPECTED_TESTS; i++) { - putstr("ok "); - putnum(i); - putstr(" skipped, TPIDR2 not supported\n"); - } - - tests_skipped += EXPECTED_TESTS; + skip_test(default_value); + skip_test(write_read); + skip_test(write_sleep_read); + skip_test(write_fork_read); + skip_test(write_clone_read); } print_summary(); diff --git a/tools/testing/selftests/arm64/fp/sve-test.S b/tools/testing/selftests/arm64/fp/sve-test.S index 547d077e35..fff60e2a25 100644 --- a/tools/testing/selftests/arm64/fp/sve-test.S +++ b/tools/testing/selftests/arm64/fp/sve-test.S @@ -515,6 +515,10 @@ function barf mov x11, x1 // actual data mov x12, x2 // data size +#ifdef SSVE + mrs x13, S3_3_C4_C2_2 +#endif + puts "Mismatch: PID=" mov x0, x20 bl putdec @@ -534,6 +538,12 @@ function barf bl dumphex puts "]\n" +#ifdef SSVE + puts "\tSVCR: " + mov x0, x13 + bl putdecn +#endif + mov x8, #__NR_getpid svc #0 // fpsimd.c acitivty log dump hack diff --git a/tools/testing/selftests/arm64/fp/vec-syscfg.c b/tools/testing/selftests/arm64/fp/vec-syscfg.c index 5f648b97a0..ea9c7d4779 100644 --- a/tools/testing/selftests/arm64/fp/vec-syscfg.c +++ b/tools/testing/selftests/arm64/fp/vec-syscfg.c @@ -66,6 +66,11 @@ static struct vec_data vec_data[] = { }, }; +static bool vec_type_supported(struct vec_data *data) +{ + return getauxval(data->hwcap_type) & data->hwcap; +} + static int stdio_read_integer(FILE *f, const char *what, int *val) { int n = 0; @@ -564,8 +569,11 @@ static void prctl_set_all_vqs(struct vec_data *data) return; } - for (i = 0; i < ARRAY_SIZE(vec_data); i++) + for (i = 0; i < ARRAY_SIZE(vec_data); i++) { + if (!vec_type_supported(&vec_data[i])) + continue; orig_vls[i] = vec_data[i].rdvl(); + } for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; vq++) { vl = sve_vl_from_vq(vq); @@ -594,7 +602,7 @@ static void prctl_set_all_vqs(struct vec_data *data) if (&vec_data[i] == data) continue; - if (!(getauxval(vec_data[i].hwcap_type) & vec_data[i].hwcap)) + if (!vec_type_supported(&vec_data[i])) continue; if (vec_data[i].rdvl() != orig_vls[i]) { @@ -765,7 +773,7 @@ int main(void) struct vec_data *data = &vec_data[i]; unsigned long supported; - supported = getauxval(data->hwcap_type) & data->hwcap; + supported = vec_type_supported(data); if (!supported) all_supported = false; diff --git a/tools/testing/selftests/arm64/fp/za-test.S b/tools/testing/selftests/arm64/fp/za-test.S index 9dcd709113..095b455316 100644 --- a/tools/testing/selftests/arm64/fp/za-test.S +++ b/tools/testing/selftests/arm64/fp/za-test.S @@ -333,6 +333,9 @@ function barf // mov w8, #__NR_exit // svc #0 // end hack + + mrs x13, S3_3_C4_C2_2 + smstop mov x10, x0 // expected data mov x11, x1 // actual data @@ -356,6 +359,9 @@ function barf mov x1, x12 bl dumphex puts "]\n" + puts "\tSVCR: " + mov x0, x13 + bl putdecn mov x8, #__NR_getpid svc #0 diff --git a/tools/testing/selftests/arm64/fp/zt-test.S b/tools/testing/selftests/arm64/fp/zt-test.S index d632863976..b5c81e81a3 100644 --- a/tools/testing/selftests/arm64/fp/zt-test.S +++ b/tools/testing/selftests/arm64/fp/zt-test.S @@ -267,6 +267,8 @@ function barf // mov w8, #__NR_exit // svc #0 // end hack + + mrs x13, S3_3_C4_C2_2 smstop mov x10, x0 // expected data mov x11, x1 // actual data @@ -287,6 +289,9 @@ function barf mov x1, x12 bl dumphex puts "]\n" + puts "\tSVCR: " + mov x0, x13 + bl putdecn mov x8, #__NR_getpid svc #0 diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 9c27b67bc7..fd15017ed3 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -18,7 +18,7 @@ else GENDIR := $(abspath ../../../../include/generated) endif GENHDR := $(GENDIR)/autoconf.h -HOSTPKG_CONFIG := pkg-config +PKG_CONFIG ?= $(CROSS_COMPILE)pkg-config ifneq ($(wildcard $(GENHDR)),) GENFLAGS := -DHAVE_GENHDR @@ -29,13 +29,17 @@ SAN_CFLAGS ?= SAN_LDFLAGS ?= $(SAN_CFLAGS) RELEASE ?= OPT_FLAGS ?= $(if $(RELEASE),-O2,-O0) + +LIBELF_CFLAGS := $(shell $(PKG_CONFIG) libelf --cflags 2>/dev/null) +LIBELF_LIBS := $(shell $(PKG_CONFIG) libelf --libs 2>/dev/null || echo -lelf) + CFLAGS += -g $(OPT_FLAGS) -rdynamic \ -Wall -Werror \ - $(GENFLAGS) $(SAN_CFLAGS) \ + $(GENFLAGS) $(SAN_CFLAGS) $(LIBELF_CFLAGS) \ -I$(CURDIR) -I$(INCLUDE_DIR) -I$(GENDIR) -I$(LIBDIR) \ -I$(TOOLSINCDIR) -I$(APIDIR) -I$(OUTPUT) LDFLAGS += $(SAN_LDFLAGS) -LDLIBS += -lelf -lz -lrt -lpthread +LDLIBS += $(LIBELF_LIBS) -lz -lrt -lpthread ifneq ($(LLVM),) # Silence some warnings when compiled with clang @@ -219,9 +223,9 @@ $(OUTPUT)/urandom_read: urandom_read.c urandom_read_aux.c $(OUTPUT)/liburandom_r $(OUTPUT)/sign-file: ../../../../scripts/sign-file.c $(call msg,SIGN-FILE,,$@) - $(Q)$(CC) $(shell $(HOSTPKG_CONFIG) --cflags libcrypto 2> /dev/null) \ + $(Q)$(CC) $(shell $(PKG_CONFIG) --cflags libcrypto 2> /dev/null) \ $< -o $@ \ - $(shell $(HOSTPKG_CONFIG) --libs libcrypto 2> /dev/null || echo -lcrypto) + $(shell $(PKG_CONFIG) --libs libcrypto 2> /dev/null || echo -lcrypto) $(OUTPUT)/bpf_testmod.ko: $(VMLINUX_BTF) $(RESOLVE_BTFIDS) $(wildcard bpf_testmod/Makefile bpf_testmod/*.[ch]) $(call msg,MOD,,$@) @@ -379,6 +383,7 @@ CLANG_SYS_INCLUDES = $(call get_sys_includes,$(CLANG),$(CLANG_TARGET_ARCH)) BPF_CFLAGS = -g -Wall -Werror -D__TARGET_ARCH_$(SRCARCH) $(MENDIAN) \ -I$(INCLUDE_DIR) -I$(CURDIR) -I$(APIDIR) \ -I$(abspath $(OUTPUT)/../usr/include) +# TODO: enable me -Wsign-compare CLANG_CFLAGS = $(CLANG_SYS_INCLUDES) \ -Wno-compare-distinct-pointer-types diff --git a/tools/testing/selftests/bpf/README.rst b/tools/testing/selftests/bpf/README.rst index cb9b95702a..9af79c7a9b 100644 --- a/tools/testing/selftests/bpf/README.rst +++ b/tools/testing/selftests/bpf/README.rst @@ -77,7 +77,7 @@ In case of linker errors when running selftests, try using static linking: .. code-block:: console - $ LDLIBS=-static vmtest.sh + $ LDLIBS=-static PKG_CONFIG='pkg-config --static' vmtest.sh .. note:: Some distros may not support static linking. diff --git a/tools/testing/selftests/bpf/benchs/bench_htab_mem.c b/tools/testing/selftests/bpf/benchs/bench_htab_mem.c index 9146d3f414..926ee82214 100644 --- a/tools/testing/selftests/bpf/benchs/bench_htab_mem.c +++ b/tools/testing/selftests/bpf/benchs/bench_htab_mem.c @@ -335,6 +335,7 @@ static void htab_mem_report_final(struct bench_res res[], int res_cnt) " peak memory usage %7.2lfMiB\n", loop_mean, loop_stddev, mem_mean, mem_stddev, peak_mem / 1048576.0); + close(ctx.fd); cleanup_cgroup_environment(); } diff --git a/tools/testing/selftests/bpf/bpf_experimental.h b/tools/testing/selftests/bpf/bpf_experimental.h index 1386baf9ae..f44875f8b3 100644 --- a/tools/testing/selftests/bpf/bpf_experimental.h +++ b/tools/testing/selftests/bpf/bpf_experimental.h @@ -254,173 +254,97 @@ extern void bpf_throw(u64 cookie) __ksym; } \ }) -/* Description - * Assert that a conditional expression is true. - * Returns - * Void. - * Throws - * An exception with the value zero when the assertion fails. - */ -#define bpf_assert(cond) if (!(cond)) bpf_throw(0); - -/* Description - * Assert that a conditional expression is true. - * Returns - * Void. - * Throws - * An exception with the specified value when the assertion fails. - */ -#define bpf_assert_with(cond, value) if (!(cond)) bpf_throw(value); - -/* Description - * Assert that LHS is equal to RHS. This statement updates the known value - * of LHS during verification. Note that RHS must be a constant value, and - * must fit within the data type of LHS. - * Returns - * Void. - * Throws - * An exception with the value zero when the assertion fails. - */ -#define bpf_assert_eq(LHS, RHS) \ - ({ \ - barrier_var(LHS); \ - __bpf_assert_op(LHS, ==, RHS, 0, true); \ - }) - -/* Description - * Assert that LHS is equal to RHS. This statement updates the known value - * of LHS during verification. Note that RHS must be a constant value, and - * must fit within the data type of LHS. - * Returns - * Void. - * Throws - * An exception with the specified value when the assertion fails. - */ -#define bpf_assert_eq_with(LHS, RHS, value) \ - ({ \ - barrier_var(LHS); \ - __bpf_assert_op(LHS, ==, RHS, value, true); \ - }) - -/* Description - * Assert that LHS is less than RHS. This statement updates the known - * bounds of LHS during verification. Note that RHS must be a constant - * value, and must fit within the data type of LHS. - * Returns - * Void. - * Throws - * An exception with the value zero when the assertion fails. - */ -#define bpf_assert_lt(LHS, RHS) \ - ({ \ - barrier_var(LHS); \ - __bpf_assert_op(LHS, <, RHS, 0, false); \ - }) - -/* Description - * Assert that LHS is less than RHS. This statement updates the known - * bounds of LHS during verification. Note that RHS must be a constant - * value, and must fit within the data type of LHS. - * Returns - * Void. - * Throws - * An exception with the specified value when the assertion fails. - */ -#define bpf_assert_lt_with(LHS, RHS, value) \ - ({ \ - barrier_var(LHS); \ - __bpf_assert_op(LHS, <, RHS, value, false); \ - }) +#define __cmp_cannot_be_signed(x) \ + __builtin_strcmp(#x, "==") == 0 || __builtin_strcmp(#x, "!=") == 0 || \ + __builtin_strcmp(#x, "&") == 0 -/* Description - * Assert that LHS is greater than RHS. This statement updates the known - * bounds of LHS during verification. Note that RHS must be a constant - * value, and must fit within the data type of LHS. - * Returns - * Void. - * Throws - * An exception with the value zero when the assertion fails. - */ -#define bpf_assert_gt(LHS, RHS) \ - ({ \ - barrier_var(LHS); \ - __bpf_assert_op(LHS, >, RHS, 0, false); \ - }) +#define __is_signed_type(type) (((type)(-1)) < (type)1) -/* Description - * Assert that LHS is greater than RHS. This statement updates the known - * bounds of LHS during verification. Note that RHS must be a constant - * value, and must fit within the data type of LHS. - * Returns - * Void. - * Throws - * An exception with the specified value when the assertion fails. +#define __bpf_cmp(LHS, OP, SIGN, PRED, RHS, DEFAULT) \ + ({ \ + __label__ l_true; \ + bool ret = DEFAULT; \ + asm volatile goto("if %[lhs] " SIGN #OP " %[rhs] goto %l[l_true]" \ + :: [lhs] "r"((short)LHS), [rhs] PRED (RHS) :: l_true); \ + ret = !DEFAULT; \ +l_true: \ + ret; \ + }) + +/* C type conversions coupled with comparison operator are tricky. + * Make sure BPF program is compiled with -Wsign-compare then + * __lhs OP __rhs below will catch the mistake. + * Be aware that we check only __lhs to figure out the sign of compare. */ -#define bpf_assert_gt_with(LHS, RHS, value) \ - ({ \ - barrier_var(LHS); \ - __bpf_assert_op(LHS, >, RHS, value, false); \ - }) +#define _bpf_cmp(LHS, OP, RHS, NOFLIP) \ + ({ \ + typeof(LHS) __lhs = (LHS); \ + typeof(RHS) __rhs = (RHS); \ + bool ret; \ + _Static_assert(sizeof(&(LHS)), "1st argument must be an lvalue expression"); \ + (void)(__lhs OP __rhs); \ + if (__cmp_cannot_be_signed(OP) || !__is_signed_type(typeof(__lhs))) { \ + if (sizeof(__rhs) == 8) \ + ret = __bpf_cmp(__lhs, OP, "", "r", __rhs, NOFLIP); \ + else \ + ret = __bpf_cmp(__lhs, OP, "", "i", __rhs, NOFLIP); \ + } else { \ + if (sizeof(__rhs) == 8) \ + ret = __bpf_cmp(__lhs, OP, "s", "r", __rhs, NOFLIP); \ + else \ + ret = __bpf_cmp(__lhs, OP, "s", "i", __rhs, NOFLIP); \ + } \ + ret; \ + }) + +#ifndef bpf_cmp_unlikely +#define bpf_cmp_unlikely(LHS, OP, RHS) _bpf_cmp(LHS, OP, RHS, true) +#endif -/* Description - * Assert that LHS is less than or equal to RHS. This statement updates the - * known bounds of LHS during verification. Note that RHS must be a - * constant value, and must fit within the data type of LHS. - * Returns - * Void. - * Throws - * An exception with the value zero when the assertion fails. - */ -#define bpf_assert_le(LHS, RHS) \ - ({ \ - barrier_var(LHS); \ - __bpf_assert_op(LHS, <=, RHS, 0, false); \ - }) +#ifndef bpf_cmp_likely +#define bpf_cmp_likely(LHS, OP, RHS) \ + ({ \ + bool ret; \ + if (__builtin_strcmp(#OP, "==") == 0) \ + ret = _bpf_cmp(LHS, !=, RHS, false); \ + else if (__builtin_strcmp(#OP, "!=") == 0) \ + ret = _bpf_cmp(LHS, ==, RHS, false); \ + else if (__builtin_strcmp(#OP, "<=") == 0) \ + ret = _bpf_cmp(LHS, >, RHS, false); \ + else if (__builtin_strcmp(#OP, "<") == 0) \ + ret = _bpf_cmp(LHS, >=, RHS, false); \ + else if (__builtin_strcmp(#OP, ">") == 0) \ + ret = _bpf_cmp(LHS, <=, RHS, false); \ + else if (__builtin_strcmp(#OP, ">=") == 0) \ + ret = _bpf_cmp(LHS, <, RHS, false); \ + else \ + (void) "bug"; \ + ret; \ + }) +#endif -/* Description - * Assert that LHS is less than or equal to RHS. This statement updates the - * known bounds of LHS during verification. Note that RHS must be a - * constant value, and must fit within the data type of LHS. - * Returns - * Void. - * Throws - * An exception with the specified value when the assertion fails. - */ -#define bpf_assert_le_with(LHS, RHS, value) \ - ({ \ - barrier_var(LHS); \ - __bpf_assert_op(LHS, <=, RHS, value, false); \ - }) +#ifndef bpf_nop_mov +#define bpf_nop_mov(var) \ + asm volatile("%[reg]=%[reg]"::[reg]"r"((short)var)) +#endif /* Description - * Assert that LHS is greater than or equal to RHS. This statement updates - * the known bounds of LHS during verification. Note that RHS must be a - * constant value, and must fit within the data type of LHS. + * Assert that a conditional expression is true. * Returns * Void. * Throws * An exception with the value zero when the assertion fails. */ -#define bpf_assert_ge(LHS, RHS) \ - ({ \ - barrier_var(LHS); \ - __bpf_assert_op(LHS, >=, RHS, 0, false); \ - }) +#define bpf_assert(cond) if (!(cond)) bpf_throw(0); /* Description - * Assert that LHS is greater than or equal to RHS. This statement updates - * the known bounds of LHS during verification. Note that RHS must be a - * constant value, and must fit within the data type of LHS. + * Assert that a conditional expression is true. * Returns * Void. * Throws * An exception with the specified value when the assertion fails. */ -#define bpf_assert_ge_with(LHS, RHS, value) \ - ({ \ - barrier_var(LHS); \ - __bpf_assert_op(LHS, >=, RHS, value, false); \ - }) +#define bpf_assert_with(cond, value) if (!(cond)) bpf_throw(value); /* Description * Assert that LHS is in the range [BEG, END] (inclusive of both). This diff --git a/tools/testing/selftests/bpf/bpf_kfuncs.h b/tools/testing/selftests/bpf/bpf_kfuncs.h index 5ca68ff0b5..b4e78c1eb3 100644 --- a/tools/testing/selftests/bpf/bpf_kfuncs.h +++ b/tools/testing/selftests/bpf/bpf_kfuncs.h @@ -55,4 +55,14 @@ void *bpf_cast_to_kern_ctx(void *) __ksym; void *bpf_rdonly_cast(void *obj, __u32 btf_id) __ksym; +extern int bpf_get_file_xattr(struct file *file, const char *name, + struct bpf_dynptr *value_ptr) __ksym; +extern int bpf_get_fsverity_digest(struct file *file, struct bpf_dynptr *digest_ptr) __ksym; + +extern struct bpf_key *bpf_lookup_user_key(__u32 serial, __u64 flags) __ksym; +extern struct bpf_key *bpf_lookup_system_key(__u64 id) __ksym; +extern void bpf_key_put(struct bpf_key *key) __ksym; +extern int bpf_verify_pkcs7_signature(struct bpf_dynptr *data_ptr, + struct bpf_dynptr *sig_ptr, + struct bpf_key *trusted_keyring) __ksym; #endif diff --git a/tools/testing/selftests/bpf/cgroup_helpers.c b/tools/testing/selftests/bpf/cgroup_helpers.c index 10b5f42e65..19be9c63d5 100644 --- a/tools/testing/selftests/bpf/cgroup_helpers.c +++ b/tools/testing/selftests/bpf/cgroup_helpers.c @@ -45,9 +45,12 @@ #define format_parent_cgroup_path(buf, path) \ format_cgroup_path_pid(buf, path, getppid()) -#define format_classid_path(buf) \ - snprintf(buf, sizeof(buf), "%s%s", NETCLS_MOUNT_PATH, \ - CGROUP_WORK_DIR) +#define format_classid_path_pid(buf, pid) \ + snprintf(buf, sizeof(buf), "%s%s%d", NETCLS_MOUNT_PATH, \ + CGROUP_WORK_DIR, pid) + +#define format_classid_path(buf) \ + format_classid_path_pid(buf, getpid()) static __thread bool cgroup_workdir_mounted; @@ -419,26 +422,23 @@ int create_and_get_cgroup(const char *relative_path) } /** - * get_cgroup_id() - Get cgroup id for a particular cgroup path - * @relative_path: The cgroup path, relative to the workdir, to join + * get_cgroup_id_from_path - Get cgroup id for a particular cgroup path + * @cgroup_workdir: The absolute cgroup path * * On success, it returns the cgroup id. On failure it returns 0, * which is an invalid cgroup id. * If there is a failure, it prints the error to stderr. */ -unsigned long long get_cgroup_id(const char *relative_path) +unsigned long long get_cgroup_id_from_path(const char *cgroup_workdir) { int dirfd, err, flags, mount_id, fhsize; union { unsigned long long cgid; unsigned char raw_bytes[8]; } id; - char cgroup_workdir[PATH_MAX + 1]; struct file_handle *fhp, *fhp2; unsigned long long ret = 0; - format_cgroup_path(cgroup_workdir, relative_path); - dirfd = AT_FDCWD; flags = 0; fhsize = sizeof(*fhp); @@ -474,6 +474,14 @@ free_mem: return ret; } +unsigned long long get_cgroup_id(const char *relative_path) +{ + char cgroup_workdir[PATH_MAX + 1]; + + format_cgroup_path(cgroup_workdir, relative_path); + return get_cgroup_id_from_path(cgroup_workdir); +} + int cgroup_setup_and_join(const char *path) { int cg_fd; @@ -551,15 +559,16 @@ int setup_classid_environment(void) /** * set_classid() - Set a cgroupv1 net_cls classid - * @id: the numeric classid * - * Writes the passed classid into the cgroup work dir's net_cls.classid + * Writes the classid into the cgroup work dir's net_cls.classid * file in order to later on trigger socket tagging. * + * We leverage the current pid as the classid, ensuring unique identification. + * * On success, it returns 0, otherwise on failure it returns 1. If there * is a failure, it prints the error to stderr. */ -int set_classid(unsigned int id) +int set_classid(void) { char cgroup_workdir[PATH_MAX - 42]; char cgroup_classid_path[PATH_MAX + 1]; @@ -575,7 +584,7 @@ int set_classid(unsigned int id) return 1; } - if (dprintf(fd, "%u\n", id) < 0) { + if (dprintf(fd, "%u\n", getpid()) < 0) { log_err("Setting cgroup classid"); rc = 1; } @@ -617,3 +626,82 @@ void cleanup_classid_environment(void) join_cgroup_from_top(NETCLS_MOUNT_PATH); nftw(cgroup_workdir, nftwfunc, WALK_FD_LIMIT, FTW_DEPTH | FTW_MOUNT); } + +/** + * get_classid_cgroup_id - Get the cgroup id of a net_cls cgroup + */ +unsigned long long get_classid_cgroup_id(void) +{ + char cgroup_workdir[PATH_MAX + 1]; + + format_classid_path(cgroup_workdir); + return get_cgroup_id_from_path(cgroup_workdir); +} + +/** + * get_cgroup1_hierarchy_id - Retrieves the ID of a cgroup1 hierarchy from the cgroup1 subsys name. + * @subsys_name: The cgroup1 subsys name, which can be retrieved from /proc/self/cgroup. It can be + * a named cgroup like "name=systemd", a controller name like "net_cls", or multi-contollers like + * "net_cls,net_prio". + */ +int get_cgroup1_hierarchy_id(const char *subsys_name) +{ + char *c, *c2, *c3, *c4; + bool found = false; + char line[1024]; + FILE *file; + int i, id; + + if (!subsys_name) + return -1; + + file = fopen("/proc/self/cgroup", "r"); + if (!file) { + log_err("fopen /proc/self/cgroup"); + return -1; + } + + while (fgets(line, 1024, file)) { + i = 0; + for (c = strtok_r(line, ":", &c2); c && i < 2; c = strtok_r(NULL, ":", &c2)) { + if (i == 0) { + id = strtol(c, NULL, 10); + } else if (i == 1) { + if (!strcmp(c, subsys_name)) { + found = true; + break; + } + + /* Multiple subsystems may share one single mount point */ + for (c3 = strtok_r(c, ",", &c4); c3; + c3 = strtok_r(NULL, ",", &c4)) { + if (!strcmp(c, subsys_name)) { + found = true; + break; + } + } + } + i++; + } + if (found) + break; + } + fclose(file); + return found ? id : -1; +} + +/** + * open_classid() - Open a cgroupv1 net_cls classid + * + * This function expects the cgroup work dir to be already created, as we + * open it here. + * + * On success, it returns the file descriptor. On failure it returns -1. + */ +int open_classid(void) +{ + char cgroup_workdir[PATH_MAX + 1]; + + format_classid_path(cgroup_workdir); + return open(cgroup_workdir, O_RDONLY); +} diff --git a/tools/testing/selftests/bpf/cgroup_helpers.h b/tools/testing/selftests/bpf/cgroup_helpers.h index 5c2cb9c8b5..502845160d 100644 --- a/tools/testing/selftests/bpf/cgroup_helpers.h +++ b/tools/testing/selftests/bpf/cgroup_helpers.h @@ -20,6 +20,7 @@ int get_root_cgroup(void); int create_and_get_cgroup(const char *relative_path); void remove_cgroup(const char *relative_path); unsigned long long get_cgroup_id(const char *relative_path); +int get_cgroup1_hierarchy_id(const char *subsys_name); int join_cgroup(const char *relative_path); int join_root_cgroup(void); @@ -29,8 +30,10 @@ int setup_cgroup_environment(void); void cleanup_cgroup_environment(void); /* cgroupv1 related */ -int set_classid(unsigned int id); +int set_classid(void); int join_classid(void); +unsigned long long get_classid_cgroup_id(void); +int open_classid(void); int setup_classid_environment(void); void cleanup_classid_environment(void); diff --git a/tools/testing/selftests/bpf/config b/tools/testing/selftests/bpf/config index 3ec5927ec3..c125c441ab 100644 --- a/tools/testing/selftests/bpf/config +++ b/tools/testing/selftests/bpf/config @@ -23,6 +23,7 @@ CONFIG_FPROBE=y CONFIG_FTRACE_SYSCALLS=y CONFIG_FUNCTION_ERROR_INJECTION=y CONFIG_FUNCTION_TRACER=y +CONFIG_FS_VERITY=y CONFIG_GENEVE=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y @@ -82,7 +83,7 @@ CONFIG_SECURITY=y CONFIG_SECURITYFS=y CONFIG_TEST_BPF=m CONFIG_USERFAULTFD=y +CONFIG_VSOCKETS=y CONFIG_VXLAN=y CONFIG_XDP_SOCKETS=y CONFIG_XFRM_INTERFACE=y -CONFIG_VSOCKETS=y diff --git a/tools/testing/selftests/bpf/config.aarch64 b/tools/testing/selftests/bpf/config.aarch64 index 2538214948..3720b76115 100644 --- a/tools/testing/selftests/bpf/config.aarch64 +++ b/tools/testing/selftests/bpf/config.aarch64 @@ -1,4 +1,3 @@ -CONFIG_9P_FS=y CONFIG_ARCH_VEXPRESS=y CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y CONFIG_ARM_SMMU_V3=y @@ -12,7 +11,6 @@ CONFIG_BLK_DEV_IO_TRACE=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_SD=y CONFIG_BONDING=y -CONFIG_BPFILTER=y CONFIG_BPF_JIT_ALWAYS_ON=y CONFIG_BPF_JIT_DEFAULT_ON=y CONFIG_BPF_PRELOAD_UMD=y @@ -37,6 +35,7 @@ CONFIG_CRYPTO_USER_API_SKCIPHER=y CONFIG_DEBUG_ATOMIC_SLEEP=y CONFIG_DEBUG_INFO_BTF=y CONFIG_DEBUG_INFO_DWARF4=y +CONFIG_DEBUG_INFO_REDUCED=n CONFIG_DEBUG_LIST=y CONFIG_DEBUG_LOCKDEP=y CONFIG_DEBUG_NOTIFIERS=y @@ -46,7 +45,6 @@ CONFIG_DEBUG_SG=y CONFIG_DETECT_HUNG_TASK=y CONFIG_DEVTMPFS_MOUNT=y CONFIG_DEVTMPFS=y -CONFIG_DRM_VIRTIO_GPU=y CONFIG_DRM=y CONFIG_DUMMY=y CONFIG_EXPERT=y @@ -67,7 +65,6 @@ CONFIG_HAVE_KRETPROBES=y CONFIG_HEADERS_INSTALL=y CONFIG_HIGH_RES_TIMERS=y CONFIG_HUGETLBFS=y -CONFIG_HW_RANDOM_VIRTIO=y CONFIG_HW_RANDOM=y CONFIG_HZ_100=y CONFIG_IDLE_PAGE_TRACKING=y @@ -99,8 +96,6 @@ CONFIG_MEMCG=y CONFIG_MEMORY_HOTPLUG=y CONFIG_MEMORY_HOTREMOVE=y CONFIG_NAMESPACES=y -CONFIG_NET_9P_VIRTIO=y -CONFIG_NET_9P=y CONFIG_NET_ACT_BPF=y CONFIG_NET_ACT_GACT=y CONFIG_NETDEVICES=y @@ -140,7 +135,6 @@ CONFIG_SCHED_TRACER=y CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_LOGGING=y CONFIG_SCSI_SCAN_ASYNC=y -CONFIG_SCSI_VIRTIO=y CONFIG_SCSI=y CONFIG_SECURITY_NETWORK=y CONFIG_SERIAL_AMBA_PL011_CONSOLE=y @@ -167,16 +161,6 @@ CONFIG_UPROBES=y CONFIG_USELIB=y CONFIG_USER_NS=y CONFIG_VETH=y -CONFIG_VIRTIO_BALLOON=y -CONFIG_VIRTIO_BLK=y -CONFIG_VIRTIO_CONSOLE=y -CONFIG_VIRTIO_FS=y -CONFIG_VIRTIO_INPUT=y -CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y -CONFIG_VIRTIO_MMIO=y -CONFIG_VIRTIO_NET=y -CONFIG_VIRTIO_PCI=y -CONFIG_VIRTIO_VSOCKETS_COMMON=y CONFIG_VLAN_8021Q=y CONFIG_VSOCKETS=y CONFIG_VSOCKETS_LOOPBACK=y diff --git a/tools/testing/selftests/bpf/config.s390x b/tools/testing/selftests/bpf/config.s390x index 2ba92167be..706931a8c2 100644 --- a/tools/testing/selftests/bpf/config.s390x +++ b/tools/testing/selftests/bpf/config.s390x @@ -1,4 +1,3 @@ -CONFIG_9P_FS=y CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y CONFIG_AUDIT=y CONFIG_BLK_CGROUP=y @@ -10,7 +9,6 @@ CONFIG_BPF_JIT_ALWAYS_ON=y CONFIG_BPF_JIT_DEFAULT_ON=y CONFIG_BPF_PRELOAD=y CONFIG_BPF_PRELOAD_UMD=y -CONFIG_BPFILTER=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_DEVICE=y CONFIG_CGROUP_FREEZER=y @@ -84,8 +82,6 @@ CONFIG_MEMORY_HOTPLUG=y CONFIG_MEMORY_HOTREMOVE=y CONFIG_NAMESPACES=y CONFIG_NET=y -CONFIG_NET_9P=y -CONFIG_NET_9P_VIRTIO=y CONFIG_NET_ACT_BPF=y CONFIG_NET_ACT_GACT=y CONFIG_NET_KEY=y @@ -114,7 +110,6 @@ CONFIG_SAMPLE_SECCOMP=y CONFIG_SAMPLES=y CONFIG_SCHED_TRACER=y CONFIG_SCSI=y -CONFIG_SCSI_VIRTIO=y CONFIG_SECURITY_NETWORK=y CONFIG_STACK_TRACER=y CONFIG_STATIC_KEYS_SELFTEST=y @@ -136,11 +131,6 @@ CONFIG_UPROBES=y CONFIG_USELIB=y CONFIG_USER_NS=y CONFIG_VETH=y -CONFIG_VIRTIO_BALLOON=y -CONFIG_VIRTIO_BLK=y -CONFIG_VIRTIO_NET=y -CONFIG_VIRTIO_PCI=y -CONFIG_VIRTIO_VSOCKETS_COMMON=y CONFIG_VLAN_8021Q=y CONFIG_VSOCKETS=y CONFIG_VSOCKETS_LOOPBACK=y diff --git a/tools/testing/selftests/bpf/config.vm b/tools/testing/selftests/bpf/config.vm new file mode 100644 index 0000000000..a9746ca787 --- /dev/null +++ b/tools/testing/selftests/bpf/config.vm @@ -0,0 +1,12 @@ +CONFIG_9P_FS=y +CONFIG_9P_FS_POSIX_ACL=y +CONFIG_9P_FS_SECURITY=y +CONFIG_CRYPTO_DEV_VIRTIO=y +CONFIG_NET_9P=y +CONFIG_NET_9P_VIRTIO=y +CONFIG_VIRTIO_BALLOON=y +CONFIG_VIRTIO_BLK=y +CONFIG_VIRTIO_CONSOLE=y +CONFIG_VIRTIO_NET=y +CONFIG_VIRTIO_PCI=y +CONFIG_VIRTIO_VSOCKETS_COMMON=y diff --git a/tools/testing/selftests/bpf/config.x86_64 b/tools/testing/selftests/bpf/config.x86_64 index 49a29dbc19..5680befae8 100644 --- a/tools/testing/selftests/bpf/config.x86_64 +++ b/tools/testing/selftests/bpf/config.x86_64 @@ -1,6 +1,3 @@ -CONFIG_9P_FS=y -CONFIG_9P_FS_POSIX_ACL=y -CONFIG_9P_FS_SECURITY=y CONFIG_AGP=y CONFIG_AGP_AMD64=y CONFIG_AGP_INTEL=y @@ -22,7 +19,6 @@ CONFIG_BOOTTIME_TRACING=y CONFIG_BPF_JIT_ALWAYS_ON=y CONFIG_BPF_PRELOAD=y CONFIG_BPF_PRELOAD_UMD=y -CONFIG_BPFILTER=y CONFIG_BSD_DISKLABEL=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_CFS_BANDWIDTH=y @@ -45,7 +41,6 @@ CONFIG_CPU_IDLE_GOV_LADDER=y CONFIG_CPUSETS=y CONFIG_CRC_T10DIF=y CONFIG_CRYPTO_BLAKE2B=y -CONFIG_CRYPTO_DEV_VIRTIO=y CONFIG_CRYPTO_SEQIV=y CONFIG_CRYPTO_XXHASH=y CONFIG_DCB=y @@ -144,8 +139,6 @@ CONFIG_MEMORY_FAILURE=y CONFIG_MINIX_SUBPARTITION=y CONFIG_NAMESPACES=y CONFIG_NET=y -CONFIG_NET_9P=y -CONFIG_NET_9P_VIRTIO=y CONFIG_NET_ACT_BPF=y CONFIG_NET_CLS_CGROUP=y CONFIG_NET_EMATCH=y @@ -227,12 +220,6 @@ CONFIG_USER_NS=y CONFIG_VALIDATE_FS_PARSER=y CONFIG_VETH=y CONFIG_VIRT_DRIVERS=y -CONFIG_VIRTIO_BALLOON=y -CONFIG_VIRTIO_BLK=y -CONFIG_VIRTIO_CONSOLE=y -CONFIG_VIRTIO_NET=y -CONFIG_VIRTIO_PCI=y -CONFIG_VIRTIO_VSOCKETS_COMMON=y CONFIG_VLAN_8021Q=y CONFIG_VSOCKETS=y CONFIG_VSOCKETS_LOOPBACK=y diff --git a/tools/testing/selftests/bpf/map_tests/map_percpu_stats.c b/tools/testing/selftests/bpf/map_tests/map_percpu_stats.c index 8bf497a984..2ea3640881 100644 --- a/tools/testing/selftests/bpf/map_tests/map_percpu_stats.c +++ b/tools/testing/selftests/bpf/map_tests/map_percpu_stats.c @@ -131,10 +131,17 @@ static bool is_lru(__u32 map_type) map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH; } +static bool is_percpu(__u32 map_type) +{ + return map_type == BPF_MAP_TYPE_PERCPU_HASH || + map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH; +} + struct upsert_opts { __u32 map_type; int map_fd; __u32 n; + bool retry_for_nomem; }; static int create_small_hash(void) @@ -148,19 +155,38 @@ static int create_small_hash(void) return map_fd; } +static bool retry_for_nomem_fn(int err) +{ + return err == ENOMEM; +} + static void *patch_map_thread(void *arg) { + /* 8KB is enough for 1024 CPUs. And it is shared between N_THREADS. */ + static __u8 blob[8 << 10]; struct upsert_opts *opts = arg; + void *val_ptr; int val; int ret; int i; for (i = 0; i < opts->n; i++) { - if (opts->map_type == BPF_MAP_TYPE_HASH_OF_MAPS) + if (opts->map_type == BPF_MAP_TYPE_HASH_OF_MAPS) { val = create_small_hash(); - else + val_ptr = &val; + } else if (is_percpu(opts->map_type)) { + val_ptr = blob; + } else { val = rand(); - ret = bpf_map_update_elem(opts->map_fd, &i, &val, 0); + val_ptr = &val; + } + + /* 2 seconds may be enough ? */ + if (opts->retry_for_nomem) + ret = map_update_retriable(opts->map_fd, &i, val_ptr, 0, + 40, retry_for_nomem_fn); + else + ret = bpf_map_update_elem(opts->map_fd, &i, val_ptr, 0); CHECK(ret < 0, "bpf_map_update_elem", "key=%d error: %s\n", i, strerror(errno)); if (opts->map_type == BPF_MAP_TYPE_HASH_OF_MAPS) @@ -281,6 +307,13 @@ static void __test(int map_fd) else opts.n /= 2; + /* per-cpu bpf memory allocator may not be able to allocate per-cpu + * pointer successfully and it can not refill free llist timely, and + * bpf_map_update_elem() will return -ENOMEM. so just retry to mitigate + * the problem temporarily. + */ + opts.retry_for_nomem = is_percpu(opts.map_type) && (info.map_flags & BPF_F_NO_PREALLOC); + /* * Upsert keys [0, n) under some competition: with random values from * N_THREADS threads. Check values, then delete all elements and check diff --git a/tools/testing/selftests/bpf/network_helpers.h b/tools/testing/selftests/bpf/network_helpers.h index 34f1200a78..94b9be24e3 100644 --- a/tools/testing/selftests/bpf/network_helpers.h +++ b/tools/testing/selftests/bpf/network_helpers.h @@ -71,4 +71,47 @@ struct nstoken; */ struct nstoken *open_netns(const char *name); void close_netns(struct nstoken *token); + +static __u16 csum_fold(__u32 csum) +{ + csum = (csum & 0xffff) + (csum >> 16); + csum = (csum & 0xffff) + (csum >> 16); + + return (__u16)~csum; +} + +static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, + __u32 len, __u8 proto, + __wsum csum) +{ + __u64 s = csum; + + s += (__u32)saddr; + s += (__u32)daddr; + s += htons(proto + len); + s = (s & 0xffffffff) + (s >> 32); + s = (s & 0xffffffff) + (s >> 32); + + return csum_fold((__u32)s); +} + +static inline __sum16 csum_ipv6_magic(const struct in6_addr *saddr, + const struct in6_addr *daddr, + __u32 len, __u8 proto, + __wsum csum) +{ + __u64 s = csum; + int i; + + for (i = 0; i < 4; i++) + s += (__u32)saddr->s6_addr32[i]; + for (i = 0; i < 4; i++) + s += (__u32)daddr->s6_addr32[i]; + s += htons(proto + len); + s = (s & 0xffffffff) + (s >> 32); + s = (s & 0xffffffff) + (s >> 32); + + return csum_fold((__u32)s); +} + #endif diff --git a/tools/testing/selftests/bpf/prog_tests/align.c b/tools/testing/selftests/bpf/prog_tests/align.c index 465c1c3a3d..4ebd0da898 100644 --- a/tools/testing/selftests/bpf/prog_tests/align.c +++ b/tools/testing/selftests/bpf/prog_tests/align.c @@ -40,7 +40,7 @@ static struct bpf_align_test tests[] = { }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .matches = { - {0, "R1", "ctx(off=0,imm=0)"}, + {0, "R1", "ctx()"}, {0, "R10", "fp0"}, {0, "R3_w", "2"}, {1, "R3_w", "4"}, @@ -68,7 +68,7 @@ static struct bpf_align_test tests[] = { }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .matches = { - {0, "R1", "ctx(off=0,imm=0)"}, + {0, "R1", "ctx()"}, {0, "R10", "fp0"}, {0, "R3_w", "1"}, {1, "R3_w", "2"}, @@ -97,7 +97,7 @@ static struct bpf_align_test tests[] = { }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .matches = { - {0, "R1", "ctx(off=0,imm=0)"}, + {0, "R1", "ctx()"}, {0, "R10", "fp0"}, {0, "R3_w", "4"}, {1, "R3_w", "8"}, @@ -119,7 +119,7 @@ static struct bpf_align_test tests[] = { }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .matches = { - {0, "R1", "ctx(off=0,imm=0)"}, + {0, "R1", "ctx()"}, {0, "R10", "fp0"}, {0, "R3_w", "7"}, {1, "R3_w", "7"}, @@ -162,13 +162,13 @@ static struct bpf_align_test tests[] = { }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .matches = { - {6, "R0_w", "pkt(off=8,r=8,imm=0)"}, + {6, "R0_w", "pkt(off=8,r=8)"}, {6, "R3_w", "var_off=(0x0; 0xff)"}, {7, "R3_w", "var_off=(0x0; 0x1fe)"}, {8, "R3_w", "var_off=(0x0; 0x3fc)"}, {9, "R3_w", "var_off=(0x0; 0x7f8)"}, {10, "R3_w", "var_off=(0x0; 0xff0)"}, - {12, "R3_w", "pkt_end(off=0,imm=0)"}, + {12, "R3_w", "pkt_end()"}, {17, "R4_w", "var_off=(0x0; 0xff)"}, {18, "R4_w", "var_off=(0x0; 0x1fe0)"}, {19, "R4_w", "var_off=(0x0; 0xff0)"}, @@ -235,11 +235,11 @@ static struct bpf_align_test tests[] = { }, .prog_type = BPF_PROG_TYPE_SCHED_CLS, .matches = { - {2, "R5_w", "pkt(off=0,r=0,imm=0)"}, - {4, "R5_w", "pkt(off=14,r=0,imm=0)"}, - {5, "R4_w", "pkt(off=14,r=0,imm=0)"}, - {9, "R2", "pkt(off=0,r=18,imm=0)"}, - {10, "R5", "pkt(off=14,r=18,imm=0)"}, + {2, "R5_w", "pkt(r=0)"}, + {4, "R5_w", "pkt(off=14,r=0)"}, + {5, "R4_w", "pkt(off=14,r=0)"}, + {9, "R2", "pkt(r=18)"}, + {10, "R5", "pkt(off=14,r=18)"}, {10, "R4_w", "var_off=(0x0; 0xff)"}, {13, "R4_w", "var_off=(0x0; 0xffff)"}, {14, "R4_w", "var_off=(0x0; 0xffff)"}, @@ -299,7 +299,7 @@ static struct bpf_align_test tests[] = { /* Calculated offset in R6 has unknown value, but known * alignment of 4. */ - {6, "R2_w", "pkt(off=0,r=8,imm=0)"}, + {6, "R2_w", "pkt(r=8)"}, {7, "R6_w", "var_off=(0x0; 0x3fc)"}, /* Offset is added to packet pointer R5, resulting in * known fixed offset, and variable offset from R6. @@ -337,7 +337,7 @@ static struct bpf_align_test tests[] = { /* Constant offset is added to R5 packet pointer, * resulting in reg->off value of 14. */ - {26, "R5_w", "pkt(off=14,r=8,"}, + {26, "R5_w", "pkt(off=14,r=8)"}, /* Variable offset is added to R5, resulting in a * variable offset of (4n). See comment for insn #18 * for R4 = R5 trick. @@ -397,7 +397,7 @@ static struct bpf_align_test tests[] = { /* Calculated offset in R6 has unknown value, but known * alignment of 4. */ - {6, "R2_w", "pkt(off=0,r=8,imm=0)"}, + {6, "R2_w", "pkt(r=8)"}, {7, "R6_w", "var_off=(0x0; 0x3fc)"}, /* Adding 14 makes R6 be (4n+2) */ {8, "R6_w", "var_off=(0x2; 0x7fc)"}, @@ -459,7 +459,7 @@ static struct bpf_align_test tests[] = { .prog_type = BPF_PROG_TYPE_SCHED_CLS, .result = REJECT, .matches = { - {3, "R5_w", "pkt_end(off=0,imm=0)"}, + {3, "R5_w", "pkt_end()"}, /* (ptr - ptr) << 2 == unknown, (4n) */ {5, "R5_w", "var_off=(0x0; 0xfffffffffffffffc)"}, /* (4n) + 14 == (4n+2). We blow our bounds, because @@ -513,7 +513,7 @@ static struct bpf_align_test tests[] = { /* Calculated offset in R6 has unknown value, but known * alignment of 4. */ - {6, "R2_w", "pkt(off=0,r=8,imm=0)"}, + {6, "R2_w", "pkt(r=8)"}, {8, "R6_w", "var_off=(0x0; 0x3fc)"}, /* Adding 14 makes R6 be (4n+2) */ {9, "R6_w", "var_off=(0x2; 0x7fc)"}, @@ -566,7 +566,7 @@ static struct bpf_align_test tests[] = { /* Calculated offset in R6 has unknown value, but known * alignment of 4. */ - {6, "R2_w", "pkt(off=0,r=8,imm=0)"}, + {6, "R2_w", "pkt(r=8)"}, {9, "R6_w", "var_off=(0x0; 0x3c)"}, /* Adding 14 makes R6 be (4n+2) */ {10, "R6_w", "var_off=(0x2; 0x7c)"}, @@ -659,14 +659,14 @@ static int do_test_single(struct bpf_align_test *test) /* Check the next line as well in case the previous line * did not have a corresponding bpf insn. Example: * func#0 @0 - * 0: R1=ctx(off=0,imm=0) R10=fp0 + * 0: R1=ctx() R10=fp0 * 0: (b7) r3 = 2 ; R3_w=2 * * Sometimes it's actually two lines below, e.g. when * searching for "6: R3_w=scalar(umax=255,var_off=(0x0; 0xff))": - * from 4 to 6: R0_w=pkt(off=8,r=8,imm=0) R1=ctx(off=0,imm=0) R2_w=pkt(off=0,r=8,imm=0) R3_w=pkt_end(off=0,imm=0) R10=fp0 - * 6: R0_w=pkt(off=8,r=8,imm=0) R1=ctx(off=0,imm=0) R2_w=pkt(off=0,r=8,imm=0) R3_w=pkt_end(off=0,imm=0) R10=fp0 - * 6: (71) r3 = *(u8 *)(r2 +0) ; R2_w=pkt(off=0,r=8,imm=0) R3_w=scalar(umax=255,var_off=(0x0; 0xff)) + * from 4 to 6: R0_w=pkt(off=8,r=8) R1=ctx() R2_w=pkt(r=8) R3_w=pkt_end() R10=fp0 + * 6: R0_w=pkt(off=8,r=8) R1=ctx() R2_w=pkt(r=8) R3_w=pkt_end() R10=fp0 + * 6: (71) r3 = *(u8 *)(r2 +0) ; R2_w=pkt(r=8) R3_w=scalar(umax=255,var_off=(0x0; 0xff)) */ while (!(p = strstr(line_ptr, m.reg)) || !strstr(p, m.match)) { cur_line = -1; diff --git a/tools/testing/selftests/bpf/prog_tests/bind_perm.c b/tools/testing/selftests/bpf/prog_tests/bind_perm.c index a1766a298b..f7cd129cb8 100644 --- a/tools/testing/selftests/bpf/prog_tests/bind_perm.c +++ b/tools/testing/selftests/bpf/prog_tests/bind_perm.c @@ -9,8 +9,6 @@ #include "cap_helpers.h" #include "bind_perm.skel.h" -static int duration; - static int create_netns(void) { if (!ASSERT_OK(unshare(CLONE_NEWNET), "create netns")) @@ -27,7 +25,7 @@ void try_bind(int family, int port, int expected_errno) int fd = -1; fd = socket(family, SOCK_STREAM, 0); - if (CHECK(fd < 0, "fd", "errno %d", errno)) + if (!ASSERT_GE(fd, 0, "socket")) goto close_socket; if (family == AF_INET) { @@ -60,7 +58,7 @@ void test_bind_perm(void) return; cgroup_fd = test__join_cgroup("/bind_perm"); - if (CHECK(cgroup_fd < 0, "cg-join", "errno %d", errno)) + if (!ASSERT_GE(cgroup_fd, 0, "test__join_cgroup")) return; skel = bind_perm__open_and_load(); diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_iter.c b/tools/testing/selftests/bpf/prog_tests/bpf_iter.c index 2cacc8fa96..618af9dfae 100644 --- a/tools/testing/selftests/bpf/prog_tests/bpf_iter.c +++ b/tools/testing/selftests/bpf/prog_tests/bpf_iter.c @@ -34,8 +34,6 @@ #include "bpf_iter_ksym.skel.h" #include "bpf_iter_sockmap.skel.h" -static int duration; - static void test_btf_id_or_null(void) { struct bpf_iter_test_kern3 *skel; @@ -64,7 +62,7 @@ static void do_dummy_read_opts(struct bpf_program *prog, struct bpf_iter_attach_ /* not check contents, but ensure read() ends without error */ while ((len = read(iter_fd, buf, sizeof(buf))) > 0) ; - CHECK(len < 0, "read", "read failed: %s\n", strerror(errno)); + ASSERT_GE(len, 0, "read"); close(iter_fd); @@ -415,7 +413,7 @@ static int do_btf_read(struct bpf_iter_task_btf *skel) goto free_link; } - if (CHECK(err < 0, "read", "read failed: %s\n", strerror(errno))) + if (!ASSERT_GE(err, 0, "read")) goto free_link; ASSERT_HAS_SUBSTR(taskbuf, "(struct task_struct)", @@ -528,11 +526,11 @@ static int do_read_with_fd(int iter_fd, const char *expected, start = 0; while ((len = read(iter_fd, buf + start, read_buf_len)) > 0) { start += len; - if (CHECK(start >= 16, "read", "read len %d\n", len)) + if (!ASSERT_LT(start, 16, "read")) return -1; read_buf_len = read_one_char ? 1 : 16 - start; } - if (CHECK(len < 0, "read", "read failed: %s\n", strerror(errno))) + if (!ASSERT_GE(len, 0, "read")) return -1; if (!ASSERT_STREQ(buf, expected, "read")) @@ -573,8 +571,7 @@ static int do_read(const char *path, const char *expected) int err, iter_fd; iter_fd = open(path, O_RDONLY); - if (CHECK(iter_fd < 0, "open", "open %s failed: %s\n", - path, strerror(errno))) + if (!ASSERT_GE(iter_fd, 0, "open")) return -1; err = do_read_with_fd(iter_fd, expected, false); @@ -602,7 +599,7 @@ static void test_file_iter(void) unlink(path); err = bpf_link__pin(link, path); - if (CHECK(err, "pin_iter", "pin_iter to %s failed: %d\n", path, err)) + if (!ASSERT_OK(err, "pin_iter")) goto free_link; err = do_read(path, "abcd"); @@ -653,12 +650,10 @@ static void test_overflow(bool test_e2big_overflow, bool ret1) * overflow and needs restart. */ map1_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, NULL, 4, 8, 1, NULL); - if (CHECK(map1_fd < 0, "bpf_map_create", - "map_creation failed: %s\n", strerror(errno))) + if (!ASSERT_GE(map1_fd, 0, "bpf_map_create")) goto out; map2_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, NULL, 4, 8, 1, NULL); - if (CHECK(map2_fd < 0, "bpf_map_create", - "map_creation failed: %s\n", strerror(errno))) + if (!ASSERT_GE(map2_fd, 0, "bpf_map_create")) goto free_map1; /* bpf_seq_printf kernel buffer is 8 pages, so one map @@ -687,14 +682,12 @@ static void test_overflow(bool test_e2big_overflow, bool ret1) /* setup filtering map_id in bpf program */ map_info_len = sizeof(map_info); err = bpf_map_get_info_by_fd(map1_fd, &map_info, &map_info_len); - if (CHECK(err, "get_map_info", "get map info failed: %s\n", - strerror(errno))) + if (!ASSERT_OK(err, "get_map_info")) goto free_map2; skel->bss->map1_id = map_info.id; err = bpf_map_get_info_by_fd(map2_fd, &map_info, &map_info_len); - if (CHECK(err, "get_map_info", "get map info failed: %s\n", - strerror(errno))) + if (!ASSERT_OK(err, "get_map_info")) goto free_map2; skel->bss->map2_id = map_info.id; @@ -707,7 +700,7 @@ static void test_overflow(bool test_e2big_overflow, bool ret1) goto free_link; buf = malloc(expected_read_len); - if (!buf) + if (!ASSERT_OK_PTR(buf, "malloc")) goto close_iter; /* do read */ @@ -716,16 +709,14 @@ static void test_overflow(bool test_e2big_overflow, bool ret1) while ((len = read(iter_fd, buf, expected_read_len)) > 0) total_read_len += len; - CHECK(len != -1 || errno != E2BIG, "read", - "expected ret -1, errno E2BIG, but get ret %d, error %s\n", - len, strerror(errno)); + ASSERT_EQ(len, -1, "read"); + ASSERT_EQ(errno, E2BIG, "read"); goto free_buf; } else if (!ret1) { while ((len = read(iter_fd, buf, expected_read_len)) > 0) total_read_len += len; - if (CHECK(len < 0, "read", "read failed: %s\n", - strerror(errno))) + if (!ASSERT_GE(len, 0, "read")) goto free_buf; } else { do { @@ -734,8 +725,7 @@ static void test_overflow(bool test_e2big_overflow, bool ret1) total_read_len += len; } while (len > 0 || len == -EAGAIN); - if (CHECK(len < 0, "read", "read failed: %s\n", - strerror(errno))) + if (!ASSERT_GE(len, 0, "read")) goto free_buf; } @@ -838,7 +828,7 @@ static void test_bpf_hash_map(void) /* do some tests */ while ((len = read(iter_fd, buf, sizeof(buf))) > 0) ; - if (CHECK(len < 0, "read", "read failed: %s\n", strerror(errno))) + if (!ASSERT_GE(len, 0, "read")) goto close_iter; /* test results */ @@ -880,6 +870,8 @@ static void test_bpf_percpu_hash_map(void) skel->rodata->num_cpus = bpf_num_possible_cpus(); val = malloc(8 * bpf_num_possible_cpus()); + if (!ASSERT_OK_PTR(val, "malloc")) + goto out; err = bpf_iter_bpf_percpu_hash_map__load(skel); if (!ASSERT_OK_PTR(skel, "bpf_iter_bpf_percpu_hash_map__load")) @@ -919,7 +911,7 @@ static void test_bpf_percpu_hash_map(void) /* do some tests */ while ((len = read(iter_fd, buf, sizeof(buf))) > 0) ; - if (CHECK(len < 0, "read", "read failed: %s\n", strerror(errno))) + if (!ASSERT_GE(len, 0, "read")) goto close_iter; /* test results */ @@ -985,17 +977,14 @@ static void test_bpf_array_map(void) start = 0; while ((len = read(iter_fd, buf + start, sizeof(buf) - start)) > 0) start += len; - if (CHECK(len < 0, "read", "read failed: %s\n", strerror(errno))) + if (!ASSERT_GE(len, 0, "read")) goto close_iter; /* test results */ res_first_key = *(__u32 *)buf; res_first_val = *(__u64 *)(buf + sizeof(__u32)); - if (CHECK(res_first_key != 0 || res_first_val != first_val, - "bpf_seq_write", - "seq_write failure: first key %u vs expected 0, " - " first value %llu vs expected %llu\n", - res_first_key, res_first_val, first_val)) + if (!ASSERT_EQ(res_first_key, 0, "bpf_seq_write") || + !ASSERT_EQ(res_first_val, first_val, "bpf_seq_write")) goto close_iter; if (!ASSERT_EQ(skel->bss->key_sum, expected_key, "key_sum")) @@ -1059,6 +1048,8 @@ static void test_bpf_percpu_array_map(void) skel->rodata->num_cpus = bpf_num_possible_cpus(); val = malloc(8 * bpf_num_possible_cpus()); + if (!ASSERT_OK_PTR(val, "malloc")) + goto out; err = bpf_iter_bpf_percpu_array_map__load(skel); if (!ASSERT_OK_PTR(skel, "bpf_iter_bpf_percpu_array_map__load")) @@ -1094,7 +1085,7 @@ static void test_bpf_percpu_array_map(void) /* do some tests */ while ((len = read(iter_fd, buf, sizeof(buf))) > 0) ; - if (CHECK(len < 0, "read", "read failed: %s\n", strerror(errno))) + if (!ASSERT_GE(len, 0, "read")) goto close_iter; /* test results */ @@ -1133,6 +1124,7 @@ static void test_bpf_sk_storage_delete(void) sock_fd = socket(AF_INET6, SOCK_STREAM, 0); if (!ASSERT_GE(sock_fd, 0, "socket")) goto out; + err = bpf_map_update_elem(map_fd, &sock_fd, &val, BPF_NOEXIST); if (!ASSERT_OK(err, "map_update")) goto out; @@ -1153,14 +1145,19 @@ static void test_bpf_sk_storage_delete(void) /* do some tests */ while ((len = read(iter_fd, buf, sizeof(buf))) > 0) ; - if (CHECK(len < 0, "read", "read failed: %s\n", strerror(errno))) + if (!ASSERT_GE(len, 0, "read")) goto close_iter; /* test results */ err = bpf_map_lookup_elem(map_fd, &sock_fd, &val); - if (CHECK(!err || errno != ENOENT, "bpf_map_lookup_elem", - "map value wasn't deleted (err=%d, errno=%d)\n", err, errno)) - goto close_iter; + + /* Note: The following assertions serve to ensure + * the value was deleted. It does so by asserting + * that bpf_map_lookup_elem has failed. This might + * seem counterintuitive at first. + */ + ASSERT_ERR(err, "bpf_map_lookup_elem"); + ASSERT_EQ(errno, ENOENT, "bpf_map_lookup_elem"); close_iter: close(iter_fd); @@ -1205,17 +1202,15 @@ static void test_bpf_sk_storage_get(void) do_dummy_read(skel->progs.fill_socket_owner); err = bpf_map_lookup_elem(map_fd, &sock_fd, &val); - if (CHECK(err || val != getpid(), "bpf_map_lookup_elem", - "map value wasn't set correctly (expected %d, got %d, err=%d)\n", - getpid(), val, err)) + if (!ASSERT_OK(err, "bpf_map_lookup_elem") || + !ASSERT_EQ(val, getpid(), "bpf_map_lookup_elem")) goto close_socket; do_dummy_read(skel->progs.negate_socket_local_storage); err = bpf_map_lookup_elem(map_fd, &sock_fd, &val); - CHECK(err || val != -getpid(), "bpf_map_lookup_elem", - "map value wasn't set correctly (expected %d, got %d, err=%d)\n", - -getpid(), val, err); + ASSERT_OK(err, "bpf_map_lookup_elem"); + ASSERT_EQ(val, -getpid(), "bpf_map_lookup_elem"); close_socket: close(sock_fd); @@ -1292,7 +1287,7 @@ static void test_bpf_sk_storage_map(void) /* do some tests */ while ((len = read(iter_fd, buf, sizeof(buf))) > 0) ; - if (CHECK(len < 0, "read", "read failed: %s\n", strerror(errno))) + if (!ASSERT_GE(len, 0, "read")) goto close_iter; /* test results */ diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_obj_id.c b/tools/testing/selftests/bpf/prog_tests/bpf_obj_id.c index 675b90b152..f09d6ac2ef 100644 --- a/tools/testing/selftests/bpf/prog_tests/bpf_obj_id.c +++ b/tools/testing/selftests/bpf/prog_tests/bpf_obj_id.c @@ -25,7 +25,7 @@ void serial_test_bpf_obj_id(void) */ __u32 map_ids[nr_iters + 1]; char jited_insns[128], xlated_insns[128], zeros[128], tp_name[128]; - __u32 i, next_id, info_len, nr_id_found, duration = 0; + __u32 i, next_id, info_len, nr_id_found; struct timespec real_time_ts, boot_time_ts; int err = 0; __u64 array_value; @@ -33,16 +33,16 @@ void serial_test_bpf_obj_id(void) time_t now, load_time; err = bpf_prog_get_fd_by_id(0); - CHECK(err >= 0 || errno != ENOENT, - "get-fd-by-notexist-prog-id", "err %d errno %d\n", err, errno); + ASSERT_LT(err, 0, "bpf_prog_get_fd_by_id"); + ASSERT_EQ(errno, ENOENT, "bpf_prog_get_fd_by_id"); err = bpf_map_get_fd_by_id(0); - CHECK(err >= 0 || errno != ENOENT, - "get-fd-by-notexist-map-id", "err %d errno %d\n", err, errno); + ASSERT_LT(err, 0, "bpf_map_get_fd_by_id"); + ASSERT_EQ(errno, ENOENT, "bpf_map_get_fd_by_id"); err = bpf_link_get_fd_by_id(0); - CHECK(err >= 0 || errno != ENOENT, - "get-fd-by-notexist-link-id", "err %d errno %d\n", err, errno); + ASSERT_LT(err, 0, "bpf_map_get_fd_by_id"); + ASSERT_EQ(errno, ENOENT, "bpf_map_get_fd_by_id"); /* Check bpf_map_get_info_by_fd() */ bzero(zeros, sizeof(zeros)); @@ -53,25 +53,26 @@ void serial_test_bpf_obj_id(void) /* test_obj_id.o is a dumb prog. It should never fail * to load. */ - if (CHECK_FAIL(err)) + if (!ASSERT_OK(err, "bpf_prog_test_load")) continue; /* Insert a magic value to the map */ map_fds[i] = bpf_find_map(__func__, objs[i], "test_map_id"); - if (CHECK_FAIL(map_fds[i] < 0)) + if (!ASSERT_GE(map_fds[i], 0, "bpf_find_map")) goto done; + err = bpf_map_update_elem(map_fds[i], &array_key, &array_magic_value, 0); - if (CHECK_FAIL(err)) + if (!ASSERT_OK(err, "bpf_map_update_elem")) goto done; - prog = bpf_object__find_program_by_name(objs[i], - "test_obj_id"); - if (CHECK_FAIL(!prog)) + prog = bpf_object__find_program_by_name(objs[i], "test_obj_id"); + if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name")) goto done; + links[i] = bpf_program__attach(prog); err = libbpf_get_error(links[i]); - if (CHECK(err, "prog_attach", "prog #%d, err %d\n", i, err)) { + if (!ASSERT_OK(err, "bpf_program__attach")) { links[i] = NULL; goto done; } @@ -81,24 +82,14 @@ void serial_test_bpf_obj_id(void) bzero(&map_infos[i], info_len); err = bpf_map_get_info_by_fd(map_fds[i], &map_infos[i], &info_len); - if (CHECK(err || - map_infos[i].type != BPF_MAP_TYPE_ARRAY || - map_infos[i].key_size != sizeof(__u32) || - map_infos[i].value_size != sizeof(__u64) || - map_infos[i].max_entries != 1 || - map_infos[i].map_flags != 0 || - info_len != sizeof(struct bpf_map_info) || - strcmp((char *)map_infos[i].name, expected_map_name), - "get-map-info(fd)", - "err %d errno %d type %d(%d) info_len %u(%zu) key_size %u value_size %u max_entries %u map_flags %X name %s(%s)\n", - err, errno, - map_infos[i].type, BPF_MAP_TYPE_ARRAY, - info_len, sizeof(struct bpf_map_info), - map_infos[i].key_size, - map_infos[i].value_size, - map_infos[i].max_entries, - map_infos[i].map_flags, - map_infos[i].name, expected_map_name)) + if (!ASSERT_OK(err, "bpf_map_get_info_by_fd") || + !ASSERT_EQ(map_infos[i].type, BPF_MAP_TYPE_ARRAY, "map_type") || + !ASSERT_EQ(map_infos[i].key_size, sizeof(__u32), "key_size") || + !ASSERT_EQ(map_infos[i].value_size, sizeof(__u64), "value_size") || + !ASSERT_EQ(map_infos[i].max_entries, 1, "max_entries") || + !ASSERT_EQ(map_infos[i].map_flags, 0, "map_flags") || + !ASSERT_EQ(info_len, sizeof(struct bpf_map_info), "map_info_len") || + !ASSERT_STREQ((char *)map_infos[i].name, expected_map_name, "map_name")) goto done; /* Check getting prog info */ @@ -112,48 +103,34 @@ void serial_test_bpf_obj_id(void) prog_infos[i].xlated_prog_len = sizeof(xlated_insns); prog_infos[i].map_ids = ptr_to_u64(map_ids + i); prog_infos[i].nr_map_ids = 2; + err = clock_gettime(CLOCK_REALTIME, &real_time_ts); - if (CHECK_FAIL(err)) + if (!ASSERT_OK(err, "clock_gettime")) goto done; + err = clock_gettime(CLOCK_BOOTTIME, &boot_time_ts); - if (CHECK_FAIL(err)) + if (!ASSERT_OK(err, "clock_gettime")) goto done; + err = bpf_prog_get_info_by_fd(prog_fds[i], &prog_infos[i], &info_len); load_time = (real_time_ts.tv_sec - boot_time_ts.tv_sec) + (prog_infos[i].load_time / nsec_per_sec); - if (CHECK(err || - prog_infos[i].type != BPF_PROG_TYPE_RAW_TRACEPOINT || - info_len != sizeof(struct bpf_prog_info) || - (env.jit_enabled && !prog_infos[i].jited_prog_len) || - (env.jit_enabled && - !memcmp(jited_insns, zeros, sizeof(zeros))) || - !prog_infos[i].xlated_prog_len || - !memcmp(xlated_insns, zeros, sizeof(zeros)) || - load_time < now - 60 || load_time > now + 60 || - prog_infos[i].created_by_uid != my_uid || - prog_infos[i].nr_map_ids != 1 || - *(int *)(long)prog_infos[i].map_ids != map_infos[i].id || - strcmp((char *)prog_infos[i].name, expected_prog_name), - "get-prog-info(fd)", - "err %d errno %d i %d type %d(%d) info_len %u(%zu) " - "jit_enabled %d jited_prog_len %u xlated_prog_len %u " - "jited_prog %d xlated_prog %d load_time %lu(%lu) " - "uid %u(%u) nr_map_ids %u(%u) map_id %u(%u) " - "name %s(%s)\n", - err, errno, i, - prog_infos[i].type, BPF_PROG_TYPE_SOCKET_FILTER, - info_len, sizeof(struct bpf_prog_info), - env.jit_enabled, - prog_infos[i].jited_prog_len, - prog_infos[i].xlated_prog_len, - !!memcmp(jited_insns, zeros, sizeof(zeros)), - !!memcmp(xlated_insns, zeros, sizeof(zeros)), - load_time, now, - prog_infos[i].created_by_uid, my_uid, - prog_infos[i].nr_map_ids, 1, - *(int *)(long)prog_infos[i].map_ids, map_infos[i].id, - prog_infos[i].name, expected_prog_name)) + + if (!ASSERT_OK(err, "bpf_prog_get_info_by_fd") || + !ASSERT_EQ(prog_infos[i].type, BPF_PROG_TYPE_RAW_TRACEPOINT, "prog_type") || + !ASSERT_EQ(info_len, sizeof(struct bpf_prog_info), "prog_info_len") || + !ASSERT_FALSE((env.jit_enabled && !prog_infos[i].jited_prog_len), "jited_prog_len") || + !ASSERT_FALSE((env.jit_enabled && !memcmp(jited_insns, zeros, sizeof(zeros))), + "jited_insns") || + !ASSERT_NEQ(prog_infos[i].xlated_prog_len, 0, "xlated_prog_len") || + !ASSERT_NEQ(memcmp(xlated_insns, zeros, sizeof(zeros)), 0, "xlated_insns") || + !ASSERT_GE(load_time, (now - 60), "load_time") || + !ASSERT_LE(load_time, (now + 60), "load_time") || + !ASSERT_EQ(prog_infos[i].created_by_uid, my_uid, "created_by_uid") || + !ASSERT_EQ(prog_infos[i].nr_map_ids, 1, "nr_map_ids") || + !ASSERT_EQ(*(int *)(long)prog_infos[i].map_ids, map_infos[i].id, "map_ids") || + !ASSERT_STREQ((char *)prog_infos[i].name, expected_prog_name, "prog_name")) goto done; /* Check getting link info */ @@ -163,25 +140,12 @@ void serial_test_bpf_obj_id(void) link_infos[i].raw_tracepoint.tp_name_len = sizeof(tp_name); err = bpf_link_get_info_by_fd(bpf_link__fd(links[i]), &link_infos[i], &info_len); - if (CHECK(err || - link_infos[i].type != BPF_LINK_TYPE_RAW_TRACEPOINT || - link_infos[i].prog_id != prog_infos[i].id || - link_infos[i].raw_tracepoint.tp_name != ptr_to_u64(&tp_name) || - strcmp(u64_to_ptr(link_infos[i].raw_tracepoint.tp_name), - "sys_enter") || - info_len != sizeof(struct bpf_link_info), - "get-link-info(fd)", - "err %d errno %d info_len %u(%zu) type %d(%d) id %d " - "prog_id %d (%d) tp_name %s(%s)\n", - err, errno, - info_len, sizeof(struct bpf_link_info), - link_infos[i].type, BPF_LINK_TYPE_RAW_TRACEPOINT, - link_infos[i].id, - link_infos[i].prog_id, prog_infos[i].id, - (const char *)u64_to_ptr(link_infos[i].raw_tracepoint.tp_name), - "sys_enter")) + if (!ASSERT_OK(err, "bpf_link_get_info_by_fd") || + !ASSERT_EQ(link_infos[i].type, BPF_LINK_TYPE_RAW_TRACEPOINT, "link_type") || + !ASSERT_EQ(link_infos[i].prog_id, prog_infos[i].id, "prog_id") || + !ASSERT_EQ(link_infos[i].raw_tracepoint.tp_name, ptr_to_u64(&tp_name), "&tp_name") || + !ASSERT_STREQ(u64_to_ptr(link_infos[i].raw_tracepoint.tp_name), "sys_enter", "tp_name")) goto done; - } /* Check bpf_prog_get_next_id() */ @@ -190,7 +154,7 @@ void serial_test_bpf_obj_id(void) while (!bpf_prog_get_next_id(next_id, &next_id)) { struct bpf_prog_info prog_info = {}; __u32 saved_map_id; - int prog_fd; + int prog_fd, cmp_res; info_len = sizeof(prog_info); @@ -198,9 +162,7 @@ void serial_test_bpf_obj_id(void) if (prog_fd < 0 && errno == ENOENT) /* The bpf_prog is in the dead row */ continue; - if (CHECK(prog_fd < 0, "get-prog-fd(next_id)", - "prog_fd %d next_id %d errno %d\n", - prog_fd, next_id, errno)) + if (!ASSERT_GE(prog_fd, 0, "bpf_prog_get_fd_by_id")) break; for (i = 0; i < nr_iters; i++) @@ -218,9 +180,8 @@ void serial_test_bpf_obj_id(void) */ prog_info.nr_map_ids = 1; err = bpf_prog_get_info_by_fd(prog_fd, &prog_info, &info_len); - if (CHECK(!err || errno != EFAULT, - "get-prog-fd-bad-nr-map-ids", "err %d errno %d(%d)", - err, errno, EFAULT)) + if (!ASSERT_ERR(err, "bpf_prog_get_info_by_fd") || + !ASSERT_EQ(errno, EFAULT, "bpf_prog_get_info_by_fd")) break; bzero(&prog_info, sizeof(prog_info)); info_len = sizeof(prog_info); @@ -231,27 +192,22 @@ void serial_test_bpf_obj_id(void) err = bpf_prog_get_info_by_fd(prog_fd, &prog_info, &info_len); prog_infos[i].jited_prog_insns = 0; prog_infos[i].xlated_prog_insns = 0; - CHECK(err || info_len != sizeof(struct bpf_prog_info) || - memcmp(&prog_info, &prog_infos[i], info_len) || - *(int *)(long)prog_info.map_ids != saved_map_id, - "get-prog-info(next_id->fd)", - "err %d errno %d info_len %u(%zu) memcmp %d map_id %u(%u)\n", - err, errno, info_len, sizeof(struct bpf_prog_info), - memcmp(&prog_info, &prog_infos[i], info_len), - *(int *)(long)prog_info.map_ids, saved_map_id); + cmp_res = memcmp(&prog_info, &prog_infos[i], info_len); + + ASSERT_OK(err, "bpf_prog_get_info_by_fd"); + ASSERT_EQ(info_len, sizeof(struct bpf_prog_info), "prog_info_len"); + ASSERT_OK(cmp_res, "memcmp"); + ASSERT_EQ(*(int *)(long)prog_info.map_ids, saved_map_id, "map_id"); close(prog_fd); } - CHECK(nr_id_found != nr_iters, - "check total prog id found by get_next_id", - "nr_id_found %u(%u)\n", - nr_id_found, nr_iters); + ASSERT_EQ(nr_id_found, nr_iters, "prog_nr_id_found"); /* Check bpf_map_get_next_id() */ nr_id_found = 0; next_id = 0; while (!bpf_map_get_next_id(next_id, &next_id)) { struct bpf_map_info map_info = {}; - int map_fd; + int map_fd, cmp_res; info_len = sizeof(map_info); @@ -259,9 +215,7 @@ void serial_test_bpf_obj_id(void) if (map_fd < 0 && errno == ENOENT) /* The bpf_map is in the dead row */ continue; - if (CHECK(map_fd < 0, "get-map-fd(next_id)", - "map_fd %d next_id %u errno %d\n", - map_fd, next_id, errno)) + if (!ASSERT_GE(map_fd, 0, "bpf_map_get_fd_by_id")) break; for (i = 0; i < nr_iters; i++) @@ -274,25 +228,19 @@ void serial_test_bpf_obj_id(void) nr_id_found++; err = bpf_map_lookup_elem(map_fd, &array_key, &array_value); - if (CHECK_FAIL(err)) + if (!ASSERT_OK(err, "bpf_map_lookup_elem")) goto done; err = bpf_map_get_info_by_fd(map_fd, &map_info, &info_len); - CHECK(err || info_len != sizeof(struct bpf_map_info) || - memcmp(&map_info, &map_infos[i], info_len) || - array_value != array_magic_value, - "check get-map-info(next_id->fd)", - "err %d errno %d info_len %u(%zu) memcmp %d array_value %llu(%llu)\n", - err, errno, info_len, sizeof(struct bpf_map_info), - memcmp(&map_info, &map_infos[i], info_len), - array_value, array_magic_value); + cmp_res = memcmp(&map_info, &map_infos[i], info_len); + ASSERT_OK(err, "bpf_map_get_info_by_fd"); + ASSERT_EQ(info_len, sizeof(struct bpf_map_info), "info_len"); + ASSERT_OK(cmp_res, "memcmp"); + ASSERT_EQ(array_value, array_magic_value, "array_value"); close(map_fd); } - CHECK(nr_id_found != nr_iters, - "check total map id found by get_next_id", - "nr_id_found %u(%u)\n", - nr_id_found, nr_iters); + ASSERT_EQ(nr_id_found, nr_iters, "map_nr_id_found"); /* Check bpf_link_get_next_id() */ nr_id_found = 0; @@ -308,9 +256,7 @@ void serial_test_bpf_obj_id(void) if (link_fd < 0 && errno == ENOENT) /* The bpf_link is in the dead row */ continue; - if (CHECK(link_fd < 0, "get-link-fd(next_id)", - "link_fd %d next_id %u errno %d\n", - link_fd, next_id, errno)) + if (!ASSERT_GE(link_fd, 0, "bpf_link_get_fd_by_id")) break; for (i = 0; i < nr_iters; i++) @@ -325,17 +271,13 @@ void serial_test_bpf_obj_id(void) err = bpf_link_get_info_by_fd(link_fd, &link_info, &info_len); cmp_res = memcmp(&link_info, &link_infos[i], offsetof(struct bpf_link_info, raw_tracepoint)); - CHECK(err || info_len != sizeof(link_info) || cmp_res, - "check get-link-info(next_id->fd)", - "err %d errno %d info_len %u(%zu) memcmp %d\n", - err, errno, info_len, sizeof(struct bpf_link_info), - cmp_res); + ASSERT_OK(err, "bpf_link_get_info_by_fd"); + ASSERT_EQ(info_len, sizeof(link_info), "info_len"); + ASSERT_OK(cmp_res, "memcmp"); close(link_fd); } - CHECK(nr_id_found != nr_iters, - "check total link id found by get_next_id", - "nr_id_found %u(%u)\n", nr_id_found, nr_iters); + ASSERT_EQ(nr_id_found, nr_iters, "link_nr_id_found"); done: for (i = 0; i < nr_iters; i++) { diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c b/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c index 4aabeaa525..a88e6e07e4 100644 --- a/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c +++ b/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c @@ -20,15 +20,14 @@ static const unsigned int total_bytes = 10 * 1024 * 1024; static int expected_stg = 0xeB9F; -static int stop, duration; +static int stop; static int settcpca(int fd, const char *tcp_ca) { int err; err = setsockopt(fd, IPPROTO_TCP, TCP_CONGESTION, tcp_ca, strlen(tcp_ca)); - if (CHECK(err == -1, "setsockopt(fd, TCP_CONGESTION)", "errno:%d\n", - errno)) + if (!ASSERT_NEQ(err, -1, "setsockopt")) return -1; return 0; @@ -65,8 +64,7 @@ static void *server(void *arg) bytes += nr_sent; } - CHECK(bytes != total_bytes, "send", "%zd != %u nr_sent:%zd errno:%d\n", - bytes, total_bytes, nr_sent, errno); + ASSERT_EQ(bytes, total_bytes, "send"); done: if (fd >= 0) @@ -92,10 +90,11 @@ static void do_test(const char *tcp_ca, const struct bpf_map *sk_stg_map) WRITE_ONCE(stop, 0); lfd = socket(AF_INET6, SOCK_STREAM, 0); - if (CHECK(lfd == -1, "socket", "errno:%d\n", errno)) + if (!ASSERT_NEQ(lfd, -1, "socket")) return; + fd = socket(AF_INET6, SOCK_STREAM, 0); - if (CHECK(fd == -1, "socket", "errno:%d\n", errno)) { + if (!ASSERT_NEQ(fd, -1, "socket")) { close(lfd); return; } @@ -108,26 +107,27 @@ static void do_test(const char *tcp_ca, const struct bpf_map *sk_stg_map) sa6.sin6_family = AF_INET6; sa6.sin6_addr = in6addr_loopback; err = bind(lfd, (struct sockaddr *)&sa6, addrlen); - if (CHECK(err == -1, "bind", "errno:%d\n", errno)) + if (!ASSERT_NEQ(err, -1, "bind")) goto done; + err = getsockname(lfd, (struct sockaddr *)&sa6, &addrlen); - if (CHECK(err == -1, "getsockname", "errno:%d\n", errno)) + if (!ASSERT_NEQ(err, -1, "getsockname")) goto done; + err = listen(lfd, 1); - if (CHECK(err == -1, "listen", "errno:%d\n", errno)) + if (!ASSERT_NEQ(err, -1, "listen")) goto done; if (sk_stg_map) { err = bpf_map_update_elem(bpf_map__fd(sk_stg_map), &fd, &expected_stg, BPF_NOEXIST); - if (CHECK(err, "bpf_map_update_elem(sk_stg_map)", - "err:%d errno:%d\n", err, errno)) + if (!ASSERT_OK(err, "bpf_map_update_elem(sk_stg_map)")) goto done; } /* connect to server */ err = connect(fd, (struct sockaddr *)&sa6, addrlen); - if (CHECK(err == -1, "connect", "errno:%d\n", errno)) + if (!ASSERT_NEQ(err, -1, "connect")) goto done; if (sk_stg_map) { @@ -135,14 +135,13 @@ static void do_test(const char *tcp_ca, const struct bpf_map *sk_stg_map) err = bpf_map_lookup_elem(bpf_map__fd(sk_stg_map), &fd, &tmp_stg); - if (CHECK(!err || errno != ENOENT, - "bpf_map_lookup_elem(sk_stg_map)", - "err:%d errno:%d\n", err, errno)) + if (!ASSERT_ERR(err, "bpf_map_lookup_elem(sk_stg_map)") || + !ASSERT_EQ(errno, ENOENT, "bpf_map_lookup_elem(sk_stg_map)")) goto done; } err = pthread_create(&srv_thread, NULL, server, (void *)(long)lfd); - if (CHECK(err != 0, "pthread_create", "err:%d errno:%d\n", err, errno)) + if (!ASSERT_OK(err, "pthread_create")) goto done; /* recv total_bytes */ @@ -156,13 +155,12 @@ static void do_test(const char *tcp_ca, const struct bpf_map *sk_stg_map) bytes += nr_recv; } - CHECK(bytes != total_bytes, "recv", "%zd != %u nr_recv:%zd errno:%d\n", - bytes, total_bytes, nr_recv, errno); + ASSERT_EQ(bytes, total_bytes, "recv"); WRITE_ONCE(stop, 1); pthread_join(srv_thread, &thread_ret); - CHECK(IS_ERR(thread_ret), "pthread_join", "thread_ret:%ld", - PTR_ERR(thread_ret)); + ASSERT_OK(IS_ERR(thread_ret), "thread_ret"); + done: close(lfd); close(fd); @@ -174,7 +172,7 @@ static void test_cubic(void) struct bpf_link *link; cubic_skel = bpf_cubic__open_and_load(); - if (CHECK(!cubic_skel, "bpf_cubic__open_and_load", "failed\n")) + if (!ASSERT_OK_PTR(cubic_skel, "bpf_cubic__open_and_load")) return; link = bpf_map__attach_struct_ops(cubic_skel->maps.cubic); @@ -197,7 +195,7 @@ static void test_dctcp(void) struct bpf_link *link; dctcp_skel = bpf_dctcp__open_and_load(); - if (CHECK(!dctcp_skel, "bpf_dctcp__open_and_load", "failed\n")) + if (!ASSERT_OK_PTR(dctcp_skel, "bpf_dctcp__open_and_load")) return; link = bpf_map__attach_struct_ops(dctcp_skel->maps.dctcp); @@ -207,9 +205,7 @@ static void test_dctcp(void) } do_test("bpf_dctcp", dctcp_skel->maps.sk_stg_map); - CHECK(dctcp_skel->bss->stg_result != expected_stg, - "Unexpected stg_result", "stg_result (%x) != expected_stg (%x)\n", - dctcp_skel->bss->stg_result, expected_stg); + ASSERT_EQ(dctcp_skel->bss->stg_result, expected_stg, "stg_result"); bpf_link__destroy(link); bpf_dctcp__destroy(dctcp_skel); diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_verif_scale.c b/tools/testing/selftests/bpf/prog_tests/bpf_verif_scale.c index 731c343897..e770912fc1 100644 --- a/tools/testing/selftests/bpf/prog_tests/bpf_verif_scale.c +++ b/tools/testing/selftests/bpf/prog_tests/bpf_verif_scale.c @@ -35,7 +35,7 @@ static int check_load(const char *file, enum bpf_prog_type type) } bpf_program__set_type(prog, type); - bpf_program__set_flags(prog, BPF_F_TEST_RND_HI32); + bpf_program__set_flags(prog, BPF_F_TEST_RND_HI32 | BPF_F_TEST_REG_INVARIANTS); bpf_program__set_log_level(prog, 4 | extra_prog_load_log_flags); err = bpf_object__load(obj); diff --git a/tools/testing/selftests/bpf/prog_tests/cgroup1_hierarchy.c b/tools/testing/selftests/bpf/prog_tests/cgroup1_hierarchy.c new file mode 100644 index 0000000000..74d6d7546f --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/cgroup1_hierarchy.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2023 Yafang Shao */ + +#include +#include +#include +#include "cgroup_helpers.h" +#include "test_cgroup1_hierarchy.skel.h" + +static void bpf_cgroup1(struct test_cgroup1_hierarchy *skel) +{ + struct bpf_link *lsm_link, *fentry_link; + int err; + + /* Attach LSM prog first */ + lsm_link = bpf_program__attach_lsm(skel->progs.lsm_run); + if (!ASSERT_OK_PTR(lsm_link, "lsm_attach")) + return; + + /* LSM prog will be triggered when attaching fentry */ + fentry_link = bpf_program__attach_trace(skel->progs.fentry_run); + ASSERT_NULL(fentry_link, "fentry_attach_fail"); + + err = bpf_link__destroy(lsm_link); + ASSERT_OK(err, "destroy_lsm"); +} + +static void bpf_cgroup1_sleepable(struct test_cgroup1_hierarchy *skel) +{ + struct bpf_link *lsm_link, *fentry_link; + int err; + + /* Attach LSM prog first */ + lsm_link = bpf_program__attach_lsm(skel->progs.lsm_s_run); + if (!ASSERT_OK_PTR(lsm_link, "lsm_attach")) + return; + + /* LSM prog will be triggered when attaching fentry */ + fentry_link = bpf_program__attach_trace(skel->progs.fentry_run); + ASSERT_NULL(fentry_link, "fentry_attach_fail"); + + err = bpf_link__destroy(lsm_link); + ASSERT_OK(err, "destroy_lsm"); +} + +static void bpf_cgroup1_invalid_id(struct test_cgroup1_hierarchy *skel) +{ + struct bpf_link *lsm_link, *fentry_link; + int err; + + /* Attach LSM prog first */ + lsm_link = bpf_program__attach_lsm(skel->progs.lsm_run); + if (!ASSERT_OK_PTR(lsm_link, "lsm_attach")) + return; + + /* LSM prog will be triggered when attaching fentry */ + fentry_link = bpf_program__attach_trace(skel->progs.fentry_run); + if (!ASSERT_OK_PTR(fentry_link, "fentry_attach_success")) + goto cleanup; + + err = bpf_link__destroy(fentry_link); + ASSERT_OK(err, "destroy_lsm"); + +cleanup: + err = bpf_link__destroy(lsm_link); + ASSERT_OK(err, "destroy_fentry"); +} + +void test_cgroup1_hierarchy(void) +{ + struct test_cgroup1_hierarchy *skel; + __u64 current_cgid; + int hid, err; + + skel = test_cgroup1_hierarchy__open(); + if (!ASSERT_OK_PTR(skel, "open")) + return; + + skel->bss->target_pid = getpid(); + + err = bpf_program__set_attach_target(skel->progs.fentry_run, 0, "bpf_fentry_test1"); + if (!ASSERT_OK(err, "fentry_set_target")) + goto destroy; + + err = test_cgroup1_hierarchy__load(skel); + if (!ASSERT_OK(err, "load")) + goto destroy; + + /* Setup cgroup1 hierarchy */ + err = setup_classid_environment(); + if (!ASSERT_OK(err, "setup_classid_environment")) + goto destroy; + + err = join_classid(); + if (!ASSERT_OK(err, "join_cgroup1")) + goto cleanup; + + current_cgid = get_classid_cgroup_id(); + if (!ASSERT_GE(current_cgid, 0, "cgroup1 id")) + goto cleanup; + + hid = get_cgroup1_hierarchy_id("net_cls"); + if (!ASSERT_GE(hid, 0, "cgroup1 id")) + goto cleanup; + skel->bss->target_hid = hid; + + if (test__start_subtest("test_cgroup1_hierarchy")) { + skel->bss->target_ancestor_cgid = current_cgid; + bpf_cgroup1(skel); + } + + if (test__start_subtest("test_root_cgid")) { + skel->bss->target_ancestor_cgid = 1; + skel->bss->target_ancestor_level = 0; + bpf_cgroup1(skel); + } + + if (test__start_subtest("test_invalid_level")) { + skel->bss->target_ancestor_cgid = 1; + skel->bss->target_ancestor_level = 1; + bpf_cgroup1_invalid_id(skel); + } + + if (test__start_subtest("test_invalid_cgid")) { + skel->bss->target_ancestor_cgid = 0; + bpf_cgroup1_invalid_id(skel); + } + + if (test__start_subtest("test_invalid_hid")) { + skel->bss->target_ancestor_cgid = 1; + skel->bss->target_ancestor_level = 0; + skel->bss->target_hid = -1; + bpf_cgroup1_invalid_id(skel); + } + + if (test__start_subtest("test_invalid_cgrp_name")) { + skel->bss->target_hid = get_cgroup1_hierarchy_id("net_cl"); + skel->bss->target_ancestor_cgid = current_cgid; + bpf_cgroup1_invalid_id(skel); + } + + if (test__start_subtest("test_invalid_cgrp_name2")) { + skel->bss->target_hid = get_cgroup1_hierarchy_id("net_cls,"); + skel->bss->target_ancestor_cgid = current_cgid; + bpf_cgroup1_invalid_id(skel); + } + + if (test__start_subtest("test_sleepable_prog")) { + skel->bss->target_hid = hid; + skel->bss->target_ancestor_cgid = current_cgid; + bpf_cgroup1_sleepable(skel); + } + +cleanup: + cleanup_classid_environment(); +destroy: + test_cgroup1_hierarchy__destroy(skel); +} diff --git a/tools/testing/selftests/bpf/prog_tests/cgroup_v1v2.c b/tools/testing/selftests/bpf/prog_tests/cgroup_v1v2.c index 9026b42914..addf720428 100644 --- a/tools/testing/selftests/bpf/prog_tests/cgroup_v1v2.c +++ b/tools/testing/selftests/bpf/prog_tests/cgroup_v1v2.c @@ -71,7 +71,7 @@ void test_cgroup_v1v2(void) } ASSERT_OK(run_test(cgroup_fd, server_fd, false), "cgroup-v2-only"); setup_classid_environment(); - set_classid(42); + set_classid(); ASSERT_OK(run_test(cgroup_fd, server_fd, true), "cgroup-v1v2"); cleanup_classid_environment(); close(server_fd); diff --git a/tools/testing/selftests/bpf/prog_tests/cgrp_local_storage.c b/tools/testing/selftests/bpf/prog_tests/cgrp_local_storage.c index 63e776f417..7477615720 100644 --- a/tools/testing/selftests/bpf/prog_tests/cgrp_local_storage.c +++ b/tools/testing/selftests/bpf/prog_tests/cgrp_local_storage.c @@ -19,6 +19,21 @@ struct socket_cookie { __u64 cookie_value; }; +static bool is_cgroup1; +static int target_hid; + +#define CGROUP_MODE_SET(skel) \ +{ \ + skel->bss->is_cgroup1 = is_cgroup1; \ + skel->bss->target_hid = target_hid; \ +} + +static void cgroup_mode_value_init(bool cgroup, int hid) +{ + is_cgroup1 = cgroup; + target_hid = hid; +} + static void test_tp_btf(int cgroup_fd) { struct cgrp_ls_tp_btf *skel; @@ -29,6 +44,8 @@ static void test_tp_btf(int cgroup_fd) if (!ASSERT_OK_PTR(skel, "skel_open_and_load")) return; + CGROUP_MODE_SET(skel); + /* populate a value in map_b */ err = bpf_map_update_elem(bpf_map__fd(skel->maps.map_b), &cgroup_fd, &val1, BPF_ANY); if (!ASSERT_OK(err, "map_update_elem")) @@ -130,6 +147,8 @@ static void test_recursion(int cgroup_fd) if (!ASSERT_OK_PTR(skel, "skel_open_and_load")) return; + CGROUP_MODE_SET(skel); + err = cgrp_ls_recursion__attach(skel); if (!ASSERT_OK(err, "skel_attach")) goto out; @@ -165,6 +184,8 @@ static void test_cgroup_iter_sleepable(int cgroup_fd, __u64 cgroup_id) if (!ASSERT_OK_PTR(skel, "skel_open")) return; + CGROUP_MODE_SET(skel); + bpf_program__set_autoload(skel->progs.cgroup_iter, true); err = cgrp_ls_sleepable__load(skel); if (!ASSERT_OK(err, "skel_load")) @@ -202,6 +223,7 @@ static void test_yes_rcu_lock(__u64 cgroup_id) if (!ASSERT_OK_PTR(skel, "skel_open")) return; + CGROUP_MODE_SET(skel); skel->bss->target_pid = syscall(SYS_gettid); bpf_program__set_autoload(skel->progs.yes_rcu_lock, true); @@ -229,6 +251,8 @@ static void test_no_rcu_lock(void) if (!ASSERT_OK_PTR(skel, "skel_open")) return; + CGROUP_MODE_SET(skel); + bpf_program__set_autoload(skel->progs.no_rcu_lock, true); err = cgrp_ls_sleepable__load(skel); ASSERT_ERR(err, "skel_load"); @@ -236,7 +260,25 @@ static void test_no_rcu_lock(void) cgrp_ls_sleepable__destroy(skel); } -void test_cgrp_local_storage(void) +static void test_cgrp1_no_rcu_lock(void) +{ + struct cgrp_ls_sleepable *skel; + int err; + + skel = cgrp_ls_sleepable__open(); + if (!ASSERT_OK_PTR(skel, "skel_open")) + return; + + CGROUP_MODE_SET(skel); + + bpf_program__set_autoload(skel->progs.cgrp1_no_rcu_lock, true); + err = cgrp_ls_sleepable__load(skel); + ASSERT_OK(err, "skel_load"); + + cgrp_ls_sleepable__destroy(skel); +} + +static void cgrp2_local_storage(void) { __u64 cgroup_id; int cgroup_fd; @@ -245,6 +287,8 @@ void test_cgrp_local_storage(void) if (!ASSERT_GE(cgroup_fd, 0, "join_cgroup /cgrp_local_storage")) return; + cgroup_mode_value_init(0, -1); + cgroup_id = get_cgroup_id("/cgrp_local_storage"); if (test__start_subtest("tp_btf")) test_tp_btf(cgroup_fd); @@ -263,3 +307,55 @@ void test_cgrp_local_storage(void) close(cgroup_fd); } + +static void cgrp1_local_storage(void) +{ + int cgrp1_fd, cgrp1_hid, cgrp1_id, err; + + /* Setup cgroup1 hierarchy */ + err = setup_classid_environment(); + if (!ASSERT_OK(err, "setup_classid_environment")) + return; + + err = join_classid(); + if (!ASSERT_OK(err, "join_cgroup1")) + goto cleanup; + + cgrp1_fd = open_classid(); + if (!ASSERT_GE(cgrp1_fd, 0, "cgroup1 fd")) + goto cleanup; + + cgrp1_id = get_classid_cgroup_id(); + if (!ASSERT_GE(cgrp1_id, 0, "cgroup1 id")) + goto close_fd; + + cgrp1_hid = get_cgroup1_hierarchy_id("net_cls"); + if (!ASSERT_GE(cgrp1_hid, 0, "cgroup1 hid")) + goto close_fd; + + cgroup_mode_value_init(1, cgrp1_hid); + + if (test__start_subtest("cgrp1_tp_btf")) + test_tp_btf(cgrp1_fd); + if (test__start_subtest("cgrp1_recursion")) + test_recursion(cgrp1_fd); + if (test__start_subtest("cgrp1_negative")) + test_negative(); + if (test__start_subtest("cgrp1_iter_sleepable")) + test_cgroup_iter_sleepable(cgrp1_fd, cgrp1_id); + if (test__start_subtest("cgrp1_yes_rcu_lock")) + test_yes_rcu_lock(cgrp1_id); + if (test__start_subtest("cgrp1_no_rcu_lock")) + test_cgrp1_no_rcu_lock(); + +close_fd: + close(cgrp1_fd); +cleanup: + cleanup_classid_environment(); +} + +void test_cgrp_local_storage(void) +{ + cgrp2_local_storage(); + cgrp1_local_storage(); +} diff --git a/tools/testing/selftests/bpf/prog_tests/cpumask.c b/tools/testing/selftests/bpf/prog_tests/cpumask.c index 756ea8b590..c2e886399e 100644 --- a/tools/testing/selftests/bpf/prog_tests/cpumask.c +++ b/tools/testing/selftests/bpf/prog_tests/cpumask.c @@ -18,6 +18,7 @@ static const char * const cpumask_success_testcases[] = { "test_insert_leave", "test_insert_remove_release", "test_global_mask_rcu", + "test_cpumask_weight", }; static void verify_success(const char *prog_name) diff --git a/tools/testing/selftests/bpf/prog_tests/fexit_bpf2bpf.c b/tools/testing/selftests/bpf/prog_tests/fexit_bpf2bpf.c index 8ec73fdfcd..f29fc789c1 100644 --- a/tools/testing/selftests/bpf/prog_tests/fexit_bpf2bpf.c +++ b/tools/testing/selftests/bpf/prog_tests/fexit_bpf2bpf.c @@ -348,7 +348,8 @@ static void test_func_sockmap_update(void) } static void test_obj_load_failure_common(const char *obj_file, - const char *target_obj_file) + const char *target_obj_file, + const char *exp_msg) { /* * standalone test that asserts failure to load freplace prog @@ -356,6 +357,7 @@ static void test_obj_load_failure_common(const char *obj_file, */ struct bpf_object *obj = NULL, *pkt_obj; struct bpf_program *prog; + char log_buf[64 * 1024]; int err, pkt_fd; __u32 duration = 0; @@ -374,11 +376,21 @@ static void test_obj_load_failure_common(const char *obj_file, err = bpf_program__set_attach_target(prog, pkt_fd, NULL); ASSERT_OK(err, "set_attach_target"); + log_buf[0] = '\0'; + if (exp_msg) + bpf_program__set_log_buf(prog, log_buf, sizeof(log_buf)); + if (env.verbosity > VERBOSE_NONE) + bpf_program__set_log_level(prog, 2); + /* It should fail to load the program */ err = bpf_object__load(obj); + if (env.verbosity > VERBOSE_NONE && exp_msg) /* we overtook log */ + printf("VERIFIER LOG:\n================\n%s\n================\n", log_buf); if (CHECK(!err, "bpf_obj_load should fail", "err %d\n", err)) goto close_prog; + if (exp_msg) + ASSERT_HAS_SUBSTR(log_buf, exp_msg, "fail_msg"); close_prog: bpf_object__close(obj); bpf_object__close(pkt_obj); @@ -388,14 +400,24 @@ static void test_func_replace_return_code(void) { /* test invalid return code in the replaced program */ test_obj_load_failure_common("./freplace_connect_v4_prog.bpf.o", - "./connect4_prog.bpf.o"); + "./connect4_prog.bpf.o", NULL); } static void test_func_map_prog_compatibility(void) { /* test with spin lock map value in the replaced program */ test_obj_load_failure_common("./freplace_attach_probe.bpf.o", - "./test_attach_probe.bpf.o"); + "./test_attach_probe.bpf.o", NULL); +} + +static void test_func_replace_unreliable(void) +{ + /* freplace'ing unreliable main prog should fail with error + * "Cannot replace static functions" + */ + test_obj_load_failure_common("freplace_unreliable_prog.bpf.o", + "./verifier_btf_unreliable_prog.bpf.o", + "Cannot replace static functions"); } static void test_func_replace_global_func(void) @@ -563,6 +585,8 @@ void serial_test_fexit_bpf2bpf(void) test_func_replace_return_code(); if (test__start_subtest("func_map_prog_compatibility")) test_func_map_prog_compatibility(); + if (test__start_subtest("func_replace_unreliable")) + test_func_replace_unreliable(); if (test__start_subtest("func_replace_multi")) test_func_replace_multi(); if (test__start_subtest("fmod_ret_freplace")) diff --git a/tools/testing/selftests/bpf/prog_tests/fill_link_info.c b/tools/testing/selftests/bpf/prog_tests/fill_link_info.c index 97142a4db3..d4b1901f78 100644 --- a/tools/testing/selftests/bpf/prog_tests/fill_link_info.c +++ b/tools/testing/selftests/bpf/prog_tests/fill_link_info.c @@ -7,6 +7,7 @@ #include #include "trace_helpers.h" #include "test_fill_link_info.skel.h" +#include "bpf/libbpf_internal.h" #define TP_CAT "sched" #define TP_NAME "sched_switch" @@ -140,14 +141,14 @@ static void test_kprobe_fill_link_info(struct test_fill_link_info *skel, .retprobe = type == BPF_PERF_EVENT_KRETPROBE, ); ssize_t entry_offset = 0; + struct bpf_link *link; int link_fd, err; - skel->links.kprobe_run = bpf_program__attach_kprobe_opts(skel->progs.kprobe_run, - KPROBE_FUNC, &opts); - if (!ASSERT_OK_PTR(skel->links.kprobe_run, "attach_kprobe")) + link = bpf_program__attach_kprobe_opts(skel->progs.kprobe_run, KPROBE_FUNC, &opts); + if (!ASSERT_OK_PTR(link, "attach_kprobe")) return; - link_fd = bpf_link__fd(skel->links.kprobe_run); + link_fd = bpf_link__fd(link); if (!invalid) { /* See also arch_adjust_kprobe_addr(). */ if (skel->kconfig->CONFIG_X86_KERNEL_IBT) @@ -157,39 +158,41 @@ static void test_kprobe_fill_link_info(struct test_fill_link_info *skel, } else { kprobe_fill_invalid_user_buffer(link_fd); } - bpf_link__detach(skel->links.kprobe_run); + bpf_link__destroy(link); } static void test_tp_fill_link_info(struct test_fill_link_info *skel) { + struct bpf_link *link; int link_fd, err; - skel->links.tp_run = bpf_program__attach_tracepoint(skel->progs.tp_run, TP_CAT, TP_NAME); - if (!ASSERT_OK_PTR(skel->links.tp_run, "attach_tp")) + link = bpf_program__attach_tracepoint(skel->progs.tp_run, TP_CAT, TP_NAME); + if (!ASSERT_OK_PTR(link, "attach_tp")) return; - link_fd = bpf_link__fd(skel->links.tp_run); + link_fd = bpf_link__fd(link); err = verify_perf_link_info(link_fd, BPF_PERF_EVENT_TRACEPOINT, 0, 0, 0); ASSERT_OK(err, "verify_perf_link_info"); - bpf_link__detach(skel->links.tp_run); + bpf_link__destroy(link); } static void test_uprobe_fill_link_info(struct test_fill_link_info *skel, enum bpf_perf_event_type type) { + struct bpf_link *link; int link_fd, err; - skel->links.uprobe_run = bpf_program__attach_uprobe(skel->progs.uprobe_run, - type == BPF_PERF_EVENT_URETPROBE, - 0, /* self pid */ - UPROBE_FILE, uprobe_offset); - if (!ASSERT_OK_PTR(skel->links.uprobe_run, "attach_uprobe")) + link = bpf_program__attach_uprobe(skel->progs.uprobe_run, + type == BPF_PERF_EVENT_URETPROBE, + 0, /* self pid */ + UPROBE_FILE, uprobe_offset); + if (!ASSERT_OK_PTR(link, "attach_uprobe")) return; - link_fd = bpf_link__fd(skel->links.uprobe_run); + link_fd = bpf_link__fd(link); err = verify_perf_link_info(link_fd, type, 0, uprobe_offset, 0); ASSERT_OK(err, "verify_perf_link_info"); - bpf_link__detach(skel->links.uprobe_run); + bpf_link__destroy(link); } static int verify_kmulti_link_info(int fd, bool retprobe) @@ -278,24 +281,214 @@ static void test_kprobe_multi_fill_link_info(struct test_fill_link_info *skel, bool retprobe, bool invalid) { LIBBPF_OPTS(bpf_kprobe_multi_opts, opts); + struct bpf_link *link; int link_fd, err; opts.syms = kmulti_syms; opts.cnt = KMULTI_CNT; opts.retprobe = retprobe; - skel->links.kmulti_run = bpf_program__attach_kprobe_multi_opts(skel->progs.kmulti_run, - NULL, &opts); - if (!ASSERT_OK_PTR(skel->links.kmulti_run, "attach_kprobe_multi")) + link = bpf_program__attach_kprobe_multi_opts(skel->progs.kmulti_run, NULL, &opts); + if (!ASSERT_OK_PTR(link, "attach_kprobe_multi")) return; - link_fd = bpf_link__fd(skel->links.kmulti_run); + link_fd = bpf_link__fd(link); if (!invalid) { err = verify_kmulti_link_info(link_fd, retprobe); ASSERT_OK(err, "verify_kmulti_link_info"); } else { verify_kmulti_invalid_user_buffer(link_fd); } - bpf_link__detach(skel->links.kmulti_run); + bpf_link__destroy(link); +} + +#define SEC(name) __attribute__((section(name), used)) + +static short uprobe_link_info_sema_1 SEC(".probes"); +static short uprobe_link_info_sema_2 SEC(".probes"); +static short uprobe_link_info_sema_3 SEC(".probes"); + +noinline void uprobe_link_info_func_1(void) +{ + asm volatile (""); + uprobe_link_info_sema_1++; +} + +noinline void uprobe_link_info_func_2(void) +{ + asm volatile (""); + uprobe_link_info_sema_2++; +} + +noinline void uprobe_link_info_func_3(void) +{ + asm volatile (""); + uprobe_link_info_sema_3++; +} + +static int +verify_umulti_link_info(int fd, bool retprobe, __u64 *offsets, + __u64 *cookies, __u64 *ref_ctr_offsets) +{ + char path[PATH_MAX], path_buf[PATH_MAX]; + struct bpf_link_info info; + __u32 len = sizeof(info); + __u64 ref_ctr_offsets_buf[3]; + __u64 offsets_buf[3]; + __u64 cookies_buf[3]; + int i, err, bit; + __u32 count = 0; + + memset(path, 0, sizeof(path)); + err = readlink("/proc/self/exe", path, sizeof(path)); + if (!ASSERT_NEQ(err, -1, "readlink")) + return -1; + + for (bit = 0; bit < 8; bit++) { + memset(&info, 0, sizeof(info)); + info.uprobe_multi.path = ptr_to_u64(path_buf); + info.uprobe_multi.path_size = sizeof(path_buf); + info.uprobe_multi.count = count; + + if (bit & 0x1) + info.uprobe_multi.offsets = ptr_to_u64(offsets_buf); + if (bit & 0x2) + info.uprobe_multi.cookies = ptr_to_u64(cookies_buf); + if (bit & 0x4) + info.uprobe_multi.ref_ctr_offsets = ptr_to_u64(ref_ctr_offsets_buf); + + err = bpf_link_get_info_by_fd(fd, &info, &len); + if (!ASSERT_OK(err, "bpf_link_get_info_by_fd")) + return -1; + + if (!ASSERT_EQ(info.type, BPF_LINK_TYPE_UPROBE_MULTI, "info.type")) + return -1; + + ASSERT_EQ(info.uprobe_multi.pid, getpid(), "info.uprobe_multi.pid"); + ASSERT_EQ(info.uprobe_multi.count, 3, "info.uprobe_multi.count"); + ASSERT_EQ(info.uprobe_multi.flags & BPF_F_KPROBE_MULTI_RETURN, + retprobe, "info.uprobe_multi.flags.retprobe"); + ASSERT_EQ(info.uprobe_multi.path_size, strlen(path) + 1, "info.uprobe_multi.path_size"); + ASSERT_STREQ(path_buf, path, "info.uprobe_multi.path"); + + for (i = 0; i < info.uprobe_multi.count; i++) { + if (info.uprobe_multi.offsets) + ASSERT_EQ(offsets_buf[i], offsets[i], "info.uprobe_multi.offsets"); + if (info.uprobe_multi.cookies) + ASSERT_EQ(cookies_buf[i], cookies[i], "info.uprobe_multi.cookies"); + if (info.uprobe_multi.ref_ctr_offsets) { + ASSERT_EQ(ref_ctr_offsets_buf[i], ref_ctr_offsets[i], + "info.uprobe_multi.ref_ctr_offsets"); + } + } + count = count ?: info.uprobe_multi.count; + } + + return 0; +} + +static void verify_umulti_invalid_user_buffer(int fd) +{ + struct bpf_link_info info; + __u32 len = sizeof(info); + __u64 buf[3]; + int err; + + /* upath_size defined, not path */ + memset(&info, 0, sizeof(info)); + info.uprobe_multi.path_size = 3; + err = bpf_link_get_info_by_fd(fd, &info, &len); + ASSERT_EQ(err, -EINVAL, "failed_upath_size"); + + /* path defined, but small */ + memset(&info, 0, sizeof(info)); + info.uprobe_multi.path = ptr_to_u64(buf); + info.uprobe_multi.path_size = 3; + err = bpf_link_get_info_by_fd(fd, &info, &len); + ASSERT_LT(err, 0, "failed_upath_small"); + + /* path has wrong pointer */ + memset(&info, 0, sizeof(info)); + info.uprobe_multi.path_size = PATH_MAX; + info.uprobe_multi.path = 123; + err = bpf_link_get_info_by_fd(fd, &info, &len); + ASSERT_EQ(err, -EFAULT, "failed_bad_path_ptr"); + + /* count zero, with offsets */ + memset(&info, 0, sizeof(info)); + info.uprobe_multi.offsets = ptr_to_u64(buf); + err = bpf_link_get_info_by_fd(fd, &info, &len); + ASSERT_EQ(err, -EINVAL, "failed_count"); + + /* offsets not big enough */ + memset(&info, 0, sizeof(info)); + info.uprobe_multi.offsets = ptr_to_u64(buf); + info.uprobe_multi.count = 2; + err = bpf_link_get_info_by_fd(fd, &info, &len); + ASSERT_EQ(err, -ENOSPC, "failed_small_count"); + + /* offsets has wrong pointer */ + memset(&info, 0, sizeof(info)); + info.uprobe_multi.offsets = 123; + info.uprobe_multi.count = 3; + err = bpf_link_get_info_by_fd(fd, &info, &len); + ASSERT_EQ(err, -EFAULT, "failed_wrong_offsets"); +} + +static void test_uprobe_multi_fill_link_info(struct test_fill_link_info *skel, + bool retprobe, bool invalid) +{ + LIBBPF_OPTS(bpf_uprobe_multi_opts, opts, + .retprobe = retprobe, + ); + const char *syms[3] = { + "uprobe_link_info_func_1", + "uprobe_link_info_func_2", + "uprobe_link_info_func_3", + }; + __u64 cookies[3] = { + 0xdead, + 0xbeef, + 0xcafe, + }; + const char *sema[3] = { + "uprobe_link_info_sema_1", + "uprobe_link_info_sema_2", + "uprobe_link_info_sema_3", + }; + __u64 *offsets = NULL, *ref_ctr_offsets; + struct bpf_link *link; + int link_fd, err; + + err = elf_resolve_syms_offsets("/proc/self/exe", 3, sema, + (unsigned long **) &ref_ctr_offsets, STT_OBJECT); + if (!ASSERT_OK(err, "elf_resolve_syms_offsets_object")) + return; + + err = elf_resolve_syms_offsets("/proc/self/exe", 3, syms, + (unsigned long **) &offsets, STT_FUNC); + if (!ASSERT_OK(err, "elf_resolve_syms_offsets_func")) + goto out; + + opts.syms = syms; + opts.cookies = &cookies[0]; + opts.ref_ctr_offsets = (unsigned long *) &ref_ctr_offsets[0]; + opts.cnt = ARRAY_SIZE(syms); + + link = bpf_program__attach_uprobe_multi(skel->progs.umulti_run, 0, + "/proc/self/exe", NULL, &opts); + if (!ASSERT_OK_PTR(link, "bpf_program__attach_uprobe_multi")) + goto out; + + link_fd = bpf_link__fd(link); + if (invalid) + verify_umulti_invalid_user_buffer(link_fd); + else + verify_umulti_link_info(link_fd, retprobe, offsets, cookies, ref_ctr_offsets); + + bpf_link__destroy(link); +out: + free(ref_ctr_offsets); + free(offsets); } void test_fill_link_info(void) @@ -337,6 +530,13 @@ void test_fill_link_info(void) if (test__start_subtest("kprobe_multi_invalid_ubuff")) test_kprobe_multi_fill_link_info(skel, true, true); + if (test__start_subtest("uprobe_multi_link_info")) + test_uprobe_multi_fill_link_info(skel, false, false); + if (test__start_subtest("uretprobe_multi_link_info")) + test_uprobe_multi_fill_link_info(skel, true, false); + if (test__start_subtest("uprobe_multi_invalid")) + test_uprobe_multi_fill_link_info(skel, false, true); + cleanup: test_fill_link_info__destroy(skel); } diff --git a/tools/testing/selftests/bpf/prog_tests/fs_kfuncs.c b/tools/testing/selftests/bpf/prog_tests/fs_kfuncs.c new file mode 100644 index 0000000000..37056ba738 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/fs_kfuncs.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ + +#include +#include +#include +#include +#include +#include +#include "test_get_xattr.skel.h" +#include "test_fsverity.skel.h" + +static const char testfile[] = "/tmp/test_progs_fs_kfuncs"; + +static void test_xattr(void) +{ + struct test_get_xattr *skel = NULL; + int fd = -1, err; + + fd = open(testfile, O_CREAT | O_RDONLY, 0644); + if (!ASSERT_GE(fd, 0, "create_file")) + return; + + close(fd); + fd = -1; + + err = setxattr(testfile, "user.kfuncs", "hello", sizeof("hello"), 0); + if (err && errno == EOPNOTSUPP) { + printf("%s:SKIP:local fs doesn't support xattr (%d)\n" + "To run this test, make sure /tmp filesystem supports xattr.\n", + __func__, errno); + test__skip(); + goto out; + } + + if (!ASSERT_OK(err, "setxattr")) + goto out; + + skel = test_get_xattr__open_and_load(); + if (!ASSERT_OK_PTR(skel, "test_get_xattr__open_and_load")) + goto out; + + skel->bss->monitored_pid = getpid(); + err = test_get_xattr__attach(skel); + + if (!ASSERT_OK(err, "test_get_xattr__attach")) + goto out; + + fd = open(testfile, O_RDONLY, 0644); + if (!ASSERT_GE(fd, 0, "open_file")) + goto out; + + ASSERT_EQ(skel->bss->found_xattr, 1, "found_xattr"); + +out: + close(fd); + test_get_xattr__destroy(skel); + remove(testfile); +} + +#ifndef SHA256_DIGEST_SIZE +#define SHA256_DIGEST_SIZE 32 +#endif + +static void test_fsverity(void) +{ + struct fsverity_enable_arg arg = {0}; + struct test_fsverity *skel = NULL; + struct fsverity_digest *d; + int fd, err; + char buffer[4096]; + + fd = open(testfile, O_CREAT | O_RDWR, 0644); + if (!ASSERT_GE(fd, 0, "create_file")) + return; + + /* Write random buffer, so the file is not empty */ + err = write(fd, buffer, 4096); + if (!ASSERT_EQ(err, 4096, "write_file")) + goto out; + close(fd); + + /* Reopen read-only, otherwise FS_IOC_ENABLE_VERITY will fail */ + fd = open(testfile, O_RDONLY, 0644); + if (!ASSERT_GE(fd, 0, "open_file1")) + return; + + /* Enable fsverity for the file. + * If the file system doesn't support verity, this will fail. Skip + * the test in such case. + */ + arg.version = 1; + arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256; + arg.block_size = 4096; + err = ioctl(fd, FS_IOC_ENABLE_VERITY, &arg); + if (err) { + printf("%s:SKIP:local fs doesn't support fsverity (%d)\n" + "To run this test, try enable CONFIG_FS_VERITY and enable FSVerity for the filesystem.\n", + __func__, errno); + test__skip(); + goto out; + } + + skel = test_fsverity__open_and_load(); + if (!ASSERT_OK_PTR(skel, "test_fsverity__open_and_load")) + goto out; + + /* Get fsverity_digest from ioctl */ + d = (struct fsverity_digest *)skel->bss->expected_digest; + d->digest_algorithm = FS_VERITY_HASH_ALG_SHA256; + d->digest_size = SHA256_DIGEST_SIZE; + err = ioctl(fd, FS_IOC_MEASURE_VERITY, skel->bss->expected_digest); + if (!ASSERT_OK(err, "ioctl_FS_IOC_MEASURE_VERITY")) + goto out; + + skel->bss->monitored_pid = getpid(); + err = test_fsverity__attach(skel); + if (!ASSERT_OK(err, "test_fsverity__attach")) + goto out; + + /* Reopen the file to trigger the program */ + close(fd); + fd = open(testfile, O_RDONLY); + if (!ASSERT_GE(fd, 0, "open_file2")) + goto out; + + ASSERT_EQ(skel->bss->got_fsverity, 1, "got_fsverity"); + ASSERT_EQ(skel->bss->digest_matches, 1, "digest_matches"); +out: + close(fd); + test_fsverity__destroy(skel); + remove(testfile); +} + +void test_fs_kfuncs(void) +{ + if (test__start_subtest("xattr")) + test_xattr(); + + if (test__start_subtest("fsverity")) + test_fsverity(); +} diff --git a/tools/testing/selftests/bpf/prog_tests/global_func_dead_code.c b/tools/testing/selftests/bpf/prog_tests/global_func_dead_code.c new file mode 100644 index 0000000000..65309894b2 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/global_func_dead_code.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ + +#include +#include "verifier_global_subprogs.skel.h" +#include "freplace_dead_global_func.skel.h" + +void test_global_func_dead_code(void) +{ + struct verifier_global_subprogs *tgt_skel = NULL; + struct freplace_dead_global_func *skel = NULL; + char log_buf[4096]; + int err, tgt_fd; + + /* first, try to load target with good global subprog */ + tgt_skel = verifier_global_subprogs__open(); + if (!ASSERT_OK_PTR(tgt_skel, "tgt_skel_good_open")) + return; + + bpf_program__set_autoload(tgt_skel->progs.chained_global_func_calls_success, true); + + err = verifier_global_subprogs__load(tgt_skel); + if (!ASSERT_OK(err, "tgt_skel_good_load")) + goto out; + + tgt_fd = bpf_program__fd(tgt_skel->progs.chained_global_func_calls_success); + + /* Attach to good non-eliminated subprog */ + skel = freplace_dead_global_func__open(); + if (!ASSERT_OK_PTR(skel, "skel_good_open")) + goto out; + + err = bpf_program__set_attach_target(skel->progs.freplace_prog, tgt_fd, "global_good"); + ASSERT_OK(err, "attach_target_good"); + + err = freplace_dead_global_func__load(skel); + if (!ASSERT_OK(err, "skel_good_load")) + goto out; + + freplace_dead_global_func__destroy(skel); + + /* Try attaching to dead code-eliminated subprog */ + skel = freplace_dead_global_func__open(); + if (!ASSERT_OK_PTR(skel, "skel_dead_open")) + goto out; + + bpf_program__set_log_buf(skel->progs.freplace_prog, log_buf, sizeof(log_buf)); + err = bpf_program__set_attach_target(skel->progs.freplace_prog, tgt_fd, "global_dead"); + ASSERT_OK(err, "attach_target_dead"); + + err = freplace_dead_global_func__load(skel); + if (!ASSERT_ERR(err, "skel_dead_load")) + goto out; + + ASSERT_HAS_SUBSTR(log_buf, "Subprog global_dead doesn't exist", "dead_subprog_missing_msg"); + +out: + verifier_global_subprogs__destroy(tgt_skel); + freplace_dead_global_func__destroy(skel); +} diff --git a/tools/testing/selftests/bpf/prog_tests/iters.c b/tools/testing/selftests/bpf/prog_tests/iters.c index bf84d4a1d9..3c440370c1 100644 --- a/tools/testing/selftests/bpf/prog_tests/iters.c +++ b/tools/testing/selftests/bpf/prog_tests/iters.c @@ -193,6 +193,7 @@ static void subtest_task_iters(void) ASSERT_EQ(skel->bss->procs_cnt, 1, "procs_cnt"); ASSERT_EQ(skel->bss->threads_cnt, thread_num + 1, "threads_cnt"); ASSERT_EQ(skel->bss->proc_threads_cnt, thread_num + 1, "proc_threads_cnt"); + ASSERT_EQ(skel->bss->invalid_cnt, 0, "invalid_cnt"); pthread_mutex_unlock(&do_nothing_mutex); for (int i = 0; i < thread_num; i++) ASSERT_OK(pthread_join(thread_ids[i], &ret), "pthread_join"); diff --git a/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c b/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c index 4041cfa670..05000810e2 100644 --- a/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c +++ b/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c @@ -222,6 +222,7 @@ static void test_attach_api_fails(void) "bpf_fentry_test2", }; __u64 cookies[2]; + int saved_error; addrs[0] = ksym_get_addr("bpf_fentry_test1"); addrs[1] = ksym_get_addr("bpf_fentry_test2"); @@ -238,10 +239,11 @@ static void test_attach_api_fails(void) /* fail_1 - pattern and opts NULL */ link = bpf_program__attach_kprobe_multi_opts(skel->progs.test_kprobe_manual, NULL, NULL); + saved_error = -errno; if (!ASSERT_ERR_PTR(link, "fail_1")) goto cleanup; - if (!ASSERT_EQ(libbpf_get_error(link), -EINVAL, "fail_1_error")) + if (!ASSERT_EQ(saved_error, -EINVAL, "fail_1_error")) goto cleanup; /* fail_2 - both addrs and syms set */ @@ -252,10 +254,11 @@ static void test_attach_api_fails(void) link = bpf_program__attach_kprobe_multi_opts(skel->progs.test_kprobe_manual, NULL, &opts); + saved_error = -errno; if (!ASSERT_ERR_PTR(link, "fail_2")) goto cleanup; - if (!ASSERT_EQ(libbpf_get_error(link), -EINVAL, "fail_2_error")) + if (!ASSERT_EQ(saved_error, -EINVAL, "fail_2_error")) goto cleanup; /* fail_3 - pattern and addrs set */ @@ -266,10 +269,11 @@ static void test_attach_api_fails(void) link = bpf_program__attach_kprobe_multi_opts(skel->progs.test_kprobe_manual, "ksys_*", &opts); + saved_error = -errno; if (!ASSERT_ERR_PTR(link, "fail_3")) goto cleanup; - if (!ASSERT_EQ(libbpf_get_error(link), -EINVAL, "fail_3_error")) + if (!ASSERT_EQ(saved_error, -EINVAL, "fail_3_error")) goto cleanup; /* fail_4 - pattern and cnt set */ @@ -280,10 +284,11 @@ static void test_attach_api_fails(void) link = bpf_program__attach_kprobe_multi_opts(skel->progs.test_kprobe_manual, "ksys_*", &opts); + saved_error = -errno; if (!ASSERT_ERR_PTR(link, "fail_4")) goto cleanup; - if (!ASSERT_EQ(libbpf_get_error(link), -EINVAL, "fail_4_error")) + if (!ASSERT_EQ(saved_error, -EINVAL, "fail_4_error")) goto cleanup; /* fail_5 - pattern and cookies */ @@ -294,10 +299,26 @@ static void test_attach_api_fails(void) link = bpf_program__attach_kprobe_multi_opts(skel->progs.test_kprobe_manual, "ksys_*", &opts); + saved_error = -errno; if (!ASSERT_ERR_PTR(link, "fail_5")) goto cleanup; - if (!ASSERT_EQ(libbpf_get_error(link), -EINVAL, "fail_5_error")) + if (!ASSERT_EQ(saved_error, -EINVAL, "fail_5_error")) + goto cleanup; + + /* fail_6 - abnormal cnt */ + opts.addrs = (const unsigned long *) addrs; + opts.syms = NULL; + opts.cnt = INT_MAX; + opts.cookies = NULL; + + link = bpf_program__attach_kprobe_multi_opts(skel->progs.test_kprobe_manual, + NULL, &opts); + saved_error = -errno; + if (!ASSERT_ERR_PTR(link, "fail_6")) + goto cleanup; + + if (!ASSERT_EQ(saved_error, -E2BIG, "fail_6_error")) goto cleanup; cleanup: diff --git a/tools/testing/selftests/bpf/prog_tests/libbpf_str.c b/tools/testing/selftests/bpf/prog_tests/libbpf_str.c index c440ea3311..eb34d612d6 100644 --- a/tools/testing/selftests/bpf/prog_tests/libbpf_str.c +++ b/tools/testing/selftests/bpf/prog_tests/libbpf_str.c @@ -87,7 +87,7 @@ static void test_libbpf_bpf_link_type_str(void) const char *link_type_str; char buf[256]; - if (link_type == MAX_BPF_LINK_TYPE) + if (link_type == __MAX_BPF_LINK_TYPE) continue; link_type_name = btf__str_by_offset(btf, e->name_off); diff --git a/tools/testing/selftests/bpf/prog_tests/local_kptr_stash.c b/tools/testing/selftests/bpf/prog_tests/local_kptr_stash.c index b25b870f87..827e713f6c 100644 --- a/tools/testing/selftests/bpf/prog_tests/local_kptr_stash.c +++ b/tools/testing/selftests/bpf/prog_tests/local_kptr_stash.c @@ -48,6 +48,27 @@ static void test_local_kptr_stash_plain(void) local_kptr_stash__destroy(skel); } +static void test_local_kptr_stash_local_with_root(void) +{ + LIBBPF_OPTS(bpf_test_run_opts, opts, + .data_in = &pkt_v4, + .data_size_in = sizeof(pkt_v4), + .repeat = 1, + ); + struct local_kptr_stash *skel; + int ret; + + skel = local_kptr_stash__open_and_load(); + if (!ASSERT_OK_PTR(skel, "local_kptr_stash__open_and_load")) + return; + + ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.stash_local_with_root), &opts); + ASSERT_OK(ret, "local_kptr_stash_add_local_with_root run"); + ASSERT_OK(opts.retval, "local_kptr_stash_add_local_with_root retval"); + + local_kptr_stash__destroy(skel); +} + static void test_local_kptr_stash_unstash(void) { LIBBPF_OPTS(bpf_test_run_opts, opts, @@ -73,6 +94,37 @@ static void test_local_kptr_stash_unstash(void) local_kptr_stash__destroy(skel); } +static void test_refcount_acquire_without_unstash(void) +{ + LIBBPF_OPTS(bpf_test_run_opts, opts, + .data_in = &pkt_v4, + .data_size_in = sizeof(pkt_v4), + .repeat = 1, + ); + struct local_kptr_stash *skel; + int ret; + + skel = local_kptr_stash__open_and_load(); + if (!ASSERT_OK_PTR(skel, "local_kptr_stash__open_and_load")) + return; + + ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.refcount_acquire_without_unstash), + &opts); + ASSERT_OK(ret, "refcount_acquire_without_unstash run"); + ASSERT_EQ(opts.retval, 2, "refcount_acquire_without_unstash retval"); + + ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.stash_refcounted_node), &opts); + ASSERT_OK(ret, "stash_refcounted_node run"); + ASSERT_OK(opts.retval, "stash_refcounted_node retval"); + + ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.refcount_acquire_without_unstash), + &opts); + ASSERT_OK(ret, "refcount_acquire_without_unstash (2) run"); + ASSERT_EQ(opts.retval, 42, "refcount_acquire_without_unstash (2) retval"); + + local_kptr_stash__destroy(skel); +} + static void test_local_kptr_stash_fail(void) { RUN_TESTS(local_kptr_stash_fail); @@ -84,8 +136,12 @@ void test_local_kptr_stash(void) test_local_kptr_stash_simple(); if (test__start_subtest("local_kptr_stash_plain")) test_local_kptr_stash_plain(); + if (test__start_subtest("local_kptr_stash_local_with_root")) + test_local_kptr_stash_local_with_root(); if (test__start_subtest("local_kptr_stash_unstash")) test_local_kptr_stash_unstash(); + if (test__start_subtest("refcount_acquire_without_unstash")) + test_refcount_acquire_without_unstash(); if (test__start_subtest("local_kptr_stash_fail")) test_local_kptr_stash_fail(); } diff --git a/tools/testing/selftests/bpf/prog_tests/log_buf.c b/tools/testing/selftests/bpf/prog_tests/log_buf.c index fe9a23e65e..0f7ea4d7d9 100644 --- a/tools/testing/selftests/bpf/prog_tests/log_buf.c +++ b/tools/testing/selftests/bpf/prog_tests/log_buf.c @@ -78,7 +78,7 @@ static void obj_load_log_buf(void) ASSERT_OK_PTR(strstr(libbpf_log_buf, "prog 'bad_prog': BPF program load failed"), "libbpf_log_not_empty"); ASSERT_OK_PTR(strstr(obj_log_buf, "DATASEC license"), "obj_log_not_empty"); - ASSERT_OK_PTR(strstr(good_log_buf, "0: R1=ctx(off=0,imm=0) R10=fp0"), + ASSERT_OK_PTR(strstr(good_log_buf, "0: R1=ctx() R10=fp0"), "good_log_verbose"); ASSERT_OK_PTR(strstr(bad_log_buf, "invalid access to map value, value_size=16 off=16000 size=4"), "bad_log_not_empty"); @@ -175,7 +175,7 @@ static void bpf_prog_load_log_buf(void) opts.log_level = 2; fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, "good_prog", "GPL", good_prog_insns, good_prog_insn_cnt, &opts); - ASSERT_OK_PTR(strstr(log_buf, "0: R1=ctx(off=0,imm=0) R10=fp0"), "good_log_2"); + ASSERT_OK_PTR(strstr(log_buf, "0: R1=ctx() R10=fp0"), "good_log_2"); ASSERT_GE(fd, 0, "good_fd2"); if (fd >= 0) close(fd); diff --git a/tools/testing/selftests/bpf/prog_tests/log_fixup.c b/tools/testing/selftests/bpf/prog_tests/log_fixup.c index effd78b2a6..7a3fa2ff56 100644 --- a/tools/testing/selftests/bpf/prog_tests/log_fixup.c +++ b/tools/testing/selftests/bpf/prog_tests/log_fixup.c @@ -169,9 +169,9 @@ void test_log_fixup(void) if (test__start_subtest("bad_core_relo_trunc_none")) bad_core_relo(0, TRUNC_NONE /* full buf */); if (test__start_subtest("bad_core_relo_trunc_partial")) - bad_core_relo(300, TRUNC_PARTIAL /* truncate original log a bit */); + bad_core_relo(280, TRUNC_PARTIAL /* truncate original log a bit */); if (test__start_subtest("bad_core_relo_trunc_full")) - bad_core_relo(210, TRUNC_FULL /* truncate also libbpf's message patch */); + bad_core_relo(220, TRUNC_FULL /* truncate also libbpf's message patch */); if (test__start_subtest("bad_core_relo_subprog")) bad_core_relo_subprog(); if (test__start_subtest("missing_map")) diff --git a/tools/testing/selftests/bpf/prog_tests/map_btf.c b/tools/testing/selftests/bpf/prog_tests/map_btf.c new file mode 100644 index 0000000000..2c4ef60375 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/map_btf.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2023. Huawei Technologies Co., Ltd */ +#include + +#include "normal_map_btf.skel.h" +#include "map_in_map_btf.skel.h" + +static void do_test_normal_map_btf(void) +{ + struct normal_map_btf *skel; + int i, err, new_fd = -1; + int map_fd_arr[64]; + + skel = normal_map_btf__open_and_load(); + if (!ASSERT_OK_PTR(skel, "open_load")) + return; + + err = normal_map_btf__attach(skel); + if (!ASSERT_OK(err, "attach")) + goto out; + + skel->bss->pid = getpid(); + usleep(1); + ASSERT_TRUE(skel->bss->done, "done"); + + /* Use percpu_array to slow bpf_map_free_deferred() down. + * The memory allocation may fail, so doesn't check the returned fd. + */ + for (i = 0; i < ARRAY_SIZE(map_fd_arr); i++) + map_fd_arr[i] = bpf_map_create(BPF_MAP_TYPE_PERCPU_ARRAY, NULL, 4, 4, 256, NULL); + + /* Close array fd later */ + new_fd = dup(bpf_map__fd(skel->maps.array)); +out: + normal_map_btf__destroy(skel); + if (new_fd < 0) + return; + /* Use kern_sync_rcu() to wait for the start of the free of the bpf + * program and use an assumed delay to wait for the release of the map + * btf which is held by other maps (e.g, bss). After that, array map + * holds the last reference of map btf. + */ + kern_sync_rcu(); + usleep(4000); + /* Spawn multiple kworkers to delay the invocation of + * bpf_map_free_deferred() for array map. + */ + for (i = 0; i < ARRAY_SIZE(map_fd_arr); i++) { + if (map_fd_arr[i] < 0) + continue; + close(map_fd_arr[i]); + } + close(new_fd); +} + +static void do_test_map_in_map_btf(void) +{ + int err, zero = 0, new_fd = -1; + struct map_in_map_btf *skel; + + skel = map_in_map_btf__open_and_load(); + if (!ASSERT_OK_PTR(skel, "open_load")) + return; + + err = map_in_map_btf__attach(skel); + if (!ASSERT_OK(err, "attach")) + goto out; + + skel->bss->pid = getpid(); + usleep(1); + ASSERT_TRUE(skel->bss->done, "done"); + + /* Close inner_array fd later */ + new_fd = dup(bpf_map__fd(skel->maps.inner_array)); + /* Defer the free of inner_array */ + err = bpf_map__delete_elem(skel->maps.outer_array, &zero, sizeof(zero), 0); + ASSERT_OK(err, "delete inner map"); +out: + map_in_map_btf__destroy(skel); + if (new_fd < 0) + return; + /* Use kern_sync_rcu() to wait for the start of the free of the bpf + * program and use an assumed delay to wait for the free of the outer + * map and the release of map btf. After that, inner map holds the last + * reference of map btf. + */ + kern_sync_rcu(); + usleep(10000); + close(new_fd); +} + +void test_map_btf(void) +{ + if (test__start_subtest("array_btf")) + do_test_normal_map_btf(); + if (test__start_subtest("inner_array_btf")) + do_test_map_in_map_btf(); +} diff --git a/tools/testing/selftests/bpf/prog_tests/map_in_map.c b/tools/testing/selftests/bpf/prog_tests/map_in_map.c new file mode 100644 index 0000000000..d2a10eb4e5 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/map_in_map.c @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2023. Huawei Technologies Co., Ltd */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include "access_map_in_map.skel.h" + +struct thread_ctx { + pthread_barrier_t barrier; + int outer_map_fd; + int start, abort; + int loop, err; +}; + +static int wait_for_start_or_abort(struct thread_ctx *ctx) +{ + while (!ctx->start && !ctx->abort) + usleep(1); + return ctx->abort ? -1 : 0; +} + +static void *update_map_fn(void *data) +{ + struct thread_ctx *ctx = data; + int loop = ctx->loop, err = 0; + + if (wait_for_start_or_abort(ctx) < 0) + return NULL; + pthread_barrier_wait(&ctx->barrier); + + while (loop-- > 0) { + int fd, zero = 0; + + fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, NULL, 4, 4, 1, NULL); + if (fd < 0) { + err |= 1; + pthread_barrier_wait(&ctx->barrier); + continue; + } + + /* Remove the old inner map */ + if (bpf_map_update_elem(ctx->outer_map_fd, &zero, &fd, 0) < 0) + err |= 2; + close(fd); + pthread_barrier_wait(&ctx->barrier); + } + + ctx->err = err; + + return NULL; +} + +static void *access_map_fn(void *data) +{ + struct thread_ctx *ctx = data; + int loop = ctx->loop; + + if (wait_for_start_or_abort(ctx) < 0) + return NULL; + pthread_barrier_wait(&ctx->barrier); + + while (loop-- > 0) { + /* Access the old inner map */ + syscall(SYS_getpgid); + pthread_barrier_wait(&ctx->barrier); + } + + return NULL; +} + +static void test_map_in_map_access(const char *prog_name, const char *map_name) +{ + struct access_map_in_map *skel; + struct bpf_map *outer_map; + struct bpf_program *prog; + struct thread_ctx ctx; + pthread_t tid[2]; + int err; + + skel = access_map_in_map__open(); + if (!ASSERT_OK_PTR(skel, "access_map_in_map open")) + return; + + prog = bpf_object__find_program_by_name(skel->obj, prog_name); + if (!ASSERT_OK_PTR(prog, "find program")) + goto out; + bpf_program__set_autoload(prog, true); + + outer_map = bpf_object__find_map_by_name(skel->obj, map_name); + if (!ASSERT_OK_PTR(outer_map, "find map")) + goto out; + + err = access_map_in_map__load(skel); + if (!ASSERT_OK(err, "access_map_in_map load")) + goto out; + + err = access_map_in_map__attach(skel); + if (!ASSERT_OK(err, "access_map_in_map attach")) + goto out; + + skel->bss->tgid = getpid(); + + memset(&ctx, 0, sizeof(ctx)); + pthread_barrier_init(&ctx.barrier, NULL, 2); + ctx.outer_map_fd = bpf_map__fd(outer_map); + ctx.loop = 4; + + err = pthread_create(&tid[0], NULL, update_map_fn, &ctx); + if (!ASSERT_OK(err, "close_thread")) + goto out; + + err = pthread_create(&tid[1], NULL, access_map_fn, &ctx); + if (!ASSERT_OK(err, "read_thread")) { + ctx.abort = 1; + pthread_join(tid[0], NULL); + goto out; + } + + ctx.start = 1; + pthread_join(tid[0], NULL); + pthread_join(tid[1], NULL); + + ASSERT_OK(ctx.err, "err"); +out: + access_map_in_map__destroy(skel); +} + +void test_map_in_map(void) +{ + if (test__start_subtest("acc_map_in_array")) + test_map_in_map_access("access_map_in_array", "outer_array_map"); + if (test__start_subtest("sleepable_acc_map_in_array")) + test_map_in_map_access("sleepable_access_map_in_array", "outer_array_map"); + if (test__start_subtest("acc_map_in_htab")) + test_map_in_map_access("access_map_in_htab", "outer_htab_map"); + if (test__start_subtest("sleepable_acc_map_in_htab")) + test_map_in_map_access("sleepable_access_map_in_htab", "outer_htab_map"); +} + diff --git a/tools/testing/selftests/bpf/prog_tests/read_vsyscall.c b/tools/testing/selftests/bpf/prog_tests/read_vsyscall.c new file mode 100644 index 0000000000..3405923fe4 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/read_vsyscall.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2024. Huawei Technologies Co., Ltd */ +#include "test_progs.h" +#include "read_vsyscall.skel.h" + +#if defined(__x86_64__) +/* For VSYSCALL_ADDR */ +#include +#else +/* To prevent build failure on non-x86 arch */ +#define VSYSCALL_ADDR 0UL +#endif + +struct read_ret_desc { + const char *name; + int ret; +} all_read[] = { + { .name = "probe_read_kernel", .ret = -ERANGE }, + { .name = "probe_read_kernel_str", .ret = -ERANGE }, + { .name = "probe_read", .ret = -ERANGE }, + { .name = "probe_read_str", .ret = -ERANGE }, + { .name = "probe_read_user", .ret = -EFAULT }, + { .name = "probe_read_user_str", .ret = -EFAULT }, + { .name = "copy_from_user", .ret = -EFAULT }, + { .name = "copy_from_user_task", .ret = -EFAULT }, +}; + +void test_read_vsyscall(void) +{ + struct read_vsyscall *skel; + unsigned int i; + int err; + +#if !defined(__x86_64__) + test__skip(); + return; +#endif + skel = read_vsyscall__open_and_load(); + if (!ASSERT_OK_PTR(skel, "read_vsyscall open_load")) + return; + + skel->bss->target_pid = getpid(); + err = read_vsyscall__attach(skel); + if (!ASSERT_EQ(err, 0, "read_vsyscall attach")) + goto out; + + /* userspace may don't have vsyscall page due to LEGACY_VSYSCALL_NONE, + * but it doesn't affect the returned error codes. + */ + skel->bss->user_ptr = (void *)VSYSCALL_ADDR; + usleep(1); + + for (i = 0; i < ARRAY_SIZE(all_read); i++) + ASSERT_EQ(skel->bss->read_ret[i], all_read[i].ret, all_read[i].name); +out: + read_vsyscall__destroy(skel); +} diff --git a/tools/testing/selftests/bpf/prog_tests/recursive_attach.c b/tools/testing/selftests/bpf/prog_tests/recursive_attach.c new file mode 100644 index 0000000000..8100509e56 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/recursive_attach.c @@ -0,0 +1,151 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Red Hat, Inc. */ +#include +#include "fentry_recursive.skel.h" +#include "fentry_recursive_target.skel.h" +#include +#include "bpf/libbpf_internal.h" + +/* Test recursive attachment of tracing progs with more than one nesting level + * is not possible. Create a chain of attachment, verify that the last prog + * will fail. Depending on the arguments, following cases are tested: + * + * - Recursive loading of tracing progs, without attaching (attach = false, + * detach = false). The chain looks like this: + * load target + * load fentry1 -> target + * load fentry2 -> fentry1 (fail) + * + * - Recursive attach of tracing progs (attach = true, detach = false). The + * chain looks like this: + * load target + * load fentry1 -> target + * attach fentry1 -> target + * load fentry2 -> fentry1 (fail) + * + * - Recursive attach and detach of tracing progs (attach = true, detach = + * true). This validates that attach_tracing_prog flag will be set throughout + * the whole lifecycle of an fentry prog, independently from whether it's + * detached. The chain looks like this: + * load target + * load fentry1 -> target + * attach fentry1 -> target + * detach fentry1 + * load fentry2 -> fentry1 (fail) + */ +static void test_recursive_fentry_chain(bool attach, bool detach) +{ + struct fentry_recursive_target *target_skel = NULL; + struct fentry_recursive *tracing_chain[2] = {}; + struct bpf_program *prog; + int prev_fd, err; + + target_skel = fentry_recursive_target__open_and_load(); + if (!ASSERT_OK_PTR(target_skel, "fentry_recursive_target__open_and_load")) + return; + + /* Create an attachment chain with two fentry progs */ + for (int i = 0; i < 2; i++) { + tracing_chain[i] = fentry_recursive__open(); + if (!ASSERT_OK_PTR(tracing_chain[i], "fentry_recursive__open")) + goto close_prog; + + /* The first prog in the chain is going to be attached to the target + * fentry program, the second one to the previous in the chain. + */ + prog = tracing_chain[i]->progs.recursive_attach; + if (i == 0) { + prev_fd = bpf_program__fd(target_skel->progs.test1); + err = bpf_program__set_attach_target(prog, prev_fd, "test1"); + } else { + prev_fd = bpf_program__fd(tracing_chain[i-1]->progs.recursive_attach); + err = bpf_program__set_attach_target(prog, prev_fd, "recursive_attach"); + } + + if (!ASSERT_OK(err, "bpf_program__set_attach_target")) + goto close_prog; + + err = fentry_recursive__load(tracing_chain[i]); + /* The first attach should succeed, the second fail */ + if (i == 0) { + if (!ASSERT_OK(err, "fentry_recursive__load")) + goto close_prog; + + if (attach) { + err = fentry_recursive__attach(tracing_chain[i]); + if (!ASSERT_OK(err, "fentry_recursive__attach")) + goto close_prog; + } + + if (detach) { + /* Flag attach_tracing_prog should still be set, preventing + * attachment of the following prog. + */ + fentry_recursive__detach(tracing_chain[i]); + } + } else { + if (!ASSERT_ERR(err, "fentry_recursive__load")) + goto close_prog; + } + } + +close_prog: + fentry_recursive_target__destroy(target_skel); + for (int i = 0; i < 2; i++) { + fentry_recursive__destroy(tracing_chain[i]); + } +} + +void test_recursive_fentry(void) +{ + if (test__start_subtest("attach")) + test_recursive_fentry_chain(true, false); + if (test__start_subtest("load")) + test_recursive_fentry_chain(false, false); + if (test__start_subtest("detach")) + test_recursive_fentry_chain(true, true); +} + +/* Test that a tracing prog reattachment (when we land in + * "prog->aux->dst_trampoline and tgt_prog is NULL" branch in + * bpf_tracing_prog_attach) does not lead to a crash due to missing attach_btf + */ +void test_fentry_attach_btf_presence(void) +{ + struct fentry_recursive_target *target_skel = NULL; + struct fentry_recursive *tracing_skel = NULL; + struct bpf_program *prog; + int err, link_fd, tgt_prog_fd; + + target_skel = fentry_recursive_target__open_and_load(); + if (!ASSERT_OK_PTR(target_skel, "fentry_recursive_target__open_and_load")) + goto close_prog; + + tracing_skel = fentry_recursive__open(); + if (!ASSERT_OK_PTR(tracing_skel, "fentry_recursive__open")) + goto close_prog; + + prog = tracing_skel->progs.recursive_attach; + tgt_prog_fd = bpf_program__fd(target_skel->progs.fentry_target); + err = bpf_program__set_attach_target(prog, tgt_prog_fd, "fentry_target"); + if (!ASSERT_OK(err, "bpf_program__set_attach_target")) + goto close_prog; + + err = fentry_recursive__load(tracing_skel); + if (!ASSERT_OK(err, "fentry_recursive__load")) + goto close_prog; + + tgt_prog_fd = bpf_program__fd(tracing_skel->progs.recursive_attach); + link_fd = bpf_link_create(tgt_prog_fd, 0, BPF_TRACE_FENTRY, NULL); + if (!ASSERT_GE(link_fd, 0, "link_fd")) + goto close_prog; + + fentry_recursive__detach(tracing_skel); + + err = fentry_recursive__attach(tracing_skel); + ASSERT_ERR(err, "fentry_recursive__attach"); + +close_prog: + fentry_recursive_target__destroy(target_skel); + fentry_recursive__destroy(tracing_skel); +} diff --git a/tools/testing/selftests/bpf/prog_tests/reg_bounds.c b/tools/testing/selftests/bpf/prog_tests/reg_bounds.c new file mode 100644 index 0000000000..820d0bcfc4 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/reg_bounds.c @@ -0,0 +1,2131 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ + +#define _GNU_SOURCE +#include +#include +#include +#include + +/* ================================= + * SHORT AND CONSISTENT NUMBER TYPES + * ================================= + */ +#define U64_MAX ((u64)UINT64_MAX) +#define U32_MAX ((u32)UINT_MAX) +#define U16_MAX ((u32)UINT_MAX) +#define S64_MIN ((s64)INT64_MIN) +#define S64_MAX ((s64)INT64_MAX) +#define S32_MIN ((s32)INT_MIN) +#define S32_MAX ((s32)INT_MAX) +#define S16_MIN ((s16)0x80000000) +#define S16_MAX ((s16)0x7fffffff) + +typedef unsigned long long ___u64; +typedef unsigned int ___u32; +typedef long long ___s64; +typedef int ___s32; + +/* avoid conflicts with already defined types in kernel headers */ +#define u64 ___u64 +#define u32 ___u32 +#define s64 ___s64 +#define s32 ___s32 + +/* ================================== + * STRING BUF ABSTRACTION AND HELPERS + * ================================== + */ +struct strbuf { + size_t buf_sz; + int pos; + char buf[0]; +}; + +#define DEFINE_STRBUF(name, N) \ + struct { struct strbuf buf; char data[(N)]; } ___##name; \ + struct strbuf *name = (___##name.buf.buf_sz = (N), ___##name.buf.pos = 0, &___##name.buf) + +__printf(2, 3) +static inline void snappendf(struct strbuf *s, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + s->pos += vsnprintf(s->buf + s->pos, + s->pos < s->buf_sz ? s->buf_sz - s->pos : 0, + fmt, args); + va_end(args); +} + +/* ================================== + * GENERIC NUMBER TYPE AND OPERATIONS + * ================================== + */ +enum num_t { U64, first_t = U64, U32, S64, S32, last_t = S32 }; + +static __always_inline u64 min_t(enum num_t t, u64 x, u64 y) +{ + switch (t) { + case U64: return (u64)x < (u64)y ? (u64)x : (u64)y; + case U32: return (u32)x < (u32)y ? (u32)x : (u32)y; + case S64: return (s64)x < (s64)y ? (s64)x : (s64)y; + case S32: return (s32)x < (s32)y ? (s32)x : (s32)y; + default: printf("min_t!\n"); exit(1); + } +} + +static __always_inline u64 max_t(enum num_t t, u64 x, u64 y) +{ + switch (t) { + case U64: return (u64)x > (u64)y ? (u64)x : (u64)y; + case U32: return (u32)x > (u32)y ? (u32)x : (u32)y; + case S64: return (s64)x > (s64)y ? (s64)x : (s64)y; + case S32: return (s32)x > (s32)y ? (u32)(s32)x : (u32)(s32)y; + default: printf("max_t!\n"); exit(1); + } +} + +static __always_inline u64 cast_t(enum num_t t, u64 x) +{ + switch (t) { + case U64: return (u64)x; + case U32: return (u32)x; + case S64: return (s64)x; + case S32: return (u32)(s32)x; + default: printf("cast_t!\n"); exit(1); + } +} + +static const char *t_str(enum num_t t) +{ + switch (t) { + case U64: return "u64"; + case U32: return "u32"; + case S64: return "s64"; + case S32: return "s32"; + default: printf("t_str!\n"); exit(1); + } +} + +static enum num_t t_is_32(enum num_t t) +{ + switch (t) { + case U64: return false; + case U32: return true; + case S64: return false; + case S32: return true; + default: printf("t_is_32!\n"); exit(1); + } +} + +static enum num_t t_signed(enum num_t t) +{ + switch (t) { + case U64: return S64; + case U32: return S32; + case S64: return S64; + case S32: return S32; + default: printf("t_signed!\n"); exit(1); + } +} + +static enum num_t t_unsigned(enum num_t t) +{ + switch (t) { + case U64: return U64; + case U32: return U32; + case S64: return U64; + case S32: return U32; + default: printf("t_unsigned!\n"); exit(1); + } +} + +#define UNUM_MAX_DECIMAL U16_MAX +#define SNUM_MAX_DECIMAL S16_MAX +#define SNUM_MIN_DECIMAL S16_MIN + +static bool num_is_small(enum num_t t, u64 x) +{ + switch (t) { + case U64: return (u64)x <= UNUM_MAX_DECIMAL; + case U32: return (u32)x <= UNUM_MAX_DECIMAL; + case S64: return (s64)x >= SNUM_MIN_DECIMAL && (s64)x <= SNUM_MAX_DECIMAL; + case S32: return (s32)x >= SNUM_MIN_DECIMAL && (s32)x <= SNUM_MAX_DECIMAL; + default: printf("num_is_small!\n"); exit(1); + } +} + +static void snprintf_num(enum num_t t, struct strbuf *sb, u64 x) +{ + bool is_small = num_is_small(t, x); + + if (is_small) { + switch (t) { + case U64: return snappendf(sb, "%llu", (u64)x); + case U32: return snappendf(sb, "%u", (u32)x); + case S64: return snappendf(sb, "%lld", (s64)x); + case S32: return snappendf(sb, "%d", (s32)x); + default: printf("snprintf_num!\n"); exit(1); + } + } else { + switch (t) { + case U64: + if (x == U64_MAX) + return snappendf(sb, "U64_MAX"); + else if (x >= U64_MAX - 256) + return snappendf(sb, "U64_MAX-%llu", U64_MAX - x); + else + return snappendf(sb, "%#llx", (u64)x); + case U32: + if ((u32)x == U32_MAX) + return snappendf(sb, "U32_MAX"); + else if ((u32)x >= U32_MAX - 256) + return snappendf(sb, "U32_MAX-%u", U32_MAX - (u32)x); + else + return snappendf(sb, "%#x", (u32)x); + case S64: + if ((s64)x == S64_MAX) + return snappendf(sb, "S64_MAX"); + else if ((s64)x >= S64_MAX - 256) + return snappendf(sb, "S64_MAX-%lld", S64_MAX - (s64)x); + else if ((s64)x == S64_MIN) + return snappendf(sb, "S64_MIN"); + else if ((s64)x <= S64_MIN + 256) + return snappendf(sb, "S64_MIN+%lld", (s64)x - S64_MIN); + else + return snappendf(sb, "%#llx", (s64)x); + case S32: + if ((s32)x == S32_MAX) + return snappendf(sb, "S32_MAX"); + else if ((s32)x >= S32_MAX - 256) + return snappendf(sb, "S32_MAX-%d", S32_MAX - (s32)x); + else if ((s32)x == S32_MIN) + return snappendf(sb, "S32_MIN"); + else if ((s32)x <= S32_MIN + 256) + return snappendf(sb, "S32_MIN+%d", (s32)x - S32_MIN); + else + return snappendf(sb, "%#x", (s32)x); + default: printf("snprintf_num!\n"); exit(1); + } + } +} + +/* =================================== + * GENERIC RANGE STRUCT AND OPERATIONS + * =================================== + */ +struct range { + u64 a, b; +}; + +static void snprintf_range(enum num_t t, struct strbuf *sb, struct range x) +{ + if (x.a == x.b) + return snprintf_num(t, sb, x.a); + + snappendf(sb, "["); + snprintf_num(t, sb, x.a); + snappendf(sb, "; "); + snprintf_num(t, sb, x.b); + snappendf(sb, "]"); +} + +static void print_range(enum num_t t, struct range x, const char *sfx) +{ + DEFINE_STRBUF(sb, 128); + + snprintf_range(t, sb, x); + printf("%s%s", sb->buf, sfx); +} + +static const struct range unkn[] = { + [U64] = { 0, U64_MAX }, + [U32] = { 0, U32_MAX }, + [S64] = { (u64)S64_MIN, (u64)S64_MAX }, + [S32] = { (u64)(u32)S32_MIN, (u64)(u32)S32_MAX }, +}; + +static struct range unkn_subreg(enum num_t t) +{ + switch (t) { + case U64: return unkn[U32]; + case U32: return unkn[U32]; + case S64: return unkn[U32]; + case S32: return unkn[S32]; + default: printf("unkn_subreg!\n"); exit(1); + } +} + +static struct range range(enum num_t t, u64 a, u64 b) +{ + switch (t) { + case U64: return (struct range){ (u64)a, (u64)b }; + case U32: return (struct range){ (u32)a, (u32)b }; + case S64: return (struct range){ (s64)a, (s64)b }; + case S32: return (struct range){ (u32)(s32)a, (u32)(s32)b }; + default: printf("range!\n"); exit(1); + } +} + +static __always_inline u32 sign64(u64 x) { return (x >> 63) & 1; } +static __always_inline u32 sign32(u64 x) { return ((u32)x >> 31) & 1; } +static __always_inline u32 upper32(u64 x) { return (u32)(x >> 32); } +static __always_inline u64 swap_low32(u64 x, u32 y) { return (x & 0xffffffff00000000ULL) | y; } + +static bool range_eq(struct range x, struct range y) +{ + return x.a == y.a && x.b == y.b; +} + +static struct range range_cast_to_s32(struct range x) +{ + u64 a = x.a, b = x.b; + + /* if upper 32 bits are constant, lower 32 bits should form a proper + * s32 range to be correct + */ + if (upper32(a) == upper32(b) && (s32)a <= (s32)b) + return range(S32, a, b); + + /* Special case where upper bits form a small sequence of two + * sequential numbers (in 32-bit unsigned space, so 0xffffffff to + * 0x00000000 is also valid), while lower bits form a proper s32 range + * going from negative numbers to positive numbers. + * + * E.g.: [0xfffffff0ffffff00; 0xfffffff100000010]. Iterating + * over full 64-bit numbers range will form a proper [-16, 16] + * ([0xffffff00; 0x00000010]) range in its lower 32 bits. + */ + if (upper32(a) + 1 == upper32(b) && (s32)a < 0 && (s32)b >= 0) + return range(S32, a, b); + + /* otherwise we can't derive much meaningful information */ + return unkn[S32]; +} + +static struct range range_cast_u64(enum num_t to_t, struct range x) +{ + u64 a = (u64)x.a, b = (u64)x.b; + + switch (to_t) { + case U64: + return x; + case U32: + if (upper32(a) != upper32(b)) + return unkn[U32]; + return range(U32, a, b); + case S64: + if (sign64(a) != sign64(b)) + return unkn[S64]; + return range(S64, a, b); + case S32: + return range_cast_to_s32(x); + default: printf("range_cast_u64!\n"); exit(1); + } +} + +static struct range range_cast_s64(enum num_t to_t, struct range x) +{ + s64 a = (s64)x.a, b = (s64)x.b; + + switch (to_t) { + case U64: + /* equivalent to (s64)a <= (s64)b check */ + if (sign64(a) != sign64(b)) + return unkn[U64]; + return range(U64, a, b); + case U32: + if (upper32(a) != upper32(b) || sign32(a) != sign32(b)) + return unkn[U32]; + return range(U32, a, b); + case S64: + return x; + case S32: + return range_cast_to_s32(x); + default: printf("range_cast_s64!\n"); exit(1); + } +} + +static struct range range_cast_u32(enum num_t to_t, struct range x) +{ + u32 a = (u32)x.a, b = (u32)x.b; + + switch (to_t) { + case U64: + case S64: + /* u32 is always a valid zero-extended u64/s64 */ + return range(to_t, a, b); + case U32: + return x; + case S32: + return range_cast_to_s32(range(U32, a, b)); + default: printf("range_cast_u32!\n"); exit(1); + } +} + +static struct range range_cast_s32(enum num_t to_t, struct range x) +{ + s32 a = (s32)x.a, b = (s32)x.b; + + switch (to_t) { + case U64: + case U32: + case S64: + if (sign32(a) != sign32(b)) + return unkn[to_t]; + return range(to_t, a, b); + case S32: + return x; + default: printf("range_cast_s32!\n"); exit(1); + } +} + +/* Reinterpret range in *from_t* domain as a range in *to_t* domain preserving + * all possible information. Worst case, it will be unknown range within + * *to_t* domain, if nothing more specific can be guaranteed during the + * conversion + */ +static struct range range_cast(enum num_t from_t, enum num_t to_t, struct range from) +{ + switch (from_t) { + case U64: return range_cast_u64(to_t, from); + case U32: return range_cast_u32(to_t, from); + case S64: return range_cast_s64(to_t, from); + case S32: return range_cast_s32(to_t, from); + default: printf("range_cast!\n"); exit(1); + } +} + +static bool is_valid_num(enum num_t t, u64 x) +{ + switch (t) { + case U64: return true; + case U32: return upper32(x) == 0; + case S64: return true; + case S32: return upper32(x) == 0; + default: printf("is_valid_num!\n"); exit(1); + } +} + +static bool is_valid_range(enum num_t t, struct range x) +{ + if (!is_valid_num(t, x.a) || !is_valid_num(t, x.b)) + return false; + + switch (t) { + case U64: return (u64)x.a <= (u64)x.b; + case U32: return (u32)x.a <= (u32)x.b; + case S64: return (s64)x.a <= (s64)x.b; + case S32: return (s32)x.a <= (s32)x.b; + default: printf("is_valid_range!\n"); exit(1); + } +} + +static struct range range_improve(enum num_t t, struct range old, struct range new) +{ + return range(t, max_t(t, old.a, new.a), min_t(t, old.b, new.b)); +} + +static struct range range_refine(enum num_t x_t, struct range x, enum num_t y_t, struct range y) +{ + struct range y_cast; + + y_cast = range_cast(y_t, x_t, y); + + /* the case when new range knowledge, *y*, is a 32-bit subregister + * range, while previous range knowledge, *x*, is a full register + * 64-bit range, needs special treatment to take into account upper 32 + * bits of full register range + */ + if (t_is_32(y_t) && !t_is_32(x_t)) { + struct range x_swap; + + /* some combinations of upper 32 bits and sign bit can lead to + * invalid ranges, in such cases it's easier to detect them + * after cast/swap than try to enumerate all the conditions + * under which transformation and knowledge transfer is valid + */ + x_swap = range(x_t, swap_low32(x.a, y_cast.a), swap_low32(x.b, y_cast.b)); + if (!is_valid_range(x_t, x_swap)) + return x; + return range_improve(x_t, x, x_swap); + } + + /* otherwise, plain range cast and intersection works */ + return range_improve(x_t, x, y_cast); +} + +/* ======================= + * GENERIC CONDITIONAL OPS + * ======================= + */ +enum op { OP_LT, OP_LE, OP_GT, OP_GE, OP_EQ, OP_NE, first_op = OP_LT, last_op = OP_NE }; + +static enum op complement_op(enum op op) +{ + switch (op) { + case OP_LT: return OP_GE; + case OP_LE: return OP_GT; + case OP_GT: return OP_LE; + case OP_GE: return OP_LT; + case OP_EQ: return OP_NE; + case OP_NE: return OP_EQ; + default: printf("complement_op!\n"); exit(1); + } +} + +static const char *op_str(enum op op) +{ + switch (op) { + case OP_LT: return "<"; + case OP_LE: return "<="; + case OP_GT: return ">"; + case OP_GE: return ">="; + case OP_EQ: return "=="; + case OP_NE: return "!="; + default: printf("op_str!\n"); exit(1); + } +} + +/* Can register with range [x.a, x.b] *EVER* satisfy + * OP (<, <=, >, >=, ==, !=) relation to + * a regsiter with range [y.a, y.b] + * _in *num_t* domain_ + */ +static bool range_canbe_op(enum num_t t, struct range x, struct range y, enum op op) +{ +#define range_canbe(T) do { \ + switch (op) { \ + case OP_LT: return (T)x.a < (T)y.b; \ + case OP_LE: return (T)x.a <= (T)y.b; \ + case OP_GT: return (T)x.b > (T)y.a; \ + case OP_GE: return (T)x.b >= (T)y.a; \ + case OP_EQ: return (T)max_t(t, x.a, y.a) <= (T)min_t(t, x.b, y.b); \ + case OP_NE: return !((T)x.a == (T)x.b && (T)y.a == (T)y.b && (T)x.a == (T)y.a); \ + default: printf("range_canbe op %d\n", op); exit(1); \ + } \ +} while (0) + + switch (t) { + case U64: { range_canbe(u64); } + case U32: { range_canbe(u32); } + case S64: { range_canbe(s64); } + case S32: { range_canbe(s32); } + default: printf("range_canbe!\n"); exit(1); + } +#undef range_canbe +} + +/* Does register with range [x.a, x.b] *ALWAYS* satisfy + * OP (<, <=, >, >=, ==, !=) relation to + * a regsiter with range [y.a, y.b] + * _in *num_t* domain_ + */ +static bool range_always_op(enum num_t t, struct range x, struct range y, enum op op) +{ + /* always op <=> ! canbe complement(op) */ + return !range_canbe_op(t, x, y, complement_op(op)); +} + +/* Does register with range [x.a, x.b] *NEVER* satisfy + * OP (<, <=, >, >=, ==, !=) relation to + * a regsiter with range [y.a, y.b] + * _in *num_t* domain_ + */ +static bool range_never_op(enum num_t t, struct range x, struct range y, enum op op) +{ + return !range_canbe_op(t, x, y, op); +} + +/* similar to verifier's is_branch_taken(): + * 1 - always taken; + * 0 - never taken, + * -1 - unsure. + */ +static int range_branch_taken_op(enum num_t t, struct range x, struct range y, enum op op) +{ + if (range_always_op(t, x, y, op)) + return 1; + if (range_never_op(t, x, y, op)) + return 0; + return -1; +} + +/* What would be the new estimates for register x and y ranges assuming truthful + * OP comparison between them. I.e., (x OP y == true) => x <- newx, y <- newy. + * + * We assume "interesting" cases where ranges overlap. Cases where it's + * obvious that (x OP y) is either always true or false should be filtered with + * range_never and range_always checks. + */ +static void range_cond(enum num_t t, struct range x, struct range y, + enum op op, struct range *newx, struct range *newy) +{ + if (!range_canbe_op(t, x, y, op)) { + /* nothing to adjust, can't happen, return original values */ + *newx = x; + *newy = y; + return; + } + switch (op) { + case OP_LT: + *newx = range(t, x.a, min_t(t, x.b, y.b - 1)); + *newy = range(t, max_t(t, x.a + 1, y.a), y.b); + break; + case OP_LE: + *newx = range(t, x.a, min_t(t, x.b, y.b)); + *newy = range(t, max_t(t, x.a, y.a), y.b); + break; + case OP_GT: + *newx = range(t, max_t(t, x.a, y.a + 1), x.b); + *newy = range(t, y.a, min_t(t, x.b - 1, y.b)); + break; + case OP_GE: + *newx = range(t, max_t(t, x.a, y.a), x.b); + *newy = range(t, y.a, min_t(t, x.b, y.b)); + break; + case OP_EQ: + *newx = range(t, max_t(t, x.a, y.a), min_t(t, x.b, y.b)); + *newy = range(t, max_t(t, x.a, y.a), min_t(t, x.b, y.b)); + break; + case OP_NE: + /* below logic is supported by the verifier now */ + if (x.a == x.b && x.a == y.a) { + /* X is a constant matching left side of Y */ + *newx = range(t, x.a, x.b); + *newy = range(t, y.a + 1, y.b); + } else if (x.a == x.b && x.b == y.b) { + /* X is a constant matching rigth side of Y */ + *newx = range(t, x.a, x.b); + *newy = range(t, y.a, y.b - 1); + } else if (y.a == y.b && x.a == y.a) { + /* Y is a constant matching left side of X */ + *newx = range(t, x.a + 1, x.b); + *newy = range(t, y.a, y.b); + } else if (y.a == y.b && x.b == y.b) { + /* Y is a constant matching rigth side of X */ + *newx = range(t, x.a, x.b - 1); + *newy = range(t, y.a, y.b); + } else { + /* generic case, can't derive more information */ + *newx = range(t, x.a, x.b); + *newy = range(t, y.a, y.b); + } + + break; + default: + break; + } +} + +/* ======================= + * REGISTER STATE HANDLING + * ======================= + */ +struct reg_state { + struct range r[4]; /* indexed by enum num_t: U64, U32, S64, S32 */ + bool valid; +}; + +static void print_reg_state(struct reg_state *r, const char *sfx) +{ + DEFINE_STRBUF(sb, 512); + enum num_t t; + int cnt = 0; + + if (!r->valid) { + printf("%s", sfx); + return; + } + + snappendf(sb, "scalar("); + for (t = first_t; t <= last_t; t++) { + snappendf(sb, "%s%s=", cnt++ ? "," : "", t_str(t)); + snprintf_range(t, sb, r->r[t]); + } + snappendf(sb, ")"); + + printf("%s%s", sb->buf, sfx); +} + +static void print_refinement(enum num_t s_t, struct range src, + enum num_t d_t, struct range old, struct range new, + const char *ctx) +{ + printf("REFINING (%s) (%s)SRC=", ctx, t_str(s_t)); + print_range(s_t, src, ""); + printf(" (%s)DST_OLD=", t_str(d_t)); + print_range(d_t, old, ""); + printf(" (%s)DST_NEW=", t_str(d_t)); + print_range(d_t, new, "\n"); +} + +static void reg_state_refine(struct reg_state *r, enum num_t t, struct range x, const char *ctx) +{ + enum num_t d_t, s_t; + struct range old; + bool keep_going = false; + +again: + /* try to derive new knowledge from just learned range x of type t */ + for (d_t = first_t; d_t <= last_t; d_t++) { + old = r->r[d_t]; + r->r[d_t] = range_refine(d_t, r->r[d_t], t, x); + if (!range_eq(r->r[d_t], old)) { + keep_going = true; + if (env.verbosity >= VERBOSE_VERY) + print_refinement(t, x, d_t, old, r->r[d_t], ctx); + } + } + + /* now see if we can derive anything new from updated reg_state's ranges */ + for (s_t = first_t; s_t <= last_t; s_t++) { + for (d_t = first_t; d_t <= last_t; d_t++) { + old = r->r[d_t]; + r->r[d_t] = range_refine(d_t, r->r[d_t], s_t, r->r[s_t]); + if (!range_eq(r->r[d_t], old)) { + keep_going = true; + if (env.verbosity >= VERBOSE_VERY) + print_refinement(s_t, r->r[s_t], d_t, old, r->r[d_t], ctx); + } + } + } + + /* keep refining until we converge */ + if (keep_going) { + keep_going = false; + goto again; + } +} + +static void reg_state_set_const(struct reg_state *rs, enum num_t t, u64 val) +{ + enum num_t tt; + + rs->valid = true; + for (tt = first_t; tt <= last_t; tt++) + rs->r[tt] = tt == t ? range(t, val, val) : unkn[tt]; + + reg_state_refine(rs, t, rs->r[t], "CONST"); +} + +static void reg_state_cond(enum num_t t, struct reg_state *x, struct reg_state *y, enum op op, + struct reg_state *newx, struct reg_state *newy, const char *ctx) +{ + char buf[32]; + enum num_t ts[2]; + struct reg_state xx = *x, yy = *y; + int i, t_cnt; + struct range z1, z2; + + if (op == OP_EQ || op == OP_NE) { + /* OP_EQ and OP_NE are sign-agnostic, so we need to process + * both signed and unsigned domains at the same time + */ + ts[0] = t_unsigned(t); + ts[1] = t_signed(t); + t_cnt = 2; + } else { + ts[0] = t; + t_cnt = 1; + } + + for (i = 0; i < t_cnt; i++) { + t = ts[i]; + z1 = x->r[t]; + z2 = y->r[t]; + + range_cond(t, z1, z2, op, &z1, &z2); + + if (newx) { + snprintf(buf, sizeof(buf), "%s R1", ctx); + reg_state_refine(&xx, t, z1, buf); + } + if (newy) { + snprintf(buf, sizeof(buf), "%s R2", ctx); + reg_state_refine(&yy, t, z2, buf); + } + } + + if (newx) + *newx = xx; + if (newy) + *newy = yy; +} + +static int reg_state_branch_taken_op(enum num_t t, struct reg_state *x, struct reg_state *y, + enum op op) +{ + if (op == OP_EQ || op == OP_NE) { + /* OP_EQ and OP_NE are sign-agnostic */ + enum num_t tu = t_unsigned(t); + enum num_t ts = t_signed(t); + int br_u, br_s, br; + + br_u = range_branch_taken_op(tu, x->r[tu], y->r[tu], op); + br_s = range_branch_taken_op(ts, x->r[ts], y->r[ts], op); + + if (br_u >= 0 && br_s >= 0 && br_u != br_s) + ASSERT_FALSE(true, "branch taken inconsistency!\n"); + + /* if 64-bit ranges are indecisive, use 32-bit subranges to + * eliminate always/never taken branches, if possible + */ + if (br_u == -1 && (t == U64 || t == S64)) { + br = range_branch_taken_op(U32, x->r[U32], y->r[U32], op); + /* we can only reject for OP_EQ, never take branch + * based on lower 32 bits + */ + if (op == OP_EQ && br == 0) + return 0; + /* for OP_NEQ we can be conclusive only if lower 32 bits + * differ and thus inequality branch is always taken + */ + if (op == OP_NE && br == 1) + return 1; + + br = range_branch_taken_op(S32, x->r[S32], y->r[S32], op); + if (op == OP_EQ && br == 0) + return 0; + if (op == OP_NE && br == 1) + return 1; + } + + return br_u >= 0 ? br_u : br_s; + } + return range_branch_taken_op(t, x->r[t], y->r[t], op); +} + +/* ===================================== + * BPF PROGS GENERATION AND VERIFICATION + * ===================================== + */ +struct case_spec { + /* whether to init full register (r1) or sub-register (w1) */ + bool init_subregs; + /* whether to establish initial value range on full register (r1) or + * sub-register (w1) + */ + bool setup_subregs; + /* whether to establish initial value range using signed or unsigned + * comparisons (i.e., initialize umin/umax or smin/smax directly) + */ + bool setup_signed; + /* whether to perform comparison on full registers or sub-registers */ + bool compare_subregs; + /* whether to perform comparison using signed or unsigned operations */ + bool compare_signed; +}; + +/* Generate test BPF program based on provided test ranges, operation, and + * specifications about register bitness and signedness. + */ +static int load_range_cmp_prog(struct range x, struct range y, enum op op, + int branch_taken, struct case_spec spec, + char *log_buf, size_t log_sz, + int *false_pos, int *true_pos) +{ +#define emit(insn) ({ \ + struct bpf_insn __insns[] = { insn }; \ + int __i; \ + for (__i = 0; __i < ARRAY_SIZE(__insns); __i++) \ + insns[cur_pos + __i] = __insns[__i]; \ + cur_pos += __i; \ +}) +#define JMP_TO(target) (target - cur_pos - 1) + int cur_pos = 0, exit_pos, fd, op_code; + struct bpf_insn insns[64]; + LIBBPF_OPTS(bpf_prog_load_opts, opts, + .log_level = 2, + .log_buf = log_buf, + .log_size = log_sz, + .prog_flags = BPF_F_TEST_REG_INVARIANTS, + ); + + /* ; skip exit block below + * goto +2; + */ + emit(BPF_JMP_A(2)); + exit_pos = cur_pos; + /* ; exit block for all the preparatory conditionals + * out: + * r0 = 0; + * exit; + */ + emit(BPF_MOV64_IMM(BPF_REG_0, 0)); + emit(BPF_EXIT_INSN()); + /* + * ; assign r6/w6 and r7/w7 unpredictable u64/u32 value + * call bpf_get_current_pid_tgid; + * r6 = r0; | w6 = w0; + * call bpf_get_current_pid_tgid; + * r7 = r0; | w7 = w0; + */ + emit(BPF_EMIT_CALL(BPF_FUNC_get_current_pid_tgid)); + if (spec.init_subregs) + emit(BPF_MOV32_REG(BPF_REG_6, BPF_REG_0)); + else + emit(BPF_MOV64_REG(BPF_REG_6, BPF_REG_0)); + emit(BPF_EMIT_CALL(BPF_FUNC_get_current_pid_tgid)); + if (spec.init_subregs) + emit(BPF_MOV32_REG(BPF_REG_7, BPF_REG_0)); + else + emit(BPF_MOV64_REG(BPF_REG_7, BPF_REG_0)); + /* ; setup initial r6/w6 possible value range ([x.a, x.b]) + * r1 = %[x.a] ll; | w1 = %[x.a]; + * r2 = %[x.b] ll; | w2 = %[x.b]; + * if r6 < r1 goto out; | if w6 < w1 goto out; + * if r6 > r2 goto out; | if w6 > w2 goto out; + */ + if (spec.setup_subregs) { + emit(BPF_MOV32_IMM(BPF_REG_1, (s32)x.a)); + emit(BPF_MOV32_IMM(BPF_REG_2, (s32)x.b)); + emit(BPF_JMP32_REG(spec.setup_signed ? BPF_JSLT : BPF_JLT, + BPF_REG_6, BPF_REG_1, JMP_TO(exit_pos))); + emit(BPF_JMP32_REG(spec.setup_signed ? BPF_JSGT : BPF_JGT, + BPF_REG_6, BPF_REG_2, JMP_TO(exit_pos))); + } else { + emit(BPF_LD_IMM64(BPF_REG_1, x.a)); + emit(BPF_LD_IMM64(BPF_REG_2, x.b)); + emit(BPF_JMP_REG(spec.setup_signed ? BPF_JSLT : BPF_JLT, + BPF_REG_6, BPF_REG_1, JMP_TO(exit_pos))); + emit(BPF_JMP_REG(spec.setup_signed ? BPF_JSGT : BPF_JGT, + BPF_REG_6, BPF_REG_2, JMP_TO(exit_pos))); + } + /* ; setup initial r7/w7 possible value range ([y.a, y.b]) + * r1 = %[y.a] ll; | w1 = %[y.a]; + * r2 = %[y.b] ll; | w2 = %[y.b]; + * if r7 < r1 goto out; | if w7 < w1 goto out; + * if r7 > r2 goto out; | if w7 > w2 goto out; + */ + if (spec.setup_subregs) { + emit(BPF_MOV32_IMM(BPF_REG_1, (s32)y.a)); + emit(BPF_MOV32_IMM(BPF_REG_2, (s32)y.b)); + emit(BPF_JMP32_REG(spec.setup_signed ? BPF_JSLT : BPF_JLT, + BPF_REG_7, BPF_REG_1, JMP_TO(exit_pos))); + emit(BPF_JMP32_REG(spec.setup_signed ? BPF_JSGT : BPF_JGT, + BPF_REG_7, BPF_REG_2, JMP_TO(exit_pos))); + } else { + emit(BPF_LD_IMM64(BPF_REG_1, y.a)); + emit(BPF_LD_IMM64(BPF_REG_2, y.b)); + emit(BPF_JMP_REG(spec.setup_signed ? BPF_JSLT : BPF_JLT, + BPF_REG_7, BPF_REG_1, JMP_TO(exit_pos))); + emit(BPF_JMP_REG(spec.setup_signed ? BPF_JSGT : BPF_JGT, + BPF_REG_7, BPF_REG_2, JMP_TO(exit_pos))); + } + /* ; range test instruction + * if r6 r7 goto +3; | if w6 w7 goto +3; + */ + switch (op) { + case OP_LT: op_code = spec.compare_signed ? BPF_JSLT : BPF_JLT; break; + case OP_LE: op_code = spec.compare_signed ? BPF_JSLE : BPF_JLE; break; + case OP_GT: op_code = spec.compare_signed ? BPF_JSGT : BPF_JGT; break; + case OP_GE: op_code = spec.compare_signed ? BPF_JSGE : BPF_JGE; break; + case OP_EQ: op_code = BPF_JEQ; break; + case OP_NE: op_code = BPF_JNE; break; + default: + printf("unrecognized op %d\n", op); + return -ENOTSUP; + } + /* ; BEFORE conditional, r0/w0 = {r6/w6,r7/w7} is to extract verifier state reliably + * ; this is used for debugging, as verifier doesn't always print + * ; registers states as of condition jump instruction (e.g., when + * ; precision marking happens) + * r0 = r6; | w0 = w6; + * r0 = r7; | w0 = w7; + */ + if (spec.compare_subregs) { + emit(BPF_MOV32_REG(BPF_REG_0, BPF_REG_6)); + emit(BPF_MOV32_REG(BPF_REG_0, BPF_REG_7)); + } else { + emit(BPF_MOV64_REG(BPF_REG_0, BPF_REG_6)); + emit(BPF_MOV64_REG(BPF_REG_0, BPF_REG_7)); + } + if (spec.compare_subregs) + emit(BPF_JMP32_REG(op_code, BPF_REG_6, BPF_REG_7, 3)); + else + emit(BPF_JMP_REG(op_code, BPF_REG_6, BPF_REG_7, 3)); + /* ; FALSE branch, r0/w0 = {r6/w6,r7/w7} is to extract verifier state reliably + * r0 = r6; | w0 = w6; + * r0 = r7; | w0 = w7; + * exit; + */ + *false_pos = cur_pos; + if (spec.compare_subregs) { + emit(BPF_MOV32_REG(BPF_REG_0, BPF_REG_6)); + emit(BPF_MOV32_REG(BPF_REG_0, BPF_REG_7)); + } else { + emit(BPF_MOV64_REG(BPF_REG_0, BPF_REG_6)); + emit(BPF_MOV64_REG(BPF_REG_0, BPF_REG_7)); + } + if (branch_taken == 1) /* false branch is never taken */ + emit(BPF_EMIT_CALL(0xDEAD)); /* poison this branch */ + else + emit(BPF_EXIT_INSN()); + /* ; TRUE branch, r0/w0 = {r6/w6,r7/w7} is to extract verifier state reliably + * r0 = r6; | w0 = w6; + * r0 = r7; | w0 = w7; + * exit; + */ + *true_pos = cur_pos; + if (spec.compare_subregs) { + emit(BPF_MOV32_REG(BPF_REG_0, BPF_REG_6)); + emit(BPF_MOV32_REG(BPF_REG_0, BPF_REG_7)); + } else { + emit(BPF_MOV64_REG(BPF_REG_0, BPF_REG_6)); + emit(BPF_MOV64_REG(BPF_REG_0, BPF_REG_7)); + } + if (branch_taken == 0) /* true branch is never taken */ + emit(BPF_EMIT_CALL(0xDEAD)); /* poison this branch */ + emit(BPF_EXIT_INSN()); /* last instruction has to be exit */ + + fd = bpf_prog_load(BPF_PROG_TYPE_RAW_TRACEPOINT, "reg_bounds_test", + "GPL", insns, cur_pos, &opts); + if (fd < 0) + return fd; + + close(fd); + return 0; +#undef emit +#undef JMP_TO +} + +#define str_has_pfx(str, pfx) (strncmp(str, pfx, strlen(pfx)) == 0) + +/* Parse register state from verifier log. + * `s` should point to the start of "Rx = ..." substring in the verifier log. + */ +static int parse_reg_state(const char *s, struct reg_state *reg) +{ + /* There are two generic forms for SCALAR register: + * - known constant: R6_rwD=P%lld + * - range: R6_rwD=scalar(id=1,...), where "..." is a comma-separated + * list of optional range specifiers: + * - umin=%llu, if missing, assumed 0; + * - umax=%llu, if missing, assumed U64_MAX; + * - smin=%lld, if missing, assumed S64_MIN; + * - smax=%lld, if missing, assummed S64_MAX; + * - umin32=%d, if missing, assumed 0; + * - umax32=%d, if missing, assumed U32_MAX; + * - smin32=%d, if missing, assumed S32_MIN; + * - smax32=%d, if missing, assummed S32_MAX; + * - var_off=(%#llx; %#llx), tnum part, we don't care about it. + * + * If some of the values are equal, they will be grouped (but min/max + * are not mixed together, and similarly negative values are not + * grouped with non-negative ones). E.g.: + * + * R6_w=Pscalar(smin=smin32=0, smax=umax=umax32=1000) + * + * _rwD part is optional (and any of the letters can be missing). + * P (precision mark) is optional as well. + * + * Anything inside scalar() is optional, including id, of course. + */ + struct { + const char *pfx; + u64 *dst, def; + bool is_32, is_set; + } *f, fields[8] = { + {"smin=", ®->r[S64].a, S64_MIN}, + {"smax=", ®->r[S64].b, S64_MAX}, + {"umin=", ®->r[U64].a, 0}, + {"umax=", ®->r[U64].b, U64_MAX}, + {"smin32=", ®->r[S32].a, (u32)S32_MIN, true}, + {"smax32=", ®->r[S32].b, (u32)S32_MAX, true}, + {"umin32=", ®->r[U32].a, 0, true}, + {"umax32=", ®->r[U32].b, U32_MAX, true}, + }; + const char *p; + int i; + + p = strchr(s, '='); + if (!p) + return -EINVAL; + p++; + if (*p == 'P') + p++; + + if (!str_has_pfx(p, "scalar(")) { + long long sval; + enum num_t t; + + if (p[0] == '0' && p[1] == 'x') { + if (sscanf(p, "%llx", &sval) != 1) + return -EINVAL; + } else { + if (sscanf(p, "%lld", &sval) != 1) + return -EINVAL; + } + + reg->valid = true; + for (t = first_t; t <= last_t; t++) { + reg->r[t] = range(t, sval, sval); + } + return 0; + } + + p += sizeof("scalar"); + while (p) { + int midxs[ARRAY_SIZE(fields)], mcnt = 0; + u64 val; + + for (i = 0; i < ARRAY_SIZE(fields); i++) { + f = &fields[i]; + if (!str_has_pfx(p, f->pfx)) + continue; + midxs[mcnt++] = i; + p += strlen(f->pfx); + } + + if (mcnt) { + /* populate all matched fields */ + if (p[0] == '0' && p[1] == 'x') { + if (sscanf(p, "%llx", &val) != 1) + return -EINVAL; + } else { + if (sscanf(p, "%lld", &val) != 1) + return -EINVAL; + } + + for (i = 0; i < mcnt; i++) { + f = &fields[midxs[i]]; + f->is_set = true; + *f->dst = f->is_32 ? (u64)(u32)val : val; + } + } else if (str_has_pfx(p, "var_off")) { + /* skip "var_off=(0x0; 0x3f)" part completely */ + p = strchr(p, ')'); + if (!p) + return -EINVAL; + p++; + } + + p = strpbrk(p, ",)"); + if (*p == ')') + break; + if (p) + p++; + } + + reg->valid = true; + + for (i = 0; i < ARRAY_SIZE(fields); i++) { + f = &fields[i]; + if (!f->is_set) + *f->dst = f->def; + } + + return 0; +} + + +/* Parse all register states (TRUE/FALSE branches and DST/SRC registers) + * out of the verifier log for a corresponding test case BPF program. + */ +static int parse_range_cmp_log(const char *log_buf, struct case_spec spec, + int false_pos, int true_pos, + struct reg_state *false1_reg, struct reg_state *false2_reg, + struct reg_state *true1_reg, struct reg_state *true2_reg) +{ + struct { + int insn_idx; + int reg_idx; + const char *reg_upper; + struct reg_state *state; + } specs[] = { + {false_pos, 6, "R6=", false1_reg}, + {false_pos + 1, 7, "R7=", false2_reg}, + {true_pos, 6, "R6=", true1_reg}, + {true_pos + 1, 7, "R7=", true2_reg}, + }; + char buf[32]; + const char *p = log_buf, *q; + int i, err; + + for (i = 0; i < 4; i++) { + sprintf(buf, "%d: (%s) %s = %s%d", specs[i].insn_idx, + spec.compare_subregs ? "bc" : "bf", + spec.compare_subregs ? "w0" : "r0", + spec.compare_subregs ? "w" : "r", specs[i].reg_idx); + + q = strstr(p, buf); + if (!q) { + *specs[i].state = (struct reg_state){.valid = false}; + continue; + } + p = strstr(q, specs[i].reg_upper); + if (!p) + return -EINVAL; + err = parse_reg_state(p, specs[i].state); + if (err) + return -EINVAL; + } + return 0; +} + +/* Validate ranges match, and print details if they don't */ +static bool assert_range_eq(enum num_t t, struct range x, struct range y, + const char *ctx1, const char *ctx2) +{ + DEFINE_STRBUF(sb, 512); + + if (range_eq(x, y)) + return true; + + snappendf(sb, "MISMATCH %s.%s: ", ctx1, ctx2); + snprintf_range(t, sb, x); + snappendf(sb, " != "); + snprintf_range(t, sb, y); + + printf("%s\n", sb->buf); + + return false; +} + +/* Validate that register states match, and print details if they don't */ +static bool assert_reg_state_eq(struct reg_state *r, struct reg_state *e, const char *ctx) +{ + bool ok = true; + enum num_t t; + + if (r->valid != e->valid) { + printf("MISMATCH %s: actual %s != expected %s\n", ctx, + r->valid ? "" : "", + e->valid ? "" : ""); + return false; + } + + if (!r->valid) + return true; + + for (t = first_t; t <= last_t; t++) { + if (!assert_range_eq(t, r->r[t], e->r[t], ctx, t_str(t))) + ok = false; + } + + return ok; +} + +/* Printf verifier log, filtering out irrelevant noise */ +static void print_verifier_log(const char *buf) +{ + const char *p; + + while (buf[0]) { + p = strchrnul(buf, '\n'); + + /* filter out irrelevant precision backtracking logs */ + if (str_has_pfx(buf, "mark_precise: ")) + goto skip_line; + + printf("%.*s\n", (int)(p - buf), buf); + +skip_line: + buf = *p == '\0' ? p : p + 1; + } +} + +/* Simulate provided test case purely with our own range-based logic. + * This is done to set up expectations for verifier's branch_taken logic and + * verifier's register states in the verifier log. + */ +static void sim_case(enum num_t init_t, enum num_t cond_t, + struct range x, struct range y, enum op op, + struct reg_state *fr1, struct reg_state *fr2, + struct reg_state *tr1, struct reg_state *tr2, + int *branch_taken) +{ + const u64 A = x.a; + const u64 B = x.b; + const u64 C = y.a; + const u64 D = y.b; + struct reg_state rc; + enum op rev_op = complement_op(op); + enum num_t t; + + fr1->valid = fr2->valid = true; + tr1->valid = tr2->valid = true; + for (t = first_t; t <= last_t; t++) { + /* if we are initializing using 32-bit subregisters, + * full registers get upper 32 bits zeroed automatically + */ + struct range z = t_is_32(init_t) ? unkn_subreg(t) : unkn[t]; + + fr1->r[t] = fr2->r[t] = tr1->r[t] = tr2->r[t] = z; + } + + /* step 1: r1 >= A, r2 >= C */ + reg_state_set_const(&rc, init_t, A); + reg_state_cond(init_t, fr1, &rc, OP_GE, fr1, NULL, "r1>=A"); + reg_state_set_const(&rc, init_t, C); + reg_state_cond(init_t, fr2, &rc, OP_GE, fr2, NULL, "r2>=C"); + *tr1 = *fr1; + *tr2 = *fr2; + if (env.verbosity >= VERBOSE_VERY) { + printf("STEP1 (%s) R1: ", t_str(init_t)); print_reg_state(fr1, "\n"); + printf("STEP1 (%s) R2: ", t_str(init_t)); print_reg_state(fr2, "\n"); + } + + /* step 2: r1 <= B, r2 <= D */ + reg_state_set_const(&rc, init_t, B); + reg_state_cond(init_t, fr1, &rc, OP_LE, fr1, NULL, "r1<=B"); + reg_state_set_const(&rc, init_t, D); + reg_state_cond(init_t, fr2, &rc, OP_LE, fr2, NULL, "r2<=D"); + *tr1 = *fr1; + *tr2 = *fr2; + if (env.verbosity >= VERBOSE_VERY) { + printf("STEP2 (%s) R1: ", t_str(init_t)); print_reg_state(fr1, "\n"); + printf("STEP2 (%s) R2: ", t_str(init_t)); print_reg_state(fr2, "\n"); + } + + /* step 3: r1 r2 */ + *branch_taken = reg_state_branch_taken_op(cond_t, fr1, fr2, op); + fr1->valid = fr2->valid = false; + tr1->valid = tr2->valid = false; + if (*branch_taken != 1) { /* FALSE is possible */ + fr1->valid = fr2->valid = true; + reg_state_cond(cond_t, fr1, fr2, rev_op, fr1, fr2, "FALSE"); + } + if (*branch_taken != 0) { /* TRUE is possible */ + tr1->valid = tr2->valid = true; + reg_state_cond(cond_t, tr1, tr2, op, tr1, tr2, "TRUE"); + } + if (env.verbosity >= VERBOSE_VERY) { + printf("STEP3 (%s) FALSE R1:", t_str(cond_t)); print_reg_state(fr1, "\n"); + printf("STEP3 (%s) FALSE R2:", t_str(cond_t)); print_reg_state(fr2, "\n"); + printf("STEP3 (%s) TRUE R1:", t_str(cond_t)); print_reg_state(tr1, "\n"); + printf("STEP3 (%s) TRUE R2:", t_str(cond_t)); print_reg_state(tr2, "\n"); + } +} + +/* =============================== + * HIGH-LEVEL TEST CASE VALIDATION + * =============================== + */ +static u32 upper_seeds[] = { + 0, + 1, + U32_MAX, + U32_MAX - 1, + S32_MAX, + (u32)S32_MIN, +}; + +static u32 lower_seeds[] = { + 0, + 1, + 2, (u32)-2, + 255, (u32)-255, + UINT_MAX, + UINT_MAX - 1, + INT_MAX, + (u32)INT_MIN, +}; + +struct ctx { + int val_cnt, subval_cnt, range_cnt, subrange_cnt; + u64 uvals[ARRAY_SIZE(upper_seeds) * ARRAY_SIZE(lower_seeds)]; + s64 svals[ARRAY_SIZE(upper_seeds) * ARRAY_SIZE(lower_seeds)]; + u32 usubvals[ARRAY_SIZE(lower_seeds)]; + s32 ssubvals[ARRAY_SIZE(lower_seeds)]; + struct range *uranges, *sranges; + struct range *usubranges, *ssubranges; + int max_failure_cnt, cur_failure_cnt; + int total_case_cnt, case_cnt; + int rand_case_cnt; + unsigned rand_seed; + __u64 start_ns; + char progress_ctx[64]; +}; + +static void cleanup_ctx(struct ctx *ctx) +{ + free(ctx->uranges); + free(ctx->sranges); + free(ctx->usubranges); + free(ctx->ssubranges); +} + +struct subtest_case { + enum num_t init_t; + enum num_t cond_t; + struct range x; + struct range y; + enum op op; +}; + +static void subtest_case_str(struct strbuf *sb, struct subtest_case *t, bool use_op) +{ + snappendf(sb, "(%s)", t_str(t->init_t)); + snprintf_range(t->init_t, sb, t->x); + snappendf(sb, " (%s)%s ", t_str(t->cond_t), use_op ? op_str(t->op) : ""); + snprintf_range(t->init_t, sb, t->y); +} + +/* Generate and validate test case based on specific combination of setup + * register ranges (including their expected num_t domain), and conditional + * operation to perform (including num_t domain in which it has to be + * performed) + */ +static int verify_case_op(enum num_t init_t, enum num_t cond_t, + struct range x, struct range y, enum op op) +{ + char log_buf[256 * 1024]; + size_t log_sz = sizeof(log_buf); + int err, false_pos = 0, true_pos = 0, branch_taken; + struct reg_state fr1, fr2, tr1, tr2; + struct reg_state fe1, fe2, te1, te2; + bool failed = false; + struct case_spec spec = { + .init_subregs = (init_t == U32 || init_t == S32), + .setup_subregs = (init_t == U32 || init_t == S32), + .setup_signed = (init_t == S64 || init_t == S32), + .compare_subregs = (cond_t == U32 || cond_t == S32), + .compare_signed = (cond_t == S64 || cond_t == S32), + }; + + log_buf[0] = '\0'; + + sim_case(init_t, cond_t, x, y, op, &fe1, &fe2, &te1, &te2, &branch_taken); + + err = load_range_cmp_prog(x, y, op, branch_taken, spec, + log_buf, log_sz, &false_pos, &true_pos); + if (err) { + ASSERT_OK(err, "load_range_cmp_prog"); + failed = true; + } + + err = parse_range_cmp_log(log_buf, spec, false_pos, true_pos, + &fr1, &fr2, &tr1, &tr2); + if (err) { + ASSERT_OK(err, "parse_range_cmp_log"); + failed = true; + } + + if (!assert_reg_state_eq(&fr1, &fe1, "false_reg1") || + !assert_reg_state_eq(&fr2, &fe2, "false_reg2") || + !assert_reg_state_eq(&tr1, &te1, "true_reg1") || + !assert_reg_state_eq(&tr2, &te2, "true_reg2")) { + failed = true; + } + + if (failed || env.verbosity >= VERBOSE_NORMAL) { + if (failed || env.verbosity >= VERBOSE_VERY) { + printf("VERIFIER LOG:\n========================\n"); + print_verifier_log(log_buf); + printf("=====================\n"); + } + printf("ACTUAL FALSE1: "); print_reg_state(&fr1, "\n"); + printf("EXPECTED FALSE1: "); print_reg_state(&fe1, "\n"); + printf("ACTUAL FALSE2: "); print_reg_state(&fr2, "\n"); + printf("EXPECTED FALSE2: "); print_reg_state(&fe2, "\n"); + printf("ACTUAL TRUE1: "); print_reg_state(&tr1, "\n"); + printf("EXPECTED TRUE1: "); print_reg_state(&te1, "\n"); + printf("ACTUAL TRUE2: "); print_reg_state(&tr2, "\n"); + printf("EXPECTED TRUE2: "); print_reg_state(&te2, "\n"); + + return failed ? -EINVAL : 0; + } + + return 0; +} + +/* Given setup ranges and number types, go over all supported operations, + * generating individual subtest for each allowed combination + */ +static int verify_case_opt(struct ctx *ctx, enum num_t init_t, enum num_t cond_t, + struct range x, struct range y, bool is_subtest) +{ + DEFINE_STRBUF(sb, 256); + int err; + struct subtest_case sub = { + .init_t = init_t, + .cond_t = cond_t, + .x = x, + .y = y, + }; + + sb->pos = 0; /* reset position in strbuf */ + subtest_case_str(sb, &sub, false /* ignore op */); + if (is_subtest && !test__start_subtest(sb->buf)) + return 0; + + for (sub.op = first_op; sub.op <= last_op; sub.op++) { + sb->pos = 0; /* reset position in strbuf */ + subtest_case_str(sb, &sub, true /* print op */); + + if (env.verbosity >= VERBOSE_NORMAL) /* this speeds up debugging */ + printf("TEST CASE: %s\n", sb->buf); + + err = verify_case_op(init_t, cond_t, x, y, sub.op); + if (err || env.verbosity >= VERBOSE_NORMAL) + ASSERT_OK(err, sb->buf); + if (err) { + ctx->cur_failure_cnt++; + if (ctx->cur_failure_cnt > ctx->max_failure_cnt) + return err; + return 0; /* keep testing other cases */ + } + ctx->case_cnt++; + if ((ctx->case_cnt % 10000) == 0) { + double progress = (ctx->case_cnt + 0.0) / ctx->total_case_cnt; + u64 elapsed_ns = get_time_ns() - ctx->start_ns; + double remain_ns = elapsed_ns / progress * (1 - progress); + + fprintf(env.stderr, "PROGRESS (%s): %d/%d (%.2lf%%), " + "elapsed %llu mins (%.2lf hrs), " + "ETA %.0lf mins (%.2lf hrs)\n", + ctx->progress_ctx, + ctx->case_cnt, ctx->total_case_cnt, 100.0 * progress, + elapsed_ns / 1000000000 / 60, + elapsed_ns / 1000000000.0 / 3600, + remain_ns / 1000000000.0 / 60, + remain_ns / 1000000000.0 / 3600); + } + } + + return 0; +} + +static int verify_case(struct ctx *ctx, enum num_t init_t, enum num_t cond_t, + struct range x, struct range y) +{ + return verify_case_opt(ctx, init_t, cond_t, x, y, true /* is_subtest */); +} + +/* ================================ + * GENERATED CASES FROM SEED VALUES + * ================================ + */ +static int u64_cmp(const void *p1, const void *p2) +{ + u64 x1 = *(const u64 *)p1, x2 = *(const u64 *)p2; + + return x1 != x2 ? (x1 < x2 ? -1 : 1) : 0; +} + +static int u32_cmp(const void *p1, const void *p2) +{ + u32 x1 = *(const u32 *)p1, x2 = *(const u32 *)p2; + + return x1 != x2 ? (x1 < x2 ? -1 : 1) : 0; +} + +static int s64_cmp(const void *p1, const void *p2) +{ + s64 x1 = *(const s64 *)p1, x2 = *(const s64 *)p2; + + return x1 != x2 ? (x1 < x2 ? -1 : 1) : 0; +} + +static int s32_cmp(const void *p1, const void *p2) +{ + s32 x1 = *(const s32 *)p1, x2 = *(const s32 *)p2; + + return x1 != x2 ? (x1 < x2 ? -1 : 1) : 0; +} + +/* Generate valid unique constants from seeds, both signed and unsigned */ +static void gen_vals(struct ctx *ctx) +{ + int i, j, cnt = 0; + + for (i = 0; i < ARRAY_SIZE(upper_seeds); i++) { + for (j = 0; j < ARRAY_SIZE(lower_seeds); j++) { + ctx->uvals[cnt++] = (((u64)upper_seeds[i]) << 32) | lower_seeds[j]; + } + } + + /* sort and compact uvals (i.e., it's `sort | uniq`) */ + qsort(ctx->uvals, cnt, sizeof(*ctx->uvals), u64_cmp); + for (i = 1, j = 0; i < cnt; i++) { + if (ctx->uvals[j] == ctx->uvals[i]) + continue; + j++; + ctx->uvals[j] = ctx->uvals[i]; + } + ctx->val_cnt = j + 1; + + /* we have exactly the same number of s64 values, they are just in + * a different order than u64s, so just sort them differently + */ + for (i = 0; i < ctx->val_cnt; i++) + ctx->svals[i] = ctx->uvals[i]; + qsort(ctx->svals, ctx->val_cnt, sizeof(*ctx->svals), s64_cmp); + + if (env.verbosity >= VERBOSE_SUPER) { + DEFINE_STRBUF(sb1, 256); + DEFINE_STRBUF(sb2, 256); + + for (i = 0; i < ctx->val_cnt; i++) { + sb1->pos = sb2->pos = 0; + snprintf_num(U64, sb1, ctx->uvals[i]); + snprintf_num(S64, sb2, ctx->svals[i]); + printf("SEED #%d: u64=%-20s s64=%-20s\n", i, sb1->buf, sb2->buf); + } + } + + /* 32-bit values are generated separately */ + cnt = 0; + for (i = 0; i < ARRAY_SIZE(lower_seeds); i++) { + ctx->usubvals[cnt++] = lower_seeds[i]; + } + + /* sort and compact usubvals (i.e., it's `sort | uniq`) */ + qsort(ctx->usubvals, cnt, sizeof(*ctx->usubvals), u32_cmp); + for (i = 1, j = 0; i < cnt; i++) { + if (ctx->usubvals[j] == ctx->usubvals[i]) + continue; + j++; + ctx->usubvals[j] = ctx->usubvals[i]; + } + ctx->subval_cnt = j + 1; + + for (i = 0; i < ctx->subval_cnt; i++) + ctx->ssubvals[i] = ctx->usubvals[i]; + qsort(ctx->ssubvals, ctx->subval_cnt, sizeof(*ctx->ssubvals), s32_cmp); + + if (env.verbosity >= VERBOSE_SUPER) { + DEFINE_STRBUF(sb1, 256); + DEFINE_STRBUF(sb2, 256); + + for (i = 0; i < ctx->subval_cnt; i++) { + sb1->pos = sb2->pos = 0; + snprintf_num(U32, sb1, ctx->usubvals[i]); + snprintf_num(S32, sb2, ctx->ssubvals[i]); + printf("SUBSEED #%d: u32=%-10s s32=%-10s\n", i, sb1->buf, sb2->buf); + } + } +} + +/* Generate valid ranges from upper/lower seeds */ +static int gen_ranges(struct ctx *ctx) +{ + int i, j, cnt = 0; + + for (i = 0; i < ctx->val_cnt; i++) { + for (j = i; j < ctx->val_cnt; j++) { + if (env.verbosity >= VERBOSE_SUPER) { + DEFINE_STRBUF(sb1, 256); + DEFINE_STRBUF(sb2, 256); + + sb1->pos = sb2->pos = 0; + snprintf_range(U64, sb1, range(U64, ctx->uvals[i], ctx->uvals[j])); + snprintf_range(S64, sb2, range(S64, ctx->svals[i], ctx->svals[j])); + printf("RANGE #%d: u64=%-40s s64=%-40s\n", cnt, sb1->buf, sb2->buf); + } + cnt++; + } + } + ctx->range_cnt = cnt; + + ctx->uranges = calloc(ctx->range_cnt, sizeof(*ctx->uranges)); + if (!ASSERT_OK_PTR(ctx->uranges, "uranges_calloc")) + return -EINVAL; + ctx->sranges = calloc(ctx->range_cnt, sizeof(*ctx->sranges)); + if (!ASSERT_OK_PTR(ctx->sranges, "sranges_calloc")) + return -EINVAL; + + cnt = 0; + for (i = 0; i < ctx->val_cnt; i++) { + for (j = i; j < ctx->val_cnt; j++) { + ctx->uranges[cnt] = range(U64, ctx->uvals[i], ctx->uvals[j]); + ctx->sranges[cnt] = range(S64, ctx->svals[i], ctx->svals[j]); + cnt++; + } + } + + cnt = 0; + for (i = 0; i < ctx->subval_cnt; i++) { + for (j = i; j < ctx->subval_cnt; j++) { + if (env.verbosity >= VERBOSE_SUPER) { + DEFINE_STRBUF(sb1, 256); + DEFINE_STRBUF(sb2, 256); + + sb1->pos = sb2->pos = 0; + snprintf_range(U32, sb1, range(U32, ctx->usubvals[i], ctx->usubvals[j])); + snprintf_range(S32, sb2, range(S32, ctx->ssubvals[i], ctx->ssubvals[j])); + printf("SUBRANGE #%d: u32=%-20s s32=%-20s\n", cnt, sb1->buf, sb2->buf); + } + cnt++; + } + } + ctx->subrange_cnt = cnt; + + ctx->usubranges = calloc(ctx->subrange_cnt, sizeof(*ctx->usubranges)); + if (!ASSERT_OK_PTR(ctx->usubranges, "usubranges_calloc")) + return -EINVAL; + ctx->ssubranges = calloc(ctx->subrange_cnt, sizeof(*ctx->ssubranges)); + if (!ASSERT_OK_PTR(ctx->ssubranges, "ssubranges_calloc")) + return -EINVAL; + + cnt = 0; + for (i = 0; i < ctx->subval_cnt; i++) { + for (j = i; j < ctx->subval_cnt; j++) { + ctx->usubranges[cnt] = range(U32, ctx->usubvals[i], ctx->usubvals[j]); + ctx->ssubranges[cnt] = range(S32, ctx->ssubvals[i], ctx->ssubvals[j]); + cnt++; + } + } + + return 0; +} + +static int parse_env_vars(struct ctx *ctx) +{ + const char *s; + + if ((s = getenv("REG_BOUNDS_MAX_FAILURE_CNT"))) { + errno = 0; + ctx->max_failure_cnt = strtol(s, NULL, 10); + if (errno || ctx->max_failure_cnt < 0) { + ASSERT_OK(-errno, "REG_BOUNDS_MAX_FAILURE_CNT"); + return -EINVAL; + } + } + + if ((s = getenv("REG_BOUNDS_RAND_CASE_CNT"))) { + errno = 0; + ctx->rand_case_cnt = strtol(s, NULL, 10); + if (errno || ctx->rand_case_cnt < 0) { + ASSERT_OK(-errno, "REG_BOUNDS_RAND_CASE_CNT"); + return -EINVAL; + } + } + + if ((s = getenv("REG_BOUNDS_RAND_SEED"))) { + errno = 0; + ctx->rand_seed = strtoul(s, NULL, 10); + if (errno) { + ASSERT_OK(-errno, "REG_BOUNDS_RAND_SEED"); + return -EINVAL; + } + } + + return 0; +} + +static int prepare_gen_tests(struct ctx *ctx) +{ + const char *s; + int err; + + if (!(s = getenv("SLOW_TESTS")) || strcmp(s, "1") != 0) { + test__skip(); + return -ENOTSUP; + } + + err = parse_env_vars(ctx); + if (err) + return err; + + gen_vals(ctx); + err = gen_ranges(ctx); + if (err) { + ASSERT_OK(err, "gen_ranges"); + return err; + } + + return 0; +} + +/* Go over generated constants and ranges and validate various supported + * combinations of them + */ +static void validate_gen_range_vs_const_64(enum num_t init_t, enum num_t cond_t) +{ + struct ctx ctx; + struct range rconst; + const struct range *ranges; + const u64 *vals; + int i, j; + + memset(&ctx, 0, sizeof(ctx)); + + if (prepare_gen_tests(&ctx)) + goto cleanup; + + ranges = init_t == U64 ? ctx.uranges : ctx.sranges; + vals = init_t == U64 ? ctx.uvals : (const u64 *)ctx.svals; + + ctx.total_case_cnt = (last_op - first_op + 1) * (2 * ctx.range_cnt * ctx.val_cnt); + ctx.start_ns = get_time_ns(); + snprintf(ctx.progress_ctx, sizeof(ctx.progress_ctx), + "RANGE x CONST, %s -> %s", + t_str(init_t), t_str(cond_t)); + + for (i = 0; i < ctx.val_cnt; i++) { + for (j = 0; j < ctx.range_cnt; j++) { + rconst = range(init_t, vals[i], vals[i]); + + /* (u64|s64)( x ) */ + if (verify_case(&ctx, init_t, cond_t, ranges[j], rconst)) + goto cleanup; + /* (u64|s64)( x ) */ + if (verify_case(&ctx, init_t, cond_t, rconst, ranges[j])) + goto cleanup; + } + } + +cleanup: + cleanup_ctx(&ctx); +} + +static void validate_gen_range_vs_const_32(enum num_t init_t, enum num_t cond_t) +{ + struct ctx ctx; + struct range rconst; + const struct range *ranges; + const u32 *vals; + int i, j; + + memset(&ctx, 0, sizeof(ctx)); + + if (prepare_gen_tests(&ctx)) + goto cleanup; + + ranges = init_t == U32 ? ctx.usubranges : ctx.ssubranges; + vals = init_t == U32 ? ctx.usubvals : (const u32 *)ctx.ssubvals; + + ctx.total_case_cnt = (last_op - first_op + 1) * (2 * ctx.subrange_cnt * ctx.subval_cnt); + ctx.start_ns = get_time_ns(); + snprintf(ctx.progress_ctx, sizeof(ctx.progress_ctx), + "RANGE x CONST, %s -> %s", + t_str(init_t), t_str(cond_t)); + + for (i = 0; i < ctx.subval_cnt; i++) { + for (j = 0; j < ctx.subrange_cnt; j++) { + rconst = range(init_t, vals[i], vals[i]); + + /* (u32|s32)( x ) */ + if (verify_case(&ctx, init_t, cond_t, ranges[j], rconst)) + goto cleanup; + /* (u32|s32)( x ) */ + if (verify_case(&ctx, init_t, cond_t, rconst, ranges[j])) + goto cleanup; + } + } + +cleanup: + cleanup_ctx(&ctx); +} + +static void validate_gen_range_vs_range(enum num_t init_t, enum num_t cond_t) +{ + struct ctx ctx; + const struct range *ranges; + int i, j, rcnt; + + memset(&ctx, 0, sizeof(ctx)); + + if (prepare_gen_tests(&ctx)) + goto cleanup; + + switch (init_t) + { + case U64: + ranges = ctx.uranges; + rcnt = ctx.range_cnt; + break; + case U32: + ranges = ctx.usubranges; + rcnt = ctx.subrange_cnt; + break; + case S64: + ranges = ctx.sranges; + rcnt = ctx.range_cnt; + break; + case S32: + ranges = ctx.ssubranges; + rcnt = ctx.subrange_cnt; + break; + default: + printf("validate_gen_range_vs_range!\n"); + exit(1); + } + + ctx.total_case_cnt = (last_op - first_op + 1) * (2 * rcnt * (rcnt + 1) / 2); + ctx.start_ns = get_time_ns(); + snprintf(ctx.progress_ctx, sizeof(ctx.progress_ctx), + "RANGE x RANGE, %s -> %s", + t_str(init_t), t_str(cond_t)); + + for (i = 0; i < rcnt; i++) { + for (j = i; j < rcnt; j++) { + /* ( x ) */ + if (verify_case(&ctx, init_t, cond_t, ranges[i], ranges[j])) + goto cleanup; + if (verify_case(&ctx, init_t, cond_t, ranges[j], ranges[i])) + goto cleanup; + } + } + +cleanup: + cleanup_ctx(&ctx); +} + +/* Go over thousands of test cases generated from initial seed values. + * Given this take a long time, guard this begind SLOW_TESTS=1 envvar. If + * envvar is not set, this test is skipped during test_progs testing. + * + * We split this up into smaller subsets based on initialization and + * conditiona numeric domains to get an easy parallelization with test_progs' + * -j argument. + */ + +/* RANGE x CONST, U64 initial range */ +void test_reg_bounds_gen_consts_u64_u64(void) { validate_gen_range_vs_const_64(U64, U64); } +void test_reg_bounds_gen_consts_u64_s64(void) { validate_gen_range_vs_const_64(U64, S64); } +void test_reg_bounds_gen_consts_u64_u32(void) { validate_gen_range_vs_const_64(U64, U32); } +void test_reg_bounds_gen_consts_u64_s32(void) { validate_gen_range_vs_const_64(U64, S32); } +/* RANGE x CONST, S64 initial range */ +void test_reg_bounds_gen_consts_s64_u64(void) { validate_gen_range_vs_const_64(S64, U64); } +void test_reg_bounds_gen_consts_s64_s64(void) { validate_gen_range_vs_const_64(S64, S64); } +void test_reg_bounds_gen_consts_s64_u32(void) { validate_gen_range_vs_const_64(S64, U32); } +void test_reg_bounds_gen_consts_s64_s32(void) { validate_gen_range_vs_const_64(S64, S32); } +/* RANGE x CONST, U32 initial range */ +void test_reg_bounds_gen_consts_u32_u64(void) { validate_gen_range_vs_const_32(U32, U64); } +void test_reg_bounds_gen_consts_u32_s64(void) { validate_gen_range_vs_const_32(U32, S64); } +void test_reg_bounds_gen_consts_u32_u32(void) { validate_gen_range_vs_const_32(U32, U32); } +void test_reg_bounds_gen_consts_u32_s32(void) { validate_gen_range_vs_const_32(U32, S32); } +/* RANGE x CONST, S32 initial range */ +void test_reg_bounds_gen_consts_s32_u64(void) { validate_gen_range_vs_const_32(S32, U64); } +void test_reg_bounds_gen_consts_s32_s64(void) { validate_gen_range_vs_const_32(S32, S64); } +void test_reg_bounds_gen_consts_s32_u32(void) { validate_gen_range_vs_const_32(S32, U32); } +void test_reg_bounds_gen_consts_s32_s32(void) { validate_gen_range_vs_const_32(S32, S32); } + +/* RANGE x RANGE, U64 initial range */ +void test_reg_bounds_gen_ranges_u64_u64(void) { validate_gen_range_vs_range(U64, U64); } +void test_reg_bounds_gen_ranges_u64_s64(void) { validate_gen_range_vs_range(U64, S64); } +void test_reg_bounds_gen_ranges_u64_u32(void) { validate_gen_range_vs_range(U64, U32); } +void test_reg_bounds_gen_ranges_u64_s32(void) { validate_gen_range_vs_range(U64, S32); } +/* RANGE x RANGE, S64 initial range */ +void test_reg_bounds_gen_ranges_s64_u64(void) { validate_gen_range_vs_range(S64, U64); } +void test_reg_bounds_gen_ranges_s64_s64(void) { validate_gen_range_vs_range(S64, S64); } +void test_reg_bounds_gen_ranges_s64_u32(void) { validate_gen_range_vs_range(S64, U32); } +void test_reg_bounds_gen_ranges_s64_s32(void) { validate_gen_range_vs_range(S64, S32); } +/* RANGE x RANGE, U32 initial range */ +void test_reg_bounds_gen_ranges_u32_u64(void) { validate_gen_range_vs_range(U32, U64); } +void test_reg_bounds_gen_ranges_u32_s64(void) { validate_gen_range_vs_range(U32, S64); } +void test_reg_bounds_gen_ranges_u32_u32(void) { validate_gen_range_vs_range(U32, U32); } +void test_reg_bounds_gen_ranges_u32_s32(void) { validate_gen_range_vs_range(U32, S32); } +/* RANGE x RANGE, S32 initial range */ +void test_reg_bounds_gen_ranges_s32_u64(void) { validate_gen_range_vs_range(S32, U64); } +void test_reg_bounds_gen_ranges_s32_s64(void) { validate_gen_range_vs_range(S32, S64); } +void test_reg_bounds_gen_ranges_s32_u32(void) { validate_gen_range_vs_range(S32, U32); } +void test_reg_bounds_gen_ranges_s32_s32(void) { validate_gen_range_vs_range(S32, S32); } + +#define DEFAULT_RAND_CASE_CNT 100 + +#define RAND_21BIT_MASK ((1 << 22) - 1) + +static u64 rand_u64() +{ + /* RAND_MAX is guaranteed to be at least 1<<15, but in practice it + * seems to be 1<<31, so we need to call it thrice to get full u64; + * we'll use rougly equal split: 22 + 21 + 21 bits + */ + return ((u64)random() << 42) | + (((u64)random() & RAND_21BIT_MASK) << 21) | + (random() & RAND_21BIT_MASK); +} + +static u64 rand_const(enum num_t t) +{ + return cast_t(t, rand_u64()); +} + +static struct range rand_range(enum num_t t) +{ + u64 x = rand_const(t), y = rand_const(t); + + return range(t, min_t(t, x, y), max_t(t, x, y)); +} + +static void validate_rand_ranges(enum num_t init_t, enum num_t cond_t, bool const_range) +{ + struct ctx ctx; + struct range range1, range2; + int err, i; + u64 t; + + memset(&ctx, 0, sizeof(ctx)); + + err = parse_env_vars(&ctx); + if (err) { + ASSERT_OK(err, "parse_env_vars"); + return; + } + + if (ctx.rand_case_cnt == 0) + ctx.rand_case_cnt = DEFAULT_RAND_CASE_CNT; + if (ctx.rand_seed == 0) + ctx.rand_seed = (unsigned)get_time_ns(); + + srandom(ctx.rand_seed); + + ctx.total_case_cnt = (last_op - first_op + 1) * (2 * ctx.rand_case_cnt); + ctx.start_ns = get_time_ns(); + snprintf(ctx.progress_ctx, sizeof(ctx.progress_ctx), + "[RANDOM SEED %u] RANGE x %s, %s -> %s", + ctx.rand_seed, const_range ? "CONST" : "RANGE", + t_str(init_t), t_str(cond_t)); + + for (i = 0; i < ctx.rand_case_cnt; i++) { + range1 = rand_range(init_t); + if (const_range) { + t = rand_const(init_t); + range2 = range(init_t, t, t); + } else { + range2 = rand_range(init_t); + } + + /* x */ + if (verify_case_opt(&ctx, init_t, cond_t, range1, range2, false /* !is_subtest */)) + goto cleanup; + /* x */ + if (verify_case_opt(&ctx, init_t, cond_t, range2, range1, false /* !is_subtest */)) + goto cleanup; + } + +cleanup: + /* make sure we report random seed for reproducing */ + ASSERT_TRUE(true, ctx.progress_ctx); + cleanup_ctx(&ctx); +} + +/* [RANDOM] RANGE x CONST, U64 initial range */ +void test_reg_bounds_rand_consts_u64_u64(void) { validate_rand_ranges(U64, U64, true /* const */); } +void test_reg_bounds_rand_consts_u64_s64(void) { validate_rand_ranges(U64, S64, true /* const */); } +void test_reg_bounds_rand_consts_u64_u32(void) { validate_rand_ranges(U64, U32, true /* const */); } +void test_reg_bounds_rand_consts_u64_s32(void) { validate_rand_ranges(U64, S32, true /* const */); } +/* [RANDOM] RANGE x CONST, S64 initial range */ +void test_reg_bounds_rand_consts_s64_u64(void) { validate_rand_ranges(S64, U64, true /* const */); } +void test_reg_bounds_rand_consts_s64_s64(void) { validate_rand_ranges(S64, S64, true /* const */); } +void test_reg_bounds_rand_consts_s64_u32(void) { validate_rand_ranges(S64, U32, true /* const */); } +void test_reg_bounds_rand_consts_s64_s32(void) { validate_rand_ranges(S64, S32, true /* const */); } +/* [RANDOM] RANGE x CONST, U32 initial range */ +void test_reg_bounds_rand_consts_u32_u64(void) { validate_rand_ranges(U32, U64, true /* const */); } +void test_reg_bounds_rand_consts_u32_s64(void) { validate_rand_ranges(U32, S64, true /* const */); } +void test_reg_bounds_rand_consts_u32_u32(void) { validate_rand_ranges(U32, U32, true /* const */); } +void test_reg_bounds_rand_consts_u32_s32(void) { validate_rand_ranges(U32, S32, true /* const */); } +/* [RANDOM] RANGE x CONST, S32 initial range */ +void test_reg_bounds_rand_consts_s32_u64(void) { validate_rand_ranges(S32, U64, true /* const */); } +void test_reg_bounds_rand_consts_s32_s64(void) { validate_rand_ranges(S32, S64, true /* const */); } +void test_reg_bounds_rand_consts_s32_u32(void) { validate_rand_ranges(S32, U32, true /* const */); } +void test_reg_bounds_rand_consts_s32_s32(void) { validate_rand_ranges(S32, S32, true /* const */); } + +/* [RANDOM] RANGE x RANGE, U64 initial range */ +void test_reg_bounds_rand_ranges_u64_u64(void) { validate_rand_ranges(U64, U64, false /* range */); } +void test_reg_bounds_rand_ranges_u64_s64(void) { validate_rand_ranges(U64, S64, false /* range */); } +void test_reg_bounds_rand_ranges_u64_u32(void) { validate_rand_ranges(U64, U32, false /* range */); } +void test_reg_bounds_rand_ranges_u64_s32(void) { validate_rand_ranges(U64, S32, false /* range */); } +/* [RANDOM] RANGE x RANGE, S64 initial range */ +void test_reg_bounds_rand_ranges_s64_u64(void) { validate_rand_ranges(S64, U64, false /* range */); } +void test_reg_bounds_rand_ranges_s64_s64(void) { validate_rand_ranges(S64, S64, false /* range */); } +void test_reg_bounds_rand_ranges_s64_u32(void) { validate_rand_ranges(S64, U32, false /* range */); } +void test_reg_bounds_rand_ranges_s64_s32(void) { validate_rand_ranges(S64, S32, false /* range */); } +/* [RANDOM] RANGE x RANGE, U32 initial range */ +void test_reg_bounds_rand_ranges_u32_u64(void) { validate_rand_ranges(U32, U64, false /* range */); } +void test_reg_bounds_rand_ranges_u32_s64(void) { validate_rand_ranges(U32, S64, false /* range */); } +void test_reg_bounds_rand_ranges_u32_u32(void) { validate_rand_ranges(U32, U32, false /* range */); } +void test_reg_bounds_rand_ranges_u32_s32(void) { validate_rand_ranges(U32, S32, false /* range */); } +/* [RANDOM] RANGE x RANGE, S32 initial range */ +void test_reg_bounds_rand_ranges_s32_u64(void) { validate_rand_ranges(S32, U64, false /* range */); } +void test_reg_bounds_rand_ranges_s32_s64(void) { validate_rand_ranges(S32, S64, false /* range */); } +void test_reg_bounds_rand_ranges_s32_u32(void) { validate_rand_ranges(S32, U32, false /* range */); } +void test_reg_bounds_rand_ranges_s32_s32(void) { validate_rand_ranges(S32, S32, false /* range */); } + +/* A set of hard-coded "interesting" cases to validate as part of normal + * test_progs test runs + */ +static struct subtest_case crafted_cases[] = { + {U64, U64, {0, 0xffffffff}, {0, 0}}, + {U64, U64, {0, 0x80000000}, {0, 0}}, + {U64, U64, {0x100000000ULL, 0x100000100ULL}, {0, 0}}, + {U64, U64, {0x100000000ULL, 0x180000000ULL}, {0, 0}}, + {U64, U64, {0x100000000ULL, 0x1ffffff00ULL}, {0, 0}}, + {U64, U64, {0x100000000ULL, 0x1ffffff01ULL}, {0, 0}}, + {U64, U64, {0x100000000ULL, 0x1fffffffeULL}, {0, 0}}, + {U64, U64, {0x100000001ULL, 0x1000000ffULL}, {0, 0}}, + + /* single point overlap, interesting BPF_EQ and BPF_NE interactions */ + {U64, U64, {0, 1}, {1, 0x80000000}}, + {U64, S64, {0, 1}, {1, 0x80000000}}, + {U64, U32, {0, 1}, {1, 0x80000000}}, + {U64, S32, {0, 1}, {1, 0x80000000}}, + + {U64, S64, {0, 0xffffffff00000000ULL}, {0, 0}}, + {U64, S64, {0x7fffffffffffffffULL, 0xffffffff00000000ULL}, {0, 0}}, + {U64, S64, {0x7fffffff00000001ULL, 0xffffffff00000000ULL}, {0, 0}}, + {U64, S64, {0, 0xffffffffULL}, {1, 1}}, + {U64, S64, {0, 0xffffffffULL}, {0x7fffffff, 0x7fffffff}}, + + {U64, U32, {0, 0x100000000}, {0, 0}}, + {U64, U32, {0xfffffffe, 0x100000000}, {0x80000000, 0x80000000}}, + + {U64, S32, {0, 0xffffffff00000000ULL}, {0, 0}}, + /* these are tricky cases where lower 32 bits allow to tighten 64 + * bit boundaries based on tightened lower 32 bit boundaries + */ + {U64, S32, {0, 0x0ffffffffULL}, {0, 0}}, + {U64, S32, {0, 0x100000000ULL}, {0, 0}}, + {U64, S32, {0, 0x100000001ULL}, {0, 0}}, + {U64, S32, {0, 0x180000000ULL}, {0, 0}}, + {U64, S32, {0, 0x17fffffffULL}, {0, 0}}, + {U64, S32, {0, 0x180000001ULL}, {0, 0}}, + + /* verifier knows about [-1, 0] range for s32 for this case already */ + {S64, S64, {0xffffffffffffffffULL, 0}, {0xffffffff00000000ULL, 0xffffffff00000000ULL}}, + /* but didn't know about these cases initially */ + {U64, U64, {0xffffffff, 0x100000000ULL}, {0, 0}}, /* s32: [-1, 0] */ + {U64, U64, {0xffffffff, 0x100000001ULL}, {0, 0}}, /* s32: [-1, 1] */ + + /* longer convergence case: learning from u64 -> s64 -> u64 -> u32, + * arriving at u32: [1, U32_MAX] (instead of more pessimistic [0, U32_MAX]) + */ + {S64, U64, {0xffffffff00000001ULL, 0}, {0xffffffff00000000ULL, 0xffffffff00000000ULL}}, + + {U32, U32, {1, U32_MAX}, {0, 0}}, + + {U32, S32, {0, U32_MAX}, {U32_MAX, U32_MAX}}, + + {S32, U64, {(u32)S32_MIN, (u32)S32_MIN}, {(u32)(s32)-255, 0}}, + {S32, S64, {(u32)S32_MIN, (u32)(s32)-255}, {(u32)(s32)-2, 0}}, + {S32, S64, {0, 1}, {(u32)S32_MIN, (u32)S32_MIN}}, + {S32, U32, {(u32)S32_MIN, (u32)S32_MIN}, {(u32)S32_MIN, (u32)S32_MIN}}, + + /* edge overlap testings for BPF_NE */ + {U64, U64, {0, U64_MAX}, {U64_MAX, U64_MAX}}, + {U64, U64, {0, U64_MAX}, {0, 0}}, + {S64, U64, {S64_MIN, 0}, {S64_MIN, S64_MIN}}, + {S64, U64, {S64_MIN, 0}, {0, 0}}, + {S64, U64, {S64_MIN, S64_MAX}, {S64_MAX, S64_MAX}}, + {U32, U32, {0, U32_MAX}, {0, 0}}, + {U32, U32, {0, U32_MAX}, {U32_MAX, U32_MAX}}, + {S32, U32, {(u32)S32_MIN, 0}, {0, 0}}, + {S32, U32, {(u32)S32_MIN, 0}, {(u32)S32_MIN, (u32)S32_MIN}}, + {S32, U32, {(u32)S32_MIN, S32_MAX}, {S32_MAX, S32_MAX}}, +}; + +/* Go over crafted hard-coded cases. This is fast, so we do it as part of + * normal test_progs run. + */ +void test_reg_bounds_crafted(void) +{ + struct ctx ctx; + int i; + + memset(&ctx, 0, sizeof(ctx)); + + for (i = 0; i < ARRAY_SIZE(crafted_cases); i++) { + struct subtest_case *c = &crafted_cases[i]; + + verify_case(&ctx, c->init_t, c->cond_t, c->x, c->y); + verify_case(&ctx, c->init_t, c->cond_t, c->y, c->x); + } + + cleanup_ctx(&ctx); +} diff --git a/tools/testing/selftests/bpf/prog_tests/sock_iter_batch.c b/tools/testing/selftests/bpf/prog_tests/sock_iter_batch.c new file mode 100644 index 0000000000..0c365f36c7 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/sock_iter_batch.c @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2024 Meta + +#include +#include "network_helpers.h" +#include "sock_iter_batch.skel.h" + +#define TEST_NS "sock_iter_batch_netns" + +static const int nr_soreuse = 4; + +static void do_test(int sock_type, bool onebyone) +{ + int err, i, nread, to_read, total_read, iter_fd = -1; + int first_idx, second_idx, indices[nr_soreuse]; + struct bpf_link *link = NULL; + struct sock_iter_batch *skel; + int *fds[2] = {}; + + skel = sock_iter_batch__open(); + if (!ASSERT_OK_PTR(skel, "sock_iter_batch__open")) + return; + + /* Prepare 2 buckets of sockets in the kernel hashtable */ + for (i = 0; i < ARRAY_SIZE(fds); i++) { + int local_port; + + fds[i] = start_reuseport_server(AF_INET6, sock_type, "::1", 0, 0, + nr_soreuse); + if (!ASSERT_OK_PTR(fds[i], "start_reuseport_server")) + goto done; + local_port = get_socket_local_port(*fds[i]); + if (!ASSERT_GE(local_port, 0, "get_socket_local_port")) + goto done; + skel->rodata->ports[i] = ntohs(local_port); + } + + err = sock_iter_batch__load(skel); + if (!ASSERT_OK(err, "sock_iter_batch__load")) + goto done; + + link = bpf_program__attach_iter(sock_type == SOCK_STREAM ? + skel->progs.iter_tcp_soreuse : + skel->progs.iter_udp_soreuse, + NULL); + if (!ASSERT_OK_PTR(link, "bpf_program__attach_iter")) + goto done; + + iter_fd = bpf_iter_create(bpf_link__fd(link)); + if (!ASSERT_GE(iter_fd, 0, "bpf_iter_create")) + goto done; + + /* Test reading a bucket (either from fds[0] or fds[1]). + * Only read "nr_soreuse - 1" number of sockets + * from a bucket and leave one socket out from + * that bucket on purpose. + */ + to_read = (nr_soreuse - 1) * sizeof(*indices); + total_read = 0; + first_idx = -1; + do { + nread = read(iter_fd, indices, onebyone ? sizeof(*indices) : to_read); + if (nread <= 0 || nread % sizeof(*indices)) + break; + total_read += nread; + + if (first_idx == -1) + first_idx = indices[0]; + for (i = 0; i < nread / sizeof(*indices); i++) + ASSERT_EQ(indices[i], first_idx, "first_idx"); + } while (total_read < to_read); + ASSERT_EQ(nread, onebyone ? sizeof(*indices) : to_read, "nread"); + ASSERT_EQ(total_read, to_read, "total_read"); + + free_fds(fds[first_idx], nr_soreuse); + fds[first_idx] = NULL; + + /* Read the "whole" second bucket */ + to_read = nr_soreuse * sizeof(*indices); + total_read = 0; + second_idx = !first_idx; + do { + nread = read(iter_fd, indices, onebyone ? sizeof(*indices) : to_read); + if (nread <= 0 || nread % sizeof(*indices)) + break; + total_read += nread; + + for (i = 0; i < nread / sizeof(*indices); i++) + ASSERT_EQ(indices[i], second_idx, "second_idx"); + } while (total_read <= to_read); + ASSERT_EQ(nread, 0, "nread"); + /* Both so_reuseport ports should be in different buckets, so + * total_read must equal to the expected to_read. + * + * For a very unlikely case, both ports collide at the same bucket, + * the bucket offset (i.e. 3) will be skipped and it cannot + * expect the to_read number of bytes. + */ + if (skel->bss->bucket[0] != skel->bss->bucket[1]) + ASSERT_EQ(total_read, to_read, "total_read"); + +done: + for (i = 0; i < ARRAY_SIZE(fds); i++) + free_fds(fds[i], nr_soreuse); + if (iter_fd < 0) + close(iter_fd); + bpf_link__destroy(link); + sock_iter_batch__destroy(skel); +} + +void test_sock_iter_batch(void) +{ + struct nstoken *nstoken = NULL; + + SYS_NOFAIL("ip netns del " TEST_NS " &> /dev/null"); + SYS(done, "ip netns add %s", TEST_NS); + SYS(done, "ip -net %s link set dev lo up", TEST_NS); + + nstoken = open_netns(TEST_NS); + if (!ASSERT_OK_PTR(nstoken, "open_netns")) + goto done; + + if (test__start_subtest("tcp")) { + do_test(SOCK_STREAM, true); + do_test(SOCK_STREAM, false); + } + if (test__start_subtest("udp")) { + do_test(SOCK_DGRAM, true); + do_test(SOCK_DGRAM, false); + } + close_netns(nstoken); + +done: + SYS_NOFAIL("ip netns del " TEST_NS " &> /dev/null"); +} diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c b/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c index 7c2241fae1..77e26ecffa 100644 --- a/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c +++ b/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c @@ -555,6 +555,213 @@ static void test_sockmap_unconnected_unix(void) close(dgram); } +static void test_sockmap_many_socket(void) +{ + struct test_sockmap_pass_prog *skel; + int stream[2], dgram, udp, tcp; + int i, err, map, entry = 0; + + skel = test_sockmap_pass_prog__open_and_load(); + if (!ASSERT_OK_PTR(skel, "open_and_load")) + return; + + map = bpf_map__fd(skel->maps.sock_map_rx); + + dgram = xsocket(AF_UNIX, SOCK_DGRAM, 0); + if (dgram < 0) { + test_sockmap_pass_prog__destroy(skel); + return; + } + + tcp = connected_socket_v4(); + if (!ASSERT_GE(tcp, 0, "connected_socket_v4")) { + close(dgram); + test_sockmap_pass_prog__destroy(skel); + return; + } + + udp = xsocket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0); + if (udp < 0) { + close(dgram); + close(tcp); + test_sockmap_pass_prog__destroy(skel); + return; + } + + err = socketpair(AF_UNIX, SOCK_STREAM, 0, stream); + ASSERT_OK(err, "socketpair(af_unix, sock_stream)"); + if (err) + goto out; + + for (i = 0; i < 2; i++, entry++) { + err = bpf_map_update_elem(map, &entry, &stream[0], BPF_ANY); + ASSERT_OK(err, "bpf_map_update_elem(stream)"); + } + for (i = 0; i < 2; i++, entry++) { + err = bpf_map_update_elem(map, &entry, &dgram, BPF_ANY); + ASSERT_OK(err, "bpf_map_update_elem(dgram)"); + } + for (i = 0; i < 2; i++, entry++) { + err = bpf_map_update_elem(map, &entry, &udp, BPF_ANY); + ASSERT_OK(err, "bpf_map_update_elem(udp)"); + } + for (i = 0; i < 2; i++, entry++) { + err = bpf_map_update_elem(map, &entry, &tcp, BPF_ANY); + ASSERT_OK(err, "bpf_map_update_elem(tcp)"); + } + for (entry--; entry >= 0; entry--) { + err = bpf_map_delete_elem(map, &entry); + ASSERT_OK(err, "bpf_map_delete_elem(entry)"); + } + + close(stream[0]); + close(stream[1]); +out: + close(dgram); + close(tcp); + close(udp); + test_sockmap_pass_prog__destroy(skel); +} + +static void test_sockmap_many_maps(void) +{ + struct test_sockmap_pass_prog *skel; + int stream[2], dgram, udp, tcp; + int i, err, map[2], entry = 0; + + skel = test_sockmap_pass_prog__open_and_load(); + if (!ASSERT_OK_PTR(skel, "open_and_load")) + return; + + map[0] = bpf_map__fd(skel->maps.sock_map_rx); + map[1] = bpf_map__fd(skel->maps.sock_map_tx); + + dgram = xsocket(AF_UNIX, SOCK_DGRAM, 0); + if (dgram < 0) { + test_sockmap_pass_prog__destroy(skel); + return; + } + + tcp = connected_socket_v4(); + if (!ASSERT_GE(tcp, 0, "connected_socket_v4")) { + close(dgram); + test_sockmap_pass_prog__destroy(skel); + return; + } + + udp = xsocket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0); + if (udp < 0) { + close(dgram); + close(tcp); + test_sockmap_pass_prog__destroy(skel); + return; + } + + err = socketpair(AF_UNIX, SOCK_STREAM, 0, stream); + ASSERT_OK(err, "socketpair(af_unix, sock_stream)"); + if (err) + goto out; + + for (i = 0; i < 2; i++, entry++) { + err = bpf_map_update_elem(map[i], &entry, &stream[0], BPF_ANY); + ASSERT_OK(err, "bpf_map_update_elem(stream)"); + } + for (i = 0; i < 2; i++, entry++) { + err = bpf_map_update_elem(map[i], &entry, &dgram, BPF_ANY); + ASSERT_OK(err, "bpf_map_update_elem(dgram)"); + } + for (i = 0; i < 2; i++, entry++) { + err = bpf_map_update_elem(map[i], &entry, &udp, BPF_ANY); + ASSERT_OK(err, "bpf_map_update_elem(udp)"); + } + for (i = 0; i < 2; i++, entry++) { + err = bpf_map_update_elem(map[i], &entry, &tcp, BPF_ANY); + ASSERT_OK(err, "bpf_map_update_elem(tcp)"); + } + for (entry--; entry >= 0; entry--) { + err = bpf_map_delete_elem(map[1], &entry); + entry--; + ASSERT_OK(err, "bpf_map_delete_elem(entry)"); + err = bpf_map_delete_elem(map[0], &entry); + ASSERT_OK(err, "bpf_map_delete_elem(entry)"); + } + + close(stream[0]); + close(stream[1]); +out: + close(dgram); + close(tcp); + close(udp); + test_sockmap_pass_prog__destroy(skel); +} + +static void test_sockmap_same_sock(void) +{ + struct test_sockmap_pass_prog *skel; + int stream[2], dgram, udp, tcp; + int i, err, map, zero = 0; + + skel = test_sockmap_pass_prog__open_and_load(); + if (!ASSERT_OK_PTR(skel, "open_and_load")) + return; + + map = bpf_map__fd(skel->maps.sock_map_rx); + + dgram = xsocket(AF_UNIX, SOCK_DGRAM, 0); + if (dgram < 0) { + test_sockmap_pass_prog__destroy(skel); + return; + } + + tcp = connected_socket_v4(); + if (!ASSERT_GE(tcp, 0, "connected_socket_v4")) { + close(dgram); + test_sockmap_pass_prog__destroy(skel); + return; + } + + udp = xsocket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0); + if (udp < 0) { + close(dgram); + close(tcp); + test_sockmap_pass_prog__destroy(skel); + return; + } + + err = socketpair(AF_UNIX, SOCK_STREAM, 0, stream); + ASSERT_OK(err, "socketpair(af_unix, sock_stream)"); + if (err) + goto out; + + for (i = 0; i < 2; i++) { + err = bpf_map_update_elem(map, &zero, &stream[0], BPF_ANY); + ASSERT_OK(err, "bpf_map_update_elem(stream)"); + } + for (i = 0; i < 2; i++) { + err = bpf_map_update_elem(map, &zero, &dgram, BPF_ANY); + ASSERT_OK(err, "bpf_map_update_elem(dgram)"); + } + for (i = 0; i < 2; i++) { + err = bpf_map_update_elem(map, &zero, &udp, BPF_ANY); + ASSERT_OK(err, "bpf_map_update_elem(udp)"); + } + for (i = 0; i < 2; i++) { + err = bpf_map_update_elem(map, &zero, &tcp, BPF_ANY); + ASSERT_OK(err, "bpf_map_update_elem(tcp)"); + } + + err = bpf_map_delete_elem(map, &zero); + ASSERT_OK(err, "bpf_map_delete_elem(entry)"); + + close(stream[0]); + close(stream[1]); +out: + close(dgram); + close(tcp); + close(udp); + test_sockmap_pass_prog__destroy(skel); +} + void test_sockmap_basic(void) { if (test__start_subtest("sockmap create_update_free")) @@ -597,7 +804,12 @@ void test_sockmap_basic(void) test_sockmap_skb_verdict_fionread(false); if (test__start_subtest("sockmap skb_verdict msg_f_peek")) test_sockmap_skb_verdict_peek(); - if (test__start_subtest("sockmap unconnected af_unix")) test_sockmap_unconnected_unix(); + if (test__start_subtest("sockmap one socket to many map entries")) + test_sockmap_many_socket(); + if (test__start_subtest("sockmap one socket to many maps")) + test_sockmap_many_maps(); + if (test__start_subtest("sockmap same socket replace")) + test_sockmap_same_sock(); } diff --git a/tools/testing/selftests/bpf/prog_tests/spin_lock.c b/tools/testing/selftests/bpf/prog_tests/spin_lock.c index f29c08d93b..18d451be57 100644 --- a/tools/testing/selftests/bpf/prog_tests/spin_lock.c +++ b/tools/testing/selftests/bpf/prog_tests/spin_lock.c @@ -13,22 +13,22 @@ static struct { const char *err_msg; } spin_lock_fail_tests[] = { { "lock_id_kptr_preserve", - "5: (bf) r1 = r0 ; R0_w=ptr_foo(id=2,ref_obj_id=2,off=0,imm=0) " - "R1_w=ptr_foo(id=2,ref_obj_id=2,off=0,imm=0) refs=2\n6: (85) call bpf_this_cpu_ptr#154\n" + "5: (bf) r1 = r0 ; R0_w=ptr_foo(id=2,ref_obj_id=2) " + "R1_w=ptr_foo(id=2,ref_obj_id=2) refs=2\n6: (85) call bpf_this_cpu_ptr#154\n" "R1 type=ptr_ expected=percpu_ptr_" }, { "lock_id_global_zero", - "; R1_w=map_value(off=0,ks=4,vs=4,imm=0)\n2: (85) call bpf_this_cpu_ptr#154\n" + "; R1_w=map_value(map=.data.A,ks=4,vs=4)\n2: (85) call bpf_this_cpu_ptr#154\n" "R1 type=map_value expected=percpu_ptr_" }, { "lock_id_mapval_preserve", "[0-9]\\+: (bf) r1 = r0 ;" - " R0_w=map_value(id=1,off=0,ks=4,vs=8,imm=0)" - " R1_w=map_value(id=1,off=0,ks=4,vs=8,imm=0)\n" + " R0_w=map_value(id=1,map=array_map,ks=4,vs=8)" + " R1_w=map_value(id=1,map=array_map,ks=4,vs=8)\n" "[0-9]\\+: (85) call bpf_this_cpu_ptr#154\n" "R1 type=map_value expected=percpu_ptr_" }, { "lock_id_innermapval_preserve", "[0-9]\\+: (bf) r1 = r0 ;" - " R0=map_value(id=2,off=0,ks=4,vs=8,imm=0)" - " R1_w=map_value(id=2,off=0,ks=4,vs=8,imm=0)\n" + " R0=map_value(id=2,ks=4,vs=8)" + " R1_w=map_value(id=2,ks=4,vs=8)\n" "[0-9]\\+: (85) call bpf_this_cpu_ptr#154\n" "R1 type=map_value expected=percpu_ptr_" }, { "lock_id_mismatch_kptr_kptr", "bpf_spin_unlock of different lock" }, diff --git a/tools/testing/selftests/bpf/prog_tests/syscall.c b/tools/testing/selftests/bpf/prog_tests/syscall.c index f4d4000115..0be8301c0f 100644 --- a/tools/testing/selftests/bpf/prog_tests/syscall.c +++ b/tools/testing/selftests/bpf/prog_tests/syscall.c @@ -12,7 +12,7 @@ struct args { int btf_fd; }; -void test_syscall(void) +static void test_syscall_load_prog(void) { static char verifier_log[8192]; struct args ctx = { @@ -32,7 +32,7 @@ void test_syscall(void) if (!ASSERT_OK_PTR(skel, "skel_load")) goto cleanup; - prog_fd = bpf_program__fd(skel->progs.bpf_prog); + prog_fd = bpf_program__fd(skel->progs.load_prog); err = bpf_prog_test_run_opts(prog_fd, &tattr); ASSERT_EQ(err, 0, "err"); ASSERT_EQ(tattr.retval, 1, "retval"); @@ -53,3 +53,29 @@ cleanup: if (ctx.btf_fd > 0) close(ctx.btf_fd); } + +static void test_syscall_update_outer_map(void) +{ + LIBBPF_OPTS(bpf_test_run_opts, opts); + struct syscall *skel; + int err, prog_fd; + + skel = syscall__open_and_load(); + if (!ASSERT_OK_PTR(skel, "skel_load")) + goto cleanup; + + prog_fd = bpf_program__fd(skel->progs.update_outer_map); + err = bpf_prog_test_run_opts(prog_fd, &opts); + ASSERT_EQ(err, 0, "err"); + ASSERT_EQ(opts.retval, 1, "retval"); +cleanup: + syscall__destroy(skel); +} + +void test_syscall(void) +{ + if (test__start_subtest("load_prog")) + test_syscall_load_prog(); + if (test__start_subtest("update_outer_map")) + test_syscall_update_outer_map(); +} diff --git a/tools/testing/selftests/bpf/prog_tests/test_bpf_ma.c b/tools/testing/selftests/bpf/prog_tests/test_bpf_ma.c index d3491a84b3..ccae0b31ac 100644 --- a/tools/testing/selftests/bpf/prog_tests/test_bpf_ma.c +++ b/tools/testing/selftests/bpf/prog_tests/test_bpf_ma.c @@ -14,7 +14,8 @@ static void do_bpf_ma_test(const char *name) struct test_bpf_ma *skel; struct bpf_program *prog; struct btf *btf; - int i, err; + int i, err, id; + char tname[32]; skel = test_bpf_ma__open(); if (!ASSERT_OK_PTR(skel, "open")) @@ -25,16 +26,21 @@ static void do_bpf_ma_test(const char *name) goto out; for (i = 0; i < ARRAY_SIZE(skel->rodata->data_sizes); i++) { - char name[32]; - int id; - - snprintf(name, sizeof(name), "bin_data_%u", skel->rodata->data_sizes[i]); - id = btf__find_by_name_kind(btf, name, BTF_KIND_STRUCT); - if (!ASSERT_GT(id, 0, "bin_data")) + snprintf(tname, sizeof(tname), "bin_data_%u", skel->rodata->data_sizes[i]); + id = btf__find_by_name_kind(btf, tname, BTF_KIND_STRUCT); + if (!ASSERT_GT(id, 0, tname)) goto out; skel->rodata->data_btf_ids[i] = id; } + for (i = 0; i < ARRAY_SIZE(skel->rodata->percpu_data_sizes); i++) { + snprintf(tname, sizeof(tname), "percpu_bin_data_%u", skel->rodata->percpu_data_sizes[i]); + id = btf__find_by_name_kind(btf, tname, BTF_KIND_STRUCT); + if (!ASSERT_GT(id, 0, tname)) + goto out; + skel->rodata->percpu_data_btf_ids[i] = id; + } + prog = bpf_object__find_program_by_name(skel->obj, name); if (!ASSERT_OK_PTR(prog, "invalid prog name")) goto out; diff --git a/tools/testing/selftests/bpf/prog_tests/test_global_funcs.c b/tools/testing/selftests/bpf/prog_tests/test_global_funcs.c index e0879df386..e905cbaf6b 100644 --- a/tools/testing/selftests/bpf/prog_tests/test_global_funcs.c +++ b/tools/testing/selftests/bpf/prog_tests/test_global_funcs.c @@ -20,6 +20,122 @@ #include "test_global_func17.skel.h" #include "test_global_func_ctx_args.skel.h" +#include "bpf/libbpf_internal.h" +#include "btf_helpers.h" + +static void check_ctx_arg_type(const struct btf *btf, const struct btf_param *p) +{ + const struct btf_type *t; + const char *s; + + t = btf__type_by_id(btf, p->type); + if (!ASSERT_EQ(btf_kind(t), BTF_KIND_PTR, "ptr_t")) + return; + + s = btf_type_raw_dump(btf, t->type); + if (!ASSERT_HAS_SUBSTR(s, "STRUCT 'bpf_perf_event_data' size=0 vlen=0", + "ctx_struct_t")) + return; +} + +static void subtest_ctx_arg_rewrite(void) +{ + struct test_global_func_ctx_args *skel = NULL; + struct bpf_prog_info info; + char func_info_buf[1024] __attribute__((aligned(8))); + struct bpf_func_info_min *rec; + struct btf *btf = NULL; + __u32 info_len = sizeof(info); + int err, fd, i; + struct btf *kern_btf = NULL; + + kern_btf = btf__load_vmlinux_btf(); + if (!ASSERT_OK_PTR(kern_btf, "kern_btf_load")) + return; + + /* simple detection of kernel native arg:ctx tag support */ + if (btf__find_by_name_kind(kern_btf, "bpf_subprog_arg_info", BTF_KIND_STRUCT) > 0) { + test__skip(); + btf__free(kern_btf); + return; + } + btf__free(kern_btf); + + skel = test_global_func_ctx_args__open(); + if (!ASSERT_OK_PTR(skel, "skel_open")) + return; + + bpf_program__set_autoload(skel->progs.arg_tag_ctx_perf, true); + + err = test_global_func_ctx_args__load(skel); + if (!ASSERT_OK(err, "skel_load")) + goto out; + + memset(&info, 0, sizeof(info)); + info.func_info = ptr_to_u64(&func_info_buf); + info.nr_func_info = 3; + info.func_info_rec_size = sizeof(struct bpf_func_info_min); + + fd = bpf_program__fd(skel->progs.arg_tag_ctx_perf); + err = bpf_prog_get_info_by_fd(fd, &info, &info_len); + if (!ASSERT_OK(err, "prog_info")) + goto out; + + if (!ASSERT_EQ(info.nr_func_info, 3, "nr_func_info")) + goto out; + + btf = btf__load_from_kernel_by_id(info.btf_id); + if (!ASSERT_OK_PTR(btf, "obj_kern_btf")) + goto out; + + rec = (struct bpf_func_info_min *)func_info_buf; + for (i = 0; i < info.nr_func_info; i++, rec = (void *)rec + info.func_info_rec_size) { + const struct btf_type *fn_t, *proto_t; + const char *name; + + if (rec->insn_off == 0) + continue; /* main prog, skip */ + + fn_t = btf__type_by_id(btf, rec->type_id); + if (!ASSERT_OK_PTR(fn_t, "fn_type")) + goto out; + if (!ASSERT_EQ(btf_kind(fn_t), BTF_KIND_FUNC, "fn_type_kind")) + goto out; + proto_t = btf__type_by_id(btf, fn_t->type); + if (!ASSERT_OK_PTR(proto_t, "proto_type")) + goto out; + + name = btf__name_by_offset(btf, fn_t->name_off); + if (strcmp(name, "subprog_ctx_tag") == 0) { + /* int subprog_ctx_tag(void *ctx __arg_ctx) */ + if (!ASSERT_EQ(btf_vlen(proto_t), 1, "arg_cnt")) + goto out; + + /* arg 0 is PTR -> STRUCT bpf_perf_event_data */ + check_ctx_arg_type(btf, &btf_params(proto_t)[0]); + } else if (strcmp(name, "subprog_multi_ctx_tags") == 0) { + /* int subprog_multi_ctx_tags(void *ctx1 __arg_ctx, + * struct my_struct *mem, + * void *ctx2 __arg_ctx) + */ + if (!ASSERT_EQ(btf_vlen(proto_t), 3, "arg_cnt")) + goto out; + + /* arg 0 is PTR -> STRUCT bpf_perf_event_data */ + check_ctx_arg_type(btf, &btf_params(proto_t)[0]); + /* arg 2 is PTR -> STRUCT bpf_perf_event_data */ + check_ctx_arg_type(btf, &btf_params(proto_t)[2]); + } else { + ASSERT_FAIL("unexpected subprog %s", name); + goto out; + } + } + +out: + btf__free(btf); + test_global_func_ctx_args__destroy(skel); +} + void test_test_global_funcs(void) { RUN_TESTS(test_global_func1); @@ -40,4 +156,7 @@ void test_test_global_funcs(void) RUN_TESTS(test_global_func16); RUN_TESTS(test_global_func17); RUN_TESTS(test_global_func_ctx_args); + + if (test__start_subtest("ctx_arg_rewrite")) + subtest_ctx_arg_rewrite(); } diff --git a/tools/testing/selftests/bpf/prog_tests/test_tunnel.c b/tools/testing/selftests/bpf/prog_tests/test_tunnel.c index d149ab9879..2b3c6dd662 100644 --- a/tools/testing/selftests/bpf/prog_tests/test_tunnel.c +++ b/tools/testing/selftests/bpf/prog_tests/test_tunnel.c @@ -50,6 +50,7 @@ */ #include +#include #include #include #include @@ -92,6 +93,11 @@ #define IPIP_TUNL_DEV0 "ipip00" #define IPIP_TUNL_DEV1 "ipip11" +#define XFRM_AUTH "0x1111111111111111111111111111111111111111" +#define XFRM_ENC "0x22222222222222222222222222222222" +#define XFRM_SPI_IN_TO_OUT 0x1 +#define XFRM_SPI_OUT_TO_IN 0x2 + #define PING_ARGS "-i 0.01 -c 3 -w 10 -q" static int config_device(void) @@ -264,6 +270,92 @@ static void delete_ipip_tunnel(void) SYS_NOFAIL("ip fou del port 5555 2> /dev/null"); } +static int add_xfrm_tunnel(void) +{ + /* at_ns0 namespace + * at_ns0 -> root + */ + SYS(fail, + "ip netns exec at_ns0 " + "ip xfrm state add src %s dst %s proto esp " + "spi %d reqid 1 mode tunnel replay-window 42 " + "auth-trunc 'hmac(sha1)' %s 96 enc 'cbc(aes)' %s", + IP4_ADDR_VETH0, IP4_ADDR1_VETH1, XFRM_SPI_IN_TO_OUT, XFRM_AUTH, XFRM_ENC); + SYS(fail, + "ip netns exec at_ns0 " + "ip xfrm policy add src %s/32 dst %s/32 dir out " + "tmpl src %s dst %s proto esp reqid 1 " + "mode tunnel", + IP4_ADDR_TUNL_DEV0, IP4_ADDR_TUNL_DEV1, IP4_ADDR_VETH0, IP4_ADDR1_VETH1); + + /* root -> at_ns0 */ + SYS(fail, + "ip netns exec at_ns0 " + "ip xfrm state add src %s dst %s proto esp " + "spi %d reqid 2 mode tunnel " + "auth-trunc 'hmac(sha1)' %s 96 enc 'cbc(aes)' %s", + IP4_ADDR1_VETH1, IP4_ADDR_VETH0, XFRM_SPI_OUT_TO_IN, XFRM_AUTH, XFRM_ENC); + SYS(fail, + "ip netns exec at_ns0 " + "ip xfrm policy add src %s/32 dst %s/32 dir in " + "tmpl src %s dst %s proto esp reqid 2 " + "mode tunnel", + IP4_ADDR_TUNL_DEV1, IP4_ADDR_TUNL_DEV0, IP4_ADDR1_VETH1, IP4_ADDR_VETH0); + + /* address & route */ + SYS(fail, "ip netns exec at_ns0 ip addr add dev veth0 %s/32", + IP4_ADDR_TUNL_DEV0); + SYS(fail, "ip netns exec at_ns0 ip route add %s dev veth0 via %s src %s", + IP4_ADDR_TUNL_DEV1, IP4_ADDR1_VETH1, IP4_ADDR_TUNL_DEV0); + + /* root namespace + * at_ns0 -> root + */ + SYS(fail, + "ip xfrm state add src %s dst %s proto esp " + "spi %d reqid 1 mode tunnel replay-window 42 " + "auth-trunc 'hmac(sha1)' %s 96 enc 'cbc(aes)' %s", + IP4_ADDR_VETH0, IP4_ADDR1_VETH1, XFRM_SPI_IN_TO_OUT, XFRM_AUTH, XFRM_ENC); + SYS(fail, + "ip xfrm policy add src %s/32 dst %s/32 dir in " + "tmpl src %s dst %s proto esp reqid 1 " + "mode tunnel", + IP4_ADDR_TUNL_DEV0, IP4_ADDR_TUNL_DEV1, IP4_ADDR_VETH0, IP4_ADDR1_VETH1); + + /* root -> at_ns0 */ + SYS(fail, + "ip xfrm state add src %s dst %s proto esp " + "spi %d reqid 2 mode tunnel " + "auth-trunc 'hmac(sha1)' %s 96 enc 'cbc(aes)' %s", + IP4_ADDR1_VETH1, IP4_ADDR_VETH0, XFRM_SPI_OUT_TO_IN, XFRM_AUTH, XFRM_ENC); + SYS(fail, + "ip xfrm policy add src %s/32 dst %s/32 dir out " + "tmpl src %s dst %s proto esp reqid 2 " + "mode tunnel", + IP4_ADDR_TUNL_DEV1, IP4_ADDR_TUNL_DEV0, IP4_ADDR1_VETH1, IP4_ADDR_VETH0); + + /* address & route */ + SYS(fail, "ip addr add dev veth1 %s/32", IP4_ADDR_TUNL_DEV1); + SYS(fail, "ip route add %s dev veth1 via %s src %s", + IP4_ADDR_TUNL_DEV0, IP4_ADDR_VETH0, IP4_ADDR_TUNL_DEV1); + + return 0; +fail: + return -1; +} + +static void delete_xfrm_tunnel(void) +{ + SYS_NOFAIL("ip xfrm policy delete dir out src %s/32 dst %s/32 2> /dev/null", + IP4_ADDR_TUNL_DEV1, IP4_ADDR_TUNL_DEV0); + SYS_NOFAIL("ip xfrm policy delete dir in src %s/32 dst %s/32 2> /dev/null", + IP4_ADDR_TUNL_DEV0, IP4_ADDR_TUNL_DEV1); + SYS_NOFAIL("ip xfrm state delete src %s dst %s proto esp spi %d 2> /dev/null", + IP4_ADDR_VETH0, IP4_ADDR1_VETH1, XFRM_SPI_IN_TO_OUT); + SYS_NOFAIL("ip xfrm state delete src %s dst %s proto esp spi %d 2> /dev/null", + IP4_ADDR1_VETH1, IP4_ADDR_VETH0, XFRM_SPI_OUT_TO_IN); +} + static int test_ping(int family, const char *addr) { SYS(fail, "%s %s %s > /dev/null", ping_command(family), PING_ARGS, addr); @@ -532,25 +624,85 @@ done: test_tunnel_kern__destroy(skel); } +static void test_xfrm_tunnel(void) +{ + DECLARE_LIBBPF_OPTS(bpf_tc_hook, tc_hook, + .attach_point = BPF_TC_INGRESS); + LIBBPF_OPTS(bpf_xdp_attach_opts, opts); + struct test_tunnel_kern *skel = NULL; + struct nstoken *nstoken; + int xdp_prog_fd; + int tc_prog_fd; + int ifindex; + int err; + + err = add_xfrm_tunnel(); + if (!ASSERT_OK(err, "add_xfrm_tunnel")) + return; + + skel = test_tunnel_kern__open_and_load(); + if (!ASSERT_OK_PTR(skel, "test_tunnel_kern__open_and_load")) + goto done; + + ifindex = if_nametoindex("veth1"); + if (!ASSERT_NEQ(ifindex, 0, "veth1 ifindex")) + goto done; + + /* attach tc prog to tunnel dev */ + tc_hook.ifindex = ifindex; + tc_prog_fd = bpf_program__fd(skel->progs.xfrm_get_state); + if (!ASSERT_GE(tc_prog_fd, 0, "bpf_program__fd")) + goto done; + if (attach_tc_prog(&tc_hook, tc_prog_fd, -1)) + goto done; + + /* attach xdp prog to tunnel dev */ + xdp_prog_fd = bpf_program__fd(skel->progs.xfrm_get_state_xdp); + if (!ASSERT_GE(xdp_prog_fd, 0, "bpf_program__fd")) + goto done; + err = bpf_xdp_attach(ifindex, xdp_prog_fd, XDP_FLAGS_REPLACE, &opts); + if (!ASSERT_OK(err, "bpf_xdp_attach")) + goto done; + + /* ping from at_ns0 namespace test */ + nstoken = open_netns("at_ns0"); + err = test_ping(AF_INET, IP4_ADDR_TUNL_DEV1); + close_netns(nstoken); + if (!ASSERT_OK(err, "test_ping")) + goto done; + + if (!ASSERT_EQ(skel->bss->xfrm_reqid, 1, "req_id")) + goto done; + if (!ASSERT_EQ(skel->bss->xfrm_spi, XFRM_SPI_IN_TO_OUT, "spi")) + goto done; + if (!ASSERT_EQ(skel->bss->xfrm_remote_ip, 0xac100164, "remote_ip")) + goto done; + if (!ASSERT_EQ(skel->bss->xfrm_replay_window, 42, "replay_window")) + goto done; + +done: + delete_xfrm_tunnel(); + if (skel) + test_tunnel_kern__destroy(skel); +} + #define RUN_TEST(name, ...) \ ({ \ if (test__start_subtest(#name)) { \ + config_device(); \ test_ ## name(__VA_ARGS__); \ + cleanup(); \ } \ }) static void *test_tunnel_run_tests(void *arg) { - cleanup(); - config_device(); - RUN_TEST(vxlan_tunnel); RUN_TEST(ip6vxlan_tunnel); RUN_TEST(ipip_tunnel, NONE); RUN_TEST(ipip_tunnel, FOU); RUN_TEST(ipip_tunnel, GUE); - - cleanup(); + RUN_TEST(xfrm_tunnel); return NULL; } diff --git a/tools/testing/selftests/bpf/prog_tests/timer.c b/tools/testing/selftests/bpf/prog_tests/timer.c index 760ad96b4b..d66687f1ee 100644 --- a/tools/testing/selftests/bpf/prog_tests/timer.c +++ b/tools/testing/selftests/bpf/prog_tests/timer.c @@ -4,10 +4,29 @@ #include "timer.skel.h" #include "timer_failure.skel.h" +#define NUM_THR 8 + +static void *spin_lock_thread(void *arg) +{ + int i, err, prog_fd = *(int *)arg; + LIBBPF_OPTS(bpf_test_run_opts, topts); + + for (i = 0; i < 10000; i++) { + err = bpf_prog_test_run_opts(prog_fd, &topts); + if (!ASSERT_OK(err, "test_run_opts err") || + !ASSERT_OK(topts.retval, "test_run_opts retval")) + break; + } + + pthread_exit(arg); +} + static int timer(struct timer *timer_skel) { - int err, prog_fd; + int i, err, prog_fd; LIBBPF_OPTS(bpf_test_run_opts, topts); + pthread_t thread_id[NUM_THR]; + void *ret; err = timer__attach(timer_skel); if (!ASSERT_OK(err, "timer_attach")) @@ -43,6 +62,20 @@ static int timer(struct timer *timer_skel) /* check that code paths completed */ ASSERT_EQ(timer_skel->bss->ok, 1 | 2 | 4, "ok"); + prog_fd = bpf_program__fd(timer_skel->progs.race); + for (i = 0; i < NUM_THR; i++) { + err = pthread_create(&thread_id[i], NULL, + &spin_lock_thread, &prog_fd); + if (!ASSERT_OK(err, "pthread_create")) + break; + } + + while (i) { + err = pthread_join(thread_id[--i], &ret); + if (ASSERT_OK(err, "pthread_join")) + ASSERT_EQ(ret, (void *)&prog_fd, "pthread_join"); + } + return 0; } diff --git a/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c b/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c index cd051d3901..8269cdee33 100644 --- a/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c +++ b/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c @@ -234,6 +234,177 @@ static void test_attach_api_syms(void) test_attach_api("/proc/self/exe", NULL, &opts); } +static void test_attach_api_fails(void) +{ + LIBBPF_OPTS(bpf_link_create_opts, opts); + const char *path = "/proc/self/exe"; + struct uprobe_multi *skel = NULL; + int prog_fd, link_fd = -1; + unsigned long offset = 0; + + skel = uprobe_multi__open_and_load(); + if (!ASSERT_OK_PTR(skel, "uprobe_multi__open_and_load")) + goto cleanup; + + prog_fd = bpf_program__fd(skel->progs.uprobe_extra); + + /* abnormal cnt */ + opts.uprobe_multi.path = path; + opts.uprobe_multi.offsets = &offset; + opts.uprobe_multi.cnt = INT_MAX; + link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts); + if (!ASSERT_ERR(link_fd, "link_fd")) + goto cleanup; + if (!ASSERT_EQ(link_fd, -E2BIG, "big cnt")) + goto cleanup; + + /* cnt is 0 */ + LIBBPF_OPTS_RESET(opts, + .uprobe_multi.path = path, + .uprobe_multi.offsets = (unsigned long *) &offset, + ); + + link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts); + if (!ASSERT_ERR(link_fd, "link_fd")) + goto cleanup; + if (!ASSERT_EQ(link_fd, -EINVAL, "cnt_is_zero")) + goto cleanup; + + /* negative offset */ + offset = -1; + opts.uprobe_multi.path = path; + opts.uprobe_multi.offsets = (unsigned long *) &offset; + opts.uprobe_multi.cnt = 1; + + link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts); + if (!ASSERT_ERR(link_fd, "link_fd")) + goto cleanup; + if (!ASSERT_EQ(link_fd, -EINVAL, "offset_is_negative")) + goto cleanup; + + /* offsets is NULL */ + LIBBPF_OPTS_RESET(opts, + .uprobe_multi.path = path, + .uprobe_multi.cnt = 1, + ); + + link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts); + if (!ASSERT_ERR(link_fd, "link_fd")) + goto cleanup; + if (!ASSERT_EQ(link_fd, -EINVAL, "offsets_is_null")) + goto cleanup; + + /* wrong offsets pointer */ + LIBBPF_OPTS_RESET(opts, + .uprobe_multi.path = path, + .uprobe_multi.offsets = (unsigned long *) 1, + .uprobe_multi.cnt = 1, + ); + + link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts); + if (!ASSERT_ERR(link_fd, "link_fd")) + goto cleanup; + if (!ASSERT_EQ(link_fd, -EFAULT, "offsets_is_wrong")) + goto cleanup; + + /* path is NULL */ + offset = 1; + LIBBPF_OPTS_RESET(opts, + .uprobe_multi.offsets = (unsigned long *) &offset, + .uprobe_multi.cnt = 1, + ); + + link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts); + if (!ASSERT_ERR(link_fd, "link_fd")) + goto cleanup; + if (!ASSERT_EQ(link_fd, -EINVAL, "path_is_null")) + goto cleanup; + + /* wrong path pointer */ + LIBBPF_OPTS_RESET(opts, + .uprobe_multi.path = (const char *) 1, + .uprobe_multi.offsets = (unsigned long *) &offset, + .uprobe_multi.cnt = 1, + ); + + link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts); + if (!ASSERT_ERR(link_fd, "link_fd")) + goto cleanup; + if (!ASSERT_EQ(link_fd, -EFAULT, "path_is_wrong")) + goto cleanup; + + /* wrong path type */ + LIBBPF_OPTS_RESET(opts, + .uprobe_multi.path = "/", + .uprobe_multi.offsets = (unsigned long *) &offset, + .uprobe_multi.cnt = 1, + ); + + link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts); + if (!ASSERT_ERR(link_fd, "link_fd")) + goto cleanup; + if (!ASSERT_EQ(link_fd, -EBADF, "path_is_wrong_type")) + goto cleanup; + + /* wrong cookies pointer */ + LIBBPF_OPTS_RESET(opts, + .uprobe_multi.path = path, + .uprobe_multi.offsets = (unsigned long *) &offset, + .uprobe_multi.cookies = (__u64 *) 1ULL, + .uprobe_multi.cnt = 1, + ); + + link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts); + if (!ASSERT_ERR(link_fd, "link_fd")) + goto cleanup; + if (!ASSERT_EQ(link_fd, -EFAULT, "cookies_is_wrong")) + goto cleanup; + + /* wrong ref_ctr_offsets pointer */ + LIBBPF_OPTS_RESET(opts, + .uprobe_multi.path = path, + .uprobe_multi.offsets = (unsigned long *) &offset, + .uprobe_multi.cookies = (__u64 *) &offset, + .uprobe_multi.ref_ctr_offsets = (unsigned long *) 1, + .uprobe_multi.cnt = 1, + ); + + link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts); + if (!ASSERT_ERR(link_fd, "link_fd")) + goto cleanup; + if (!ASSERT_EQ(link_fd, -EFAULT, "ref_ctr_offsets_is_wrong")) + goto cleanup; + + /* wrong flags */ + LIBBPF_OPTS_RESET(opts, + .uprobe_multi.flags = 1 << 31, + ); + + link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts); + if (!ASSERT_ERR(link_fd, "link_fd")) + goto cleanup; + if (!ASSERT_EQ(link_fd, -EINVAL, "wrong_flags")) + goto cleanup; + + /* wrong pid */ + LIBBPF_OPTS_RESET(opts, + .uprobe_multi.path = path, + .uprobe_multi.offsets = (unsigned long *) &offset, + .uprobe_multi.cnt = 1, + .uprobe_multi.pid = -2, + ); + + link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts); + if (!ASSERT_ERR(link_fd, "link_fd")) + goto cleanup; + ASSERT_EQ(link_fd, -ESRCH, "pid_is_wrong"); + +cleanup: + if (link_fd >= 0) + close(link_fd); + uprobe_multi__destroy(skel); +} + static void __test_link_api(struct child *child) { int prog_fd, link1_fd = -1, link2_fd = -1, link3_fd = -1, link4_fd = -1; @@ -249,7 +420,7 @@ static void __test_link_api(struct child *child) int link_extra_fd = -1; int err; - err = elf_resolve_syms_offsets(path, 3, syms, (unsigned long **) &offsets); + err = elf_resolve_syms_offsets(path, 3, syms, (unsigned long **) &offsets, STT_FUNC); if (!ASSERT_OK(err, "elf_resolve_syms_offsets")) return; @@ -311,7 +482,7 @@ cleanup: free(offsets); } -void test_link_api(void) +static void test_link_api(void) { struct child *child; @@ -412,4 +583,6 @@ void test_uprobe_multi_test(void) test_bench_attach_uprobe(); if (test__start_subtest("bench_usdt")) test_bench_attach_usdt(); + if (test__start_subtest("attach_api_fails")) + test_attach_api_fails(); } diff --git a/tools/testing/selftests/bpf/prog_tests/verifier.c b/tools/testing/selftests/bpf/prog_tests/verifier.c index 5cfa7a6316..d62c5bf00e 100644 --- a/tools/testing/selftests/bpf/prog_tests/verifier.c +++ b/tools/testing/selftests/bpf/prog_tests/verifier.c @@ -6,6 +6,7 @@ #include "verifier_and.skel.h" #include "verifier_array_access.skel.h" #include "verifier_basic_stack.skel.h" +#include "verifier_bitfield_write.skel.h" #include "verifier_bounds.skel.h" #include "verifier_bounds_deduction.skel.h" #include "verifier_bounds_deduction_non_const.skel.h" @@ -13,6 +14,7 @@ #include "verifier_bpf_get_stack.skel.h" #include "verifier_bswap.skel.h" #include "verifier_btf_ctx_access.skel.h" +#include "verifier_btf_unreliable_prog.skel.h" #include "verifier_cfg.skel.h" #include "verifier_cgroup_inv_retcode.skel.h" #include "verifier_cgroup_skb.skel.h" @@ -25,6 +27,7 @@ #include "verifier_direct_stack_access_wraparound.skel.h" #include "verifier_div0.skel.h" #include "verifier_div_overflow.skel.h" +#include "verifier_global_subprogs.skel.h" #include "verifier_gotol.skel.h" #include "verifier_helper_access_var_len.skel.h" #include "verifier_helper_packet_access.skel.h" @@ -115,6 +118,7 @@ static void run_tests_aux(const char *skel_name, void test_verifier_and(void) { RUN(verifier_and); } void test_verifier_basic_stack(void) { RUN(verifier_basic_stack); } +void test_verifier_bitfield_write(void) { RUN(verifier_bitfield_write); } void test_verifier_bounds(void) { RUN(verifier_bounds); } void test_verifier_bounds_deduction(void) { RUN(verifier_bounds_deduction); } void test_verifier_bounds_deduction_non_const(void) { RUN(verifier_bounds_deduction_non_const); } @@ -122,6 +126,7 @@ void test_verifier_bounds_mix_sign_unsign(void) { RUN(verifier_bounds_mix_sign_u void test_verifier_bpf_get_stack(void) { RUN(verifier_bpf_get_stack); } void test_verifier_bswap(void) { RUN(verifier_bswap); } void test_verifier_btf_ctx_access(void) { RUN(verifier_btf_ctx_access); } +void test_verifier_btf_unreliable_prog(void) { RUN(verifier_btf_unreliable_prog); } void test_verifier_cfg(void) { RUN(verifier_cfg); } void test_verifier_cgroup_inv_retcode(void) { RUN(verifier_cgroup_inv_retcode); } void test_verifier_cgroup_skb(void) { RUN(verifier_cgroup_skb); } @@ -134,6 +139,7 @@ void test_verifier_direct_packet_access(void) { RUN(verifier_direct_packet_acces void test_verifier_direct_stack_access_wraparound(void) { RUN(verifier_direct_stack_access_wraparound); } void test_verifier_div0(void) { RUN(verifier_div0); } void test_verifier_div_overflow(void) { RUN(verifier_div_overflow); } +void test_verifier_global_subprogs(void) { RUN(verifier_global_subprogs); } void test_verifier_gotol(void) { RUN(verifier_gotol); } void test_verifier_helper_access_var_len(void) { RUN(verifier_helper_access_var_len); } void test_verifier_helper_packet_access(void) { RUN(verifier_helper_packet_access); } diff --git a/tools/testing/selftests/bpf/prog_tests/verify_pkcs7_sig.c b/tools/testing/selftests/bpf/prog_tests/verify_pkcs7_sig.c index dd7f2bc700..ab0f02faa8 100644 --- a/tools/testing/selftests/bpf/prog_tests/verify_pkcs7_sig.c +++ b/tools/testing/selftests/bpf/prog_tests/verify_pkcs7_sig.c @@ -16,9 +16,12 @@ #include #include #include +#include +#include #include #include "test_verify_pkcs7_sig.skel.h" +#include "test_sig_in_xattr.skel.h" #define MAX_DATA_SIZE (1024 * 1024) #define MAX_SIG_SIZE 1024 @@ -26,6 +29,10 @@ #define VERIFY_USE_SECONDARY_KEYRING (1UL) #define VERIFY_USE_PLATFORM_KEYRING (2UL) +#ifndef SHA256_DIGEST_SIZE +#define SHA256_DIGEST_SIZE 32 +#endif + /* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */ #define MODULE_SIG_STRING "~Module signature appended~\n" @@ -254,7 +261,7 @@ out: return ret; } -void test_verify_pkcs7_sig(void) +static void test_verify_pkcs7_sig_from_map(void) { libbpf_print_fn_t old_print_cb; char tmp_dir_template[] = "/tmp/verify_sigXXXXXX"; @@ -400,3 +407,159 @@ close_prog: skel->bss->monitored_pid = 0; test_verify_pkcs7_sig__destroy(skel); } + +static int get_signature_size(const char *sig_path) +{ + struct stat st; + + if (stat(sig_path, &st) == -1) + return -1; + + return st.st_size; +} + +static int add_signature_to_xattr(const char *data_path, const char *sig_path) +{ + char sig[MAX_SIG_SIZE] = {0}; + int fd, size, ret; + + if (sig_path) { + fd = open(sig_path, O_RDONLY); + if (fd < 0) + return -1; + + size = read(fd, sig, MAX_SIG_SIZE); + close(fd); + if (size <= 0) + return -1; + } else { + /* no sig_path, just write 32 bytes of zeros */ + size = 32; + } + ret = setxattr(data_path, "user.sig", sig, size, 0); + if (!ASSERT_OK(ret, "setxattr")) + return -1; + + return 0; +} + +static int test_open_file(struct test_sig_in_xattr *skel, char *data_path, + pid_t pid, bool should_success, char *name) +{ + int ret; + + skel->bss->monitored_pid = pid; + ret = open(data_path, O_RDONLY); + close(ret); + skel->bss->monitored_pid = 0; + + if (should_success) { + if (!ASSERT_GE(ret, 0, name)) + return -1; + } else { + if (!ASSERT_LT(ret, 0, name)) + return -1; + } + return 0; +} + +static void test_pkcs7_sig_fsverity(void) +{ + char data_path[PATH_MAX]; + char sig_path[PATH_MAX]; + char tmp_dir_template[] = "/tmp/verify_sigXXXXXX"; + char *tmp_dir; + struct test_sig_in_xattr *skel = NULL; + pid_t pid; + int ret; + + tmp_dir = mkdtemp(tmp_dir_template); + if (!ASSERT_OK_PTR(tmp_dir, "mkdtemp")) + return; + + snprintf(data_path, PATH_MAX, "%s/data-file", tmp_dir); + snprintf(sig_path, PATH_MAX, "%s/sig-file", tmp_dir); + + ret = _run_setup_process(tmp_dir, "setup"); + if (!ASSERT_OK(ret, "_run_setup_process")) + goto out; + + ret = _run_setup_process(tmp_dir, "fsverity-create-sign"); + + if (ret) { + printf("%s: SKIP: fsverity [sign|enable] doesn't work.\n" + "To run this test, try enable CONFIG_FS_VERITY and enable FSVerity for the filesystem.\n", + __func__); + test__skip(); + goto out; + } + + skel = test_sig_in_xattr__open(); + if (!ASSERT_OK_PTR(skel, "test_sig_in_xattr__open")) + goto out; + ret = get_signature_size(sig_path); + if (!ASSERT_GT(ret, 0, "get_signature_size")) + goto out; + skel->bss->sig_size = ret; + skel->bss->user_keyring_serial = syscall(__NR_request_key, "keyring", + "ebpf_testing_keyring", NULL, + KEY_SPEC_SESSION_KEYRING); + memcpy(skel->bss->digest, "FSVerity", 8); + + ret = test_sig_in_xattr__load(skel); + if (!ASSERT_OK(ret, "test_sig_in_xattr__load")) + goto out; + + ret = test_sig_in_xattr__attach(skel); + if (!ASSERT_OK(ret, "test_sig_in_xattr__attach")) + goto out; + + pid = getpid(); + + /* Case 1: fsverity is not enabled, open should succeed */ + if (test_open_file(skel, data_path, pid, true, "open_1")) + goto out; + + /* Case 2: fsverity is enabled, xattr is missing, open should + * fail + */ + ret = _run_setup_process(tmp_dir, "fsverity-enable"); + if (!ASSERT_OK(ret, "fsverity-enable")) + goto out; + if (test_open_file(skel, data_path, pid, false, "open_2")) + goto out; + + /* Case 3: fsverity is enabled, xattr has valid signature, open + * should succeed + */ + ret = add_signature_to_xattr(data_path, sig_path); + if (!ASSERT_OK(ret, "add_signature_to_xattr_1")) + goto out; + + if (test_open_file(skel, data_path, pid, true, "open_3")) + goto out; + + /* Case 4: fsverity is enabled, xattr has invalid signature, open + * should fail + */ + ret = add_signature_to_xattr(data_path, NULL); + if (!ASSERT_OK(ret, "add_signature_to_xattr_2")) + goto out; + test_open_file(skel, data_path, pid, false, "open_4"); + +out: + _run_setup_process(tmp_dir, "cleanup"); + if (!skel) + return; + + skel->bss->monitored_pid = 0; + test_sig_in_xattr__destroy(skel); +} + +void test_verify_pkcs7_sig(void) +{ + if (test__start_subtest("pkcs7_sig_from_map")) + test_verify_pkcs7_sig_from_map(); + if (test__start_subtest("pkcs7_sig_fsverity")) + test_pkcs7_sig_fsverity(); +} diff --git a/tools/testing/selftests/bpf/prog_tests/vmlinux.c b/tools/testing/selftests/bpf/prog_tests/vmlinux.c index 72310cfc64..6fb2217d94 100644 --- a/tools/testing/selftests/bpf/prog_tests/vmlinux.c +++ b/tools/testing/selftests/bpf/prog_tests/vmlinux.c @@ -16,27 +16,27 @@ static void nsleep() void test_vmlinux(void) { - int duration = 0, err; + int err; struct test_vmlinux* skel; struct test_vmlinux__bss *bss; skel = test_vmlinux__open_and_load(); - if (CHECK(!skel, "skel_open", "failed to open skeleton\n")) + if (!ASSERT_OK_PTR(skel, "test_vmlinux__open_and_load")) return; bss = skel->bss; err = test_vmlinux__attach(skel); - if (CHECK(err, "skel_attach", "skeleton attach failed: %d\n", err)) + if (!ASSERT_OK(err, "test_vmlinux__attach")) goto cleanup; /* trigger everything */ nsleep(); - CHECK(!bss->tp_called, "tp", "not called\n"); - CHECK(!bss->raw_tp_called, "raw_tp", "not called\n"); - CHECK(!bss->tp_btf_called, "tp_btf", "not called\n"); - CHECK(!bss->kprobe_called, "kprobe", "not called\n"); - CHECK(!bss->fentry_called, "fentry", "not called\n"); + ASSERT_TRUE(bss->tp_called, "tp"); + ASSERT_TRUE(bss->raw_tp_called, "raw_tp"); + ASSERT_TRUE(bss->tp_btf_called, "tp_btf"); + ASSERT_TRUE(bss->kprobe_called, "kprobe"); + ASSERT_TRUE(bss->fentry_called, "fentry"); cleanup: test_vmlinux__destroy(skel); diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c b/tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c index ab4952b9fb..e6a783c7f5 100644 --- a/tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c +++ b/tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c @@ -77,8 +77,8 @@ void test_xdp_context_test_run(void) test_xdp_context_error(prog_fd, opts, 4, sizeof(__u32), sizeof(data), 0, 0, 0); - /* Meta data must be 32 bytes or smaller */ - test_xdp_context_error(prog_fd, opts, 0, 36, sizeof(data), 0, 0, 0); + /* Meta data must be 255 bytes or smaller */ + test_xdp_context_error(prog_fd, opts, 0, 256, sizeof(data), 0, 0, 0); /* Total size of data must match data_end - data_meta */ test_xdp_context_error(prog_fd, opts, 0, sizeof(__u32), diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_metadata.c b/tools/testing/selftests/bpf/prog_tests/xdp_metadata.c index 4439ba9392..05edcf32f5 100644 --- a/tools/testing/selftests/bpf/prog_tests/xdp_metadata.c +++ b/tools/testing/selftests/bpf/prog_tests/xdp_metadata.c @@ -20,7 +20,7 @@ #define UDP_PAYLOAD_BYTES 4 -#define AF_XDP_SOURCE_PORT 1234 +#define UDP_SOURCE_PORT 1234 #define AF_XDP_CONSUMER_PORT 8080 #define UMEM_NUM 16 @@ -33,6 +33,18 @@ #define RX_ADDR "10.0.0.2" #define PREFIX_LEN "8" #define FAMILY AF_INET +#define TX_NETNS_NAME "xdp_metadata_tx" +#define RX_NETNS_NAME "xdp_metadata_rx" +#define TX_MAC "00:00:00:00:00:01" +#define RX_MAC "00:00:00:00:00:02" + +#define VLAN_ID 59 +#define VLAN_PROTO "802.1Q" +#define VLAN_PID htons(ETH_P_8021Q) +#define TX_NAME_VLAN TX_NAME "." TO_STR(VLAN_ID) + +#define XDP_RSS_TYPE_L4 BIT(3) +#define VLAN_VID_MASK 0xfff struct xsk { void *umem_area; @@ -56,7 +68,8 @@ static int open_xsk(int ifindex, struct xsk *xsk) .fill_size = XSK_RING_PROD__DEFAULT_NUM_DESCS, .comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS, .frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE, - .flags = XDP_UMEM_UNALIGNED_CHUNK_FLAG, + .flags = XDP_UMEM_UNALIGNED_CHUNK_FLAG | XDP_UMEM_TX_SW_CSUM, + .tx_metadata_len = sizeof(struct xsk_tx_metadata), }; __u32 idx; u64 addr; @@ -138,6 +151,7 @@ static void ip_csum(struct iphdr *iph) static int generate_packet(struct xsk *xsk, __u16 dst_port) { + struct xsk_tx_metadata *meta; struct xdp_desc *tx_desc; struct udphdr *udph; struct ethhdr *eth; @@ -151,10 +165,14 @@ static int generate_packet(struct xsk *xsk, __u16 dst_port) return -1; tx_desc = xsk_ring_prod__tx_desc(&xsk->tx, idx); - tx_desc->addr = idx % (UMEM_NUM / 2) * UMEM_FRAME_SIZE; + tx_desc->addr = idx % (UMEM_NUM / 2) * UMEM_FRAME_SIZE + sizeof(struct xsk_tx_metadata); printf("%p: tx_desc[%u]->addr=%llx\n", xsk, idx, tx_desc->addr); data = xsk_umem__get_data(xsk->umem_area, tx_desc->addr); + meta = data - sizeof(struct xsk_tx_metadata); + memset(meta, 0, sizeof(*meta)); + meta->flags = XDP_TXMD_FLAGS_TIMESTAMP; + eth = data; iph = (void *)(eth + 1); udph = (void *)(iph + 1); @@ -175,14 +193,20 @@ static int generate_packet(struct xsk *xsk, __u16 dst_port) ASSERT_EQ(inet_pton(FAMILY, RX_ADDR, &iph->daddr), 1, "inet_pton(RX_ADDR)"); ip_csum(iph); - udph->source = htons(AF_XDP_SOURCE_PORT); + udph->source = htons(UDP_SOURCE_PORT); udph->dest = htons(dst_port); udph->len = htons(sizeof(*udph) + UDP_PAYLOAD_BYTES); - udph->check = 0; + udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, + ntohs(udph->len), IPPROTO_UDP, 0); memset(udph + 1, 0xAA, UDP_PAYLOAD_BYTES); + meta->flags |= XDP_TXMD_FLAGS_CHECKSUM; + meta->request.csum_start = sizeof(*eth) + sizeof(*iph); + meta->request.csum_offset = offsetof(struct udphdr, check); + tx_desc->len = sizeof(*eth) + sizeof(*iph) + sizeof(*udph) + UDP_PAYLOAD_BYTES; + tx_desc->options |= XDP_TX_METADATA; xsk_ring_prod__submit(&xsk->tx, 1); ret = sendto(xsk_socket__fd(xsk->socket), NULL, 0, MSG_DONTWAIT, NULL, 0); @@ -192,15 +216,47 @@ static int generate_packet(struct xsk *xsk, __u16 dst_port) return 0; } +static int generate_packet_inet(void) +{ + char udp_payload[UDP_PAYLOAD_BYTES]; + struct sockaddr_in rx_addr; + int sock_fd, err = 0; + + /* Build a packet */ + memset(udp_payload, 0xAA, UDP_PAYLOAD_BYTES); + rx_addr.sin_addr.s_addr = inet_addr(RX_ADDR); + rx_addr.sin_family = AF_INET; + rx_addr.sin_port = htons(AF_XDP_CONSUMER_PORT); + + sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (!ASSERT_GE(sock_fd, 0, "socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)")) + return sock_fd; + + err = sendto(sock_fd, udp_payload, UDP_PAYLOAD_BYTES, MSG_DONTWAIT, + (void *)&rx_addr, sizeof(rx_addr)); + ASSERT_GE(err, 0, "sendto"); + + close(sock_fd); + return err; +} + static void complete_tx(struct xsk *xsk) { - __u32 idx; + struct xsk_tx_metadata *meta; __u64 addr; + void *data; + __u32 idx; if (ASSERT_EQ(xsk_ring_cons__peek(&xsk->comp, 1, &idx), 1, "xsk_ring_cons__peek")) { addr = *xsk_ring_cons__comp_addr(&xsk->comp, idx); printf("%p: complete tx idx=%u addr=%llx\n", xsk, idx, addr); + + data = xsk_umem__get_data(xsk->umem_area, addr); + meta = data - sizeof(struct xsk_tx_metadata); + + ASSERT_NEQ(meta->completion.tx_timestamp, 0, "tx_timestamp"); + xsk_ring_cons__release(&xsk->comp, 1); } } @@ -216,11 +272,12 @@ static void refill_rx(struct xsk *xsk, __u64 addr) } } -static int verify_xsk_metadata(struct xsk *xsk) +static int verify_xsk_metadata(struct xsk *xsk, bool sent_from_af_xdp) { const struct xdp_desc *rx_desc; struct pollfd fds = {}; struct xdp_meta *meta; + struct udphdr *udph; struct ethhdr *eth; struct iphdr *iph; __u64 comp_addr; @@ -257,6 +314,7 @@ static int verify_xsk_metadata(struct xsk *xsk) ASSERT_EQ(eth->h_proto, htons(ETH_P_IP), "eth->h_proto"); iph = (void *)(eth + 1); ASSERT_EQ((int)iph->version, 4, "iph->version"); + udph = (void *)(iph + 1); /* custom metadata */ @@ -268,14 +326,42 @@ static int verify_xsk_metadata(struct xsk *xsk) if (!ASSERT_NEQ(meta->rx_hash, 0, "rx_hash")) return -1; + if (!sent_from_af_xdp) { + if (!ASSERT_NEQ(meta->rx_hash_type & XDP_RSS_TYPE_L4, 0, "rx_hash_type")) + return -1; + + if (!ASSERT_EQ(meta->rx_vlan_tci & VLAN_VID_MASK, VLAN_ID, "rx_vlan_tci")) + return -1; + + if (!ASSERT_EQ(meta->rx_vlan_proto, VLAN_PID, "rx_vlan_proto")) + return -1; + goto done; + } + ASSERT_EQ(meta->rx_hash_type, 0, "rx_hash_type"); + /* checksum offload */ + ASSERT_EQ(udph->check, htons(0x721c), "csum"); + +done: xsk_ring_cons__release(&xsk->rx, 1); refill_rx(xsk, comp_addr); return 0; } +static void switch_ns_to_rx(struct nstoken **tok) +{ + close_netns(*tok); + *tok = open_netns(RX_NETNS_NAME); +} + +static void switch_ns_to_tx(struct nstoken **tok) +{ + close_netns(*tok); + *tok = open_netns(TX_NETNS_NAME); +} + void test_xdp_metadata(void) { struct xdp_metadata2 *bpf_obj2 = NULL; @@ -293,27 +379,35 @@ void test_xdp_metadata(void) int sock_fd; int ret; - /* Setup new networking namespace, with a veth pair. */ + /* Setup new networking namespaces, with a veth pair. */ + SYS(out, "ip netns add " TX_NETNS_NAME); + SYS(out, "ip netns add " RX_NETNS_NAME); - SYS(out, "ip netns add xdp_metadata"); - tok = open_netns("xdp_metadata"); + tok = open_netns(TX_NETNS_NAME); SYS(out, "ip link add numtxqueues 1 numrxqueues 1 " TX_NAME " type veth peer " RX_NAME " numtxqueues 1 numrxqueues 1"); - SYS(out, "ip link set dev " TX_NAME " address 00:00:00:00:00:01"); - SYS(out, "ip link set dev " RX_NAME " address 00:00:00:00:00:02"); + SYS(out, "ip link set " RX_NAME " netns " RX_NETNS_NAME); + + SYS(out, "ip link set dev " TX_NAME " address " TX_MAC); SYS(out, "ip link set dev " TX_NAME " up"); + + SYS(out, "ip link add link " TX_NAME " " TX_NAME_VLAN + " type vlan proto " VLAN_PROTO " id " TO_STR(VLAN_ID)); + SYS(out, "ip link set dev " TX_NAME_VLAN " up"); + SYS(out, "ip addr add " TX_ADDR "/" PREFIX_LEN " dev " TX_NAME_VLAN); + + /* Avoid ARP calls */ + SYS(out, "ip -4 neigh add " RX_ADDR " lladdr " RX_MAC " dev " TX_NAME_VLAN); + + switch_ns_to_rx(&tok); + + SYS(out, "ip link set dev " RX_NAME " address " RX_MAC); SYS(out, "ip link set dev " RX_NAME " up"); - SYS(out, "ip addr add " TX_ADDR "/" PREFIX_LEN " dev " TX_NAME); SYS(out, "ip addr add " RX_ADDR "/" PREFIX_LEN " dev " RX_NAME); rx_ifindex = if_nametoindex(RX_NAME); - tx_ifindex = if_nametoindex(TX_NAME); - /* Setup separate AF_XDP for TX and RX interfaces. */ - - ret = open_xsk(tx_ifindex, &tx_xsk); - if (!ASSERT_OK(ret, "open_xsk(TX_NAME)")) - goto out; + /* Setup separate AF_XDP for RX interface. */ ret = open_xsk(rx_ifindex, &rx_xsk); if (!ASSERT_OK(ret, "open_xsk(RX_NAME)")) @@ -354,18 +448,38 @@ void test_xdp_metadata(void) if (!ASSERT_GE(ret, 0, "bpf_map_update_elem")) goto out; - /* Send packet destined to RX AF_XDP socket. */ + switch_ns_to_tx(&tok); + + /* Setup separate AF_XDP for TX interface nad send packet to the RX socket. */ + tx_ifindex = if_nametoindex(TX_NAME); + ret = open_xsk(tx_ifindex, &tx_xsk); + if (!ASSERT_OK(ret, "open_xsk(TX_NAME)")) + goto out; + if (!ASSERT_GE(generate_packet(&tx_xsk, AF_XDP_CONSUMER_PORT), 0, "generate AF_XDP_CONSUMER_PORT")) goto out; - /* Verify AF_XDP RX packet has proper metadata. */ - if (!ASSERT_GE(verify_xsk_metadata(&rx_xsk), 0, + switch_ns_to_rx(&tok); + + /* Verify packet sent from AF_XDP has proper metadata. */ + if (!ASSERT_GE(verify_xsk_metadata(&rx_xsk, true), 0, "verify_xsk_metadata")) goto out; + switch_ns_to_tx(&tok); complete_tx(&tx_xsk); + /* Now check metadata of packet, generated with network stack */ + if (!ASSERT_GE(generate_packet_inet(), 0, "generate UDP packet")) + goto out; + + switch_ns_to_rx(&tok); + + if (!ASSERT_GE(verify_xsk_metadata(&rx_xsk, false), 0, + "verify_xsk_metadata")) + goto out; + /* Make sure freplace correctly picks up original bound device * and doesn't crash. */ @@ -383,11 +497,15 @@ void test_xdp_metadata(void) if (!ASSERT_OK(xdp_metadata2__attach(bpf_obj2), "attach freplace")) goto out; + switch_ns_to_tx(&tok); + /* Send packet to trigger . */ if (!ASSERT_GE(generate_packet(&tx_xsk, AF_XDP_CONSUMER_PORT), 0, "generate freplace packet")) goto out; + switch_ns_to_rx(&tok); + while (!retries--) { if (bpf_obj2->bss->called) break; @@ -402,5 +520,6 @@ out: xdp_metadata__destroy(bpf_obj); if (tok) close_netns(tok); - SYS_NOFAIL("ip netns del xdp_metadata"); + SYS_NOFAIL("ip netns del " RX_NETNS_NAME); + SYS_NOFAIL("ip netns del " TX_NETNS_NAME); } diff --git a/tools/testing/selftests/bpf/progs/access_map_in_map.c b/tools/testing/selftests/bpf/progs/access_map_in_map.c new file mode 100644 index 0000000000..1126871c2e --- /dev/null +++ b/tools/testing/selftests/bpf/progs/access_map_in_map.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2023. Huawei Technologies Co., Ltd */ +#include +#include +#include + +#include "bpf_misc.h" + +struct inner_map_type { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(key_size, 4); + __uint(value_size, 4); + __uint(max_entries, 1); +} inner_map SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); + __type(key, int); + __type(value, int); + __uint(max_entries, 1); + __array(values, struct inner_map_type); +} outer_array_map SEC(".maps") = { + .values = { + [0] = &inner_map, + }, +}; + +struct { + __uint(type, BPF_MAP_TYPE_HASH_OF_MAPS); + __type(key, int); + __type(value, int); + __uint(max_entries, 1); + __array(values, struct inner_map_type); +} outer_htab_map SEC(".maps") = { + .values = { + [0] = &inner_map, + }, +}; + +char _license[] SEC("license") = "GPL"; + +int tgid = 0; + +static int acc_map_in_map(void *outer_map) +{ + int i, key, value = 0xdeadbeef; + void *inner_map; + + if ((bpf_get_current_pid_tgid() >> 32) != tgid) + return 0; + + /* Find nonexistent inner map */ + key = 1; + inner_map = bpf_map_lookup_elem(outer_map, &key); + if (inner_map) + return 0; + + /* Find the old inner map */ + key = 0; + inner_map = bpf_map_lookup_elem(outer_map, &key); + if (!inner_map) + return 0; + + /* Wait for the old inner map to be replaced */ + for (i = 0; i < 2048; i++) + bpf_map_update_elem(inner_map, &key, &value, 0); + + return 0; +} + +SEC("?kprobe/" SYS_PREFIX "sys_getpgid") +int access_map_in_array(void *ctx) +{ + return acc_map_in_map(&outer_array_map); +} + +SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") +int sleepable_access_map_in_array(void *ctx) +{ + return acc_map_in_map(&outer_array_map); +} + +SEC("?kprobe/" SYS_PREFIX "sys_getpgid") +int access_map_in_htab(void *ctx) +{ + return acc_map_in_map(&outer_htab_map); +} + +SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") +int sleepable_access_map_in_htab(void *ctx) +{ + return acc_map_in_map(&outer_htab_map); +} diff --git a/tools/testing/selftests/bpf/progs/bpf_iter_bpf_percpu_hash_map.c b/tools/testing/selftests/bpf/progs/bpf_iter_bpf_percpu_hash_map.c index feaaa2b89c..5014a17d6c 100644 --- a/tools/testing/selftests/bpf/progs/bpf_iter_bpf_percpu_hash_map.c +++ b/tools/testing/selftests/bpf/progs/bpf_iter_bpf_percpu_hash_map.c @@ -20,7 +20,7 @@ struct { } hashmap1 SEC(".maps"); /* will set before prog run */ -volatile const __u32 num_cpus = 0; +volatile const __s32 num_cpus = 0; /* will collect results during prog run */ __u32 key_sum_a = 0, key_sum_b = 0, key_sum_c = 0; diff --git a/tools/testing/selftests/bpf/progs/bpf_iter_task_vmas.c b/tools/testing/selftests/bpf/progs/bpf_iter_task_vmas.c index dd923dc637..423b39e60b 100644 --- a/tools/testing/selftests/bpf/progs/bpf_iter_task_vmas.c +++ b/tools/testing/selftests/bpf/progs/bpf_iter_task_vmas.c @@ -35,7 +35,7 @@ SEC("iter/task_vma") int proc_maps(struct bpf_iter__task_vma *ctx) return 0; file = vma->vm_file; - if (task->tgid != pid) { + if (task->tgid != (pid_t)pid) { if (one_task) one_task_error = 1; return 0; diff --git a/tools/testing/selftests/bpf/progs/bpf_iter_tasks.c b/tools/testing/selftests/bpf/progs/bpf_iter_tasks.c index 96131b9a1c..6cbb3393f2 100644 --- a/tools/testing/selftests/bpf/progs/bpf_iter_tasks.c +++ b/tools/testing/selftests/bpf/progs/bpf_iter_tasks.c @@ -22,7 +22,7 @@ int dump_task(struct bpf_iter__task *ctx) return 0; } - if (task->pid != tid) + if (task->pid != (pid_t)tid) num_unknown_tid++; else num_known_tid++; diff --git a/tools/testing/selftests/bpf/progs/bpf_iter_test_kern4.c b/tools/testing/selftests/bpf/progs/bpf_iter_test_kern4.c index 400fdf8d62..dbf61c44ac 100644 --- a/tools/testing/selftests/bpf/progs/bpf_iter_test_kern4.c +++ b/tools/testing/selftests/bpf/progs/bpf_iter_test_kern4.c @@ -45,7 +45,7 @@ int dump_bpf_map(struct bpf_iter__bpf_map *ctx) } /* fill seq_file buffer */ - for (i = 0; i < print_len; i++) + for (i = 0; i < (int)print_len; i++) bpf_seq_write(seq, &seq_num, sizeof(seq_num)); return ret; diff --git a/tools/testing/selftests/bpf/progs/bpf_misc.h b/tools/testing/selftests/bpf/progs/bpf_misc.h index 799fff4995..2fd59970c4 100644 --- a/tools/testing/selftests/bpf/progs/bpf_misc.h +++ b/tools/testing/selftests/bpf/progs/bpf_misc.h @@ -71,6 +71,7 @@ #define __retval_unpriv(val) __attribute__((btf_decl_tag("comment:test_retval_unpriv="#val))) #define __auxiliary __attribute__((btf_decl_tag("comment:test_auxiliary"))) #define __auxiliary_unpriv __attribute__((btf_decl_tag("comment:test_auxiliary_unpriv"))) +#define __btf_path(path) __attribute__((btf_decl_tag("comment:test_btf_path=" path))) /* Convenience macro for use with 'asm volatile' blocks */ #define __naked __attribute__((naked)) diff --git a/tools/testing/selftests/bpf/progs/bpf_tracing_net.h b/tools/testing/selftests/bpf/progs/bpf_tracing_net.h index 0b793a1027..e8bd4b7b5e 100644 --- a/tools/testing/selftests/bpf/progs/bpf_tracing_net.h +++ b/tools/testing/selftests/bpf/progs/bpf_tracing_net.h @@ -26,6 +26,7 @@ #define IPV6_AUTOFLOWLABEL 70 #define TC_ACT_UNSPEC (-1) +#define TC_ACT_OK 0 #define TC_ACT_SHOT 2 #define SOL_TCP 6 @@ -71,6 +72,8 @@ #define inet_rcv_saddr sk.__sk_common.skc_rcv_saddr #define inet_dport sk.__sk_common.skc_dport +#define udp_portaddr_hash inet.sk.__sk_common.skc_u16hashes[1] + #define ir_loc_addr req.__req_common.skc_rcv_saddr #define ir_num req.__req_common.skc_num #define ir_rmt_addr req.__req_common.skc_daddr @@ -84,6 +87,7 @@ #define sk_rmem_alloc sk_backlog.rmem_alloc #define sk_refcnt __sk_common.skc_refcnt #define sk_state __sk_common.skc_state +#define sk_net __sk_common.skc_net #define sk_v6_daddr __sk_common.skc_v6_daddr #define sk_v6_rcv_saddr __sk_common.skc_v6_rcv_saddr #define sk_flags __sk_common.skc_flags diff --git a/tools/testing/selftests/bpf/progs/cgroup_getset_retval_setsockopt.c b/tools/testing/selftests/bpf/progs/cgroup_getset_retval_setsockopt.c index b7fa8804e1..45a0e9f492 100644 --- a/tools/testing/selftests/bpf/progs/cgroup_getset_retval_setsockopt.c +++ b/tools/testing/selftests/bpf/progs/cgroup_getset_retval_setsockopt.c @@ -11,7 +11,7 @@ __u32 invocations = 0; __u32 assertion_error = 0; __u32 retval_value = 0; -__u32 page_size = 0; +__s32 page_size = 0; SEC("cgroup/setsockopt") int get_retval(struct bpf_sockopt *ctx) diff --git a/tools/testing/selftests/bpf/progs/cgrp_kfunc_failure.c b/tools/testing/selftests/bpf/progs/cgrp_kfunc_failure.c index 0fa564a5cc..9fe9c4a4e8 100644 --- a/tools/testing/selftests/bpf/progs/cgrp_kfunc_failure.c +++ b/tools/testing/selftests/bpf/progs/cgrp_kfunc_failure.c @@ -78,7 +78,7 @@ int BPF_PROG(cgrp_kfunc_acquire_fp, struct cgroup *cgrp, const char *path) } SEC("kretprobe/cgroup_destroy_locked") -__failure __msg("reg type unsupported for arg#0 function") +__failure __msg("calling kernel function bpf_cgroup_acquire is not allowed") int BPF_PROG(cgrp_kfunc_acquire_unsafe_kretprobe, struct cgroup *cgrp) { struct cgroup *acquired; diff --git a/tools/testing/selftests/bpf/progs/cgrp_ls_recursion.c b/tools/testing/selftests/bpf/progs/cgrp_ls_recursion.c index a043d8fefd..610c2427fd 100644 --- a/tools/testing/selftests/bpf/progs/cgrp_ls_recursion.c +++ b/tools/testing/selftests/bpf/progs/cgrp_ls_recursion.c @@ -21,50 +21,100 @@ struct { __type(value, long); } map_b SEC(".maps"); +int target_hid = 0; +bool is_cgroup1 = 0; + +struct cgroup *bpf_task_get_cgroup1(struct task_struct *task, int hierarchy_id) __ksym; +void bpf_cgroup_release(struct cgroup *cgrp) __ksym; + +static void __on_lookup(struct cgroup *cgrp) +{ + bpf_cgrp_storage_delete(&map_a, cgrp); + bpf_cgrp_storage_delete(&map_b, cgrp); +} + SEC("fentry/bpf_local_storage_lookup") int BPF_PROG(on_lookup) { struct task_struct *task = bpf_get_current_task_btf(); + struct cgroup *cgrp; + + if (is_cgroup1) { + cgrp = bpf_task_get_cgroup1(task, target_hid); + if (!cgrp) + return 0; - bpf_cgrp_storage_delete(&map_a, task->cgroups->dfl_cgrp); - bpf_cgrp_storage_delete(&map_b, task->cgroups->dfl_cgrp); + __on_lookup(cgrp); + bpf_cgroup_release(cgrp); + return 0; + } + + __on_lookup(task->cgroups->dfl_cgrp); return 0; } -SEC("fentry/bpf_local_storage_update") -int BPF_PROG(on_update) +static void __on_update(struct cgroup *cgrp) { - struct task_struct *task = bpf_get_current_task_btf(); long *ptr; - ptr = bpf_cgrp_storage_get(&map_a, task->cgroups->dfl_cgrp, 0, - BPF_LOCAL_STORAGE_GET_F_CREATE); + ptr = bpf_cgrp_storage_get(&map_a, cgrp, 0, BPF_LOCAL_STORAGE_GET_F_CREATE); if (ptr) *ptr += 1; - ptr = bpf_cgrp_storage_get(&map_b, task->cgroups->dfl_cgrp, 0, - BPF_LOCAL_STORAGE_GET_F_CREATE); + ptr = bpf_cgrp_storage_get(&map_b, cgrp, 0, BPF_LOCAL_STORAGE_GET_F_CREATE); if (ptr) *ptr += 1; +} +SEC("fentry/bpf_local_storage_update") +int BPF_PROG(on_update) +{ + struct task_struct *task = bpf_get_current_task_btf(); + struct cgroup *cgrp; + + if (is_cgroup1) { + cgrp = bpf_task_get_cgroup1(task, target_hid); + if (!cgrp) + return 0; + + __on_update(cgrp); + bpf_cgroup_release(cgrp); + return 0; + } + + __on_update(task->cgroups->dfl_cgrp); return 0; } -SEC("tp_btf/sys_enter") -int BPF_PROG(on_enter, struct pt_regs *regs, long id) +static void __on_enter(struct pt_regs *regs, long id, struct cgroup *cgrp) { - struct task_struct *task; long *ptr; - task = bpf_get_current_task_btf(); - ptr = bpf_cgrp_storage_get(&map_a, task->cgroups->dfl_cgrp, 0, - BPF_LOCAL_STORAGE_GET_F_CREATE); + ptr = bpf_cgrp_storage_get(&map_a, cgrp, 0, BPF_LOCAL_STORAGE_GET_F_CREATE); if (ptr) *ptr = 200; - ptr = bpf_cgrp_storage_get(&map_b, task->cgroups->dfl_cgrp, 0, - BPF_LOCAL_STORAGE_GET_F_CREATE); + ptr = bpf_cgrp_storage_get(&map_b, cgrp, 0, BPF_LOCAL_STORAGE_GET_F_CREATE); if (ptr) *ptr = 100; +} + +SEC("tp_btf/sys_enter") +int BPF_PROG(on_enter, struct pt_regs *regs, long id) +{ + struct task_struct *task = bpf_get_current_task_btf(); + struct cgroup *cgrp; + + if (is_cgroup1) { + cgrp = bpf_task_get_cgroup1(task, target_hid); + if (!cgrp) + return 0; + + __on_enter(regs, id, cgrp); + bpf_cgroup_release(cgrp); + return 0; + } + + __on_enter(regs, id, task->cgroups->dfl_cgrp); return 0; } diff --git a/tools/testing/selftests/bpf/progs/cgrp_ls_sleepable.c b/tools/testing/selftests/bpf/progs/cgrp_ls_sleepable.c index 4c7844e1db..5e282c16ea 100644 --- a/tools/testing/selftests/bpf/progs/cgrp_ls_sleepable.c +++ b/tools/testing/selftests/bpf/progs/cgrp_ls_sleepable.c @@ -15,9 +15,13 @@ struct { __type(value, long); } map_a SEC(".maps"); -__u32 target_pid; +__s32 target_pid; __u64 cgroup_id; +int target_hid; +bool is_cgroup1; +struct cgroup *bpf_task_get_cgroup1(struct task_struct *task, int hierarchy_id) __ksym; +void bpf_cgroup_release(struct cgroup *cgrp) __ksym; void bpf_rcu_read_lock(void) __ksym; void bpf_rcu_read_unlock(void) __ksym; @@ -37,23 +41,50 @@ int cgroup_iter(struct bpf_iter__cgroup *ctx) return 0; } +static void __no_rcu_lock(struct cgroup *cgrp) +{ + long *ptr; + + /* Note that trace rcu is held in sleepable prog, so we can use + * bpf_cgrp_storage_get() in sleepable prog. + */ + ptr = bpf_cgrp_storage_get(&map_a, cgrp, 0, + BPF_LOCAL_STORAGE_GET_F_CREATE); + if (ptr) + cgroup_id = cgrp->kn->id; +} + SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") -int no_rcu_lock(void *ctx) +int cgrp1_no_rcu_lock(void *ctx) { struct task_struct *task; struct cgroup *cgrp; - long *ptr; + + task = bpf_get_current_task_btf(); + if (task->pid != target_pid) + return 0; + + /* bpf_task_get_cgroup1 can work in sleepable prog */ + cgrp = bpf_task_get_cgroup1(task, target_hid); + if (!cgrp) + return 0; + + __no_rcu_lock(cgrp); + bpf_cgroup_release(cgrp); + return 0; +} + +SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") +int no_rcu_lock(void *ctx) +{ + struct task_struct *task; task = bpf_get_current_task_btf(); if (task->pid != target_pid) return 0; /* task->cgroups is untrusted in sleepable prog outside of RCU CS */ - cgrp = task->cgroups->dfl_cgrp; - ptr = bpf_cgrp_storage_get(&map_a, cgrp, 0, - BPF_LOCAL_STORAGE_GET_F_CREATE); - if (ptr) - cgroup_id = cgrp->kn->id; + __no_rcu_lock(task->cgroups->dfl_cgrp); return 0; } @@ -68,6 +99,22 @@ int yes_rcu_lock(void *ctx) if (task->pid != target_pid) return 0; + if (is_cgroup1) { + bpf_rcu_read_lock(); + cgrp = bpf_task_get_cgroup1(task, target_hid); + if (!cgrp) { + bpf_rcu_read_unlock(); + return 0; + } + + ptr = bpf_cgrp_storage_get(&map_a, cgrp, 0, BPF_LOCAL_STORAGE_GET_F_CREATE); + if (ptr) + cgroup_id = cgrp->kn->id; + bpf_cgroup_release(cgrp); + bpf_rcu_read_unlock(); + return 0; + } + bpf_rcu_read_lock(); cgrp = task->cgroups->dfl_cgrp; /* cgrp is trusted under RCU CS */ diff --git a/tools/testing/selftests/bpf/progs/cgrp_ls_tp_btf.c b/tools/testing/selftests/bpf/progs/cgrp_ls_tp_btf.c index 9ebb8e2fe5..1c348f000f 100644 --- a/tools/testing/selftests/bpf/progs/cgrp_ls_tp_btf.c +++ b/tools/testing/selftests/bpf/progs/cgrp_ls_tp_btf.c @@ -27,62 +27,100 @@ pid_t target_pid = 0; int mismatch_cnt = 0; int enter_cnt = 0; int exit_cnt = 0; +int target_hid = 0; +bool is_cgroup1 = 0; -SEC("tp_btf/sys_enter") -int BPF_PROG(on_enter, struct pt_regs *regs, long id) +struct cgroup *bpf_task_get_cgroup1(struct task_struct *task, int hierarchy_id) __ksym; +void bpf_cgroup_release(struct cgroup *cgrp) __ksym; + +static void __on_enter(struct pt_regs *regs, long id, struct cgroup *cgrp) { - struct task_struct *task; long *ptr; int err; - task = bpf_get_current_task_btf(); - if (task->pid != target_pid) - return 0; - /* populate value 0 */ - ptr = bpf_cgrp_storage_get(&map_a, task->cgroups->dfl_cgrp, 0, + ptr = bpf_cgrp_storage_get(&map_a, cgrp, 0, BPF_LOCAL_STORAGE_GET_F_CREATE); if (!ptr) - return 0; + return; /* delete value 0 */ - err = bpf_cgrp_storage_delete(&map_a, task->cgroups->dfl_cgrp); + err = bpf_cgrp_storage_delete(&map_a, cgrp); if (err) - return 0; + return; /* value is not available */ - ptr = bpf_cgrp_storage_get(&map_a, task->cgroups->dfl_cgrp, 0, 0); + ptr = bpf_cgrp_storage_get(&map_a, cgrp, 0, 0); if (ptr) - return 0; + return; /* re-populate the value */ - ptr = bpf_cgrp_storage_get(&map_a, task->cgroups->dfl_cgrp, 0, + ptr = bpf_cgrp_storage_get(&map_a, cgrp, 0, BPF_LOCAL_STORAGE_GET_F_CREATE); if (!ptr) - return 0; + return; __sync_fetch_and_add(&enter_cnt, 1); *ptr = MAGIC_VALUE + enter_cnt; - - return 0; } -SEC("tp_btf/sys_exit") -int BPF_PROG(on_exit, struct pt_regs *regs, long id) +SEC("tp_btf/sys_enter") +int BPF_PROG(on_enter, struct pt_regs *regs, long id) { struct task_struct *task; - long *ptr; + struct cgroup *cgrp; task = bpf_get_current_task_btf(); if (task->pid != target_pid) return 0; - ptr = bpf_cgrp_storage_get(&map_a, task->cgroups->dfl_cgrp, 0, + if (is_cgroup1) { + cgrp = bpf_task_get_cgroup1(task, target_hid); + if (!cgrp) + return 0; + + __on_enter(regs, id, cgrp); + bpf_cgroup_release(cgrp); + return 0; + } + + __on_enter(regs, id, task->cgroups->dfl_cgrp); + return 0; +} + +static void __on_exit(struct pt_regs *regs, long id, struct cgroup *cgrp) +{ + long *ptr; + + ptr = bpf_cgrp_storage_get(&map_a, cgrp, 0, BPF_LOCAL_STORAGE_GET_F_CREATE); if (!ptr) - return 0; + return; __sync_fetch_and_add(&exit_cnt, 1); if (*ptr != MAGIC_VALUE + exit_cnt) __sync_fetch_and_add(&mismatch_cnt, 1); +} + +SEC("tp_btf/sys_exit") +int BPF_PROG(on_exit, struct pt_regs *regs, long id) +{ + struct task_struct *task; + struct cgroup *cgrp; + + task = bpf_get_current_task_btf(); + if (task->pid != target_pid) + return 0; + + if (is_cgroup1) { + cgrp = bpf_task_get_cgroup1(task, target_hid); + if (!cgrp) + return 0; + + __on_exit(regs, id, cgrp); + bpf_cgroup_release(cgrp); + return 0; + } + + __on_exit(regs, id, task->cgroups->dfl_cgrp); return 0; } diff --git a/tools/testing/selftests/bpf/progs/cpumask_common.h b/tools/testing/selftests/bpf/progs/cpumask_common.h index b15c588ace..0cd4aebb97 100644 --- a/tools/testing/selftests/bpf/progs/cpumask_common.h +++ b/tools/testing/selftests/bpf/progs/cpumask_common.h @@ -54,6 +54,7 @@ bool bpf_cpumask_full(const struct cpumask *cpumask) __ksym; void bpf_cpumask_copy(struct bpf_cpumask *dst, const struct cpumask *src) __ksym; u32 bpf_cpumask_any_distribute(const struct cpumask *src) __ksym; u32 bpf_cpumask_any_and_distribute(const struct cpumask *src1, const struct cpumask *src2) __ksym; +u32 bpf_cpumask_weight(const struct cpumask *cpumask) __ksym; void bpf_rcu_read_lock(void) __ksym; void bpf_rcu_read_unlock(void) __ksym; diff --git a/tools/testing/selftests/bpf/progs/cpumask_success.c b/tools/testing/selftests/bpf/progs/cpumask_success.c index 674a63424d..7a1e64c6c0 100644 --- a/tools/testing/selftests/bpf/progs/cpumask_success.c +++ b/tools/testing/selftests/bpf/progs/cpumask_success.c @@ -332,7 +332,7 @@ SEC("tp_btf/task_newtask") int BPF_PROG(test_copy_any_anyand, struct task_struct *task, u64 clone_flags) { struct bpf_cpumask *mask1, *mask2, *dst1, *dst2; - u32 cpu; + int cpu; if (!is_test_task()) return 0; @@ -460,6 +460,49 @@ int BPF_PROG(test_global_mask_rcu, struct task_struct *task, u64 clone_flags) return 0; } +SEC("tp_btf/task_newtask") +int BPF_PROG(test_cpumask_weight, struct task_struct *task, u64 clone_flags) +{ + struct bpf_cpumask *local; + + if (!is_test_task()) + return 0; + + local = create_cpumask(); + if (!local) + return 0; + + if (bpf_cpumask_weight(cast(local)) != 0) { + err = 3; + goto out; + } + + bpf_cpumask_set_cpu(0, local); + if (bpf_cpumask_weight(cast(local)) != 1) { + err = 4; + goto out; + } + + /* + * Make sure that adding additional CPUs changes the weight. Test to + * see whether the CPU was set to account for running on UP machines. + */ + bpf_cpumask_set_cpu(1, local); + if (bpf_cpumask_test_cpu(1, cast(local)) && bpf_cpumask_weight(cast(local)) != 2) { + err = 5; + goto out; + } + + bpf_cpumask_clear(local); + if (bpf_cpumask_weight(cast(local)) != 0) { + err = 6; + goto out; + } +out: + bpf_cpumask_release(local); + return 0; +} + SEC("tp_btf/task_newtask") __success int BPF_PROG(test_refcount_null_tracking, struct task_struct *task, u64 clone_flags) diff --git a/tools/testing/selftests/bpf/progs/exceptions.c b/tools/testing/selftests/bpf/progs/exceptions.c index 2811ee842b..f09cd14d8e 100644 --- a/tools/testing/selftests/bpf/progs/exceptions.c +++ b/tools/testing/selftests/bpf/progs/exceptions.c @@ -210,7 +210,7 @@ __noinline int assert_zero_gfunc(u64 c) { volatile u64 cookie = c; - bpf_assert_eq(cookie, 0); + bpf_assert(bpf_cmp_unlikely(cookie, ==, 0)); return 0; } @@ -218,7 +218,7 @@ __noinline int assert_neg_gfunc(s64 c) { volatile s64 cookie = c; - bpf_assert_lt(cookie, 0); + bpf_assert(bpf_cmp_unlikely(cookie, <, 0)); return 0; } @@ -226,7 +226,7 @@ __noinline int assert_pos_gfunc(s64 c) { volatile s64 cookie = c; - bpf_assert_gt(cookie, 0); + bpf_assert(bpf_cmp_unlikely(cookie, >, 0)); return 0; } @@ -234,7 +234,7 @@ __noinline int assert_negeq_gfunc(s64 c) { volatile s64 cookie = c; - bpf_assert_le(cookie, -1); + bpf_assert(bpf_cmp_unlikely(cookie, <=, -1)); return 0; } @@ -242,7 +242,7 @@ __noinline int assert_poseq_gfunc(s64 c) { volatile s64 cookie = c; - bpf_assert_ge(cookie, 1); + bpf_assert(bpf_cmp_unlikely(cookie, >=, 1)); return 0; } @@ -258,7 +258,7 @@ __noinline int assert_zero_gfunc_with(u64 c) { volatile u64 cookie = c; - bpf_assert_eq_with(cookie, 0, cookie + 100); + bpf_assert_with(bpf_cmp_unlikely(cookie, ==, 0), cookie + 100); return 0; } @@ -266,7 +266,7 @@ __noinline int assert_neg_gfunc_with(s64 c) { volatile s64 cookie = c; - bpf_assert_lt_with(cookie, 0, cookie + 100); + bpf_assert_with(bpf_cmp_unlikely(cookie, <, 0), cookie + 100); return 0; } @@ -274,7 +274,7 @@ __noinline int assert_pos_gfunc_with(s64 c) { volatile s64 cookie = c; - bpf_assert_gt_with(cookie, 0, cookie + 100); + bpf_assert_with(bpf_cmp_unlikely(cookie, >, 0), cookie + 100); return 0; } @@ -282,7 +282,7 @@ __noinline int assert_negeq_gfunc_with(s64 c) { volatile s64 cookie = c; - bpf_assert_le_with(cookie, -1, cookie + 100); + bpf_assert_with(bpf_cmp_unlikely(cookie, <=, -1), cookie + 100); return 0; } @@ -290,7 +290,7 @@ __noinline int assert_poseq_gfunc_with(s64 c) { volatile s64 cookie = c; - bpf_assert_ge_with(cookie, 1, cookie + 100); + bpf_assert_with(bpf_cmp_unlikely(cookie, >=, 1), cookie + 100); return 0; } diff --git a/tools/testing/selftests/bpf/progs/exceptions_assert.c b/tools/testing/selftests/bpf/progs/exceptions_assert.c index e1e5c54a6a..5e0a1ca96d 100644 --- a/tools/testing/selftests/bpf/progs/exceptions_assert.c +++ b/tools/testing/selftests/bpf/progs/exceptions_assert.c @@ -11,55 +11,55 @@ #define check_assert(type, op, name, value) \ SEC("?tc") \ __log_level(2) __failure \ - int check_assert_##op##_##name(void *ctx) \ + int check_assert_##name(void *ctx) \ { \ type num = bpf_ktime_get_ns(); \ - bpf_assert_##op(num, value); \ + bpf_assert(bpf_cmp_unlikely(num, op, value)); \ return *(u64 *)num; \ } -__msg(": R0_w=-2147483648 R10=fp0") -check_assert(s64, eq, int_min, INT_MIN); -__msg(": R0_w=2147483647 R10=fp0") -check_assert(s64, eq, int_max, INT_MAX); -__msg(": R0_w=0 R10=fp0") -check_assert(s64, eq, zero, 0); -__msg(": R0_w=-9223372036854775808 R1_w=-9223372036854775808 R10=fp0") -check_assert(s64, eq, llong_min, LLONG_MIN); -__msg(": R0_w=9223372036854775807 R1_w=9223372036854775807 R10=fp0") -check_assert(s64, eq, llong_max, LLONG_MAX); - -__msg(": R0_w=scalar(smax=2147483646) R10=fp0") -check_assert(s64, lt, pos, INT_MAX); -__msg(": R0_w=scalar(smax=-1,umin=9223372036854775808,var_off=(0x8000000000000000; 0x7fffffffffffffff))") -check_assert(s64, lt, zero, 0); -__msg(": R0_w=scalar(smax=-2147483649,umin=9223372036854775808,umax=18446744071562067967,var_off=(0x8000000000000000; 0x7fffffffffffffff))") -check_assert(s64, lt, neg, INT_MIN); - -__msg(": R0_w=scalar(smax=2147483647) R10=fp0") -check_assert(s64, le, pos, INT_MAX); -__msg(": R0_w=scalar(smax=0) R10=fp0") -check_assert(s64, le, zero, 0); -__msg(": R0_w=scalar(smax=-2147483648,umin=9223372036854775808,umax=18446744071562067968,var_off=(0x8000000000000000; 0x7fffffffffffffff))") -check_assert(s64, le, neg, INT_MIN); - -__msg(": R0_w=scalar(smin=umin=2147483648,umax=9223372036854775807,var_off=(0x0; 0x7fffffffffffffff))") -check_assert(s64, gt, pos, INT_MAX); -__msg(": R0_w=scalar(smin=umin=1,umax=9223372036854775807,var_off=(0x0; 0x7fffffffffffffff))") -check_assert(s64, gt, zero, 0); -__msg(": R0_w=scalar(smin=-2147483647) R10=fp0") -check_assert(s64, gt, neg, INT_MIN); - -__msg(": R0_w=scalar(smin=umin=2147483647,umax=9223372036854775807,var_off=(0x0; 0x7fffffffffffffff))") -check_assert(s64, ge, pos, INT_MAX); -__msg(": R0_w=scalar(smin=0,umax=9223372036854775807,var_off=(0x0; 0x7fffffffffffffff)) R10=fp0") -check_assert(s64, ge, zero, 0); -__msg(": R0_w=scalar(smin=-2147483648) R10=fp0") -check_assert(s64, ge, neg, INT_MIN); +__msg(": R0_w=0xffffffff80000000") +check_assert(s64, ==, eq_int_min, INT_MIN); +__msg(": R0_w=0x7fffffff") +check_assert(s64, ==, eq_int_max, INT_MAX); +__msg(": R0_w=0") +check_assert(s64, ==, eq_zero, 0); +__msg(": R0_w=0x8000000000000000 R1_w=0x8000000000000000") +check_assert(s64, ==, eq_llong_min, LLONG_MIN); +__msg(": R0_w=0x7fffffffffffffff R1_w=0x7fffffffffffffff") +check_assert(s64, ==, eq_llong_max, LLONG_MAX); + +__msg(": R0_w=scalar(id=1,smax=0x7ffffffe)") +check_assert(s64, <, lt_pos, INT_MAX); +__msg(": R0_w=scalar(id=1,smax=-1,umin=0x8000000000000000,var_off=(0x8000000000000000; 0x7fffffffffffffff))") +check_assert(s64, <, lt_zero, 0); +__msg(": R0_w=scalar(id=1,smax=0xffffffff7fffffff") +check_assert(s64, <, lt_neg, INT_MIN); + +__msg(": R0_w=scalar(id=1,smax=0x7fffffff)") +check_assert(s64, <=, le_pos, INT_MAX); +__msg(": R0_w=scalar(id=1,smax=0)") +check_assert(s64, <=, le_zero, 0); +__msg(": R0_w=scalar(id=1,smax=0xffffffff80000000") +check_assert(s64, <=, le_neg, INT_MIN); + +__msg(": R0_w=scalar(id=1,smin=umin=0x80000000,umax=0x7fffffffffffffff,var_off=(0x0; 0x7fffffffffffffff))") +check_assert(s64, >, gt_pos, INT_MAX); +__msg(": R0_w=scalar(id=1,smin=umin=1,umax=0x7fffffffffffffff,var_off=(0x0; 0x7fffffffffffffff))") +check_assert(s64, >, gt_zero, 0); +__msg(": R0_w=scalar(id=1,smin=0xffffffff80000001") +check_assert(s64, >, gt_neg, INT_MIN); + +__msg(": R0_w=scalar(id=1,smin=umin=0x7fffffff,umax=0x7fffffffffffffff,var_off=(0x0; 0x7fffffffffffffff))") +check_assert(s64, >=, ge_pos, INT_MAX); +__msg(": R0_w=scalar(id=1,smin=0,umax=0x7fffffffffffffff,var_off=(0x0; 0x7fffffffffffffff))") +check_assert(s64, >=, ge_zero, 0); +__msg(": R0_w=scalar(id=1,smin=0xffffffff80000000") +check_assert(s64, >=, ge_neg, INT_MIN); SEC("?tc") __log_level(2) __failure -__msg(": R0=0 R1=ctx(off=0,imm=0) R2=scalar(smin=smin32=-2147483646,smax=smax32=2147483645) R10=fp0") +__msg(": R0=0 R1=ctx() R2=scalar(smin=0xffffffff80000002,smax=smax32=0x7ffffffd,smin32=0x80000002) R10=fp0") int check_assert_range_s64(struct __sk_buff *ctx) { struct bpf_sock *sk = ctx->sk; @@ -75,7 +75,7 @@ int check_assert_range_s64(struct __sk_buff *ctx) SEC("?tc") __log_level(2) __failure -__msg(": R1=ctx(off=0,imm=0) R2=scalar(smin=umin=smin32=umin32=4096,smax=umax=smax32=umax32=8192,var_off=(0x0; 0x3fff))") +__msg(": R1=ctx() R2=scalar(smin=umin=smin32=umin32=4096,smax=umax=smax32=umax32=8192,var_off=(0x0; 0x3fff))") int check_assert_range_u64(struct __sk_buff *ctx) { u64 num = ctx->len; @@ -86,7 +86,7 @@ int check_assert_range_u64(struct __sk_buff *ctx) SEC("?tc") __log_level(2) __failure -__msg(": R0=0 R1=ctx(off=0,imm=0) R2=4096 R10=fp0") +__msg(": R0=0 R1=ctx() R2=4096 R10=fp0") int check_assert_single_range_s64(struct __sk_buff *ctx) { struct bpf_sock *sk = ctx->sk; @@ -103,7 +103,7 @@ int check_assert_single_range_s64(struct __sk_buff *ctx) SEC("?tc") __log_level(2) __failure -__msg(": R1=ctx(off=0,imm=0) R2=4096 R10=fp0") +__msg(": R1=ctx() R2=4096 R10=fp0") int check_assert_single_range_u64(struct __sk_buff *ctx) { u64 num = ctx->len; @@ -114,7 +114,7 @@ int check_assert_single_range_u64(struct __sk_buff *ctx) SEC("?tc") __log_level(2) __failure -__msg(": R1=pkt(off=64,r=64,imm=0) R2=pkt_end(off=0,imm=0) R6=pkt(off=0,r=64,imm=0) R10=fp0") +__msg(": R1=pkt(off=64,r=64) R2=pkt_end() R6=pkt(r=64) R10=fp0") int check_assert_generic(struct __sk_buff *ctx) { u8 *data_end = (void *)(long)ctx->data_end; @@ -125,7 +125,7 @@ int check_assert_generic(struct __sk_buff *ctx) } SEC("?fentry/bpf_check") -__failure __msg("At program exit the register R0 has value (0x40; 0x0)") +__failure __msg("At program exit the register R1 has smin=64 smax=64") int check_assert_with_return(void *ctx) { bpf_assert_with(!ctx, 64); diff --git a/tools/testing/selftests/bpf/progs/exceptions_fail.c b/tools/testing/selftests/bpf/progs/exceptions_fail.c index 8c0ef27422..9cceb65211 100644 --- a/tools/testing/selftests/bpf/progs/exceptions_fail.c +++ b/tools/testing/selftests/bpf/progs/exceptions_fail.c @@ -308,7 +308,7 @@ int reject_set_exception_cb_bad_ret1(void *ctx) } SEC("?fentry/bpf_check") -__failure __msg("At program exit the register R0 has value (0x40; 0x0) should") +__failure __msg("At program exit the register R1 has smin=64 smax=64 should") int reject_set_exception_cb_bad_ret2(void *ctx) { bpf_throw(64); diff --git a/tools/testing/selftests/bpf/progs/fentry_recursive.c b/tools/testing/selftests/bpf/progs/fentry_recursive.c new file mode 100644 index 0000000000..2c9fb5ac42 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/fentry_recursive.c @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Red Hat, Inc. */ +#include +#include +#include + +char _license[] SEC("license") = "GPL"; + +/* Dummy fentry bpf prog for testing fentry attachment chains */ +SEC("fentry/XXX") +int BPF_PROG(recursive_attach, int a) +{ + return 0; +} diff --git a/tools/testing/selftests/bpf/progs/fentry_recursive_target.c b/tools/testing/selftests/bpf/progs/fentry_recursive_target.c new file mode 100644 index 0000000000..267c876d0a --- /dev/null +++ b/tools/testing/selftests/bpf/progs/fentry_recursive_target.c @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Red Hat, Inc. */ +#include +#include +#include + +char _license[] SEC("license") = "GPL"; + +/* Dummy fentry bpf prog for testing fentry attachment chains. It's going to be + * a start of the chain. + */ +SEC("fentry/bpf_testmod_fentry_test1") +int BPF_PROG(test1, int a) +{ + return 0; +} + +/* Dummy bpf prog for testing attach_btf presence when attaching an fentry + * program. + */ +SEC("raw_tp/sys_enter") +int BPF_PROG(fentry_target, struct pt_regs *regs, long id) +{ + return 0; +} diff --git a/tools/testing/selftests/bpf/progs/freplace_dead_global_func.c b/tools/testing/selftests/bpf/progs/freplace_dead_global_func.c new file mode 100644 index 0000000000..e6a75f86ca --- /dev/null +++ b/tools/testing/selftests/bpf/progs/freplace_dead_global_func.c @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include + +SEC("freplace") +int freplace_prog(void) +{ + return 0; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/freplace_unreliable_prog.c b/tools/testing/selftests/bpf/progs/freplace_unreliable_prog.c new file mode 100644 index 0000000000..624078abf3 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/freplace_unreliable_prog.c @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2020 Facebook + +#include "vmlinux.h" +#include +#include + +SEC("freplace/btf_unreliable_kprobe") +/* context type is what BPF verifier expects for kprobe context, but target + * program has `stuct whatever *ctx` argument, so freplace operation will be + * rejected with the following message: + * + * arg0 replace_btf_unreliable_kprobe(struct pt_regs *) doesn't match btf_unreliable_kprobe(struct whatever *) + */ +int replace_btf_unreliable_kprobe(bpf_user_pt_regs_t *ctx) +{ + return 0; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/iters.c b/tools/testing/selftests/bpf/progs/iters.c index 844d968c27..fe971992e6 100644 --- a/tools/testing/selftests/bpf/progs/iters.c +++ b/tools/testing/selftests/bpf/progs/iters.c @@ -6,7 +6,7 @@ #include #include "bpf_misc.h" -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#define ARRAY_SIZE(x) (int)(sizeof(x) / sizeof((x)[0])) static volatile int zero = 0; @@ -676,7 +676,7 @@ static __noinline int sum(struct bpf_iter_num *it, int *arr, __u32 n) while ((t = bpf_iter_num_next(it))) { i = *t; - if (i >= n) + if ((__u32)i >= n) break; sum += arr[i]; } @@ -1411,4 +1411,26 @@ __naked int checkpoint_states_deletion(void) ); } +struct { + int data[32]; + int n; +} loop_data; + +SEC("raw_tp") +__success +int iter_arr_with_actual_elem_count(const void *ctx) +{ + int i, n = loop_data.n, sum = 0; + + if (n > ARRAY_SIZE(loop_data.data)) + return 0; + + bpf_for(i, 0, n) { + /* no rechecking of i against ARRAY_SIZE(loop_data.n) */ + sum += loop_data.data[i]; + } + + return sum; +} + char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/iters_task.c b/tools/testing/selftests/bpf/progs/iters_task.c index c9b4055cd4..e4d53e40ff 100644 --- a/tools/testing/selftests/bpf/progs/iters_task.c +++ b/tools/testing/selftests/bpf/progs/iters_task.c @@ -10,7 +10,7 @@ char _license[] SEC("license") = "GPL"; pid_t target_pid; -int procs_cnt, threads_cnt, proc_threads_cnt; +int procs_cnt, threads_cnt, proc_threads_cnt, invalid_cnt; void bpf_rcu_read_lock(void) __ksym; void bpf_rcu_read_unlock(void) __ksym; @@ -26,6 +26,16 @@ int iter_task_for_each_sleep(void *ctx) procs_cnt = threads_cnt = proc_threads_cnt = 0; bpf_rcu_read_lock(); + bpf_for_each(task, pos, NULL, ~0U) { + /* Below instructions shouldn't be executed for invalid flags */ + invalid_cnt++; + } + + bpf_for_each(task, pos, NULL, BPF_TASK_ITER_PROC_THREADS) { + /* Below instructions shouldn't be executed for invalid task__nullable */ + invalid_cnt++; + } + bpf_for_each(task, pos, NULL, BPF_TASK_ITER_ALL_PROCS) if (pos->pid == target_pid) procs_cnt++; diff --git a/tools/testing/selftests/bpf/progs/iters_task_vma.c b/tools/testing/selftests/bpf/progs/iters_task_vma.c index e085a51d15..dc0c3691dc 100644 --- a/tools/testing/selftests/bpf/progs/iters_task_vma.c +++ b/tools/testing/selftests/bpf/progs/iters_task_vma.c @@ -28,9 +28,8 @@ int iter_task_vma_for_each(const void *ctx) return 0; bpf_for_each(task_vma, vma, task, 0) { - if (seen >= 1000) + if (bpf_cmp_unlikely(seen, >=, 1000)) break; - barrier_var(seen); vm_ranges[seen].vm_start = vma->vm_start; vm_ranges[seen].vm_end = vma->vm_end; diff --git a/tools/testing/selftests/bpf/progs/linked_funcs1.c b/tools/testing/selftests/bpf/progs/linked_funcs1.c index c4b49ceea9..cc79dddac1 100644 --- a/tools/testing/selftests/bpf/progs/linked_funcs1.c +++ b/tools/testing/selftests/bpf/progs/linked_funcs1.c @@ -8,7 +8,7 @@ #include "bpf_misc.h" /* weak and shared between two files */ -const volatile int my_tid __weak; +const volatile __u32 my_tid __weak; long syscall_id __weak; int output_val1; diff --git a/tools/testing/selftests/bpf/progs/linked_funcs2.c b/tools/testing/selftests/bpf/progs/linked_funcs2.c index 013ff0645f..942cc5526d 100644 --- a/tools/testing/selftests/bpf/progs/linked_funcs2.c +++ b/tools/testing/selftests/bpf/progs/linked_funcs2.c @@ -68,7 +68,7 @@ int BPF_PROG(handler2, struct pt_regs *regs, long id) { static volatile int whatever; - if (my_tid != (u32)bpf_get_current_pid_tgid() || id != syscall_id) + if (my_tid != (s32)bpf_get_current_pid_tgid() || id != syscall_id) return 0; /* make sure we have CO-RE relocations in main program */ diff --git a/tools/testing/selftests/bpf/progs/linked_list.c b/tools/testing/selftests/bpf/progs/linked_list.c index 84d1777a9e..26205ca806 100644 --- a/tools/testing/selftests/bpf/progs/linked_list.c +++ b/tools/testing/selftests/bpf/progs/linked_list.c @@ -6,7 +6,7 @@ #include "bpf_experimental.h" #ifndef ARRAY_SIZE -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#define ARRAY_SIZE(x) (int)(sizeof(x) / sizeof((x)[0])) #endif #include "linked_list.h" diff --git a/tools/testing/selftests/bpf/progs/local_kptr_stash.c b/tools/testing/selftests/bpf/progs/local_kptr_stash.c index b567a666d2..75043ffc5d 100644 --- a/tools/testing/selftests/bpf/progs/local_kptr_stash.c +++ b/tools/testing/selftests/bpf/progs/local_kptr_stash.c @@ -14,16 +14,41 @@ struct node_data { struct bpf_rb_node node; }; +struct refcounted_node { + long data; + struct bpf_rb_node rb_node; + struct bpf_refcount refcount; +}; + +struct stash { + struct bpf_spin_lock l; + struct refcounted_node __kptr *stashed; +}; + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __type(key, int); + __type(value, struct stash); + __uint(max_entries, 10); +} refcounted_node_stash SEC(".maps"); + struct plain_local { long key; long data; }; +struct local_with_root { + long key; + struct bpf_spin_lock l; + struct bpf_rb_root r __contains(node_data, node); +}; + struct map_value { struct prog_test_ref_kfunc *not_kptr; struct prog_test_ref_kfunc __kptr *val; struct node_data __kptr *node; struct plain_local __kptr *plain; + struct local_with_root __kptr *local_root; }; /* This is necessary so that LLVM generates BTF for node_data struct @@ -38,6 +63,7 @@ struct map_value { * Had to do the same w/ bpf_kfunc_call_test_release below */ struct node_data *just_here_because_btf_bug; +struct refcounted_node *just_here_because_btf_bug2; struct { __uint(type, BPF_MAP_TYPE_ARRAY); @@ -46,6 +72,17 @@ struct { __uint(max_entries, 2); } some_nodes SEC(".maps"); +static bool less(struct bpf_rb_node *a, const struct bpf_rb_node *b) +{ + struct node_data *node_a; + struct node_data *node_b; + + node_a = container_of(a, struct node_data, node); + node_b = container_of(b, struct node_data, node); + + return node_a->key < node_b->key; +} + static int create_and_stash(int idx, int val) { struct map_value *mapval; @@ -94,6 +131,41 @@ long stash_plain(void *ctx) return 0; } +SEC("tc") +long stash_local_with_root(void *ctx) +{ + struct local_with_root *res; + struct map_value *mapval; + struct node_data *n; + int idx = 0; + + mapval = bpf_map_lookup_elem(&some_nodes, &idx); + if (!mapval) + return 1; + + res = bpf_obj_new(typeof(*res)); + if (!res) + return 2; + res->key = 41; + + n = bpf_obj_new(typeof(*n)); + if (!n) { + bpf_obj_drop(res); + return 3; + } + + bpf_spin_lock(&res->l); + bpf_rbtree_add(&res->r, &n->node, less); + bpf_spin_unlock(&res->l); + + res = bpf_kptr_xchg(&mapval->local_root, res); + if (res) { + bpf_obj_drop(res); + return 4; + } + return 0; +} + SEC("tc") long unstash_rb_node(void *ctx) { @@ -132,4 +204,56 @@ long stash_test_ref_kfunc(void *ctx) return 0; } +SEC("tc") +long refcount_acquire_without_unstash(void *ctx) +{ + struct refcounted_node *p; + struct stash *s; + int ret = 0; + + s = bpf_map_lookup_elem(&refcounted_node_stash, &ret); + if (!s) + return 1; + + if (!s->stashed) + /* refcount_acquire failure is expected when no refcounted_node + * has been stashed before this program executes + */ + return 2; + + p = bpf_refcount_acquire(s->stashed); + if (!p) + return 3; + + ret = s->stashed ? s->stashed->data : -1; + bpf_obj_drop(p); + return ret; +} + +/* Helper for refcount_acquire_without_unstash test */ +SEC("tc") +long stash_refcounted_node(void *ctx) +{ + struct refcounted_node *p; + struct stash *s; + int key = 0; + + s = bpf_map_lookup_elem(&refcounted_node_stash, &key); + if (!s) + return 1; + + p = bpf_obj_new(typeof(*p)); + if (!p) + return 2; + p->data = 42; + + p = bpf_kptr_xchg(&s->stashed, p); + if (p) { + bpf_obj_drop(p); + return 3; + } + + return 0; +} + char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/local_storage.c b/tools/testing/selftests/bpf/progs/local_storage.c index bc8ea56671..e5e3a8b8dd 100644 --- a/tools/testing/selftests/bpf/progs/local_storage.c +++ b/tools/testing/selftests/bpf/progs/local_storage.c @@ -13,7 +13,7 @@ char _license[] SEC("license") = "GPL"; #define DUMMY_STORAGE_VALUE 0xdeadbeef -int monitored_pid = 0; +__u32 monitored_pid = 0; int inode_storage_result = -1; int sk_storage_result = -1; int task_storage_result = -1; diff --git a/tools/testing/selftests/bpf/progs/lsm.c b/tools/testing/selftests/bpf/progs/lsm.c index fadfdd9870..0c13b74099 100644 --- a/tools/testing/selftests/bpf/progs/lsm.c +++ b/tools/testing/selftests/bpf/progs/lsm.c @@ -92,7 +92,7 @@ int BPF_PROG(test_int_hook, struct vm_area_struct *vma, if (ret != 0) return ret; - __u32 pid = bpf_get_current_pid_tgid() >> 32; + __s32 pid = bpf_get_current_pid_tgid() >> 32; int is_stack = 0; is_stack = (vma->vm_start <= vma->vm_mm->start_stack && diff --git a/tools/testing/selftests/bpf/progs/map_in_map_btf.c b/tools/testing/selftests/bpf/progs/map_in_map_btf.c new file mode 100644 index 0000000000..7a1336d7b1 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/map_in_map_btf.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2023. Huawei Technologies Co., Ltd */ +#include +#include +#include + +#include "bpf_misc.h" +#include "bpf_experimental.h" + +struct node_data { + __u64 data; + struct bpf_list_node node; +}; + +struct map_value { + struct bpf_list_head head __contains(node_data, node); + struct bpf_spin_lock lock; +}; + +struct inner_array_type { + __uint(type, BPF_MAP_TYPE_ARRAY); + __type(key, int); + __type(value, struct map_value); + __uint(max_entries, 1); +} inner_array SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); + __uint(key_size, 4); + __uint(value_size, 4); + __uint(max_entries, 1); + __array(values, struct inner_array_type); +} outer_array SEC(".maps") = { + .values = { + [0] = &inner_array, + }, +}; + +char _license[] SEC("license") = "GPL"; + +int pid = 0; +bool done = false; + +SEC("fentry/" SYS_PREFIX "sys_nanosleep") +int add_to_list_in_inner_array(void *ctx) +{ + struct map_value *value; + struct node_data *new; + struct bpf_map *map; + int zero = 0; + + if (done || (u32)bpf_get_current_pid_tgid() != pid) + return 0; + + map = bpf_map_lookup_elem(&outer_array, &zero); + if (!map) + return 0; + + value = bpf_map_lookup_elem(map, &zero); + if (!value) + return 0; + + new = bpf_obj_new(typeof(*new)); + if (!new) + return 0; + + bpf_spin_lock(&value->lock); + bpf_list_push_back(&value->head, &new->node); + bpf_spin_unlock(&value->lock); + done = true; + + return 0; +} diff --git a/tools/testing/selftests/bpf/progs/normal_map_btf.c b/tools/testing/selftests/bpf/progs/normal_map_btf.c new file mode 100644 index 0000000000..a45c929955 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/normal_map_btf.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2023. Huawei Technologies Co., Ltd */ +#include +#include +#include + +#include "bpf_misc.h" +#include "bpf_experimental.h" + +struct node_data { + __u64 data; + struct bpf_list_node node; +}; + +struct map_value { + struct bpf_list_head head __contains(node_data, node); + struct bpf_spin_lock lock; +}; + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __type(key, int); + __type(value, struct map_value); + __uint(max_entries, 1); +} array SEC(".maps"); + +char _license[] SEC("license") = "GPL"; + +int pid = 0; +bool done = false; + +SEC("fentry/" SYS_PREFIX "sys_nanosleep") +int add_to_list_in_array(void *ctx) +{ + struct map_value *value; + struct node_data *new; + int zero = 0; + + if (done || (int)bpf_get_current_pid_tgid() != pid) + return 0; + + value = bpf_map_lookup_elem(&array, &zero); + if (!value) + return 0; + + new = bpf_obj_new(typeof(*new)); + if (!new) + return 0; + + bpf_spin_lock(&value->lock); + bpf_list_push_back(&value->head, &new->node); + bpf_spin_unlock(&value->lock); + done = true; + + return 0; +} diff --git a/tools/testing/selftests/bpf/progs/percpu_alloc_fail.c b/tools/testing/selftests/bpf/progs/percpu_alloc_fail.c index 1a891d30f1..f2b8eb2ff7 100644 --- a/tools/testing/selftests/bpf/progs/percpu_alloc_fail.c +++ b/tools/testing/selftests/bpf/progs/percpu_alloc_fail.c @@ -17,6 +17,10 @@ struct val_with_rb_root_t { struct bpf_spin_lock lock; }; +struct val_600b_t { + char b[600]; +}; + struct elem { long sum; struct val_t __percpu_kptr *pc; @@ -161,4 +165,18 @@ int BPF_PROG(test_array_map_7) return 0; } +SEC("?fentry.s/bpf_fentry_test1") +__failure __msg("bpf_percpu_obj_new type size (600) is greater than 512") +int BPF_PROG(test_array_map_8) +{ + struct val_600b_t __percpu_kptr *p; + + p = bpf_percpu_obj_new(struct val_600b_t); + if (!p) + return 0; + + bpf_percpu_obj_drop(p); + return 0; +} + char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/profiler.inc.h b/tools/testing/selftests/bpf/progs/profiler.inc.h index 897061930c..de3b6e4e4d 100644 --- a/tools/testing/selftests/bpf/progs/profiler.inc.h +++ b/tools/testing/selftests/bpf/progs/profiler.inc.h @@ -7,6 +7,7 @@ #include "profiler.h" #include "err.h" +#include "bpf_experimental.h" #ifndef NULL #define NULL 0 @@ -132,7 +133,7 @@ struct { } disallowed_exec_inodes SEC(".maps"); #ifndef ARRAY_SIZE -#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) +#define ARRAY_SIZE(arr) (int)(sizeof(arr) / sizeof(arr[0])) #endif static INLINE bool IS_ERR(const void* ptr) @@ -221,8 +222,7 @@ static INLINE void* read_full_cgroup_path(struct kernfs_node* cgroup_node, return payload; if (cgroup_node == cgroup_root_node) *root_pos = payload - payload_start; - if (filepart_length <= MAX_PATH) { - barrier_var(filepart_length); + if (bpf_cmp_likely(filepart_length, <=, MAX_PATH)) { payload += filepart_length; } cgroup_node = BPF_CORE_READ(cgroup_node, parent); @@ -305,9 +305,7 @@ static INLINE void* populate_cgroup_info(struct cgroup_data_t* cgroup_data, size_t cgroup_root_length = bpf_probe_read_kernel_str(payload, MAX_PATH, BPF_CORE_READ(root_kernfs, name)); - barrier_var(cgroup_root_length); - if (cgroup_root_length <= MAX_PATH) { - barrier_var(cgroup_root_length); + if (bpf_cmp_likely(cgroup_root_length, <=, MAX_PATH)) { cgroup_data->cgroup_root_length = cgroup_root_length; payload += cgroup_root_length; } @@ -315,9 +313,7 @@ static INLINE void* populate_cgroup_info(struct cgroup_data_t* cgroup_data, size_t cgroup_proc_length = bpf_probe_read_kernel_str(payload, MAX_PATH, BPF_CORE_READ(proc_kernfs, name)); - barrier_var(cgroup_proc_length); - if (cgroup_proc_length <= MAX_PATH) { - barrier_var(cgroup_proc_length); + if (bpf_cmp_likely(cgroup_proc_length, <=, MAX_PATH)) { cgroup_data->cgroup_proc_length = cgroup_proc_length; payload += cgroup_proc_length; } @@ -347,9 +343,7 @@ static INLINE void* populate_var_metadata(struct var_metadata_t* metadata, metadata->comm_length = 0; size_t comm_length = bpf_core_read_str(payload, TASK_COMM_LEN, &task->comm); - barrier_var(comm_length); - if (comm_length <= TASK_COMM_LEN) { - barrier_var(comm_length); + if (bpf_cmp_likely(comm_length, <=, TASK_COMM_LEN)) { metadata->comm_length = comm_length; payload += comm_length; } @@ -494,10 +488,9 @@ read_absolute_file_path_from_dentry(struct dentry* filp_dentry, void* payload) filepart_length = bpf_probe_read_kernel_str(payload, MAX_PATH, BPF_CORE_READ(filp_dentry, d_name.name)); - barrier_var(filepart_length); - if (filepart_length > MAX_PATH) + bpf_nop_mov(filepart_length); + if (bpf_cmp_unlikely(filepart_length, >, MAX_PATH)) break; - barrier_var(filepart_length); payload += filepart_length; length += filepart_length; @@ -579,9 +572,7 @@ ssize_t BPF_KPROBE(kprobe__proc_sys_write, size_t sysctl_val_length = bpf_probe_read_kernel_str(payload, CTL_MAXNAME, buf); - barrier_var(sysctl_val_length); - if (sysctl_val_length <= CTL_MAXNAME) { - barrier_var(sysctl_val_length); + if (bpf_cmp_likely(sysctl_val_length, <=, CTL_MAXNAME)) { sysctl_data->sysctl_val_length = sysctl_val_length; payload += sysctl_val_length; } @@ -590,9 +581,7 @@ ssize_t BPF_KPROBE(kprobe__proc_sys_write, bpf_probe_read_kernel_str(payload, MAX_PATH, BPF_CORE_READ(filp, f_path.dentry, d_name.name)); - barrier_var(sysctl_path_length); - if (sysctl_path_length <= MAX_PATH) { - barrier_var(sysctl_path_length); + if (bpf_cmp_likely(sysctl_path_length, <=, MAX_PATH)) { sysctl_data->sysctl_path_length = sysctl_path_length; payload += sysctl_path_length; } @@ -645,7 +634,7 @@ int raw_tracepoint__sched_process_exit(void* ctx) for (int i = 0; i < ARRAY_SIZE(arr_struct->array); i++) { struct var_kill_data_t* past_kill_data = &arr_struct->array[i]; - if (past_kill_data != NULL && past_kill_data->kill_target_pid == tpid) { + if (past_kill_data != NULL && past_kill_data->kill_target_pid == (pid_t)tpid) { bpf_probe_read_kernel(kill_data, sizeof(*past_kill_data), past_kill_data); void* payload = kill_data->payload; @@ -658,9 +647,7 @@ int raw_tracepoint__sched_process_exit(void* ctx) kill_data->kill_target_cgroup_proc_length = 0; size_t comm_length = bpf_core_read_str(payload, TASK_COMM_LEN, &task->comm); - barrier_var(comm_length); - if (comm_length <= TASK_COMM_LEN) { - barrier_var(comm_length); + if (bpf_cmp_likely(comm_length, <=, TASK_COMM_LEN)) { kill_data->kill_target_name_length = comm_length; payload += comm_length; } @@ -669,9 +656,7 @@ int raw_tracepoint__sched_process_exit(void* ctx) bpf_probe_read_kernel_str(payload, KILL_TARGET_LEN, BPF_CORE_READ(proc_kernfs, name)); - barrier_var(cgroup_proc_length); - if (cgroup_proc_length <= KILL_TARGET_LEN) { - barrier_var(cgroup_proc_length); + if (bpf_cmp_likely(cgroup_proc_length, <=, KILL_TARGET_LEN)) { kill_data->kill_target_cgroup_proc_length = cgroup_proc_length; payload += cgroup_proc_length; } @@ -731,9 +716,7 @@ int raw_tracepoint__sched_process_exec(struct bpf_raw_tracepoint_args* ctx) const char* filename = BPF_CORE_READ(bprm, filename); size_t bin_path_length = bpf_probe_read_kernel_str(payload, MAX_FILENAME_LEN, filename); - barrier_var(bin_path_length); - if (bin_path_length <= MAX_FILENAME_LEN) { - barrier_var(bin_path_length); + if (bpf_cmp_likely(bin_path_length, <=, MAX_FILENAME_LEN)) { proc_exec_data->bin_path_length = bin_path_length; payload += bin_path_length; } @@ -743,8 +726,7 @@ int raw_tracepoint__sched_process_exec(struct bpf_raw_tracepoint_args* ctx) unsigned int cmdline_length = probe_read_lim(payload, arg_start, arg_end - arg_start, MAX_ARGS_LEN); - if (cmdline_length <= MAX_ARGS_LEN) { - barrier_var(cmdline_length); + if (bpf_cmp_likely(cmdline_length, <=, MAX_ARGS_LEN)) { proc_exec_data->cmdline_length = cmdline_length; payload += cmdline_length; } @@ -821,9 +803,7 @@ int kprobe_ret__do_filp_open(struct pt_regs* ctx) payload = populate_cgroup_info(&filemod_data->cgroup_data, task, payload); size_t len = read_absolute_file_path_from_dentry(filp_dentry, payload); - barrier_var(len); - if (len <= MAX_FILEPATH_LENGTH) { - barrier_var(len); + if (bpf_cmp_likely(len, <=, MAX_FILEPATH_LENGTH)) { payload += len; filemod_data->dst_filepath_length = len; } @@ -876,17 +856,13 @@ int BPF_KPROBE(kprobe__vfs_link, payload = populate_cgroup_info(&filemod_data->cgroup_data, task, payload); size_t len = read_absolute_file_path_from_dentry(old_dentry, payload); - barrier_var(len); - if (len <= MAX_FILEPATH_LENGTH) { - barrier_var(len); + if (bpf_cmp_likely(len, <=, MAX_FILEPATH_LENGTH)) { payload += len; filemod_data->src_filepath_length = len; } len = read_absolute_file_path_from_dentry(new_dentry, payload); - barrier_var(len); - if (len <= MAX_FILEPATH_LENGTH) { - barrier_var(len); + if (bpf_cmp_likely(len, <=, MAX_FILEPATH_LENGTH)) { payload += len; filemod_data->dst_filepath_length = len; } @@ -936,16 +912,12 @@ int BPF_KPROBE(kprobe__vfs_symlink, struct inode* dir, struct dentry* dentry, size_t len = bpf_probe_read_kernel_str(payload, MAX_FILEPATH_LENGTH, oldname); - barrier_var(len); - if (len <= MAX_FILEPATH_LENGTH) { - barrier_var(len); + if (bpf_cmp_likely(len, <=, MAX_FILEPATH_LENGTH)) { payload += len; filemod_data->src_filepath_length = len; } len = read_absolute_file_path_from_dentry(dentry, payload); - barrier_var(len); - if (len <= MAX_FILEPATH_LENGTH) { - barrier_var(len); + if (bpf_cmp_likely(len, <=, MAX_FILEPATH_LENGTH)) { payload += len; filemod_data->dst_filepath_length = len; } diff --git a/tools/testing/selftests/bpf/progs/read_vsyscall.c b/tools/testing/selftests/bpf/progs/read_vsyscall.c new file mode 100644 index 0000000000..986f96687a --- /dev/null +++ b/tools/testing/selftests/bpf/progs/read_vsyscall.c @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2024. Huawei Technologies Co., Ltd */ +#include +#include + +#include "bpf_misc.h" + +int target_pid = 0; +void *user_ptr = 0; +int read_ret[8]; + +char _license[] SEC("license") = "GPL"; + +SEC("fentry/" SYS_PREFIX "sys_nanosleep") +int do_probe_read(void *ctx) +{ + char buf[8]; + + if ((bpf_get_current_pid_tgid() >> 32) != target_pid) + return 0; + + read_ret[0] = bpf_probe_read_kernel(buf, sizeof(buf), user_ptr); + read_ret[1] = bpf_probe_read_kernel_str(buf, sizeof(buf), user_ptr); + read_ret[2] = bpf_probe_read(buf, sizeof(buf), user_ptr); + read_ret[3] = bpf_probe_read_str(buf, sizeof(buf), user_ptr); + read_ret[4] = bpf_probe_read_user(buf, sizeof(buf), user_ptr); + read_ret[5] = bpf_probe_read_user_str(buf, sizeof(buf), user_ptr); + + return 0; +} + +SEC("fentry.s/" SYS_PREFIX "sys_nanosleep") +int do_copy_from_user(void *ctx) +{ + char buf[8]; + + if ((bpf_get_current_pid_tgid() >> 32) != target_pid) + return 0; + + read_ret[6] = bpf_copy_from_user(buf, sizeof(buf), user_ptr); + read_ret[7] = bpf_copy_from_user_task(buf, sizeof(buf), user_ptr, + bpf_get_current_task_btf(), 0); + + return 0; +} diff --git a/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c b/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c index 1ef07f6ee5..1553b9c16a 100644 --- a/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c +++ b/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c @@ -53,6 +53,25 @@ long rbtree_refcounted_node_ref_escapes(void *ctx) return 0; } +SEC("?tc") +__failure __msg("Possibly NULL pointer passed to trusted arg0") +long refcount_acquire_maybe_null(void *ctx) +{ + struct node_acquire *n, *m; + + n = bpf_obj_new(typeof(*n)); + /* Intentionally not testing !n + * it's MAYBE_NULL for refcount_acquire + */ + m = bpf_refcount_acquire(n); + if (m) + bpf_obj_drop(m); + if (n) + bpf_obj_drop(n); + + return 0; +} + SEC("?tc") __failure __msg("Unreleased reference id=3 alloc_insn=9") long rbtree_refcounted_node_ref_escapes_owning_input(void *ctx) diff --git a/tools/testing/selftests/bpf/progs/sock_iter_batch.c b/tools/testing/selftests/bpf/progs/sock_iter_batch.c new file mode 100644 index 0000000000..ffbbfe1fa1 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/sock_iter_batch.c @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2024 Meta + +#include "vmlinux.h" +#include +#include +#include +#include "bpf_tracing_net.h" +#include "bpf_kfuncs.h" + +#define ATTR __always_inline +#include "test_jhash.h" + +static bool ipv6_addr_loopback(const struct in6_addr *a) +{ + return (a->s6_addr32[0] | a->s6_addr32[1] | + a->s6_addr32[2] | (a->s6_addr32[3] ^ bpf_htonl(1))) == 0; +} + +volatile const __u16 ports[2]; +unsigned int bucket[2]; + +SEC("iter/tcp") +int iter_tcp_soreuse(struct bpf_iter__tcp *ctx) +{ + struct sock *sk = (struct sock *)ctx->sk_common; + struct inet_hashinfo *hinfo; + unsigned int hash; + struct net *net; + int idx; + + if (!sk) + return 0; + + sk = bpf_rdonly_cast(sk, bpf_core_type_id_kernel(struct sock)); + if (sk->sk_family != AF_INET6 || + sk->sk_state != TCP_LISTEN || + !ipv6_addr_loopback(&sk->sk_v6_rcv_saddr)) + return 0; + + if (sk->sk_num == ports[0]) + idx = 0; + else if (sk->sk_num == ports[1]) + idx = 1; + else + return 0; + + /* bucket selection as in inet_lhash2_bucket_sk() */ + net = sk->sk_net.net; + hash = jhash2(sk->sk_v6_rcv_saddr.s6_addr32, 4, net->hash_mix); + hash ^= sk->sk_num; + hinfo = net->ipv4.tcp_death_row.hashinfo; + bucket[idx] = hash & hinfo->lhash2_mask; + bpf_seq_write(ctx->meta->seq, &idx, sizeof(idx)); + + return 0; +} + +#define udp_sk(ptr) container_of(ptr, struct udp_sock, inet.sk) + +SEC("iter/udp") +int iter_udp_soreuse(struct bpf_iter__udp *ctx) +{ + struct sock *sk = (struct sock *)ctx->udp_sk; + struct udp_table *udptable; + int idx; + + if (!sk) + return 0; + + sk = bpf_rdonly_cast(sk, bpf_core_type_id_kernel(struct sock)); + if (sk->sk_family != AF_INET6 || + !ipv6_addr_loopback(&sk->sk_v6_rcv_saddr)) + return 0; + + if (sk->sk_num == ports[0]) + idx = 0; + else if (sk->sk_num == ports[1]) + idx = 1; + else + return 0; + + /* bucket selection as in udp_hashslot2() */ + udptable = sk->sk_net.net->ipv4.udp_table; + bucket[idx] = udp_sk(sk)->udp_portaddr_hash & udptable->mask; + bpf_seq_write(ctx->meta->seq, &idx, sizeof(idx)); + + return 0; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/sockopt_inherit.c b/tools/testing/selftests/bpf/progs/sockopt_inherit.c index c8f59caa46..a3434b8409 100644 --- a/tools/testing/selftests/bpf/progs/sockopt_inherit.c +++ b/tools/testing/selftests/bpf/progs/sockopt_inherit.c @@ -9,7 +9,7 @@ char _license[] SEC("license") = "GPL"; #define CUSTOM_INHERIT2 1 #define CUSTOM_LISTENER 2 -__u32 page_size = 0; +__s32 page_size = 0; struct sockopt_inherit { __u8 val; diff --git a/tools/testing/selftests/bpf/progs/sockopt_multi.c b/tools/testing/selftests/bpf/progs/sockopt_multi.c index 96f29fce05..db67278e12 100644 --- a/tools/testing/selftests/bpf/progs/sockopt_multi.c +++ b/tools/testing/selftests/bpf/progs/sockopt_multi.c @@ -5,7 +5,7 @@ char _license[] SEC("license") = "GPL"; -__u32 page_size = 0; +__s32 page_size = 0; SEC("cgroup/getsockopt") int _getsockopt_child(struct bpf_sockopt *ctx) diff --git a/tools/testing/selftests/bpf/progs/sockopt_qos_to_cc.c b/tools/testing/selftests/bpf/progs/sockopt_qos_to_cc.c index dbe235ede7..83753b00a5 100644 --- a/tools/testing/selftests/bpf/progs/sockopt_qos_to_cc.c +++ b/tools/testing/selftests/bpf/progs/sockopt_qos_to_cc.c @@ -9,7 +9,7 @@ char _license[] SEC("license") = "GPL"; -__u32 page_size = 0; +__s32 page_size = 0; SEC("cgroup/setsockopt") int sockopt_qos_to_cc(struct bpf_sockopt *ctx) diff --git a/tools/testing/selftests/bpf/progs/syscall.c b/tools/testing/selftests/bpf/progs/syscall.c index e550f72896..3d3cafdebe 100644 --- a/tools/testing/selftests/bpf/progs/syscall.c +++ b/tools/testing/selftests/bpf/progs/syscall.c @@ -6,9 +6,15 @@ #include #include <../../../tools/include/linux/filter.h> #include +#include +#include char _license[] SEC("license") = "GPL"; +struct bpf_map { + int id; +} __attribute__((preserve_access_index)); + struct args { __u64 log_buf; __u32 log_size; @@ -27,6 +33,37 @@ struct args { BTF_TYPE_ENC(name, BTF_INFO_ENC(BTF_KIND_INT, 0, 0), sz), \ BTF_INT_ENC(encoding, bits_offset, bits) +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __type(key, int); + __type(value, union bpf_attr); + __uint(max_entries, 1); +} bpf_attr_array SEC(".maps"); + +struct inner_map_type { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(key_size, 4); + __uint(value_size, 4); + __uint(max_entries, 1); +} inner_map SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); + __type(key, int); + __type(value, int); + __uint(max_entries, 1); + __array(values, struct inner_map_type); +} outer_array_map SEC(".maps") = { + .values = { + [0] = &inner_map, + }, +}; + +static inline __u64 ptr_to_u64(const void *ptr) +{ + return (__u64) (unsigned long) ptr; +} + static int btf_load(void) { struct btf_blob { @@ -58,7 +95,7 @@ static int btf_load(void) } SEC("syscall") -int bpf_prog(struct args *ctx) +int load_prog(struct args *ctx) { static char license[] = "GPL"; static struct bpf_insn insns[] = { @@ -94,8 +131,8 @@ int bpf_prog(struct args *ctx) map_create_attr.max_entries = ctx->max_entries; map_create_attr.btf_fd = ret; - prog_load_attr.license = (long) license; - prog_load_attr.insns = (long) insns; + prog_load_attr.license = ptr_to_u64(license); + prog_load_attr.insns = ptr_to_u64(insns); prog_load_attr.log_buf = ctx->log_buf; prog_load_attr.log_size = ctx->log_size; prog_load_attr.log_level = 1; @@ -107,8 +144,8 @@ int bpf_prog(struct args *ctx) insns[3].imm = ret; map_update_attr.map_fd = ret; - map_update_attr.key = (long) &key; - map_update_attr.value = (long) &value; + map_update_attr.key = ptr_to_u64(&key); + map_update_attr.value = ptr_to_u64(&value); ret = bpf_sys_bpf(BPF_MAP_UPDATE_ELEM, &map_update_attr, sizeof(map_update_attr)); if (ret < 0) return ret; @@ -119,3 +156,52 @@ int bpf_prog(struct args *ctx) ctx->prog_fd = ret; return 1; } + +SEC("syscall") +int update_outer_map(void *ctx) +{ + int zero = 0, ret = 0, outer_fd = -1, inner_fd = -1, err; + const int attr_sz = sizeof(union bpf_attr); + union bpf_attr *attr; + + attr = bpf_map_lookup_elem((struct bpf_map *)&bpf_attr_array, &zero); + if (!attr) + goto out; + + memset(attr, 0, attr_sz); + attr->map_id = ((struct bpf_map *)&outer_array_map)->id; + outer_fd = bpf_sys_bpf(BPF_MAP_GET_FD_BY_ID, attr, attr_sz); + if (outer_fd < 0) + goto out; + + memset(attr, 0, attr_sz); + attr->map_type = BPF_MAP_TYPE_ARRAY; + attr->key_size = 4; + attr->value_size = 4; + attr->max_entries = 1; + inner_fd = bpf_sys_bpf(BPF_MAP_CREATE, attr, attr_sz); + if (inner_fd < 0) + goto out; + + memset(attr, 0, attr_sz); + attr->map_fd = outer_fd; + attr->key = ptr_to_u64(&zero); + attr->value = ptr_to_u64(&inner_fd); + err = bpf_sys_bpf(BPF_MAP_UPDATE_ELEM, attr, attr_sz); + if (err) + goto out; + + memset(attr, 0, attr_sz); + attr->map_fd = outer_fd; + attr->key = ptr_to_u64(&zero); + err = bpf_sys_bpf(BPF_MAP_DELETE_ELEM, attr, attr_sz); + if (err) + goto out; + ret = 1; +out: + if (inner_fd >= 0) + bpf_sys_close(inner_fd); + if (outer_fd >= 0) + bpf_sys_close(outer_fd); + return ret; +} diff --git a/tools/testing/selftests/bpf/progs/task_kfunc_failure.c b/tools/testing/selftests/bpf/progs/task_kfunc_failure.c index dcdea31270..ad88a3796d 100644 --- a/tools/testing/selftests/bpf/progs/task_kfunc_failure.c +++ b/tools/testing/selftests/bpf/progs/task_kfunc_failure.c @@ -248,7 +248,7 @@ int BPF_PROG(task_kfunc_from_pid_no_null_check, struct task_struct *task, u64 cl } SEC("lsm/task_free") -__failure __msg("reg type unsupported for arg#0 function") +__failure __msg("R1 must be a rcu pointer") int BPF_PROG(task_kfunc_from_lsm_task_free, struct task_struct *task) { struct task_struct *acquired; diff --git a/tools/testing/selftests/bpf/progs/test_bpf_ma.c b/tools/testing/selftests/bpf/progs/test_bpf_ma.c index b685a4aba6..3494ca30fa 100644 --- a/tools/testing/selftests/bpf/progs/test_bpf_ma.c +++ b/tools/testing/selftests/bpf/progs/test_bpf_ma.c @@ -17,20 +17,23 @@ struct generic_map_value { char _license[] SEC("license") = "GPL"; -const unsigned int data_sizes[] = {8, 16, 32, 64, 96, 128, 192, 256, 512, 1024, 2048, 4096}; +const unsigned int data_sizes[] = {16, 32, 64, 96, 128, 192, 256, 512, 1024, 2048, 4096}; const volatile unsigned int data_btf_ids[ARRAY_SIZE(data_sizes)] = {}; +const unsigned int percpu_data_sizes[] = {8, 16, 32, 64, 96, 128, 192, 256, 512}; +const volatile unsigned int percpu_data_btf_ids[ARRAY_SIZE(data_sizes)] = {}; + int err = 0; -int pid = 0; +u32 pid = 0; #define DEFINE_ARRAY_WITH_KPTR(_size) \ struct bin_data_##_size { \ char data[_size - sizeof(void *)]; \ }; \ + /* See Commit 5d8d6634ccc, force btf generation for type bin_data_##_size */ \ + struct bin_data_##_size *__bin_data_##_size; \ struct map_value_##_size { \ struct bin_data_##_size __kptr * data; \ - /* To emit BTF info for bin_data_xx */ \ - struct bin_data_##_size not_used; \ }; \ struct { \ __uint(type, BPF_MAP_TYPE_ARRAY); \ @@ -40,8 +43,12 @@ int pid = 0; } array_##_size SEC(".maps") #define DEFINE_ARRAY_WITH_PERCPU_KPTR(_size) \ + struct percpu_bin_data_##_size { \ + char data[_size]; \ + }; \ + struct percpu_bin_data_##_size *__percpu_bin_data_##_size; \ struct map_value_percpu_##_size { \ - struct bin_data_##_size __percpu_kptr * data; \ + struct percpu_bin_data_##_size __percpu_kptr * data; \ }; \ struct { \ __uint(type, BPF_MAP_TYPE_ARRAY); \ @@ -114,7 +121,7 @@ static __always_inline void batch_percpu_alloc(struct bpf_map *map, unsigned int return; } /* per-cpu allocator may not be able to refill in time */ - new = bpf_percpu_obj_new_impl(data_btf_ids[idx], NULL); + new = bpf_percpu_obj_new_impl(percpu_data_btf_ids[idx], NULL); if (!new) continue; @@ -166,7 +173,7 @@ static __always_inline void batch_percpu_free(struct bpf_map *map, unsigned int batch_percpu_free((struct bpf_map *)(&array_percpu_##size), batch, idx); \ } while (0) -DEFINE_ARRAY_WITH_KPTR(8); +/* kptr doesn't support bin_data_8 which is a zero-sized array */ DEFINE_ARRAY_WITH_KPTR(16); DEFINE_ARRAY_WITH_KPTR(32); DEFINE_ARRAY_WITH_KPTR(64); @@ -179,7 +186,7 @@ DEFINE_ARRAY_WITH_KPTR(1024); DEFINE_ARRAY_WITH_KPTR(2048); DEFINE_ARRAY_WITH_KPTR(4096); -/* per-cpu kptr doesn't support bin_data_8 which is a zero-sized array */ +DEFINE_ARRAY_WITH_PERCPU_KPTR(8); DEFINE_ARRAY_WITH_PERCPU_KPTR(16); DEFINE_ARRAY_WITH_PERCPU_KPTR(32); DEFINE_ARRAY_WITH_PERCPU_KPTR(64); @@ -188,9 +195,6 @@ DEFINE_ARRAY_WITH_PERCPU_KPTR(128); DEFINE_ARRAY_WITH_PERCPU_KPTR(192); DEFINE_ARRAY_WITH_PERCPU_KPTR(256); DEFINE_ARRAY_WITH_PERCPU_KPTR(512); -DEFINE_ARRAY_WITH_PERCPU_KPTR(1024); -DEFINE_ARRAY_WITH_PERCPU_KPTR(2048); -DEFINE_ARRAY_WITH_PERCPU_KPTR(4096); SEC("?fentry/" SYS_PREFIX "sys_nanosleep") int test_batch_alloc_free(void *ctx) @@ -198,21 +202,20 @@ int test_batch_alloc_free(void *ctx) if ((u32)bpf_get_current_pid_tgid() != pid) return 0; - /* Alloc 128 8-bytes objects in batch to trigger refilling, - * then free 128 8-bytes objects in batch to trigger freeing. + /* Alloc 128 16-bytes objects in batch to trigger refilling, + * then free 128 16-bytes objects in batch to trigger freeing. */ - CALL_BATCH_ALLOC_FREE(8, 128, 0); - CALL_BATCH_ALLOC_FREE(16, 128, 1); - CALL_BATCH_ALLOC_FREE(32, 128, 2); - CALL_BATCH_ALLOC_FREE(64, 128, 3); - CALL_BATCH_ALLOC_FREE(96, 128, 4); - CALL_BATCH_ALLOC_FREE(128, 128, 5); - CALL_BATCH_ALLOC_FREE(192, 128, 6); - CALL_BATCH_ALLOC_FREE(256, 128, 7); - CALL_BATCH_ALLOC_FREE(512, 64, 8); - CALL_BATCH_ALLOC_FREE(1024, 32, 9); - CALL_BATCH_ALLOC_FREE(2048, 16, 10); - CALL_BATCH_ALLOC_FREE(4096, 8, 11); + CALL_BATCH_ALLOC_FREE(16, 128, 0); + CALL_BATCH_ALLOC_FREE(32, 128, 1); + CALL_BATCH_ALLOC_FREE(64, 128, 2); + CALL_BATCH_ALLOC_FREE(96, 128, 3); + CALL_BATCH_ALLOC_FREE(128, 128, 4); + CALL_BATCH_ALLOC_FREE(192, 128, 5); + CALL_BATCH_ALLOC_FREE(256, 128, 6); + CALL_BATCH_ALLOC_FREE(512, 64, 7); + CALL_BATCH_ALLOC_FREE(1024, 32, 8); + CALL_BATCH_ALLOC_FREE(2048, 16, 9); + CALL_BATCH_ALLOC_FREE(4096, 8, 10); return 0; } @@ -223,21 +226,20 @@ int test_free_through_map_free(void *ctx) if ((u32)bpf_get_current_pid_tgid() != pid) return 0; - /* Alloc 128 8-bytes objects in batch to trigger refilling, + /* Alloc 128 16-bytes objects in batch to trigger refilling, * then free these objects through map free. */ - CALL_BATCH_ALLOC(8, 128, 0); - CALL_BATCH_ALLOC(16, 128, 1); - CALL_BATCH_ALLOC(32, 128, 2); - CALL_BATCH_ALLOC(64, 128, 3); - CALL_BATCH_ALLOC(96, 128, 4); - CALL_BATCH_ALLOC(128, 128, 5); - CALL_BATCH_ALLOC(192, 128, 6); - CALL_BATCH_ALLOC(256, 128, 7); - CALL_BATCH_ALLOC(512, 64, 8); - CALL_BATCH_ALLOC(1024, 32, 9); - CALL_BATCH_ALLOC(2048, 16, 10); - CALL_BATCH_ALLOC(4096, 8, 11); + CALL_BATCH_ALLOC(16, 128, 0); + CALL_BATCH_ALLOC(32, 128, 1); + CALL_BATCH_ALLOC(64, 128, 2); + CALL_BATCH_ALLOC(96, 128, 3); + CALL_BATCH_ALLOC(128, 128, 4); + CALL_BATCH_ALLOC(192, 128, 5); + CALL_BATCH_ALLOC(256, 128, 6); + CALL_BATCH_ALLOC(512, 64, 7); + CALL_BATCH_ALLOC(1024, 32, 8); + CALL_BATCH_ALLOC(2048, 16, 9); + CALL_BATCH_ALLOC(4096, 8, 10); return 0; } @@ -248,9 +250,10 @@ int test_batch_percpu_alloc_free(void *ctx) if ((u32)bpf_get_current_pid_tgid() != pid) return 0; - /* Alloc 128 16-bytes per-cpu objects in batch to trigger refilling, - * then free 128 16-bytes per-cpu objects in batch to trigger freeing. + /* Alloc 128 8-bytes per-cpu objects in batch to trigger refilling, + * then free 128 8-bytes per-cpu objects in batch to trigger freeing. */ + CALL_BATCH_PERCPU_ALLOC_FREE(8, 128, 0); CALL_BATCH_PERCPU_ALLOC_FREE(16, 128, 1); CALL_BATCH_PERCPU_ALLOC_FREE(32, 128, 2); CALL_BATCH_PERCPU_ALLOC_FREE(64, 128, 3); @@ -259,9 +262,6 @@ int test_batch_percpu_alloc_free(void *ctx) CALL_BATCH_PERCPU_ALLOC_FREE(192, 128, 6); CALL_BATCH_PERCPU_ALLOC_FREE(256, 128, 7); CALL_BATCH_PERCPU_ALLOC_FREE(512, 64, 8); - CALL_BATCH_PERCPU_ALLOC_FREE(1024, 32, 9); - CALL_BATCH_PERCPU_ALLOC_FREE(2048, 16, 10); - CALL_BATCH_PERCPU_ALLOC_FREE(4096, 8, 11); return 0; } @@ -272,9 +272,10 @@ int test_percpu_free_through_map_free(void *ctx) if ((u32)bpf_get_current_pid_tgid() != pid) return 0; - /* Alloc 128 16-bytes per-cpu objects in batch to trigger refilling, + /* Alloc 128 8-bytes per-cpu objects in batch to trigger refilling, * then free these object through map free. */ + CALL_BATCH_PERCPU_ALLOC(8, 128, 0); CALL_BATCH_PERCPU_ALLOC(16, 128, 1); CALL_BATCH_PERCPU_ALLOC(32, 128, 2); CALL_BATCH_PERCPU_ALLOC(64, 128, 3); @@ -283,9 +284,6 @@ int test_percpu_free_through_map_free(void *ctx) CALL_BATCH_PERCPU_ALLOC(192, 128, 6); CALL_BATCH_PERCPU_ALLOC(256, 128, 7); CALL_BATCH_PERCPU_ALLOC(512, 64, 8); - CALL_BATCH_PERCPU_ALLOC(1024, 32, 9); - CALL_BATCH_PERCPU_ALLOC(2048, 16, 10); - CALL_BATCH_PERCPU_ALLOC(4096, 8, 11); return 0; } diff --git a/tools/testing/selftests/bpf/progs/test_cgroup1_hierarchy.c b/tools/testing/selftests/bpf/progs/test_cgroup1_hierarchy.c new file mode 100644 index 0000000000..44628865fe --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_cgroup1_hierarchy.c @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2023 Yafang Shao */ + +#include "vmlinux.h" +#include +#include +#include + +__u32 target_ancestor_level; +__u64 target_ancestor_cgid; +int target_pid, target_hid; + +struct cgroup *bpf_task_get_cgroup1(struct task_struct *task, int hierarchy_id) __ksym; +struct cgroup *bpf_cgroup_ancestor(struct cgroup *cgrp, int level) __ksym; +void bpf_cgroup_release(struct cgroup *cgrp) __ksym; + +static int bpf_link_create_verify(int cmd) +{ + struct cgroup *cgrp, *ancestor; + struct task_struct *task; + int ret = 0; + + if (cmd != BPF_LINK_CREATE) + return 0; + + task = bpf_get_current_task_btf(); + + /* Then it can run in parallel with others */ + if (task->pid != target_pid) + return 0; + + cgrp = bpf_task_get_cgroup1(task, target_hid); + if (!cgrp) + return 0; + + /* Refuse it if its cgid or its ancestor's cgid is the target cgid */ + if (cgrp->kn->id == target_ancestor_cgid) + ret = -1; + + ancestor = bpf_cgroup_ancestor(cgrp, target_ancestor_level); + if (!ancestor) + goto out; + + if (ancestor->kn->id == target_ancestor_cgid) + ret = -1; + bpf_cgroup_release(ancestor); + +out: + bpf_cgroup_release(cgrp); + return ret; +} + +SEC("lsm/bpf") +int BPF_PROG(lsm_run, int cmd, union bpf_attr *attr, unsigned int size) +{ + return bpf_link_create_verify(cmd); +} + +SEC("lsm.s/bpf") +int BPF_PROG(lsm_s_run, int cmd, union bpf_attr *attr, unsigned int size) +{ + return bpf_link_create_verify(cmd); +} + +SEC("fentry") +int BPF_PROG(fentry_run) +{ + return 0; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_core_reloc_kernel.c b/tools/testing/selftests/bpf/progs/test_core_reloc_kernel.c index a17dd83eae..ee4a601dcb 100644 --- a/tools/testing/selftests/bpf/progs/test_core_reloc_kernel.c +++ b/tools/testing/selftests/bpf/progs/test_core_reloc_kernel.c @@ -53,7 +53,7 @@ int test_core_kernel(void *ctx) struct task_struct *task = (void *)bpf_get_current_task(); struct core_reloc_kernel_output *out = (void *)&data.out; uint64_t pid_tgid = bpf_get_current_pid_tgid(); - uint32_t real_tgid = (uint32_t)pid_tgid; + int32_t real_tgid = (int32_t)pid_tgid; int pid, tgid; if (data.my_pid_tgid != pid_tgid) diff --git a/tools/testing/selftests/bpf/progs/test_core_reloc_module.c b/tools/testing/selftests/bpf/progs/test_core_reloc_module.c index f59f175c7b..bcb31ff92d 100644 --- a/tools/testing/selftests/bpf/progs/test_core_reloc_module.c +++ b/tools/testing/selftests/bpf/progs/test_core_reloc_module.c @@ -43,8 +43,8 @@ int BPF_PROG(test_core_module_probed, #if __has_builtin(__builtin_preserve_enum_value) struct core_reloc_module_output *out = (void *)&data.out; __u64 pid_tgid = bpf_get_current_pid_tgid(); - __u32 real_tgid = (__u32)(pid_tgid >> 32); - __u32 real_pid = (__u32)pid_tgid; + __s32 real_tgid = (__s32)(pid_tgid >> 32); + __s32 real_pid = (__s32)pid_tgid; if (data.my_pid_tgid != pid_tgid) return 0; @@ -77,8 +77,8 @@ int BPF_PROG(test_core_module_direct, #if __has_builtin(__builtin_preserve_enum_value) struct core_reloc_module_output *out = (void *)&data.out; __u64 pid_tgid = bpf_get_current_pid_tgid(); - __u32 real_tgid = (__u32)(pid_tgid >> 32); - __u32 real_pid = (__u32)pid_tgid; + __s32 real_tgid = (__s32)(pid_tgid >> 32); + __s32 real_pid = (__s32)pid_tgid; if (data.my_pid_tgid != pid_tgid) return 0; diff --git a/tools/testing/selftests/bpf/progs/test_fill_link_info.c b/tools/testing/selftests/bpf/progs/test_fill_link_info.c index 564f402d56..69509f8bb6 100644 --- a/tools/testing/selftests/bpf/progs/test_fill_link_info.c +++ b/tools/testing/selftests/bpf/progs/test_fill_link_info.c @@ -39,4 +39,10 @@ int BPF_PROG(kmulti_run) return 0; } +SEC("uprobe.multi") +int BPF_PROG(umulti_run) +{ + return 0; +} + char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_fsverity.c b/tools/testing/selftests/bpf/progs/test_fsverity.c new file mode 100644 index 0000000000..9e0f73e818 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_fsverity.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ + +#include "vmlinux.h" +#include +#include +#include "bpf_kfuncs.h" + +char _license[] SEC("license") = "GPL"; + +#ifndef SHA256_DIGEST_SIZE +#define SHA256_DIGEST_SIZE 32 +#endif + +#define SIZEOF_STRUCT_FSVERITY_DIGEST 4 /* sizeof(struct fsverity_digest) */ + +char expected_digest[SIZEOF_STRUCT_FSVERITY_DIGEST + SHA256_DIGEST_SIZE]; +char digest[SIZEOF_STRUCT_FSVERITY_DIGEST + SHA256_DIGEST_SIZE]; +__u32 monitored_pid; +__u32 got_fsverity; +__u32 digest_matches; + +SEC("lsm.s/file_open") +int BPF_PROG(test_file_open, struct file *f) +{ + struct bpf_dynptr digest_ptr; + __u32 pid; + int ret; + int i; + + pid = bpf_get_current_pid_tgid() >> 32; + if (pid != monitored_pid) + return 0; + + bpf_dynptr_from_mem(digest, sizeof(digest), 0, &digest_ptr); + ret = bpf_get_fsverity_digest(f, &digest_ptr); + if (ret < 0) + return 0; + got_fsverity = 1; + + for (i = 0; i < (int)sizeof(digest); i++) { + if (digest[i] != expected_digest[i]) + return 0; + } + + digest_matches = 1; + return 0; +} diff --git a/tools/testing/selftests/bpf/progs/test_get_xattr.c b/tools/testing/selftests/bpf/progs/test_get_xattr.c new file mode 100644 index 0000000000..7eb2a4e5a3 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_get_xattr.c @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ + +#include "vmlinux.h" +#include +#include +#include "bpf_kfuncs.h" + +char _license[] SEC("license") = "GPL"; + +__u32 monitored_pid; +__u32 found_xattr; + +static const char expected_value[] = "hello"; +char value[32]; + +SEC("lsm.s/file_open") +int BPF_PROG(test_file_open, struct file *f) +{ + struct bpf_dynptr value_ptr; + __u32 pid; + int ret; + + pid = bpf_get_current_pid_tgid() >> 32; + if (pid != monitored_pid) + return 0; + + bpf_dynptr_from_mem(value, sizeof(value), 0, &value_ptr); + + ret = bpf_get_file_xattr(f, "user.kfuncs", &value_ptr); + if (ret != sizeof(expected_value)) + return 0; + if (bpf_strncmp(value, ret, expected_value)) + return 0; + found_xattr = 1; + return 0; +} diff --git a/tools/testing/selftests/bpf/progs/test_global_func12.c b/tools/testing/selftests/bpf/progs/test_global_func12.c index 7f159d83c6..6e03d42519 100644 --- a/tools/testing/selftests/bpf/progs/test_global_func12.c +++ b/tools/testing/selftests/bpf/progs/test_global_func12.c @@ -19,5 +19,7 @@ int global_func12(struct __sk_buff *skb) { const struct S s = {.x = skb->len }; - return foo(&s); + foo(&s); + + return 1; } diff --git a/tools/testing/selftests/bpf/progs/test_global_func15.c b/tools/testing/selftests/bpf/progs/test_global_func15.c index b512d6a6c7..b4e089d698 100644 --- a/tools/testing/selftests/bpf/progs/test_global_func15.c +++ b/tools/testing/selftests/bpf/progs/test_global_func15.c @@ -13,7 +13,7 @@ __noinline int foo(unsigned int *v) } SEC("cgroup_skb/ingress") -__failure __msg("At program exit the register R0 has value") +__failure __msg("At program exit the register R0 has ") int global_func15(struct __sk_buff *skb) { unsigned int v = 1; @@ -22,3 +22,35 @@ int global_func15(struct __sk_buff *skb) return v; } + +SEC("cgroup_skb/ingress") +__log_level(2) __flag(BPF_F_TEST_STATE_FREQ) +__failure +/* check that fallthrough code path marks r0 as precise */ +__msg("mark_precise: frame0: regs=r0 stack= before 2: (b7) r0 = 1") +/* check that branch code path marks r0 as precise */ +__msg("mark_precise: frame0: regs=r0 stack= before 0: (85) call bpf_get_prandom_u32#7") +__msg("At program exit the register R0 has ") +__naked int global_func15_tricky_pruning(void) +{ + asm volatile ( + "call %[bpf_get_prandom_u32];" + "if r0 s> 1000 goto 1f;" + "r0 = 1;" + "1:" + "goto +0;" /* checkpoint */ + /* cgroup_skb/ingress program is expected to return [0, 1] + * values, so branch above makes sure that in a fallthrough + * case we have a valid 1 stored in R0 register, but in + * a branch case we assign some random value to R0. So if + * there is something wrong with precision tracking for R0 at + * program exit, we might erronenously prune branch case, + * because R0 in fallthrough case is imprecise (and thus any + * value is valid from POV of verifier is_state_equal() logic) + */ + "exit;" + : + : __imm(bpf_get_prandom_u32) + : __clobber_common + ); +} diff --git a/tools/testing/selftests/bpf/progs/test_global_func5.c b/tools/testing/selftests/bpf/progs/test_global_func5.c index cc55aedaf8..257c0569ff 100644 --- a/tools/testing/selftests/bpf/progs/test_global_func5.c +++ b/tools/testing/selftests/bpf/progs/test_global_func5.c @@ -26,7 +26,7 @@ int f3(int val, struct __sk_buff *skb) } SEC("tc") -__failure __msg("expected pointer to ctx, but got PTR") +__failure __msg("expects pointer to ctx") int global_func5(struct __sk_buff *skb) { return f1(skb) + f2(2, skb) + f3(3, skb); diff --git a/tools/testing/selftests/bpf/progs/test_global_func_ctx_args.c b/tools/testing/selftests/bpf/progs/test_global_func_ctx_args.c index 7faa8eef05..9a06e5eb1f 100644 --- a/tools/testing/selftests/bpf/progs/test_global_func_ctx_args.c +++ b/tools/testing/selftests/bpf/progs/test_global_func_ctx_args.c @@ -102,3 +102,52 @@ int perf_event_ctx(void *ctx) { return perf_event_ctx_subprog(ctx); } + +/* this global subprog can be now called from many types of entry progs, each + * with different context type + */ +__weak int subprog_ctx_tag(void *ctx __arg_ctx) +{ + return bpf_get_stack(ctx, stack, sizeof(stack), 0); +} + +struct my_struct { int x; }; + +__weak int subprog_multi_ctx_tags(void *ctx1 __arg_ctx, + struct my_struct *mem, + void *ctx2 __arg_ctx) +{ + if (!mem) + return 0; + + return bpf_get_stack(ctx1, stack, sizeof(stack), 0) + + mem->x + + bpf_get_stack(ctx2, stack, sizeof(stack), 0); +} + +SEC("?raw_tp") +__success __log_level(2) +int arg_tag_ctx_raw_tp(void *ctx) +{ + struct my_struct x = { .x = 123 }; + + return subprog_ctx_tag(ctx) + subprog_multi_ctx_tags(ctx, &x, ctx); +} + +SEC("?perf_event") +__success __log_level(2) +int arg_tag_ctx_perf(void *ctx) +{ + struct my_struct x = { .x = 123 }; + + return subprog_ctx_tag(ctx) + subprog_multi_ctx_tags(ctx, &x, ctx); +} + +SEC("?kprobe") +__success __log_level(2) +int arg_tag_ctx_kprobe(void *ctx) +{ + struct my_struct x = { .x = 123 }; + + return subprog_ctx_tag(ctx) + subprog_multi_ctx_tags(ctx, &x, ctx); +} diff --git a/tools/testing/selftests/bpf/progs/test_jhash.h b/tools/testing/selftests/bpf/progs/test_jhash.h index c300734d26..ef53559bbb 100644 --- a/tools/testing/selftests/bpf/progs/test_jhash.h +++ b/tools/testing/selftests/bpf/progs/test_jhash.h @@ -69,3 +69,34 @@ u32 jhash(const void *key, u32 length, u32 initval) return c; } + +static __always_inline u32 jhash2(const u32 *k, u32 length, u32 initval) +{ + u32 a, b, c; + + /* Set up the internal state */ + a = b = c = JHASH_INITVAL + (length<<2) + initval; + + /* Handle most of the key */ + while (length > 3) { + a += k[0]; + b += k[1]; + c += k[2]; + __jhash_mix(a, b, c); + length -= 3; + k += 3; + } + + /* Handle the last 3 u32's */ + switch (length) { + case 3: c += k[2]; + case 2: b += k[1]; + case 1: a += k[0]; + __jhash_final(a, b, c); + break; + case 0: /* Nothing left to add */ + break; + } + + return c; +} diff --git a/tools/testing/selftests/bpf/progs/test_sig_in_xattr.c b/tools/testing/selftests/bpf/progs/test_sig_in_xattr.c new file mode 100644 index 0000000000..2f0eb1334d --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_sig_in_xattr.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ + +#include "vmlinux.h" +#include +#include +#include +#include "bpf_kfuncs.h" + +char _license[] SEC("license") = "GPL"; + +#ifndef SHA256_DIGEST_SIZE +#define SHA256_DIGEST_SIZE 32 +#endif + +#define MAX_SIG_SIZE 1024 + +/* By default, "fsverity sign" signs a file with fsverity_formatted_digest + * of the file. fsverity_formatted_digest on the kernel side is only used + * with CONFIG_FS_VERITY_BUILTIN_SIGNATURES. However, BPF LSM doesn't not + * require CONFIG_FS_VERITY_BUILTIN_SIGNATURES, so vmlinux.h may not have + * fsverity_formatted_digest. In this test, we intentionally avoid using + * fsverity_formatted_digest. + * + * Luckily, fsverity_formatted_digest is simply 8-byte magic followed by + * fsverity_digest. We use a char array of size fsverity_formatted_digest + * plus SHA256_DIGEST_SIZE. The magic part of it is filled by user space, + * and the rest of it is filled by bpf_get_fsverity_digest. + * + * Note that, generating signatures based on fsverity_formatted_digest is + * the design choice of this selftest (and "fsverity sign"). With BPF + * LSM, we have the flexibility to generate signature based on other data + * sets, for example, fsverity_digest or only the digest[] part of it. + */ +#define MAGIC_SIZE 8 +#define SIZEOF_STRUCT_FSVERITY_DIGEST 4 /* sizeof(struct fsverity_digest) */ +char digest[MAGIC_SIZE + SIZEOF_STRUCT_FSVERITY_DIGEST + SHA256_DIGEST_SIZE]; + +__u32 monitored_pid; +char sig[MAX_SIG_SIZE]; +__u32 sig_size; +__u32 user_keyring_serial; + +SEC("lsm.s/file_open") +int BPF_PROG(test_file_open, struct file *f) +{ + struct bpf_dynptr digest_ptr, sig_ptr; + struct bpf_key *trusted_keyring; + __u32 pid; + int ret; + + pid = bpf_get_current_pid_tgid() >> 32; + if (pid != monitored_pid) + return 0; + + /* digest_ptr points to fsverity_digest */ + bpf_dynptr_from_mem(digest + MAGIC_SIZE, sizeof(digest) - MAGIC_SIZE, 0, &digest_ptr); + + ret = bpf_get_fsverity_digest(f, &digest_ptr); + /* No verity, allow access */ + if (ret < 0) + return 0; + + /* Move digest_ptr to fsverity_formatted_digest */ + bpf_dynptr_from_mem(digest, sizeof(digest), 0, &digest_ptr); + + /* Read signature from xattr */ + bpf_dynptr_from_mem(sig, sizeof(sig), 0, &sig_ptr); + ret = bpf_get_file_xattr(f, "user.sig", &sig_ptr); + /* No signature, reject access */ + if (ret < 0) + return -EPERM; + + trusted_keyring = bpf_lookup_user_key(user_keyring_serial, 0); + if (!trusted_keyring) + return -ENOENT; + + /* Verify signature */ + ret = bpf_verify_pkcs7_signature(&digest_ptr, &sig_ptr, trusted_keyring); + + bpf_key_put(trusted_keyring); + return ret; +} diff --git a/tools/testing/selftests/bpf/progs/test_skc_to_unix_sock.c b/tools/testing/selftests/bpf/progs/test_skc_to_unix_sock.c index eacda9fe07..4cfa42aa94 100644 --- a/tools/testing/selftests/bpf/progs/test_skc_to_unix_sock.c +++ b/tools/testing/selftests/bpf/progs/test_skc_to_unix_sock.c @@ -29,7 +29,7 @@ int BPF_PROG(unix_listen, struct socket *sock, int backlog) len = unix_sk->addr->len - sizeof(short); path[0] = '@'; for (i = 1; i < len; i++) { - if (i >= sizeof(struct sockaddr_un)) + if (i >= (int)sizeof(struct sockaddr_un)) break; path[i] = unix_sk->addr->name->sun_path[i]; diff --git a/tools/testing/selftests/bpf/progs/test_tunnel_kern.c b/tools/testing/selftests/bpf/progs/test_tunnel_kern.c index f66af753bb..3e436e6f73 100644 --- a/tools/testing/selftests/bpf/progs/test_tunnel_kern.c +++ b/tools/testing/selftests/bpf/progs/test_tunnel_kern.c @@ -6,66 +6,34 @@ * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "vmlinux.h" +#include #include #include +#include "bpf_kfuncs.h" +#include "bpf_tracing_net.h" #define log_err(__ret) bpf_printk("ERROR line:%d ret:%d\n", __LINE__, __ret) -#define VXLAN_UDP_PORT 4789 +#define VXLAN_UDP_PORT 4789 +#define ETH_P_IP 0x0800 +#define PACKET_HOST 0 +#define TUNNEL_CSUM bpf_htons(0x01) +#define TUNNEL_KEY bpf_htons(0x04) /* Only IPv4 address assigned to veth1. * 172.16.1.200 */ #define ASSIGNED_ADDR_VETH1 0xac1001c8 -struct geneve_opt { - __be16 opt_class; - __u8 type; - __u8 length:5; - __u8 r3:1; - __u8 r2:1; - __u8 r1:1; - __u8 opt_data[8]; /* hard-coded to 8 byte */ -}; - -struct vxlanhdr { - __be32 vx_flags; - __be32 vx_vni; -} __attribute__((packed)); - -struct vxlan_metadata { - __u32 gbp; -}; - -struct bpf_fou_encap { - __be16 sport; - __be16 dport; -}; - -enum bpf_fou_encap_type { - FOU_BPF_ENCAP_FOU, - FOU_BPF_ENCAP_GUE, -}; - int bpf_skb_set_fou_encap(struct __sk_buff *skb_ctx, struct bpf_fou_encap *encap, int type) __ksym; int bpf_skb_get_fou_encap(struct __sk_buff *skb_ctx, struct bpf_fou_encap *encap) __ksym; +struct xfrm_state * +bpf_xdp_get_xfrm_state(struct xdp_md *ctx, struct bpf_xfrm_state_opts *opts, + u32 opts__sz) __ksym; +void bpf_xdp_xfrm_state_release(struct xfrm_state *x) __ksym; struct { __uint(type, BPF_MAP_TYPE_ARRAY); @@ -205,9 +173,9 @@ int erspan_set_tunnel(struct __sk_buff *skb) __u8 hwid = 7; md.version = 2; - md.u.md2.dir = direction; - md.u.md2.hwid = hwid & 0xf; - md.u.md2.hwid_upper = (hwid >> 4) & 0x3; + BPF_CORE_WRITE_BITFIELD(&md.u.md2, dir, direction); + BPF_CORE_WRITE_BITFIELD(&md.u.md2, hwid, (hwid & 0xf)); + BPF_CORE_WRITE_BITFIELD(&md.u.md2, hwid_upper, (hwid >> 4) & 0x3); #endif ret = bpf_skb_set_tunnel_opt(skb, &md, sizeof(md)); @@ -246,8 +214,9 @@ int erspan_get_tunnel(struct __sk_buff *skb) bpf_printk("\tindex %x\n", index); #else bpf_printk("\tdirection %d hwid %x timestamp %u\n", - md.u.md2.dir, - (md.u.md2.hwid_upper << 4) + md.u.md2.hwid, + BPF_CORE_READ_BITFIELD(&md.u.md2, dir), + (BPF_CORE_READ_BITFIELD(&md.u.md2, hwid_upper) << 4) + + BPF_CORE_READ_BITFIELD(&md.u.md2, hwid), bpf_ntohl(md.u.md2.timestamp)); #endif @@ -284,9 +253,9 @@ int ip4ip6erspan_set_tunnel(struct __sk_buff *skb) __u8 hwid = 17; md.version = 2; - md.u.md2.dir = direction; - md.u.md2.hwid = hwid & 0xf; - md.u.md2.hwid_upper = (hwid >> 4) & 0x3; + BPF_CORE_WRITE_BITFIELD(&md.u.md2, dir, direction); + BPF_CORE_WRITE_BITFIELD(&md.u.md2, hwid, (hwid & 0xf)); + BPF_CORE_WRITE_BITFIELD(&md.u.md2, hwid_upper, (hwid >> 4) & 0x3); #endif ret = bpf_skb_set_tunnel_opt(skb, &md, sizeof(md)); @@ -326,8 +295,9 @@ int ip4ip6erspan_get_tunnel(struct __sk_buff *skb) bpf_printk("\tindex %x\n", index); #else bpf_printk("\tdirection %d hwid %x timestamp %u\n", - md.u.md2.dir, - (md.u.md2.hwid_upper << 4) + md.u.md2.hwid, + BPF_CORE_READ_BITFIELD(&md.u.md2, dir), + (BPF_CORE_READ_BITFIELD(&md.u.md2, hwid_upper) << 4) + + BPF_CORE_READ_BITFIELD(&md.u.md2, hwid), bpf_ntohl(md.u.md2.timestamp)); #endif @@ -963,6 +933,10 @@ int ip6ip6_get_tunnel(struct __sk_buff *skb) return TC_ACT_OK; } +volatile int xfrm_reqid = 0; +volatile int xfrm_spi = 0; +volatile int xfrm_remote_ip = 0; + SEC("tc") int xfrm_get_state(struct __sk_buff *skb) { @@ -973,10 +947,58 @@ int xfrm_get_state(struct __sk_buff *skb) if (ret < 0) return TC_ACT_OK; - bpf_printk("reqid %d spi 0x%x remote ip 0x%x\n", - x.reqid, bpf_ntohl(x.spi), - bpf_ntohl(x.remote_ipv4)); + xfrm_reqid = x.reqid; + xfrm_spi = bpf_ntohl(x.spi); + xfrm_remote_ip = bpf_ntohl(x.remote_ipv4); + return TC_ACT_OK; } +volatile int xfrm_replay_window = 0; + +SEC("xdp") +int xfrm_get_state_xdp(struct xdp_md *xdp) +{ + struct bpf_xfrm_state_opts opts = {}; + struct xfrm_state *x = NULL; + struct ip_esp_hdr *esph; + struct bpf_dynptr ptr; + u8 esph_buf[8] = {}; + u8 iph_buf[20] = {}; + struct iphdr *iph; + u32 off; + + if (bpf_dynptr_from_xdp(xdp, 0, &ptr)) + goto out; + + off = sizeof(struct ethhdr); + iph = bpf_dynptr_slice(&ptr, off, iph_buf, sizeof(iph_buf)); + if (!iph || iph->protocol != IPPROTO_ESP) + goto out; + + off += sizeof(struct iphdr); + esph = bpf_dynptr_slice(&ptr, off, esph_buf, sizeof(esph_buf)); + if (!esph) + goto out; + + opts.netns_id = BPF_F_CURRENT_NETNS; + opts.daddr.a4 = iph->daddr; + opts.spi = esph->spi; + opts.proto = IPPROTO_ESP; + opts.family = AF_INET; + + x = bpf_xdp_get_xfrm_state(xdp, &opts, sizeof(opts)); + if (!x) + goto out; + + if (!x->replay_esn) + goto out; + + xfrm_replay_window = x->replay_esn->replay_window; +out: + if (x) + bpf_xdp_xfrm_state_release(x); + return XDP_PASS; +} + char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_verify_pkcs7_sig.c b/tools/testing/selftests/bpf/progs/test_verify_pkcs7_sig.c index 7748cc23de..f42e9f3831 100644 --- a/tools/testing/selftests/bpf/progs/test_verify_pkcs7_sig.c +++ b/tools/testing/selftests/bpf/progs/test_verify_pkcs7_sig.c @@ -10,17 +10,11 @@ #include #include #include +#include "bpf_kfuncs.h" #define MAX_DATA_SIZE (1024 * 1024) #define MAX_SIG_SIZE 1024 -extern struct bpf_key *bpf_lookup_user_key(__u32 serial, __u64 flags) __ksym; -extern struct bpf_key *bpf_lookup_system_key(__u64 id) __ksym; -extern void bpf_key_put(struct bpf_key *key) __ksym; -extern int bpf_verify_pkcs7_signature(struct bpf_dynptr *data_ptr, - struct bpf_dynptr *sig_ptr, - struct bpf_key *trusted_keyring) __ksym; - __u32 monitored_pid; __u32 user_keyring_serial; __u64 system_keyring_id; diff --git a/tools/testing/selftests/bpf/progs/test_xdp_do_redirect.c b/tools/testing/selftests/bpf/progs/test_xdp_do_redirect.c index 5baaafed0d..3abf068b84 100644 --- a/tools/testing/selftests/bpf/progs/test_xdp_do_redirect.c +++ b/tools/testing/selftests/bpf/progs/test_xdp_do_redirect.c @@ -38,7 +38,7 @@ int xdp_redirect(struct xdp_md *xdp) if (payload + 1 > data_end) return XDP_ABORTED; - if (xdp->ingress_ifindex != ifindex_in) + if (xdp->ingress_ifindex != (__u32)ifindex_in) return XDP_ABORTED; if (metadata + 1 > data) diff --git a/tools/testing/selftests/bpf/progs/timer.c b/tools/testing/selftests/bpf/progs/timer.c index 8b946c8188..f615da97df 100644 --- a/tools/testing/selftests/bpf/progs/timer.c +++ b/tools/testing/selftests/bpf/progs/timer.c @@ -51,7 +51,8 @@ struct { __uint(max_entries, 1); __type(key, int); __type(value, struct elem); -} abs_timer SEC(".maps"), soft_timer_pinned SEC(".maps"), abs_timer_pinned SEC(".maps"); +} abs_timer SEC(".maps"), soft_timer_pinned SEC(".maps"), abs_timer_pinned SEC(".maps"), + race_array SEC(".maps"); __u64 bss_data; __u64 abs_data; @@ -390,3 +391,34 @@ int BPF_PROG2(test5, int, a) return 0; } + +static int race_timer_callback(void *race_array, int *race_key, struct bpf_timer *timer) +{ + bpf_timer_start(timer, 1000000, 0); + return 0; +} + +SEC("syscall") +int race(void *ctx) +{ + struct bpf_timer *timer; + int err, race_key = 0; + struct elem init; + + __builtin_memset(&init, 0, sizeof(struct elem)); + bpf_map_update_elem(&race_array, &race_key, &init, BPF_ANY); + + timer = bpf_map_lookup_elem(&race_array, &race_key); + if (!timer) + return 1; + + err = bpf_timer_init(timer, &race_array, CLOCK_MONOTONIC); + if (err && err != -EBUSY) + return 1; + + bpf_timer_set_callback(timer, race_timer_callback); + bpf_timer_start(timer, 0, 0); + bpf_timer_cancel(timer); + + return 0; +} diff --git a/tools/testing/selftests/bpf/progs/timer_failure.c b/tools/testing/selftests/bpf/progs/timer_failure.c index 226d33b5a0..0996c2486f 100644 --- a/tools/testing/selftests/bpf/progs/timer_failure.c +++ b/tools/testing/selftests/bpf/progs/timer_failure.c @@ -21,17 +21,38 @@ struct { __type(value, struct elem); } timer_map SEC(".maps"); -static int timer_cb_ret1(void *map, int *key, struct bpf_timer *timer) +__naked __noinline __used +static unsigned long timer_cb_ret_bad() { - if (bpf_get_smp_processor_id() % 2) - return 1; - else - return 0; + asm volatile ( + "call %[bpf_get_prandom_u32];" + "if r0 s> 1000 goto 1f;" + "r0 = 0;" + "1:" + "goto +0;" /* checkpoint */ + /* async callback is expected to return 0, so branch above + * skipping r0 = 0; should lead to a failure, but if exit + * instruction doesn't enforce r0's precision, this callback + * will be successfully verified + */ + "exit;" + : + : __imm(bpf_get_prandom_u32) + : __clobber_common + ); } SEC("fentry/bpf_fentry_test1") -__failure __msg("should have been in (0x0; 0x0)") -int BPF_PROG2(test_ret_1, int, a) +__log_level(2) +__flag(BPF_F_TEST_STATE_FREQ) +__failure +/* check that fallthrough code path marks r0 as precise */ +__msg("mark_precise: frame0: regs=r0 stack= before") +__msg(": (85) call bpf_get_prandom_u32#7") /* anchor message */ +/* check that branch code path marks r0 as precise */ +__msg("mark_precise: frame0: regs=r0 stack= before ") __msg(": (85) call bpf_get_prandom_u32#7") +__msg("should have been in [0, 0]") +long BPF_PROG2(test_bad_ret, int, a) { int key = 0; struct bpf_timer *timer; @@ -39,7 +60,7 @@ int BPF_PROG2(test_ret_1, int, a) timer = bpf_map_lookup_elem(&timer_map, &key); if (timer) { bpf_timer_init(timer, &timer_map, CLOCK_BOOTTIME); - bpf_timer_set_callback(timer, timer_cb_ret1); + bpf_timer_set_callback(timer, timer_cb_ret_bad); bpf_timer_start(timer, 1000, 0); } diff --git a/tools/testing/selftests/bpf/progs/user_ringbuf_fail.c b/tools/testing/selftests/bpf/progs/user_ringbuf_fail.c index 03ee946c6b..11ab25c42c 100644 --- a/tools/testing/selftests/bpf/progs/user_ringbuf_fail.c +++ b/tools/testing/selftests/bpf/progs/user_ringbuf_fail.c @@ -184,7 +184,7 @@ invalid_drain_callback_return(struct bpf_dynptr *dynptr, void *context) * not be able to write to that pointer. */ SEC("?raw_tp") -__failure __msg("At callback return the register R0 has value") +__failure __msg("At callback return the register R0 has ") int user_ringbuf_callback_invalid_return(void *ctx) { bpf_user_ringbuf_drain(&user_ringbuf, invalid_drain_callback_return, NULL, 0); diff --git a/tools/testing/selftests/bpf/progs/verifier_bitfield_write.c b/tools/testing/selftests/bpf/progs/verifier_bitfield_write.c new file mode 100644 index 0000000000..623f130a31 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/verifier_bitfield_write.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include + +#include +#include + +#include "bpf_misc.h" + +struct core_reloc_bitfields { + /* unsigned bitfields */ + uint8_t ub1: 1; + uint8_t ub2: 2; + uint32_t ub7: 7; + /* signed bitfields */ + int8_t sb4: 4; + int32_t sb20: 20; + /* non-bitfields */ + uint32_t u32; + int32_t s32; +} __attribute__((preserve_access_index)); + +SEC("tc") +__description("single CO-RE bitfield roundtrip") +__btf_path("btf__core_reloc_bitfields.bpf.o") +__success +__retval(3) +int single_field_roundtrip(struct __sk_buff *ctx) +{ + struct core_reloc_bitfields bitfields; + + __builtin_memset(&bitfields, 0, sizeof(bitfields)); + BPF_CORE_WRITE_BITFIELD(&bitfields, ub2, 3); + return BPF_CORE_READ_BITFIELD(&bitfields, ub2); +} + +SEC("tc") +__description("multiple CO-RE bitfield roundtrip") +__btf_path("btf__core_reloc_bitfields.bpf.o") +__success +__retval(0x3FD) +int multiple_field_roundtrip(struct __sk_buff *ctx) +{ + struct core_reloc_bitfields bitfields; + uint8_t ub2; + int8_t sb4; + + __builtin_memset(&bitfields, 0, sizeof(bitfields)); + BPF_CORE_WRITE_BITFIELD(&bitfields, ub2, 1); + BPF_CORE_WRITE_BITFIELD(&bitfields, sb4, -1); + + ub2 = BPF_CORE_READ_BITFIELD(&bitfields, ub2); + sb4 = BPF_CORE_READ_BITFIELD(&bitfields, sb4); + + return (((uint8_t)sb4) << 2) | ub2; +} + +SEC("tc") +__description("adjacent CO-RE bitfield roundtrip") +__btf_path("btf__core_reloc_bitfields.bpf.o") +__success +__retval(7) +int adjacent_field_roundtrip(struct __sk_buff *ctx) +{ + struct core_reloc_bitfields bitfields; + uint8_t ub1, ub2; + + __builtin_memset(&bitfields, 0, sizeof(bitfields)); + BPF_CORE_WRITE_BITFIELD(&bitfields, ub1, 1); + BPF_CORE_WRITE_BITFIELD(&bitfields, ub2, 3); + + ub1 = BPF_CORE_READ_BITFIELD(&bitfields, ub1); + ub2 = BPF_CORE_READ_BITFIELD(&bitfields, ub2); + + return (ub2 << 1) | ub1; +} + +SEC("tc") +__description("multibyte CO-RE bitfield roundtrip") +__btf_path("btf__core_reloc_bitfields.bpf.o") +__success +__retval(0x21) +int multibyte_field_roundtrip(struct __sk_buff *ctx) +{ + struct core_reloc_bitfields bitfields; + uint32_t ub7; + uint8_t ub1; + + __builtin_memset(&bitfields, 0, sizeof(bitfields)); + BPF_CORE_WRITE_BITFIELD(&bitfields, ub1, 1); + BPF_CORE_WRITE_BITFIELD(&bitfields, ub7, 16); + + ub1 = BPF_CORE_READ_BITFIELD(&bitfields, ub1); + ub7 = BPF_CORE_READ_BITFIELD(&bitfields, ub7); + + return (ub7 << 1) | ub1; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/verifier_bounds.c b/tools/testing/selftests/bpf/progs/verifier_bounds.c index c5588a14fe..960998f163 100644 --- a/tools/testing/selftests/bpf/progs/verifier_bounds.c +++ b/tools/testing/selftests/bpf/progs/verifier_bounds.c @@ -965,6 +965,7 @@ l0_%=: r0 = 0; \ SEC("xdp") __description("bound check with JMP_JSLT for crossing 64-bit signed boundary") __success __retval(0) +__flag(!BPF_F_TEST_REG_INVARIANTS) /* known invariants violation */ __naked void crossing_64_bit_signed_boundary_2(void) { asm volatile (" \ @@ -1046,6 +1047,7 @@ l0_%=: r0 = 0; \ SEC("xdp") __description("bound check with JMP32_JSLT for crossing 32-bit signed boundary") __success __retval(0) +__flag(!BPF_F_TEST_REG_INVARIANTS) /* known invariants violation */ __naked void crossing_32_bit_signed_boundary_2(void) { asm volatile (" \ @@ -1073,4 +1075,66 @@ l0_%=: r0 = 0; \ : __clobber_all); } +SEC("tc") +__description("bounds check with JMP_NE for reg edge") +__success __retval(0) +__naked void reg_not_equal_const(void) +{ + asm volatile (" \ + r6 = r1; \ + r1 = 0; \ + *(u64*)(r10 - 8) = r1; \ + call %[bpf_get_prandom_u32]; \ + r4 = r0; \ + r4 &= 7; \ + if r4 != 0 goto l0_%=; \ + r0 = 0; \ + exit; \ +l0_%=: r1 = r6; \ + r2 = 0; \ + r3 = r10; \ + r3 += -8; \ + r5 = 0; \ + /* The 4th argument of bpf_skb_store_bytes is defined as \ + * ARG_CONST_SIZE, so 0 is not allowed. The 'r4 != 0' \ + * is providing us this exclusion of zero from initial \ + * [0, 7] range. \ + */ \ + call %[bpf_skb_store_bytes]; \ + r0 = 0; \ + exit; \ +" : + : __imm(bpf_get_prandom_u32), + __imm(bpf_skb_store_bytes) + : __clobber_all); +} + +SEC("tc") +__description("bounds check with JMP_EQ for reg edge") +__success __retval(0) +__naked void reg_equal_const(void) +{ + asm volatile (" \ + r6 = r1; \ + r1 = 0; \ + *(u64*)(r10 - 8) = r1; \ + call %[bpf_get_prandom_u32]; \ + r4 = r0; \ + r4 &= 7; \ + if r4 == 0 goto l0_%=; \ + r1 = r6; \ + r2 = 0; \ + r3 = r10; \ + r3 += -8; \ + r5 = 0; \ + /* Just the same as what we do in reg_not_equal_const() */ \ + call %[bpf_skb_store_bytes]; \ +l0_%=: r0 = 0; \ + exit; \ +" : + : __imm(bpf_get_prandom_u32), + __imm(bpf_skb_store_bytes) + : __clobber_all); +} + char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/verifier_btf_unreliable_prog.c b/tools/testing/selftests/bpf/progs/verifier_btf_unreliable_prog.c new file mode 100644 index 0000000000..36e033a2e0 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/verifier_btf_unreliable_prog.c @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2017 Facebook + +#include "vmlinux.h" +#include +#include +#include +#include "bpf_misc.h" + +struct whatever {}; + +SEC("kprobe") +__success __log_level(2) +/* context type is wrong, making it impossible to freplace this program */ +int btf_unreliable_kprobe(struct whatever *ctx) +{ + return 0; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/verifier_cgroup_inv_retcode.c b/tools/testing/selftests/bpf/progs/verifier_cgroup_inv_retcode.c index d6c4a7f3f7..6e0f349f8f 100644 --- a/tools/testing/selftests/bpf/progs/verifier_cgroup_inv_retcode.c +++ b/tools/testing/selftests/bpf/progs/verifier_cgroup_inv_retcode.c @@ -7,7 +7,7 @@ SEC("cgroup/sock") __description("bpf_exit with invalid return code. test1") -__failure __msg("R0 has value (0x0; 0xffffffff)") +__failure __msg("smin=0 smax=4294967295 should have been in [0, 1]") __naked void with_invalid_return_code_test1(void) { asm volatile (" \ @@ -30,7 +30,7 @@ __naked void with_invalid_return_code_test2(void) SEC("cgroup/sock") __description("bpf_exit with invalid return code. test3") -__failure __msg("R0 has value (0x0; 0x3)") +__failure __msg("smin=0 smax=3 should have been in [0, 1]") __naked void with_invalid_return_code_test3(void) { asm volatile (" \ @@ -53,7 +53,7 @@ __naked void with_invalid_return_code_test4(void) SEC("cgroup/sock") __description("bpf_exit with invalid return code. test5") -__failure __msg("R0 has value (0x2; 0x0)") +__failure __msg("smin=2 smax=2 should have been in [0, 1]") __naked void with_invalid_return_code_test5(void) { asm volatile (" \ @@ -75,7 +75,7 @@ __naked void with_invalid_return_code_test6(void) SEC("cgroup/sock") __description("bpf_exit with invalid return code. test7") -__failure __msg("R0 has unknown scalar value") +__failure __msg("R0 has unknown scalar value should have been in [0, 1]") __naked void with_invalid_return_code_test7(void) { asm volatile (" \ diff --git a/tools/testing/selftests/bpf/progs/verifier_direct_packet_access.c b/tools/testing/selftests/bpf/progs/verifier_direct_packet_access.c index 99a23dea82..be95570ab3 100644 --- a/tools/testing/selftests/bpf/progs/verifier_direct_packet_access.c +++ b/tools/testing/selftests/bpf/progs/verifier_direct_packet_access.c @@ -411,7 +411,7 @@ l0_%=: r0 = 0; \ SEC("tc") __description("direct packet access: test17 (pruning, alignment)") -__failure __msg("misaligned packet access off 2+(0x0; 0x0)+15+-4 size 4") +__failure __msg("misaligned packet access off 2+0+15+-4 size 4") __flag(BPF_F_STRICT_ALIGNMENT) __naked void packet_access_test17_pruning_alignment(void) { diff --git a/tools/testing/selftests/bpf/progs/verifier_global_subprogs.c b/tools/testing/selftests/bpf/progs/verifier_global_subprogs.c new file mode 100644 index 0000000000..67dddd9418 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/verifier_global_subprogs.c @@ -0,0 +1,350 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ + +#include +#include +#include +#include "bpf_misc.h" +#include "xdp_metadata.h" +#include "bpf_kfuncs.h" + +int arr[1]; +int unkn_idx; +const volatile bool call_dead_subprog = false; + +__noinline long global_bad(void) +{ + return arr[unkn_idx]; /* BOOM */ +} + +__noinline long global_good(void) +{ + return arr[0]; +} + +__noinline long global_calls_bad(void) +{ + return global_good() + global_bad() /* does BOOM indirectly */; +} + +__noinline long global_calls_good_only(void) +{ + return global_good(); +} + +__noinline long global_dead(void) +{ + return arr[0] * 2; +} + +SEC("?raw_tp") +__success __log_level(2) +/* main prog is validated completely first */ +__msg("('global_calls_good_only') is global and assumed valid.") +/* eventually global_good() is transitively validated as well */ +__msg("Validating global_good() func") +__msg("('global_good') is safe for any args that match its prototype") +int chained_global_func_calls_success(void) +{ + int sum = 0; + + if (call_dead_subprog) + sum += global_dead(); + return global_calls_good_only() + sum; +} + +SEC("?raw_tp") +__failure __log_level(2) +/* main prog validated successfully first */ +__msg("('global_calls_bad') is global and assumed valid.") +/* eventually we validate global_bad() and fail */ +__msg("Validating global_bad() func") +__msg("math between map_value pointer and register") /* BOOM */ +int chained_global_func_calls_bad(void) +{ + return global_calls_bad(); +} + +/* do out of bounds access forcing verifier to fail verification if this + * global func is called + */ +__noinline int global_unsupp(const int *mem) +{ + if (!mem) + return 0; + return mem[100]; /* BOOM */ +} + +const volatile bool skip_unsupp_global = true; + +SEC("?raw_tp") +__success +int guarded_unsupp_global_called(void) +{ + if (!skip_unsupp_global) + return global_unsupp(NULL); + return 0; +} + +SEC("?raw_tp") +__failure __log_level(2) +__msg("Func#1 ('global_unsupp') is global and assumed valid.") +__msg("Validating global_unsupp() func#1...") +__msg("value is outside of the allowed memory range") +int unguarded_unsupp_global_called(void) +{ + int x = 0; + + return global_unsupp(&x); +} + +long stack[128]; + +__weak int subprog_nullable_ptr_bad(int *p) +{ + return (*p) * 2; /* bad, missing null check */ +} + +SEC("?raw_tp") +__failure __log_level(2) +__msg("invalid mem access 'mem_or_null'") +int arg_tag_nullable_ptr_fail(void *ctx) +{ + int x = 42; + + return subprog_nullable_ptr_bad(&x); +} + +__noinline __weak int subprog_nonnull_ptr_good(int *p1 __arg_nonnull, int *p2 __arg_nonnull) +{ + return (*p1) * (*p2); /* good, no need for NULL checks */ +} + +int x = 47; + +SEC("?raw_tp") +__success __log_level(2) +int arg_tag_nonnull_ptr_good(void *ctx) +{ + int y = 74; + + return subprog_nonnull_ptr_good(&x, &y); +} + +/* this global subprog can be now called from many types of entry progs, each + * with different context type + */ +__weak int subprog_ctx_tag(void *ctx __arg_ctx) +{ + return bpf_get_stack(ctx, stack, sizeof(stack), 0); +} + +__weak int raw_tp_canonical(struct bpf_raw_tracepoint_args *ctx __arg_ctx) +{ + return 0; +} + +__weak int raw_tp_u64_array(u64 *ctx __arg_ctx) +{ + return 0; +} + +SEC("?raw_tp") +__success __log_level(2) +int arg_tag_ctx_raw_tp(void *ctx) +{ + return subprog_ctx_tag(ctx) + raw_tp_canonical(ctx) + raw_tp_u64_array(ctx); +} + +SEC("?raw_tp.w") +__success __log_level(2) +int arg_tag_ctx_raw_tp_writable(void *ctx) +{ + return subprog_ctx_tag(ctx) + raw_tp_canonical(ctx) + raw_tp_u64_array(ctx); +} + +SEC("?tp_btf/sys_enter") +__success __log_level(2) +int arg_tag_ctx_raw_tp_btf(void *ctx) +{ + return subprog_ctx_tag(ctx) + raw_tp_canonical(ctx) + raw_tp_u64_array(ctx); +} + +struct whatever { }; + +__weak int tp_whatever(struct whatever *ctx __arg_ctx) +{ + return 0; +} + +SEC("?tp") +__success __log_level(2) +int arg_tag_ctx_tp(void *ctx) +{ + return subprog_ctx_tag(ctx) + tp_whatever(ctx); +} + +__weak int kprobe_subprog_pt_regs(struct pt_regs *ctx __arg_ctx) +{ + return 0; +} + +__weak int kprobe_subprog_typedef(bpf_user_pt_regs_t *ctx __arg_ctx) +{ + return 0; +} + +SEC("?kprobe") +__success __log_level(2) +int arg_tag_ctx_kprobe(void *ctx) +{ + return subprog_ctx_tag(ctx) + + kprobe_subprog_pt_regs(ctx) + + kprobe_subprog_typedef(ctx); +} + +__weak int perf_subprog_regs( +#if defined(bpf_target_riscv) + struct user_regs_struct *ctx __arg_ctx +#elif defined(bpf_target_s390) + /* user_pt_regs typedef is anonymous struct, so only `void *` works */ + void *ctx __arg_ctx +#elif defined(bpf_target_loongarch) || defined(bpf_target_arm64) || defined(bpf_target_powerpc) + struct user_pt_regs *ctx __arg_ctx +#else + struct pt_regs *ctx __arg_ctx +#endif +) +{ + return 0; +} + +__weak int perf_subprog_typedef(bpf_user_pt_regs_t *ctx __arg_ctx) +{ + return 0; +} + +__weak int perf_subprog_canonical(struct bpf_perf_event_data *ctx __arg_ctx) +{ + return 0; +} + +SEC("?perf_event") +__success __log_level(2) +int arg_tag_ctx_perf(void *ctx) +{ + return subprog_ctx_tag(ctx) + + perf_subprog_regs(ctx) + + perf_subprog_typedef(ctx) + + perf_subprog_canonical(ctx); +} + +__weak int iter_subprog_void(void *ctx __arg_ctx) +{ + return 0; +} + +__weak int iter_subprog_typed(struct bpf_iter__task *ctx __arg_ctx) +{ + return 0; +} + +SEC("?iter/task") +__success __log_level(2) +int arg_tag_ctx_iter_task(struct bpf_iter__task *ctx) +{ + return (iter_subprog_void(ctx) + iter_subprog_typed(ctx)) & 1; +} + +__weak int tracing_subprog_void(void *ctx __arg_ctx) +{ + return 0; +} + +__weak int tracing_subprog_u64(u64 *ctx __arg_ctx) +{ + return 0; +} + +int acc; + +SEC("?fentry/" SYS_PREFIX "sys_nanosleep") +__success __log_level(2) +int BPF_PROG(arg_tag_ctx_fentry) +{ + acc += tracing_subprog_void(ctx) + tracing_subprog_u64(ctx); + return 0; +} + +SEC("?fexit/" SYS_PREFIX "sys_nanosleep") +__success __log_level(2) +int BPF_PROG(arg_tag_ctx_fexit) +{ + acc += tracing_subprog_void(ctx) + tracing_subprog_u64(ctx); + return 0; +} + +SEC("?fmod_ret/" SYS_PREFIX "sys_nanosleep") +__success __log_level(2) +int BPF_PROG(arg_tag_ctx_fmod_ret) +{ + return tracing_subprog_void(ctx) + tracing_subprog_u64(ctx); +} + +SEC("?lsm/bpf") +__success __log_level(2) +int BPF_PROG(arg_tag_ctx_lsm) +{ + return tracing_subprog_void(ctx) + tracing_subprog_u64(ctx); +} + +SEC("?struct_ops/test_1") +__success __log_level(2) +int BPF_PROG(arg_tag_ctx_struct_ops) +{ + return tracing_subprog_void(ctx) + tracing_subprog_u64(ctx); +} + +SEC(".struct_ops") +struct bpf_dummy_ops dummy_1 = { + .test_1 = (void *)arg_tag_ctx_struct_ops, +}; + +SEC("?syscall") +__success __log_level(2) +int arg_tag_ctx_syscall(void *ctx) +{ + return tracing_subprog_void(ctx) + tracing_subprog_u64(ctx) + tp_whatever(ctx); +} + +__weak int subprog_dynptr(struct bpf_dynptr *dptr) +{ + long *d, t, buf[1] = {}; + + d = bpf_dynptr_data(dptr, 0, sizeof(long)); + if (!d) + return 0; + + t = *d + 1; + + d = bpf_dynptr_slice(dptr, 0, &buf, sizeof(long)); + if (!d) + return t; + + t = *d + 2; + + return t; +} + +SEC("?xdp") +__success __log_level(2) +int arg_tag_dynptr(struct xdp_md *ctx) +{ + struct bpf_dynptr dptr; + + bpf_dynptr_from_xdp(ctx, 0, &dptr); + + return subprog_dynptr(&dptr); +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/verifier_gotol.c b/tools/testing/selftests/bpf/progs/verifier_gotol.c index d1edbcff9a..05a329ee45 100644 --- a/tools/testing/selftests/bpf/progs/verifier_gotol.c +++ b/tools/testing/selftests/bpf/progs/verifier_gotol.c @@ -33,6 +33,25 @@ l3_%=: \ : __clobber_all); } +SEC("socket") +__description("gotol, large_imm") +__success __failure_unpriv __retval(40000) +__naked void gotol_large_imm(void) +{ + asm volatile (" \ + gotol 1f; \ +0: \ + r0 = 0; \ + .rept 40000; \ + r0 += 1; \ + .endr; \ + exit; \ +1: gotol 0b; \ +" : + : + : __clobber_all); +} + #else SEC("socket") diff --git a/tools/testing/selftests/bpf/progs/verifier_helper_value_access.c b/tools/testing/selftests/bpf/progs/verifier_helper_value_access.c index 692216c0ad..886498b5e6 100644 --- a/tools/testing/selftests/bpf/progs/verifier_helper_value_access.c +++ b/tools/testing/selftests/bpf/progs/verifier_helper_value_access.c @@ -89,9 +89,14 @@ l0_%=: exit; \ : __clobber_all); } +/* Call a function taking a pointer and a size which doesn't allow the size to + * be zero (i.e. bpf_trace_printk() declares the second argument to be + * ARG_CONST_SIZE, not ARG_CONST_SIZE_OR_ZERO). We attempt to pass zero for the + * size and expect to fail. + */ SEC("tracepoint") __description("helper access to map: empty range") -__failure __msg("invalid access to map value, value_size=48 off=0 size=0") +__failure __msg("R2 invalid zero-sized read: u64=[0,0]") __naked void access_to_map_empty_range(void) { asm volatile (" \ @@ -113,6 +118,38 @@ l0_%=: exit; \ : __clobber_all); } +/* Like the test above, but this time the size register is not known to be zero; + * its lower-bound is zero though, which is still unacceptable. + */ +SEC("tracepoint") +__description("helper access to map: possibly-empty ange") +__failure __msg("R2 invalid zero-sized read: u64=[0,4]") +__naked void access_to_map_possibly_empty_range(void) +{ + asm volatile (" \ + r2 = r10; \ + r2 += -8; \ + r1 = 0; \ + *(u64*)(r2 + 0) = r1; \ + r1 = %[map_hash_48b] ll; \ + call %[bpf_map_lookup_elem]; \ + if r0 == 0 goto l0_%=; \ + r1 = r0; \ + /* Read an unknown value */ \ + r7 = *(u64*)(r0 + 0); \ + /* Make it small and positive, to avoid other errors */ \ + r7 &= 4; \ + r2 = 0; \ + r2 += r7; \ + call %[bpf_trace_printk]; \ +l0_%=: exit; \ +" : + : __imm(bpf_map_lookup_elem), + __imm(bpf_trace_printk), + __imm_addr(map_hash_48b) + : __clobber_all); +} + SEC("tracepoint") __description("helper access to map: out-of-bound range") __failure __msg("invalid access to map value, value_size=48 off=0 size=56") @@ -221,7 +258,7 @@ l0_%=: exit; \ SEC("tracepoint") __description("helper access to adjusted map (via const imm): empty range") -__failure __msg("invalid access to map value, value_size=48 off=4 size=0") +__failure __msg("R2 invalid zero-sized read") __naked void via_const_imm_empty_range(void) { asm volatile (" \ @@ -386,7 +423,7 @@ l0_%=: exit; \ SEC("tracepoint") __description("helper access to adjusted map (via const reg): empty range") -__failure __msg("R1 min value is outside of the allowed memory range") +__failure __msg("R2 invalid zero-sized read") __naked void via_const_reg_empty_range(void) { asm volatile (" \ @@ -556,7 +593,7 @@ l0_%=: exit; \ SEC("tracepoint") __description("helper access to adjusted map (via variable): empty range") -__failure __msg("R1 min value is outside of the allowed memory range") +__failure __msg("R2 invalid zero-sized read") __naked void map_via_variable_empty_range(void) { asm volatile (" \ diff --git a/tools/testing/selftests/bpf/progs/verifier_int_ptr.c b/tools/testing/selftests/bpf/progs/verifier_int_ptr.c index 589e8270de..9fc3fae5cd 100644 --- a/tools/testing/selftests/bpf/progs/verifier_int_ptr.c +++ b/tools/testing/selftests/bpf/progs/verifier_int_ptr.c @@ -68,7 +68,7 @@ __naked void ptr_to_long_half_uninitialized(void) SEC("cgroup/sysctl") __description("ARG_PTR_TO_LONG misaligned") -__failure __msg("misaligned stack access off (0x0; 0x0)+-20+0 size 8") +__failure __msg("misaligned stack access off 0+-20+0 size 8") __naked void arg_ptr_to_long_misaligned(void) { asm volatile (" \ diff --git a/tools/testing/selftests/bpf/progs/verifier_iterating_callbacks.c b/tools/testing/selftests/bpf/progs/verifier_iterating_callbacks.c index 5905e036e0..a955a63582 100644 --- a/tools/testing/selftests/bpf/progs/verifier_iterating_callbacks.c +++ b/tools/testing/selftests/bpf/progs/verifier_iterating_callbacks.c @@ -239,4 +239,74 @@ int bpf_loop_iter_limit_nested(void *unused) return 1000 * a + b + c; } +struct iter_limit_bug_ctx { + __u64 a; + __u64 b; + __u64 c; +}; + +static __naked void iter_limit_bug_cb(void) +{ + /* This is the same as C code below, but written + * in assembly to control which branches are fall-through. + * + * switch (bpf_get_prandom_u32()) { + * case 1: ctx->a = 42; break; + * case 2: ctx->b = 42; break; + * default: ctx->c = 42; break; + * } + */ + asm volatile ( + "r9 = r2;" + "call %[bpf_get_prandom_u32];" + "r1 = r0;" + "r2 = 42;" + "r0 = 0;" + "if r1 == 0x1 goto 1f;" + "if r1 == 0x2 goto 2f;" + "*(u64 *)(r9 + 16) = r2;" + "exit;" + "1: *(u64 *)(r9 + 0) = r2;" + "exit;" + "2: *(u64 *)(r9 + 8) = r2;" + "exit;" + : + : __imm(bpf_get_prandom_u32) + : __clobber_all + ); +} + +SEC("tc") +__failure +__flag(BPF_F_TEST_STATE_FREQ) +int iter_limit_bug(struct __sk_buff *skb) +{ + struct iter_limit_bug_ctx ctx = { 7, 7, 7 }; + + bpf_loop(2, iter_limit_bug_cb, &ctx, 0); + + /* This is the same as C code below, + * written in assembly to guarantee checks order. + * + * if (ctx.a == 42 && ctx.b == 42 && ctx.c == 7) + * asm volatile("r1 /= 0;":::"r1"); + */ + asm volatile ( + "r1 = *(u64 *)%[ctx_a];" + "if r1 != 42 goto 1f;" + "r1 = *(u64 *)%[ctx_b];" + "if r1 != 42 goto 1f;" + "r1 = *(u64 *)%[ctx_c];" + "if r1 != 7 goto 1f;" + "r1 /= 0;" + "1:" + : + : [ctx_a]"m"(ctx.a), + [ctx_b]"m"(ctx.b), + [ctx_c]"m"(ctx.c) + : "r1" + ); + return 0; +} + char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/verifier_netfilter_retcode.c b/tools/testing/selftests/bpf/progs/verifier_netfilter_retcode.c index 353ae6da00..e1ffa5d32f 100644 --- a/tools/testing/selftests/bpf/progs/verifier_netfilter_retcode.c +++ b/tools/testing/selftests/bpf/progs/verifier_netfilter_retcode.c @@ -39,7 +39,7 @@ __naked void with_valid_return_code_test3(void) SEC("netfilter") __description("bpf_exit with invalid return code. test4") -__failure __msg("R0 has value (0x2; 0x0)") +__failure __msg("R0 has smin=2 smax=2 should have been in [0, 1]") __naked void with_invalid_return_code_test4(void) { asm volatile (" \ diff --git a/tools/testing/selftests/bpf/progs/verifier_raw_stack.c b/tools/testing/selftests/bpf/progs/verifier_raw_stack.c index f67390224a..7cc83acac7 100644 --- a/tools/testing/selftests/bpf/progs/verifier_raw_stack.c +++ b/tools/testing/selftests/bpf/progs/verifier_raw_stack.c @@ -64,7 +64,7 @@ __naked void load_bytes_negative_len_2(void) SEC("tc") __description("raw_stack: skb_load_bytes, zero len") -__failure __msg("invalid zero-sized read") +__failure __msg("R4 invalid zero-sized read: u64=[0,0]") __naked void skb_load_bytes_zero_len(void) { asm volatile (" \ diff --git a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c index 6115520154..39fe3372e0 100644 --- a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c +++ b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c @@ -4,6 +4,7 @@ #include #include #include "bpf_misc.h" +#include <../../../tools/include/linux/filter.h> struct { __uint(type, BPF_MAP_TYPE_RINGBUF); @@ -450,4 +451,290 @@ l0_%=: r1 >>= 16; \ : __clobber_all); } +SEC("raw_tp") +__log_level(2) +__success +__msg("fp-8=0m??mmmm") +__msg("fp-16=00mm??mm") +__msg("fp-24=00mm???m") +__naked void spill_subregs_preserve_stack_zero(void) +{ + asm volatile ( + "call %[bpf_get_prandom_u32];" + + /* 32-bit subreg spill with ZERO, MISC, and INVALID */ + ".8byte %[fp1_u8_st_zero];" /* ZERO, LLVM-18+: *(u8 *)(r10 -1) = 0; */ + "*(u8 *)(r10 -2) = r0;" /* MISC */ + /* fp-3 and fp-4 stay INVALID */ + "*(u32 *)(r10 -8) = r0;" + + /* 16-bit subreg spill with ZERO, MISC, and INVALID */ + ".8byte %[fp10_u16_st_zero];" /* ZERO, LLVM-18+: *(u16 *)(r10 -10) = 0; */ + "*(u16 *)(r10 -12) = r0;" /* MISC */ + /* fp-13 and fp-14 stay INVALID */ + "*(u16 *)(r10 -16) = r0;" + + /* 8-bit subreg spill with ZERO, MISC, and INVALID */ + ".8byte %[fp18_u16_st_zero];" /* ZERO, LLVM-18+: *(u16 *)(r18 -10) = 0; */ + "*(u16 *)(r10 -20) = r0;" /* MISC */ + /* fp-21, fp-22, and fp-23 stay INVALID */ + "*(u8 *)(r10 -24) = r0;" + + "r0 = 0;" + "exit;" + : + : __imm(bpf_get_prandom_u32), + __imm_insn(fp1_u8_st_zero, BPF_ST_MEM(BPF_B, BPF_REG_FP, -1, 0)), + __imm_insn(fp10_u16_st_zero, BPF_ST_MEM(BPF_H, BPF_REG_FP, -10, 0)), + __imm_insn(fp18_u16_st_zero, BPF_ST_MEM(BPF_H, BPF_REG_FP, -18, 0)) + : __clobber_all); +} + +char single_byte_buf[1] SEC(".data.single_byte_buf"); + +SEC("raw_tp") +__log_level(2) +__success +/* make sure fp-8 is all STACK_ZERO */ +__msg("2: (7a) *(u64 *)(r10 -8) = 0 ; R10=fp0 fp-8_w=00000000") +/* but fp-16 is spilled IMPRECISE zero const reg */ +__msg("4: (7b) *(u64 *)(r10 -16) = r0 ; R0_w=0 R10=fp0 fp-16_w=0") +/* validate that assigning R2 from STACK_ZERO doesn't mark register + * precise immediately; if necessary, it will be marked precise later + */ +__msg("6: (71) r2 = *(u8 *)(r10 -1) ; R2_w=0 R10=fp0 fp-8_w=00000000") +/* similarly, when R2 is assigned from spilled register, it is initially + * imprecise, but will be marked precise later once it is used in precise context + */ +__msg("10: (71) r2 = *(u8 *)(r10 -9) ; R2_w=0 R10=fp0 fp-16_w=0") +__msg("11: (0f) r1 += r2") +__msg("mark_precise: frame0: last_idx 11 first_idx 0 subseq_idx -1") +__msg("mark_precise: frame0: regs=r2 stack= before 10: (71) r2 = *(u8 *)(r10 -9)") +__msg("mark_precise: frame0: regs= stack=-16 before 9: (bf) r1 = r6") +__msg("mark_precise: frame0: regs= stack=-16 before 8: (73) *(u8 *)(r1 +0) = r2") +__msg("mark_precise: frame0: regs= stack=-16 before 7: (0f) r1 += r2") +__msg("mark_precise: frame0: regs= stack=-16 before 6: (71) r2 = *(u8 *)(r10 -1)") +__msg("mark_precise: frame0: regs= stack=-16 before 5: (bf) r1 = r6") +__msg("mark_precise: frame0: regs= stack=-16 before 4: (7b) *(u64 *)(r10 -16) = r0") +__msg("mark_precise: frame0: regs=r0 stack= before 3: (b7) r0 = 0") +__naked void partial_stack_load_preserves_zeros(void) +{ + asm volatile ( + /* fp-8 is all STACK_ZERO */ + ".8byte %[fp8_st_zero];" /* LLVM-18+: *(u64 *)(r10 -8) = 0; */ + + /* fp-16 is const zero register */ + "r0 = 0;" + "*(u64 *)(r10 -16) = r0;" + + /* load single U8 from non-aligned STACK_ZERO slot */ + "r1 = %[single_byte_buf];" + "r2 = *(u8 *)(r10 -1);" + "r1 += r2;" + "*(u8 *)(r1 + 0) = r2;" /* this should be fine */ + + /* load single U8 from non-aligned ZERO REG slot */ + "r1 = %[single_byte_buf];" + "r2 = *(u8 *)(r10 -9);" + "r1 += r2;" + "*(u8 *)(r1 + 0) = r2;" /* this should be fine */ + + /* load single U16 from non-aligned STACK_ZERO slot */ + "r1 = %[single_byte_buf];" + "r2 = *(u16 *)(r10 -2);" + "r1 += r2;" + "*(u8 *)(r1 + 0) = r2;" /* this should be fine */ + + /* load single U16 from non-aligned ZERO REG slot */ + "r1 = %[single_byte_buf];" + "r2 = *(u16 *)(r10 -10);" + "r1 += r2;" + "*(u8 *)(r1 + 0) = r2;" /* this should be fine */ + + /* load single U32 from non-aligned STACK_ZERO slot */ + "r1 = %[single_byte_buf];" + "r2 = *(u32 *)(r10 -4);" + "r1 += r2;" + "*(u8 *)(r1 + 0) = r2;" /* this should be fine */ + + /* load single U32 from non-aligned ZERO REG slot */ + "r1 = %[single_byte_buf];" + "r2 = *(u32 *)(r10 -12);" + "r1 += r2;" + "*(u8 *)(r1 + 0) = r2;" /* this should be fine */ + + /* for completeness, load U64 from STACK_ZERO slot */ + "r1 = %[single_byte_buf];" + "r2 = *(u64 *)(r10 -8);" + "r1 += r2;" + "*(u8 *)(r1 + 0) = r2;" /* this should be fine */ + + /* for completeness, load U64 from ZERO REG slot */ + "r1 = %[single_byte_buf];" + "r2 = *(u64 *)(r10 -16);" + "r1 += r2;" + "*(u8 *)(r1 + 0) = r2;" /* this should be fine */ + + "r0 = 0;" + "exit;" + : + : __imm_ptr(single_byte_buf), + __imm_insn(fp8_st_zero, BPF_ST_MEM(BPF_DW, BPF_REG_FP, -8, 0)) + : __clobber_common); +} + +char two_byte_buf[2] SEC(".data.two_byte_buf"); + +SEC("raw_tp") +__log_level(2) __flag(BPF_F_TEST_STATE_FREQ) +__success +/* make sure fp-8 is IMPRECISE fake register spill */ +__msg("3: (7a) *(u64 *)(r10 -8) = 1 ; R10=fp0 fp-8_w=1") +/* and fp-16 is spilled IMPRECISE const reg */ +__msg("5: (7b) *(u64 *)(r10 -16) = r0 ; R0_w=1 R10=fp0 fp-16_w=1") +/* validate load from fp-8, which was initialized using BPF_ST_MEM */ +__msg("8: (79) r2 = *(u64 *)(r10 -8) ; R2_w=1 R10=fp0 fp-8=1") +__msg("9: (0f) r1 += r2") +__msg("mark_precise: frame0: last_idx 9 first_idx 7 subseq_idx -1") +__msg("mark_precise: frame0: regs=r2 stack= before 8: (79) r2 = *(u64 *)(r10 -8)") +__msg("mark_precise: frame0: regs= stack=-8 before 7: (bf) r1 = r6") +/* note, fp-8 is precise, fp-16 is not yet precise, we'll get there */ +__msg("mark_precise: frame0: parent state regs= stack=-8: R0_w=1 R1=ctx() R6_r=map_value(map=.data.two_byte_,ks=4,vs=2) R10=fp0 fp-8_rw=P1 fp-16_w=1") +__msg("mark_precise: frame0: last_idx 6 first_idx 3 subseq_idx 7") +__msg("mark_precise: frame0: regs= stack=-8 before 6: (05) goto pc+0") +__msg("mark_precise: frame0: regs= stack=-8 before 5: (7b) *(u64 *)(r10 -16) = r0") +__msg("mark_precise: frame0: regs= stack=-8 before 4: (b7) r0 = 1") +__msg("mark_precise: frame0: regs= stack=-8 before 3: (7a) *(u64 *)(r10 -8) = 1") +__msg("10: R1_w=map_value(map=.data.two_byte_,ks=4,vs=2,off=1) R2_w=1") +/* validate load from fp-16, which was initialized using BPF_STX_MEM */ +__msg("12: (79) r2 = *(u64 *)(r10 -16) ; R2_w=1 R10=fp0 fp-16=1") +__msg("13: (0f) r1 += r2") +__msg("mark_precise: frame0: last_idx 13 first_idx 7 subseq_idx -1") +__msg("mark_precise: frame0: regs=r2 stack= before 12: (79) r2 = *(u64 *)(r10 -16)") +__msg("mark_precise: frame0: regs= stack=-16 before 11: (bf) r1 = r6") +__msg("mark_precise: frame0: regs= stack=-16 before 10: (73) *(u8 *)(r1 +0) = r2") +__msg("mark_precise: frame0: regs= stack=-16 before 9: (0f) r1 += r2") +__msg("mark_precise: frame0: regs= stack=-16 before 8: (79) r2 = *(u64 *)(r10 -8)") +__msg("mark_precise: frame0: regs= stack=-16 before 7: (bf) r1 = r6") +/* now both fp-8 and fp-16 are precise, very good */ +__msg("mark_precise: frame0: parent state regs= stack=-16: R0_w=1 R1=ctx() R6_r=map_value(map=.data.two_byte_,ks=4,vs=2) R10=fp0 fp-8_rw=P1 fp-16_rw=P1") +__msg("mark_precise: frame0: last_idx 6 first_idx 3 subseq_idx 7") +__msg("mark_precise: frame0: regs= stack=-16 before 6: (05) goto pc+0") +__msg("mark_precise: frame0: regs= stack=-16 before 5: (7b) *(u64 *)(r10 -16) = r0") +__msg("mark_precise: frame0: regs=r0 stack= before 4: (b7) r0 = 1") +__msg("14: R1_w=map_value(map=.data.two_byte_,ks=4,vs=2,off=1) R2_w=1") +__naked void stack_load_preserves_const_precision(void) +{ + asm volatile ( + /* establish checkpoint with state that has no stack slots; + * if we bubble up to this state without finding desired stack + * slot, then it's a bug and should be caught + */ + "goto +0;" + + /* fp-8 is const 1 *fake* register */ + ".8byte %[fp8_st_one];" /* LLVM-18+: *(u64 *)(r10 -8) = 1; */ + + /* fp-16 is const 1 register */ + "r0 = 1;" + "*(u64 *)(r10 -16) = r0;" + + /* force checkpoint to check precision marks preserved in parent states */ + "goto +0;" + + /* load single U64 from aligned FAKE_REG=1 slot */ + "r1 = %[two_byte_buf];" + "r2 = *(u64 *)(r10 -8);" + "r1 += r2;" + "*(u8 *)(r1 + 0) = r2;" /* this should be fine */ + + /* load single U64 from aligned REG=1 slot */ + "r1 = %[two_byte_buf];" + "r2 = *(u64 *)(r10 -16);" + "r1 += r2;" + "*(u8 *)(r1 + 0) = r2;" /* this should be fine */ + + "r0 = 0;" + "exit;" + : + : __imm_ptr(two_byte_buf), + __imm_insn(fp8_st_one, BPF_ST_MEM(BPF_DW, BPF_REG_FP, -8, 1)) + : __clobber_common); +} + +SEC("raw_tp") +__log_level(2) __flag(BPF_F_TEST_STATE_FREQ) +__success +/* make sure fp-8 is 32-bit FAKE subregister spill */ +__msg("3: (62) *(u32 *)(r10 -8) = 1 ; R10=fp0 fp-8=????1") +/* but fp-16 is spilled IMPRECISE zero const reg */ +__msg("5: (63) *(u32 *)(r10 -16) = r0 ; R0_w=1 R10=fp0 fp-16=????1") +/* validate load from fp-8, which was initialized using BPF_ST_MEM */ +__msg("8: (61) r2 = *(u32 *)(r10 -8) ; R2_w=1 R10=fp0 fp-8=????1") +__msg("9: (0f) r1 += r2") +__msg("mark_precise: frame0: last_idx 9 first_idx 7 subseq_idx -1") +__msg("mark_precise: frame0: regs=r2 stack= before 8: (61) r2 = *(u32 *)(r10 -8)") +__msg("mark_precise: frame0: regs= stack=-8 before 7: (bf) r1 = r6") +__msg("mark_precise: frame0: parent state regs= stack=-8: R0_w=1 R1=ctx() R6_r=map_value(map=.data.two_byte_,ks=4,vs=2) R10=fp0 fp-8_r=????P1 fp-16=????1") +__msg("mark_precise: frame0: last_idx 6 first_idx 3 subseq_idx 7") +__msg("mark_precise: frame0: regs= stack=-8 before 6: (05) goto pc+0") +__msg("mark_precise: frame0: regs= stack=-8 before 5: (63) *(u32 *)(r10 -16) = r0") +__msg("mark_precise: frame0: regs= stack=-8 before 4: (b7) r0 = 1") +__msg("mark_precise: frame0: regs= stack=-8 before 3: (62) *(u32 *)(r10 -8) = 1") +__msg("10: R1_w=map_value(map=.data.two_byte_,ks=4,vs=2,off=1) R2_w=1") +/* validate load from fp-16, which was initialized using BPF_STX_MEM */ +__msg("12: (61) r2 = *(u32 *)(r10 -16) ; R2_w=1 R10=fp0 fp-16=????1") +__msg("13: (0f) r1 += r2") +__msg("mark_precise: frame0: last_idx 13 first_idx 7 subseq_idx -1") +__msg("mark_precise: frame0: regs=r2 stack= before 12: (61) r2 = *(u32 *)(r10 -16)") +__msg("mark_precise: frame0: regs= stack=-16 before 11: (bf) r1 = r6") +__msg("mark_precise: frame0: regs= stack=-16 before 10: (73) *(u8 *)(r1 +0) = r2") +__msg("mark_precise: frame0: regs= stack=-16 before 9: (0f) r1 += r2") +__msg("mark_precise: frame0: regs= stack=-16 before 8: (61) r2 = *(u32 *)(r10 -8)") +__msg("mark_precise: frame0: regs= stack=-16 before 7: (bf) r1 = r6") +__msg("mark_precise: frame0: parent state regs= stack=-16: R0_w=1 R1=ctx() R6_r=map_value(map=.data.two_byte_,ks=4,vs=2) R10=fp0 fp-8_r=????P1 fp-16_r=????P1") +__msg("mark_precise: frame0: last_idx 6 first_idx 3 subseq_idx 7") +__msg("mark_precise: frame0: regs= stack=-16 before 6: (05) goto pc+0") +__msg("mark_precise: frame0: regs= stack=-16 before 5: (63) *(u32 *)(r10 -16) = r0") +__msg("mark_precise: frame0: regs=r0 stack= before 4: (b7) r0 = 1") +__msg("14: R1_w=map_value(map=.data.two_byte_,ks=4,vs=2,off=1) R2_w=1") +__naked void stack_load_preserves_const_precision_subreg(void) +{ + asm volatile ( + /* establish checkpoint with state that has no stack slots; + * if we bubble up to this state without finding desired stack + * slot, then it's a bug and should be caught + */ + "goto +0;" + + /* fp-8 is const 1 *fake* SUB-register */ + ".8byte %[fp8_st_one];" /* LLVM-18+: *(u32 *)(r10 -8) = 1; */ + + /* fp-16 is const 1 SUB-register */ + "r0 = 1;" + "*(u32 *)(r10 -16) = r0;" + + /* force checkpoint to check precision marks preserved in parent states */ + "goto +0;" + + /* load single U32 from aligned FAKE_REG=1 slot */ + "r1 = %[two_byte_buf];" + "r2 = *(u32 *)(r10 -8);" + "r1 += r2;" + "*(u8 *)(r1 + 0) = r2;" /* this should be fine */ + + /* load single U32 from aligned REG=1 slot */ + "r1 = %[two_byte_buf];" + "r2 = *(u32 *)(r10 -16);" + "r1 += r2;" + "*(u8 *)(r1 + 0) = r2;" /* this should be fine */ + + "r0 = 0;" + "exit;" + : + : __imm_ptr(two_byte_buf), + __imm_insn(fp8_st_one, BPF_ST_MEM(BPF_W, BPF_REG_FP, -8, 1)) /* 32-bit spill */ + : __clobber_common); +} + char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/verifier_stack_ptr.c b/tools/testing/selftests/bpf/progs/verifier_stack_ptr.c index e0f77e3e78..417c61cd4b 100644 --- a/tools/testing/selftests/bpf/progs/verifier_stack_ptr.c +++ b/tools/testing/selftests/bpf/progs/verifier_stack_ptr.c @@ -37,7 +37,7 @@ __naked void ptr_to_stack_store_load(void) SEC("socket") __description("PTR_TO_STACK store/load - bad alignment on off") -__failure __msg("misaligned stack access off (0x0; 0x0)+-8+2 size 8") +__failure __msg("misaligned stack access off 0+-8+2 size 8") __failure_unpriv __naked void load_bad_alignment_on_off(void) { @@ -53,7 +53,7 @@ __naked void load_bad_alignment_on_off(void) SEC("socket") __description("PTR_TO_STACK store/load - bad alignment on reg") -__failure __msg("misaligned stack access off (0x0; 0x0)+-10+8 size 8") +__failure __msg("misaligned stack access off 0+-10+8 size 8") __failure_unpriv __naked void load_bad_alignment_on_reg(void) { diff --git a/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c b/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c index f61d623b1c..6f5d19665c 100644 --- a/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c +++ b/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c @@ -117,6 +117,56 @@ __naked int global_subprog_result_precise(void) ); } +__naked __noinline __used +static unsigned long loop_callback_bad() +{ + /* bpf_loop() callback that can return values outside of [0, 1] range */ + asm volatile ( + "call %[bpf_get_prandom_u32];" + "if r0 s> 1000 goto 1f;" + "r0 = 0;" + "1:" + "goto +0;" /* checkpoint */ + /* bpf_loop() expects [0, 1] values, so branch above skipping + * r0 = 0; should lead to a failure, but if exit instruction + * doesn't enforce r0's precision, this callback will be + * successfully verified + */ + "exit;" + : + : __imm(bpf_get_prandom_u32) + : __clobber_common + ); +} + +SEC("?raw_tp") +__failure __log_level(2) +__flag(BPF_F_TEST_STATE_FREQ) +/* check that fallthrough code path marks r0 as precise */ +__msg("mark_precise: frame1: regs=r0 stack= before 11: (b7) r0 = 0") +/* check that we have branch code path doing its own validation */ +__msg("from 10 to 12: frame1: R0=scalar(smin=umin=1001") +/* check that branch code path marks r0 as precise, before failing */ +__msg("mark_precise: frame1: regs=r0 stack= before 9: (85) call bpf_get_prandom_u32#7") +__msg("At callback return the register R0 has smin=1001 should have been in [0, 1]") +__naked int callback_precise_return_fail(void) +{ + asm volatile ( + "r1 = 1;" /* nr_loops */ + "r2 = %[loop_callback_bad];" /* callback_fn */ + "r3 = 0;" /* callback_ctx */ + "r4 = 0;" /* flags */ + "call %[bpf_loop];" + + "r0 = 0;" + "exit;" + : + : __imm_ptr(loop_callback_bad), + __imm(bpf_loop) + : __clobber_common + ); +} + SEC("?raw_tp") __success __log_level(2) /* First simulated path does not include callback body, @@ -370,12 +420,10 @@ __naked int parent_stack_slot_precise(void) SEC("?raw_tp") __success __log_level(2) __msg("9: (0f) r1 += r6") -__msg("mark_precise: frame0: last_idx 9 first_idx 6") +__msg("mark_precise: frame0: last_idx 9 first_idx 0") __msg("mark_precise: frame0: regs=r6 stack= before 8: (bf) r1 = r7") __msg("mark_precise: frame0: regs=r6 stack= before 7: (27) r6 *= 4") __msg("mark_precise: frame0: regs=r6 stack= before 6: (79) r6 = *(u64 *)(r10 -8)") -__msg("mark_precise: frame0: parent state regs= stack=-8:") -__msg("mark_precise: frame0: last_idx 5 first_idx 0") __msg("mark_precise: frame0: regs= stack=-8 before 5: (85) call pc+6") __msg("mark_precise: frame0: regs= stack=-8 before 4: (b7) r1 = 0") __msg("mark_precise: frame0: regs= stack=-8 before 3: (7b) *(u64 *)(r10 -8) = r6") @@ -541,11 +589,24 @@ static __u64 subprog_spill_reg_precise(void) SEC("?raw_tp") __success __log_level(2) -/* precision backtracking can't currently handle stack access not through r10, - * so we won't be able to mark stack slot fp-8 as precise, and so will - * fallback to forcing all as precise - */ -__msg("mark_precise: frame0: falling back to forcing all scalars precise") +__msg("10: (0f) r1 += r7") +__msg("mark_precise: frame0: last_idx 10 first_idx 7 subseq_idx -1") +__msg("mark_precise: frame0: regs=r7 stack= before 9: (bf) r1 = r8") +__msg("mark_precise: frame0: regs=r7 stack= before 8: (27) r7 *= 4") +__msg("mark_precise: frame0: regs=r7 stack= before 7: (79) r7 = *(u64 *)(r10 -8)") +__msg("mark_precise: frame0: parent state regs= stack=-8: R0_w=2 R6_w=1 R8_rw=map_value(map=.data.vals,ks=4,vs=16) R10=fp0 fp-8_rw=P1") +__msg("mark_precise: frame0: last_idx 18 first_idx 0 subseq_idx 7") +__msg("mark_precise: frame0: regs= stack=-8 before 18: (95) exit") +__msg("mark_precise: frame1: regs= stack= before 17: (0f) r0 += r2") +__msg("mark_precise: frame1: regs= stack= before 16: (79) r2 = *(u64 *)(r1 +0)") +__msg("mark_precise: frame1: regs= stack= before 15: (79) r0 = *(u64 *)(r10 -16)") +__msg("mark_precise: frame1: regs= stack= before 14: (7b) *(u64 *)(r10 -16) = r2") +__msg("mark_precise: frame1: regs= stack= before 13: (7b) *(u64 *)(r1 +0) = r2") +__msg("mark_precise: frame1: regs=r2 stack= before 6: (85) call pc+6") +__msg("mark_precise: frame0: regs=r2 stack= before 5: (bf) r2 = r6") +__msg("mark_precise: frame0: regs=r6 stack= before 4: (07) r1 += -8") +__msg("mark_precise: frame0: regs=r6 stack= before 3: (bf) r1 = r10") +__msg("mark_precise: frame0: regs=r6 stack= before 2: (b7) r6 = 1") __naked int subprog_spill_into_parent_stack_slot_precise(void) { asm volatile ( @@ -580,14 +641,68 @@ __naked int subprog_spill_into_parent_stack_slot_precise(void) ); } -__naked __noinline __used -static __u64 subprog_with_checkpoint(void) +SEC("?raw_tp") +__success __log_level(2) +__msg("17: (0f) r1 += r0") +__msg("mark_precise: frame0: last_idx 17 first_idx 0 subseq_idx -1") +__msg("mark_precise: frame0: regs=r0 stack= before 16: (bf) r1 = r7") +__msg("mark_precise: frame0: regs=r0 stack= before 15: (27) r0 *= 4") +__msg("mark_precise: frame0: regs=r0 stack= before 14: (79) r0 = *(u64 *)(r10 -16)") +__msg("mark_precise: frame0: regs= stack=-16 before 13: (7b) *(u64 *)(r7 -8) = r0") +__msg("mark_precise: frame0: regs=r0 stack= before 12: (79) r0 = *(u64 *)(r8 +16)") +__msg("mark_precise: frame0: regs= stack=-16 before 11: (7b) *(u64 *)(r8 +16) = r0") +__msg("mark_precise: frame0: regs=r0 stack= before 10: (79) r0 = *(u64 *)(r7 -8)") +__msg("mark_precise: frame0: regs= stack=-16 before 9: (7b) *(u64 *)(r10 -16) = r0") +__msg("mark_precise: frame0: regs=r0 stack= before 8: (07) r8 += -32") +__msg("mark_precise: frame0: regs=r0 stack= before 7: (bf) r8 = r10") +__msg("mark_precise: frame0: regs=r0 stack= before 6: (07) r7 += -8") +__msg("mark_precise: frame0: regs=r0 stack= before 5: (bf) r7 = r10") +__msg("mark_precise: frame0: regs=r0 stack= before 21: (95) exit") +__msg("mark_precise: frame1: regs=r0 stack= before 20: (bf) r0 = r1") +__msg("mark_precise: frame1: regs=r1 stack= before 4: (85) call pc+15") +__msg("mark_precise: frame0: regs=r1 stack= before 3: (bf) r1 = r6") +__msg("mark_precise: frame0: regs=r6 stack= before 2: (b7) r6 = 1") +__naked int stack_slot_aliases_precision(void) { asm volatile ( - "r0 = 0;" - /* guaranteed checkpoint if BPF_F_TEST_STATE_FREQ is used */ - "goto +0;" + "r6 = 1;" + /* pass r6 through r1 into subprog to get it back as r0; + * this whole chain will have to be marked as precise later + */ + "r1 = r6;" + "call identity_subprog;" + /* let's setup two registers that are aliased to r10 */ + "r7 = r10;" + "r7 += -8;" /* r7 = r10 - 8 */ + "r8 = r10;" + "r8 += -32;" /* r8 = r10 - 32 */ + /* now spill subprog's return value (a r6 -> r1 -> r0 chain) + * a few times through different stack pointer regs, making + * sure to use r10, r7, and r8 both in LDX and STX insns, and + * *importantly* also using a combination of const var_off and + * insn->off to validate that we record final stack slot + * correctly, instead of relying on just insn->off derivation, + * which is only valid for r10-based stack offset + */ + "*(u64 *)(r10 - 16) = r0;" + "r0 = *(u64 *)(r7 - 8);" /* r7 - 8 == r10 - 16 */ + "*(u64 *)(r8 + 16) = r0;" /* r8 + 16 = r10 - 16 */ + "r0 = *(u64 *)(r8 + 16);" + "*(u64 *)(r7 - 8) = r0;" + "r0 = *(u64 *)(r10 - 16);" + /* get ready to use r0 as an index into array to force precision */ + "r0 *= 4;" + "r1 = %[vals];" + /* here r0->r1->r6 chain is forced to be precise and has to be + * propagated back to the beginning, including through the + * subprog call and all the stack spills and loads + */ + "r1 += r0;" + "r0 = *(u32 *)(r1 + 0);" "exit;" + : + : __imm_ptr(vals) + : __clobber_common, "r6" ); } diff --git a/tools/testing/selftests/bpf/progs/verifier_value_illegal_alu.c b/tools/testing/selftests/bpf/progs/verifier_value_illegal_alu.c index 71814a7532..a9ab37d3b9 100644 --- a/tools/testing/selftests/bpf/progs/verifier_value_illegal_alu.c +++ b/tools/testing/selftests/bpf/progs/verifier_value_illegal_alu.c @@ -146,4 +146,23 @@ l0_%=: exit; \ : __clobber_all); } +SEC("flow_dissector") +__description("flow_keys illegal alu op with variable offset") +__failure __msg("R7 pointer arithmetic on flow_keys prohibited") +__naked void flow_keys_illegal_variable_offset_alu(void) +{ + asm volatile(" \ + r6 = r1; \ + r7 = *(u64*)(r6 + %[flow_keys_off]); \ + r8 = 8; \ + r8 /= 1; \ + r8 &= 8; \ + r7 += r8; \ + r0 = *(u64*)(r7 + 0); \ + exit; \ +" : + : __imm_const(flow_keys_off, offsetof(struct __sk_buff, flow_keys)) + : __clobber_all); +} + char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/verifier_var_off.c b/tools/testing/selftests/bpf/progs/verifier_var_off.c index d1f23c1a7c..c810f4f6f4 100644 --- a/tools/testing/selftests/bpf/progs/verifier_var_off.c +++ b/tools/testing/selftests/bpf/progs/verifier_var_off.c @@ -263,6 +263,35 @@ __naked void access_max_out_of_bound(void) : __clobber_all); } +/* Similar to the test above, but this time check the special case of a + * zero-sized stack access. We used to have a bug causing crashes for zero-sized + * out-of-bounds accesses. + */ +SEC("socket") +__description("indirect variable-offset stack access, zero-sized, max out of bound") +__failure __msg("invalid variable-offset indirect access to stack R1") +__naked void zero_sized_access_max_out_of_bound(void) +{ + asm volatile (" \ + r0 = 0; \ + /* Fill some stack */ \ + *(u64*)(r10 - 16) = r0; \ + *(u64*)(r10 - 8) = r0; \ + /* Get an unknown value */ \ + r1 = *(u32*)(r1 + 0); \ + r1 &= 63; \ + r1 += -16; \ + /* r1 is now anywhere in [-16,48) */ \ + r1 += r10; \ + r2 = 0; \ + r3 = 0; \ + call %[bpf_probe_read_kernel]; \ + exit; \ +" : + : __imm(bpf_probe_read_kernel) + : __clobber_all); +} + SEC("lwt_in") __description("indirect variable-offset stack access, min out of bound") __failure __msg("invalid variable-offset indirect access to stack R2") diff --git a/tools/testing/selftests/bpf/progs/xdp_hw_metadata.c b/tools/testing/selftests/bpf/progs/xdp_hw_metadata.c index f6d1cc9ad8..330ece2eab 100644 --- a/tools/testing/selftests/bpf/progs/xdp_hw_metadata.c +++ b/tools/testing/selftests/bpf/progs/xdp_hw_metadata.c @@ -20,21 +20,32 @@ extern int bpf_xdp_metadata_rx_timestamp(const struct xdp_md *ctx, __u64 *timestamp) __ksym; extern int bpf_xdp_metadata_rx_hash(const struct xdp_md *ctx, __u32 *hash, enum xdp_rss_hash_type *rss_type) __ksym; +extern int bpf_xdp_metadata_rx_vlan_tag(const struct xdp_md *ctx, + __be16 *vlan_proto, + __u16 *vlan_tci) __ksym; SEC("xdp.frags") int rx(struct xdp_md *ctx) { void *data, *data_meta, *data_end; struct ipv6hdr *ip6h = NULL; - struct ethhdr *eth = NULL; struct udphdr *udp = NULL; struct iphdr *iph = NULL; struct xdp_meta *meta; + struct ethhdr *eth; int err; data = (void *)(long)ctx->data; data_end = (void *)(long)ctx->data_end; eth = data; + + if (eth + 1 < data_end && (eth->h_proto == bpf_htons(ETH_P_8021AD) || + eth->h_proto == bpf_htons(ETH_P_8021Q))) + eth = (void *)eth + sizeof(struct vlan_hdr); + + if (eth + 1 < data_end && eth->h_proto == bpf_htons(ETH_P_8021Q)) + eth = (void *)eth + sizeof(struct vlan_hdr); + if (eth + 1 < data_end) { if (eth->h_proto == bpf_htons(ETH_P_IP)) { iph = (void *)(eth + 1); @@ -76,15 +87,28 @@ int rx(struct xdp_md *ctx) return XDP_PASS; } + meta->hint_valid = 0; + + meta->xdp_timestamp = bpf_ktime_get_tai_ns(); err = bpf_xdp_metadata_rx_timestamp(ctx, &meta->rx_timestamp); - if (!err) - meta->xdp_timestamp = bpf_ktime_get_tai_ns(); + if (err) + meta->rx_timestamp_err = err; else - meta->rx_timestamp = 0; /* Used by AF_XDP as not avail signal */ + meta->hint_valid |= XDP_META_FIELD_TS; - err = bpf_xdp_metadata_rx_hash(ctx, &meta->rx_hash, &meta->rx_hash_type); - if (err < 0) - meta->rx_hash_err = err; /* Used by AF_XDP as no hash signal */ + err = bpf_xdp_metadata_rx_hash(ctx, &meta->rx_hash, + &meta->rx_hash_type); + if (err) + meta->rx_hash_err = err; + else + meta->hint_valid |= XDP_META_FIELD_RSS; + + err = bpf_xdp_metadata_rx_vlan_tag(ctx, &meta->rx_vlan_proto, + &meta->rx_vlan_tci); + if (err) + meta->rx_vlan_tag_err = err; + else + meta->hint_valid |= XDP_META_FIELD_VLAN_TAG; __sync_add_and_fetch(&pkts_redir, 1); return bpf_redirect_map(&xsk, ctx->rx_queue_index, XDP_PASS); diff --git a/tools/testing/selftests/bpf/progs/xdp_metadata.c b/tools/testing/selftests/bpf/progs/xdp_metadata.c index d151d406a1..31ca229bb3 100644 --- a/tools/testing/selftests/bpf/progs/xdp_metadata.c +++ b/tools/testing/selftests/bpf/progs/xdp_metadata.c @@ -23,15 +23,47 @@ extern int bpf_xdp_metadata_rx_timestamp(const struct xdp_md *ctx, __u64 *timestamp) __ksym; extern int bpf_xdp_metadata_rx_hash(const struct xdp_md *ctx, __u32 *hash, enum xdp_rss_hash_type *rss_type) __ksym; +extern int bpf_xdp_metadata_rx_vlan_tag(const struct xdp_md *ctx, + __be16 *vlan_proto, + __u16 *vlan_tci) __ksym; SEC("xdp") int rx(struct xdp_md *ctx) { - void *data, *data_meta; + void *data, *data_meta, *data_end; + struct ipv6hdr *ip6h = NULL; + struct ethhdr *eth = NULL; + struct udphdr *udp = NULL; + struct iphdr *iph = NULL; struct xdp_meta *meta; u64 timestamp = -1; int ret; + data = (void *)(long)ctx->data; + data_end = (void *)(long)ctx->data_end; + eth = data; + if (eth + 1 < data_end) { + if (eth->h_proto == bpf_htons(ETH_P_IP)) { + iph = (void *)(eth + 1); + if (iph + 1 < data_end && iph->protocol == IPPROTO_UDP) + udp = (void *)(iph + 1); + } + if (eth->h_proto == bpf_htons(ETH_P_IPV6)) { + ip6h = (void *)(eth + 1); + if (ip6h + 1 < data_end && ip6h->nexthdr == IPPROTO_UDP) + udp = (void *)(ip6h + 1); + } + if (udp && udp + 1 > data_end) + udp = NULL; + } + + if (!udp) + return XDP_PASS; + + /* Forwarding UDP:8080 to AF_XDP */ + if (udp->dest != bpf_htons(8080)) + return XDP_PASS; + /* Reserve enough for all custom metadata. */ ret = bpf_xdp_adjust_meta(ctx, -(int)sizeof(struct xdp_meta)); @@ -57,6 +89,8 @@ int rx(struct xdp_md *ctx) meta->rx_timestamp = 1; bpf_xdp_metadata_rx_hash(ctx, &meta->rx_hash, &meta->rx_hash_type); + bpf_xdp_metadata_rx_vlan_tag(ctx, &meta->rx_vlan_proto, + &meta->rx_vlan_tci); return bpf_redirect_map(&xsk, ctx->rx_queue_index, XDP_PASS); } diff --git a/tools/testing/selftests/bpf/test_loader.c b/tools/testing/selftests/bpf/test_loader.c index 37ffa57f28..f013910212 100644 --- a/tools/testing/selftests/bpf/test_loader.c +++ b/tools/testing/selftests/bpf/test_loader.c @@ -12,7 +12,7 @@ #define str_has_pfx(str, pfx) \ (strncmp(str, pfx, __builtin_constant_p(pfx) ? sizeof(pfx) - 1 : strlen(pfx)) == 0) -#define TEST_LOADER_LOG_BUF_SZ 1048576 +#define TEST_LOADER_LOG_BUF_SZ 2097152 #define TEST_TAG_EXPECT_FAILURE "comment:test_expect_failure" #define TEST_TAG_EXPECT_SUCCESS "comment:test_expect_success" @@ -27,6 +27,7 @@ #define TEST_TAG_RETVAL_PFX_UNPRIV "comment:test_retval_unpriv=" #define TEST_TAG_AUXILIARY "comment:test_auxiliary" #define TEST_TAG_AUXILIARY_UNPRIV "comment:test_auxiliary_unpriv" +#define TEST_BTF_PATH "comment:test_btf_path=" /* Warning: duplicated in bpf_misc.h */ #define POINTER_VALUE 0xcafe4all @@ -58,6 +59,7 @@ struct test_spec { const char *prog_name; struct test_subspec priv; struct test_subspec unpriv; + const char *btf_custom_path; int log_level; int prog_flags; int mode_mask; @@ -153,6 +155,14 @@ static int parse_retval(const char *str, int *val, const char *name) return parse_int(str, val, name); } +static void update_flags(int *flags, int flag, bool clear) +{ + if (clear) + *flags &= ~flag; + else + *flags |= flag; +} + /* Uses btf_decl_tag attributes to describe the expected test * behavior, see bpf_misc.h for detailed description of each attribute * and attribute combinations. @@ -171,6 +181,7 @@ static int parse_test_spec(struct test_loader *tester, memset(spec, 0, sizeof(*spec)); spec->prog_name = bpf_program__name(prog); + spec->prog_flags = BPF_F_TEST_REG_INVARIANTS; /* by default be strict */ btf = bpf_object__btf(obj); if (!btf) { @@ -187,7 +198,8 @@ static int parse_test_spec(struct test_loader *tester, for (i = 1; i < btf__type_cnt(btf); i++) { const char *s, *val, *msg; const struct btf_type *t; - int tmp; + bool clear; + int flags; t = btf__type_by_id(btf, i); if (!btf_is_decl_tag(t)) @@ -253,24 +265,33 @@ static int parse_test_spec(struct test_loader *tester, goto cleanup; } else if (str_has_pfx(s, TEST_TAG_PROG_FLAGS_PFX)) { val = s + sizeof(TEST_TAG_PROG_FLAGS_PFX) - 1; + + clear = val[0] == '!'; + if (clear) + val++; + if (strcmp(val, "BPF_F_STRICT_ALIGNMENT") == 0) { - spec->prog_flags |= BPF_F_STRICT_ALIGNMENT; + update_flags(&spec->prog_flags, BPF_F_STRICT_ALIGNMENT, clear); } else if (strcmp(val, "BPF_F_ANY_ALIGNMENT") == 0) { - spec->prog_flags |= BPF_F_ANY_ALIGNMENT; + update_flags(&spec->prog_flags, BPF_F_ANY_ALIGNMENT, clear); } else if (strcmp(val, "BPF_F_TEST_RND_HI32") == 0) { - spec->prog_flags |= BPF_F_TEST_RND_HI32; + update_flags(&spec->prog_flags, BPF_F_TEST_RND_HI32, clear); } else if (strcmp(val, "BPF_F_TEST_STATE_FREQ") == 0) { - spec->prog_flags |= BPF_F_TEST_STATE_FREQ; + update_flags(&spec->prog_flags, BPF_F_TEST_STATE_FREQ, clear); } else if (strcmp(val, "BPF_F_SLEEPABLE") == 0) { - spec->prog_flags |= BPF_F_SLEEPABLE; + update_flags(&spec->prog_flags, BPF_F_SLEEPABLE, clear); } else if (strcmp(val, "BPF_F_XDP_HAS_FRAGS") == 0) { - spec->prog_flags |= BPF_F_XDP_HAS_FRAGS; + update_flags(&spec->prog_flags, BPF_F_XDP_HAS_FRAGS, clear); + } else if (strcmp(val, "BPF_F_TEST_REG_INVARIANTS") == 0) { + update_flags(&spec->prog_flags, BPF_F_TEST_REG_INVARIANTS, clear); } else /* assume numeric value */ { - err = parse_int(val, &tmp, "test prog flags"); + err = parse_int(val, &flags, "test prog flags"); if (err) goto cleanup; - spec->prog_flags |= tmp; + update_flags(&spec->prog_flags, flags, clear); } + } else if (str_has_pfx(s, TEST_BTF_PATH)) { + spec->btf_custom_path = s + sizeof(TEST_BTF_PATH) - 1; } } @@ -561,6 +582,9 @@ void run_subtest(struct test_loader *tester, } } + /* Implicitly reset to NULL if next test case doesn't specify */ + open_opts->btf_custom_path = spec->btf_custom_path; + tobj = bpf_object__open_mem(obj_bytes, obj_byte_cnt, open_opts); if (!ASSERT_OK_PTR(tobj, "obj_open_mem")) /* shouldn't happen */ goto subtest_cleanup; diff --git a/tools/testing/selftests/bpf/test_maps.c b/tools/testing/selftests/bpf/test_maps.c index e0dd101c9f..dfbab214f4 100644 --- a/tools/testing/selftests/bpf/test_maps.c +++ b/tools/testing/selftests/bpf/test_maps.c @@ -1400,13 +1400,18 @@ static void test_map_stress(void) #define MAX_DELAY_US 50000 #define MIN_DELAY_RANGE_US 5000 -static int map_update_retriable(int map_fd, const void *key, const void *value, - int flags, int attempts) +static bool retry_for_again_or_busy(int err) +{ + return (err == EAGAIN || err == EBUSY); +} + +int map_update_retriable(int map_fd, const void *key, const void *value, int flags, int attempts, + retry_for_error_fn need_retry) { int delay = rand() % MIN_DELAY_RANGE_US; while (bpf_map_update_elem(map_fd, key, value, flags)) { - if (!attempts || (errno != EAGAIN && errno != EBUSY)) + if (!attempts || !need_retry(errno)) return -errno; if (delay <= MAX_DELAY_US / 2) @@ -1449,11 +1454,13 @@ static void test_update_delete(unsigned int fn, void *data) key = value = i; if (do_update) { - err = map_update_retriable(fd, &key, &value, BPF_NOEXIST, MAP_RETRIES); + err = map_update_retriable(fd, &key, &value, BPF_NOEXIST, MAP_RETRIES, + retry_for_again_or_busy); if (err) printf("error %d %d\n", err, errno); assert(err == 0); - err = map_update_retriable(fd, &key, &value, BPF_EXIST, MAP_RETRIES); + err = map_update_retriable(fd, &key, &value, BPF_EXIST, MAP_RETRIES, + retry_for_again_or_busy); if (err) printf("error %d %d\n", err, errno); assert(err == 0); diff --git a/tools/testing/selftests/bpf/test_maps.h b/tools/testing/selftests/bpf/test_maps.h index f6fbca7617..e4ac704a53 100644 --- a/tools/testing/selftests/bpf/test_maps.h +++ b/tools/testing/selftests/bpf/test_maps.h @@ -4,6 +4,7 @@ #include #include +#include #define CHECK(condition, tag, format...) ({ \ int __ret = !!(condition); \ @@ -16,4 +17,8 @@ extern int skips; +typedef bool (*retry_for_error_fn)(int err); +int map_update_retriable(int map_fd, const void *key, const void *value, int flags, int attempts, + retry_for_error_fn need_retry); + #endif diff --git a/tools/testing/selftests/bpf/test_offload.py b/tools/testing/selftests/bpf/test_offload.py index 40cba8d368..6157f884d0 100755 --- a/tools/testing/selftests/bpf/test_offload.py +++ b/tools/testing/selftests/bpf/test_offload.py @@ -169,12 +169,14 @@ 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=""): +def bpftool_prog_list(expected=None, ns="", exclude_orphaned=True): _, progs = bpftool("prog show", JSON=True, ns=ns, fail=True) # Remove the base progs for p in base_progs: if p in progs: progs.remove(p) + if exclude_orphaned: + progs = [ p for p in progs if not p['orphaned'] ] if expected is not None: if len(progs) != expected: fail(True, "%d BPF programs loaded, expected %d" % @@ -612,11 +614,9 @@ def pin_map(file_name, idx=0, expected=1): def check_dev_info_removed(prog_file=None, map_file=None): bpftool_prog_list(expected=0) + bpftool_prog_list(expected=1, exclude_orphaned=False) ret, err = bpftool("prog show pin %s" % (prog_file), fail=False) - fail(ret == 0, "Showing prog with removed device did not fail") - fail(err["error"].find("No such device") == -1, - "Showing prog with removed device expected ENODEV, error is %s" % - (err["error"])) + fail(ret != 0, "failed to show prog with removed device") bpftool_map_list(expected=0) ret, err = bpftool("map show pin %s" % (map_file), fail=False) @@ -1395,10 +1395,7 @@ try: 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") + fail(ret != 0, "couldn't get information about orphaned program") print("%s: OK" % (os.path.basename(__file__))) diff --git a/tools/testing/selftests/bpf/test_sock_addr.c b/tools/testing/selftests/bpf/test_sock_addr.c index 2c89674fc6..b0068a9d2c 100644 --- a/tools/testing/selftests/bpf/test_sock_addr.c +++ b/tools/testing/selftests/bpf/test_sock_addr.c @@ -679,7 +679,7 @@ static int load_path(const struct sock_addr_test *test, const char *path) bpf_program__set_type(prog, BPF_PROG_TYPE_CGROUP_SOCK_ADDR); bpf_program__set_expected_attach_type(prog, test->expected_attach_type); - bpf_program__set_flags(prog, BPF_F_TEST_RND_HI32); + bpf_program__set_flags(prog, BPF_F_TEST_RND_HI32 | BPF_F_TEST_REG_INVARIANTS); err = bpf_object__load(obj); if (err) { diff --git a/tools/testing/selftests/bpf/test_tunnel.sh b/tools/testing/selftests/bpf/test_tunnel.sh index 2dec7dbf29..d9661b9988 100755 --- a/tools/testing/selftests/bpf/test_tunnel.sh +++ b/tools/testing/selftests/bpf/test_tunnel.sh @@ -517,90 +517,6 @@ test_ip6ip6() echo -e ${GREEN}"PASS: ip6$TYPE"${NC} } -setup_xfrm_tunnel() -{ - auth=0x$(printf '1%.0s' {1..40}) - enc=0x$(printf '2%.0s' {1..32}) - spi_in_to_out=0x1 - spi_out_to_in=0x2 - # at_ns0 namespace - # at_ns0 -> root - ip netns exec at_ns0 \ - ip xfrm state add src 172.16.1.100 dst 172.16.1.200 proto esp \ - spi $spi_in_to_out reqid 1 mode tunnel \ - auth-trunc 'hmac(sha1)' $auth 96 enc 'cbc(aes)' $enc - ip netns exec at_ns0 \ - ip xfrm policy add src 10.1.1.100/32 dst 10.1.1.200/32 dir out \ - tmpl src 172.16.1.100 dst 172.16.1.200 proto esp reqid 1 \ - mode tunnel - # root -> at_ns0 - ip netns exec at_ns0 \ - ip xfrm state add src 172.16.1.200 dst 172.16.1.100 proto esp \ - spi $spi_out_to_in reqid 2 mode tunnel \ - auth-trunc 'hmac(sha1)' $auth 96 enc 'cbc(aes)' $enc - ip netns exec at_ns0 \ - ip xfrm policy add src 10.1.1.200/32 dst 10.1.1.100/32 dir in \ - tmpl src 172.16.1.200 dst 172.16.1.100 proto esp reqid 2 \ - mode tunnel - # address & route - ip netns exec at_ns0 \ - ip addr add dev veth0 10.1.1.100/32 - ip netns exec at_ns0 \ - ip route add 10.1.1.200 dev veth0 via 172.16.1.200 \ - src 10.1.1.100 - - # root namespace - # at_ns0 -> root - ip xfrm state add src 172.16.1.100 dst 172.16.1.200 proto esp \ - spi $spi_in_to_out reqid 1 mode tunnel \ - auth-trunc 'hmac(sha1)' $auth 96 enc 'cbc(aes)' $enc - ip xfrm policy add src 10.1.1.100/32 dst 10.1.1.200/32 dir in \ - tmpl src 172.16.1.100 dst 172.16.1.200 proto esp reqid 1 \ - mode tunnel - # root -> at_ns0 - ip xfrm state add src 172.16.1.200 dst 172.16.1.100 proto esp \ - spi $spi_out_to_in reqid 2 mode tunnel \ - auth-trunc 'hmac(sha1)' $auth 96 enc 'cbc(aes)' $enc - ip xfrm policy add src 10.1.1.200/32 dst 10.1.1.100/32 dir out \ - tmpl src 172.16.1.200 dst 172.16.1.100 proto esp reqid 2 \ - mode tunnel - # address & route - ip addr add dev veth1 10.1.1.200/32 - ip route add 10.1.1.100 dev veth1 via 172.16.1.100 src 10.1.1.200 -} - -test_xfrm_tunnel() -{ - if [[ -e /sys/kernel/tracing/trace ]]; then - TRACE=/sys/kernel/tracing/trace - else - TRACE=/sys/kernel/debug/tracing/trace - fi - config_device - > ${TRACE} - setup_xfrm_tunnel - mkdir -p ${BPF_PIN_TUNNEL_DIR} - bpftool prog loadall ${BPF_FILE} ${BPF_PIN_TUNNEL_DIR} - tc qdisc add dev veth1 clsact - tc filter add dev veth1 proto ip ingress bpf da object-pinned \ - ${BPF_PIN_TUNNEL_DIR}/xfrm_get_state - ip netns exec at_ns0 ping $PING_ARG 10.1.1.200 - sleep 1 - grep "reqid 1" ${TRACE} - check_err $? - grep "spi 0x1" ${TRACE} - check_err $? - grep "remote ip 0xac100164" ${TRACE} - check_err $? - cleanup - - if [ $ret -ne 0 ]; then - echo -e ${RED}"FAIL: xfrm tunnel"${NC} - return 1 - fi - echo -e ${GREEN}"PASS: xfrm tunnel"${NC} -} - attach_bpf() { DEV=$1 @@ -630,10 +546,6 @@ cleanup() ip link del ip6geneve11 2> /dev/null ip link del erspan11 2> /dev/null ip link del ip6erspan11 2> /dev/null - ip xfrm policy delete dir out src 10.1.1.200/32 dst 10.1.1.100/32 2> /dev/null - ip xfrm policy delete dir in src 10.1.1.100/32 dst 10.1.1.200/32 2> /dev/null - ip xfrm state delete src 172.16.1.100 dst 172.16.1.200 proto esp spi 0x1 2> /dev/null - ip xfrm state delete src 172.16.1.200 dst 172.16.1.100 proto esp spi 0x2 2> /dev/null } cleanup_exit() @@ -716,10 +628,6 @@ bpf_tunnel_test() test_ip6ip6 errors=$(( $errors + $? )) - echo "Testing IPSec tunnel..." - test_xfrm_tunnel - errors=$(( $errors + $? )) - return $errors } diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 98107e0452..f36e41435b 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -1588,7 +1588,7 @@ static void do_test_single(struct bpf_test *test, bool unpriv, if (fixup_skips != skips) return; - pflags = BPF_F_TEST_RND_HI32; + pflags = BPF_F_TEST_RND_HI32 | BPF_F_TEST_REG_INVARIANTS; if (test->flags & F_LOAD_WITH_STRICT_ALIGNMENT) pflags |= BPF_F_STRICT_ALIGNMENT; if (test->flags & F_NEEDS_EFFICIENT_UNALIGNED_ACCESS) diff --git a/tools/testing/selftests/bpf/testing_helpers.c b/tools/testing/selftests/bpf/testing_helpers.c index 8d994884c7..d2458c1b16 100644 --- a/tools/testing/selftests/bpf/testing_helpers.c +++ b/tools/testing/selftests/bpf/testing_helpers.c @@ -276,7 +276,7 @@ int bpf_prog_test_load(const char *file, enum bpf_prog_type type, if (type != BPF_PROG_TYPE_UNSPEC && bpf_program__type(prog) != type) bpf_program__set_type(prog, type); - flags = bpf_program__flags(prog) | BPF_F_TEST_RND_HI32; + flags = bpf_program__flags(prog) | BPF_F_TEST_RND_HI32 | BPF_F_TEST_REG_INVARIANTS; bpf_program__set_flags(prog, flags); err = bpf_object__load(obj); @@ -299,7 +299,7 @@ int bpf_test_load_program(enum bpf_prog_type type, const struct bpf_insn *insns, { LIBBPF_OPTS(bpf_prog_load_opts, opts, .kern_version = kern_version, - .prog_flags = BPF_F_TEST_RND_HI32, + .prog_flags = BPF_F_TEST_RND_HI32 | BPF_F_TEST_REG_INVARIANTS, .log_level = extra_prog_load_log_flags, .log_buf = log_buf, .log_size = log_buf_sz, diff --git a/tools/testing/selftests/bpf/testing_helpers.h b/tools/testing/selftests/bpf/testing_helpers.h index 5b7a551367..35284faff4 100644 --- a/tools/testing/selftests/bpf/testing_helpers.h +++ b/tools/testing/selftests/bpf/testing_helpers.h @@ -9,6 +9,9 @@ #include #include +#define __TO_STR(x) #x +#define TO_STR(x) __TO_STR(x) + int parse_num_list(const char *s, bool **set, int *set_len); __u32 link_info_prog_id(const struct bpf_link *link, struct bpf_link_info *info); int bpf_prog_test_load(const char *file, enum bpf_prog_type type, diff --git a/tools/testing/selftests/bpf/verifier/precise.c b/tools/testing/selftests/bpf/verifier/precise.c index 0d84dd1f38..8a2ff81d83 100644 --- a/tools/testing/selftests/bpf/verifier/precise.c +++ b/tools/testing/selftests/bpf/verifier/precise.c @@ -140,10 +140,11 @@ .result = REJECT, }, { - "precise: ST insn causing spi > allocated_stack", + "precise: ST zero to stack insn is supported", .insns = { BPF_MOV64_REG(BPF_REG_3, BPF_REG_10), BPF_JMP_IMM(BPF_JNE, BPF_REG_3, 123, 0), + /* not a register spill, so we stop precision propagation for R4 here */ BPF_ST_MEM(BPF_DW, BPF_REG_3, -8, 0), BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_10, -8), BPF_MOV64_IMM(BPF_REG_0, -1), @@ -157,11 +158,11 @@ mark_precise: frame0: last_idx 4 first_idx 2\ mark_precise: frame0: regs=r4 stack= before 4\ mark_precise: frame0: regs=r4 stack= before 3\ - mark_precise: frame0: regs= stack=-8 before 2\ - mark_precise: frame0: falling back to forcing all scalars precise\ - force_precise: frame0: forcing r0 to be precise\ mark_precise: frame0: last_idx 5 first_idx 5\ - mark_precise: frame0: parent state regs= stack=:", + mark_precise: frame0: parent state regs=r0 stack=:\ + mark_precise: frame0: last_idx 4 first_idx 2\ + mark_precise: frame0: regs=r0 stack= before 4\ + 5: R0=-1 R4=0", .result = VERBOSE_ACCEPT, .retval = -1, }, @@ -169,6 +170,8 @@ "precise: STX insn causing spi > allocated_stack", .insns = { BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_prandom_u32), + /* make later reg spill more interesting by having somewhat known scalar */ + BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 0xff), BPF_MOV64_REG(BPF_REG_3, BPF_REG_10), BPF_JMP_IMM(BPF_JNE, BPF_REG_3, 123, 0), BPF_STX_MEM(BPF_DW, BPF_REG_3, BPF_REG_0, -8), @@ -179,18 +182,21 @@ }, .prog_type = BPF_PROG_TYPE_XDP, .flags = BPF_F_TEST_STATE_FREQ, - .errstr = "mark_precise: frame0: last_idx 6 first_idx 6\ + .errstr = "mark_precise: frame0: last_idx 7 first_idx 7\ mark_precise: frame0: parent state regs=r4 stack=:\ - mark_precise: frame0: last_idx 5 first_idx 3\ - mark_precise: frame0: regs=r4 stack= before 5\ - mark_precise: frame0: regs=r4 stack= before 4\ - mark_precise: frame0: regs= stack=-8 before 3\ - mark_precise: frame0: falling back to forcing all scalars precise\ - force_precise: frame0: forcing r0 to be precise\ - force_precise: frame0: forcing r0 to be precise\ - force_precise: frame0: forcing r0 to be precise\ - force_precise: frame0: forcing r0 to be precise\ - mark_precise: frame0: last_idx 6 first_idx 6\ + mark_precise: frame0: last_idx 6 first_idx 4\ + mark_precise: frame0: regs=r4 stack= before 6: (b7) r0 = -1\ + mark_precise: frame0: regs=r4 stack= before 5: (79) r4 = *(u64 *)(r10 -8)\ + mark_precise: frame0: regs= stack=-8 before 4: (7b) *(u64 *)(r3 -8) = r0\ + mark_precise: frame0: parent state regs=r0 stack=:\ + mark_precise: frame0: last_idx 3 first_idx 3\ + mark_precise: frame0: regs=r0 stack= before 3: (55) if r3 != 0x7b goto pc+0\ + mark_precise: frame0: regs=r0 stack= before 2: (bf) r3 = r10\ + mark_precise: frame0: regs=r0 stack= before 1: (57) r0 &= 255\ + mark_precise: frame0: parent state regs=r0 stack=:\ + mark_precise: frame0: last_idx 0 first_idx 0\ + mark_precise: frame0: regs=r0 stack= before 0: (85) call bpf_get_prandom_u32#7\ + mark_precise: frame0: last_idx 7 first_idx 7\ mark_precise: frame0: parent state regs= stack=:", .result = VERBOSE_ACCEPT, .retval = -1, diff --git a/tools/testing/selftests/bpf/verify_sig_setup.sh b/tools/testing/selftests/bpf/verify_sig_setup.sh index ba08922b4a..f2cac42298 100755 --- a/tools/testing/selftests/bpf/verify_sig_setup.sh +++ b/tools/testing/selftests/bpf/verify_sig_setup.sh @@ -60,6 +60,27 @@ cleanup() { rm -rf ${tmp_dir} } +fsverity_create_sign_file() { + local tmp_dir="$1" + + data_file=${tmp_dir}/data-file + sig_file=${tmp_dir}/sig-file + dd if=/dev/urandom of=$data_file bs=1 count=12345 2> /dev/null + fsverity sign --key ${tmp_dir}/signing_key.pem $data_file $sig_file + + # We do not want to enable fsverity on $data_file yet. Try whether + # the file system support fsverity on a different file. + touch ${tmp_dir}/tmp-file + fsverity enable ${tmp_dir}/tmp-file +} + +fsverity_enable_file() { + local tmp_dir="$1" + + data_file=${tmp_dir}/data-file + fsverity enable $data_file +} + catch() { local exit_code="$1" @@ -86,6 +107,10 @@ main() setup "${tmp_dir}" elif [[ "${action}" == "cleanup" ]]; then cleanup "${tmp_dir}" + elif [[ "${action}" == "fsverity-create-sign" ]]; then + fsverity_create_sign_file "${tmp_dir}" + elif [[ "${action}" == "fsverity-enable" ]]; then + fsverity_enable_file "${tmp_dir}" else echo "Unknown action: ${action}" exit 1 diff --git a/tools/testing/selftests/bpf/veristat.c b/tools/testing/selftests/bpf/veristat.c index 0ad98b6a8e..244d4996e0 100644 --- a/tools/testing/selftests/bpf/veristat.c +++ b/tools/testing/selftests/bpf/veristat.c @@ -18,6 +18,7 @@ #include #include #include +#include #ifndef ARRAY_SIZE #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) @@ -99,6 +100,7 @@ struct stat_specs { enum stat_id ids[ALL_STATS_CNT]; enum stat_variant variants[ALL_STATS_CNT]; bool asc[ALL_STATS_CNT]; + bool abs[ALL_STATS_CNT]; int lens[ALL_STATS_CNT * 3]; /* 3x for comparison mode */ }; @@ -133,6 +135,7 @@ struct filter { int stat_id; enum stat_variant stat_var; long value; + bool abs; }; static struct env { @@ -142,10 +145,12 @@ static struct env { bool debug; bool quiet; bool force_checkpoints; + bool force_reg_invariants; enum resfmt out_fmt; bool show_version; bool comparison_mode; bool replay_mode; + int top_n; int log_level; int log_size; @@ -210,8 +215,7 @@ static const struct argp_option opts[] = { { "log-level", 'l', "LEVEL", 0, "Verifier log level (default 0 for normal mode, 1 for verbose mode)" }, { "log-fixed", OPT_LOG_FIXED, NULL, 0, "Disable verifier log rotation" }, { "log-size", OPT_LOG_SIZE, "BYTES", 0, "Customize verifier log size (default to 16MB)" }, - { "test-states", 't', NULL, 0, - "Force frequent BPF verifier state checkpointing (set BPF_F_TEST_STATE_FREQ program flag)" }, + { "top-n", 'n', "N", 0, "Emit only up to first N results." }, { "quiet", 'q', NULL, 0, "Quiet mode" }, { "emit", 'e', "SPEC", 0, "Specify stats to be emitted" }, { "sort", 's', "SPEC", 0, "Specify sort order" }, @@ -219,6 +223,10 @@ static const struct argp_option opts[] = { { "compare", 'C', NULL, 0, "Comparison mode" }, { "replay", 'R', NULL, 0, "Replay mode" }, { "filter", 'f', "FILTER", 0, "Filter expressions (or @filename for file with expressions)." }, + { "test-states", 't', NULL, 0, + "Force frequent BPF verifier state checkpointing (set BPF_F_TEST_STATE_FREQ program flag)" }, + { "test-reg-invariants", 'r', NULL, 0, + "Force BPF verifier failure on register invariant violation (BPF_F_TEST_REG_INVARIANTS program flag)" }, {}, }; @@ -290,6 +298,16 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) case 't': env.force_checkpoints = true; break; + case 'r': + env.force_reg_invariants = true; + break; + case 'n': + errno = 0; + env.top_n = strtol(arg, NULL, 10); + if (errno) { + fprintf(stderr, "invalid top N specifier: %s\n", arg); + argp_usage(state); + } case 'C': env.comparison_mode = true; break; @@ -455,7 +473,8 @@ static struct { { OP_EQ, "=" }, }; -static bool parse_stat_id_var(const char *name, size_t len, int *id, enum stat_variant *var); +static bool parse_stat_id_var(const char *name, size_t len, int *id, + enum stat_variant *var, bool *is_abs); static int append_filter(struct filter **filters, int *cnt, const char *str) { @@ -488,13 +507,14 @@ static int append_filter(struct filter **filters, int *cnt, const char *str) long val; const char *end = str; const char *op_str; + bool is_abs; op_str = operators[i].op_str; p = strstr(str, op_str); if (!p) continue; - if (!parse_stat_id_var(str, p - str, &id, &var)) { + if (!parse_stat_id_var(str, p - str, &id, &var, &is_abs)) { fprintf(stderr, "Unrecognized stat name in '%s'!\n", str); return -EINVAL; } @@ -533,6 +553,7 @@ static int append_filter(struct filter **filters, int *cnt, const char *str) f->stat_id = id; f->stat_var = var; f->op = operators[i].op_kind; + f->abs = true; f->value = val; *cnt += 1; @@ -657,7 +678,8 @@ static struct stat_def { [MARK_READ_MAX_LEN] = { "Max mark read length", {"max_mark_read_len", "mark_read"}, }, }; -static bool parse_stat_id_var(const char *name, size_t len, int *id, enum stat_variant *var) +static bool parse_stat_id_var(const char *name, size_t len, int *id, + enum stat_variant *var, bool *is_abs) { static const char *var_sfxs[] = { [VARIANT_A] = "_a", @@ -667,6 +689,14 @@ static bool parse_stat_id_var(const char *name, size_t len, int *id, enum stat_v }; int i, j, k; + /* || means we take absolute value of given stat */ + *is_abs = false; + if (len > 2 && name[0] == '|' && name[len - 1] == '|') { + *is_abs = true; + name += 1; + len -= 2; + } + for (i = 0; i < ARRAY_SIZE(stat_defs); i++) { struct stat_def *def = &stat_defs[i]; size_t alias_len, sfx_len; @@ -722,7 +752,7 @@ static bool is_desc_sym(char c) static int parse_stat(const char *stat_name, struct stat_specs *specs) { int id; - bool has_order = false, is_asc = false; + bool has_order = false, is_asc = false, is_abs = false; size_t len = strlen(stat_name); enum stat_variant var; @@ -737,7 +767,7 @@ static int parse_stat(const char *stat_name, struct stat_specs *specs) len -= 1; } - if (!parse_stat_id_var(stat_name, len, &id, &var)) { + if (!parse_stat_id_var(stat_name, len, &id, &var, &is_abs)) { fprintf(stderr, "Unrecognized stat name '%s'\n", stat_name); return -ESRCH; } @@ -745,6 +775,7 @@ static int parse_stat(const char *stat_name, struct stat_specs *specs) specs->ids[specs->spec_cnt] = id; specs->variants[specs->spec_cnt] = var; specs->asc[specs->spec_cnt] = has_order ? is_asc : stat_defs[id].asc_by_default; + specs->abs[specs->spec_cnt] = is_abs; specs->spec_cnt++; return 0; @@ -997,6 +1028,8 @@ static int process_prog(const char *filename, struct bpf_object *obj, struct bpf if (env.force_checkpoints) bpf_program__set_flags(prog, bpf_program__flags(prog) | BPF_F_TEST_STATE_FREQ); + if (env.force_reg_invariants) + bpf_program__set_flags(prog, bpf_program__flags(prog) | BPF_F_TEST_REG_INVARIANTS); err = bpf_object__load(obj); env.progs_processed++; @@ -1103,7 +1136,7 @@ cleanup: } static int cmp_stat(const struct verif_stats *s1, const struct verif_stats *s2, - enum stat_id id, bool asc) + enum stat_id id, bool asc, bool abs) { int cmp = 0; @@ -1124,6 +1157,11 @@ static int cmp_stat(const struct verif_stats *s1, const struct verif_stats *s2, long v1 = s1->stats[id]; long v2 = s2->stats[id]; + if (abs) { + v1 = v1 < 0 ? -v1 : v1; + v2 = v2 < 0 ? -v2 : v2; + } + if (v1 != v2) cmp = v1 < v2 ? -1 : 1; break; @@ -1142,7 +1180,8 @@ static int cmp_prog_stats(const void *v1, const void *v2) int i, cmp; for (i = 0; i < env.sort_spec.spec_cnt; i++) { - cmp = cmp_stat(s1, s2, env.sort_spec.ids[i], env.sort_spec.asc[i]); + cmp = cmp_stat(s1, s2, env.sort_spec.ids[i], + env.sort_spec.asc[i], env.sort_spec.abs[i]); if (cmp != 0) return cmp; } @@ -1211,7 +1250,8 @@ static void fetch_join_stat_value(const struct verif_stats_join *s, static int cmp_join_stat(const struct verif_stats_join *s1, const struct verif_stats_join *s2, - enum stat_id id, enum stat_variant var, bool asc) + enum stat_id id, enum stat_variant var, + bool asc, bool abs) { const char *str1 = NULL, *str2 = NULL; double v1 = 0.0, v2 = 0.0; @@ -1220,6 +1260,11 @@ static int cmp_join_stat(const struct verif_stats_join *s1, fetch_join_stat_value(s1, id, var, &str1, &v1); fetch_join_stat_value(s2, id, var, &str2, &v2); + if (abs) { + v1 = fabs(v1); + v2 = fabs(v2); + } + if (str1) cmp = strcmp(str1, str2); else if (v1 != v2) @@ -1237,7 +1282,8 @@ static int cmp_join_stats(const void *v1, const void *v2) cmp = cmp_join_stat(s1, s2, env.sort_spec.ids[i], env.sort_spec.variants[i], - env.sort_spec.asc[i]); + env.sort_spec.asc[i], + env.sort_spec.abs[i]); if (cmp != 0) return cmp; } @@ -1720,6 +1766,9 @@ static bool is_join_stat_filter_matched(struct filter *f, const struct verif_sta fetch_join_stat_value(stats, f->stat_id, f->stat_var, &str, &value); + if (f->abs) + value = fabs(value); + switch (f->op) { case OP_EQ: return value > f->value - eps && value < f->value + eps; case OP_NEQ: return value < f->value - eps || value > f->value + eps; @@ -1766,7 +1815,7 @@ static int handle_comparison_mode(void) struct stat_specs base_specs = {}, comp_specs = {}; struct stat_specs tmp_sort_spec; enum resfmt cur_fmt; - int err, i, j, last_idx; + int err, i, j, last_idx, cnt; if (env.filename_cnt != 2) { fprintf(stderr, "Comparison mode expects exactly two input CSV files!\n\n"); @@ -1879,7 +1928,7 @@ static int handle_comparison_mode(void) env.join_stat_cnt += 1; } - /* now sort joined results accorsing to sort spec */ + /* now sort joined results according to sort spec */ qsort(env.join_stats, env.join_stat_cnt, sizeof(*env.join_stats), cmp_join_stats); /* for human-readable table output we need to do extra pass to @@ -1896,16 +1945,22 @@ one_more_time: output_comp_headers(cur_fmt); last_idx = -1; + cnt = 0; for (i = 0; i < env.join_stat_cnt; i++) { const struct verif_stats_join *join = &env.join_stats[i]; if (!should_output_join_stats(join)) continue; + if (env.top_n && cnt >= env.top_n) + break; + if (cur_fmt == RESFMT_TABLE_CALCLEN) last_idx = i; output_comp_stats(join, cur_fmt, i == last_idx); + + cnt++; } if (cur_fmt == RESFMT_TABLE_CALCLEN) { @@ -1920,6 +1975,9 @@ static bool is_stat_filter_matched(struct filter *f, const struct verif_stats *s { long value = stats->stats[f->stat_id]; + if (f->abs) + value = value < 0 ? -value : value; + switch (f->op) { case OP_EQ: return value == f->value; case OP_NEQ: return value != f->value; @@ -1964,7 +2022,7 @@ static bool should_output_stats(const struct verif_stats *stats) static void output_prog_stats(void) { const struct verif_stats *stats; - int i, last_stat_idx = 0; + int i, last_stat_idx = 0, cnt = 0; if (env.out_fmt == RESFMT_TABLE) { /* calculate column widths */ @@ -1984,7 +2042,10 @@ static void output_prog_stats(void) stats = &env.prog_stats[i]; if (!should_output_stats(stats)) continue; + if (env.top_n && cnt >= env.top_n) + break; output_stats(stats, env.out_fmt, i == last_stat_idx); + cnt++; } } diff --git a/tools/testing/selftests/bpf/vmtest.sh b/tools/testing/selftests/bpf/vmtest.sh index 6850345280..65d14f3bbe 100755 --- a/tools/testing/selftests/bpf/vmtest.sh +++ b/tools/testing/selftests/bpf/vmtest.sh @@ -36,7 +36,9 @@ DEFAULT_COMMAND="./test_progs" MOUNT_DIR="mnt" ROOTFS_IMAGE="root.img" OUTPUT_DIR="$HOME/.bpf_selftests" -KCONFIG_REL_PATHS=("tools/testing/selftests/bpf/config" "tools/testing/selftests/bpf/config.${ARCH}") +KCONFIG_REL_PATHS=("tools/testing/selftests/bpf/config" + "tools/testing/selftests/bpf/config.vm" + "tools/testing/selftests/bpf/config.${ARCH}") INDEX_URL="https://raw.githubusercontent.com/libbpf/ci/master/INDEX" NUM_COMPILE_JOBS="$(nproc)" LOG_FILE_BASE="$(date +"bpf_selftests.%Y-%m-%d_%H-%M-%S")" diff --git a/tools/testing/selftests/bpf/xdp_hw_metadata.c b/tools/testing/selftests/bpf/xdp_hw_metadata.c index c5e7937d7f..878d68db03 100644 --- a/tools/testing/selftests/bpf/xdp_hw_metadata.c +++ b/tools/testing/selftests/bpf/xdp_hw_metadata.c @@ -10,7 +10,9 @@ * - rx_hash * * TX: - * - TBD + * - UDP 9091 packets trigger TX reply + * - TX HW timestamp is requested and reported back upon completion + * - TX checksum is requested */ #include @@ -19,20 +21,26 @@ #include "xsk.h" #include +#include +#include +#include #include #include #include #include #include +#include #include #include #include #include #include +#include +#include #include "xdp_metadata.h" -#define UMEM_NUM 16 +#define UMEM_NUM 256 #define UMEM_FRAME_SIZE XSK_UMEM__DEFAULT_FRAME_SIZE #define UMEM_SIZE (UMEM_FRAME_SIZE * UMEM_NUM) #define XDP_FLAGS (XDP_FLAGS_DRV_MODE | XDP_FLAGS_REPLACE) @@ -48,11 +56,14 @@ struct xsk { }; struct xdp_hw_metadata *bpf_obj; -__u16 bind_flags = XDP_COPY; +__u16 bind_flags = XDP_USE_NEED_WAKEUP | XDP_ZEROCOPY; struct xsk *rx_xsk; const char *ifname; int ifindex; int rxq; +bool skip_tx; +__u64 last_hw_rx_timestamp; +__u64 last_xdp_rx_timestamp; void test__fail(void) { /* for network_helpers.c */ } @@ -68,7 +79,8 @@ static int open_xsk(int ifindex, struct xsk *xsk, __u32 queue_id) .fill_size = XSK_RING_PROD__DEFAULT_NUM_DESCS, .comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS, .frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE, - .flags = XDP_UMEM_UNALIGNED_CHUNK_FLAG, + .flags = XSK_UMEM__DEFAULT_FLAGS, + .tx_metadata_len = sizeof(struct xsk_tx_metadata), }; __u32 idx = 0; u64 addr; @@ -110,7 +122,7 @@ static int open_xsk(int ifindex, struct xsk *xsk, __u32 queue_id) for (i = 0; i < UMEM_NUM / 2; i++) { addr = (UMEM_NUM / 2 + i) * UMEM_FRAME_SIZE; printf("%p: rx_desc[%d] -> %lx\n", xsk, i, addr); - *xsk_ring_prod__fill_addr(&xsk->fill, i) = addr; + *xsk_ring_prod__fill_addr(&xsk->fill, idx + i) = addr; } xsk_ring_prod__submit(&xsk->fill, ret); @@ -131,12 +143,22 @@ static void refill_rx(struct xsk *xsk, __u64 addr) __u32 idx; if (xsk_ring_prod__reserve(&xsk->fill, 1, &idx) == 1) { - printf("%p: complete idx=%u addr=%llx\n", xsk, idx, addr); + printf("%p: complete rx idx=%u addr=%llx\n", xsk, idx, addr); *xsk_ring_prod__fill_addr(&xsk->fill, idx) = addr; xsk_ring_prod__submit(&xsk->fill, 1); } } +static int kick_tx(struct xsk *xsk) +{ + return sendto(xsk_socket__fd(xsk->socket), NULL, 0, MSG_DONTWAIT, NULL, 0); +} + +static int kick_rx(struct xsk *xsk) +{ + return recvfrom(xsk_socket__fd(xsk->socket), NULL, 0, MSG_DONTWAIT, NULL, NULL); +} + #define NANOSEC_PER_SEC 1000000000 /* 10^9 */ static __u64 gettime(clockid_t clock_id) { @@ -152,37 +174,64 @@ static __u64 gettime(clockid_t clock_id) return (__u64) t.tv_sec * NANOSEC_PER_SEC + t.tv_nsec; } +static void print_tstamp_delta(const char *name, const char *refname, + __u64 tstamp, __u64 reference) +{ + __s64 delta = (__s64)reference - (__s64)tstamp; + + printf("%s: %llu (sec:%0.4f) delta to %s sec:%0.4f (%0.3f usec)\n", + name, tstamp, (double)tstamp / NANOSEC_PER_SEC, refname, + (double)delta / NANOSEC_PER_SEC, + (double)delta / 1000); +} + +#define VLAN_PRIO_MASK GENMASK(15, 13) /* Priority Code Point */ +#define VLAN_DEI_MASK GENMASK(12, 12) /* Drop Eligible Indicator */ +#define VLAN_VID_MASK GENMASK(11, 0) /* VLAN Identifier */ +static void print_vlan_tci(__u16 tag) +{ + __u16 vlan_id = FIELD_GET(VLAN_VID_MASK, tag); + __u8 pcp = FIELD_GET(VLAN_PRIO_MASK, tag); + bool dei = FIELD_GET(VLAN_DEI_MASK, tag); + + printf("PCP=%u, DEI=%d, VID=0x%X\n", pcp, dei, vlan_id); +} + static void verify_xdp_metadata(void *data, clockid_t clock_id) { struct xdp_meta *meta; meta = data - sizeof(*meta); - if (meta->rx_hash_err < 0) - printf("No rx_hash err=%d\n", meta->rx_hash_err); - else + if (meta->hint_valid & XDP_META_FIELD_RSS) printf("rx_hash: 0x%X with RSS type:0x%X\n", meta->rx_hash, meta->rx_hash_type); + else + printf("No rx_hash, err=%d\n", meta->rx_hash_err); + + if (meta->hint_valid & XDP_META_FIELD_TS) { + __u64 ref_tstamp = gettime(clock_id); - printf("rx_timestamp: %llu (sec:%0.4f)\n", meta->rx_timestamp, - (double)meta->rx_timestamp / NANOSEC_PER_SEC); - if (meta->rx_timestamp) { - __u64 usr_clock = gettime(clock_id); - __u64 xdp_clock = meta->xdp_timestamp; - __s64 delta_X = xdp_clock - meta->rx_timestamp; - __s64 delta_X2U = usr_clock - xdp_clock; - - printf("XDP RX-time: %llu (sec:%0.4f) delta sec:%0.4f (%0.3f usec)\n", - xdp_clock, (double)xdp_clock / NANOSEC_PER_SEC, - (double)delta_X / NANOSEC_PER_SEC, - (double)delta_X / 1000); - - printf("AF_XDP time: %llu (sec:%0.4f) delta sec:%0.4f (%0.3f usec)\n", - usr_clock, (double)usr_clock / NANOSEC_PER_SEC, - (double)delta_X2U / NANOSEC_PER_SEC, - (double)delta_X2U / 1000); + /* store received timestamps to calculate a delta at tx */ + last_hw_rx_timestamp = meta->rx_timestamp; + last_xdp_rx_timestamp = meta->xdp_timestamp; + + print_tstamp_delta("HW RX-time", "User RX-time", + meta->rx_timestamp, ref_tstamp); + print_tstamp_delta("XDP RX-time", "User RX-time", + meta->xdp_timestamp, ref_tstamp); + } else { + printf("No rx_timestamp, err=%d\n", meta->rx_timestamp_err); } + if (meta->hint_valid & XDP_META_FIELD_VLAN_TAG) { + printf("rx_vlan_proto: 0x%X\n", ntohs(meta->rx_vlan_proto)); + printf("rx_vlan_tci: "); + print_vlan_tci(meta->rx_vlan_tci); + } else { + printf("No rx_vlan_tci or rx_vlan_proto, err=%d\n", + meta->rx_vlan_tag_err); + } } static void verify_skb_metadata(int fd) @@ -230,6 +279,129 @@ static void verify_skb_metadata(int fd) printf("skb hwtstamp is not found!\n"); } +static bool complete_tx(struct xsk *xsk, clockid_t clock_id) +{ + struct xsk_tx_metadata *meta; + __u64 addr; + void *data; + __u32 idx; + + if (!xsk_ring_cons__peek(&xsk->comp, 1, &idx)) + return false; + + addr = *xsk_ring_cons__comp_addr(&xsk->comp, idx); + data = xsk_umem__get_data(xsk->umem_area, addr); + meta = data - sizeof(struct xsk_tx_metadata); + + printf("%p: complete tx idx=%u addr=%llx\n", xsk, idx, addr); + + if (meta->completion.tx_timestamp) { + __u64 ref_tstamp = gettime(clock_id); + + print_tstamp_delta("HW TX-complete-time", "User TX-complete-time", + meta->completion.tx_timestamp, ref_tstamp); + print_tstamp_delta("XDP RX-time", "User TX-complete-time", + last_xdp_rx_timestamp, ref_tstamp); + print_tstamp_delta("HW RX-time", "HW TX-complete-time", + last_hw_rx_timestamp, meta->completion.tx_timestamp); + } else { + printf("No tx_timestamp\n"); + } + + xsk_ring_cons__release(&xsk->comp, 1); + + return true; +} + +#define swap(a, b, len) do { \ + for (int i = 0; i < len; i++) { \ + __u8 tmp = ((__u8 *)a)[i]; \ + ((__u8 *)a)[i] = ((__u8 *)b)[i]; \ + ((__u8 *)b)[i] = tmp; \ + } \ +} while (0) + +static void ping_pong(struct xsk *xsk, void *rx_packet, clockid_t clock_id) +{ + struct xsk_tx_metadata *meta; + struct ipv6hdr *ip6h = NULL; + struct iphdr *iph = NULL; + struct xdp_desc *tx_desc; + struct udphdr *udph; + struct ethhdr *eth; + __sum16 want_csum; + void *data; + __u32 idx; + int ret; + int len; + + ret = xsk_ring_prod__reserve(&xsk->tx, 1, &idx); + if (ret != 1) { + printf("%p: failed to reserve tx slot\n", xsk); + return; + } + + tx_desc = xsk_ring_prod__tx_desc(&xsk->tx, idx); + tx_desc->addr = idx % (UMEM_NUM / 2) * UMEM_FRAME_SIZE + sizeof(struct xsk_tx_metadata); + data = xsk_umem__get_data(xsk->umem_area, tx_desc->addr); + + meta = data - sizeof(struct xsk_tx_metadata); + memset(meta, 0, sizeof(*meta)); + meta->flags = XDP_TXMD_FLAGS_TIMESTAMP; + + eth = rx_packet; + + if (eth->h_proto == htons(ETH_P_IP)) { + iph = (void *)(eth + 1); + udph = (void *)(iph + 1); + } else if (eth->h_proto == htons(ETH_P_IPV6)) { + ip6h = (void *)(eth + 1); + udph = (void *)(ip6h + 1); + } else { + printf("%p: failed to detect IP version for ping pong %04x\n", xsk, eth->h_proto); + xsk_ring_prod__cancel(&xsk->tx, 1); + return; + } + + len = ETH_HLEN; + if (ip6h) + len += sizeof(*ip6h) + ntohs(ip6h->payload_len); + if (iph) + len += ntohs(iph->tot_len); + + swap(eth->h_dest, eth->h_source, ETH_ALEN); + if (iph) + swap(&iph->saddr, &iph->daddr, 4); + else + swap(&ip6h->saddr, &ip6h->daddr, 16); + swap(&udph->source, &udph->dest, 2); + + want_csum = udph->check; + if (ip6h) + udph->check = ~csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, + ntohs(udph->len), IPPROTO_UDP, 0); + else + udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, + ntohs(udph->len), IPPROTO_UDP, 0); + + meta->flags |= XDP_TXMD_FLAGS_CHECKSUM; + if (iph) + meta->request.csum_start = sizeof(*eth) + sizeof(*iph); + else + meta->request.csum_start = sizeof(*eth) + sizeof(*ip6h); + meta->request.csum_offset = offsetof(struct udphdr, check); + + printf("%p: ping-pong with csum=%04x (want %04x) csum_start=%d csum_offset=%d\n", + xsk, ntohs(udph->check), ntohs(want_csum), + meta->request.csum_start, meta->request.csum_offset); + + memcpy(data, rx_packet, len); /* don't share umem chunk for simplicity */ + tx_desc->options |= XDP_TX_METADATA; + tx_desc->len = len; + + xsk_ring_prod__submit(&xsk->tx, 1); +} + static int verify_metadata(struct xsk *rx_xsk, int rxq, int server_fd, clockid_t clock_id) { const struct xdp_desc *rx_desc; @@ -252,6 +424,13 @@ static int verify_metadata(struct xsk *rx_xsk, int rxq, int server_fd, clockid_t while (true) { errno = 0; + + for (i = 0; i < rxq; i++) { + ret = kick_rx(&rx_xsk[i]); + if (ret) + printf("kick_rx ret=%d\n", ret); + } + ret = poll(fds, rxq + 1, 1000); printf("poll: %d (%d) skip=%llu fail=%llu redir=%llu\n", ret, errno, bpf_obj->bss->pkts_skip, @@ -288,6 +467,22 @@ peek: verify_xdp_metadata(xsk_umem__get_data(xsk->umem_area, addr), clock_id); first_seg = false; + + if (!skip_tx) { + /* mirror first chunk back */ + ping_pong(xsk, xsk_umem__get_data(xsk->umem_area, addr), + clock_id); + + ret = kick_tx(xsk); + if (ret) + printf("kick_tx ret=%d\n", ret); + + for (int j = 0; j < 500; j++) { + if (complete_tx(xsk, clock_id)) + break; + usleep(10*1000); + } + } } xsk_ring_cons__release(&xsk->rx, 1); @@ -420,8 +615,10 @@ static void print_usage(void) { const char *usage = "Usage: xdp_hw_metadata [OPTIONS] [IFNAME]\n" - " -m Enable multi-buffer XDP for larger MTU\n" + " -c Run in copy mode (zerocopy is default)\n" " -h Display this help and exit\n\n" + " -m Enable multi-buffer XDP for larger MTU\n" + " -r Don't generate AF_XDP reply (rx metadata only)\n" "Generate test packets on the other machine with:\n" " echo -n xdp | nc -u -q1 9091\n"; @@ -432,14 +629,22 @@ static void read_args(int argc, char *argv[]) { int opt; - while ((opt = getopt(argc, argv, "mh")) != -1) { + while ((opt = getopt(argc, argv, "chmr")) != -1) { switch (opt) { - case 'm': - bind_flags |= XDP_USE_SG; + case 'c': + bind_flags &= ~XDP_USE_NEED_WAKEUP; + bind_flags &= ~XDP_ZEROCOPY; + bind_flags |= XDP_COPY; break; case 'h': print_usage(); exit(0); + case 'm': + bind_flags |= XDP_USE_SG; + break; + case 'r': + skip_tx = true; + break; case '?': if (isprint(optopt)) fprintf(stderr, "Unknown option: -%c\n", optopt); diff --git a/tools/testing/selftests/bpf/xdp_metadata.h b/tools/testing/selftests/bpf/xdp_metadata.h index 938a729bd3..87318ad111 100644 --- a/tools/testing/selftests/bpf/xdp_metadata.h +++ b/tools/testing/selftests/bpf/xdp_metadata.h @@ -9,12 +9,44 @@ #define ETH_P_IPV6 0x86DD #endif +#ifndef ETH_P_8021Q +#define ETH_P_8021Q 0x8100 +#endif + +#ifndef ETH_P_8021AD +#define ETH_P_8021AD 0x88A8 +#endif + +#ifndef BIT +#define BIT(nr) (1 << (nr)) +#endif + +/* Non-existent checksum status */ +#define XDP_CHECKSUM_MAGIC BIT(2) + +enum xdp_meta_field { + XDP_META_FIELD_TS = BIT(0), + XDP_META_FIELD_RSS = BIT(1), + XDP_META_FIELD_VLAN_TAG = BIT(2), +}; + struct xdp_meta { - __u64 rx_timestamp; + union { + __u64 rx_timestamp; + __s32 rx_timestamp_err; + }; __u64 xdp_timestamp; __u32 rx_hash; union { __u32 rx_hash_type; __s32 rx_hash_err; }; + union { + struct { + __be16 rx_vlan_proto; + __u16 rx_vlan_tci; + }; + __s32 rx_vlan_tag_err; + }; + enum xdp_meta_field hint_valid; }; diff --git a/tools/testing/selftests/bpf/xsk.c b/tools/testing/selftests/bpf/xsk.c index e574711eeb..25d568abf0 100644 --- a/tools/testing/selftests/bpf/xsk.c +++ b/tools/testing/selftests/bpf/xsk.c @@ -115,6 +115,7 @@ static void xsk_set_umem_config(struct xsk_umem_config *cfg, cfg->frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE; cfg->frame_headroom = XSK_UMEM__DEFAULT_FRAME_HEADROOM; cfg->flags = XSK_UMEM__DEFAULT_FLAGS; + cfg->tx_metadata_len = 0; return; } @@ -123,6 +124,7 @@ static void xsk_set_umem_config(struct xsk_umem_config *cfg, cfg->frame_size = usr_cfg->frame_size; cfg->frame_headroom = usr_cfg->frame_headroom; cfg->flags = usr_cfg->flags; + cfg->tx_metadata_len = usr_cfg->tx_metadata_len; } static int xsk_set_xdp_socket_config(struct xsk_socket_config *cfg, @@ -252,6 +254,7 @@ int xsk_umem__create(struct xsk_umem **umem_ptr, void *umem_area, mr.chunk_size = umem->config.frame_size; mr.headroom = umem->config.frame_headroom; mr.flags = umem->config.flags; + mr.tx_metadata_len = umem->config.tx_metadata_len; err = setsockopt(umem->fd, SOL_XDP, XDP_UMEM_REG, &mr, sizeof(mr)); if (err) { diff --git a/tools/testing/selftests/bpf/xsk.h b/tools/testing/selftests/bpf/xsk.h index 771570bc37..93c2cc413c 100644 --- a/tools/testing/selftests/bpf/xsk.h +++ b/tools/testing/selftests/bpf/xsk.h @@ -200,6 +200,7 @@ struct xsk_umem_config { __u32 frame_size; __u32 frame_headroom; __u32 flags; + __u32 tx_metadata_len; }; int xsk_attach_xdp_program(struct bpf_program *prog, int ifindex, u32 xdp_flags); diff --git a/tools/testing/selftests/breakpoints/breakpoint_test.c b/tools/testing/selftests/breakpoints/breakpoint_test.c index 3266cc9293..d46962a247 100644 --- a/tools/testing/selftests/breakpoints/breakpoint_test.c +++ b/tools/testing/selftests/breakpoints/breakpoint_test.c @@ -284,9 +284,9 @@ static void check_success(const char *msg) nr_tests++; if (ret) - ksft_test_result_pass(msg); + ksft_test_result_pass("%s", msg); else - ksft_test_result_fail(msg); + ksft_test_result_fail("%s", msg); } static void launch_instruction_breakpoints(char *buf, int local, int global) diff --git a/tools/testing/selftests/breakpoints/step_after_suspend_test.c b/tools/testing/selftests/breakpoints/step_after_suspend_test.c index 2cf6f10ab7..b8703c499d 100644 --- a/tools/testing/selftests/breakpoints/step_after_suspend_test.c +++ b/tools/testing/selftests/breakpoints/step_after_suspend_test.c @@ -89,7 +89,7 @@ int run_test(int cpu) wpid = waitpid(pid, &status, __WALL); if (wpid != pid) { - ksft_print_msg("waitpid() failed: $s\n", strerror(errno)); + ksft_print_msg("waitpid() failed: %s\n", strerror(errno)); return KSFT_FAIL; } if (WIFEXITED(status)) { diff --git a/tools/testing/selftests/capabilities/test_execve.c b/tools/testing/selftests/capabilities/test_execve.c index e3a352b020..7cde07a5df 100644 --- a/tools/testing/selftests/capabilities/test_execve.c +++ b/tools/testing/selftests/capabilities/test_execve.c @@ -88,11 +88,7 @@ static bool create_and_enter_ns(uid_t inner_uid) outer_uid = getuid(); outer_gid = getgid(); - /* - * TODO: If we're already root, we could skip creating the userns. - */ - - if (unshare(CLONE_NEWNS) == 0) { + if (outer_uid == 0 && unshare(CLONE_NEWNS) == 0) { ksft_print_msg("[NOTE]\tUsing global UIDs for tests\n"); if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) ksft_exit_fail_msg("PR_SET_KEEPCAPS - %s\n", diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/testing/selftests/cgroup/test_cpuset_prs.sh index a6e9848189..b5eb1be224 100755 --- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh +++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh @@ -146,71 +146,6 @@ test_add_proc() echo $$ > $CGROUP2/cgroup.procs # Move out the task } -# -# Testing the new "isolated" partition root type -# -test_isolated() -{ - cd $CGROUP2/test - echo 2-3 > cpuset.cpus - TYPE=$(cat cpuset.cpus.partition) - [[ $TYPE = member ]] || echo member > cpuset.cpus.partition - - console_msg "Change from member to root" - test_partition root - - console_msg "Change from root to isolated" - test_partition isolated - - console_msg "Change from isolated to member" - test_partition member - - console_msg "Change from member to isolated" - test_partition isolated - - console_msg "Change from isolated to root" - test_partition root - - console_msg "Change from root to member" - test_partition member - - # - # Testing partition root with no cpu - # - console_msg "Distribute all cpus to child partition" - echo +cpuset > cgroup.subtree_control - test_partition root - - mkdir A1 - cd A1 - echo 2-3 > cpuset.cpus - test_partition root - test_effective_cpus 2-3 - cd .. - test_effective_cpus "" - - console_msg "Moving task to partition test" - test_add_proc "No space left" - cd A1 - test_add_proc "" - cd .. - - console_msg "Shrink and expand child partition" - cd A1 - echo 2 > cpuset.cpus - cd .. - test_effective_cpus 3 - cd A1 - echo 2-3 > cpuset.cpus - cd .. - test_effective_cpus "" - - # Cleaning up - console_msg "Cleaning up" - echo $$ > $CGROUP2/cgroup.procs - [[ -d A1 ]] && rmdir A1 -} - # # Cpuset controller state transition test matrix. # @@ -297,14 +232,14 @@ TEST_MATRIX=( " C0-3:S+ C1-3:S+ C2-3 C4-5 X2-3 X2-3:P1 P2 P1 0 A1:0-1,A2:,A3:2-3,B1:4-5 \ A1:P0,A2:P1,A3:P2,B1:P1 2-3" " C0-3:S+ C1-3:S+ C2-3 C4 X2-3 X2-3:P1 P2 P1 0 A1:0-1,A2:,A3:2-3,B1:4 \ - A1:P0,A2:P1,A3:P2,B1:P1 2-4" + A1:P0,A2:P1,A3:P2,B1:P1 2-4,2-3" " C0-3:S+ C1-3:S+ C3 C4 X2-3 X2-3:P1 P2 P1 0 A1:0-1,A2:2,A3:3,B1:4 \ - A1:P0,A2:P1,A3:P2,B1:P1 2-4" + A1:P0,A2:P1,A3:P2,B1:P1 2-4,3" " C0-4:S+ C1-4:S+ C2-4 . X2-4 X2-4:P2 X4:P1 . 0 A1:0-1,A2:2-3,A3:4 \ - A1:P0,A2:P2,A3:P1 2-4" + A1:P0,A2:P2,A3:P1 2-4,2-3" " C0-4:X2-4:S+ C1-4:X2-4:S+:P2 C2-4:X4:P1 \ . . X5 . . 0 A1:0-4,A2:1-4,A3:2-4 \ - A1:P0,A2:P-2,A3:P-1 ." + A1:P0,A2:P-2,A3:P-1" " C0-4:X2-4:S+ C1-4:X2-4:S+:P2 C2-4:X4:P1 \ . . . X1 . 0 A1:0-1,A2:2-4,A3:2-4 \ A1:P0,A2:P2,A3:P-1 2-4" @@ -313,7 +248,7 @@ TEST_MATRIX=( " C0-3:S+ C1-3:S+ C2-3 . X2-3 X2-3 X2-3:P2:O2=0 . 0 A1:0-1,A2:1,A3:3 A1:P0,A3:P2 2-3" " C0-3:S+ C1-3:S+ C2-3 . X2-3 X2-3 X2-3:P2:O2=0 O2=1 0 A1:0-1,A2:1,A3:2-3 A1:P0,A3:P2 2-3" " C0-3:S+ C1-3:S+ C3 . X2-3 X2-3 P2:O3=0 . 0 A1:0-2,A2:1-2,A3: A1:P0,A3:P2 3" - " C0-3:S+ C1-3:S+ C3 . X2-3 X2-3 T:P2:O3=0 . 0 A1:0-2,A2:1-2,A3:1-2 A1:P0,A3:P-2 3" + " C0-3:S+ C1-3:S+ C3 . X2-3 X2-3 T:P2:O3=0 . 0 A1:0-2,A2:1-2,A3:1-2 A1:P0,A3:P-2 3," # An invalidated remote partition cannot self-recover from hotplug " C0-3:S+ C1-3:S+ C2 . X2-3 X2-3 T:P2:O2=0 O2=1 0 A1:0-3,A2:1-3,A3:2 A1:P0,A3:P-2" @@ -347,10 +282,10 @@ TEST_MATRIX=( # cpus_allowed/exclusive_cpus update tests " C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3 \ . C4 . P2 . 0 A1:4,A2:4,XA2:,XA3:,A3:4 \ - A1:P0,A3:P-2 ." + A1:P0,A3:P-2" " C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3 \ . X1 . P2 . 0 A1:0-3,A2:1-3,XA1:1,XA2:,XA3:,A3:2-3 \ - A1:P0,A3:P-2 ." + A1:P0,A3:P-2" " C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3 \ . . C3 P2 . 0 A1:0-2,A2:0-2,XA2:3,XA3:3,A3:3 \ A1:P0,A3:P2 3" @@ -359,13 +294,13 @@ TEST_MATRIX=( A1:P0,A3:P2 3" " C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3:P2 \ . . X3 . . 0 A1:0-3,A2:1-3,XA2:3,XA3:3,A3:2-3 \ - A1:P0,A3:P-2 ." + A1:P0,A3:P-2" " C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3:P2 \ . . C3 . . 0 A1:0-3,A2:3,XA2:3,XA3:3,A3:3 \ - A1:P0,A3:P-2 ." + A1:P0,A3:P-2" " C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3:P2 \ . C4 . . . 0 A1:4,A2:4,A3:4,XA1:,XA2:,XA3 \ - A1:P0,A3:P-2 ." + A1:P0,A3:P-2" # old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs Pstate ISOLCPUS # ------ ------ ------ ------ ------ ------ ------ ------ ---- ----- ------ -------- @@ -441,7 +376,7 @@ write_cpu_online() } fi echo $VAL > $CPUFILE - pause 0.01 + pause 0.05 } # @@ -573,12 +508,14 @@ dump_states() XECPUS=$DIR/cpuset.cpus.exclusive.effective PRS=$DIR/cpuset.cpus.partition PCPUS=$DIR/.__DEBUG__.cpuset.cpus.subpartitions + ISCPUS=$DIR/cpuset.cpus.isolated [[ -e $CPUS ]] && echo "$CPUS: $(cat $CPUS)" [[ -e $XCPUS ]] && echo "$XCPUS: $(cat $XCPUS)" [[ -e $ECPUS ]] && echo "$ECPUS: $(cat $ECPUS)" [[ -e $XECPUS ]] && echo "$XECPUS: $(cat $XECPUS)" [[ -e $PRS ]] && echo "$PRS: $(cat $PRS)" [[ -e $PCPUS ]] && echo "$PCPUS: $(cat $PCPUS)" + [[ -e $ISCPUS ]] && echo "$ISCPUS: $(cat $ISCPUS)" done } @@ -656,11 +593,17 @@ check_cgroup_states() # # Get isolated (including offline) CPUs by looking at -# /sys/kernel/debug/sched/domains and compare that with the expected value. +# /sys/kernel/debug/sched/domains and cpuset.cpus.isolated control file, +# if available, and compare that with the expected value. # -# Note that a sched domain of just 1 CPU will be considered isolated. +# Note that isolated CPUs from the sched/domains context include offline +# CPUs as well as CPUs in non-isolated 1-CPU partition. Those CPUs may +# not be included in the cpuset.cpus.isolated control file which contains +# only CPUs in isolated partitions. # -# $1 - expected isolated cpu list +# $1 - expected isolated cpu list(s) {,} +# - expected sched/domains value +# - cpuset.cpus.isolated value = if not defined # check_isolcpus() { @@ -668,8 +611,38 @@ check_isolcpus() ISOLCPUS= LASTISOLCPU= SCHED_DOMAINS=/sys/kernel/debug/sched/domains + ISCPUS=${CGROUP2}/cpuset.cpus.isolated + if [[ $EXPECT_VAL = . ]] + then + EXPECT_VAL= + EXPECT_VAL2= + elif [[ $(expr $EXPECT_VAL : ".*,.*") > 0 ]] + then + set -- $(echo $EXPECT_VAL | sed -e "s/,/ /g") + EXPECT_VAL=$1 + EXPECT_VAL2=$2 + else + EXPECT_VAL2=$EXPECT_VAL + fi + + # + # Check the debug isolated cpumask, if present + # + [[ -f $ISCPUS ]] && { + ISOLCPUS=$(cat $ISCPUS) + [[ "$EXPECT_VAL2" != "$ISOLCPUS" ]] && { + # Take a 50ms pause and try again + pause 0.05 + ISOLCPUS=$(cat $ISCPUS) + } + [[ "$EXPECT_VAL2" != "$ISOLCPUS" ]] && return 1 + ISOLCPUS= + } + + # + # Use the sched domain in debugfs to check isolated CPUs, if available + # [[ -d $SCHED_DOMAINS ]] || return 0 - [[ $EXPECT_VAL = . ]] && EXPECT_VAL= for ((CPU=0; CPU < $NR_CPUS; CPU++)) do @@ -713,6 +686,26 @@ test_fail() exit 1 } +# +# Check to see if there are unexpected isolated CPUs left +# +null_isolcpus_check() +{ + [[ $VERBOSE -gt 0 ]] || return 0 + # Retry a few times before printing error + RETRY=0 + while [[ $RETRY -lt 5 ]] + do + pause 0.01 + check_isolcpus "." + [[ $? -eq 0 ]] && return 0 + ((RETRY++)) + done + echo "Unexpected isolated CPUs: $ISOLCPUS" + dump_states + exit 1 +} + # # Run cpuset state transition test # $1 - test matrix name @@ -787,7 +780,7 @@ run_state_test() # NEWLIST=$(cat cpuset.cpus.effective) RETRY=0 - while [[ $NEWLIST != $CPULIST && $RETRY -lt 5 ]] + while [[ $NEWLIST != $CPULIST && $RETRY -lt 8 ]] do # Wait a bit longer & recheck a few times pause 0.01 @@ -798,12 +791,79 @@ run_state_test() echo "Effective cpus changed to $NEWLIST after test $I!" exit 1 } + null_isolcpus_check [[ $VERBOSE -gt 0 ]] && echo "Test $I done." ((I++)) done echo "All $I tests of $TEST PASSED." } +# +# Testing the new "isolated" partition root type +# +test_isolated() +{ + cd $CGROUP2/test + echo 2-3 > cpuset.cpus + TYPE=$(cat cpuset.cpus.partition) + [[ $TYPE = member ]] || echo member > cpuset.cpus.partition + + console_msg "Change from member to root" + test_partition root + + console_msg "Change from root to isolated" + test_partition isolated + + console_msg "Change from isolated to member" + test_partition member + + console_msg "Change from member to isolated" + test_partition isolated + + console_msg "Change from isolated to root" + test_partition root + + console_msg "Change from root to member" + test_partition member + + # + # Testing partition root with no cpu + # + console_msg "Distribute all cpus to child partition" + echo +cpuset > cgroup.subtree_control + test_partition root + + mkdir A1 + cd A1 + echo 2-3 > cpuset.cpus + test_partition root + test_effective_cpus 2-3 + cd .. + test_effective_cpus "" + + console_msg "Moving task to partition test" + test_add_proc "No space left" + cd A1 + test_add_proc "" + cd .. + + console_msg "Shrink and expand child partition" + cd A1 + echo 2 > cpuset.cpus + cd .. + test_effective_cpus 3 + cd A1 + echo 2-3 > cpuset.cpus + cd .. + test_effective_cpus "" + + # Cleaning up + console_msg "Cleaning up" + echo $$ > $CGROUP2/cgroup.procs + [[ -d A1 ]] && rmdir A1 + null_isolcpus_check +} + # # Wait for inotify event for the given file and read it # $1: cgroup file to wait for diff --git a/tools/testing/selftests/cgroup/test_freezer.c b/tools/testing/selftests/cgroup/test_freezer.c index ff519029f6..8845353aca 100644 --- a/tools/testing/selftests/cgroup/test_freezer.c +++ b/tools/testing/selftests/cgroup/test_freezer.c @@ -740,7 +740,7 @@ static int test_cgfreezer_ptraced(const char *root) /* * cg_check_frozen(cgroup, true) will fail here, - * because the task in in the TRACEd state. + * because the task is in the TRACEd state. */ if (cg_freeze_wait(cgroup, false)) goto cleanup; diff --git a/tools/testing/selftests/cgroup/test_zswap.c b/tools/testing/selftests/cgroup/test_zswap.c index c99d2adaca..47fdaa1464 100644 --- a/tools/testing/selftests/cgroup/test_zswap.c +++ b/tools/testing/selftests/cgroup/test_zswap.c @@ -50,9 +50,9 @@ static int get_zswap_stored_pages(size_t *value) return read_int("/sys/kernel/debug/zswap/stored_pages", value); } -static int get_zswap_written_back_pages(size_t *value) +static int get_cg_wb_count(const char *cg) { - return read_int("/sys/kernel/debug/zswap/written_back_pages", value); + return cg_read_key_long(cg, "memory.stat", "zswp_wb"); } static long get_zswpout(const char *cgroup) @@ -73,6 +73,24 @@ static int allocate_bytes(const char *cgroup, void *arg) return 0; } +static char *setup_test_group_1M(const char *root, const char *name) +{ + char *group_name = cg_name(root, name); + + if (!group_name) + return NULL; + if (cg_create(group_name)) + goto fail; + if (cg_write(group_name, "memory.max", "1M")) { + cg_destroy(group_name); + goto fail; + } + return group_name; +fail: + free(group_name); + return NULL; +} + /* * Sanity test to check that pages are written into zswap. */ @@ -117,43 +135,51 @@ out: /* * When trying to store a memcg page in zswap, if the memcg hits its memory - * limit in zswap, writeback should not be triggered. - * - * This was fixed with commit 0bdf0efa180a("zswap: do not shrink if cgroup may - * not zswap"). Needs to be revised when a per memcg writeback mechanism is - * implemented. + * limit in zswap, writeback should affect only the zswapped pages of that + * memcg. */ static int test_no_invasive_cgroup_shrink(const char *root) { - size_t written_back_before, written_back_after; int ret = KSFT_FAIL; - char *test_group; + size_t control_allocation_size = MB(10); + char *control_allocation, *wb_group = NULL, *control_group = NULL; /* Set up */ - test_group = cg_name(root, "no_shrink_test"); - if (!test_group) - goto out; - if (cg_create(test_group)) + wb_group = setup_test_group_1M(root, "per_memcg_wb_test1"); + if (!wb_group) + return KSFT_FAIL; + if (cg_write(wb_group, "memory.zswap.max", "10K")) goto out; - if (cg_write(test_group, "memory.max", "1M")) + control_group = setup_test_group_1M(root, "per_memcg_wb_test2"); + if (!control_group) goto out; - if (cg_write(test_group, "memory.zswap.max", "10K")) + + /* Push some test_group2 memory into zswap */ + if (cg_enter_current(control_group)) goto out; - if (get_zswap_written_back_pages(&written_back_before)) + control_allocation = malloc(control_allocation_size); + for (int i = 0; i < control_allocation_size; i += 4095) + control_allocation[i] = 'a'; + if (cg_read_key_long(control_group, "memory.stat", "zswapped") < 1) goto out; - /* Allocate 10x memory.max to push memory into zswap */ - if (cg_run(test_group, allocate_bytes, (void *)MB(10))) + /* Allocate 10x memory.max to push wb_group memory into zswap and trigger wb */ + if (cg_run(wb_group, allocate_bytes, (void *)MB(10))) goto out; - /* Verify that no writeback happened because of the memcg allocation */ - if (get_zswap_written_back_pages(&written_back_after)) - goto out; - if (written_back_after == written_back_before) + /* Verify that only zswapped memory from gwb_group has been written back */ + if (get_cg_wb_count(wb_group) > 0 && get_cg_wb_count(control_group) == 0) ret = KSFT_PASS; out: - cg_destroy(test_group); - free(test_group); + cg_enter_current(root); + if (control_group) { + cg_destroy(control_group); + free(control_group); + } + cg_destroy(wb_group); + free(wb_group); + if (control_allocation) + free(control_allocation); return ret; } diff --git a/tools/testing/selftests/damon/Makefile b/tools/testing/selftests/damon/Makefile index b71247ba71..8a1cc2bf18 100644 --- a/tools/testing/selftests/damon/Makefile +++ b/tools/testing/selftests/damon/Makefile @@ -2,6 +2,7 @@ # Makefile for damon selftests TEST_GEN_FILES += huge_count_read_write +TEST_GEN_FILES += access_memory TEST_FILES = _chk_dependency.sh _debugfs_common.sh TEST_PROGS = debugfs_attrs.sh debugfs_schemes.sh debugfs_target_ids.sh @@ -9,6 +10,8 @@ TEST_PROGS += debugfs_empty_targets.sh debugfs_huge_count_read_write.sh TEST_PROGS += debugfs_duplicate_context_creation.sh TEST_PROGS += debugfs_rm_non_contexts.sh TEST_PROGS += sysfs.sh sysfs_update_removed_scheme_dir.sh +TEST_PROGS += sysfs_update_schemes_tried_regions_hang.py +TEST_PROGS += sysfs_update_schemes_tried_regions_wss_estimation.py TEST_PROGS += reclaim.sh lru_sort.sh include ../lib.mk diff --git a/tools/testing/selftests/damon/_damon_sysfs.py b/tools/testing/selftests/damon/_damon_sysfs.py new file mode 100644 index 0000000000..e98cf4b6a4 --- /dev/null +++ b/tools/testing/selftests/damon/_damon_sysfs.py @@ -0,0 +1,322 @@ +# SPDX-License-Identifier: GPL-2.0 + +import os + +sysfs_root = '/sys/kernel/mm/damon/admin' + +def write_file(path, string): + "Returns error string if failed, or None otherwise" + string = '%s' % string + try: + with open(path, 'w') as f: + f.write(string) + except Exception as e: + return '%s' % e + return None + +def read_file(path): + '''Returns the read content and error string. The read content is None if + the reading failed''' + try: + with open(path, 'r') as f: + return f.read(), None + except Exception as e: + return None, '%s' % e + +class DamosAccessPattern: + size = None + nr_accesses = None + age = None + scheme = None + + def __init__(self, size=None, nr_accesses=None, age=None): + self.size = size + self.nr_accesses = nr_accesses + self.age = age + + if self.size == None: + self.size = [0, 2**64 - 1] + if self.nr_accesses == None: + self.nr_accesses = [0, 2**64 - 1] + if self.age == None: + self.age = [0, 2**64 - 1] + + def sysfs_dir(self): + return os.path.join(self.scheme.sysfs_dir(), 'access_pattern') + + def stage(self): + err = write_file( + os.path.join(self.sysfs_dir(), 'sz', 'min'), self.size[0]) + if err != None: + return err + err = write_file( + os.path.join(self.sysfs_dir(), 'sz', 'max'), self.size[1]) + if err != None: + return err + err = write_file(os.path.join(self.sysfs_dir(), 'nr_accesses', 'min'), + self.nr_accesses[0]) + if err != None: + return err + err = write_file(os.path.join(self.sysfs_dir(), 'nr_accesses', 'max'), + self.nr_accesses[1]) + if err != None: + return err + err = write_file( + os.path.join(self.sysfs_dir(), 'age', 'min'), self.age[0]) + if err != None: + return err + err = write_file( + os.path.join(self.sysfs_dir(), 'age', 'max'), self.age[1]) + if err != None: + return err + +class Damos: + action = None + access_pattern = None + # todo: Support quotas, watermarks, stats, tried_regions + idx = None + context = None + tried_bytes = None + + def __init__(self, action='stat', access_pattern=DamosAccessPattern()): + self.action = action + self.access_pattern = access_pattern + self.access_pattern.scheme = self + + def sysfs_dir(self): + return os.path.join( + self.context.sysfs_dir(), 'schemes', '%d' % self.idx) + + def stage(self): + err = write_file(os.path.join(self.sysfs_dir(), 'action'), self.action) + if err != None: + return err + err = self.access_pattern.stage() + if err != None: + return err + + # disable quotas + err = write_file(os.path.join(self.sysfs_dir(), 'quotas', 'ms'), '0') + if err != None: + return err + err = write_file( + os.path.join(self.sysfs_dir(), 'quotas', 'bytes'), '0') + if err != None: + return err + + # disable watermarks + err = write_file( + os.path.join(self.sysfs_dir(), 'watermarks', 'metric'), 'none') + if err != None: + return err + + # disable filters + err = write_file( + os.path.join(self.sysfs_dir(), 'filters', 'nr_filters'), '0') + if err != None: + return err + +class DamonTarget: + pid = None + # todo: Support target regions if test is made + idx = None + context = None + + def __init__(self, pid): + self.pid = pid + + def sysfs_dir(self): + return os.path.join( + self.context.sysfs_dir(), 'targets', '%d' % self.idx) + + def stage(self): + err = write_file( + os.path.join(self.sysfs_dir(), 'regions', 'nr_regions'), '0') + if err != None: + return err + return write_file( + os.path.join(self.sysfs_dir(), 'pid_target'), self.pid) + +class DamonAttrs: + sample_us = None + aggr_us = None + update_us = None + min_nr_regions = None + max_nr_regions = None + context = None + + def __init__(self, sample_us=5000, aggr_us=100000, update_us=1000000, + min_nr_regions=10, max_nr_regions=1000): + self.sample_us = sample_us + self.aggr_us = aggr_us + self.update_us = update_us + self.min_nr_regions = min_nr_regions + self.max_nr_regions = max_nr_regions + + def interval_sysfs_dir(self): + return os.path.join(self.context.sysfs_dir(), 'monitoring_attrs', + 'intervals') + + def nr_regions_range_sysfs_dir(self): + return os.path.join(self.context.sysfs_dir(), 'monitoring_attrs', + 'nr_regions') + + def stage(self): + err = write_file(os.path.join(self.interval_sysfs_dir(), 'sample_us'), + self.sample_us) + if err != None: + return err + err = write_file(os.path.join(self.interval_sysfs_dir(), 'aggr_us'), + self.aggr_us) + if err != None: + return err + err = write_file(os.path.join(self.interval_sysfs_dir(), 'update_us'), + self.update_us) + if err != None: + return err + + err = write_file( + os.path.join(self.nr_regions_range_sysfs_dir(), 'min'), + self.min_nr_regions) + if err != None: + return err + + err = write_file( + os.path.join(self.nr_regions_range_sysfs_dir(), 'max'), + self.max_nr_regions) + if err != None: + return err + +class DamonCtx: + ops = None + monitoring_attrs = None + targets = None + schemes = None + kdamond = None + idx = None + + def __init__(self, ops='paddr', monitoring_attrs=DamonAttrs(), targets=[], + schemes=[]): + self.ops = ops + self.monitoring_attrs = monitoring_attrs + self.monitoring_attrs.context = self + + self.targets = targets + for idx, target in enumerate(self.targets): + target.idx = idx + target.context = self + + self.schemes = schemes + for idx, scheme in enumerate(self.schemes): + scheme.idx = idx + scheme.context = self + + def sysfs_dir(self): + return os.path.join(self.kdamond.sysfs_dir(), 'contexts', + '%d' % self.idx) + + def stage(self): + err = write_file( + os.path.join(self.sysfs_dir(), 'operations'), self.ops) + if err != None: + return err + err = self.monitoring_attrs.stage() + if err != None: + return err + + nr_targets_file = os.path.join( + self.sysfs_dir(), 'targets', 'nr_targets') + content, err = read_file(nr_targets_file) + if err != None: + return err + if int(content) != len(self.targets): + err = write_file(nr_targets_file, '%d' % len(self.targets)) + if err != None: + return err + for target in self.targets: + err = target.stage() + if err != None: + return err + + nr_schemes_file = os.path.join( + self.sysfs_dir(), 'schemes', 'nr_schemes') + content, err = read_file(nr_schemes_file) + if int(content) != len(self.schemes): + err = write_file(nr_schemes_file, '%d' % len(self.schemes)) + if err != None: + return err + for scheme in self.schemes: + err = scheme.stage() + if err != None: + return err + return None + +class Kdamond: + state = None + pid = None + contexts = None + idx = None # index of this kdamond between siblings + kdamonds = None # parent + + def __init__(self, contexts=[]): + self.contexts = contexts + for idx, context in enumerate(self.contexts): + context.idx = idx + context.kdamond = self + + def sysfs_dir(self): + return os.path.join(self.kdamonds.sysfs_dir(), '%d' % self.idx) + + def start(self): + nr_contexts_file = os.path.join(self.sysfs_dir(), + 'contexts', 'nr_contexts') + content, err = read_file(nr_contexts_file) + if err != None: + return err + if int(content) != len(self.contexts): + err = write_file(nr_contexts_file, '%d' % len(self.contexts)) + if err != None: + return err + + for context in self.contexts: + err = context.stage() + if err != None: + return err + err = write_file(os.path.join(self.sysfs_dir(), 'state'), 'on') + return err + + def update_schemes_tried_bytes(self): + err = write_file(os.path.join(self.sysfs_dir(), 'state'), + 'update_schemes_tried_bytes') + if err != None: + return err + for context in self.contexts: + for scheme in context.schemes: + content, err = read_file(os.path.join(scheme.sysfs_dir(), + 'tried_regions', 'total_bytes')) + if err != None: + return err + scheme.tried_bytes = int(content) + +class Kdamonds: + kdamonds = [] + + def __init__(self, kdamonds=[]): + self.kdamonds = kdamonds + for idx, kdamond in enumerate(self.kdamonds): + kdamond.idx = idx + kdamond.kdamonds = self + + def sysfs_dir(self): + return os.path.join(sysfs_root, 'kdamonds') + + def start(self): + err = write_file(os.path.join(self.sysfs_dir(), 'nr_kdamonds'), + '%s' % len(self.kdamonds)) + if err != None: + return err + for kdamond in self.kdamonds: + err = kdamond.start() + if err != None: + return err + return None diff --git a/tools/testing/selftests/damon/access_memory.c b/tools/testing/selftests/damon/access_memory.c new file mode 100644 index 0000000000..585a2fa543 --- /dev/null +++ b/tools/testing/selftests/damon/access_memory.c @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Artificial memory access program for testing DAMON. + */ + +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + char **regions; + clock_t start_clock; + int nr_regions; + int sz_region; + int access_time_ms; + int i; + + if (argc != 4) { + printf("Usage: %s