History

Merge https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next

Alexei Starovoitov says: ==================== pull-request: bpf-next 2021-09-17 We've added 63 non-merge commits during the last 12 day(s) which contain a total of 65 files changed, 2653 insertions(+), 751 deletions(-). The main changes are: 1) Streamline internal BPF program sections handling and bpf_program__set_attach_target() in libbpf, from Andrii. 2) Add support for new btf kind BTF_KIND_TAG, from Yonghong. 3) Introduce bpf_get_branch_snapshot() to capture LBR, from Song. 4) IMUL optimization for x86-64 JIT, from Jie. 5) xsk selftest improvements, from Magnus. 6) Introduce legacy kprobe events support in libbpf, from Rafael. 7) Access hw timestamp through BPF's __sk_buff, from Vadim. * https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next: (63 commits) selftests/bpf: Fix a few compiler warnings libbpf: Constify all high-level program attach APIs libbpf: Schedule open_opts.attach_prog_fd deprecation since v0.7 selftests/bpf: Switch fexit_bpf2bpf selftest to set_attach_target() API libbpf: Allow skipping attach_func_name in bpf_program__set_attach_target() libbpf: Deprecated bpf_object_open_opts.relaxed_core_relocs selftests/bpf: Stop using relaxed_core_relocs which has no effect libbpf: Use pre-setup sec_def in libbpf_find_attach_btf_id() bpf: Update bpf_get_smp_processor_id() documentation libbpf: Add sphinx code documentation comments selftests/bpf: Skip btf_tag test if btf_tag attribute not supported docs/bpf: Add documentation for BTF_KIND_TAG selftests/bpf: Add a test with a bpf program with btf_tag attributes selftests/bpf: Test BTF_KIND_TAG for deduplication selftests/bpf: Add BTF_KIND_TAG unit tests selftests/bpf: Change NAME_NTH/IS_NAME_NTH for BTF_KIND_TAG format selftests/bpf: Test libbpf API function btf__add_tag() bpftool: Add support for BTF_KIND_TAG libbpf: Add support for BTF_KIND_TAG libbpf: Rename btf_{hash,equal}_int to btf_{hash,equal}_int_tag ... ====================

Jakub Kicinski committed 5 years ago

Commit af54faa2 parents f68d08c ca21a3e65 files · +2653 −751Browse files

Unified · Split

65 files
  1. Documentation/bpf/btf.rst +28 −1
  2. arch/x86/events/intel/core.c +61 −6
  3. arch/x86/events/intel/ds.c +1 −1
  4. arch/x86/events/intel/lbr.c +5 −15
  5. arch/x86/events/perf_event.h +19 −0
  6. arch/x86/net/bpf_jit_comp.c +23 −30
  7. include/linux/perf_event.h +23 −0
  8. include/uapi/linux/bpf.h +25 −1
  9. include/uapi/linux/btf.h +35 −20
  10. kernel/bpf/btf.c +128 −0
  11. kernel/bpf/trampoline.c +2 −1
  12. kernel/events/core.c +2 −0
  13. kernel/trace/bpf_trace.c +30 −0
  14. lib/test_bpf.c +1 −0
  15. net/bpf/test_run.c +11 −5
  16. net/core/filter.c +21 −0
  17. tools/bpf/bpftool/Makefile +3 −0
  18. tools/bpf/bpftool/btf.c +12 −0
  19. tools/bpf/bpftool/gen.c +19 −12
  20. tools/bpf/resolve_btfids/Makefile +3 −2
  21. tools/include/uapi/linux/bpf.h +25 −1
  22. tools/include/uapi/linux/btf.h +35 −20
  23. tools/lib/bpf/.gitignore +0 −1
  24. tools/lib/bpf/Makefile +29 −10
  25. tools/lib/bpf/btf.c +76 −8
  26. tools/lib/bpf/btf.h +87 −0
  27. tools/lib/bpf/btf_dump.c +3 −0
  28. tools/lib/bpf/libbpf.c +288 −143
  29. tools/lib/bpf/libbpf.h +22 −19
  30. tools/lib/bpf/libbpf.map +5 −0
  31. tools/lib/bpf/libbpf_common.h +24 −0
  32. tools/lib/bpf/libbpf_internal.h +21 −6
  33. tools/lib/bpf/libbpf_version.h +9 −0
  34. tools/lib/bpf/xsk.c +2 −2
  35. tools/testing/selftests/bpf/.gitignore +3 −2
  36. tools/testing/selftests/bpf/Makefile +2 −2
  37. tools/testing/selftests/bpf/README.rst +14 −0
  38. tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c +17 −2
  39. tools/testing/selftests/bpf/btf_helpers.c +6 −1
  40. tools/testing/selftests/bpf/prog_tests/bpf_iter.c +2 −4
  41. tools/testing/selftests/bpf/prog_tests/btf.c +422 −19
  42. tools/testing/selftests/bpf/prog_tests/btf_tag.c +20 −0
  43. tools/testing/selftests/bpf/prog_tests/btf_write.c +21 −0
  44. tools/testing/selftests/bpf/prog_tests/core_reloc.c +4 −13
  45. tools/testing/selftests/bpf/prog_tests/fexit_bpf2bpf.c +26 −17
  46. tools/testing/selftests/bpf/prog_tests/get_branch_snapshot.c +100 −0
  47. tools/testing/selftests/bpf/prog_tests/module_attach.c +0 −39
  48. tools/testing/selftests/bpf/prog_tests/skb_ctx.c +6 −0
  49. tools/testing/selftests/bpf/prog_tests/skeleton.c +6 −0
  50. tools/testing/selftests/bpf/prog_tests/tailcalls.c +20 −5
  51. tools/testing/selftests/bpf/prog_tests/tc_redirect.c +1 −1
  52. tools/testing/selftests/bpf/progs/bpf_cubic.c +3 −9
  53. tools/testing/selftests/bpf/progs/get_branch_snapshot.c +40 −0
  54. tools/testing/selftests/bpf/progs/tag.c +49 −0
  55. tools/testing/selftests/bpf/progs/tailcall6.c +34 −0
  56. tools/testing/selftests/bpf/progs/test_skb_ctx.c +6 −0
  57. tools/testing/selftests/bpf/test_btf.h +3 −0
  58. tools/testing/selftests/bpf/test_progs.c +39 −0
  59. tools/testing/selftests/bpf/test_progs.h +2 −0
  60. tools/testing/selftests/bpf/trace_helpers.c +37 −0
  61. tools/testing/selftests/bpf/trace_helpers.h +5 −0
  62. tools/testing/selftests/bpf/verifier/ctx_skb.c +60 −0
  63. tools/testing/selftests/bpf/verifier/jit.c +19 −3
  64. tools/testing/selftests/bpf/xdpxceiver.c +570 −302
  65. tools/testing/selftests/bpf/xdpxceiver.h +38 −28
Documentation/bpf/btf.rst+28−1
@@ -85,6 +85,7 @@ sequentially and type id is assigned to each recognized type starting from id · 84 unmodified lines
8585 #define BTF_KIND_VAR 14 /* Variable */
8686 #define BTF_KIND_DATASEC 15 /* Section */
8787 #define BTF_KIND_FLOAT 16 /* Floating point */
88+ #define BTF_KIND_TAG 17 /* Tag */
8889
8990 Note that the type section encodes debug info, not just pure types.
9091 ``BTF_KIND_FUNC`` is not a type, and it represents a defined subprogram.
@@ -106,7 +107,7 @@ Each type contains the following common data:: · 15 unmodified lines
106107 * "size" tells the size of the type it is describing.
107108 *
108109 * "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT,
109− * FUNC and FUNC_PROTO.
110+ * FUNC, FUNC_PROTO and TAG.
110111 * "type" is a type_id referring to another type.
111112 */
112113 union {
@@ -465,6 +466,32 @@ map definition. · 352 unmodified lines
465466
466467 No additional type data follow ``btf_type``.
467468
469+2.2.17 BTF_KIND_TAG
470+~~~~~~~~~~~~~~~~~~~
471+
472+``struct btf_type`` encoding requirement:
473+ * ``name_off``: offset to a non-empty string
474+ * ``info.kind_flag``: 0
475+ * ``info.kind``: BTF_KIND_TAG
476+ * ``info.vlen``: 0
477+ * ``type``: ``struct``, ``union``, ``func`` or ``var``
478+
479+``btf_type`` is followed by ``struct btf_tag``.::
480+
481+ struct btf_tag {
482+ __u32 component_idx;
483+ };
484+
485+The ``name_off`` encodes btf_tag attribute string.
486+The ``type`` should be ``struct``, ``union``, ``func`` or ``var``.
487+For ``var`` type, ``btf_tag.component_idx`` must be ``-1``.
488+For the other three types, if the btf_tag attribute is
489+applied to the ``struct``, ``union`` or ``func`` itself,
490+``btf_tag.component_idx`` must be ``-1``. Otherwise,
491+the attribute is applied to a ``struct``/``union`` member or
492+a ``func`` argument, and ``btf_tag.component_idx`` should be a
493+valid index (starting from 0) pointing to a member or an argument.
494+
468495 3. BTF Kernel API
469496 *****************
470497
arch/x86/events/intel/core.c+61−6
@@ -2143,19 +2143,19 @@ static __initconst const u64 knl_hw_cache_extra_regs · 2142 unmodified lines
21432143 * However, there are some cases which may change PEBS status, e.g. PMI
21442144 * throttle. The PEBS_ENABLE should be updated where the status changes.
21452145 */
2146−static void __intel_pmu_disable_all(void)
2146+static __always_inline void __intel_pmu_disable_all(bool bts)
21472147 {
21482148 struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
21492149
21502150 wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0);
21512151
2152− if (test_bit(INTEL_PMC_IDX_FIXED_BTS, cpuc->active_mask))
2152+ if (bts && test_bit(INTEL_PMC_IDX_FIXED_BTS, cpuc->active_mask))
21532153 intel_pmu_disable_bts();
21542154 }
21552155
2156−static void intel_pmu_disable_all(void)
2156+static __always_inline void intel_pmu_disable_all(void)
21572157 {
2158− __intel_pmu_disable_all();
2158+ __intel_pmu_disable_all(true);
21592159 intel_pmu_pebs_disable_all();
21602160 intel_pmu_lbr_disable_all();
21612161 }
@@ -2186,6 +2186,49 @@ static void intel_pmu_enable_all(int added) · 24 unmodified lines
21862186 __intel_pmu_enable_all(added, false);
21872187 }
21882188
2189+static noinline int
2190+__intel_pmu_snapshot_branch_stack(struct perf_branch_entry *entries,
2191+ unsigned int cnt, unsigned long flags)
2192+{
2193+ struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
2194+
2195+ intel_pmu_lbr_read();
2196+ cnt = min_t(unsigned int, cnt, x86_pmu.lbr_nr);
2197+
2198+ memcpy(entries, cpuc->lbr_entries, sizeof(struct perf_branch_entry) * cnt);
2199+ intel_pmu_enable_all(0);
2200+ local_irq_restore(flags);
2201+ return cnt;
2202+}
2203+
2204+static int
2205+intel_pmu_snapshot_branch_stack(struct perf_branch_entry *entries, unsigned int cnt)
2206+{
2207+ unsigned long flags;
2208+
2209+ /* must not have branches... */
2210+ local_irq_save(flags);
2211+ __intel_pmu_disable_all(false); /* we don't care about BTS */
2212+ __intel_pmu_pebs_disable_all();
2213+ __intel_pmu_lbr_disable();
2214+ /* ... until here */
2215+ return __intel_pmu_snapshot_branch_stack(entries, cnt, flags);
2216+}
2217+
2218+static int
2219+intel_pmu_snapshot_arch_branch_stack(struct perf_branch_entry *entries, unsigned int cnt)
2220+{
2221+ unsigned long flags;
2222+
2223+ /* must not have branches... */
2224+ local_irq_save(flags);
2225+ __intel_pmu_disable_all(false); /* we don't care about BTS */
2226+ __intel_pmu_pebs_disable_all();
2227+ __intel_pmu_arch_lbr_disable();
2228+ /* ... until here */
2229+ return __intel_pmu_snapshot_branch_stack(entries, cnt, flags);
2230+}
2231+
21892232 /*
21902233 * Workaround for:
21912234 * Intel Errata AAK100 (model 26)
@@ -2929,7 +2972,7 @@ static int intel_pmu_handle_irq(struct pt_regs *regs) · 737 unmodified lines
29292972 apic_write(APIC_LVTPC, APIC_DM_NMI);
29302973 intel_bts_disable_local();
29312974 cpuc->enabled = 0;
2932− __intel_pmu_disable_all();
2975+ __intel_pmu_disable_all(true);
29332976 handled = intel_pmu_drain_bts_buffer();
29342977 handled += intel_bts_interrupt();
29352978 status = intel_pmu_get_status();
@@ -6283,9 +6326,21 @@ __init int intel_pmu_init(void) · 3347 unmodified lines
62836326 x86_pmu.lbr_nr = 0;
62846327 }
62856328
6286− if (x86_pmu.lbr_nr)
6329+ if (x86_pmu.lbr_nr) {
62876330 pr_cont("%d-deep LBR, ", x86_pmu.lbr_nr);
62886331
6332+ /* only support branch_stack snapshot for perfmon >= v2 */
6333+ if (x86_pmu.disable_all == intel_pmu_disable_all) {
6334+ if (boot_cpu_has(X86_FEATURE_ARCH_LBR)) {
6335+ static_call_update(perf_snapshot_branch_stack,
6336+ intel_pmu_snapshot_arch_branch_stack);
6337+ } else {
6338+ static_call_update(perf_snapshot_branch_stack,
6339+ intel_pmu_snapshot_branch_stack);
6340+ }
6341+ }
6342+ }
6343+
62896344 intel_pmu_check_extra_regs(x86_pmu.extra_regs);
62906345
62916346 /* Support full width counters using alternative MSR range */
arch/x86/events/intel/ds.c+1−1
@@ -1301,7 +1301,7 @@ void intel_pmu_pebs_disable_all(void) · 1300 unmodified lines
13011301 struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
13021302
13031303 if (cpuc->pebs_enabled)
1304− wrmsrl(MSR_IA32_PEBS_ENABLE, 0);
1304+ __intel_pmu_pebs_disable_all();
13051305 }
13061306
13071307 static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs)
arch/x86/events/intel/lbr.c+5−15
@@ -228,20 +228,6 @@ static void __intel_pmu_lbr_enable(bool pmi) · 227 unmodified lines
228228 wrmsrl(MSR_ARCH_LBR_CTL, lbr_select | ARCH_LBR_CTL_LBREN);
229229 }
230230
231−static void __intel_pmu_lbr_disable(void)
232−{
233− u64 debugctl;
234−
235− if (static_cpu_has(X86_FEATURE_ARCH_LBR)) {
236− wrmsrl(MSR_ARCH_LBR_CTL, 0);
237− return;
238− }
239−
240− rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctl);
241− debugctl &= ~(DEBUGCTLMSR_LBR | DEBUGCTLMSR_FREEZE_LBRS_ON_PMI);
242− wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctl);
243−}
244−
245231 void intel_pmu_lbr_reset_32(void)
246232 {
247233 int i;
@@ -779,8 +765,12 @@ void intel_pmu_lbr_disable_all(void) · 531 unmodified lines
779765 {
780766 struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
781767
782− if (cpuc->lbr_users && !vlbr_exclude_host())
768+ if (cpuc->lbr_users && !vlbr_exclude_host()) {
769+ if (static_cpu_has(X86_FEATURE_ARCH_LBR))
770+ return __intel_pmu_arch_lbr_disable();
771+
783772 __intel_pmu_lbr_disable();
773+ }
784774 }
785775
786776 void intel_pmu_lbr_read_32(struct cpu_hw_events *cpuc)
arch/x86/events/perf_event.h+19−0
@@ -1240,6 +1240,25 @@ static inline bool intel_pmu_has_bts(struct perf_event *event) · 1239 unmodified lines
12401240 return intel_pmu_has_bts_period(event, hwc->sample_period);
12411241 }
12421242
1243+static __always_inline void __intel_pmu_pebs_disable_all(void)
1244+{
1245+ wrmsrl(MSR_IA32_PEBS_ENABLE, 0);
1246+}
1247+
1248+static __always_inline void __intel_pmu_arch_lbr_disable(void)
1249+{
1250+ wrmsrl(MSR_ARCH_LBR_CTL, 0);
1251+}
1252+
1253+static __always_inline void __intel_pmu_lbr_disable(void)
1254+{
1255+ u64 debugctl;
1256+
1257+ rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctl);
1258+ debugctl &= ~(DEBUGCTLMSR_LBR | DEBUGCTLMSR_FREEZE_LBRS_ON_PMI);
1259+ wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctl);
1260+}
1261+
12431262 int intel_pmu_save_and_restart(struct perf_event *event);
12441263
12451264 struct event_constraint *
arch/x86/net/bpf_jit_comp.c+23−30
@@ -1070,41 +1070,34 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, · 1069 unmodified lines
10701070 break;
10711071
10721072 case BPF_ALU | BPF_MUL | BPF_K:
1073− case BPF_ALU | BPF_MUL | BPF_X:
10741073 case BPF_ALU64 | BPF_MUL | BPF_K:
1075− case BPF_ALU64 | BPF_MUL | BPF_X:
1076− {
1077− bool is64 = BPF_CLASS(insn->code) == BPF_ALU64;
1074+ if (BPF_CLASS(insn->code) == BPF_ALU64)
1075+ EMIT1(add_2mod(0x48, dst_reg, dst_reg));
1076+ else if (is_ereg(dst_reg))
1077+ EMIT1(add_2mod(0x40, dst_reg, dst_reg));
10781078
1079− if (dst_reg != BPF_REG_0)
1080− EMIT1(0x50); /* push rax */
1081− if (dst_reg != BPF_REG_3)
1082− EMIT1(0x52); /* push rdx */
1079+ if (is_imm8(imm32))
1080+ /* imul dst_reg, dst_reg, imm8 */
1081+ EMIT3(0x6B, add_2reg(0xC0, dst_reg, dst_reg),
1082+ imm32);
1083+ else
1084+ /* imul dst_reg, dst_reg, imm32 */
1085+ EMIT2_off32(0x69,
1086+ add_2reg(0xC0, dst_reg, dst_reg),
1087+ imm32);
1088+ break;
10831089
1084− /* mov r11, dst_reg */
1085− EMIT_mov(AUX_REG, dst_reg);
1090+ case BPF_ALU | BPF_MUL | BPF_X:
1091+ case BPF_ALU64 | BPF_MUL | BPF_X:
1092+ if (BPF_CLASS(insn->code) == BPF_ALU64)
1093+ EMIT1(add_2mod(0x48, src_reg, dst_reg));
1094+ else if (is_ereg(dst_reg) || is_ereg(src_reg))
1095+ EMIT1(add_2mod(0x40, src_reg, dst_reg));
10861096
1087− if (BPF_SRC(insn->code) == BPF_X)
1088− emit_mov_reg(&prog, is64, BPF_REG_0, src_reg);
1089− else
1090− emit_mov_imm32(&prog, is64, BPF_REG_0, imm32);
1091−
1092− if (is64)
1093− EMIT1(add_1mod(0x48, AUX_REG));
1094− else if (is_ereg(AUX_REG))
1095− EMIT1(add_1mod(0x40, AUX_REG));
1096− /* mul(q) r11 */
1097− EMIT2(0xF7, add_1reg(0xE0, AUX_REG));
1098−
1099− if (dst_reg != BPF_REG_3)
1100− EMIT1(0x5A); /* pop rdx */
1101− if (dst_reg != BPF_REG_0) {
1102− /* mov dst_reg, rax */
1103− EMIT_mov(dst_reg, BPF_REG_0);
1104− EMIT1(0x58); /* pop rax */
1105− }
1097+ /* imul dst_reg, src_reg */
1098+ EMIT3(0x0F, 0xAF, add_2reg(0xC0, src_reg, dst_reg));
11061099 break;
1107− }
1100+
11081101 /* Shifts */
11091102 case BPF_ALU | BPF_LSH | BPF_K:
11101103 case BPF_ALU | BPF_RSH | BPF_K:
include/linux/perf_event.h+23−0
@@ -57,6 +57,7 @@ struct perf_guest_info_callbacks { · 56 unmodified lines
5757 #include <linux/cgroup.h>
5858 #include <linux/refcount.h>
5959 #include <linux/security.h>
60+#include <linux/static_call.h>
6061 #include <asm/local.h>
6162
6263 struct perf_callchain_entry {
@@ -1612,4 +1613,26 @@ extern void __weak arch_perf_update_userpage(struct perf_event *event, · 1549 unmodified lines
16121613 extern __weak u64 arch_perf_get_page_size(struct mm_struct *mm, unsigned long addr);
16131614 #endif
16141615
1616+/*
1617+ * Snapshot branch stack on software events.
1618+ *
1619+ * Branch stack can be very useful in understanding software events. For
1620+ * example, when a long function, e.g. sys_perf_event_open, returns an
1621+ * errno, it is not obvious why the function failed. Branch stack could
1622+ * provide very helpful information in this type of scenarios.
1623+ *
1624+ * On software event, it is necessary to stop the hardware branch recorder
1625+ * fast. Otherwise, the hardware register/buffer will be flushed with
1626+ * entries of the triggering event. Therefore, static call is used to
1627+ * stop the hardware recorder.
1628+ */
1629+
1630+/*
1631+ * cnt is the number of entries allocated for entries.
1632+ * Return number of entries copied to .
1633+ */
1634+typedef int (perf_snapshot_branch_stack_t)(struct perf_branch_entry *entries,
1635+ unsigned int cnt);
1636+DECLARE_STATIC_CALL(perf_snapshot_branch_stack, perf_snapshot_branch_stack_t);
1637+
16151638 #endif /* _LINUX_PERF_EVENT_H */
include/uapi/linux/bpf.h+25−1
@@ -1629,7 +1629,7 @@ union bpf_attr { · 1628 unmodified lines
16291629 * u32 bpf_get_smp_processor_id(void)
16301630 * Description
16311631 * Get the SMP (symmetric multiprocessing) processor id. Note that
1632− * all programs run with preemption disabled, which means that the
1632+ * all programs run with migration disabled, which means that the
16331633 * SMP processor id is stable during all the execution of the
16341634 * program.
16351635 * Return
@@ -4877,6 +4877,27 @@ union bpf_attr { · 3241 unmodified lines
48774877 * Get the struct pt_regs associated with **task**.
48784878 * Return
48794879 * A pointer to struct pt_regs.
4880+ *
4881+ * long bpf_get_branch_snapshot(void *entries, u32 size, u64 flags)
4882+ * Description
4883+ * Get branch trace from hardware engines like Intel LBR. The
4884+ * hardware engine is stopped shortly after the helper is
4885+ * called. Therefore, the user need to filter branch entries
4886+ * based on the actual use case. To capture branch trace
4887+ * before the trigger point of the BPF program, the helper
4888+ * should be called at the beginning of the BPF program.
4889+ *
4890+ * The data is stored as struct perf_branch_entry into output
4891+ * buffer *entries*. *size* is the size of *entries* in bytes.
4892+ * *flags* is reserved for now and must be zero.
4893+ *
4894+ * Return
4895+ * On success, number of bytes written to *buf*. On error, a
4896+ * negative value.
4897+ *
4898+ * **-EINVAL** if *flags* is not zero.
4899+ *
4900+ * **-ENOENT** if architecture does not support branch records.
48804901 */
48814902 #define __BPF_FUNC_MAPPER(FN) \
48824903 FN(unspec), \
@@ -5055,6 +5076,7 @@ union bpf_attr { · 172 unmodified lines
50555076 FN(get_func_ip), \
50565077 FN(get_attach_cookie), \
50575078 FN(task_pt_regs), \
5079+ FN(get_branch_snapshot), \
50585080 /* */
50595081
50605082 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
@@ -5284,6 +5306,8 @@ struct __sk_buff { · 223 unmodified lines
52845306 __u32 gso_segs;
52855307 __bpf_md_ptr(struct bpf_sock *, sk);
52865308 __u32 gso_size;
5309+ __u32 :32; /* Padding, future use. */
5310+ __u64 hwtstamp;
52875311 };
52885312
52895313 struct bpf_tunnel_key {
include/uapi/linux/btf.h+35−20
@@ -43,7 +43,7 @@ struct btf_type { · 42 unmodified lines
4343 * "size" tells the size of the type it is describing.
4444 *
4545 * "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT,
46− * FUNC, FUNC_PROTO and VAR.
46+ * FUNC, FUNC_PROTO, VAR and TAG.
4747 * "type" is a type_id referring to another type.
4848 */
4949 union {
@@ -56,25 +56,29 @@ struct btf_type { · 6 unmodified lines
5656 #define BTF_INFO_VLEN(info) ((info) & 0xffff)
5757 #define BTF_INFO_KFLAG(info) ((info) >> 31)
5858
59−#define BTF_KIND_UNKN 0 /* Unknown */
60−#define BTF_KIND_INT 1 /* Integer */
61−#define BTF_KIND_PTR 2 /* Pointer */
62−#define BTF_KIND_ARRAY 3 /* Array */
63−#define BTF_KIND_STRUCT 4 /* Struct */
64−#define BTF_KIND_UNION 5 /* Union */
65−#define BTF_KIND_ENUM 6 /* Enumeration */
66−#define BTF_KIND_FWD 7 /* Forward */
67−#define BTF_KIND_TYPEDEF 8 /* Typedef */
68−#define BTF_KIND_VOLATILE 9 /* Volatile */
69−#define BTF_KIND_CONST 10 /* Const */
70−#define BTF_KIND_RESTRICT 11 /* Restrict */
71−#define BTF_KIND_FUNC 12 /* Function */
72−#define BTF_KIND_FUNC_PROTO 13 /* Function Proto */
73−#define BTF_KIND_VAR 14 /* Variable */
74−#define BTF_KIND_DATASEC 15 /* Section */
75−#define BTF_KIND_FLOAT 16 /* Floating point */
76−#define BTF_KIND_MAX BTF_KIND_FLOAT
77−#define NR_BTF_KINDS (BTF_KIND_MAX + 1)
59+enum {
60+ BTF_KIND_UNKN = 0, /* Unknown */
61+ BTF_KIND_INT = 1, /* Integer */
62+ BTF_KIND_PTR = 2, /* Pointer */
63+ BTF_KIND_ARRAY = 3, /* Array */
64+ BTF_KIND_STRUCT = 4, /* Struct */
65+ BTF_KIND_UNION = 5, /* Union */
66+ BTF_KIND_ENUM = 6, /* Enumeration */
67+ BTF_KIND_FWD = 7, /* Forward */
68+ BTF_KIND_TYPEDEF = 8, /* Typedef */
69+ BTF_KIND_VOLATILE = 9, /* Volatile */
70+ BTF_KIND_CONST = 10, /* Const */
71+ BTF_KIND_RESTRICT = 11, /* Restrict */
72+ BTF_KIND_FUNC = 12, /* Function */
73+ BTF_KIND_FUNC_PROTO = 13, /* Function Proto */
74+ BTF_KIND_VAR = 14, /* Variable */
75+ BTF_KIND_DATASEC = 15, /* Section */
76+ BTF_KIND_FLOAT = 16, /* Floating point */
77+ BTF_KIND_TAG = 17, /* Tag */
78+
79+ NR_BTF_KINDS,
80+ BTF_KIND_MAX = NR_BTF_KINDS - 1,
81+};
7882
7983 /* For some specific BTF_KIND, "struct btf_type" is immediately
8084 * followed by extra data.
@@ -170,4 +174,15 @@ struct btf_var_secinfo { · 89 unmodified lines
170174 __u32 size;
171175 };
172176
177+/* BTF_KIND_TAG is followed by a single "struct btf_tag" to describe
178+ * additional information related to the tag applied location.
179+ * If component_idx == -1, the tag is applied to a struct, union,
180+ * variable or function. Otherwise, it is applied to a struct/union
181+ * member or a func argument, and component_idx indicates which member
182+ * or argument (0 ... vlen-1).
183+ */
184+struct btf_tag {
185+ __s32 component_idx;
186+};
187+
173188 #endif /* _UAPI__LINUX_BTF_H__ */
kernel/bpf/btf.c+128−0
@@ -281,6 +281,7 @@ static const char * const btf_kind_str[NR_BTF_KINDS] = { · 280 unmodified lines
281281 [BTF_KIND_VAR] = "VAR",
282282 [BTF_KIND_DATASEC] = "DATASEC",
283283 [BTF_KIND_FLOAT] = "FLOAT",
284+ [BTF_KIND_TAG] = "TAG",
284285 };
285286
286287 const char *btf_type_str(const struct btf_type *t)
@@ -459,6 +460,17 @@ static bool btf_type_is_datasec(const struct btf_type *t) · 172 unmodified lines
459460 return BTF_INFO_KIND(t->info) == BTF_KIND_DATASEC;
460461 }
461462
463+static bool btf_type_is_tag(const struct btf_type *t)
464+{
465+ return BTF_INFO_KIND(t->info) == BTF_KIND_TAG;
466+}
467+
468+static bool btf_type_is_tag_target(const struct btf_type *t)
469+{
470+ return btf_type_is_func(t) || btf_type_is_struct(t) ||
471+ btf_type_is_var(t);
472+}
473+
462474 u32 btf_nr_types(const struct btf *btf)
463475 {
464476 u32 total = 0;
@@ -537,6 +549,7 @@ const struct btf_type *btf_type_resolve_func_ptr(const struct btf *btf, · 72 unmodified lines
537549 static bool btf_type_is_resolve_source_only(const struct btf_type *t)
538550 {
539551 return btf_type_is_var(t) ||
552+ btf_type_is_tag(t) ||
540553 btf_type_is_datasec(t);
541554 }
542555
@@ -563,6 +576,7 @@ static bool btf_type_needs_resolve(const struct btf_type *t) · 20 unmodified lines
563576 btf_type_is_struct(t) ||
564577 btf_type_is_array(t) ||
565578 btf_type_is_var(t) ||
579+ btf_type_is_tag(t) ||
566580 btf_type_is_datasec(t);
567581 }
568582
@@ -616,6 +630,11 @@ static const struct btf_var *btf_type_var(const struct btf_type *t) · 47 unmodified lines
616630 return (const struct btf_var *)(t + 1);
617631 }
618632
633+static const struct btf_tag *btf_type_tag(const struct btf_type *t)
634+{
635+ return (const struct btf_tag *)(t + 1);
636+}
637+
619638 static const struct btf_kind_operations *btf_type_ops(const struct btf_type *t)
620639 {
621640 return kind_ops[BTF_INFO_KIND(t->info)];
@@ -3801,6 +3820,110 @@ static const struct btf_kind_operations float_ops = { · 3179 unmodified lines
38013820 .show = btf_df_show,
38023821 };
38033822
3823+static s32 btf_tag_check_meta(struct btf_verifier_env *env,
3824+ const struct btf_type *t,
3825+ u32 meta_left)
3826+{
3827+ const struct btf_tag *tag;
3828+ u32 meta_needed = sizeof(*tag);
3829+ s32 component_idx;
3830+ const char *value;
3831+
3832+ if (meta_left < meta_needed) {
3833+ btf_verifier_log_basic(env, t,
3834+ "meta_left:%u meta_needed:%u",
3835+ meta_left, meta_needed);
3836+ return -EINVAL;
3837+ }
3838+
3839+ value = btf_name_by_offset(env->btf, t->name_off);
3840+ if (!value || !value[0]) {
3841+ btf_verifier_log_type(env, t, "Invalid value");
3842+ return -EINVAL;
3843+ }
3844+
3845+ if (btf_type_vlen(t)) {
3846+ btf_verifier_log_type(env, t, "vlen != 0");
3847+ return -EINVAL;
3848+ }
3849+
3850+ if (btf_type_kflag(t)) {
3851+ btf_verifier_log_type(env, t, "Invalid btf_info kind_flag");
3852+ return -EINVAL;
3853+ }
3854+
3855+ component_idx = btf_type_tag(t)->component_idx;
3856+ if (component_idx < -1) {
3857+ btf_verifier_log_type(env, t, "Invalid component_idx");
3858+ return -EINVAL;
3859+ }
3860+
3861+ btf_verifier_log_type(env, t, NULL);
3862+
3863+ return meta_needed;
3864+}
3865+
3866+static int btf_tag_resolve(struct btf_verifier_env *env,
3867+ const struct resolve_vertex *v)
3868+{
3869+ const struct btf_type *next_type;
3870+ const struct btf_type *t = v->t;
3871+ u32 next_type_id = t->type;
3872+ struct btf *btf = env->btf;
3873+ s32 component_idx;
3874+ u32 vlen;
3875+
3876+ next_type = btf_type_by_id(btf, next_type_id);
3877+ if (!next_type || !btf_type_is_tag_target(next_type)) {
3878+ btf_verifier_log_type(env, v->t, "Invalid type_id");
3879+ return -EINVAL;
3880+ }
3881+
3882+ if (!env_type_is_resolve_sink(env, next_type) &&
3883+ !env_type_is_resolved(env, next_type_id))
3884+ return env_stack_push(env, next_type, next_type_id);
3885+
3886+ component_idx = btf_type_tag(t)->component_idx;
3887+ if (component_idx != -1) {
3888+ if (btf_type_is_var(next_type)) {
3889+ btf_verifier_log_type(env, v->t, "Invalid component_idx");
3890+ return -EINVAL;
3891+ }
3892+
3893+ if (btf_type_is_struct(next_type)) {
3894+ vlen = btf_type_vlen(next_type);
3895+ } else {
3896+ /* next_type should be a function */
3897+ next_type = btf_type_by_id(btf, next_type->type);
3898+ vlen = btf_type_vlen(next_type);
3899+ }
3900+
3901+ if ((u32)component_idx >= vlen) {
3902+ btf_verifier_log_type(env, v->t, "Invalid component_idx");
3903+ return -EINVAL;
3904+ }
3905+ }
3906+
3907+ env_stack_pop_resolved(env, next_type_id, 0);
3908+
3909+ return 0;
3910+}
3911+
3912+static void btf_tag_log(struct btf_verifier_env *env, const struct btf_type *t)
3913+{
3914+ btf_verifier_log(env, "type=%u component_idx=%d", t->type,
3915+ btf_type_tag(t)->component_idx);
3916+}
3917+
3918+static const struct btf_kind_operations tag_ops = {
3919+ .check_meta = btf_tag_check_meta,
3920+ .resolve = btf_tag_resolve,
3921+ .check_member = btf_df_check_member,
3922+ .check_kflag_member = btf_df_check_kflag_member,
3923+ .log_details = btf_tag_log,
3924+ .show = btf_df_show,
3925+};
3926+
38043927 static int btf_func_proto_check(struct btf_verifier_env *env,
38053928 const struct btf_type *t)
38063929 {
@@ -3935,6 +4058,7 @@ static const struct btf_kind_operations * const kind_ops[NR_BTF_KINDS] = { · 128 unmodified lines
39354058 [BTF_KIND_VAR] = &var_ops,
39364059 [BTF_KIND_DATASEC] = &datasec_ops,
39374060 [BTF_KIND_FLOAT] = &float_ops,
4061+ [BTF_KIND_TAG] = &tag_ops,
39384062 };
39394063
39404064 static s32 btf_check_meta(struct btf_verifier_env *env,
@@ -4019,6 +4143,10 @@ static bool btf_resolve_valid(struct btf_verifier_env *env, · 78 unmodified lines
40194143 return !btf_resolved_type_id(btf, type_id) &&
40204144 !btf_resolved_type_size(btf, type_id);
40214145
4146+ if (btf_type_is_tag(t))
4147+ return btf_resolved_type_id(btf, type_id) &&
4148+ !btf_resolved_type_size(btf, type_id);
4149+
40224150 if (btf_type_is_modifier(t) || btf_type_is_ptr(t) ||
40234151 btf_type_is_var(t)) {
40244152 t = btf_type_id_resolve(btf, &type_id);
kernel/bpf/trampoline.c+2−1
@@ -10,6 +10,7 @@ · 9 unmodified lines
1010 #include <linux/rcupdate_trace.h>
1111 #include <linux/rcupdate_wait.h>
1212 #include <linux/module.h>
13+#include <linux/static_call.h>
1314
1415 /* dummy _ops. The verifier will operate on target program's ops. */
1516 const struct bpf_verifier_ops bpf_extension_verifier_ops = {
@@ -526,7 +527,7 @@ out: · 510 unmodified lines
526527 }
527528
528529 #define NO_START_TIME 1
529−static u64 notrace bpf_prog_start_time(void)
530+static __always_inline u64 notrace bpf_prog_start_time(void)
530531 {
531532 u64 start = NO_START_TIME;
532533
kernel/events/core.c+2−0
@@ -13435,3 +13435,5 @@ struct cgroup_subsys perf_event_cgrp_subsys = { · 13434 unmodified lines
1343513435 .threaded = true,
1343613436 };
1343713437 #endif /* CONFIG_CGROUP_PERF */
13438+
13439+DEFINE_STATIC_CALL_RET0(perf_snapshot_branch_stack, perf_snapshot_branch_stack_t);
kernel/trace/bpf_trace.c+30−0
@@ -1017,6 +1017,34 @@ static const struct bpf_func_proto bpf_get_attach_cookie_proto_pe = { · 1016 unmodified lines
10171017 .arg1_type = ARG_PTR_TO_CTX,
10181018 };
10191019
1020+BPF_CALL_3(bpf_get_branch_snapshot, void *, buf, u32, size, u64, flags)
1021+{
1022+#ifndef CONFIG_X86
1023+ return -ENOENT;
1024+#else
1025+ static const u32 br_entry_size = sizeof(struct perf_branch_entry);
1026+ u32 entry_cnt = size / br_entry_size;
1027+
1028+ entry_cnt = static_call(perf_snapshot_branch_stack)(buf, entry_cnt);
1029+
1030+ if (unlikely(flags))
1031+ return -EINVAL;
1032+
1033+ if (!entry_cnt)
1034+ return -ENOENT;
1035+
1036+ return entry_cnt * br_entry_size;
1037+#endif
1038+}
1039+
1040+static const struct bpf_func_proto bpf_get_branch_snapshot_proto = {
1041+ .func = bpf_get_branch_snapshot,
1042+ .gpl_only = true,
1043+ .ret_type = RET_INTEGER,
1044+ .arg1_type = ARG_PTR_TO_UNINIT_MEM,
1045+ .arg2_type = ARG_CONST_SIZE_OR_ZERO,
1046+};
1047+
10201048 static const struct bpf_func_proto *
10211049 bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
10221050 {
@@ -1132,6 +1160,8 @@ bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) · 109 unmodified lines
11321160 return &bpf_snprintf_proto;
11331161 case BPF_FUNC_get_func_ip:
11341162 return &bpf_get_func_ip_proto_tracing;
1163+ case BPF_FUNC_get_branch_snapshot:
1164+ return &bpf_get_branch_snapshot_proto;
11351165 default:
11361166 return bpf_base_func_proto(func_id);
11371167 }
lib/test_bpf.c+1−0
@@ -8800,6 +8800,7 @@ static __init struct sk_buff *build_test_skb(void) · 8799 unmodified lines
88008800 skb_shinfo(skb[0])->gso_type |= SKB_GSO_DODGY;
88018801 skb_shinfo(skb[0])->gso_segs = 0;
88028802 skb_shinfo(skb[0])->frag_list = skb[1];
8803+ skb_shinfo(skb[0])->hwtstamps.hwtstamp = 1000;
88038804
88048805 /* adjust skb[0]'s len */
88058806 skb[0]->len += skb[1]->len;
net/bpf/test_run.c+11−5
@@ -483,11 +483,7 @@ static int convert___skb_to_skb(struct sk_buff *skb, struct __sk_buff *__skb) · 482 unmodified lines
483483 return -EINVAL;
484484
485485 /* priority is allowed */
486−
487− if (!range_is_zero(__skb, offsetofend(struct __sk_buff, priority),
488− offsetof(struct __sk_buff, ifindex)))
489− return -EINVAL;
490−
486+ /* ingress_ifindex is allowed */
491487 /* ifindex is allowed */
492488
493489 if (!range_is_zero(__skb, offsetofend(struct __sk_buff, ifindex),
@@ -511,11 +507,18 @@ static int convert___skb_to_skb(struct sk_buff *skb, struct __sk_buff *__skb) · 17 unmodified lines
511507 /* gso_size is allowed */
512508
513509 if (!range_is_zero(__skb, offsetofend(struct __sk_buff, gso_size),
510+ offsetof(struct __sk_buff, hwtstamp)))
511+ return -EINVAL;
512+
513+ /* hwtstamp is allowed */
514+
515+ if (!range_is_zero(__skb, offsetofend(struct __sk_buff, hwtstamp),
514516 sizeof(struct __sk_buff)))
515517 return -EINVAL;
516518
517519 skb->mark = __skb->mark;
518520 skb->priority = __skb->priority;
521+ skb->skb_iif = __skb->ingress_ifindex;
519522 skb->tstamp = __skb->tstamp;
520523 memcpy(&cb->data, __skb->cb, QDISC_CB_PRIV_LEN);
521524
@@ -532,6 +535,7 @@ static int convert___skb_to_skb(struct sk_buff *skb, struct __sk_buff *__skb) · 10 unmodified lines
532535 return -EINVAL;
533536 skb_shinfo(skb)->gso_segs = __skb->gso_segs;
534537 skb_shinfo(skb)->gso_size = __skb->gso_size;
538+ skb_shinfo(skb)->hwtstamps.hwtstamp = __skb->hwtstamp;
535539
536540 return 0;
537541 }
@@ -545,11 +549,13 @@ static void convert_skb_to___skb(struct sk_buff *skb, struct __sk_buff *__skb) · 7 unmodified lines
545549
546550 __skb->mark = skb->mark;
547551 __skb->priority = skb->priority;
552+ __skb->ingress_ifindex = skb->skb_iif;
548553 __skb->ifindex = skb->dev->ifindex;
549554 __skb->tstamp = skb->tstamp;
550555 memcpy(__skb->cb, &cb->data, QDISC_CB_PRIV_LEN);
551556 __skb->wire_len = cb->pkt_len;
552557 __skb->gso_segs = skb_shinfo(skb)->gso_segs;
558+ __skb->hwtstamp = skb_shinfo(skb)->hwtstamps.hwtstamp;
553559 }
554560
555561 int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr,
net/core/filter.c+21−0
@@ -7765,6 +7765,10 @@ static bool bpf_skb_is_valid_access(int off, int size, enum bpf_access_type type · 7764 unmodified lines
77657765 break;
77667766 case bpf_ctx_range_ptr(struct __sk_buff, flow_keys):
77677767 return false;
7768+ case bpf_ctx_range(struct __sk_buff, hwtstamp):
7769+ if (type == BPF_WRITE || size != sizeof(__u64))
7770+ return false;
7771+ break;
77687772 case bpf_ctx_range(struct __sk_buff, tstamp):
77697773 if (size != sizeof(__u64))
77707774 return false;
@@ -7774,6 +7778,9 @@ static bool bpf_skb_is_valid_access(int off, int size, enum bpf_access_type type · 3 unmodified lines
77747778 return false;
77757779 info->reg_type = PTR_TO_SOCK_COMMON_OR_NULL;
77767780 break;
7781+ case offsetofend(struct __sk_buff, gso_size) ... offsetof(struct __sk_buff, hwtstamp) - 1:
7782+ /* Explicitly prohibit access to padding in __sk_buff. */
7783+ return false;
77777784 default:
77787785 /* Only narrow read access allowed for now. */
77797786 if (type == BPF_WRITE) {
@@ -7802,6 +7809,7 @@ static bool sk_filter_is_valid_access(int off, int size, · 22 unmodified lines
78027809 case bpf_ctx_range_till(struct __sk_buff, family, local_port):
78037810 case bpf_ctx_range(struct __sk_buff, tstamp):
78047811 case bpf_ctx_range(struct __sk_buff, wire_len):
7812+ case bpf_ctx_range(struct __sk_buff, hwtstamp):
78057813 return false;
78067814 }
78077815
@@ -7872,6 +7880,7 @@ static bool lwt_is_valid_access(int off, int size, · 64 unmodified lines
78727880 case bpf_ctx_range(struct __sk_buff, data_meta):
78737881 case bpf_ctx_range(struct __sk_buff, tstamp):
78747882 case bpf_ctx_range(struct __sk_buff, wire_len):
7883+ case bpf_ctx_range(struct __sk_buff, hwtstamp):
78757884 return false;
78767885 }
78777886
@@ -8373,6 +8382,7 @@ static bool sk_skb_is_valid_access(int off, int size, · 495 unmodified lines
83738382 case bpf_ctx_range(struct __sk_buff, data_meta):
83748383 case bpf_ctx_range(struct __sk_buff, tstamp):
83758384 case bpf_ctx_range(struct __sk_buff, wire_len):
8385+ case bpf_ctx_range(struct __sk_buff, hwtstamp):
83768386 return false;
83778387 }
83788388
@@ -8884,6 +8894,17 @@ static u32 bpf_convert_ctx_access(enum bpf_access_type type, · 505 unmodified lines
88848894 si->dst_reg, si->src_reg,
88858895 offsetof(struct sk_buff, sk));
88868896 break;
8897+ case offsetof(struct __sk_buff, hwtstamp):
8898+ BUILD_BUG_ON(sizeof_field(struct skb_shared_hwtstamps, hwtstamp) != 8);
8899+ BUILD_BUG_ON(offsetof(struct skb_shared_hwtstamps, hwtstamp) != 0);
8900+
8901+ insn = bpf_convert_shinfo_access(si, insn);
8902+ *insn++ = BPF_LDX_MEM(BPF_DW,
8903+ si->dst_reg, si->dst_reg,
8904+ bpf_target_off(struct skb_shared_info,
8905+ hwtstamps, 8,
8906+ target_size));
8907+ break;
88878908 }
88888909
88898910 return insn - insn_buf;
tools/bpf/bpftool/Makefile+3−0
@@ -137,7 +137,10 @@ endif · 136 unmodified lines
137137 BPFTOOL_BOOTSTRAP := $(BOOTSTRAP_OUTPUT)bpftool
138138
139139 BOOTSTRAP_OBJS = $(addprefix $(BOOTSTRAP_OUTPUT),main.o common.o json_writer.o gen.o btf.o xlated_dumper.o btf_dumper.o disasm.o)
140+$(BOOTSTRAP_OBJS): $(LIBBPF_BOOTSTRAP)
141+
140142 OBJS = $(patsubst %.c,$(OUTPUT)%.o,$(SRCS)) $(OUTPUT)disasm.o
143+$(OBJS): $(LIBBPF)
141144
142145 VMLINUX_BTF_PATHS ?= $(if $(O),$(O)/vmlinux) \
143146 $(if $(KBUILD_OUTPUT),$(KBUILD_OUTPUT)/vmlinux) \
tools/bpf/bpftool/btf.c+12−0
@@ -37,6 +37,7 @@ static const char * const btf_kind_str[NR_BTF_KINDS] = { · 36 unmodified lines
3737 [BTF_KIND_VAR] = "VAR",
3838 [BTF_KIND_DATASEC] = "DATASEC",
3939 [BTF_KIND_FLOAT] = "FLOAT",
40+ [BTF_KIND_TAG] = "TAG",
4041 };
4142
4243 struct btf_attach_table {
@@ -347,6 +348,17 @@ static int dump_btf_type(const struct btf *btf, __u32 id, · 304 unmodified lines
347348 printf(" size=%u", t->size);
348349 break;
349350 }
351+ case BTF_KIND_TAG: {
352+ const struct btf_tag *tag = (const void *)(t + 1);
353+
354+ if (json_output) {
355+ jsonw_uint_field(w, "type_id", t->type);
356+ jsonw_int_field(w, "component_idx", tag->component_idx);
357+ } else {
358+ printf(" type_id=%u component_idx=%d", t->type, tag->component_idx);
359+ }
360+ break;
361+ }
350362 default:
351363 break;
352364 }
tools/bpf/bpftool/gen.c+19−12
@@ -238,8 +238,8 @@ static void codegen(const char *template, ...) · 237 unmodified lines
238238 } else if (c == '\n') {
239239 break;
240240 } else {
241− p_err("unrecognized character at pos %td in template '%s'",
242− src - template - 1, template);
241+ p_err("unrecognized character at pos %td in template '%s': '%c'",
242+ src - template - 1, template, c);
243243 free(s);
244244 exit(-1);
245245 }
@@ -406,7 +406,7 @@ static void codegen_destroy(struct bpf_object *obj, const char *obj_name) · 160 unmodified lines
406406 }
407407
408408 bpf_object__for_each_map(map, obj) {
409− const char * ident;
409+ const char *ident;
410410
411411 ident = get_map_ident(map);
412412 if (!ident)
@@ -862,6 +862,8 @@ static int do_skeleton(int argc, char **argv) · 449 unmodified lines
862862 codegen("\
863863 \n\
864864 \n\
865+ static inline const void *%1$s__elf_bytes(size_t *sz); \n\
866+ \n\
865867 static inline int \n\
866868 %1$s__create_skeleton(struct %1$s *obj) \n\
867869 { \n\
@@ -943,10 +945,20 @@ static int do_skeleton(int argc, char **argv) · 75 unmodified lines
943945 codegen("\
944946 \n\
945947 \n\
946− s->data_sz = %d; \n\
947− s->data = (void *)\"\\ \n\
948− ",
949− file_sz);
948+ s->data = (void *)%2$s__elf_bytes(&s->data_sz); \n\
949+ \n\
950+ return 0; \n\
951+ err: \n\
952+ bpf_object__destroy_skeleton(s); \n\
953+ return -ENOMEM; \n\
954+ } \n\
955+ \n\
956+ static inline const void *%2$s__elf_bytes(size_t *sz) \n\
957+ { \n\
958+ *sz = %1$d; \n\
959+ return (const void *)\"\\ \n\
960+ "
961+ , file_sz, obj_name);
950962
951963 /* embed contents of BPF object file */
952964 print_hex(obj_data, file_sz);
@@ -954,11 +966,6 @@ static int do_skeleton(int argc, char **argv) · 1 unmodified line
954966 codegen("\
955967 \n\
956968 \"; \n\
957− \n\
958− return 0; \n\
959− err: \n\
960− bpf_object__destroy_skeleton(s); \n\
961− return -ENOMEM; \n\
962969 } \n\
963970 \n\
964971 #endif /* %s */ \n\
tools/bpf/resolve_btfids/Makefile+3−2
@@ -26,6 +26,7 @@ LIBBPF_SRC := $(srctree)/tools/lib/bpf/ · 25 unmodified lines
2626 SUBCMD_SRC := $(srctree)/tools/lib/subcmd/
2727
2828 BPFOBJ := $(OUTPUT)/libbpf/libbpf.a
29+LIBBPF_OUT := $(abspath $(dir $(BPFOBJ)))/
2930 SUBCMDOBJ := $(OUTPUT)/libsubcmd/libsubcmd.a
3031
3132 BINARY := $(OUTPUT)/resolve_btfids
@@ -41,7 +42,7 @@ $(SUBCMDOBJ): fixdep FORCE | $(OUTPUT)/libsubcmd · 9 unmodified lines
4142 $(Q)$(MAKE) -C $(SUBCMD_SRC) OUTPUT=$(abspath $(dir $@))/ $(abspath $@)
4243
4344 $(BPFOBJ): $(wildcard $(LIBBPF_SRC)/*.[ch] $(LIBBPF_SRC)/Makefile) | $(OUTPUT)/libbpf
44− $(Q)$(MAKE) $(submake_extras) -C $(LIBBPF_SRC) OUTPUT=$(abspath $(dir $@))/ $(abspath $@)
45+ $(Q)$(MAKE) $(submake_extras) -C $(LIBBPF_SRC) OUTPUT=$(LIBBPF_OUT) $(abspath $@)
4546
4647 CFLAGS := -g \
4748 -I$(srctree)/tools/include \
@@ -54,7 +55,7 @@ LIBS = -lelf -lz · 6 unmodified lines
5455 export srctree OUTPUT CFLAGS Q
5556 include $(srctree)/tools/build/Makefile.include
5657
57−$(BINARY_IN): fixdep FORCE | $(OUTPUT)
58+$(BINARY_IN): $(BPFOBJ) fixdep FORCE | $(OUTPUT)
5859 $(Q)$(MAKE) $(build)=resolve_btfids
5960
6061 $(BINARY): $(BPFOBJ) $(SUBCMDOBJ) $(BINARY_IN)
tools/include/uapi/linux/bpf.h+25−1
@@ -1629,7 +1629,7 @@ union bpf_attr { · 1628 unmodified lines
16291629 * u32 bpf_get_smp_processor_id(void)
16301630 * Description
16311631 * Get the SMP (symmetric multiprocessing) processor id. Note that
1632− * all programs run with preemption disabled, which means that the
1632+ * all programs run with migration disabled, which means that the
16331633 * SMP processor id is stable during all the execution of the
16341634 * program.
16351635 * Return
@@ -4877,6 +4877,27 @@ union bpf_attr { · 3241 unmodified lines
48774877 * Get the struct pt_regs associated with **task**.
48784878 * Return
48794879 * A pointer to struct pt_regs.
4880+ *
4881+ * long bpf_get_branch_snapshot(void *entries, u32 size, u64 flags)
4882+ * Description
4883+ * Get branch trace from hardware engines like Intel LBR. The
4884+ * hardware engine is stopped shortly after the helper is
4885+ * called. Therefore, the user need to filter branch entries
4886+ * based on the actual use case. To capture branch trace
4887+ * before the trigger point of the BPF program, the helper
4888+ * should be called at the beginning of the BPF program.
4889+ *
4890+ * The data is stored as struct perf_branch_entry into output
4891+ * buffer *entries*. *size* is the size of *entries* in bytes.
4892+ * *flags* is reserved for now and must be zero.
4893+ *
4894+ * Return
4895+ * On success, number of bytes written to *buf*. On error, a
4896+ * negative value.
4897+ *
4898+ * **-EINVAL** if *flags* is not zero.
4899+ *
4900+ * **-ENOENT** if architecture does not support branch records.
48804901 */
48814902 #define __BPF_FUNC_MAPPER(FN) \
48824903 FN(unspec), \
@@ -5055,6 +5076,7 @@ union bpf_attr { · 172 unmodified lines
50555076 FN(get_func_ip), \
50565077 FN(get_attach_cookie), \
50575078 FN(task_pt_regs), \
5079+ FN(get_branch_snapshot), \
50585080 /* */
50595081
50605082 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
@@ -5284,6 +5306,8 @@ struct __sk_buff { · 223 unmodified lines
52845306 __u32 gso_segs;
52855307 __bpf_md_ptr(struct bpf_sock *, sk);
52865308 __u32 gso_size;
5309+ __u32 :32; /* Padding, future use. */
5310+ __u64 hwtstamp;
52875311 };
52885312
52895313 struct bpf_tunnel_key {
tools/include/uapi/linux/btf.h+35−20
@@ -43,7 +43,7 @@ struct btf_type { · 42 unmodified lines
4343 * "size" tells the size of the type it is describing.
4444 *
4545 * "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT,
46− * FUNC, FUNC_PROTO and VAR.
46+ * FUNC, FUNC_PROTO, VAR and TAG.
4747 * "type" is a type_id referring to another type.
4848 */
4949 union {
@@ -56,25 +56,29 @@ struct btf_type { · 6 unmodified lines
5656 #define BTF_INFO_VLEN(info) ((info) & 0xffff)
5757 #define BTF_INFO_KFLAG(info) ((info) >> 31)
5858
59−#define BTF_KIND_UNKN 0 /* Unknown */
60−#define BTF_KIND_INT 1 /* Integer */
61−#define BTF_KIND_PTR 2 /* Pointer */
62−#define BTF_KIND_ARRAY 3 /* Array */
63−#define BTF_KIND_STRUCT 4 /* Struct */
64−#define BTF_KIND_UNION 5 /* Union */
65−#define BTF_KIND_ENUM 6 /* Enumeration */
66−#define BTF_KIND_FWD 7 /* Forward */
67−#define BTF_KIND_TYPEDEF 8 /* Typedef */
68−#define BTF_KIND_VOLATILE 9 /* Volatile */
69−#define BTF_KIND_CONST 10 /* Const */
70−#define BTF_KIND_RESTRICT 11 /* Restrict */
71−#define BTF_KIND_FUNC 12 /* Function */
72−#define BTF_KIND_FUNC_PROTO 13 /* Function Proto */
73−#define BTF_KIND_VAR 14 /* Variable */
74−#define BTF_KIND_DATASEC 15 /* Section */
75−#define BTF_KIND_FLOAT 16 /* Floating point */
76−#define BTF_KIND_MAX BTF_KIND_FLOAT
77−#define NR_BTF_KINDS (BTF_KIND_MAX + 1)
59+enum {
60+ BTF_KIND_UNKN = 0, /* Unknown */
61+ BTF_KIND_INT = 1, /* Integer */
62+ BTF_KIND_PTR = 2, /* Pointer */
63+ BTF_KIND_ARRAY = 3, /* Array */
64+ BTF_KIND_STRUCT = 4, /* Struct */
65+ BTF_KIND_UNION = 5, /* Union */
66+ BTF_KIND_ENUM = 6, /* Enumeration */
67+ BTF_KIND_FWD = 7, /* Forward */
68+ BTF_KIND_TYPEDEF = 8, /* Typedef */
69+ BTF_KIND_VOLATILE = 9, /* Volatile */
70+ BTF_KIND_CONST = 10, /* Const */
71+ BTF_KIND_RESTRICT = 11, /* Restrict */
72+ BTF_KIND_FUNC = 12, /* Function */
73+ BTF_KIND_FUNC_PROTO = 13, /* Function Proto */
74+ BTF_KIND_VAR = 14, /* Variable */
75+ BTF_KIND_DATASEC = 15, /* Section */
76+ BTF_KIND_FLOAT = 16, /* Floating point */
77+ BTF_KIND_TAG = 17, /* Tag */
78+
79+ NR_BTF_KINDS,
80+ BTF_KIND_MAX = NR_BTF_KINDS - 1,
81+};
7882
7983 /* For some specific BTF_KIND, "struct btf_type" is immediately
8084 * followed by extra data.
@@ -170,4 +174,15 @@ struct btf_var_secinfo { · 89 unmodified lines
170174 __u32 size;
171175 };
172176
177+/* BTF_KIND_TAG is followed by a single "struct btf_tag" to describe
178+ * additional information related to the tag applied location.
179+ * If component_idx == -1, the tag is applied to a struct, union,
180+ * variable or function. Otherwise, it is applied to a struct/union
181+ * member or a func argument, and component_idx indicates which member
182+ * or argument (0 ... vlen-1).
183+ */
184+struct btf_tag {
185+ __s32 component_idx;
186+};
187+
173188 #endif /* _UAPI__LINUX_BTF_H__ */
tools/lib/bpf/.gitignore+0−1
@@ -1,5 +1,4 @@
11 # SPDX-License-Identifier: GPL-2.0-only
2−libbpf_version.h
32 libbpf.pc
43 libbpf.so.*
54 TAGS
tools/lib/bpf/Makefile+29−10
@@ -8,7 +8,8 @@ VERSION_SCRIPT := libbpf.map · 7 unmodified lines
88 LIBBPF_VERSION := $(shell \
99 grep -oE '^LIBBPF_([0-9.]+)' $(VERSION_SCRIPT) | \
1010 sort -rV | head -n1 | cut -d'_' -f2)
11−LIBBPF_MAJOR_VERSION := $(firstword $(subst ., ,$(LIBBPF_VERSION)))
11+LIBBPF_MAJOR_VERSION := $(word 1,$(subst ., ,$(LIBBPF_VERSION)))
12+LIBBPF_MINOR_VERSION := $(word 2,$(subst ., ,$(LIBBPF_VERSION)))
1213
1314 MAKEFLAGS += --no-print-directory
1415
@@ -59,7 +60,8 @@ ifndef VERBOSE · 44 unmodified lines
5960 VERBOSE = 0
6061 endif
6162
62−INCLUDES = -I. -I$(srctree)/tools/include -I$(srctree)/tools/include/uapi
63+INCLUDES = -I$(if $(OUTPUT),$(OUTPUT),.) \
64+ -I$(srctree)/tools/include -I$(srctree)/tools/include/uapi
6365
6466 export prefix libdir src obj
6567
@@ -112,6 +114,7 @@ STATIC_OBJDIR := $(OUTPUT)staticobjs/ · 46 unmodified lines
112114 BPF_IN_SHARED := $(SHARED_OBJDIR)libbpf-in.o
113115 BPF_IN_STATIC := $(STATIC_OBJDIR)libbpf-in.o
114116 BPF_HELPER_DEFS := $(OUTPUT)bpf_helper_defs.h
117+BPF_GENERATED := $(BPF_HELPER_DEFS)
115118
116119 LIB_TARGET := $(addprefix $(OUTPUT),$(LIB_TARGET))
117120 LIB_FILE := $(addprefix $(OUTPUT),$(LIB_FILE))
@@ -136,7 +139,7 @@ all: fixdep · 18 unmodified lines
136139
137140 all_cmd: $(CMD_TARGETS) check
138141
139−$(BPF_IN_SHARED): force $(BPF_HELPER_DEFS)
142+$(BPF_IN_SHARED): force $(BPF_GENERATED)
140143 @(test -f ../../include/uapi/linux/bpf.h -a -f ../../../include/uapi/linux/bpf.h && ( \
141144 (diff -B ../../include/uapi/linux/bpf.h ../../../include/uapi/linux/bpf.h >/dev/null) || \
142145 echo "Warning: Kernel ABI header at 'tools/include/uapi/linux/bpf.h' differs from latest version at 'include/uapi/linux/bpf.h'" >&2 )) || true
@@ -154,7 +157,7 @@ $(BPF_IN_SHARED): force $(BPF_HELPER_DEFS) · 11 unmodified lines
154157 echo "Warning: Kernel ABI header at 'tools/include/uapi/linux/if_xdp.h' differs from latest version at 'include/uapi/linux/if_xdp.h'" >&2 )) || true
155158 $(Q)$(MAKE) $(build)=libbpf OUTPUT=$(SHARED_OBJDIR) CFLAGS="$(CFLAGS) $(SHLIB_FLAGS)"
156159
157−$(BPF_IN_STATIC): force $(BPF_HELPER_DEFS)
160+$(BPF_IN_STATIC): force $(BPF_GENERATED)
158161 $(Q)$(MAKE) $(build)=libbpf OUTPUT=$(STATIC_OBJDIR)
159162
160163 $(BPF_HELPER_DEFS): $(srctree)/tools/include/uapi/linux/bpf.h
@@ -179,7 +182,7 @@ $(OUTPUT)libbpf.pc: · 18 unmodified lines
179182 -e "s|@VERSION@|$(LIBBPF_VERSION)|" \
180183 < libbpf.pc.template > $@
181184
182−check: check_abi
185+check: check_abi check_version
183186
184187 check_abi: $(OUTPUT)libbpf.so $(VERSION_SCRIPT)
185188 @if [ "$(GLOBAL_SYM_COUNT)" != "$(VERSIONED_SYM_COUNT)" ]; then \
@@ -205,6 +208,21 @@ check_abi: $(OUTPUT)libbpf.so $(VERSION_SCRIPT) · 19 unmodified lines
205208 exit 1; \
206209 fi
207210
211+HDR_MAJ_VERSION := $(shell grep -oE '^\#define LIBBPF_MAJOR_VERSION ([0-9]+)$$' libbpf_version.h | cut -d' ' -f3)
212+HDR_MIN_VERSION := $(shell grep -oE '^\#define LIBBPF_MINOR_VERSION ([0-9]+)$$' libbpf_version.h | cut -d' ' -f3)
213+
214+check_version: $(VERSION_SCRIPT) libbpf_version.h
215+ @if [ "$(HDR_MAJ_VERSION)" != "$(LIBBPF_MAJOR_VERSION)" ]; then \
216+ echo "Error: libbpf major version mismatch detected: " \
217+ "'$(HDR_MAJ_VERSION)' != '$(LIBBPF_MAJOR_VERSION)'" >&2; \
218+ exit 1; \
219+ fi
220+ @if [ "$(HDR_MIN_VERSION)" != "$(LIBBPF_MINOR_VERSION)" ]; then \
221+ echo "Error: libbpf minor version mismatch detected: " \
222+ "'$(HDR_MIN_VERSION)' != '$(LIBBPF_MINOR_VERSION)'" >&2; \
223+ exit 1; \
224+ fi
225+
208226 define do_install_mkdir
209227 if [ ! -d '$(DESTDIR_SQ)$1' ]; then \
210228 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$1'; \
@@ -224,10 +242,11 @@ install_lib: all_cmd · 13 unmodified lines
224242 cp -fpR $(LIB_FILE) $(DESTDIR)$(libdir_SQ)
225243
226244 INSTALL_HEADERS = bpf.h libbpf.h btf.h libbpf_common.h libbpf_legacy.h xsk.h \
227− bpf_helpers.h $(BPF_HELPER_DEFS) bpf_tracing.h \
228− bpf_endian.h bpf_core_read.h skel_internal.h
245+ bpf_helpers.h $(BPF_GENERATED) bpf_tracing.h \
246+ bpf_endian.h bpf_core_read.h skel_internal.h \
247+ libbpf_version.h
229248
230−install_headers: $(BPF_HELPER_DEFS)
249+install_headers: $(BPF_GENERATED)
231250 $(call QUIET_INSTALL, headers) \
232251 $(foreach hdr,$(INSTALL_HEADERS), \
233252 $(call do_install,$(hdr),$(prefix)/include/bpf,644);)
@@ -240,12 +259,12 @@ install: install_lib install_pkgconfig install_headers · 6 unmodified lines
240259
241260 clean:
242261 $(call QUIET_CLEAN, libbpf) $(RM) -rf $(CMD_TARGETS) \
243− *~ .*.d .*.cmd LIBBPF-CFLAGS $(BPF_HELPER_DEFS) \
262+ *~ .*.d .*.cmd LIBBPF-CFLAGS $(BPF_GENERATED) \
244263 $(SHARED_OBJDIR) $(STATIC_OBJDIR) \
245264 $(addprefix $(OUTPUT), \
246265 *.o *.a *.so *.so.$(LIBBPF_MAJOR_VERSION) *.pc)
247266
248−PHONY += force cscope tags
267+PHONY += force cscope tags check check_abi check_version
249268 force:
250269
251270 cscope:
tools/lib/bpf/btf.c+76−8
@@ -304,6 +304,8 @@ static int btf_type_size(const struct btf_type *t) · 303 unmodified lines
304304 return base_size + sizeof(struct btf_var);
305305 case BTF_KIND_DATASEC:
306306 return base_size + vlen * sizeof(struct btf_var_secinfo);
307+ case BTF_KIND_TAG:
308+ return base_size + sizeof(struct btf_tag);
307309 default:
308310 pr_debug("Unsupported BTF_KIND:%u\n", btf_kind(t));
309311 return -EINVAL;
@@ -376,6 +378,9 @@ static int btf_bswap_type_rest(struct btf_type *t) · 66 unmodified lines
376378 v->size = bswap_32(v->size);
377379 }
378380 return 0;
381+ case BTF_KIND_TAG:
382+ btf_tag(t)->component_idx = bswap_32(btf_tag(t)->component_idx);
383+ return 0;
379384 default:
380385 pr_debug("Unsupported BTF_KIND:%u\n", btf_kind(t));
381386 return -EINVAL;
@@ -586,6 +591,7 @@ __s64 btf__resolve_size(const struct btf *btf, __u32 type_id) · 204 unmodified lines
586591 case BTF_KIND_CONST:
587592 case BTF_KIND_RESTRICT:
588593 case BTF_KIND_VAR:
594+ case BTF_KIND_TAG:
589595 type_id = t->type;
590596 break;
591597 case BTF_KIND_ARRAY:
@@ -2440,6 +2446,48 @@ int btf__add_datasec_var_info(struct btf *btf, int var_type_id, __u32 offset, __ · 1848 unmodified lines
24402446 return 0;
24412447 }
24422448
2449+/*
2450+ * Append new BTF_KIND_TAG type with:
2451+ * - *value* - non-empty/non-NULL string;
2452+ * - *ref_type_id* - referenced type ID, it might not exist yet;
2453+ * - *component_idx* - -1 for tagging reference type, otherwise struct/union
2454+ * member or function argument index;
2455+ * Returns:
2456+ * - >0, type ID of newly added BTF type;
2457+ * - <0, on error.
2458+ */
2459+int btf__add_tag(struct btf *btf, const char *value, int ref_type_id,
2460+ int component_idx)
2461+{
2462+ struct btf_type *t;
2463+ int sz, value_off;
2464+
2465+ if (!value || !value[0] || component_idx < -1)
2466+ return libbpf_err(-EINVAL);
2467+
2468+ if (validate_type_id(ref_type_id))
2469+ return libbpf_err(-EINVAL);
2470+
2471+ if (btf_ensure_modifiable(btf))
2472+ return libbpf_err(-ENOMEM);
2473+
2474+ sz = sizeof(struct btf_type) + sizeof(struct btf_tag);
2475+ t = btf_add_type_mem(btf, sz);
2476+ if (!t)
2477+ return libbpf_err(-ENOMEM);
2478+
2479+ value_off = btf__add_str(btf, value);
2480+ if (value_off < 0)
2481+ return value_off;
2482+
2483+ t->name_off = value_off;
2484+ t->info = btf_type_info(BTF_KIND_TAG, 0, false);
2485+ t->type = ref_type_id;
2486+ btf_tag(t)->component_idx = component_idx;
2487+
2488+ return btf_commit_type(btf, sz);
2489+}
2490+
24432491 struct btf_ext_sec_setup_param {
24442492 __u32 off;
24452493 __u32 len;
@@ -3256,8 +3304,8 @@ static bool btf_equal_common(struct btf_type *t1, struct btf_type *t2) · 810 unmodified lines
32563304 t1->size == t2->size;
32573305 }
32583306
3259−/* Calculate type signature hash of INT. */
3260−static long btf_hash_int(struct btf_type *t)
3307+/* Calculate type signature hash of INT or TAG. */
3308+static long btf_hash_int_tag(struct btf_type *t)
32613309 {
32623310 __u32 info = *(__u32 *)(t + 1);
32633311 long h;
@@ -3267,8 +3315,8 @@ static long btf_hash_int(struct btf_type *t) · 3 unmodified lines
32673315 return h;
32683316 }
32693317
3270−/* Check structural equality of two INTs. */
3271−static bool btf_equal_int(struct btf_type *t1, struct btf_type *t2)
3318+/* Check structural equality of two INTs or TAGs. */
3319+static bool btf_equal_int_tag(struct btf_type *t1, struct btf_type *t2)
32723320 {
32733321 __u32 info1, info2;
32743322
@@ -3535,7 +3583,8 @@ static int btf_dedup_prep(struct btf_dedup *d) · 260 unmodified lines
35353583 h = btf_hash_common(t);
35363584 break;
35373585 case BTF_KIND_INT:
3538− h = btf_hash_int(t);
3586+ case BTF_KIND_TAG:
3587+ h = btf_hash_int_tag(t);
35393588 break;
35403589 case BTF_KIND_ENUM:
35413590 h = btf_hash_enum(t);
@@ -3590,14 +3639,15 @@ static int btf_dedup_prim_type(struct btf_dedup *d, __u32 type_id) · 48 unmodified lines
35903639 case BTF_KIND_FUNC_PROTO:
35913640 case BTF_KIND_VAR:
35923641 case BTF_KIND_DATASEC:
3642+ case BTF_KIND_TAG:
35933643 return 0;
35943644
35953645 case BTF_KIND_INT:
3596− h = btf_hash_int(t);
3646+ h = btf_hash_int_tag(t);
35973647 for_each_dedup_cand(d, hash_entry, h) {
35983648 cand_id = (__u32)(long)hash_entry->value;
35993649 cand = btf_type_by_id(d->btf, cand_id);
3600− if (btf_equal_int(t, cand)) {
3650+ if (btf_equal_int_tag(t, cand)) {
36013651 new_id = cand_id;
36023652 break;
36033653 }
@@ -3881,7 +3931,7 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id, · 277 unmodified lines
38813931
38823932 switch (cand_kind) {
38833933 case BTF_KIND_INT:
3884− return btf_equal_int(cand_type, canon_type);
3934+ return btf_equal_int_tag(cand_type, canon_type);
38853935
38863936 case BTF_KIND_ENUM:
38873937 if (d->opts.dont_resolve_fwds)
@@ -4210,6 +4260,23 @@ static int btf_dedup_ref_type(struct btf_dedup *d, __u32 type_id) · 322 unmodified lines
42104260 }
42114261 break;
42124262
4263+ case BTF_KIND_TAG:
4264+ ref_type_id = btf_dedup_ref_type(d, t->type);
4265+ if (ref_type_id < 0)
4266+ return ref_type_id;
4267+ t->type = ref_type_id;
4268+
4269+ h = btf_hash_int_tag(t);
4270+ for_each_dedup_cand(d, hash_entry, h) {
4271+ cand_id = (__u32)(long)hash_entry->value;
4272+ cand = btf_type_by_id(d->btf, cand_id);
4273+ if (btf_equal_int_tag(t, cand)) {
4274+ new_id = cand_id;
4275+ break;
4276+ }
4277+ }
4278+ break;
4279+
42134280 case BTF_KIND_ARRAY: {
42144281 struct btf_array *info = btf_array(t);
42154282
@@ -4482,6 +4549,7 @@ int btf_type_visit_type_ids(struct btf_type *t, type_id_visit_fn visit, void *ct · 266 unmodified lines
44824549 case BTF_KIND_TYPEDEF:
44834550 case BTF_KIND_FUNC:
44844551 case BTF_KIND_VAR:
4552+ case BTF_KIND_TAG:
44854553 return visit(&t->type, ctx);
44864554
44874555 case BTF_KIND_ARRAY: {
tools/lib/bpf/btf.h+87−0
@@ -1,5 +1,6 @@
11 /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
22 /* Copyright (c) 2018 Facebook */
3+/*! \file */
34
45 #ifndef __LIBBPF_BTF_H
56 #define __LIBBPF_BTF_H
@@ -30,11 +31,80 @@ enum btf_endianness { · 24 unmodified lines
3031 BTF_BIG_ENDIAN = 1,
3132 };
3233
34+/**
35+ * @brief **btf__free()** frees all data of a BTF object
36+ * @param btf BTF object to free
37+ */
3338 LIBBPF_API void btf__free(struct btf *btf);
3439
40+/**
41+ * @brief **btf__new()** creates a new instance of a BTF object from the raw
42+ * bytes of an ELF's BTF section
43+ * @param data raw bytes
44+ * @param size number of bytes passed in `data`
45+ * @return new BTF object instance which has to be eventually freed with
46+ * **btf__free()**
47+ *
48+ * On error, error-code-encoded-as-pointer is returned, not a NULL. To extract
49+ * error code from such a pointer `libbpf_get_error()` should be used. If
50+ * `libbpf_set_strict_mode(LIBBPF_STRICT_CLEAN_PTRS)` is enabled, NULL is
51+ * returned on error instead. In both cases thread-local `errno` variable is
52+ * always set to error code as well.
53+ */
3554 LIBBPF_API struct btf *btf__new(const void *data, __u32 size);
55+
56+/**
57+ * @brief **btf__new_split()** create a new instance of a BTF object from the
58+ * provided raw data bytes. It takes another BTF instance, **base_btf**, which
59+ * serves as a base BTF, which is extended by types in a newly created BTF
60+ * instance
61+ * @param data raw bytes
62+ * @param size length of raw bytes
63+ * @param base_btf the base BTF object
64+ * @return new BTF object instance which has to be eventually freed with
65+ * **btf__free()**
66+ *
67+ * If *base_btf* is NULL, `btf__new_split()` is equivalent to `btf__new()` and
68+ * creates non-split BTF.
69+ *
70+ * On error, error-code-encoded-as-pointer is returned, not a NULL. To extract
71+ * error code from such a pointer `libbpf_get_error()` should be used. If
72+ * `libbpf_set_strict_mode(LIBBPF_STRICT_CLEAN_PTRS)` is enabled, NULL is
73+ * returned on error instead. In both cases thread-local `errno` variable is
74+ * always set to error code as well.
75+ */
3676 LIBBPF_API struct btf *btf__new_split(const void *data, __u32 size, struct btf *base_btf);
77+
78+/**
79+ * @brief **btf__new_empty()** creates an empty BTF object. Use
80+ * `btf__add_*()` to populate such BTF object.
81+ * @return new BTF object instance which has to be eventually freed with
82+ * **btf__free()**
83+ *
84+ * On error, error-code-encoded-as-pointer is returned, not a NULL. To extract
85+ * error code from such a pointer `libbpf_get_error()` should be used. If
86+ * `libbpf_set_strict_mode(LIBBPF_STRICT_CLEAN_PTRS)` is enabled, NULL is
87+ * returned on error instead. In both cases thread-local `errno` variable is
88+ * always set to error code as well.
89+ */
3790 LIBBPF_API struct btf *btf__new_empty(void);
91+
92+/**
93+ * @brief **btf__new_empty_split()** creates an unpopulated BTF object from an
94+ * ELF BTF section except with a base BTF on top of which split BTF should be
95+ * based
96+ * @return new BTF object instance which has to be eventually freed with
97+ * **btf__free()**
98+ *
99+ * If *base_btf* is NULL, `btf__new_empty_split()` is equivalent to
100+ * `btf__new_empty()` and creates non-split BTF.
101+ *
102+ * On error, error-code-encoded-as-pointer is returned, not a NULL. To extract
103+ * error code from such a pointer `libbpf_get_error()` should be used. If
104+ * `libbpf_set_strict_mode(LIBBPF_STRICT_CLEAN_PTRS)` is enabled, NULL is
105+ * returned on error instead. In both cases thread-local `errno` variable is
106+ * always set to error code as well.
107+ */
38108 LIBBPF_API struct btf *btf__new_empty_split(struct btf *base_btf);
39109
40110 LIBBPF_API struct btf *btf__parse(const char *path, struct btf_ext **btf_ext);
@@ -50,9 +120,11 @@ LIBBPF_API struct btf *libbpf_find_kernel_btf(void); · 9 unmodified lines
50120
51121 LIBBPF_API struct btf *btf__load_from_kernel_by_id(__u32 id);
52122 LIBBPF_API struct btf *btf__load_from_kernel_by_id_split(__u32 id, struct btf *base_btf);
123+LIBBPF_DEPRECATED_SINCE(0, 6, "use btf__load_from_kernel_by_id instead")
53124 LIBBPF_API int btf__get_from_id(__u32 id, struct btf **btf);
54125
55126 LIBBPF_API int btf__finalize_data(struct bpf_object *obj, struct btf *btf);
127+LIBBPF_DEPRECATED_SINCE(0, 6, "use btf__load_into_kernel instead")
56128 LIBBPF_API int btf__load(struct btf *btf);
57129 LIBBPF_API int btf__load_into_kernel(struct btf *btf);
58130 LIBBPF_API __s32 btf__find_by_name(const struct btf *btf,
@@ -141,6 +213,10 @@ LIBBPF_API int btf__add_datasec(struct btf *btf, const char *name, __u32 byte_sz · 82 unmodified lines
141213 LIBBPF_API int btf__add_datasec_var_info(struct btf *btf, int var_type_id,
142214 __u32 offset, __u32 byte_sz);
143215
216+/* tag construction API */
217+LIBBPF_API int btf__add_tag(struct btf *btf, const char *value, int ref_type_id,
218+ int component_idx);
219+
144220 struct btf_dedup_opts {
145221 unsigned int dedup_table_size;
146222 bool dont_resolve_fwds;
@@ -328,6 +404,11 @@ static inline bool btf_is_float(const struct btf_type *t) · 181 unmodified lines
328404 return btf_kind(t) == BTF_KIND_FLOAT;
329405 }
330406
407+static inline bool btf_is_tag(const struct btf_type *t)
408+{
409+ return btf_kind(t) == BTF_KIND_TAG;
410+}
411+
331412 static inline __u8 btf_int_encoding(const struct btf_type *t)
332413 {
333414 return BTF_INT_ENCODING(*(__u32 *)(t + 1));
@@ -396,6 +477,12 @@ btf_var_secinfos(const struct btf_type *t) · 62 unmodified lines
396477 return (struct btf_var_secinfo *)(t + 1);
397478 }
398479
480+struct btf_tag;
481+static inline struct btf_tag *btf_tag(const struct btf_type *t)
482+{
483+ return (struct btf_tag *)(t + 1);
484+}
485+
399486 #ifdef __cplusplus
400487 } /* extern "C" */
401488 #endif
tools/lib/bpf/btf_dump.c+3−0
@@ -316,6 +316,7 @@ static int btf_dump_mark_referenced(struct btf_dump *d) · 315 unmodified lines
316316 case BTF_KIND_TYPEDEF:
317317 case BTF_KIND_FUNC:
318318 case BTF_KIND_VAR:
319+ case BTF_KIND_TAG:
319320 d->type_states[t->type].referenced = 1;
320321 break;
321322
@@ -583,6 +584,7 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr) · 261 unmodified lines
583584 case BTF_KIND_FUNC:
584585 case BTF_KIND_VAR:
585586 case BTF_KIND_DATASEC:
587+ case BTF_KIND_TAG:
586588 d->type_states[id].order_state = ORDERED;
587589 return 0;
588590
@@ -2215,6 +2217,7 @@ static int btf_dump_dump_type_data(struct btf_dump *d, · 1626 unmodified lines
22152217 case BTF_KIND_FWD:
22162218 case BTF_KIND_FUNC:
22172219 case BTF_KIND_FUNC_PROTO:
2220+ case BTF_KIND_TAG:
22182221 err = btf_dump_unsupported_data(d, t, id);
22192222 break;
22202223 case BTF_KIND_INT:
tools/lib/bpf/libbpf.c+288−143
@@ -195,6 +195,8 @@ enum kern_feature_id { · 194 unmodified lines
195195 FEAT_BTF_FLOAT,
196196 /* BPF perf link support */
197197 FEAT_PERF_LINK,
198+ /* BTF_KIND_TAG support */
199+ FEAT_BTF_TAG,
198200 __FEAT_CNT,
199201 };
200202
@@ -218,8 +220,7 @@ struct reloc_desc { · 17 unmodified lines
218220
219221 struct bpf_sec_def;
220222
221−typedef struct bpf_link *(*attach_fn_t)(const struct bpf_sec_def *sec,
222− struct bpf_program *prog);
223+typedef struct bpf_link *(*attach_fn_t)(const struct bpf_program *prog);
223224
224225 struct bpf_sec_def {
225226 const char *sec;
@@ -1987,6 +1988,7 @@ static const char *__btf_kind_str(__u16 kind) · 1761 unmodified lines
19871988 case BTF_KIND_VAR: return "var";
19881989 case BTF_KIND_DATASEC: return "datasec";
19891990 case BTF_KIND_FLOAT: return "float";
1991+ case BTF_KIND_TAG: return "tag";
19901992 default: return "unknown";
19911993 }
19921994 }
@@ -2486,8 +2488,9 @@ static bool btf_needs_sanitization(struct bpf_object *obj) · 493 unmodified lines
24862488 bool has_datasec = kernel_supports(obj, FEAT_BTF_DATASEC);
24872489 bool has_float = kernel_supports(obj, FEAT_BTF_FLOAT);
24882490 bool has_func = kernel_supports(obj, FEAT_BTF_FUNC);
2491+ bool has_tag = kernel_supports(obj, FEAT_BTF_TAG);
24892492
2490− return !has_func || !has_datasec || !has_func_global || !has_float;
2493+ return !has_func || !has_datasec || !has_func_global || !has_float || !has_tag;
24912494 }
24922495
24932496 static void bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *btf)
@@ -2496,14 +2499,15 @@ static void bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *btf) · 2 unmodified lines
24962499 bool has_datasec = kernel_supports(obj, FEAT_BTF_DATASEC);
24972500 bool has_float = kernel_supports(obj, FEAT_BTF_FLOAT);
24982501 bool has_func = kernel_supports(obj, FEAT_BTF_FUNC);
2502+ bool has_tag = kernel_supports(obj, FEAT_BTF_TAG);
24992503 struct btf_type *t;
25002504 int i, j, vlen;
25012505
25022506 for (i = 1; i <= btf__get_nr_types(btf); i++) {
25032507 t = (struct btf_type *)btf__type_by_id(btf, i);
25042508
2505− if (!has_datasec && btf_is_var(t)) {
2506− /* replace VAR with INT */
2509+ if ((!has_datasec && btf_is_var(t)) || (!has_tag && btf_is_tag(t))) {
2510+ /* replace VAR/TAG with INT */
25072511 t->info = BTF_INFO_ENC(BTF_KIND_INT, 0, 0);
25082512 /*
25092513 * using size = 1 is the safest choice, 4 will be too
@@ -2993,6 +2997,12 @@ static int bpf_object__elf_collect(struct bpf_object *obj) · 483 unmodified lines
29932997 }
29942998 }
29952999
3000+ if (!obj->efile.symbols) {
3001+ pr_warn("elf: couldn't find symbol table in %s, stripped object file?\n",
3002+ obj->path);
3003+ return -ENOENT;
3004+ }
3005+
29963006 scn = NULL;
29973007 while ((scn = elf_nextscn(elf, scn)) != NULL) {
29983008 idx++;
@@ -4207,6 +4217,23 @@ static int probe_kern_btf_float(void) · 1208 unmodified lines
42074217 strs, sizeof(strs)));
42084218 }
42094219
4220+static int probe_kern_btf_tag(void)
4221+{
4222+ static const char strs[] = "\0tag";
4223+ __u32 types[] = {
4224+ /* int */
4225+ BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
4226+ /* VAR x */ /* [2] */
4227+ BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_VAR, 0, 0), 1),
4228+ BTF_VAR_STATIC,
4229+ /* attr */
4230+ BTF_TYPE_TAG_ENC(1, 2, -1),
4231+ };
4232+
4233+ return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types),
4234+ strs, sizeof(strs)));
4235+}
4236+
42104237 static int probe_kern_array_mmap(void)
42114238 {
42124239 struct bpf_create_map_attr attr = {
@@ -4423,6 +4450,9 @@ static struct kern_feature_desc { · 210 unmodified lines
44234450 [FEAT_PERF_LINK] = {
44244451 "BPF perf link support", probe_perf_link,
44254452 },
4453+ [FEAT_BTF_TAG] = {
4454+ "BTF_KIND_TAG support", probe_kern_btf_tag,
4455+ },
44264456 };
44274457
44284458 static bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id)
@@ -6367,12 +6397,40 @@ bpf_object__load_progs(struct bpf_object *obj, int log_level) · 1938 unmodified lines
63676397
63686398 static const struct bpf_sec_def *find_sec_def(const char *sec_name);
63696399
6400+static int bpf_object_init_progs(struct bpf_object *obj, const struct bpf_object_open_opts *opts)
6401+{
6402+ struct bpf_program *prog;
6403+
6404+ bpf_object__for_each_program(prog, obj) {
6405+ prog->sec_def = find_sec_def(prog->sec_name);
6406+ if (!prog->sec_def) {
6407+ /* couldn't guess, but user might manually specify */
6408+ pr_debug("prog '%s': unrecognized ELF section name '%s'\n",
6409+ prog->name, prog->sec_name);
6410+ continue;
6411+ }
6412+
6413+ if (prog->sec_def->is_sleepable)
6414+ prog->prog_flags |= BPF_F_SLEEPABLE;
6415+ bpf_program__set_type(prog, prog->sec_def->prog_type);
6416+ bpf_program__set_expected_attach_type(prog, prog->sec_def->expected_attach_type);
6417+
6418+#pragma GCC diagnostic push
6419+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
6420+ if (prog->sec_def->prog_type == BPF_PROG_TYPE_TRACING ||
6421+ prog->sec_def->prog_type == BPF_PROG_TYPE_EXT)
6422+ prog->attach_prog_fd = OPTS_GET(opts, attach_prog_fd, 0);
6423+#pragma GCC diagnostic pop
6424+ }
6425+
6426+ return 0;
6427+}
6428+
63706429 static struct bpf_object *
63716430 __bpf_object__open(const char *path, const void *obj_buf, size_t obj_buf_sz,
63726431 const struct bpf_object_open_opts *opts)
63736432 {
63746433 const char *obj_name, *kconfig, *btf_tmp_path;
6375− struct bpf_program *prog;
63766434 struct bpf_object *obj;
63776435 char tmp_name[64];
63786436 int err;
@@ -6430,30 +6488,12 @@ __bpf_object__open(const char *path, const void *obj_buf, size_t obj_buf_sz, · 51 unmodified lines
64306488 err = err ? : bpf_object__collect_externs(obj);
64316489 err = err ? : bpf_object__finalize_btf(obj);
64326490 err = err ? : bpf_object__init_maps(obj, opts);
6491+ err = err ? : bpf_object_init_progs(obj, opts);
64336492 err = err ? : bpf_object__collect_relos(obj);
64346493 if (err)
64356494 goto out;
6436− bpf_object__elf_finish(obj);
64376495
6438− bpf_object__for_each_program(prog, obj) {
6439− prog->sec_def = find_sec_def(prog->sec_name);
6440− if (!prog->sec_def) {
6441− /* couldn't guess, but user might manually specify */
6442− pr_debug("prog '%s': unrecognized ELF section name '%s'\n",
6443− prog->name, prog->sec_name);
6444− continue;
6445− }
6446−
6447− if (prog->sec_def->is_sleepable)
6448− prog->prog_flags |= BPF_F_SLEEPABLE;
6449− bpf_program__set_type(prog, prog->sec_def->prog_type);
6450− bpf_program__set_expected_attach_type(prog,
6451− prog->sec_def->expected_attach_type);
6452−
6453− if (prog->sec_def->prog_type == BPF_PROG_TYPE_TRACING ||
6454− prog->sec_def->prog_type == BPF_PROG_TYPE_EXT)
6455− prog->attach_prog_fd = OPTS_GET(opts, attach_prog_fd, 0);
6456− }
6496+ bpf_object__elf_finish(obj);
64576497
64586498 return obj;
64596499 out:
@@ -7907,18 +7947,12 @@ void bpf_program__set_expected_attach_type(struct bpf_program *prog, · 1447 unmodified lines
79077947 __VA_ARGS__ \
79087948 }
79097949
7910−static struct bpf_link *attach_kprobe(const struct bpf_sec_def *sec,
7911− struct bpf_program *prog);
7912−static struct bpf_link *attach_tp(const struct bpf_sec_def *sec,
7913− struct bpf_program *prog);
7914−static struct bpf_link *attach_raw_tp(const struct bpf_sec_def *sec,
7915− struct bpf_program *prog);
7916−static struct bpf_link *attach_trace(const struct bpf_sec_def *sec,
7917− struct bpf_program *prog);
7918−static struct bpf_link *attach_lsm(const struct bpf_sec_def *sec,
7919− struct bpf_program *prog);
7920−static struct bpf_link *attach_iter(const struct bpf_sec_def *sec,
7921− struct bpf_program *prog);
7950+static struct bpf_link *attach_kprobe(const struct bpf_program *prog);
7951+static struct bpf_link *attach_tp(const struct bpf_program *prog);
7952+static struct bpf_link *attach_raw_tp(const struct bpf_program *prog);
7953+static struct bpf_link *attach_trace(const struct bpf_program *prog);
7954+static struct bpf_link *attach_lsm(const struct bpf_program *prog);
7955+static struct bpf_link *attach_iter(const struct bpf_program *prog);
79227956
79237957 static const struct bpf_sec_def section_defs[] = {
79247958 BPF_PROG_SEC("socket", BPF_PROG_TYPE_SOCKET_FILTER),
@@ -8244,35 +8278,37 @@ static int bpf_object__collect_st_ops_relos(struct bpf_object *obj, · 319 unmodified lines
82448278 return -EINVAL;
82458279 }
82468280
8247− if (prog->type == BPF_PROG_TYPE_UNSPEC) {
8248− const struct bpf_sec_def *sec_def;
8249−
8250− sec_def = find_sec_def(prog->sec_name);
8251− if (sec_def &&
8252− sec_def->prog_type != BPF_PROG_TYPE_STRUCT_OPS) {
8253− /* for pr_warn */
8254− prog->type = sec_def->prog_type;
8255− goto invalid_prog;
8256− }
8281+ /* prevent the use of BPF prog with invalid type */
8282+ if (prog->type != BPF_PROG_TYPE_STRUCT_OPS) {
8283+ pr_warn("struct_ops reloc %s: prog %s is not struct_ops BPF program\n",
8284+ map->name, prog->name);
8285+ return -EINVAL;
8286+ }
82578287
8258− prog->type = BPF_PROG_TYPE_STRUCT_OPS;
8288+ /* if we haven't yet processed this BPF program, record proper
8289+ * attach_btf_id and member_idx
8290+ */
8291+ if (!prog->attach_btf_id) {
82598292 prog->attach_btf_id = st_ops->type_id;
82608293 prog->expected_attach_type = member_idx;
8261− } else if (prog->type != BPF_PROG_TYPE_STRUCT_OPS ||
8262− prog->attach_btf_id != st_ops->type_id ||
8263− prog->expected_attach_type != member_idx) {
8264− goto invalid_prog;
82658294 }
8295+
8296+ /* struct_ops BPF prog can be re-used between multiple
8297+ * .struct_ops as long as it's the same struct_ops struct
8298+ * definition and the same function pointer field
8299+ */
8300+ if (prog->attach_btf_id != st_ops->type_id ||
8301+ prog->expected_attach_type != member_idx) {
8302+ pr_warn("struct_ops reloc %s: cannot use prog %s in sec %s with type %u attach_btf_id %u expected_attach_type %u for func ptr %s\n",
8303+ map->name, prog->name, prog->sec_name, prog->type,
8304+ prog->attach_btf_id, prog->expected_attach_type, name);
8305+ return -EINVAL;
8306+ }
8307+
82668308 st_ops->progs[member_idx] = prog;
82678309 }
82688310
82698311 return 0;
8270−
8271−invalid_prog:
8272− pr_warn("struct_ops reloc %s: cannot use prog %s in sec %s with type %u attach_btf_id %u expected_attach_type %u for func ptr %s\n",
8273− map->name, prog->name, prog->sec_name, prog->type,
8274− prog->attach_btf_id, prog->expected_attach_type, name);
8275− return -EINVAL;
82768312 }
82778313
82788314 #define BTF_TRACE_PREFIX "btf_trace_"
@@ -8428,28 +8464,15 @@ static int libbpf_find_attach_btf_id(struct bpf_program *prog, int *btf_obj_fd, · 149 unmodified lines
84288464 {
84298465 enum bpf_attach_type attach_type = prog->expected_attach_type;
84308466 __u32 attach_prog_fd = prog->attach_prog_fd;
8431− const char *name = prog->sec_name, *attach_name;
8432− const struct bpf_sec_def *sec = NULL;
8433− int i, err = 0;
8434−
8435− if (!name)
8436− return -EINVAL;
8437−
8438− for (i = 0; i < ARRAY_SIZE(section_defs); i++) {
8439− if (!section_defs[i].is_attach_btf)
8440− continue;
8441− if (strncmp(name, section_defs[i].sec, section_defs[i].len))
8442− continue;
8443−
8444− sec = &section_defs[i];
8445− break;
8446− }
8467+ const char *attach_name;
8468+ int err = 0;
84478469
8448− if (!sec) {
8449− pr_warn("failed to identify BTF ID based on ELF section name '%s'\n", name);
8470+ if (!prog->sec_def || !prog->sec_def->is_attach_btf) {
8471+ pr_warn("failed to identify BTF ID based on ELF section name '%s'\n",
8472+ prog->sec_name);
84508473 return -ESRCH;
84518474 }
8452− attach_name = name + sec->len;
8475+ attach_name = prog->sec_name + prog->sec_def->len;
84538476
84548477 /* BPF program's BTF ID */
84558478 if (attach_prog_fd) {
@@ -8483,27 +8506,28 @@ int libbpf_attach_type_by_name(const char *name, · 27 unmodified lines
84838506 enum bpf_attach_type *attach_type)
84848507 {
84858508 char *type_names;
8486− int i;
8509+ const struct bpf_sec_def *sec_def;
84878510
84888511 if (!name)
84898512 return libbpf_err(-EINVAL);
84908513
8491− for (i = 0; i < ARRAY_SIZE(section_defs); i++) {
8492− if (strncmp(name, section_defs[i].sec, section_defs[i].len))
8493− continue;
8494− if (!section_defs[i].is_attachable)
8495− return libbpf_err(-EINVAL);
8496− *attach_type = section_defs[i].expected_attach_type;
8497− return 0;
8498− }
8499− pr_debug("failed to guess attach type based on ELF section name '%s'\n", name);
8500− type_names = libbpf_get_type_names(true);
8501− if (type_names != NULL) {
8502− pr_debug("attachable section(type) names are:%s\n", type_names);
8503− free(type_names);
8514+ sec_def = find_sec_def(name);
8515+ if (!sec_def) {
8516+ pr_debug("failed to guess attach type based on ELF section name '%s'\n", name);
8517+ type_names = libbpf_get_type_names(true);
8518+ if (type_names != NULL) {
8519+ pr_debug("attachable section(type) names are:%s\n", type_names);
8520+ free(type_names);
8521+ }
8522+
8523+ return libbpf_err(-EINVAL);
85048524 }
85058525
8506− return libbpf_err(-EINVAL);
8526+ if (!sec_def->is_attachable)
8527+ return libbpf_err(-EINVAL);
8528+
8529+ *attach_type = sec_def->expected_attach_type;
8530+ return 0;
85078531 }
85088532
85098533 int bpf_map__fd(const struct bpf_map *map)
@@ -8987,9 +9011,57 @@ int bpf_link__unpin(struct bpf_link *link) · 477 unmodified lines
89879011 return 0;
89889012 }
89899013
9014+static int poke_kprobe_events(bool add, const char *name, bool retprobe, uint64_t offset)
9015+{
9016+ int fd, ret = 0;
9017+ pid_t p = getpid();
9018+ char cmd[260], probename[128], probefunc[128];
9019+ const char *file = "/sys/kernel/debug/tracing/kprobe_events";
9020+
9021+ if (retprobe)
9022+ snprintf(probename, sizeof(probename), "kretprobes/%s_libbpf_%u", name, p);
9023+ else
9024+ snprintf(probename, sizeof(probename), "kprobes/%s_libbpf_%u", name, p);
9025+
9026+ if (offset)
9027+ snprintf(probefunc, sizeof(probefunc), "%s+%zu", name, (size_t)offset);
9028+
9029+ if (add) {
9030+ snprintf(cmd, sizeof(cmd), "%c:%s %s",
9031+ retprobe ? 'r' : 'p',
9032+ probename,
9033+ offset ? probefunc : name);
9034+ } else {
9035+ snprintf(cmd, sizeof(cmd), "-:%s", probename);
9036+ }
9037+
9038+ fd = open(file, O_WRONLY | O_APPEND, 0);
9039+ if (!fd)
9040+ return -errno;
9041+ ret = write(fd, cmd, strlen(cmd));
9042+ if (ret < 0)
9043+ ret = -errno;
9044+ close(fd);
9045+
9046+ return ret;
9047+}
9048+
9049+static inline int add_kprobe_event_legacy(const char *name, bool retprobe, uint64_t offset)
9050+{
9051+ return poke_kprobe_events(true, name, retprobe, offset);
9052+}
9053+
9054+static inline int remove_kprobe_event_legacy(const char *name, bool retprobe)
9055+{
9056+ return poke_kprobe_events(false, name, retprobe, 0);
9057+}
9058+
89909059 struct bpf_link_perf {
89919060 struct bpf_link link;
89929061 int perf_event_fd;
9062+ /* legacy kprobe support: keep track of probe identifier and type */
9063+ char *legacy_probe_name;
9064+ bool legacy_is_retprobe;
89939065 };
89949066
89959067 static int bpf_link_perf_detach(struct bpf_link *link)
@@ -9004,17 +9076,23 @@ static int bpf_link_perf_detach(struct bpf_link *link) · 8 unmodified lines
90049076 close(perf_link->perf_event_fd);
90059077 close(link->fd);
90069078
9007− return libbpf_err(err);
9079+ /* legacy kprobe needs to be removed after perf event fd closure */
9080+ if (perf_link->legacy_probe_name)
9081+ err = remove_kprobe_event_legacy(perf_link->legacy_probe_name,
9082+ perf_link->legacy_is_retprobe);
9083+
9084+ return err;
90089085 }
90099086
90109087 static void bpf_link_perf_dealloc(struct bpf_link *link)
90119088 {
90129089 struct bpf_link_perf *perf_link = container_of(link, struct bpf_link_perf, link);
90139090
9091+ free(perf_link->legacy_probe_name);
90149092 free(perf_link);
90159093 }
90169094
9017−struct bpf_link *bpf_program__attach_perf_event_opts(struct bpf_program *prog, int pfd,
9095+struct bpf_link *bpf_program__attach_perf_event_opts(const struct bpf_program *prog, int pfd,
90189096 const struct bpf_perf_event_opts *opts)
90199097 {
90209098 char errmsg[STRERR_BUFSIZE];
@@ -9089,7 +9167,7 @@ err_out: · 68 unmodified lines
90899167 return libbpf_err_ptr(err);
90909168 }
90919169
9092−struct bpf_link *bpf_program__attach_perf_event(struct bpf_program *prog, int pfd)
9170+struct bpf_link *bpf_program__attach_perf_event(const struct bpf_program *prog, int pfd)
90939171 {
90949172 return bpf_program__attach_perf_event_opts(prog, pfd, NULL);
90959173 }
@@ -9124,6 +9202,18 @@ static int parse_uint_from_file(const char *file, const char *fmt) · 28 unmodified lines
91249202 return ret;
91259203 }
91269204
9205+static int determine_kprobe_perf_type_legacy(const char *func_name, bool is_retprobe)
9206+{
9207+ char file[192];
9208+
9209+ snprintf(file, sizeof(file),
9210+ "/sys/kernel/debug/tracing/events/%s/%s_libbpf_%d/id",
9211+ is_retprobe ? "kretprobes" : "kprobes",
9212+ func_name, getpid());
9213+
9214+ return parse_uint_from_file(file, "%d\n");
9215+}
9216+
91279217 static int determine_kprobe_perf_type(void)
91289218 {
91299219 const char *file = "/sys/bus/event_source/devices/kprobe/type";
@@ -9206,16 +9296,52 @@ static int perf_event_open_probe(bool uprobe, bool retprobe, const char *name, · 76 unmodified lines
92069296 return pfd;
92079297 }
92089298
9299+static int perf_event_kprobe_open_legacy(bool retprobe, const char *name, uint64_t offset, int pid)
9300+{
9301+ struct perf_event_attr attr = {};
9302+ char errmsg[STRERR_BUFSIZE];
9303+ int type, pfd, err;
9304+
9305+ err = add_kprobe_event_legacy(name, retprobe, offset);
9306+ if (err < 0) {
9307+ pr_warn("failed to add legacy kprobe event: %s\n",
9308+ libbpf_strerror_r(err, errmsg, sizeof(errmsg)));
9309+ return err;
9310+ }
9311+ type = determine_kprobe_perf_type_legacy(name, retprobe);
9312+ if (type < 0) {
9313+ pr_warn("failed to determine legacy kprobe event id: %s\n",
9314+ libbpf_strerror_r(type, errmsg, sizeof(errmsg)));
9315+ return type;
9316+ }
9317+ attr.size = sizeof(attr);
9318+ attr.config = type;
9319+ attr.type = PERF_TYPE_TRACEPOINT;
9320+
9321+ pfd = syscall(__NR_perf_event_open, &attr,
9322+ pid < 0 ? -1 : pid, /* pid */
9323+ pid == -1 ? 0 : -1, /* cpu */
9324+ -1 /* group_fd */, PERF_FLAG_FD_CLOEXEC);
9325+ if (pfd < 0) {
9326+ err = -errno;
9327+ pr_warn("legacy kprobe perf_event_open() failed: %s\n",
9328+ libbpf_strerror_r(err, errmsg, sizeof(errmsg)));
9329+ return err;
9330+ }
9331+ return pfd;
9332+}
9333+
92099334 struct bpf_link *
9210−bpf_program__attach_kprobe_opts(struct bpf_program *prog,
9335+bpf_program__attach_kprobe_opts(const struct bpf_program *prog,
92119336 const char *func_name,
92129337 const struct bpf_kprobe_opts *opts)
92139338 {
92149339 DECLARE_LIBBPF_OPTS(bpf_perf_event_opts, pe_opts);
92159340 char errmsg[STRERR_BUFSIZE];
9341+ char *legacy_probe = NULL;
92169342 struct bpf_link *link;
92179343 unsigned long offset;
9218− bool retprobe;
9344+ bool retprobe, legacy;
92199345 int pfd, err;
92209346
92219347 if (!OPTS_VALID(opts, bpf_kprobe_opts))
@@ -9225,8 +9351,19 @@ bpf_program__attach_kprobe_opts(struct bpf_program *prog, · 3 unmodified lines
92259351 offset = OPTS_GET(opts, offset, 0);
92269352 pe_opts.bpf_cookie = OPTS_GET(opts, bpf_cookie, 0);
92279353
9228− pfd = perf_event_open_probe(false /* uprobe */, retprobe, func_name,
9229− offset, -1 /* pid */, 0 /* ref_ctr_off */);
9354+ legacy = determine_kprobe_perf_type() < 0;
9355+ if (!legacy) {
9356+ pfd = perf_event_open_probe(false /* uprobe */, retprobe,
9357+ func_name, offset,
9358+ -1 /* pid */, 0 /* ref_ctr_off */);
9359+ } else {
9360+ legacy_probe = strdup(func_name);
9361+ if (!legacy_probe)
9362+ return libbpf_err_ptr(-ENOMEM);
9363+
9364+ pfd = perf_event_kprobe_open_legacy(retprobe, func_name,
9365+ offset, -1 /* pid */);
9366+ }
92309367 if (pfd < 0) {
92319368 pr_warn("prog '%s': failed to create %s '%s' perf event: %s\n",
92329369 prog->name, retprobe ? "kretprobe" : "kprobe", func_name,
@@ -9242,10 +9379,17 @@ bpf_program__attach_kprobe_opts(struct bpf_program *prog, · 9 unmodified lines
92429379 libbpf_strerror_r(err, errmsg, sizeof(errmsg)));
92439380 return libbpf_err_ptr(err);
92449381 }
9382+ if (legacy) {
9383+ struct bpf_link_perf *perf_link = container_of(link, struct bpf_link_perf, link);
9384+
9385+ perf_link->legacy_probe_name = legacy_probe;
9386+ perf_link->legacy_is_retprobe = retprobe;
9387+ }
9388+
92459389 return link;
92469390 }
92479391
9248−struct bpf_link *bpf_program__attach_kprobe(struct bpf_program *prog,
9392+struct bpf_link *bpf_program__attach_kprobe(const struct bpf_program *prog,
92499393 bool retprobe,
92509394 const char *func_name)
92519395 {
@@ -9256,8 +9400,7 @@ struct bpf_link *bpf_program__attach_kprobe(struct bpf_program *prog, · 4 unmodified lines
92569400 return bpf_program__attach_kprobe_opts(prog, func_name, &opts);
92579401 }
92589402
9259−static struct bpf_link *attach_kprobe(const struct bpf_sec_def *sec,
9260− struct bpf_program *prog)
9403+static struct bpf_link *attach_kprobe(const struct bpf_program *prog)
92619404 {
92629405 DECLARE_LIBBPF_OPTS(bpf_kprobe_opts, opts);
92639406 unsigned long offset = 0;
@@ -9266,8 +9409,8 @@ static struct bpf_link *attach_kprobe(const struct bpf_sec_def *sec, · 2 unmodified lines
92669409 char *func;
92679410 int n, err;
92689411
9269− func_name = prog->sec_name + sec->len;
9270− opts.retprobe = strcmp(sec->sec, "kretprobe/") == 0;
9412+ func_name = prog->sec_name + prog->sec_def->len;
9413+ opts.retprobe = strcmp(prog->sec_def->sec, "kretprobe/") == 0;
92719414
92729415 n = sscanf(func_name, "%m[a-zA-Z0-9_.]+%li", &func, &offset);
92739416 if (n < 1) {
@@ -9289,7 +9432,7 @@ static struct bpf_link *attach_kprobe(const struct bpf_sec_def *sec, · 15 unmodified lines
92899432 }
92909433
92919434 LIBBPF_API struct bpf_link *
9292−bpf_program__attach_uprobe_opts(struct bpf_program *prog, pid_t pid,
9435+bpf_program__attach_uprobe_opts(const struct bpf_program *prog, pid_t pid,
92939436 const char *binary_path, size_t func_offset,
92949437 const struct bpf_uprobe_opts *opts)
92959438 {
@@ -9329,7 +9472,7 @@ bpf_program__attach_uprobe_opts(struct bpf_program *prog, pid_t pid, · 33 unmodified lines
93299472 return link;
93309473 }
93319474
9332−struct bpf_link *bpf_program__attach_uprobe(struct bpf_program *prog,
9475+struct bpf_link *bpf_program__attach_uprobe(const struct bpf_program *prog,
93339476 bool retprobe, pid_t pid,
93349477 const char *binary_path,
93359478 size_t func_offset)
@@ -9389,7 +9532,7 @@ static int perf_event_open_tracepoint(const char *tp_category, · 53 unmodified lines
93899532 return pfd;
93909533 }
93919534
9392−struct bpf_link *bpf_program__attach_tracepoint_opts(struct bpf_program *prog,
9535+struct bpf_link *bpf_program__attach_tracepoint_opts(const struct bpf_program *prog,
93939536 const char *tp_category,
93949537 const char *tp_name,
93959538 const struct bpf_tracepoint_opts *opts)
@@ -9423,15 +9566,14 @@ struct bpf_link *bpf_program__attach_tracepoint_opts(struct bpf_program *prog, · 27 unmodified lines
94239566 return link;
94249567 }
94259568
9426−struct bpf_link *bpf_program__attach_tracepoint(struct bpf_program *prog,
9569+struct bpf_link *bpf_program__attach_tracepoint(const struct bpf_program *prog,
94279570 const char *tp_category,
94289571 const char *tp_name)
94299572 {
94309573 return bpf_program__attach_tracepoint_opts(prog, tp_category, tp_name, NULL);
94319574 }
94329575
9433−static struct bpf_link *attach_tp(const struct bpf_sec_def *sec,
9434− struct bpf_program *prog)
9576+static struct bpf_link *attach_tp(const struct bpf_program *prog)
94359577 {
94369578 char *sec_name, *tp_cat, *tp_name;
94379579 struct bpf_link *link;
@@ -9441,7 +9583,7 @@ static struct bpf_link *attach_tp(const struct bpf_sec_def *sec, · 3 unmodified lines
94419583 return libbpf_err_ptr(-ENOMEM);
94429584
94439585 /* extract "tp/<category>/<name>" */
9444− tp_cat = sec_name + sec->len;
9586+ tp_cat = sec_name + prog->sec_def->len;
94459587 tp_name = strchr(tp_cat, '/');
94469588 if (!tp_name) {
94479589 free(sec_name);
@@ -9455,7 +9597,7 @@ static struct bpf_link *attach_tp(const struct bpf_sec_def *sec, · 7 unmodified lines
94559597 return link;
94569598 }
94579599
9458−struct bpf_link *bpf_program__attach_raw_tracepoint(struct bpf_program *prog,
9600+struct bpf_link *bpf_program__attach_raw_tracepoint(const struct bpf_program *prog,
94599601 const char *tp_name)
94609602 {
94619603 char errmsg[STRERR_BUFSIZE];
@@ -9485,16 +9627,15 @@ struct bpf_link *bpf_program__attach_raw_tracepoint(struct bpf_program *prog, · 23 unmodified lines
94859627 return link;
94869628 }
94879629
9488−static struct bpf_link *attach_raw_tp(const struct bpf_sec_def *sec,
9489− struct bpf_program *prog)
9630+static struct bpf_link *attach_raw_tp(const struct bpf_program *prog)
94909631 {
9491− const char *tp_name = prog->sec_name + sec->len;
9632+ const char *tp_name = prog->sec_name + prog->sec_def->len;
94929633
94939634 return bpf_program__attach_raw_tracepoint(prog, tp_name);
94949635 }
94959636
94969637 /* Common logic for all BPF program types that attach to a btf_id */
9497−static struct bpf_link *bpf_program__attach_btf_id(struct bpf_program *prog)
9638+static struct bpf_link *bpf_program__attach_btf_id(const struct bpf_program *prog)
94989639 {
94999640 char errmsg[STRERR_BUFSIZE];
95009641 struct bpf_link *link;
@@ -9523,30 +9664,28 @@ static struct bpf_link *bpf_program__attach_btf_id(struct bpf_program *prog) · 22 unmodified lines
95239664 return (struct bpf_link *)link;
95249665 }
95259666
9526−struct bpf_link *bpf_program__attach_trace(struct bpf_program *prog)
9667+struct bpf_link *bpf_program__attach_trace(const struct bpf_program *prog)
95279668 {
95289669 return bpf_program__attach_btf_id(prog);
95299670 }
95309671
9531−struct bpf_link *bpf_program__attach_lsm(struct bpf_program *prog)
9672+struct bpf_link *bpf_program__attach_lsm(const struct bpf_program *prog)
95329673 {
95339674 return bpf_program__attach_btf_id(prog);
95349675 }
95359676
9536−static struct bpf_link *attach_trace(const struct bpf_sec_def *sec,
9537− struct bpf_program *prog)
9677+static struct bpf_link *attach_trace(const struct bpf_program *prog)
95389678 {
95399679 return bpf_program__attach_trace(prog);
95409680 }
95419681
9542−static struct bpf_link *attach_lsm(const struct bpf_sec_def *sec,
9543− struct bpf_program *prog)
9682+static struct bpf_link *attach_lsm(const struct bpf_program *prog)
95449683 {
95459684 return bpf_program__attach_lsm(prog);
95469685 }
95479686
95489687 static struct bpf_link *
9549−bpf_program__attach_fd(struct bpf_program *prog, int target_fd, int btf_id,
9688+bpf_program__attach_fd(const struct bpf_program *prog, int target_fd, int btf_id,
95509689 const char *target_name)
95519690 {
95529691 DECLARE_LIBBPF_OPTS(bpf_link_create_opts, opts,
@@ -9582,24 +9721,24 @@ bpf_program__attach_fd(struct bpf_program *prog, int target_fd, int btf_id, · 29 unmodified lines
95829721 }
95839722
95849723 struct bpf_link *
9585−bpf_program__attach_cgroup(struct bpf_program *prog, int cgroup_fd)
9724+bpf_program__attach_cgroup(const struct bpf_program *prog, int cgroup_fd)
95869725 {
95879726 return bpf_program__attach_fd(prog, cgroup_fd, 0, "cgroup");
95889727 }
95899728
95909729 struct bpf_link *
9591−bpf_program__attach_netns(struct bpf_program *prog, int netns_fd)
9730+bpf_program__attach_netns(const struct bpf_program *prog, int netns_fd)
95929731 {
95939732 return bpf_program__attach_fd(prog, netns_fd, 0, "netns");
95949733 }
95959734
9596−struct bpf_link *bpf_program__attach_xdp(struct bpf_program *prog, int ifindex)
9735+struct bpf_link *bpf_program__attach_xdp(const struct bpf_program *prog, int ifindex)
95979736 {
95989737 /* target_fd/target_ifindex use the same field in LINK_CREATE */
95999738 return bpf_program__attach_fd(prog, ifindex, 0, "xdp");
96009739 }
96019740
9602−struct bpf_link *bpf_program__attach_freplace(struct bpf_program *prog,
9741+struct bpf_link *bpf_program__attach_freplace(const struct bpf_program *prog,
96039742 int target_fd,
96049743 const char *attach_func_name)
96059744 {
@@ -9632,7 +9771,7 @@ struct bpf_link *bpf_program__attach_freplace(struct bpf_program *prog, · 26 unmodified lines
96329771 }
96339772
96349773 struct bpf_link *
9635−bpf_program__attach_iter(struct bpf_program *prog,
9774+bpf_program__attach_iter(const struct bpf_program *prog,
96369775 const struct bpf_iter_attach_opts *opts)
96379776 {
96389777 DECLARE_LIBBPF_OPTS(bpf_link_create_opts, link_create_opts);
@@ -9671,21 +9810,17 @@ bpf_program__attach_iter(struct bpf_program *prog, · 32 unmodified lines
96719810 return link;
96729811 }
96739812
9674−static struct bpf_link *attach_iter(const struct bpf_sec_def *sec,
9675− struct bpf_program *prog)
9813+static struct bpf_link *attach_iter(const struct bpf_program *prog)
96769814 {
96779815 return bpf_program__attach_iter(prog, NULL);
96789816 }
96799817
9680−struct bpf_link *bpf_program__attach(struct bpf_program *prog)
9818+struct bpf_link *bpf_program__attach(const struct bpf_program *prog)
96819819 {
9682− const struct bpf_sec_def *sec_def;
9683−
9684− sec_def = find_sec_def(prog->sec_name);
9685− if (!sec_def || !sec_def->attach_fn)
9820+ if (!prog->sec_def || !prog->sec_def->attach_fn)
96869821 return libbpf_err_ptr(-ESRCH);
96879822
9688− return sec_def->attach_fn(sec_def, prog);
9823+ return prog->sec_def->attach_fn(prog);
96899824 }
96909825
96919826 static int bpf_link__detach_struct_ops(struct bpf_link *link)
@@ -9698,7 +9833,7 @@ static int bpf_link__detach_struct_ops(struct bpf_link *link) · 6 unmodified lines
96989833 return 0;
96999834 }
97009835
9701−struct bpf_link *bpf_map__attach_struct_ops(struct bpf_map *map)
9836+struct bpf_link *bpf_map__attach_struct_ops(const struct bpf_map *map)
97029837 {
97039838 struct bpf_struct_ops *st_ops;
97049839 struct bpf_link *link;
@@ -10511,18 +10646,29 @@ int bpf_program__set_attach_target(struct bpf_program *prog, · 806 unmodified lines
1051110646 {
1051210647 int btf_obj_fd = 0, btf_id = 0, err;
1051310648
10514− if (!prog || attach_prog_fd < 0 || !attach_func_name)
10649+ if (!prog || attach_prog_fd < 0)
1051510650 return libbpf_err(-EINVAL);
1051610651
1051710652 if (prog->obj->loaded)
1051810653 return libbpf_err(-EINVAL);
1051910654
10655+ if (attach_prog_fd && !attach_func_name) {
10656+ /* remember attach_prog_fd and let bpf_program__load() find
10657+ * BTF ID during the program load
10658+ */
10659+ prog->attach_prog_fd = attach_prog_fd;
10660+ return 0;
10661+ }
10662+
1052010663 if (attach_prog_fd) {
1052110664 btf_id = libbpf_find_prog_btf_id(attach_func_name,
1052210665 attach_prog_fd);
1052310666 if (btf_id < 0)
1052410667 return libbpf_err(btf_id);
1052510668 } else {
10669+ if (!attach_func_name)
10670+ return libbpf_err(-EINVAL);
10671+
1052610672 /* load btf_vmlinux, if not yet */
1052710673 err = bpf_object__load_vmlinux_btf(prog->obj, true);
1052810674 if (err)
@@ -10764,16 +10910,15 @@ int bpf_object__attach_skeleton(struct bpf_object_skeleton *s) · 235 unmodified lines
1076410910 for (i = 0; i < s->prog_cnt; i++) {
1076510911 struct bpf_program *prog = *s->progs[i].prog;
1076610912 struct bpf_link **link = s->progs[i].link;
10767− const struct bpf_sec_def *sec_def;
1076810913
1076910914 if (!prog->load)
1077010915 continue;
1077110916
10772− sec_def = find_sec_def(prog->sec_name);
10773− if (!sec_def || !sec_def->attach_fn)
10917+ /* auto-attaching not supported for this program */
10918+ if (!prog->sec_def || !prog->sec_def->attach_fn)
1077410919 continue;
1077510920
10776− *link = sec_def->attach_fn(sec_def, prog);
10921+ *link = bpf_program__attach(prog);
1077710922 err = libbpf_get_error(*link);
1077810923 if (err) {
1077910924 pr_warn("failed to auto-attach program '%s': %d\n",
tools/lib/bpf/libbpf.h+22−19
@@ -83,12 +83,15 @@ struct bpf_object_open_opts { · 82 unmodified lines
8383 * Non-relocatable instructions are replaced with invalid ones to
8484 * prevent accidental errors.
8585 * */
86+ LIBBPF_DEPRECATED_SINCE(0, 6, "field has no effect")
8687 bool relaxed_core_relocs;
8788 /* maps that set the 'pinning' attribute in their definition will have
8889 * their pin_path attribute set to a file in this directory, and be
8990 * auto-pinned to that path on load; defaults to "/sys/fs/bpf".
9091 */
9192 const char *pin_root_path;
93+
94+ LIBBPF_DEPRECATED_SINCE(0, 7, "use bpf_program__set_attach_target() on each individual bpf_program")
9295 __u32 attach_prog_fd;
9396 /* Additional kernel config content that augments and overrides
9497 * system Kconfig for CONFIG_xxx externs.
@@ -243,7 +246,7 @@ LIBBPF_API int bpf_link__detach(struct bpf_link *link); · 148 unmodified lines
243246 LIBBPF_API int bpf_link__destroy(struct bpf_link *link);
244247
245248 LIBBPF_API struct bpf_link *
246−bpf_program__attach(struct bpf_program *prog);
249+bpf_program__attach(const struct bpf_program *prog);
247250
248251 struct bpf_perf_event_opts {
249252 /* size of this struct, for forward/backward compatiblity */
@@ -254,10 +257,10 @@ struct bpf_perf_event_opts { · 4 unmodified lines
254257 #define bpf_perf_event_opts__last_field bpf_cookie
255258
256259 LIBBPF_API struct bpf_link *
257−bpf_program__attach_perf_event(struct bpf_program *prog, int pfd);
260+bpf_program__attach_perf_event(const struct bpf_program *prog, int pfd);
258261
259262 LIBBPF_API struct bpf_link *
260−bpf_program__attach_perf_event_opts(struct bpf_program *prog, int pfd,
263+bpf_program__attach_perf_event_opts(const struct bpf_program *prog, int pfd,
261264 const struct bpf_perf_event_opts *opts);
262265
263266 struct bpf_kprobe_opts {
@@ -274,10 +277,10 @@ struct bpf_kprobe_opts { · 10 unmodified lines
274277 #define bpf_kprobe_opts__last_field retprobe
275278
276279 LIBBPF_API struct bpf_link *
277−bpf_program__attach_kprobe(struct bpf_program *prog, bool retprobe,
280+bpf_program__attach_kprobe(const struct bpf_program *prog, bool retprobe,
278281 const char *func_name);
279282 LIBBPF_API struct bpf_link *
280−bpf_program__attach_kprobe_opts(struct bpf_program *prog,
283+bpf_program__attach_kprobe_opts(const struct bpf_program *prog,
281284 const char *func_name,
282285 const struct bpf_kprobe_opts *opts);
283286
@@ -297,11 +300,11 @@ struct bpf_uprobe_opts { · 13 unmodified lines
297300 #define bpf_uprobe_opts__last_field retprobe
298301
299302 LIBBPF_API struct bpf_link *
300−bpf_program__attach_uprobe(struct bpf_program *prog, bool retprobe,
303+bpf_program__attach_uprobe(const struct bpf_program *prog, bool retprobe,
301304 pid_t pid, const char *binary_path,
302305 size_t func_offset);
303306 LIBBPF_API struct bpf_link *
304−bpf_program__attach_uprobe_opts(struct bpf_program *prog, pid_t pid,
307+bpf_program__attach_uprobe_opts(const struct bpf_program *prog, pid_t pid,
305308 const char *binary_path, size_t func_offset,
306309 const struct bpf_uprobe_opts *opts);
307310
@@ -314,35 +317,35 @@ struct bpf_tracepoint_opts { · 6 unmodified lines
314317 #define bpf_tracepoint_opts__last_field bpf_cookie
315318
316319 LIBBPF_API struct bpf_link *
317−bpf_program__attach_tracepoint(struct bpf_program *prog,
320+bpf_program__attach_tracepoint(const struct bpf_program *prog,
318321 const char *tp_category,
319322 const char *tp_name);
320323 LIBBPF_API struct bpf_link *
321−bpf_program__attach_tracepoint_opts(struct bpf_program *prog,
324+bpf_program__attach_tracepoint_opts(const struct bpf_program *prog,
322325 const char *tp_category,
323326 const char *tp_name,
324327 const struct bpf_tracepoint_opts *opts);
325328
326329 LIBBPF_API struct bpf_link *
327−bpf_program__attach_raw_tracepoint(struct bpf_program *prog,
330+bpf_program__attach_raw_tracepoint(const struct bpf_program *prog,
328331 const char *tp_name);
329332 LIBBPF_API struct bpf_link *
330−bpf_program__attach_trace(struct bpf_program *prog);
333+bpf_program__attach_trace(const struct bpf_program *prog);
331334 LIBBPF_API struct bpf_link *
332−bpf_program__attach_lsm(struct bpf_program *prog);
335+bpf_program__attach_lsm(const struct bpf_program *prog);
333336 LIBBPF_API struct bpf_link *
334−bpf_program__attach_cgroup(struct bpf_program *prog, int cgroup_fd);
337+bpf_program__attach_cgroup(const struct bpf_program *prog, int cgroup_fd);
335338 LIBBPF_API struct bpf_link *
336−bpf_program__attach_netns(struct bpf_program *prog, int netns_fd);
339+bpf_program__attach_netns(const struct bpf_program *prog, int netns_fd);
337340 LIBBPF_API struct bpf_link *
338−bpf_program__attach_xdp(struct bpf_program *prog, int ifindex);
341+bpf_program__attach_xdp(const struct bpf_program *prog, int ifindex);
339342 LIBBPF_API struct bpf_link *
340−bpf_program__attach_freplace(struct bpf_program *prog,
343+bpf_program__attach_freplace(const struct bpf_program *prog,
341344 int target_fd, const char *attach_func_name);
342345
343346 struct bpf_map;
344347
345−LIBBPF_API struct bpf_link *bpf_map__attach_struct_ops(struct bpf_map *map);
348+LIBBPF_API struct bpf_link *bpf_map__attach_struct_ops(const struct bpf_map *map);
346349
347350 struct bpf_iter_attach_opts {
348351 size_t sz; /* size of this struct for forward/backward compatibility */
@@ -352,7 +355,7 @@ struct bpf_iter_attach_opts { · 3 unmodified lines
352355 #define bpf_iter_attach_opts__last_field link_info_len
353356
354357 LIBBPF_API struct bpf_link *
355−bpf_program__attach_iter(struct bpf_program *prog,
358+bpf_program__attach_iter(const struct bpf_program *prog,
356359 const struct bpf_iter_attach_opts *opts);
357360
358361 struct bpf_insn;
@@ -854,7 +857,7 @@ struct bpf_object_skeleton { · 495 unmodified lines
854857 size_t sz; /* size of this struct, for forward/backward compatibility */
855858
856859 const char *name;
857− void *data;
860+ const void *data;
858861 size_t data_sz;
859862
860863 struct bpf_object **obj;
tools/lib/bpf/libbpf.map+5−0
@@ -386,3 +386,8 @@ LIBBPF_0.5.0 { · 385 unmodified lines
386386 btf_dump__dump_type_data;
387387 libbpf_set_strict_mode;
388388 } LIBBPF_0.4.0;
389+
390+LIBBPF_0.6.0 {
391+ global:
392+ btf__add_tag;
393+} LIBBPF_0.5.0;
tools/lib/bpf/libbpf_common.h+24−0
@@ -10,6 +10,7 @@ · 9 unmodified lines
1010 #define __LIBBPF_LIBBPF_COMMON_H
1111
1212 #include <string.h>
13+#include "libbpf_version.h"
1314
1415 #ifndef LIBBPF_API
1516 #define LIBBPF_API __attribute__((visibility("default")))
@@ -17,6 +18,29 @@ · 1 unmodified line
1718
1819 #define LIBBPF_DEPRECATED(msg) __attribute__((deprecated(msg)))
1920
21+/* Mark a symbol as deprecated when libbpf version is >= {major}.{minor} */
22+#define LIBBPF_DEPRECATED_SINCE(major, minor, msg) \
23+ __LIBBPF_MARK_DEPRECATED_ ## major ## _ ## minor \
24+ (LIBBPF_DEPRECATED("libbpf v" # major "." # minor "+: " msg))
25+
26+#define __LIBBPF_CURRENT_VERSION_GEQ(major, minor) \
27+ (LIBBPF_MAJOR_VERSION > (major) || \
28+ (LIBBPF_MAJOR_VERSION == (major) && LIBBPF_MINOR_VERSION >= (minor)))
29+
30+/* Add checks for other versions below when planning deprecation of API symbols
31+ * with the LIBBPF_DEPRECATED_SINCE macro.
32+ */
33+#if __LIBBPF_CURRENT_VERSION_GEQ(0, 6)
34+#define __LIBBPF_MARK_DEPRECATED_0_6(X) X
35+#else
36+#define __LIBBPF_MARK_DEPRECATED_0_6(X)
37+#endif
38+#if __LIBBPF_CURRENT_VERSION_GEQ(0, 7)
39+#define __LIBBPF_MARK_DEPRECATED_0_7(X) X
40+#else
41+#define __LIBBPF_MARK_DEPRECATED_0_7(X)
42+#endif
43+
2044 /* Helper macro to declare and initialize libbpf options struct
2145 *
2246 * This dance with uninitialized declaration, followed by memset to zero,
tools/lib/bpf/libbpf_internal.h+21−6
@@ -69,6 +69,8 @@ · 68 unmodified lines
6969 #define BTF_VAR_SECINFO_ENC(type, offset, size) (type), (offset), (size)
7070 #define BTF_TYPE_FLOAT_ENC(name, sz) \
7171 BTF_TYPE_ENC(name, BTF_INFO_ENC(BTF_KIND_FLOAT, 0, 0), sz)
72+#define BTF_TYPE_TAG_ENC(value, type, component_idx) \
73+ BTF_TYPE_ENC(value, BTF_INFO_ENC(BTF_KIND_TAG, 0, 0), type), (component_idx)
7274
7375 #ifndef likely
7476 #define likely(x) __builtin_expect(!!(x), 1)
@@ -90,17 +92,30 @@ · 15 unmodified lines
9092 /* Symbol versioning is different between static and shared library.
9193 * Properly versioned symbols are needed for shared library, but
9294 * only the symbol of the new version is needed for static library.
95+ * Starting with GNU C 10, use symver attribute instead of .symver assembler
96+ * directive, which works better with GCC LTO builds.
9397 */
94−#ifdef SHARED
95−# define COMPAT_VERSION(internal_name, api_name, version) \
98+#if defined(SHARED) && defined(__GNUC__) && __GNUC__ >= 10
99+
100+#define DEFAULT_VERSION(internal_name, api_name, version) \
101+ __attribute__((symver(#api_name "@@" #version)))
102+#define COMPAT_VERSION(internal_name, api_name, version) \
103+ __attribute__((symver(#api_name "@" #version)))
104+
105+#elif defined(SHARED)
106+
107+#define COMPAT_VERSION(internal_name, api_name, version) \
96108 asm(".symver " #internal_name "," #api_name "@" #version);
97−# define DEFAULT_VERSION(internal_name, api_name, version) \
109+#define DEFAULT_VERSION(internal_name, api_name, version) \
98110 asm(".symver " #internal_name "," #api_name "@@" #version);
99−#else
100−# define COMPAT_VERSION(internal_name, api_name, version)
101−# define DEFAULT_VERSION(internal_name, api_name, version) \
111+
112+#else /* !SHARED */
113+
114+#define COMPAT_VERSION(internal_name, api_name, version)
115+#define DEFAULT_VERSION(internal_name, api_name, version) \
102116 extern typeof(internal_name) api_name \
103117 __attribute__((alias(#internal_name)));
118+
104119 #endif
105120
106121 extern void libbpf_print(enum libbpf_print_level level,
tools/lib/bpf/libbpf_version.h+9−0
@@ -0,0 +1,9 @@
1+/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
2+/* Copyright (C) 2021 Facebook */
3+#ifndef __LIBBPF_VERSION_H
4+#define __LIBBPF_VERSION_H
5+
6+#define LIBBPF_MAJOR_VERSION 0
7+#define LIBBPF_MINOR_VERSION 6
8+
9+#endif /* __LIBBPF_VERSION_H */
tools/lib/bpf/xsk.c+2−2
@@ -281,6 +281,7 @@ out_mmap: · 280 unmodified lines
281281 return err;
282282 }
283283
284+DEFAULT_VERSION(xsk_umem__create_v0_0_4, xsk_umem__create, LIBBPF_0.0.4)
284285 int xsk_umem__create_v0_0_4(struct xsk_umem **umem_ptr, void *umem_area,
285286 __u64 size, struct xsk_ring_prod *fill,
286287 struct xsk_ring_cons *comp,
@@ -345,6 +346,7 @@ struct xsk_umem_config_v1 { · 58 unmodified lines
345346 __u32 frame_headroom;
346347 };
347348
349+COMPAT_VERSION(xsk_umem__create_v0_0_2, xsk_umem__create, LIBBPF_0.0.2)
348350 int xsk_umem__create_v0_0_2(struct xsk_umem **umem_ptr, void *umem_area,
349351 __u64 size, struct xsk_ring_prod *fill,
350352 struct xsk_ring_cons *comp,
@@ -358,8 +360,6 @@ int xsk_umem__create_v0_0_2(struct xsk_umem **umem_ptr, void *umem_area, · 7 unmodified lines
358360 return xsk_umem__create_v0_0_4(umem_ptr, umem_area, size, fill, comp,
359361 &config);
360362 }
361−COMPAT_VERSION(xsk_umem__create_v0_0_2, xsk_umem__create, LIBBPF_0.0.2)
362−DEFAULT_VERSION(xsk_umem__create_v0_0_4, xsk_umem__create, LIBBPF_0.0.4)
363363
364364 static enum xsk_prog get_xsk_prog(void)
365365 {
tools/testing/selftests/bpf/.gitignore+3−2
@@ -9,8 +9,9 @@ test_tag · 8 unmodified lines
99 FEATURE-DUMP.libbpf
1010 fixdep
1111 test_dev_cgroup
12−/test_progs*
13−!test_progs.h
12+/test_progs
13+/test_progs-no_alu32
14+/test_progs-bpf_gcc
1415 test_verifier_log
1516 feature
1617 test_sock
tools/testing/selftests/bpf/Makefile+2−2
@@ -512,14 +512,14 @@ $(OUTPUT)/test_cpp: test_cpp.cpp $(OUTPUT)/test_core_extern.skel.h $(BPFOBJ) · 511 unmodified lines
512512 $(Q)$(CXX) $(CFLAGS) $(filter %.a %.o %.cpp,$^) $(LDLIBS) -o $@
513513
514514 # Benchmark runner
515−$(OUTPUT)/bench_%.o: benchs/bench_%.c bench.h
515+$(OUTPUT)/bench_%.o: benchs/bench_%.c bench.h $(BPFOBJ)
516516 $(call msg,CC,,$@)
517517 $(Q)$(CC) $(CFLAGS) -c $(filter %.c,$^) $(LDLIBS) -o $@
518518 $(OUTPUT)/bench_rename.o: $(OUTPUT)/test_overhead.skel.h
519519 $(OUTPUT)/bench_trigger.o: $(OUTPUT)/trigger_bench.skel.h
520520 $(OUTPUT)/bench_ringbufs.o: $(OUTPUT)/ringbuf_bench.skel.h \
521521 $(OUTPUT)/perfbuf_bench.skel.h
522−$(OUTPUT)/bench.o: bench.h testing_helpers.h
522+$(OUTPUT)/bench.o: bench.h testing_helpers.h $(BPFOBJ)
523523 $(OUTPUT)/bench: LDLIBS += -lm
524524 $(OUTPUT)/bench: $(OUTPUT)/bench.o $(OUTPUT)/testing_helpers.o \
525525 $(OUTPUT)/bench_count.o \
tools/testing/selftests/bpf/README.rst+14−0
@@ -201,6 +201,20 @@ Without it, the error from compiling bpf selftests looks like: · 200 unmodified lines
201201
202202 __ https://reviews.llvm.org/D93563
203203
204+btf_tag test and Clang version
205+==============================
206+
207+The btf_tag selftest require LLVM support to recognize the btf_tag attribute.
208+It was introduced in `Clang 14`__.
209+
210+Without it, the btf_tag selftest will be skipped and you will observe:
211+
212+.. code-block:: console
213+
214+ #<test_num> btf_tag:SKIP
215+
216+__ https://reviews.llvm.org/D106614
217+
204218 Clang dependencies for static linking tests
205219 ===========================================
206220
tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c+17−2
@@ -13,6 +13,18 @@ · 12 unmodified lines
1313
1414 DEFINE_PER_CPU(int, bpf_testmod_ksym_percpu) = 123;
1515
16+noinline int bpf_testmod_loop_test(int n)
17+{
18+ int i, sum = 0;
19+
20+ /* the primary goal of this test is to test LBR. Create a lot of
21+ * branches in the function, so we can catch it easily.
22+ */
23+ for (i = 0; i < n; i++)
24+ sum += i;
25+ return sum;
26+}
27+
1628 noinline ssize_t
1729 bpf_testmod_test_read(struct file *file, struct kobject *kobj,
1830 struct bin_attribute *bin_attr,
@@ -24,7 +36,11 @@ bpf_testmod_test_read(struct file *file, struct kobject *kobj, · 5 unmodified lines
2436 .len = len,
2537 };
2638
27− trace_bpf_testmod_test_read(current, &ctx);
39+ /* This is always true. Use the check to make sure the compiler
40+ * doesn't remove bpf_testmod_loop_test.
41+ */
42+ if (bpf_testmod_loop_test(101) > 100)
43+ trace_bpf_testmod_test_read(current, &ctx);
2844
2945 return -EIO; /* always fail */
3046 }
@@ -71,4 +87,3 @@ module_exit(bpf_testmod_exit); · 40 unmodified lines
7187 MODULE_AUTHOR("Andrii Nakryiko");
7288 MODULE_DESCRIPTION("BPF selftests module");
7389 MODULE_LICENSE("Dual BSD/GPL");
74−
tools/testing/selftests/bpf/btf_helpers.c+6−1
@@ -24,11 +24,12 @@ static const char * const btf_kind_str_mapping[] = { · 23 unmodified lines
2424 [BTF_KIND_VAR] = "VAR",
2525 [BTF_KIND_DATASEC] = "DATASEC",
2626 [BTF_KIND_FLOAT] = "FLOAT",
27+ [BTF_KIND_TAG] = "TAG",
2728 };
2829
2930 static const char *btf_kind_str(__u16 kind)
3031 {
31− if (kind > BTF_KIND_DATASEC)
32+ if (kind > BTF_KIND_TAG)
3233 return "UNKNOWN";
3334 return btf_kind_str_mapping[kind];
3435 }
@@ -177,6 +178,10 @@ int fprintf_btf_type_raw(FILE *out, const struct btf *btf, __u32 id) · 142 unmodified lines
177178 case BTF_KIND_FLOAT:
178179 fprintf(out, " size=%u", t->size);
179180 break;
181+ case BTF_KIND_TAG:
182+ fprintf(out, " type_id=%u component_idx=%d",
183+ t->type, btf_tag(t)->component_idx);
184+ break;
180185 default:
181186 break;
182187 }
tools/testing/selftests/bpf/prog_tests/bpf_iter.c+2−4
@@ -589,7 +589,7 @@ out: · 588 unmodified lines
589589
590590 static void test_bpf_hash_map(void)
591591 {
592− __u32 expected_key_a = 0, expected_key_b = 0, expected_key_c = 0;
592+ __u32 expected_key_a = 0, expected_key_b = 0;
593593 DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
594594 struct bpf_iter_bpf_hash_map *skel;
595595 int err, i, len, map_fd, iter_fd;
@@ -638,7 +638,6 @@ static void test_bpf_hash_map(void) · 42 unmodified lines
638638 val = i + 4;
639639 expected_key_a += key.a;
640640 expected_key_b += key.b;
641− expected_key_c += key.c;
642641 expected_val += val;
643642
644643 err = bpf_map_update_elem(map_fd, &key, &val, BPF_ANY);
@@ -685,7 +684,7 @@ out: · 40 unmodified lines
685684
686685 static void test_bpf_percpu_hash_map(void)
687686 {
688− __u32 expected_key_a = 0, expected_key_b = 0, expected_key_c = 0;
687+ __u32 expected_key_a = 0, expected_key_b = 0;
689688 DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
690689 struct bpf_iter_bpf_percpu_hash_map *skel;
691690 int err, i, j, len, map_fd, iter_fd;
@@ -722,7 +721,6 @@ static void test_bpf_percpu_hash_map(void) · 30 unmodified lines
722721 key.c = i + 3;
723722 expected_key_a += key.a;
724723 expected_key_b += key.b;
725− expected_key_c += key.c;
726724
727725 for (j = 0; j < bpf_num_possible_cpus(); j++) {
728726 *(__u32 *)(val + j * 8) = i + j;
tools/testing/selftests/bpf/prog_tests/btf.c+422−19
@@ -39,8 +39,8 @@ static bool always_log; · 38 unmodified lines
3939 #define BTF_END_RAW 0xdeadbeef
4040 #define NAME_TBD 0xdeadb33f
4141
42−#define NAME_NTH(N) (0xffff0000 | N)
43−#define IS_NAME_NTH(X) ((X & 0xffff0000) == 0xffff0000)
42+#define NAME_NTH(N) (0xfffe0000 | N)
43+#define IS_NAME_NTH(X) ((X & 0xffff0000) == 0xfffe0000)
4444 #define GET_NAME_NTH_IDX(X) (X & 0x0000ffff)
4545
4646 #define MAX_NR_RAW_U32 1024
@@ -3661,6 +3661,249 @@ static struct btf_raw_test raw_tests[] = { · 3614 unmodified lines
36613661 .err_str = "Invalid type_size",
36623662 },
36633663
3664+{
3665+ .descr = "tag test #1, struct/member, well-formed",
3666+ .raw_types = {
3667+ BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
3668+ BTF_STRUCT_ENC(0, 2, 8), /* [2] */
3669+ BTF_MEMBER_ENC(NAME_TBD, 1, 0),
3670+ BTF_MEMBER_ENC(NAME_TBD, 1, 32),
3671+ BTF_TAG_ENC(NAME_TBD, 2, -1),
3672+ BTF_TAG_ENC(NAME_TBD, 2, 0),
3673+ BTF_TAG_ENC(NAME_TBD, 2, 1),
3674+ BTF_END_RAW,
3675+ },
3676+ BTF_STR_SEC("\0m1\0m2\0tag1\0tag2\0tag3"),
3677+ .map_type = BPF_MAP_TYPE_ARRAY,
3678+ .map_name = "tag_type_check_btf",
3679+ .key_size = sizeof(int),
3680+ .value_size = 8,
3681+ .key_type_id = 1,
3682+ .value_type_id = 2,
3683+ .max_entries = 1,
3684+},
3685+{
3686+ .descr = "tag test #2, union/member, well-formed",
3687+ .raw_types = {
3688+ BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
3689+ BTF_UNION_ENC(NAME_TBD, 2, 4), /* [2] */
3690+ BTF_MEMBER_ENC(NAME_TBD, 1, 0),
3691+ BTF_MEMBER_ENC(NAME_TBD, 1, 0),
3692+ BTF_TAG_ENC(NAME_TBD, 2, -1),
3693+ BTF_TAG_ENC(NAME_TBD, 2, 0),
3694+ BTF_TAG_ENC(NAME_TBD, 2, 1),
3695+ BTF_END_RAW,
3696+ },
3697+ BTF_STR_SEC("\0t\0m1\0m2\0tag1\0tag2\0tag3"),
3698+ .map_type = BPF_MAP_TYPE_ARRAY,
3699+ .map_name = "tag_type_check_btf",
3700+ .key_size = sizeof(int),
3701+ .value_size = 4,
3702+ .key_type_id = 1,
3703+ .value_type_id = 2,
3704+ .max_entries = 1,
3705+},
3706+{
3707+ .descr = "tag test #3, variable, well-formed",
3708+ .raw_types = {
3709+ BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
3710+ BTF_VAR_ENC(NAME_TBD, 1, 0), /* [2] */
3711+ BTF_VAR_ENC(NAME_TBD, 1, 1), /* [3] */
3712+ BTF_TAG_ENC(NAME_TBD, 2, -1),
3713+ BTF_TAG_ENC(NAME_TBD, 3, -1),
3714+ BTF_END_RAW,
3715+ },
3716+ BTF_STR_SEC("\0local\0global\0tag1\0tag2"),
3717+ .map_type = BPF_MAP_TYPE_ARRAY,
3718+ .map_name = "tag_type_check_btf",
3719+ .key_size = sizeof(int),
3720+ .value_size = 4,
3721+ .key_type_id = 1,
3722+ .value_type_id = 1,
3723+ .max_entries = 1,
3724+},
3725+{
3726+ .descr = "tag test #4, func/parameter, well-formed",
3727+ .raw_types = {
3728+ BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
3729+ BTF_FUNC_PROTO_ENC(0, 2), /* [2] */
3730+ BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 1),
3731+ BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 1),
3732+ BTF_FUNC_ENC(NAME_TBD, 2), /* [3] */
3733+ BTF_TAG_ENC(NAME_TBD, 3, -1),
3734+ BTF_TAG_ENC(NAME_TBD, 3, 0),
3735+ BTF_TAG_ENC(NAME_TBD, 3, 1),
3736+ BTF_END_RAW,
3737+ },
3738+ BTF_STR_SEC("\0arg1\0arg2\0f\0tag1\0tag2\0tag3"),
3739+ .map_type = BPF_MAP_TYPE_ARRAY,
3740+ .map_name = "tag_type_check_btf",
3741+ .key_size = sizeof(int),
3742+ .value_size = 4,
3743+ .key_type_id = 1,
3744+ .value_type_id = 1,
3745+ .max_entries = 1,
3746+},
3747+{
3748+ .descr = "tag test #5, invalid value",
3749+ .raw_types = {
3750+ BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
3751+ BTF_VAR_ENC(NAME_TBD, 1, 0), /* [2] */
3752+ BTF_TAG_ENC(0, 2, -1),
3753+ BTF_END_RAW,
3754+ },
3755+ BTF_STR_SEC("\0local\0tag"),
3756+ .map_type = BPF_MAP_TYPE_ARRAY,
3757+ .map_name = "tag_type_check_btf",
3758+ .key_size = sizeof(int),
3759+ .value_size = 4,
3760+ .key_type_id = 1,
3761+ .value_type_id = 1,
3762+ .max_entries = 1,
3763+ .btf_load_err = true,
3764+ .err_str = "Invalid value",
3765+},
3766+{
3767+ .descr = "tag test #6, invalid target type",
3768+ .raw_types = {
3769+ BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
3770+ BTF_TAG_ENC(NAME_TBD, 1, -1),
3771+ BTF_END_RAW,
3772+ },
3773+ BTF_STR_SEC("\0tag1"),
3774+ .map_type = BPF_MAP_TYPE_ARRAY,
3775+ .map_name = "tag_type_check_btf",
3776+ .key_size = sizeof(int),
3777+ .value_size = 4,
3778+ .key_type_id = 1,
3779+ .value_type_id = 1,
3780+ .max_entries = 1,
3781+ .btf_load_err = true,
3782+ .err_str = "Invalid type",
3783+},
3784+{
3785+ .descr = "tag test #7, invalid vlen",
3786+ .raw_types = {
3787+ BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
3788+ BTF_VAR_ENC(NAME_TBD, 1, 0), /* [2] */
3789+ BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_TAG, 0, 1), 2), (0),
3790+ BTF_END_RAW,
3791+ },
3792+ BTF_STR_SEC("\0local\0tag1"),
3793+ .map_type = BPF_MAP_TYPE_ARRAY,
3794+ .map_name = "tag_type_check_btf",
3795+ .key_size = sizeof(int),
3796+ .value_size = 4,
3797+ .key_type_id = 1,
3798+ .value_type_id = 1,
3799+ .max_entries = 1,
3800+ .btf_load_err = true,
3801+ .err_str = "vlen != 0",
3802+},
3803+{
3804+ .descr = "tag test #8, invalid kflag",
3805+ .raw_types = {
3806+ BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
3807+ BTF_VAR_ENC(NAME_TBD, 1, 0), /* [2] */
3808+ BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_TAG, 1, 0), 2), (-1),
3809+ BTF_END_RAW,
3810+ },
3811+ BTF_STR_SEC("\0local\0tag1"),
3812+ .map_type = BPF_MAP_TYPE_ARRAY,
3813+ .map_name = "tag_type_check_btf",
3814+ .key_size = sizeof(int),
3815+ .value_size = 4,
3816+ .key_type_id = 1,
3817+ .value_type_id = 1,
3818+ .max_entries = 1,
3819+ .btf_load_err = true,
3820+ .err_str = "Invalid btf_info kind_flag",
3821+},
3822+{
3823+ .descr = "tag test #9, var, invalid component_idx",
3824+ .raw_types = {
3825+ BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
3826+ BTF_VAR_ENC(NAME_TBD, 1, 0), /* [2] */
3827+ BTF_TAG_ENC(NAME_TBD, 2, 0),
3828+ BTF_END_RAW,
3829+ },
3830+ BTF_STR_SEC("\0local\0tag"),
3831+ .map_type = BPF_MAP_TYPE_ARRAY,
3832+ .map_name = "tag_type_check_btf",
3833+ .key_size = sizeof(int),
3834+ .value_size = 4,
3835+ .key_type_id = 1,
3836+ .value_type_id = 1,
3837+ .max_entries = 1,
3838+ .btf_load_err = true,
3839+ .err_str = "Invalid component_idx",
3840+},
3841+{
3842+ .descr = "tag test #10, struct member, invalid component_idx",
3843+ .raw_types = {
3844+ BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
3845+ BTF_STRUCT_ENC(0, 2, 8), /* [2] */
3846+ BTF_MEMBER_ENC(NAME_TBD, 1, 0),
3847+ BTF_MEMBER_ENC(NAME_TBD, 1, 32),
3848+ BTF_TAG_ENC(NAME_TBD, 2, 2),
3849+ BTF_END_RAW,
3850+ },
3851+ BTF_STR_SEC("\0m1\0m2\0tag"),
3852+ .map_type = BPF_MAP_TYPE_ARRAY,
3853+ .map_name = "tag_type_check_btf",
3854+ .key_size = sizeof(int),
3855+ .value_size = 8,
3856+ .key_type_id = 1,
3857+ .value_type_id = 2,
3858+ .max_entries = 1,
3859+ .btf_load_err = true,
3860+ .err_str = "Invalid component_idx",
3861+},
3862+{
3863+ .descr = "tag test #11, func parameter, invalid component_idx",
3864+ .raw_types = {
3865+ BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
3866+ BTF_FUNC_PROTO_ENC(0, 2), /* [2] */
3867+ BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 1),
3868+ BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 1),
3869+ BTF_FUNC_ENC(NAME_TBD, 2), /* [3] */
3870+ BTF_TAG_ENC(NAME_TBD, 3, 2),
3871+ BTF_END_RAW,
3872+ },
3873+ BTF_STR_SEC("\0arg1\0arg2\0f\0tag"),
3874+ .map_type = BPF_MAP_TYPE_ARRAY,
3875+ .map_name = "tag_type_check_btf",
3876+ .key_size = sizeof(int),
3877+ .value_size = 4,
3878+ .key_type_id = 1,
3879+ .value_type_id = 1,
3880+ .max_entries = 1,
3881+ .btf_load_err = true,
3882+ .err_str = "Invalid component_idx",
3883+},
3884+{
3885+ .descr = "tag test #12, < -1 component_idx",
3886+ .raw_types = {
3887+ BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
3888+ BTF_FUNC_PROTO_ENC(0, 2), /* [2] */
3889+ BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 1),
3890+ BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 1),
3891+ BTF_FUNC_ENC(NAME_TBD, 2), /* [3] */
3892+ BTF_TAG_ENC(NAME_TBD, 3, -2),
3893+ BTF_END_RAW,
3894+ },
3895+ BTF_STR_SEC("\0arg1\0arg2\0f\0tag"),
3896+ .map_type = BPF_MAP_TYPE_ARRAY,
3897+ .map_name = "tag_type_check_btf",
3898+ .key_size = sizeof(int),
3899+ .value_size = 4,
3900+ .key_type_id = 1,
3901+ .value_type_id = 1,
3902+ .max_entries = 1,
3903+ .btf_load_err = true,
3904+ .err_str = "Invalid component_idx",
3905+},
3906+
36643907 }; /* struct btf_raw_test raw_tests[] */
36653908
36663909 static const char *get_next_str(const char *start, const char *end)
@@ -6421,27 +6664,33 @@ const struct btf_dedup_test dedup_tests[] = { · 2754 unmodified lines
64216664 BTF_MEMBER_ENC(NAME_NTH(4), 5, 64), /* const int *a; */
64226665 BTF_MEMBER_ENC(NAME_NTH(5), 2, 128), /* int b[16]; */
64236666 BTF_MEMBER_ENC(NAME_NTH(6), 1, 640), /* int c; */
6424− BTF_MEMBER_ENC(NAME_NTH(8), 13, 672), /* float d; */
6667+ BTF_MEMBER_ENC(NAME_NTH(8), 15, 672), /* float d; */
64256668 /* ptr -> [3] struct s */
64266669 BTF_PTR_ENC(3), /* [4] */
64276670 /* ptr -> [6] const int */
64286671 BTF_PTR_ENC(6), /* [5] */
64296672 /* const -> [1] int */
64306673 BTF_CONST_ENC(1), /* [6] */
6674+ /* tag -> [3] struct s */
6675+ BTF_TAG_ENC(NAME_NTH(2), 3, -1), /* [7] */
6676+ /* tag -> [3] struct s, member 1 */
6677+ BTF_TAG_ENC(NAME_NTH(2), 3, 1), /* [8] */
64316678
64326679 /* full copy of the above */
6433− BTF_TYPE_INT_ENC(NAME_NTH(1), BTF_INT_SIGNED, 0, 32, 4), /* [7] */
6434− BTF_TYPE_ARRAY_ENC(7, 7, 16), /* [8] */
6435− BTF_STRUCT_ENC(NAME_NTH(2), 5, 88), /* [9] */
6436− BTF_MEMBER_ENC(NAME_NTH(3), 10, 0),
6437− BTF_MEMBER_ENC(NAME_NTH(4), 11, 64),
6438− BTF_MEMBER_ENC(NAME_NTH(5), 8, 128),
6439− BTF_MEMBER_ENC(NAME_NTH(6), 7, 640),
6440− BTF_MEMBER_ENC(NAME_NTH(8), 13, 672),
6441− BTF_PTR_ENC(9), /* [10] */
6442− BTF_PTR_ENC(12), /* [11] */
6443− BTF_CONST_ENC(7), /* [12] */
6444− BTF_TYPE_FLOAT_ENC(NAME_NTH(7), 4), /* [13] */
6680+ BTF_TYPE_INT_ENC(NAME_NTH(1), BTF_INT_SIGNED, 0, 32, 4), /* [9] */
6681+ BTF_TYPE_ARRAY_ENC(9, 9, 16), /* [10] */
6682+ BTF_STRUCT_ENC(NAME_NTH(2), 5, 88), /* [11] */
6683+ BTF_MEMBER_ENC(NAME_NTH(3), 12, 0),
6684+ BTF_MEMBER_ENC(NAME_NTH(4), 13, 64),
6685+ BTF_MEMBER_ENC(NAME_NTH(5), 10, 128),
6686+ BTF_MEMBER_ENC(NAME_NTH(6), 9, 640),
6687+ BTF_MEMBER_ENC(NAME_NTH(8), 15, 672),
6688+ BTF_PTR_ENC(11), /* [12] */
6689+ BTF_PTR_ENC(14), /* [13] */
6690+ BTF_CONST_ENC(9), /* [14] */
6691+ BTF_TYPE_FLOAT_ENC(NAME_NTH(7), 4), /* [15] */
6692+ BTF_TAG_ENC(NAME_NTH(2), 11, -1), /* [16] */
6693+ BTF_TAG_ENC(NAME_NTH(2), 11, 1), /* [17] */
64456694 BTF_END_RAW,
64466695 },
64476696 BTF_STR_SEC("\0int\0s\0next\0a\0b\0c\0float\0d"),
@@ -6458,14 +6707,16 @@ const struct btf_dedup_test dedup_tests[] = { · 10 unmodified lines
64586707 BTF_MEMBER_ENC(NAME_NTH(1), 5, 64), /* const int *a; */
64596708 BTF_MEMBER_ENC(NAME_NTH(2), 2, 128), /* int b[16]; */
64606709 BTF_MEMBER_ENC(NAME_NTH(3), 1, 640), /* int c; */
6461− BTF_MEMBER_ENC(NAME_NTH(4), 7, 672), /* float d; */
6710+ BTF_MEMBER_ENC(NAME_NTH(4), 9, 672), /* float d; */
64626711 /* ptr -> [3] struct s */
64636712 BTF_PTR_ENC(3), /* [4] */
64646713 /* ptr -> [6] const int */
64656714 BTF_PTR_ENC(6), /* [5] */
64666715 /* const -> [1] int */
64676716 BTF_CONST_ENC(1), /* [6] */
6468− BTF_TYPE_FLOAT_ENC(NAME_NTH(7), 4), /* [7] */
6717+ BTF_TAG_ENC(NAME_NTH(2), 3, -1), /* [7] */
6718+ BTF_TAG_ENC(NAME_NTH(2), 3, 1), /* [8] */
6719+ BTF_TYPE_FLOAT_ENC(NAME_NTH(7), 4), /* [9] */
64696720 BTF_END_RAW,
64706721 },
64716722 BTF_STR_SEC("\0a\0b\0c\0d\0int\0float\0next\0s"),
@@ -6590,9 +6841,11 @@ const struct btf_dedup_test dedup_tests[] = { · 118 unmodified lines
65906841 BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 8),
65916842 BTF_FUNC_ENC(NAME_TBD, 12), /* [13] func */
65926843 BTF_TYPE_FLOAT_ENC(NAME_TBD, 2), /* [14] float */
6844+ BTF_TAG_ENC(NAME_TBD, 13, -1), /* [15] tag */
6845+ BTF_TAG_ENC(NAME_TBD, 13, 1), /* [16] tag */
65936846 BTF_END_RAW,
65946847 },
6595− BTF_STR_SEC("\0A\0B\0C\0D\0E\0F\0G\0H\0I\0J\0K\0L\0M\0N"),
6848+ BTF_STR_SEC("\0A\0B\0C\0D\0E\0F\0G\0H\0I\0J\0K\0L\0M\0N\0O\0P"),
65966849 },
65976850 .expect = {
65986851 .raw_types = {
@@ -6616,9 +6869,11 @@ const struct btf_dedup_test dedup_tests[] = { · 17 unmodified lines
66166869 BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 8),
66176870 BTF_FUNC_ENC(NAME_TBD, 12), /* [13] func */
66186871 BTF_TYPE_FLOAT_ENC(NAME_TBD, 2), /* [14] float */
6872+ BTF_TAG_ENC(NAME_TBD, 13, -1), /* [15] tag */
6873+ BTF_TAG_ENC(NAME_TBD, 13, 1), /* [16] tag */
66196874 BTF_END_RAW,
66206875 },
6621− BTF_STR_SEC("\0A\0B\0C\0D\0E\0F\0G\0H\0I\0J\0K\0L\0M\0N"),
6876+ BTF_STR_SEC("\0A\0B\0C\0D\0E\0F\0G\0H\0I\0J\0K\0L\0M\0N\0O\0P"),
66226877 },
66236878 .opts = {
66246879 .dont_resolve_fwds = false,
@@ -6767,6 +7022,152 @@ const struct btf_dedup_test dedup_tests[] = { · 142 unmodified lines
67677022 .dedup_table_size = 1
67687023 },
67697024 },
7025+{
7026+ .descr = "dedup: func/func_arg/var tags",
7027+ .input = {
7028+ .raw_types = {
7029+ /* int */
7030+ BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
7031+ /* static int t */
7032+ BTF_VAR_ENC(NAME_NTH(1), 1, 0), /* [2] */
7033+ /* void f(int a1, int a2) */
7034+ BTF_FUNC_PROTO_ENC(0, 2), /* [3] */
7035+ BTF_FUNC_PROTO_ARG_ENC(NAME_NTH(2), 1),
7036+ BTF_FUNC_PROTO_ARG_ENC(NAME_NTH(3), 1),
7037+ BTF_FUNC_ENC(NAME_NTH(4), 2), /* [4] */
7038+ /* tag -> t */
7039+ BTF_TAG_ENC(NAME_NTH(5), 2, -1), /* [5] */
7040+ BTF_TAG_ENC(NAME_NTH(5), 2, -1), /* [6] */
7041+ /* tag -> func */
7042+ BTF_TAG_ENC(NAME_NTH(5), 4, -1), /* [7] */
7043+ BTF_TAG_ENC(NAME_NTH(5), 4, -1), /* [8] */
7044+ /* tag -> func arg a1 */
7045+ BTF_TAG_ENC(NAME_NTH(5), 4, 1), /* [9] */
7046+ BTF_TAG_ENC(NAME_NTH(5), 4, 1), /* [10] */
7047+ BTF_END_RAW,
7048+ },
7049+ BTF_STR_SEC("\0t\0a1\0a2\0f\0tag"),
7050+ },
7051+ .expect = {
7052+ .raw_types = {
7053+ BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
7054+ BTF_VAR_ENC(NAME_NTH(1), 1, 0), /* [2] */
7055+ BTF_FUNC_PROTO_ENC(0, 2), /* [3] */
7056+ BTF_FUNC_PROTO_ARG_ENC(NAME_NTH(2), 1),
7057+ BTF_FUNC_PROTO_ARG_ENC(NAME_NTH(3), 1),
7058+ BTF_FUNC_ENC(NAME_NTH(4), 2), /* [4] */
7059+ BTF_TAG_ENC(NAME_NTH(5), 2, -1), /* [5] */
7060+ BTF_TAG_ENC(NAME_NTH(5), 4, -1), /* [6] */
7061+ BTF_TAG_ENC(NAME_NTH(5), 4, 1), /* [7] */
7062+ BTF_END_RAW,
7063+ },
7064+ BTF_STR_SEC("\0t\0a1\0a2\0f\0tag"),
7065+ },
7066+ .opts = {
7067+ .dont_resolve_fwds = false,
7068+ },
7069+},
7070+{
7071+ .descr = "dedup: func/func_param tags",
7072+ .input = {
7073+ .raw_types = {
7074+ /* int */
7075+ BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
7076+ /* void f(int a1, int a2) */
7077+ BTF_FUNC_PROTO_ENC(0, 2), /* [2] */
7078+ BTF_FUNC_PROTO_ARG_ENC(NAME_NTH(1), 1),
7079+ BTF_FUNC_PROTO_ARG_ENC(NAME_NTH(2), 1),
7080+ BTF_FUNC_ENC(NAME_NTH(3), 2), /* [3] */
7081+ /* void f(int a1, int a2) */
7082+ BTF_FUNC_PROTO_ENC(0, 2), /* [4] */
7083+ BTF_FUNC_PROTO_ARG_ENC(NAME_NTH(1), 1),
7084+ BTF_FUNC_PROTO_ARG_ENC(NAME_NTH(2), 1),
7085+ BTF_FUNC_ENC(NAME_NTH(3), 4), /* [5] */
7086+ /* tag -> f: tag1, tag2 */
7087+ BTF_TAG_ENC(NAME_NTH(4), 3, -1), /* [6] */
7088+ BTF_TAG_ENC(NAME_NTH(5), 3, -1), /* [7] */
7089+ /* tag -> f/a2: tag1, tag2 */
7090+ BTF_TAG_ENC(NAME_NTH(4), 3, 1), /* [8] */
7091+ BTF_TAG_ENC(NAME_NTH(5), 3, 1), /* [9] */
7092+ /* tag -> f: tag1, tag3 */
7093+ BTF_TAG_ENC(NAME_NTH(4), 5, -1), /* [10] */
7094+ BTF_TAG_ENC(NAME_NTH(6), 5, -1), /* [11] */
7095+ /* tag -> f/a2: tag1, tag3 */
7096+ BTF_TAG_ENC(NAME_NTH(4), 5, 1), /* [12] */
7097+ BTF_TAG_ENC(NAME_NTH(6), 5, 1), /* [13] */
7098+ BTF_END_RAW,
7099+ },
7100+ BTF_STR_SEC("\0a1\0a2\0f\0tag1\0tag2\0tag3"),
7101+ },
7102+ .expect = {
7103+ .raw_types = {
7104+ BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
7105+ BTF_FUNC_PROTO_ENC(0, 2), /* [2] */
7106+ BTF_FUNC_PROTO_ARG_ENC(NAME_NTH(1), 1),
7107+ BTF_FUNC_PROTO_ARG_ENC(NAME_NTH(2), 1),
7108+ BTF_FUNC_ENC(NAME_NTH(3), 2), /* [3] */
7109+ BTF_TAG_ENC(NAME_NTH(4), 3, -1), /* [4] */
7110+ BTF_TAG_ENC(NAME_NTH(5), 3, -1), /* [5] */
7111+ BTF_TAG_ENC(NAME_NTH(6), 3, -1), /* [6] */
7112+ BTF_TAG_ENC(NAME_NTH(4), 3, 1), /* [7] */
7113+ BTF_TAG_ENC(NAME_NTH(5), 3, 1), /* [8] */
7114+ BTF_TAG_ENC(NAME_NTH(6), 3, 1), /* [9] */
7115+ BTF_END_RAW,
7116+ },
7117+ BTF_STR_SEC("\0a1\0a2\0f\0tag1\0tag2\0tag3"),
7118+ },
7119+ .opts = {
7120+ .dont_resolve_fwds = false,
7121+ },
7122+},
7123+{
7124+ .descr = "dedup: struct/struct_member tags",
7125+ .input = {
7126+ .raw_types = {
7127+ /* int */
7128+ BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
7129+ BTF_STRUCT_ENC(NAME_NTH(1), 2, 8), /* [2] */
7130+ BTF_MEMBER_ENC(NAME_NTH(2), 1, 0),
7131+ BTF_MEMBER_ENC(NAME_NTH(3), 1, 32),
7132+ BTF_STRUCT_ENC(NAME_NTH(1), 2, 8), /* [3] */
7133+ BTF_MEMBER_ENC(NAME_NTH(2), 1, 0),
7134+ BTF_MEMBER_ENC(NAME_NTH(3), 1, 32),
7135+ /* tag -> t: tag1, tag2 */
7136+ BTF_TAG_ENC(NAME_NTH(4), 2, -1), /* [4] */
7137+ BTF_TAG_ENC(NAME_NTH(5), 2, -1), /* [5] */
7138+ /* tag -> t/m2: tag1, tag2 */
7139+ BTF_TAG_ENC(NAME_NTH(4), 2, 1), /* [6] */
7140+ BTF_TAG_ENC(NAME_NTH(5), 2, 1), /* [7] */
7141+ /* tag -> t: tag1, tag3 */
7142+ BTF_TAG_ENC(NAME_NTH(4), 3, -1), /* [8] */
7143+ BTF_TAG_ENC(NAME_NTH(6), 3, -1), /* [9] */
7144+ /* tag -> t/m2: tag1, tag3 */
7145+ BTF_TAG_ENC(NAME_NTH(4), 3, 1), /* [10] */
7146+ BTF_TAG_ENC(NAME_NTH(6), 3, 1), /* [11] */
7147+ BTF_END_RAW,
7148+ },
7149+ BTF_STR_SEC("\0t\0m1\0m2\0tag1\0tag2\0tag3"),
7150+ },
7151+ .expect = {
7152+ .raw_types = {
7153+ BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
7154+ BTF_STRUCT_ENC(NAME_NTH(1), 2, 8), /* [2] */
7155+ BTF_MEMBER_ENC(NAME_NTH(2), 1, 0),
7156+ BTF_MEMBER_ENC(NAME_NTH(3), 1, 32),
7157+ BTF_TAG_ENC(NAME_NTH(4), 2, -1), /* [3] */
7158+ BTF_TAG_ENC(NAME_NTH(5), 2, -1), /* [4] */
7159+ BTF_TAG_ENC(NAME_NTH(6), 2, -1), /* [5] */
7160+ BTF_TAG_ENC(NAME_NTH(4), 2, 1), /* [6] */
7161+ BTF_TAG_ENC(NAME_NTH(5), 2, 1), /* [7] */
7162+ BTF_TAG_ENC(NAME_NTH(6), 2, 1), /* [8] */
7163+ BTF_END_RAW,
7164+ },
7165+ BTF_STR_SEC("\0t\0m1\0m2\0tag1\0tag2\0tag3"),
7166+ },
7167+ .opts = {
7168+ .dont_resolve_fwds = false,
7169+ },
7170+},
67707171
67717172 };
67727173
@@ -6801,6 +7202,8 @@ static int btf_type_size(const struct btf_type *t) · 28 unmodified lines
68017202 return base_size + sizeof(struct btf_var);
68027203 case BTF_KIND_DATASEC:
68037204 return base_size + vlen * sizeof(struct btf_var_secinfo);
7205+ case BTF_KIND_TAG:
7206+ return base_size + sizeof(struct btf_tag);
68047207 default:
68057208 fprintf(stderr, "Unsupported BTF_KIND:%u\n", kind);
68067209 return -EINVAL;
tools/testing/selftests/bpf/prog_tests/btf_tag.c+20−0
@@ -0,0 +1,20 @@
1+// SPDX-License-Identifier: GPL-2.0
2+/* Copyright (c) 2021 Facebook */
3+#include <test_progs.h>
4+#include "tag.skel.h"
5+
6+void test_btf_tag(void)
7+{
8+ struct tag *skel;
9+
10+ skel = tag__open_and_load();
11+ if (!ASSERT_OK_PTR(skel, "btf_tag"))
12+ return;
13+
14+ if (skel->rodata->skip_tests) {
15+ printf("%s:SKIP: btf_tag attribute not supported", __func__);
16+ test__skip();
17+ }
18+
19+ tag__destroy(skel);
20+}
tools/testing/selftests/bpf/prog_tests/btf_write.c+21−0
@@ -281,5 +281,26 @@ void test_btf_write() { · 280 unmodified lines
281281 "[17] DATASEC 'datasec1' size=12 vlen=1\n"
282282 "\ttype_id=1 offset=4 size=8", "raw_dump");
283283
284+ /* TAG */
285+ id = btf__add_tag(btf, "tag1", 16, -1);
286+ ASSERT_EQ(id, 18, "tag_id");
287+ t = btf__type_by_id(btf, 18);
288+ ASSERT_STREQ(btf__str_by_offset(btf, t->name_off), "tag1", "tag_value");
289+ ASSERT_EQ(btf_kind(t), BTF_KIND_TAG, "tag_kind");
290+ ASSERT_EQ(t->type, 16, "tag_type");
291+ ASSERT_EQ(btf_tag(t)->component_idx, -1, "tag_component_idx");
292+ ASSERT_STREQ(btf_type_raw_dump(btf, 18),
293+ "[18] TAG 'tag1' type_id=16 component_idx=-1", "raw_dump");
294+
295+ id = btf__add_tag(btf, "tag2", 14, 1);
296+ ASSERT_EQ(id, 19, "tag_id");
297+ t = btf__type_by_id(btf, 19);
298+ ASSERT_STREQ(btf__str_by_offset(btf, t->name_off), "tag2", "tag_value");
299+ ASSERT_EQ(btf_kind(t), BTF_KIND_TAG, "tag_kind");
300+ ASSERT_EQ(t->type, 14, "tag_type");
301+ ASSERT_EQ(btf_tag(t)->component_idx, 1, "tag_component_idx");
302+ ASSERT_STREQ(btf_type_raw_dump(btf, 19),
303+ "[19] TAG 'tag2' type_id=14 component_idx=1", "raw_dump");
304+
284305 btf__free(btf);
285306 }
tools/testing/selftests/bpf/prog_tests/core_reloc.c+4−13
@@ -30,7 +30,7 @@ static int duration = 0; · 29 unmodified lines
3030 .output_len = sizeof(struct core_reloc_module_output), \
3131 .prog_sec_name = sec_name, \
3232 .raw_tp_name = tp_name, \
33− .trigger = trigger_module_test_read, \
33+ .trigger = __trigger_module_test_read, \
3434 .needs_testmod = true, \
3535 }
3636
@@ -249,8 +249,7 @@ static int duration = 0; · 212 unmodified lines
249249 #define SIZE_CASE_COMMON(name) \
250250 .case_name = #name, \
251251 .bpf_obj_file = "test_core_reloc_size.o", \
252− .btf_src_file = "btf__core_reloc_" #name ".o", \
253− .relaxed_core_relocs = true
252+ .btf_src_file = "btf__core_reloc_" #name ".o"
254253
255254 #define SIZE_OUTPUT_DATA(type) \
256255 STRUCT_TO_CHAR_PTR(core_reloc_size_output) { \
@@ -475,19 +474,11 @@ static int setup_type_id_case_failure(struct core_reloc_test_case *test) · 218 unmodified lines
475474 return 0;
476475 }
477476
478−static int trigger_module_test_read(const struct core_reloc_test_case *test)
477+static int __trigger_module_test_read(const struct core_reloc_test_case *test)
479478 {
480479 struct core_reloc_module_output *exp = (void *)test->output;
481− int fd, err;
482−
483− fd = open("/sys/kernel/bpf_testmod", O_RDONLY);
484− err = -errno;
485− if (CHECK(fd < 0, "testmod_file_open", "failed: %d\n", err))
486− return err;
487−
488− read(fd, NULL, exp->len); /* request expected number of bytes */
489− close(fd);
490480
481+ trigger_module_test_read(exp->len);
491482 return 0;
492483 }
493484
tools/testing/selftests/bpf/prog_tests/fexit_bpf2bpf.c+26−17
@@ -60,7 +60,7 @@ static void test_fexit_bpf2bpf_common(const char *obj_file, · 59 unmodified lines
6060 struct bpf_object *obj = NULL, *tgt_obj;
6161 __u32 retval, tgt_prog_id, info_len;
6262 struct bpf_prog_info prog_info = {};
63− struct bpf_program **prog = NULL;
63+ struct bpf_program **prog = NULL, *p;
6464 struct bpf_link **link = NULL;
6565 int err, tgt_fd, i;
6666 struct btf *btf;
@@ -69,9 +69,6 @@ static void test_fexit_bpf2bpf_common(const char *obj_file, · 2 unmodified lines
6969 &tgt_obj, &tgt_fd);
7070 if (!ASSERT_OK(err, "tgt_prog_load"))
7171 return;
72− DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts,
73− .attach_prog_fd = tgt_fd,
74− );
7572
7673 info_len = sizeof(prog_info);
7774 err = bpf_obj_get_info_by_fd(tgt_fd, &prog_info, &info_len);
@@ -89,10 +86,15 @@ static void test_fexit_bpf2bpf_common(const char *obj_file, · 11 unmodified lines
8986 if (!ASSERT_OK_PTR(prog, "prog_ptr"))
9087 goto close_prog;
9188
92− obj = bpf_object__open_file(obj_file, &opts);
89+ obj = bpf_object__open_file(obj_file, NULL);
9390 if (!ASSERT_OK_PTR(obj, "obj_open"))
9491 goto close_prog;
9592
93+ bpf_object__for_each_program(p, obj) {
94+ err = bpf_program__set_attach_target(p, tgt_fd, NULL);
95+ ASSERT_OK(err, "set_attach_target");
96+ }
97+
9698 err = bpf_object__load(obj);
9799 if (!ASSERT_OK(err, "obj_load"))
98100 goto close_prog;
@@ -270,7 +272,7 @@ static void test_fmod_ret_freplace(void) · 171 unmodified lines
270272 struct bpf_link *freplace_link = NULL;
271273 struct bpf_program *prog;
272274 __u32 duration = 0;
273− int err, pkt_fd;
275+ int err, pkt_fd, attach_prog_fd;
274276
275277 err = bpf_prog_load(tgt_name, BPF_PROG_TYPE_UNSPEC,
276278 &pkt_obj, &pkt_fd);
@@ -278,26 +280,32 @@ static void test_fmod_ret_freplace(void) · 1 unmodified line
278280 if (CHECK(err, "tgt_prog_load", "file %s err %d errno %d\n",
279281 tgt_name, err, errno))
280282 return;
281− opts.attach_prog_fd = pkt_fd;
282283
283− freplace_obj = bpf_object__open_file(freplace_name, &opts);
284+ freplace_obj = bpf_object__open_file(freplace_name, NULL);
284285 if (!ASSERT_OK_PTR(freplace_obj, "freplace_obj_open"))
285286 goto out;
286287
288+ prog = bpf_program__next(NULL, freplace_obj);
289+ err = bpf_program__set_attach_target(prog, pkt_fd, NULL);
290+ ASSERT_OK(err, "freplace__set_attach_target");
291+
287292 err = bpf_object__load(freplace_obj);
288293 if (CHECK(err, "freplace_obj_load", "err %d\n", err))
289294 goto out;
290295
291− prog = bpf_program__next(NULL, freplace_obj);
292296 freplace_link = bpf_program__attach_trace(prog);
293297 if (!ASSERT_OK_PTR(freplace_link, "freplace_attach_trace"))
294298 goto out;
295299
296− opts.attach_prog_fd = bpf_program__fd(prog);
297− fmod_obj = bpf_object__open_file(fmod_ret_name, &opts);
300+ fmod_obj = bpf_object__open_file(fmod_ret_name, NULL);
298301 if (!ASSERT_OK_PTR(fmod_obj, "fmod_obj_open"))
299302 goto out;
300303
304+ attach_prog_fd = bpf_program__fd(prog);
305+ prog = bpf_program__next(NULL, fmod_obj);
306+ err = bpf_program__set_attach_target(prog, attach_prog_fd, NULL);
307+ ASSERT_OK(err, "fmod_ret_set_attach_target");
308+
301309 err = bpf_object__load(fmod_obj);
302310 if (CHECK(!err, "fmod_obj_load", "loading fmod_ret should fail\n"))
303311 goto out;
@@ -322,14 +330,14 @@ static void test_func_sockmap_update(void) · 18 unmodified lines
322330 }
323331
324332 static void test_obj_load_failure_common(const char *obj_file,
325− const char *target_obj_file)
326−
333+ const char *target_obj_file)
327334 {
328335 /*
329336 * standalone test that asserts failure to load freplace prog
330337 * because of invalid return code.
331338 */
332339 struct bpf_object *obj = NULL, *pkt_obj;
340+ struct bpf_program *prog;
333341 int err, pkt_fd;
334342 __u32 duration = 0;
335343
@@ -339,14 +347,15 @@ static void test_obj_load_failure_common(const char *obj_file, · 3 unmodified lines
339347 if (CHECK(err, "tgt_prog_load", "file %s err %d errno %d\n",
340348 target_obj_file, err, errno))
341349 return;
342− DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts,
343− .attach_prog_fd = pkt_fd,
344− );
345350
346− obj = bpf_object__open_file(obj_file, &opts);
351+ obj = bpf_object__open_file(obj_file, NULL);
347352 if (!ASSERT_OK_PTR(obj, "obj_open"))
348353 goto close_prog;
349354
355+ prog = bpf_program__next(NULL, obj);
356+ err = bpf_program__set_attach_target(prog, pkt_fd, NULL);
357+ ASSERT_OK(err, "set_attach_target");
358+
350359 /* It should fail to load the program */
351360 err = bpf_object__load(obj);
352361 if (CHECK(!err, "bpf_obj_load should fail", "err %d\n", err))
tools/testing/selftests/bpf/prog_tests/get_branch_snapshot.c+100−0
@@ -0,0 +1,100 @@
1+// SPDX-License-Identifier: GPL-2.0
2+/* Copyright (c) 2021 Facebook */
3+#include <test_progs.h>
4+#include "get_branch_snapshot.skel.h"
5+
6+static int *pfd_array;
7+static int cpu_cnt;
8+
9+static int create_perf_events(void)
10+{
11+ struct perf_event_attr attr = {0};
12+ int cpu;
13+
14+ /* create perf event */
15+ attr.size = sizeof(attr);
16+ attr.type = PERF_TYPE_RAW;
17+ attr.config = 0x1b00;
18+ attr.sample_type = PERF_SAMPLE_BRANCH_STACK;
19+ attr.branch_sample_type = PERF_SAMPLE_BRANCH_KERNEL |
20+ PERF_SAMPLE_BRANCH_USER | PERF_SAMPLE_BRANCH_ANY;
21+
22+ cpu_cnt = libbpf_num_possible_cpus();
23+ pfd_array = malloc(sizeof(int) * cpu_cnt);
24+ if (!pfd_array) {
25+ cpu_cnt = 0;
26+ return 1;
27+ }
28+
29+ for (cpu = 0; cpu < cpu_cnt; cpu++) {
30+ pfd_array[cpu] = syscall(__NR_perf_event_open, &attr,
31+ -1, cpu, -1, PERF_FLAG_FD_CLOEXEC);
32+ if (pfd_array[cpu] < 0)
33+ break;
34+ }
35+
36+ return cpu == 0;
37+}
38+
39+static void close_perf_events(void)
40+{
41+ int cpu = 0;
42+ int fd;
43+
44+ while (cpu++ < cpu_cnt) {
45+ fd = pfd_array[cpu];
46+ if (fd < 0)
47+ break;
48+ close(fd);
49+ }
50+ free(pfd_array);
51+}
52+
53+void test_get_branch_snapshot(void)
54+{
55+ struct get_branch_snapshot *skel = NULL;
56+ int err;
57+
58+ if (create_perf_events()) {
59+ test__skip(); /* system doesn't support LBR */
60+ goto cleanup;
61+ }
62+
63+ skel = get_branch_snapshot__open_and_load();
64+ if (!ASSERT_OK_PTR(skel, "get_branch_snapshot__open_and_load"))
65+ goto cleanup;
66+
67+ err = kallsyms_find("bpf_testmod_loop_test", &skel->bss->address_low);
68+ if (!ASSERT_OK(err, "kallsyms_find"))
69+ goto cleanup;
70+
71+ err = kallsyms_find_next("bpf_testmod_loop_test", &skel->bss->address_high);
72+ if (!ASSERT_OK(err, "kallsyms_find_next"))
73+ goto cleanup;
74+
75+ err = get_branch_snapshot__attach(skel);
76+ if (!ASSERT_OK(err, "get_branch_snapshot__attach"))
77+ goto cleanup;
78+
79+ trigger_module_test_read(100);
80+
81+ if (skel->bss->total_entries < 16) {
82+ /* too few entries for the hit/waste test */
83+ test__skip();
84+ goto cleanup;
85+ }
86+
87+ ASSERT_GT(skel->bss->test1_hits, 6, "find_looptest_in_lbr");
88+
89+ /* Given we stop LBR in software, we will waste a few entries.
90+ * But we should try to waste as few as possible entries. We are at
91+ * about 7 on x86_64 systems.
92+ * Add a check for < 10 so that we get heads-up when something
93+ * changes and wastes too many entries.
94+ */
95+ ASSERT_LT(skel->bss->wasted_entries, 10, "check_wasted_entries");
96+
97+cleanup:
98+ get_branch_snapshot__destroy(skel);
99+ close_perf_events();
100+}
tools/testing/selftests/bpf/prog_tests/module_attach.c+0−39
@@ -6,45 +6,6 @@ · 5 unmodified lines
66
77 static int duration;
88
9−static int trigger_module_test_read(int read_sz)
10−{
11− int fd, err;
12−
13− fd = open("/sys/kernel/bpf_testmod", O_RDONLY);
14− err = -errno;
15− if (CHECK(fd < 0, "testmod_file_open", "failed: %d\n", err))
16− return err;
17−
18− read(fd, NULL, read_sz);
19− close(fd);
20−
21− return 0;
22−}
23−
24−static int trigger_module_test_write(int write_sz)
25−{
26− int fd, err;
27− char *buf = malloc(write_sz);
28−
29− if (!buf)
30− return -ENOMEM;
31−
32− memset(buf, 'a', write_sz);
33− buf[write_sz-1] = '\0';
34−
35− fd = open("/sys/kernel/bpf_testmod", O_WRONLY);
36− err = -errno;
37− if (CHECK(fd < 0, "testmod_file_open", "failed: %d\n", err)) {
38− free(buf);
39− return err;
40− }
41−
42− write(fd, buf, write_sz);
43− close(fd);
44− free(buf);
45− return 0;
46−}
47−
489 static int delete_module(const char *name, int flags)
4910 {
5011 return syscall(__NR_delete_module, name, flags);
tools/testing/selftests/bpf/prog_tests/skb_ctx.c+6−0
@@ -11,12 +11,14 @@ void test_skb_ctx(void) · 10 unmodified lines
1111 .cb[3] = 4,
1212 .cb[4] = 5,
1313 .priority = 6,
14+ .ingress_ifindex = 11,
1415 .ifindex = 1,
1516 .tstamp = 7,
1617 .wire_len = 100,
1718 .gso_segs = 8,
1819 .mark = 9,
1920 .gso_size = 10,
21+ .hwtstamp = 11,
2022 };
2123 struct bpf_prog_test_run_attr tattr = {
2224 .data_in = &pkt_v4,
@@ -97,6 +99,10 @@ void test_skb_ctx(void) · 74 unmodified lines
9799 "ctx_out_ifindex",
98100 "skb->ifindex == %d, expected %d\n",
99101 skb.ifindex, 1);
102+ CHECK_ATTR(skb.ingress_ifindex != 11,
103+ "ctx_out_ingress_ifindex",
104+ "skb->ingress_ifindex == %d, expected %d\n",
105+ skb.ingress_ifindex, 11);
100106 CHECK_ATTR(skb.tstamp != 8,
101107 "ctx_out_tstamp",
102108 "skb->tstamp == %lld, expected %d\n",
tools/testing/selftests/bpf/prog_tests/skeleton.c+6−0
@@ -18,6 +18,8 @@ void test_skeleton(void) · 17 unmodified lines
1818 struct test_skeleton__data *data;
1919 struct test_skeleton__rodata *rodata;
2020 struct test_skeleton__kconfig *kcfg;
21+ const void *elf_bytes;
22+ size_t elf_bytes_sz = 0;
2123
2224 skel = test_skeleton__open();
2325 if (CHECK(!skel, "skel_open", "failed to open skeleton\n"))
@@ -91,6 +93,10 @@ void test_skeleton(void) · 67 unmodified lines
9193 CHECK(bss->kern_ver != kcfg->LINUX_KERNEL_VERSION, "ext2",
9294 "got %d != exp %d\n", bss->kern_ver, kcfg->LINUX_KERNEL_VERSION);
9395
96+ elf_bytes = test_skeleton__elf_bytes(&elf_bytes_sz);
97+ ASSERT_OK_PTR(elf_bytes, "elf_bytes");
98+ ASSERT_GE(elf_bytes_sz, 0, "elf_bytes_sz");
99+
94100 cleanup:
95101 test_skeleton__destroy(skel);
96102 }
tools/testing/selftests/bpf/prog_tests/tailcalls.c+20−5
@@ -219,10 +219,7 @@ out: · 218 unmodified lines
219219 bpf_object__close(obj);
220220 }
221221
222−/* test_tailcall_3 checks that the count value of the tail call limit
223− * enforcement matches with expectations.
224− */
225−static void test_tailcall_3(void)
222+static void test_tailcall_count(const char *which)
226223 {
227224 int err, map_fd, prog_fd, main_fd, data_fd, i, val;
228225 struct bpf_map *prog_array, *data_map;
@@ -231,7 +228,7 @@ static void test_tailcall_3(void) · 2 unmodified lines
231228 __u32 retval, duration;
232229 char buff[128] = {};
233230
234− err = bpf_prog_load("tailcall3.o", BPF_PROG_TYPE_SCHED_CLS, &obj,
231+ err = bpf_prog_load(which, BPF_PROG_TYPE_SCHED_CLS, &obj,
235232 &prog_fd);
236233 if (CHECK_FAIL(err))
237234 return;
@@ -296,6 +293,22 @@ out: · 58 unmodified lines
296293 bpf_object__close(obj);
297294 }
298295
296+/* test_tailcall_3 checks that the count value of the tail call limit
297+ * enforcement matches with expectations. JIT uses direct jump.
298+ */
299+static void test_tailcall_3(void)
300+{
301+ test_tailcall_count("tailcall3.o");
302+}
303+
304+/* test_tailcall_6 checks that the count value of the tail call limit
305+ * enforcement matches with expectations. JIT uses indirect jump.
306+ */
307+static void test_tailcall_6(void)
308+{
309+ test_tailcall_count("tailcall6.o");
310+}
311+
299312 /* test_tailcall_4 checks that the kernel properly selects indirect jump
300313 * for the case where the key is not known. Latter is passed via global
301314 * data to select different targets we can compare return value of.
@@ -822,6 +835,8 @@ void test_tailcalls(void) · 520 unmodified lines
822835 test_tailcall_4();
823836 if (test__start_subtest("tailcall_5"))
824837 test_tailcall_5();
838+ if (test__start_subtest("tailcall_6"))
839+ test_tailcall_6();
825840 if (test__start_subtest("tailcall_bpf2bpf_1"))
826841 test_tailcall_bpf2bpf_1();
827842 if (test__start_subtest("tailcall_bpf2bpf_2"))
tools/testing/selftests/bpf/prog_tests/tc_redirect.c+1−1
@@ -633,7 +633,7 @@ static void test_tc_redirect_peer_l3(struct netns_setup_result *setup_result) · 632 unmodified lines
633633 struct nstoken *nstoken = NULL;
634634 int err;
635635 int tunnel_pid = -1;
636− int src_fd, target_fd;
636+ int src_fd, target_fd = -1;
637637 int ifindex;
638638
639639 /* Start a L3 TUN/TAP tunnel between the src and dst namespaces.
tools/testing/selftests/bpf/progs/bpf_cubic.c+3−9
@@ -169,11 +169,7 @@ static __always_inline void bictcp_hystart_reset(struct sock *sk) · 168 unmodified lines
169169 ca->sample_cnt = 0;
170170 }
171171
172−/* "struct_ops/" prefix is not a requirement
173− * It will be recognized as BPF_PROG_TYPE_STRUCT_OPS
174− * as long as it is used in one of the func ptr
175− * under SEC(".struct_ops").
176− */
172+/* "struct_ops/" prefix is a requirement */
177173 SEC("struct_ops/bpf_cubic_init")
178174 void BPF_PROG(bpf_cubic_init, struct sock *sk)
179175 {
@@ -188,10 +184,8 @@ void BPF_PROG(bpf_cubic_init, struct sock *sk) · 8 unmodified lines
188184 tcp_sk(sk)->snd_ssthresh = initial_ssthresh;
189185 }
190186
191−/* No prefix in SEC will also work.
192− * The remaining tcp-cubic functions have an easier way.
193− */
194−SEC("no-sec-prefix-bictcp_cwnd_event")
187+/* "struct_ops" prefix is a requirement */
188+SEC("struct_ops/bpf_cubic_cwnd_event")
195189 void BPF_PROG(bpf_cubic_cwnd_event, struct sock *sk, enum tcp_ca_event event)
196190 {
197191 if (event == CA_EVENT_TX_START) {
tools/testing/selftests/bpf/progs/get_branch_snapshot.c+40−0
@@ -0,0 +1,40 @@
1+// SPDX-License-Identifier: GPL-2.0
2+/* Copyright (c) 2021 Facebook */
3+#include "vmlinux.h"
4+#include <bpf/bpf_helpers.h>
5+#include <bpf/bpf_tracing.h>
6+
7+char _license[] SEC("license") = "GPL";
8+
9+__u64 test1_hits = 0;
10+__u64 address_low = 0;
11+__u64 address_high = 0;
12+int wasted_entries = 0;
13+long total_entries = 0;
14+
15+#define ENTRY_CNT 32
16+struct perf_branch_entry entries[ENTRY_CNT] = {};
17+
18+static inline bool in_range(__u64 val)
19+{
20+ return (val >= address_low) && (val < address_high);
21+}
22+
23+SEC("fexit/bpf_testmod_loop_test")
24+int BPF_PROG(test1, int n, int ret)
25+{
26+ long i;
27+
28+ total_entries = bpf_get_branch_snapshot(entries, sizeof(entries), 0);
29+ total_entries /= sizeof(struct perf_branch_entry);
30+
31+ for (i = 0; i < ENTRY_CNT; i++) {
32+ if (i >= total_entries)
33+ break;
34+ if (in_range(entries[i].from) && in_range(entries[i].to))
35+ test1_hits++;
36+ else if (!test1_hits)
37+ wasted_entries++;
38+ }
39+ return 0;
40+}
tools/testing/selftests/bpf/progs/tag.c+49−0
@@ -0,0 +1,49 @@
1+// SPDX-License-Identifier: GPL-2.0
2+/* Copyright (c) 2021 Facebook */
3+#include "vmlinux.h"
4+#include <bpf/bpf_helpers.h>
5+#include <bpf/bpf_tracing.h>
6+
7+#ifndef __has_attribute
8+#define __has_attribute(x) 0
9+#endif
10+
11+#if __has_attribute(btf_tag)
12+#define __tag1 __attribute__((btf_tag("tag1")))
13+#define __tag2 __attribute__((btf_tag("tag2")))
14+volatile const bool skip_tests __tag1 __tag2 = false;
15+#else
16+#define __tag1
17+#define __tag2
18+volatile const bool skip_tests = true;
19+#endif
20+
21+struct key_t {
22+ int a;
23+ int b __tag1 __tag2;
24+ int c;
25+} __tag1 __tag2;
26+
27+struct {
28+ __uint(type, BPF_MAP_TYPE_HASH);
29+ __uint(max_entries, 3);
30+ __type(key, struct key_t);
31+ __type(value, __u64);
32+} hashmap1 SEC(".maps");
33+
34+
35+static __noinline int foo(int x __tag1 __tag2) __tag1 __tag2
36+{
37+ struct key_t key;
38+ __u64 val = 1;
39+
40+ key.a = key.b = key.c = x;
41+ bpf_map_update_elem(&hashmap1, &key, &val, 0);
42+ return 0;
43+}
44+
45+SEC("fentry/bpf_fentry_test1")
46+int BPF_PROG(sub, int x)
47+{
48+ return foo(x);
49+}
tools/testing/selftests/bpf/progs/tailcall6.c+34−0
@@ -0,0 +1,34 @@
1+// SPDX-License-Identifier: GPL-2.0
2+#include <linux/bpf.h>
3+
4+#include <bpf/bpf_helpers.h>
5+
6+struct {
7+ __uint(type, BPF_MAP_TYPE_PROG_ARRAY);
8+ __uint(max_entries, 1);
9+ __uint(key_size, sizeof(__u32));
10+ __uint(value_size, sizeof(__u32));
11+} jmp_table SEC(".maps");
12+
13+int count, which;
14+
15+SEC("classifier/0")
16+int bpf_func_0(struct __sk_buff *skb)
17+{
18+ count++;
19+ if (__builtin_constant_p(which))
20+ __bpf_unreachable();
21+ bpf_tail_call(skb, &jmp_table, which);
22+ return 1;
23+}
24+
25+SEC("classifier")
26+int entry(struct __sk_buff *skb)
27+{
28+ if (__builtin_constant_p(which))
29+ __bpf_unreachable();
30+ bpf_tail_call(skb, &jmp_table, which);
31+ return 0;
32+}
33+
34+char __license[] SEC("license") = "GPL";
tools/testing/selftests/bpf/progs/test_skb_ctx.c+6−0
@@ -25,6 +25,12 @@ int process(struct __sk_buff *skb) · 24 unmodified lines
2525 return 1;
2626 if (skb->gso_size != 10)
2727 return 1;
28+ if (skb->ingress_ifindex != 11)
29+ return 1;
30+ if (skb->ifindex != 1)
31+ return 1;
32+ if (skb->hwtstamp != 11)
33+ return 1;
2834
2935 return 0;
3036 }
tools/testing/selftests/bpf/test_btf.h+3−0
@@ -69,4 +69,7 @@ · 68 unmodified lines
6969 #define BTF_TYPE_FLOAT_ENC(name, sz) \
7070 BTF_TYPE_ENC(name, BTF_INFO_ENC(BTF_KIND_FLOAT, 0, 0), sz)
7171
72+#define BTF_TAG_ENC(value, type, component_idx) \
73+ BTF_TYPE_ENC(value, BTF_INFO_ENC(BTF_KIND_TAG, 0, 0), type), (component_idx)
74+
7275 #endif /* _TEST_BTF_H */
tools/testing/selftests/bpf/test_progs.c+39−0
@@ -743,6 +743,45 @@ int cd_flavor_subdir(const char *exec_name) · 742 unmodified lines
743743 return chdir(flavor);
744744 }
745745
746+int trigger_module_test_read(int read_sz)
747+{
748+ int fd, err;
749+
750+ fd = open("/sys/kernel/bpf_testmod", O_RDONLY);
751+ err = -errno;
752+ if (!ASSERT_GE(fd, 0, "testmod_file_open"))
753+ return err;
754+
755+ read(fd, NULL, read_sz);
756+ close(fd);
757+
758+ return 0;
759+}
760+
761+int trigger_module_test_write(int write_sz)
762+{
763+ int fd, err;
764+ char *buf = malloc(write_sz);
765+
766+ if (!buf)
767+ return -ENOMEM;
768+
769+ memset(buf, 'a', write_sz);
770+ buf[write_sz-1] = '\0';
771+
772+ fd = open("/sys/kernel/bpf_testmod", O_WRONLY);
773+ err = -errno;
774+ if (!ASSERT_GE(fd, 0, "testmod_file_open")) {
775+ free(buf);
776+ return err;
777+ }
778+
779+ write(fd, buf, write_sz);
780+ close(fd);
781+ free(buf);
782+ return 0;
783+}
784+
746785 #define MAX_BACKTRACE_SZ 128
747786 void crash_handler(int signum)
748787 {
tools/testing/selftests/bpf/test_progs.h+2−0
@@ -291,6 +291,8 @@ int compare_map_keys(int map1_fd, int map2_fd); · 290 unmodified lines
291291 int compare_stack_ips(int smap_fd, int amap_fd, int stack_trace_len);
292292 int extract_build_id(char *build_id, size_t size);
293293 int kern_sync_rcu(void);
294+int trigger_module_test_read(int read_sz);
295+int trigger_module_test_write(int write_sz);
294296
295297 #ifdef __x86_64__
296298 #define SYS_NANOSLEEP_KPROBE_NAME "__x64_sys_nanosleep"
tools/testing/selftests/bpf/trace_helpers.c+37−0
@@ -1,4 +1,5 @@
11 // SPDX-License-Identifier: GPL-2.0
2+#include <ctype.h>
23 #include <stdio.h>
34 #include <stdlib.h>
45 #include <string.h>
@@ -117,6 +118,42 @@ out: · 112 unmodified lines
117118 return err;
118119 }
119120
121+/* find the address of the next symbol of the same type, this can be used
122+ * to determine the end of a function.
123+ */
124+int kallsyms_find_next(const char *sym, unsigned long long *addr)
125+{
126+ char type, found_type, name[500];
127+ unsigned long long value;
128+ bool found = false;
129+ int err = 0;
130+ FILE *f;
131+
132+ f = fopen("/proc/kallsyms", "r");
133+ if (!f)
134+ return -EINVAL;
135+
136+ while (fscanf(f, "%llx %c %499s%*[^\n]\n", &value, &type, name) > 0) {
137+ /* Different types of symbols in kernel modules are mixed
138+ * in /proc/kallsyms. Only return the next matching type.
139+ * Use tolower() for type so that 'T' matches 't'.
140+ */
141+ if (found && found_type == tolower(type)) {
142+ *addr = value;
143+ goto out;
144+ }
145+ if (strcmp(name, sym) == 0) {
146+ found = true;
147+ found_type = tolower(type);
148+ }
149+ }
150+ err = -ENOENT;
151+
152+out:
153+ fclose(f);
154+ return err;
155+}
156+
120157 void read_trace_pipe(void)
121158 {
122159 int trace_fd;
tools/testing/selftests/bpf/trace_helpers.h+5−0
@@ -16,6 +16,11 @@ long ksym_get_addr(const char *name); · 15 unmodified lines
1616 /* open kallsyms and find addresses on the fly, faster than load + search. */
1717 int kallsyms_find(const char *sym, unsigned long long *addr);
1818
19+/* find the address of the next symbol, this can be used to determine the
20+ * end of a function
21+ */
22+int kallsyms_find_next(const char *sym, unsigned long long *addr);
23+
1924 void read_trace_pipe(void);
2025
2126 ssize_t get_uprobe_offset(const void *addr, ssize_t base);
tools/testing/selftests/bpf/verifier/ctx_skb.c+60−0
@@ -1057,6 +1057,66 @@ · 1056 unmodified lines
10571057 .result = ACCEPT,
10581058 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
10591059 },
1060+{
1061+ "padding after gso_size is not accessible",
1062+ .insns = {
1063+ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
1064+ offsetofend(struct __sk_buff, gso_size)),
1065+ BPF_MOV64_IMM(BPF_REG_0, 0),
1066+ BPF_EXIT_INSN(),
1067+ },
1068+ .result = REJECT,
1069+ .result_unpriv = REJECT,
1070+ .errstr = "invalid bpf_context access off=180 size=4",
1071+ .prog_type = BPF_PROG_TYPE_SCHED_CLS,
1072+},
1073+{
1074+ "read hwtstamp from CGROUP_SKB",
1075+ .insns = {
1076+ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1,
1077+ offsetof(struct __sk_buff, hwtstamp)),
1078+ BPF_MOV64_IMM(BPF_REG_0, 0),
1079+ BPF_EXIT_INSN(),
1080+ },
1081+ .result = ACCEPT,
1082+ .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
1083+},
1084+{
1085+ "read hwtstamp from CGROUP_SKB",
1086+ .insns = {
1087+ BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_1,
1088+ offsetof(struct __sk_buff, hwtstamp)),
1089+ BPF_MOV64_IMM(BPF_REG_0, 0),
1090+ BPF_EXIT_INSN(),
1091+ },
1092+ .result = ACCEPT,
1093+ .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
1094+},
1095+{
1096+ "write hwtstamp from CGROUP_SKB",
1097+ .insns = {
1098+ BPF_MOV64_IMM(BPF_REG_0, 0),
1099+ BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0,
1100+ offsetof(struct __sk_buff, hwtstamp)),
1101+ BPF_MOV64_IMM(BPF_REG_0, 0),
1102+ BPF_EXIT_INSN(),
1103+ },
1104+ .result = REJECT,
1105+ .result_unpriv = REJECT,
1106+ .errstr = "invalid bpf_context access off=184 size=8",
1107+ .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
1108+},
1109+{
1110+ "read hwtstamp from CLS",
1111+ .insns = {
1112+ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1,
1113+ offsetof(struct __sk_buff, hwtstamp)),
1114+ BPF_MOV64_IMM(BPF_REG_0, 0),
1115+ BPF_EXIT_INSN(),
1116+ },
1117+ .result = ACCEPT,
1118+ .prog_type = BPF_PROG_TYPE_SCHED_CLS,
1119+},
10601120 {
10611121 "check wire_len is not readable by sockets",
10621122 .insns = {
tools/testing/selftests/bpf/verifier/jit.c+19−3
@@ -62,6 +62,11 @@ · 61 unmodified lines
6262 BPF_JMP_REG(BPF_JEQ, BPF_REG_3, BPF_REG_2, 2),
6363 BPF_MOV64_IMM(BPF_REG_0, 1),
6464 BPF_EXIT_INSN(),
65+ BPF_LD_IMM64(BPF_REG_3, 0xfefefeULL),
66+ BPF_ALU64_IMM(BPF_MUL, BPF_REG_3, 0xefefef),
67+ BPF_JMP_REG(BPF_JEQ, BPF_REG_3, BPF_REG_2, 2),
68+ BPF_MOV64_IMM(BPF_REG_0, 1),
69+ BPF_EXIT_INSN(),
6570 BPF_MOV32_REG(BPF_REG_2, BPF_REG_2),
6671 BPF_LD_IMM64(BPF_REG_0, 0xfefefeULL),
6772 BPF_ALU32_REG(BPF_MUL, BPF_REG_0, BPF_REG_1),
@@ -73,11 +78,22 @@ · 5 unmodified lines
7378 BPF_JMP_REG(BPF_JEQ, BPF_REG_3, BPF_REG_2, 2),
7479 BPF_MOV64_IMM(BPF_REG_0, 1),
7580 BPF_EXIT_INSN(),
81+ BPF_LD_IMM64(BPF_REG_3, 0xfefefeULL),
82+ BPF_ALU32_IMM(BPF_MUL, BPF_REG_3, 0xefefef),
83+ BPF_JMP_REG(BPF_JEQ, BPF_REG_3, BPF_REG_2, 2),
84+ BPF_MOV64_IMM(BPF_REG_0, 1),
85+ BPF_EXIT_INSN(),
86+ BPF_LD_IMM64(BPF_REG_0, 0xfefefeULL),
87+ BPF_LD_IMM64(BPF_REG_2, 0x2ad4d4aaULL),
88+ BPF_ALU32_IMM(BPF_MUL, BPF_REG_0, 0x2b),
89+ BPF_JMP_REG(BPF_JEQ, BPF_REG_0, BPF_REG_2, 2),
90+ BPF_MOV64_IMM(BPF_REG_0, 1),
91+ BPF_EXIT_INSN(),
7692 BPF_LD_IMM64(BPF_REG_0, 0x952a7bbcULL),
7793 BPF_LD_IMM64(BPF_REG_1, 0xfefefeULL),
78− BPF_LD_IMM64(BPF_REG_2, 0xeeff0d413122ULL),
79− BPF_ALU32_REG(BPF_MUL, BPF_REG_2, BPF_REG_1),
80− BPF_JMP_REG(BPF_JEQ, BPF_REG_2, BPF_REG_0, 2),
94+ BPF_LD_IMM64(BPF_REG_5, 0xeeff0d413122ULL),
95+ BPF_ALU32_REG(BPF_MUL, BPF_REG_5, BPF_REG_1),
96+ BPF_JMP_REG(BPF_JEQ, BPF_REG_5, BPF_REG_0, 2),
8197 BPF_MOV64_IMM(BPF_REG_0, 1),
8298 BPF_EXIT_INSN(),
8399 BPF_MOV64_IMM(BPF_REG_0, 2),
tools/testing/selftests/bpf/xdpxceiver.c+570−302
@@ -19,7 +19,7 @@ · 18 unmodified lines
1919 * Virtual Ethernet interfaces.
2020 *
2121 * For each mode, the following tests are run:
22− * a. nopoll - soft-irq processing
22+ * a. nopoll - soft-irq processing in run-to-completion mode
2323 * b. poll - using poll() syscall
2424 * c. Socket Teardown
2525 * Create a Tx and a Rx socket, Tx from one socket, Rx on another. Destroy
@@ -45,6 +45,10 @@ · 19 unmodified lines
4545 * Configure sockets at indexes 0 and 1, run a traffic on queue ids 0,
4646 * then remove xsk sockets from queue 0 on both veth interfaces and
4747 * finally run a traffic on queues ids 1
48+ * g. unaligned mode
49+ * h. tests for invalid and corner case Tx descriptors so that the correct ones
50+ * are discarded and let through, respectively.
51+ * i. 2K frame size tests
4852 *
4953 * Total tests: 12
5054 *
@@ -112,13 +116,10 @@ static void __exit_with_error(int error, const char *file, const char *func, int · 61 unmodified lines
112116
113117 #define exit_with_error(error) __exit_with_error(error, __FILE__, __func__, __LINE__)
114118
115−#define print_ksft_result(void)\
116− (ksft_test_result_pass("PASS: %s %s %s%s%s%s\n", configured_mode ? "DRV" : "SKB",\
117− test_type == TEST_TYPE_POLL ? "POLL" : "NOPOLL",\
118− test_type == TEST_TYPE_TEARDOWN ? "Socket Teardown" : "",\
119− test_type == TEST_TYPE_BIDI ? "Bi-directional Sockets" : "",\
120− test_type == TEST_TYPE_STATS ? "Stats" : "",\
121− test_type == TEST_TYPE_BPF_RES ? "BPF RES" : ""))
119+#define mode_string(test) (test)->ifobj_tx->xdp_flags & XDP_FLAGS_SKB_MODE ? "SKB" : "DRV"
120+
121+#define print_ksft_result(test) \
122+ (ksft_test_result_pass("PASS: %s %s\n", mode_string(test), (test)->name))
122123
123124 static void memset32_htonl(void *dest, u32 val, u32 size)
124125 {
@@ -235,80 +236,46 @@ static void gen_udp_csum(struct udphdr *udp_hdr, struct iphdr *ip_hdr) · 110 unmodified lines
235236 udp_csum(ip_hdr->saddr, ip_hdr->daddr, UDP_PKT_SIZE, IPPROTO_UDP, (u16 *)udp_hdr);
236237 }
237238
238−static void xsk_configure_umem(struct ifobject *data, void *buffer, u64 size, int idx)
239+static int xsk_configure_umem(struct xsk_umem_info *umem, void *buffer, u64 size)
239240 {
240241 struct xsk_umem_config cfg = {
241242 .fill_size = XSK_RING_PROD__DEFAULT_NUM_DESCS,
242243 .comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS,
243− .frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE,
244− .frame_headroom = frame_headroom,
244+ .frame_size = umem->frame_size,
245+ .frame_headroom = umem->frame_headroom,
245246 .flags = XSK_UMEM__DEFAULT_FLAGS
246247 };
247− struct xsk_umem_info *umem;
248248 int ret;
249249
250− umem = calloc(1, sizeof(struct xsk_umem_info));
251− if (!umem)
252− exit_with_error(errno);
250+ if (umem->unaligned_mode)
251+ cfg.flags |= XDP_UMEM_UNALIGNED_CHUNK_FLAG;
253252
254253 ret = xsk_umem__create(&umem->umem, buffer, size,
255254 &umem->fq, &umem->cq, &cfg);
256255 if (ret)
257− exit_with_error(-ret);
256+ return ret;
258257
259258 umem->buffer = buffer;
260−
261− data->umem_arr[idx] = umem;
262−}
263−
264−static void xsk_populate_fill_ring(struct xsk_umem_info *umem)
265−{
266− int ret, i;
267− u32 idx = 0;
268−
269− ret = xsk_ring_prod__reserve(&umem->fq, XSK_RING_PROD__DEFAULT_NUM_DESCS, &idx);
270− if (ret != XSK_RING_PROD__DEFAULT_NUM_DESCS)
271− exit_with_error(-ret);
272− for (i = 0; i < XSK_RING_PROD__DEFAULT_NUM_DESCS; i++)
273− *xsk_ring_prod__fill_addr(&umem->fq, idx++) = i * XSK_UMEM__DEFAULT_FRAME_SIZE;
274− xsk_ring_prod__submit(&umem->fq, XSK_RING_PROD__DEFAULT_NUM_DESCS);
259+ return 0;
275260 }
276261
277−static int xsk_configure_socket(struct ifobject *ifobject, int idx)
262+static int xsk_configure_socket(struct xsk_socket_info *xsk, struct xsk_umem_info *umem,
263+ struct ifobject *ifobject, u32 qid)
278264 {
279265 struct xsk_socket_config cfg;
280− struct xsk_socket_info *xsk;
281266 struct xsk_ring_cons *rxr;
282267 struct xsk_ring_prod *txr;
283− int ret;
284268
285− xsk = calloc(1, sizeof(struct xsk_socket_info));
286− if (!xsk)
287− exit_with_error(errno);
288−
289− xsk->umem = ifobject->umem;
290− cfg.rx_size = rxqsize;
269+ xsk->umem = umem;
270+ cfg.rx_size = xsk->rxqsize;
291271 cfg.tx_size = XSK_RING_PROD__DEFAULT_NUM_DESCS;
292272 cfg.libbpf_flags = 0;
293− cfg.xdp_flags = xdp_flags;
294− cfg.bind_flags = xdp_bind_flags;
295−
296− if (test_type != TEST_TYPE_BIDI) {
297− rxr = (ifobject->fv.vector == rx) ? &xsk->rx : NULL;
298− txr = (ifobject->fv.vector == tx) ? &xsk->tx : NULL;
299− } else {
300− rxr = &xsk->rx;
301− txr = &xsk->tx;
302− }
303−
304− ret = xsk_socket__create(&xsk->xsk, ifobject->ifname, idx,
305− ifobject->umem->umem, rxr, txr, &cfg);
306− if (ret)
307− return 1;
273+ cfg.xdp_flags = ifobject->xdp_flags;
274+ cfg.bind_flags = ifobject->bind_flags;
308275
309− ifobject->xsk_arr[idx] = xsk;
310−
311− return 0;
276+ txr = ifobject->tx_on ? &xsk->tx : NULL;
277+ rxr = ifobject->rx_on ? &xsk->rx : NULL;
278+ return xsk_socket__create(&xsk->xsk, ifobject->ifname, qid, umem->umem, rxr, txr, &cfg);
312279 }
313280
314281 static struct option long_options[] = {
@@ -354,45 +321,44 @@ static int switch_namespace(const char *nsname) · 39 unmodified lines
354321 return nsfd;
355322 }
356323
357−static int validate_interfaces(void)
324+static bool validate_interface(struct ifobject *ifobj)
358325 {
359− bool ret = true;
360−
361− for (int i = 0; i < MAX_INTERFACES; i++) {
362− if (!strcmp(ifdict[i]->ifname, "")) {
363− ret = false;
364− ksft_test_result_fail("ERROR: interfaces: -i <int>,<ns> -i <int>,<ns>.");
365− }
366− }
367− return ret;
326+ if (!strcmp(ifobj->ifname, ""))
327+ return false;
328+ return true;
368329 }
369330
370−static void parse_command_line(int argc, char **argv)
331+static void parse_command_line(struct ifobject *ifobj_tx, struct ifobject *ifobj_rx, int argc,
332+ char **argv)
371333 {
372− int option_index, interface_index = 0, c;
334+ struct ifobject *ifobj;
335+ u32 interface_nb = 0;
336+ int option_index, c;
373337
374338 opterr = 0;
375339
376340 for (;;) {
377− c = getopt_long(argc, argv, "i:Dv", long_options, &option_index);
341+ char *sptr, *token;
378342
343+ c = getopt_long(argc, argv, "i:Dv", long_options, &option_index);
379344 if (c == -1)
380345 break;
381346
382347 switch (c) {
383348 case 'i':
384− if (interface_index == MAX_INTERFACES)
349+ if (interface_nb == 0)
350+ ifobj = ifobj_tx;
351+ else if (interface_nb == 1)
352+ ifobj = ifobj_rx;
353+ else
385354 break;
386− char *sptr, *token;
387355
388356 sptr = strndupa(optarg, strlen(optarg));
389− memcpy(ifdict[interface_index]->ifname,
390− strsep(&sptr, ","), MAX_INTERFACE_NAME_CHARS);
357+ memcpy(ifobj->ifname, strsep(&sptr, ","), MAX_INTERFACE_NAME_CHARS);
391358 token = strsep(&sptr, ",");
392359 if (token)
393− memcpy(ifdict[interface_index]->nsname, token,
394− MAX_INTERFACES_NAMESPACE_CHARS);
395− interface_index++;
360+ memcpy(ifobj->nsname, token, MAX_INTERFACES_NAMESPACE_CHARS);
361+ interface_nb++;
396362 break;
397363 case 'D':
398364 opt_pkt_dump = true;
@@ -405,11 +371,78 @@ static void parse_command_line(int argc, char **argv) · 6 unmodified lines
405371 ksft_exit_xfail();
406372 }
407373 }
374+}
408375
409− if (!validate_interfaces()) {
410− usage(basename(argv[0]));
411− ksft_exit_xfail();
376+static void __test_spec_init(struct test_spec *test, struct ifobject *ifobj_tx,
377+ struct ifobject *ifobj_rx)
378+{
379+ u32 i, j;
380+
381+ for (i = 0; i < MAX_INTERFACES; i++) {
382+ struct ifobject *ifobj = i ? ifobj_rx : ifobj_tx;
383+
384+ ifobj->umem = &ifobj->umem_arr[0];
385+ ifobj->xsk = &ifobj->xsk_arr[0];
386+ ifobj->use_poll = false;
387+ ifobj->pkt_stream = test->pkt_stream_default;
388+
389+ if (i == 0) {
390+ ifobj->rx_on = false;
391+ ifobj->tx_on = true;
392+ } else {
393+ ifobj->rx_on = true;
394+ ifobj->tx_on = false;
395+ }
396+
397+ for (j = 0; j < MAX_SOCKETS; j++) {
398+ memset(&ifobj->umem_arr[j], 0, sizeof(ifobj->umem_arr[j]));
399+ memset(&ifobj->xsk_arr[j], 0, sizeof(ifobj->xsk_arr[j]));
400+ ifobj->umem_arr[j].num_frames = DEFAULT_UMEM_BUFFERS;
401+ ifobj->umem_arr[j].frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE;
402+ ifobj->xsk_arr[j].rxqsize = XSK_RING_CONS__DEFAULT_NUM_DESCS;
403+ }
412404 }
405+
406+ test->ifobj_tx = ifobj_tx;
407+ test->ifobj_rx = ifobj_rx;
408+ test->current_step = 0;
409+ test->total_steps = 1;
410+ test->nb_sockets = 1;
411+}
412+
413+static void test_spec_init(struct test_spec *test, struct ifobject *ifobj_tx,
414+ struct ifobject *ifobj_rx, enum test_mode mode)
415+{
416+ struct pkt_stream *pkt_stream;
417+ u32 i;
418+
419+ pkt_stream = test->pkt_stream_default;
420+ memset(test, 0, sizeof(*test));
421+ test->pkt_stream_default = pkt_stream;
422+
423+ for (i = 0; i < MAX_INTERFACES; i++) {
424+ struct ifobject *ifobj = i ? ifobj_rx : ifobj_tx;
425+
426+ ifobj->xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
427+ if (mode == TEST_MODE_SKB)
428+ ifobj->xdp_flags |= XDP_FLAGS_SKB_MODE;
429+ else
430+ ifobj->xdp_flags |= XDP_FLAGS_DRV_MODE;
431+
432+ ifobj->bind_flags = XDP_USE_NEED_WAKEUP | XDP_COPY;
433+ }
434+
435+ __test_spec_init(test, ifobj_tx, ifobj_rx);
436+}
437+
438+static void test_spec_reset(struct test_spec *test)
439+{
440+ __test_spec_init(test, test->ifobj_tx, test->ifobj_rx);
441+}
442+
443+static void test_spec_set_name(struct test_spec *test, const char *name)
444+{
445+ strncpy(test->name, name, MAX_TEST_NAME_SIZE);
413446 }
414447
415448 static struct pkt *pkt_stream_get_pkt(struct pkt_stream *pkt_stream, u32 pkt_nb)
@@ -420,29 +453,105 @@ static struct pkt *pkt_stream_get_pkt(struct pkt_stream *pkt_stream, u32 pkt_nb) · 4 unmodified lines
420453 return &pkt_stream->pkts[pkt_nb];
421454 }
422455
423−static struct pkt_stream *pkt_stream_generate(u32 nb_pkts, u32 pkt_len)
456+static struct pkt *pkt_stream_get_next_rx_pkt(struct pkt_stream *pkt_stream)
457+{
458+ while (pkt_stream->rx_pkt_nb < pkt_stream->nb_pkts) {
459+ if (pkt_stream->pkts[pkt_stream->rx_pkt_nb].valid)
460+ return &pkt_stream->pkts[pkt_stream->rx_pkt_nb++];
461+ pkt_stream->rx_pkt_nb++;
462+ }
463+ return NULL;
464+}
465+
466+static void pkt_stream_delete(struct pkt_stream *pkt_stream)
467+{
468+ free(pkt_stream->pkts);
469+ free(pkt_stream);
470+}
471+
472+static void pkt_stream_restore_default(struct test_spec *test)
473+{
474+ if (test->ifobj_tx->pkt_stream != test->pkt_stream_default) {
475+ pkt_stream_delete(test->ifobj_tx->pkt_stream);
476+ test->ifobj_tx->pkt_stream = test->pkt_stream_default;
477+ }
478+ test->ifobj_rx->pkt_stream = test->pkt_stream_default;
479+}
480+
481+static struct pkt_stream *__pkt_stream_alloc(u32 nb_pkts)
424482 {
425483 struct pkt_stream *pkt_stream;
426− u32 i;
427484
428− pkt_stream = malloc(sizeof(*pkt_stream));
485+ pkt_stream = calloc(1, sizeof(*pkt_stream));
429486 if (!pkt_stream)
430− exit_with_error(ENOMEM);
487+ return NULL;
431488
432489 pkt_stream->pkts = calloc(nb_pkts, sizeof(*pkt_stream->pkts));
433− if (!pkt_stream->pkts)
490+ if (!pkt_stream->pkts) {
491+ free(pkt_stream);
492+ return NULL;
493+ }
494+
495+ pkt_stream->nb_pkts = nb_pkts;
496+ return pkt_stream;
497+}
498+
499+static struct pkt_stream *pkt_stream_generate(struct xsk_umem_info *umem, u32 nb_pkts, u32 pkt_len)
500+{
501+ struct pkt_stream *pkt_stream;
502+ u32 i;
503+
504+ pkt_stream = __pkt_stream_alloc(nb_pkts);
505+ if (!pkt_stream)
434506 exit_with_error(ENOMEM);
435507
436508 pkt_stream->nb_pkts = nb_pkts;
437509 for (i = 0; i < nb_pkts; i++) {
438− pkt_stream->pkts[i].addr = (i % num_frames) * XSK_UMEM__DEFAULT_FRAME_SIZE;
510+ pkt_stream->pkts[i].addr = (i % umem->num_frames) * umem->frame_size +
511+ DEFAULT_OFFSET;
439512 pkt_stream->pkts[i].len = pkt_len;
440513 pkt_stream->pkts[i].payload = i;
514+
515+ if (pkt_len > umem->frame_size)
516+ pkt_stream->pkts[i].valid = false;
517+ else
518+ pkt_stream->pkts[i].valid = true;
441519 }
442520
443521 return pkt_stream;
444522 }
445523
524+static struct pkt_stream *pkt_stream_clone(struct xsk_umem_info *umem,
525+ struct pkt_stream *pkt_stream)
526+{
527+ return pkt_stream_generate(umem, pkt_stream->nb_pkts, pkt_stream->pkts[0].len);
528+}
529+
530+static void pkt_stream_replace(struct test_spec *test, u32 nb_pkts, u32 pkt_len)
531+{
532+ struct pkt_stream *pkt_stream;
533+
534+ pkt_stream = pkt_stream_generate(test->ifobj_tx->umem, nb_pkts, pkt_len);
535+ test->ifobj_tx->pkt_stream = pkt_stream;
536+ test->ifobj_rx->pkt_stream = pkt_stream;
537+}
538+
539+static void pkt_stream_replace_half(struct test_spec *test, u32 pkt_len, u32 offset)
540+{
541+ struct xsk_umem_info *umem = test->ifobj_tx->umem;
542+ struct pkt_stream *pkt_stream;
543+ u32 i;
544+
545+ pkt_stream = pkt_stream_clone(umem, test->pkt_stream_default);
546+ for (i = 0; i < test->pkt_stream_default->nb_pkts; i += 2) {
547+ pkt_stream->pkts[i].addr = (i % umem->num_frames) * umem->frame_size + offset;
548+ pkt_stream->pkts[i].len = pkt_len;
549+ }
550+
551+ test->ifobj_tx->pkt_stream = pkt_stream;
552+ test->ifobj_rx->pkt_stream = pkt_stream;
553+}
554+
446555 static struct pkt *pkt_generate(struct ifobject *ifobject, u32 pkt_nb)
447556 {
448557 struct pkt *pkt = pkt_stream_get_pkt(ifobject->pkt_stream, pkt_nb);
@@ -453,6 +562,8 @@ static struct pkt *pkt_generate(struct ifobject *ifobject, u32 pkt_nb) · 4 unmodified lines
453562
454563 if (!pkt)
455564 return NULL;
565+ if (!pkt->valid || pkt->len < PKT_SIZE)
566+ return pkt;
456567
457568 data = xsk_umem__get_data(ifobject->umem->buffer, pkt->addr);
458569 udp_hdr = (struct udphdr *)(data + sizeof(struct ethhdr) + sizeof(struct iphdr));
@@ -467,6 +578,26 @@ static struct pkt *pkt_generate(struct ifobject *ifobject, u32 pkt_nb) · 8 unmodified lines
467578 return pkt;
468579 }
469580
581+static void pkt_stream_generate_custom(struct test_spec *test, struct pkt *pkts, u32 nb_pkts)
582+{
583+ struct pkt_stream *pkt_stream;
584+ u32 i;
585+
586+ pkt_stream = __pkt_stream_alloc(nb_pkts);
587+ if (!pkt_stream)
588+ exit_with_error(ENOMEM);
589+
590+ test->ifobj_tx->pkt_stream = pkt_stream;
591+ test->ifobj_rx->pkt_stream = pkt_stream;
592+
593+ for (i = 0; i < nb_pkts; i++) {
594+ pkt_stream->pkts[i].addr = pkts[i].addr;
595+ pkt_stream->pkts[i].len = pkts[i].len;
596+ pkt_stream->pkts[i].payload = i;
597+ pkt_stream->pkts[i].valid = pkts[i].valid;
598+ }
599+}
600+
470601 static void pkt_dump(void *pkt, u32 len)
471602 {
472603 char s[INET_ADDRSTRLEN];
@@ -504,9 +635,9 @@ static void pkt_dump(void *pkt, u32 len) · 31 unmodified lines
504635 fprintf(stdout, "---------------------------------------\n");
505636 }
506637
507−static bool is_pkt_valid(struct pkt *pkt, void *buffer, const struct xdp_desc *desc)
638+static bool is_pkt_valid(struct pkt *pkt, void *buffer, u64 addr, u32 len)
508639 {
509− void *data = xsk_umem__get_data(buffer, desc->addr);
640+ void *data = xsk_umem__get_data(buffer, addr);
510641 struct iphdr *iphdr = (struct iphdr *)(data + sizeof(struct ethhdr));
511642
512643 if (!pkt) {
@@ -514,19 +645,24 @@ static bool is_pkt_valid(struct pkt *pkt, void *buffer, const struct xdp_desc *d · 1 unmodified line
514645 return false;
515646 }
516647
648+ if (len < PKT_SIZE) {
649+ /*Do not try to verify packets that are smaller than minimum size. */
650+ return true;
651+ }
652+
653+ if (pkt->len != len) {
654+ ksft_test_result_fail
655+ ("ERROR: [%s] expected length [%d], got length [%d]\n",
656+ __func__, pkt->len, len);
657+ return false;
658+ }
659+
517660 if (iphdr->version == IP_PKT_VER && iphdr->tos == IP_PKT_TOS) {
518661 u32 seqnum = ntohl(*((u32 *)(data + PKT_HDR_SIZE)));
519662
520− if (opt_pkt_dump && test_type != TEST_TYPE_STATS)
663+ if (opt_pkt_dump)
521664 pkt_dump(data, PKT_SIZE);
522665
523− if (pkt->len != desc->len) {
524− ksft_test_result_fail
525− ("ERROR: [%s] expected length [%d], got length [%d]\n",
526− __func__, pkt->len, desc->len);
527− return false;
528− }
529−
530666 if (pkt->payload != seqnum) {
531667 ksft_test_result_fail
532668 ("ERROR: [%s] expected seqnum [%d], got seqnum [%d]\n",
@@ -558,14 +694,20 @@ static void complete_pkts(struct xsk_socket_info *xsk, int batch_size) · 25 unmodified lines
558694 unsigned int rcvd;
559695 u32 idx;
560696
561− if (!xsk->outstanding_tx)
562− return;
563−
564697 if (xsk_ring_prod__needs_wakeup(&xsk->tx))
565698 kick_tx(xsk);
566699
567700 rcvd = xsk_ring_cons__peek(&xsk->umem->cq, batch_size, &idx);
568701 if (rcvd) {
702+ if (rcvd > xsk->outstanding_tx) {
703+ u64 addr = *xsk_ring_cons__comp_addr(&xsk->umem->cq, idx + rcvd - 1);
704+
705+ ksft_test_result_fail("ERROR: [%s] Too many packets completed\n",
706+ __func__);
707+ ksft_print_msg("Last completion address: %llx\n", addr);
708+ return;
709+ }
710+
569711 xsk_ring_cons__release(&xsk->umem->cq, rcvd);
570712 xsk->outstanding_tx -= rcvd;
571713 }
@@ -574,11 +716,10 @@ static void complete_pkts(struct xsk_socket_info *xsk, int batch_size) · 2 unmodified lines
574716 static void receive_pkts(struct pkt_stream *pkt_stream, struct xsk_socket_info *xsk,
575717 struct pollfd *fds)
576718 {
577− u32 idx_rx = 0, idx_fq = 0, rcvd, i, pkt_count = 0;
578− struct pkt *pkt;
719+ struct pkt *pkt = pkt_stream_get_next_rx_pkt(pkt_stream);
720+ u32 idx_rx = 0, idx_fq = 0, rcvd, i;
579721 int ret;
580722
581− pkt = pkt_stream_get_pkt(pkt_stream, pkt_count++);
582723 while (pkt) {
583724 rcvd = xsk_ring_cons__peek(&xsk->rx, BATCH_SIZE, &idx_rx);
584725 if (!rcvd) {
@@ -606,13 +747,21 @@ static void receive_pkts(struct pkt_stream *pkt_stream, struct xsk_socket_info * · 21 unmodified lines
606747 const struct xdp_desc *desc = xsk_ring_cons__rx_desc(&xsk->rx, idx_rx++);
607748 u64 addr = desc->addr, orig;
608749
750+ if (!pkt) {
751+ ksft_test_result_fail("ERROR: [%s] Received too many packets.\n",
752+ __func__);
753+ ksft_print_msg("Last packet has addr: %llx len: %u\n",
754+ addr, desc->len);
755+ return;
756+ }
757+
609758 orig = xsk_umem__extract_addr(addr);
610759 addr = xsk_umem__add_offset_to_addr(addr);
611− if (!is_pkt_valid(pkt, xsk->umem->buffer, desc))
760+ if (!is_pkt_valid(pkt, xsk->umem->buffer, addr, desc->len))
612761 return;
613762
614763 *xsk_ring_prod__fill_addr(&xsk->umem->fq, idx_fq++) = orig;
615− pkt = pkt_stream_get_pkt(pkt_stream, pkt_count++);
764+ pkt = pkt_stream_get_next_rx_pkt(pkt_stream);
616765 }
617766
618767 xsk_ring_prod__submit(&xsk->umem->fq, rcvd);
@@ -623,7 +772,7 @@ static void receive_pkts(struct pkt_stream *pkt_stream, struct xsk_socket_info * · 4 unmodified lines
623772 static u32 __send_pkts(struct ifobject *ifobject, u32 pkt_nb)
624773 {
625774 struct xsk_socket_info *xsk = ifobject->xsk;
626− u32 i, idx;
775+ u32 i, idx, valid_pkts = 0;
627776
628777 while (xsk_ring_prod__reserve(&xsk->tx, BATCH_SIZE, &idx) < BATCH_SIZE)
629778 complete_pkts(xsk, BATCH_SIZE);
@@ -638,14 +787,13 @@ static u32 __send_pkts(struct ifobject *ifobject, u32 pkt_nb) · 8 unmodified lines
638787 tx_desc->addr = pkt->addr;
639788 tx_desc->len = pkt->len;
640789 pkt_nb++;
790+ if (pkt->valid)
791+ valid_pkts++;
641792 }
642793
643794 xsk_ring_prod__submit(&xsk->tx, i);
644− if (stat_test_type != STAT_TEST_TX_INVALID)
645− xsk->outstanding_tx += i;
646− else if (xsk_ring_prod__needs_wakeup(&xsk->tx))
647− kick_tx(xsk);
648− complete_pkts(xsk, i);
795+ xsk->outstanding_tx += valid_pkts;
796+ complete_pkts(xsk, BATCH_SIZE);
649797
650798 return i;
651799 }
@@ -658,23 +806,23 @@ static void wait_for_tx_completion(struct xsk_socket_info *xsk) · 6 unmodified lines
658806
659807 static void send_pkts(struct ifobject *ifobject)
660808 {
661− struct pollfd fds[MAX_SOCKS] = { };
809+ struct pollfd fds = { };
662810 u32 pkt_cnt = 0;
663811
664− fds[0].fd = xsk_socket__fd(ifobject->xsk->xsk);
665− fds[0].events = POLLOUT;
812+ fds.fd = xsk_socket__fd(ifobject->xsk->xsk);
813+ fds.events = POLLOUT;
666814
667815 while (pkt_cnt < ifobject->pkt_stream->nb_pkts) {
668816 u32 sent;
669817
670− if (test_type == TEST_TYPE_POLL) {
818+ if (ifobject->use_poll) {
671819 int ret;
672820
673− ret = poll(fds, 1, POLL_TMOUT);
821+ ret = poll(&fds, 1, POLL_TMOUT);
674822 if (ret <= 0)
675823 continue;
676824
677− if (!(fds[0].revents & POLLOUT))
825+ if (!(fds.revents & POLLOUT))
678826 continue;
679827 }
680828
@@ -698,7 +846,7 @@ static bool rx_stats_are_valid(struct ifobject *ifobject) · 17 unmodified lines
698846 optlen = sizeof(stats);
699847 err = getsockopt(fd, SOL_XDP, XDP_STATISTICS, &stats, &optlen);
700848 if (err) {
701− ksft_test_result_fail("ERROR: [%s] getsockopt(XDP_STATISTICS) error %u %s\n",
849+ ksft_test_result_fail("ERROR Rx: [%s] getsockopt(XDP_STATISTICS) error %u %s\n",
702850 __func__, -err, strerror(-err));
703851 return true;
704852 }
@@ -739,7 +887,7 @@ static void tx_stats_validate(struct ifobject *ifobject) · 34 unmodified lines
739887 optlen = sizeof(stats);
740888 err = getsockopt(fd, SOL_XDP, XDP_STATISTICS, &stats, &optlen);
741889 if (err) {
742− ksft_test_result_fail("ERROR: [%s] getsockopt(XDP_STATISTICS) error %u %s\n",
890+ ksft_test_result_fail("ERROR Tx: [%s] getsockopt(XDP_STATISTICS) error %u %s\n",
743891 __func__, -err, strerror(-err));
744892 return;
745893 }
@@ -751,71 +899,63 @@ static void tx_stats_validate(struct ifobject *ifobject) · 5 unmodified lines
751899 __func__, stats.tx_invalid_descs, ifobject->pkt_stream->nb_pkts);
752900 }
753901
754−static void thread_common_ops(struct ifobject *ifobject, void *bufs)
902+static void thread_common_ops(struct test_spec *test, struct ifobject *ifobject)
755903 {
756− u64 umem_sz = num_frames * XSK_UMEM__DEFAULT_FRAME_SIZE;
757904 int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
758− size_t mmap_sz = umem_sz;
759− int ctr = 0;
760− int ret;
905+ u32 i;
761906
762907 ifobject->ns_fd = switch_namespace(ifobject->nsname);
763908
764− if (test_type == TEST_TYPE_BPF_RES)
765− mmap_sz *= 2;
909+ if (ifobject->umem->unaligned_mode)
910+ mmap_flags |= MAP_HUGETLB;
766911
767− bufs = mmap(NULL, mmap_sz, PROT_READ | PROT_WRITE, mmap_flags, -1, 0);
768− if (bufs == MAP_FAILED)
769− exit_with_error(errno);
912+ for (i = 0; i < test->nb_sockets; i++) {
913+ u64 umem_sz = ifobject->umem->num_frames * ifobject->umem->frame_size;
914+ u32 ctr = 0;
915+ void *bufs;
770916
771− while (ctr++ < SOCK_RECONF_CTR) {
772− xsk_configure_umem(ifobject, bufs, umem_sz, 0);
773− ifobject->umem = ifobject->umem_arr[0];
774− ret = xsk_configure_socket(ifobject, 0);
775− if (!ret)
776− break;
917+ bufs = mmap(NULL, umem_sz, PROT_READ | PROT_WRITE, mmap_flags, -1, 0);
918+ if (bufs == MAP_FAILED)
919+ exit_with_error(errno);
777920
778− /* Retry Create Socket if it fails as xsk_socket__create() is asynchronous */
779− usleep(USLEEP_MAX);
780− if (ctr >= SOCK_RECONF_CTR)
781− exit_with_error(-ret);
782− }
921+ while (ctr++ < SOCK_RECONF_CTR) {
922+ int ret;
783923
784− ifobject->umem = ifobject->umem_arr[0];
785− ifobject->xsk = ifobject->xsk_arr[0];
924+ ret = xsk_configure_umem(&ifobject->umem_arr[i], bufs, umem_sz);
925+ if (ret)
926+ exit_with_error(-ret);
786927
787− if (test_type == TEST_TYPE_BPF_RES) {
788− xsk_configure_umem(ifobject, (u8 *)bufs + umem_sz, umem_sz, 1);
789− ifobject->umem = ifobject->umem_arr[1];
790− ret = xsk_configure_socket(ifobject, 1);
791− }
928+ ret = xsk_configure_socket(&ifobject->xsk_arr[i], &ifobject->umem_arr[i],
929+ ifobject, i);
930+ if (!ret)
931+ break;
792932
793− ifobject->umem = ifobject->umem_arr[0];
794− ifobject->xsk = ifobject->xsk_arr[0];
795− print_verbose("Interface [%s] vector [%s]\n",
796− ifobject->ifname, ifobject->fv.vector == tx ? "Tx" : "Rx");
797−}
933+ /* Retry if it fails as xsk_socket__create() is asynchronous */
934+ if (ctr >= SOCK_RECONF_CTR)
935+ exit_with_error(-ret);
936+ usleep(USLEEP_MAX);
937+ }
938+ }
798939
799−static bool testapp_is_test_two_stepped(void)
800−{
801− return (test_type != TEST_TYPE_BIDI && test_type != TEST_TYPE_BPF_RES) || second_step;
940+ ifobject->umem = &ifobject->umem_arr[0];
941+ ifobject->xsk = &ifobject->xsk_arr[0];
802942 }
803943
804944 static void testapp_cleanup_xsk_res(struct ifobject *ifobj)
805945 {
806− if (testapp_is_test_two_stepped()) {
807− xsk_socket__delete(ifobj->xsk->xsk);
808− (void)xsk_umem__delete(ifobj->umem->umem);
809− }
946+ print_verbose("Destroying socket\n");
947+ xsk_socket__delete(ifobj->xsk->xsk);
948+ munmap(ifobj->umem->buffer, ifobj->umem->num_frames * ifobj->umem->frame_size);
949+ xsk_umem__delete(ifobj->umem->umem);
810950 }
811951
812952 static void *worker_testapp_validate_tx(void *arg)
813953 {
814− struct ifobject *ifobject = (struct ifobject *)arg;
815− void *bufs = NULL;
954+ struct test_spec *test = (struct test_spec *)arg;
955+ struct ifobject *ifobject = test->ifobj_tx;
816956
817− if (!second_step)
818− thread_common_ops(ifobject, bufs);
957+ if (test->current_step == 1)
958+ thread_common_ops(test, ifobject);
819959
820960 print_verbose("Sending %d packets on interface %s\n", ifobject->pkt_stream->nb_pkts,
821961 ifobject->ifname);
@@ -824,24 +964,50 @@ static void *worker_testapp_validate_tx(void *arg) · 2 unmodified lines
824964 if (stat_test_type == STAT_TEST_TX_INVALID)
825965 tx_stats_validate(ifobject);
826966
827− testapp_cleanup_xsk_res(ifobject);
967+ if (test->total_steps == test->current_step)
968+ testapp_cleanup_xsk_res(ifobject);
828969 pthread_exit(NULL);
829970 }
830971
972+static void xsk_populate_fill_ring(struct xsk_umem_info *umem, struct pkt_stream *pkt_stream)
973+{
974+ u32 idx = 0, i;
975+ int ret;
976+
977+ ret = xsk_ring_prod__reserve(&umem->fq, XSK_RING_PROD__DEFAULT_NUM_DESCS, &idx);
978+ if (ret != XSK_RING_PROD__DEFAULT_NUM_DESCS)
979+ exit_with_error(ENOSPC);
980+ for (i = 0; i < XSK_RING_PROD__DEFAULT_NUM_DESCS; i++) {
981+ u64 addr;
982+
983+ if (pkt_stream->use_addr_for_fill) {
984+ struct pkt *pkt = pkt_stream_get_pkt(pkt_stream, i);
985+
986+ if (!pkt)
987+ break;
988+ addr = pkt->addr;
989+ } else {
990+ addr = (i % umem->num_frames) * umem->frame_size + DEFAULT_OFFSET;
991+ }
992+
993+ *xsk_ring_prod__fill_addr(&umem->fq, idx++) = addr;
994+ }
995+ xsk_ring_prod__submit(&umem->fq, XSK_RING_PROD__DEFAULT_NUM_DESCS);
996+}
997+
831998 static void *worker_testapp_validate_rx(void *arg)
832999 {
833− struct ifobject *ifobject = (struct ifobject *)arg;
834− struct pollfd fds[MAX_SOCKS] = { };
835− void *bufs = NULL;
1000+ struct test_spec *test = (struct test_spec *)arg;
1001+ struct ifobject *ifobject = test->ifobj_rx;
1002+ struct pollfd fds = { };
8361003
837− if (!second_step)
838− thread_common_ops(ifobject, bufs);
1004+ if (test->current_step == 1)
1005+ thread_common_ops(test, ifobject);
8391006
840− if (stat_test_type != STAT_TEST_RX_FILL_EMPTY)
841− xsk_populate_fill_ring(ifobject->umem);
1007+ xsk_populate_fill_ring(ifobject->umem, ifobject->pkt_stream);
8421008
843− fds[0].fd = xsk_socket__fd(ifobject->xsk->xsk);
844− fds[0].events = POLLIN;
1009+ fds.fd = xsk_socket__fd(ifobject->xsk->xsk);
1010+ fds.events = POLLIN;
8451011
8461012 pthread_barrier_wait(&barr);
8471013
@@ -849,151 +1015,219 @@ static void *worker_testapp_validate_rx(void *arg) · 1 unmodified line
8491015 while (!rx_stats_are_valid(ifobject))
8501016 continue;
8511017 else
852− receive_pkts(ifobject->pkt_stream, ifobject->xsk, fds);
853−
854− if (test_type == TEST_TYPE_TEARDOWN)
855− print_verbose("Destroying socket\n");
1018+ receive_pkts(ifobject->pkt_stream, ifobject->xsk, &fds);
8561019
857− testapp_cleanup_xsk_res(ifobject);
1020+ if (test->total_steps == test->current_step)
1021+ testapp_cleanup_xsk_res(ifobject);
8581022 pthread_exit(NULL);
8591023 }
8601024
861−static void testapp_validate(void)
1025+static void testapp_validate_traffic(struct test_spec *test)
8621026 {
863− bool bidi = test_type == TEST_TYPE_BIDI;
864− bool bpf = test_type == TEST_TYPE_BPF_RES;
865− struct pkt_stream *pkt_stream;
1027+ struct ifobject *ifobj_tx = test->ifobj_tx;
1028+ struct ifobject *ifobj_rx = test->ifobj_rx;
1029+ pthread_t t0, t1;
8661030
8671031 if (pthread_barrier_init(&barr, NULL, 2))
8681032 exit_with_error(errno);
8691033
870− if (stat_test_type == STAT_TEST_TX_INVALID)
871− pkt_stream = pkt_stream_generate(DEFAULT_PKT_CNT, XSK_UMEM__INVALID_FRAME_SIZE);
872− else
873− pkt_stream = pkt_stream_generate(DEFAULT_PKT_CNT, PKT_SIZE);
874− ifdict_tx->pkt_stream = pkt_stream;
875− ifdict_rx->pkt_stream = pkt_stream;
1034+ test->current_step++;
8761035
8771036 /*Spawn RX thread */
878− pthread_create(&t0, NULL, ifdict_rx->func_ptr, ifdict_rx);
1037+ pthread_create(&t0, NULL, ifobj_rx->func_ptr, test);
8791038
8801039 pthread_barrier_wait(&barr);
8811040 if (pthread_barrier_destroy(&barr))
8821041 exit_with_error(errno);
8831042
8841043 /*Spawn TX thread */
885− pthread_create(&t1, NULL, ifdict_tx->func_ptr, ifdict_tx);
1044+ pthread_create(&t1, NULL, ifobj_tx->func_ptr, test);
8861045
8871046 pthread_join(t1, NULL);
8881047 pthread_join(t0, NULL);
889−
890− if (!(test_type == TEST_TYPE_TEARDOWN) && !bidi && !bpf && !(test_type == TEST_TYPE_STATS))
891− print_ksft_result();
8921048 }
8931049
894−static void testapp_teardown(void)
1050+static void testapp_teardown(struct test_spec *test)
8951051 {
8961052 int i;
8971053
1054+ test_spec_set_name(test, "TEARDOWN");
8981055 for (i = 0; i < MAX_TEARDOWN_ITER; i++) {
899− print_verbose("Creating socket\n");
900− testapp_validate();
1056+ testapp_validate_traffic(test);
1057+ test_spec_reset(test);
9011058 }
902−
903− print_ksft_result();
9041059 }
9051060
906−static void swap_vectors(struct ifobject *ifobj1, struct ifobject *ifobj2)
1061+static void swap_directions(struct ifobject **ifobj1, struct ifobject **ifobj2)
9071062 {
908− void *(*tmp_func_ptr)(void *) = ifobj1->func_ptr;
909− enum fvector tmp_vector = ifobj1->fv.vector;
1063+ thread_func_t tmp_func_ptr = (*ifobj1)->func_ptr;
1064+ struct ifobject *tmp_ifobj = (*ifobj1);
9101065
911− ifobj1->func_ptr = ifobj2->func_ptr;
912− ifobj1->fv.vector = ifobj2->fv.vector;
1066+ (*ifobj1)->func_ptr = (*ifobj2)->func_ptr;
1067+ (*ifobj2)->func_ptr = tmp_func_ptr;
9131068
914− ifobj2->func_ptr = tmp_func_ptr;
915− ifobj2->fv.vector = tmp_vector;
916−
917− ifdict_tx = ifobj1;
918− ifdict_rx = ifobj2;
1069+ *ifobj1 = *ifobj2;
1070+ *ifobj2 = tmp_ifobj;
9191071 }
9201072
921−static void testapp_bidi(void)
1073+static void testapp_bidi(struct test_spec *test)
9221074 {
923− for (int i = 0; i < MAX_BIDI_ITER; i++) {
924− print_verbose("Creating socket\n");
925− testapp_validate();
926− if (!second_step) {
927− print_verbose("Switching Tx/Rx vectors\n");
928− swap_vectors(ifdict[1], ifdict[0]);
929− }
930− second_step = true;
931− }
1075+ test_spec_set_name(test, "BIDIRECTIONAL");
1076+ test->ifobj_tx->rx_on = true;
1077+ test->ifobj_rx->tx_on = true;
1078+ test->total_steps = 2;
1079+ testapp_validate_traffic(test);
9321080
933− swap_vectors(ifdict[0], ifdict[1]);
1081+ print_verbose("Switching Tx/Rx vectors\n");
1082+ swap_directions(&test->ifobj_rx, &test->ifobj_tx);
1083+ testapp_validate_traffic(test);
9341084
935− print_ksft_result();
1085+ swap_directions(&test->ifobj_rx, &test->ifobj_tx);
9361086 }
9371087
938−static void swap_xsk_res(void)
1088+static void swap_xsk_resources(struct ifobject *ifobj_tx, struct ifobject *ifobj_rx)
9391089 {
940− xsk_socket__delete(ifdict_tx->xsk->xsk);
941− xsk_umem__delete(ifdict_tx->umem->umem);
942− xsk_socket__delete(ifdict_rx->xsk->xsk);
943− xsk_umem__delete(ifdict_rx->umem->umem);
944− ifdict_tx->umem = ifdict_tx->umem_arr[1];
945− ifdict_tx->xsk = ifdict_tx->xsk_arr[1];
946− ifdict_rx->umem = ifdict_rx->umem_arr[1];
947− ifdict_rx->xsk = ifdict_rx->xsk_arr[1];
1090+ xsk_socket__delete(ifobj_tx->xsk->xsk);
1091+ xsk_umem__delete(ifobj_tx->umem->umem);
1092+ xsk_socket__delete(ifobj_rx->xsk->xsk);
1093+ xsk_umem__delete(ifobj_rx->umem->umem);
1094+ ifobj_tx->umem = &ifobj_tx->umem_arr[1];
1095+ ifobj_tx->xsk = &ifobj_tx->xsk_arr[1];
1096+ ifobj_rx->umem = &ifobj_rx->umem_arr[1];
1097+ ifobj_rx->xsk = &ifobj_rx->xsk_arr[1];
9481098 }
9491099
950−static void testapp_bpf_res(void)
1100+static void testapp_bpf_res(struct test_spec *test)
9511101 {
952− int i;
1102+ test_spec_set_name(test, "BPF_RES");
1103+ test->total_steps = 2;
1104+ test->nb_sockets = 2;
1105+ testapp_validate_traffic(test);
9531106
954− for (i = 0; i < MAX_BPF_ITER; i++) {
955− print_verbose("Creating socket\n");
956− testapp_validate();
957− if (!second_step)
958− swap_xsk_res();
959− second_step = true;
960− }
961−
962− print_ksft_result();
1107+ swap_xsk_resources(test->ifobj_tx, test->ifobj_rx);
1108+ testapp_validate_traffic(test);
9631109 }
9641110
965−static void testapp_stats(void)
1111+static void testapp_stats(struct test_spec *test)
9661112 {
967− for (int i = 0; i < STAT_TEST_TYPE_MAX; i++) {
968− stat_test_type = i;
1113+ int i;
9691114
970− /* reset defaults */
971− rxqsize = XSK_RING_CONS__DEFAULT_NUM_DESCS;
972− frame_headroom = XSK_UMEM__DEFAULT_FRAME_HEADROOM;
1115+ for (i = 0; i < STAT_TEST_TYPE_MAX; i++) {
1116+ test_spec_reset(test);
1117+ stat_test_type = i;
9731118
9741119 switch (stat_test_type) {
9751120 case STAT_TEST_RX_DROPPED:
976− frame_headroom = XSK_UMEM__DEFAULT_FRAME_SIZE -
977− XDP_PACKET_HEADROOM - 1;
1121+ test_spec_set_name(test, "STAT_RX_DROPPED");
1122+ test->ifobj_rx->umem->frame_headroom = test->ifobj_rx->umem->frame_size -
1123+ XDP_PACKET_HEADROOM - 1;
1124+ testapp_validate_traffic(test);
9781125 break;
9791126 case STAT_TEST_RX_FULL:
980− rxqsize = RX_FULL_RXQSIZE;
1127+ test_spec_set_name(test, "STAT_RX_FULL");
1128+ test->ifobj_rx->xsk->rxqsize = RX_FULL_RXQSIZE;
1129+ testapp_validate_traffic(test);
9811130 break;
9821131 case STAT_TEST_TX_INVALID:
983− continue;
1132+ test_spec_set_name(test, "STAT_TX_INVALID");
1133+ pkt_stream_replace(test, DEFAULT_PKT_CNT, XSK_UMEM__INVALID_FRAME_SIZE);
1134+ testapp_validate_traffic(test);
1135+
1136+ pkt_stream_restore_default(test);
1137+ break;
1138+ case STAT_TEST_RX_FILL_EMPTY:
1139+ test_spec_set_name(test, "STAT_RX_FILL_EMPTY");
1140+ test->ifobj_rx->pkt_stream = pkt_stream_generate(test->ifobj_rx->umem, 0,
1141+ MIN_PKT_SIZE);
1142+ if (!test->ifobj_rx->pkt_stream)
1143+ exit_with_error(ENOMEM);
1144+ test->ifobj_rx->pkt_stream->use_addr_for_fill = true;
1145+ testapp_validate_traffic(test);
1146+
1147+ pkt_stream_restore_default(test);
1148+ break;
9841149 default:
9851150 break;
9861151 }
987− testapp_validate();
9881152 }
9891153
990− print_ksft_result();
1154+ /* To only see the whole stat set being completed unless an individual test fails. */
1155+ test_spec_set_name(test, "STATS");
1156+}
1157+
1158+/* Simple test */
1159+static bool hugepages_present(struct ifobject *ifobject)
1160+{
1161+ const size_t mmap_sz = 2 * ifobject->umem->num_frames * ifobject->umem->frame_size;
1162+ void *bufs;
1163+
1164+ bufs = mmap(NULL, mmap_sz, PROT_READ | PROT_WRITE,
1165+ MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_HUGETLB, -1, 0);
1166+ if (bufs == MAP_FAILED)
1167+ return false;
1168+
1169+ munmap(bufs, mmap_sz);
1170+ return true;
1171+}
1172+
1173+static bool testapp_unaligned(struct test_spec *test)
1174+{
1175+ if (!hugepages_present(test->ifobj_tx)) {
1176+ ksft_test_result_skip("No 2M huge pages present.\n");
1177+ return false;
1178+ }
1179+
1180+ test_spec_set_name(test, "UNALIGNED_MODE");
1181+ test->ifobj_tx->umem->unaligned_mode = true;
1182+ test->ifobj_rx->umem->unaligned_mode = true;
1183+ /* Let half of the packets straddle a buffer boundrary */
1184+ pkt_stream_replace_half(test, PKT_SIZE, test->ifobj_tx->umem->frame_size - 32);
1185+ test->ifobj_rx->pkt_stream->use_addr_for_fill = true;
1186+ testapp_validate_traffic(test);
1187+
1188+ pkt_stream_restore_default(test);
1189+ return true;
1190+}
1191+
1192+static void testapp_invalid_desc(struct test_spec *test)
1193+{
1194+ struct pkt pkts[] = {
1195+ /* Zero packet length at address zero allowed */
1196+ {0, 0, 0, true},
1197+ /* Zero packet length allowed */
1198+ {0x1000, 0, 0, true},
1199+ /* Straddling the start of umem */
1200+ {-2, PKT_SIZE, 0, false},
1201+ /* Packet too large */
1202+ {0x2000, XSK_UMEM__INVALID_FRAME_SIZE, 0, false},
1203+ /* After umem ends */
1204+ {UMEM_SIZE, PKT_SIZE, 0, false},
1205+ /* Straddle the end of umem */
1206+ {UMEM_SIZE - PKT_SIZE / 2, PKT_SIZE, 0, false},
1207+ /* Straddle a page boundrary */
1208+ {0x3000 - PKT_SIZE / 2, PKT_SIZE, 0, false},
1209+ /* Straddle a 2K boundrary */
1210+ {0x3800 - PKT_SIZE / 2, PKT_SIZE, 0, true},
1211+ /* Valid packet for synch so that something is received */
1212+ {0x4000, PKT_SIZE, 0, true}};
1213+
1214+ if (test->ifobj_tx->umem->unaligned_mode) {
1215+ /* Crossing a page boundrary allowed */
1216+ pkts[6].valid = true;
1217+ }
1218+ if (test->ifobj_tx->umem->frame_size == XSK_UMEM__DEFAULT_FRAME_SIZE / 2) {
1219+ /* Crossing a 2K frame size boundrary not allowed */
1220+ pkts[7].valid = false;
1221+ }
1222+
1223+ pkt_stream_generate_custom(test, pkts, ARRAY_SIZE(pkts));
1224+ testapp_validate_traffic(test);
1225+ pkt_stream_restore_default(test);
9911226 }
9921227
993−static void init_iface(struct ifobject *ifobj, const char *dst_mac,
994− const char *src_mac, const char *dst_ip,
995− const char *src_ip, const u16 dst_port,
996− const u16 src_port, enum fvector vector)
1228+static void init_iface(struct ifobject *ifobj, const char *dst_mac, const char *src_mac,
1229+ const char *dst_ip, const char *src_ip, const u16 dst_port,
1230+ const u16 src_port, thread_func_t func_ptr)
9971231 {
9981232 struct in_addr ip;
9991233
@@ -1009,58 +1243,73 @@ static void init_iface(struct ifobject *ifobj, const char *dst_mac, · 9 unmodified lines
10091243 ifobj->dst_port = dst_port;
10101244 ifobj->src_port = src_port;
10111245
1012− if (vector == tx) {
1013− ifobj->fv.vector = tx;
1014− ifobj->func_ptr = worker_testapp_validate_tx;
1015− ifdict_tx = ifobj;
1016− } else {
1017− ifobj->fv.vector = rx;
1018− ifobj->func_ptr = worker_testapp_validate_rx;
1019− ifdict_rx = ifobj;
1020− }
1246+ ifobj->func_ptr = func_ptr;
10211247 }
10221248
1023−static void run_pkt_test(int mode, int type)
1249+static void run_pkt_test(struct test_spec *test, enum test_mode mode, enum test_type type)
10241250 {
10251251 test_type = type;
10261252
10271253 /* reset defaults after potential previous test */
1028− xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
1029− second_step = 0;
10301254 stat_test_type = -1;
1031− rxqsize = XSK_RING_CONS__DEFAULT_NUM_DESCS;
1032− frame_headroom = XSK_UMEM__DEFAULT_FRAME_HEADROOM;
1033−
1034− configured_mode = mode;
1035−
1036− switch (mode) {
1037− case (TEST_MODE_SKB):
1038− xdp_flags |= XDP_FLAGS_SKB_MODE;
1039− break;
1040− case (TEST_MODE_DRV):
1041− xdp_flags |= XDP_FLAGS_DRV_MODE;
1042− break;
1043− default:
1044− break;
1045− }
10461255
10471256 switch (test_type) {
10481257 case TEST_TYPE_STATS:
1049− testapp_stats();
1258+ testapp_stats(test);
10501259 break;
10511260 case TEST_TYPE_TEARDOWN:
1052− testapp_teardown();
1261+ testapp_teardown(test);
10531262 break;
10541263 case TEST_TYPE_BIDI:
1055− testapp_bidi();
1264+ testapp_bidi(test);
10561265 break;
10571266 case TEST_TYPE_BPF_RES:
1058− testapp_bpf_res();
1267+ testapp_bpf_res(test);
1268+ break;
1269+ case TEST_TYPE_RUN_TO_COMPLETION:
1270+ test_spec_set_name(test, "RUN_TO_COMPLETION");
1271+ testapp_validate_traffic(test);
1272+ break;
1273+ case TEST_TYPE_RUN_TO_COMPLETION_2K_FRAME:
1274+ test_spec_set_name(test, "RUN_TO_COMPLETION_2K_FRAME_SIZE");
1275+ test->ifobj_tx->umem->frame_size = 2048;
1276+ test->ifobj_rx->umem->frame_size = 2048;
1277+ pkt_stream_replace(test, DEFAULT_PKT_CNT, MIN_PKT_SIZE);
1278+ testapp_validate_traffic(test);
1279+
1280+ pkt_stream_restore_default(test);
1281+ break;
1282+ case TEST_TYPE_POLL:
1283+ test->ifobj_tx->use_poll = true;
1284+ test->ifobj_rx->use_poll = true;
1285+ test_spec_set_name(test, "POLL");
1286+ testapp_validate_traffic(test);
1287+ break;
1288+ case TEST_TYPE_ALIGNED_INV_DESC:
1289+ test_spec_set_name(test, "ALIGNED_INV_DESC");
1290+ testapp_invalid_desc(test);
1291+ break;
1292+ case TEST_TYPE_ALIGNED_INV_DESC_2K_FRAME:
1293+ test_spec_set_name(test, "ALIGNED_INV_DESC_2K_FRAME_SIZE");
1294+ test->ifobj_tx->umem->frame_size = 2048;
1295+ test->ifobj_rx->umem->frame_size = 2048;
1296+ testapp_invalid_desc(test);
1297+ break;
1298+ case TEST_TYPE_UNALIGNED_INV_DESC:
1299+ test_spec_set_name(test, "UNALIGNED_INV_DESC");
1300+ test->ifobj_tx->umem->unaligned_mode = true;
1301+ test->ifobj_rx->umem->unaligned_mode = true;
1302+ testapp_invalid_desc(test);
1303+ break;
1304+ case TEST_TYPE_UNALIGNED:
1305+ if (!testapp_unaligned(test))
1306+ return;
10591307 break;
10601308 default:
1061− testapp_validate();
10621309 break;
10631310 }
1311+
1312+ print_ksft_result(test);
10641313 }
10651314
10661315 static struct ifobject *ifobject_create(void)
@@ -1071,11 +1320,11 @@ static struct ifobject *ifobject_create(void) · 4 unmodified lines
10711320 if (!ifobj)
10721321 return NULL;
10731322
1074− ifobj->xsk_arr = calloc(2, sizeof(struct xsk_socket_info *));
1323+ ifobj->xsk_arr = calloc(MAX_SOCKETS, sizeof(*ifobj->xsk_arr));
10751324 if (!ifobj->xsk_arr)
10761325 goto out_xsk_arr;
10771326
1078− ifobj->umem_arr = calloc(2, sizeof(struct xsk_umem_info *));
1327+ ifobj->umem_arr = calloc(MAX_SOCKETS, sizeof(*ifobj->umem_arr));
10791328 if (!ifobj->umem_arr)
10801329 goto out_umem_arr;
10811330
@@ -1098,34 +1347,53 @@ static void ifobject_delete(struct ifobject *ifobj) · 16 unmodified lines
10981347 int main(int argc, char **argv)
10991348 {
11001349 struct rlimit _rlim = { RLIM_INFINITY, RLIM_INFINITY };
1101− int i, j;
1350+ struct pkt_stream *pkt_stream_default;
1351+ struct ifobject *ifobj_tx, *ifobj_rx;
1352+ struct test_spec test;
1353+ u32 i, j;
11021354
11031355 if (setrlimit(RLIMIT_MEMLOCK, &_rlim))
11041356 exit_with_error(errno);
11051357
1106− for (i = 0; i < MAX_INTERFACES; i++) {
1107− ifdict[i] = ifobject_create();
1108− if (!ifdict[i])
1109− exit_with_error(ENOMEM);
1110− }
1358+ ifobj_tx = ifobject_create();
1359+ if (!ifobj_tx)
1360+ exit_with_error(ENOMEM);
1361+ ifobj_rx = ifobject_create();
1362+ if (!ifobj_rx)
1363+ exit_with_error(ENOMEM);
11111364
11121365 setlocale(LC_ALL, "");
11131366
1114− parse_command_line(argc, argv);
1367+ parse_command_line(ifobj_tx, ifobj_rx, argc, argv);
11151368
1116− init_iface(ifdict[tx], MAC1, MAC2, IP1, IP2, UDP_PORT1, UDP_PORT2, tx);
1117− init_iface(ifdict[rx], MAC2, MAC1, IP2, IP1, UDP_PORT2, UDP_PORT1, rx);
1369+ if (!validate_interface(ifobj_tx) || !validate_interface(ifobj_rx)) {
1370+ usage(basename(argv[0]));
1371+ ksft_exit_xfail();
1372+ }
1373+
1374+ init_iface(ifobj_tx, MAC1, MAC2, IP1, IP2, UDP_PORT1, UDP_PORT2,
1375+ worker_testapp_validate_tx);
1376+ init_iface(ifobj_rx, MAC2, MAC1, IP2, IP1, UDP_PORT2, UDP_PORT1,
1377+ worker_testapp_validate_rx);
1378+
1379+ test_spec_init(&test, ifobj_tx, ifobj_rx, 0);
1380+ pkt_stream_default = pkt_stream_generate(ifobj_tx->umem, DEFAULT_PKT_CNT, PKT_SIZE);
1381+ if (!pkt_stream_default)
1382+ exit_with_error(ENOMEM);
1383+ test.pkt_stream_default = pkt_stream_default;
11181384
11191385 ksft_set_plan(TEST_MODE_MAX * TEST_TYPE_MAX);
11201386
11211387 for (i = 0; i < TEST_MODE_MAX; i++)
11221388 for (j = 0; j < TEST_TYPE_MAX; j++) {
1123− run_pkt_test(i, j);
1389+ test_spec_init(&test, ifobj_tx, ifobj_rx, i);
1390+ run_pkt_test(&test, i, j);
11241391 usleep(USLEEP_MAX);
11251392 }
11261393
1127− for (i = 0; i < MAX_INTERFACES; i++)
1128− ifobject_delete(ifdict[i]);
1394+ pkt_stream_delete(pkt_stream_default);
1395+ ifobject_delete(ifobj_tx);
1396+ ifobject_delete(ifobj_rx);
11291397
11301398 ksft_exit_pass();
11311399 return 0;
tools/testing/selftests/bpf/xdpxceiver.h+38−28
@@ -20,10 +20,9 @@ · 19 unmodified lines
2020 #define MAX_INTERFACES 2
2121 #define MAX_INTERFACE_NAME_CHARS 7
2222 #define MAX_INTERFACES_NAMESPACE_CHARS 10
23−#define MAX_SOCKS 1
23+#define MAX_SOCKETS 2
24+#define MAX_TEST_NAME_SIZE 32
2425 #define MAX_TEARDOWN_ITER 10
25−#define MAX_BIDI_ITER 2
26−#define MAX_BPF_ITER 2
2726 #define PKT_HDR_SIZE (sizeof(struct ethhdr) + sizeof(struct iphdr) + \
2827 sizeof(struct udphdr))
2928 #define MIN_PKT_SIZE 64
@@ -39,7 +38,10 @@ · 9 unmodified lines
3938 #define BATCH_SIZE 8
4039 #define POLL_TMOUT 1000
4140 #define DEFAULT_PKT_CNT (4 * 1024)
41+#define DEFAULT_UMEM_BUFFERS (DEFAULT_PKT_CNT / 4)
42+#define UMEM_SIZE (DEFAULT_UMEM_BUFFERS * XSK_UMEM__DEFAULT_FRAME_SIZE)
4243 #define RX_FULL_RXQSIZE 32
44+#define DEFAULT_OFFSET 256
4345 #define XSK_UMEM__INVALID_FRAME_SIZE (XSK_UMEM__DEFAULT_FRAME_SIZE + 1)
4446
4547 #define print_verbose(x...) do { if (opt_verbose) ksft_print_msg(x); } while (0)
@@ -51,8 +53,13 @@ enum test_mode { · 5 unmodified lines
5153 };
5254
5355 enum test_type {
54− TEST_TYPE_NOPOLL,
56+ TEST_TYPE_RUN_TO_COMPLETION,
57+ TEST_TYPE_RUN_TO_COMPLETION_2K_FRAME,
5558 TEST_TYPE_POLL,
59+ TEST_TYPE_UNALIGNED,
60+ TEST_TYPE_ALIGNED_INV_DESC,
61+ TEST_TYPE_ALIGNED_INV_DESC_2K_FRAME,
62+ TEST_TYPE_UNALIGNED_INV_DESC,
5663 TEST_TYPE_TEARDOWN,
5764 TEST_TYPE_BIDI,
5865 TEST_TYPE_STATS,
@@ -68,25 +75,21 @@ enum stat_test_type { · 9 unmodified lines
6875 STAT_TEST_TYPE_MAX
6976 };
7077
71−static int configured_mode;
7278 static bool opt_pkt_dump;
73−static u32 num_frames = DEFAULT_PKT_CNT / 4;
74−static bool second_step;
7579 static int test_type;
7680
7781 static bool opt_verbose;
78−
79−static u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
80−static u32 xdp_bind_flags = XDP_USE_NEED_WAKEUP | XDP_COPY;
8182 static int stat_test_type;
82−static u32 rxqsize;
83−static u32 frame_headroom;
8483
8584 struct xsk_umem_info {
8685 struct xsk_ring_prod fq;
8786 struct xsk_ring_cons cq;
8887 struct xsk_umem *umem;
88+ u32 num_frames;
89+ u32 frame_headroom;
8990 void *buffer;
91+ u32 frame_size;
92+ bool unaligned_mode;
9093 };
9194
9295 struct xsk_socket_info {
@@ -95,51 +98,58 @@ struct xsk_socket_info { · 2 unmodified lines
9598 struct xsk_umem_info *umem;
9699 struct xsk_socket *xsk;
97100 u32 outstanding_tx;
98−};
99−
100−struct flow_vector {
101− enum fvector {
102− tx,
103− rx,
104− } vector;
101+ u32 rxqsize;
105102 };
106103
107104 struct pkt {
108105 u64 addr;
109106 u32 len;
110107 u32 payload;
108+ bool valid;
111109 };
112110
113111 struct pkt_stream {
114112 u32 nb_pkts;
113+ u32 rx_pkt_nb;
115114 struct pkt *pkts;
115+ bool use_addr_for_fill;
116116 };
117117
118+typedef void *(*thread_func_t)(void *arg);
119+
118120 struct ifobject {
119121 char ifname[MAX_INTERFACE_NAME_CHARS];
120122 char nsname[MAX_INTERFACES_NAMESPACE_CHARS];
121123 struct xsk_socket_info *xsk;
122− struct xsk_socket_info **xsk_arr;
123− struct xsk_umem_info **umem_arr;
124+ struct xsk_socket_info *xsk_arr;
124125 struct xsk_umem_info *umem;
125− void *(*func_ptr)(void *arg);
126− struct flow_vector fv;
126+ struct xsk_umem_info *umem_arr;
127+ thread_func_t func_ptr;
127128 struct pkt_stream *pkt_stream;
128129 int ns_fd;
129130 u32 dst_ip;
130131 u32 src_ip;
132+ u32 xdp_flags;
133+ u32 bind_flags;
131134 u16 src_port;
132135 u16 dst_port;
136+ bool tx_on;
137+ bool rx_on;
138+ bool use_poll;
133139 u8 dst_mac[ETH_ALEN];
134140 u8 src_mac[ETH_ALEN];
135141 };
136142
137−static struct ifobject *ifdict[MAX_INTERFACES];
138−static struct ifobject *ifdict_rx;
139−static struct ifobject *ifdict_tx;
143+struct test_spec {
144+ struct ifobject *ifobj_tx;
145+ struct ifobject *ifobj_rx;
146+ struct pkt_stream *pkt_stream_default;
147+ u16 total_steps;
148+ u16 current_step;
149+ u16 nb_sockets;
150+ char name[MAX_TEST_NAME_SIZE];
151+};
140152
141−/*threads*/
142153 pthread_barrier_t barr;
143−pthread_t t0, t1;
144154
145155 #endif /* XDPXCEIVER_H */

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t