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 ... ====================
Unified · Split
| @@ -85,6 +85,7 @@ sequentially and type id is assigned to each recognized type starting from id · 84 unmodified lines | ||
| 85 | 85 | #define BTF_KIND_VAR 14 /* Variable */ |
| 86 | 86 | #define BTF_KIND_DATASEC 15 /* Section */ |
| 87 | 87 | #define BTF_KIND_FLOAT 16 /* Floating point */ |
| 88 | + #define BTF_KIND_TAG 17 /* Tag */ | |
| 88 | 89 | |
| 89 | 90 | Note that the type section encodes debug info, not just pure types. |
| 90 | 91 | ``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 | ||
| 106 | 107 | * "size" tells the size of the type it is describing. |
| 107 | 108 | * |
| 108 | 109 | * "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT, |
| 109 | − * FUNC and FUNC_PROTO. | |
| 110 | + * FUNC, FUNC_PROTO and TAG. | |
| 110 | 111 | * "type" is a type_id referring to another type. |
| 111 | 112 | */ |
| 112 | 113 | union { |
| @@ -465,6 +466,32 @@ map definition. · 352 unmodified lines | ||
| 465 | 466 | |
| 466 | 467 | No additional type data follow ``btf_type``. |
| 467 | 468 | |
| 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 | + | |
| 468 | 495 | 3. BTF Kernel API |
| 469 | 496 | ***************** |
| 470 | 497 | |
| @@ -2143,19 +2143,19 @@ static __initconst const u64 knl_hw_cache_extra_regs · 2142 unmodified lines | ||
| 2143 | 2143 | * However, there are some cases which may change PEBS status, e.g. PMI |
| 2144 | 2144 | * throttle. The PEBS_ENABLE should be updated where the status changes. |
| 2145 | 2145 | */ |
| 2146 | −static void __intel_pmu_disable_all(void) | |
| 2146 | +static __always_inline void __intel_pmu_disable_all(bool bts) | |
| 2147 | 2147 | { |
| 2148 | 2148 | struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); |
| 2149 | 2149 | |
| 2150 | 2150 | wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0); |
| 2151 | 2151 | |
| 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)) | |
| 2153 | 2153 | intel_pmu_disable_bts(); |
| 2154 | 2154 | } |
| 2155 | 2155 | |
| 2156 | −static void intel_pmu_disable_all(void) | |
| 2156 | +static __always_inline void intel_pmu_disable_all(void) | |
| 2157 | 2157 | { |
| 2158 | − __intel_pmu_disable_all(); | |
| 2158 | + __intel_pmu_disable_all(true); | |
| 2159 | 2159 | intel_pmu_pebs_disable_all(); |
| 2160 | 2160 | intel_pmu_lbr_disable_all(); |
| 2161 | 2161 | } |
| @@ -2186,6 +2186,49 @@ static void intel_pmu_enable_all(int added) · 24 unmodified lines | ||
| 2186 | 2186 | __intel_pmu_enable_all(added, false); |
| 2187 | 2187 | } |
| 2188 | 2188 | |
| 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 | + | |
| 2189 | 2232 | /* |
| 2190 | 2233 | * Workaround for: |
| 2191 | 2234 | * Intel Errata AAK100 (model 26) |
| @@ -2929,7 +2972,7 @@ static int intel_pmu_handle_irq(struct pt_regs *regs) · 737 unmodified lines | ||
| 2929 | 2972 | apic_write(APIC_LVTPC, APIC_DM_NMI); |
| 2930 | 2973 | intel_bts_disable_local(); |
| 2931 | 2974 | cpuc->enabled = 0; |
| 2932 | − __intel_pmu_disable_all(); | |
| 2975 | + __intel_pmu_disable_all(true); | |
| 2933 | 2976 | handled = intel_pmu_drain_bts_buffer(); |
| 2934 | 2977 | handled += intel_bts_interrupt(); |
| 2935 | 2978 | status = intel_pmu_get_status(); |
| @@ -6283,9 +6326,21 @@ __init int intel_pmu_init(void) · 3347 unmodified lines | ||
| 6283 | 6326 | x86_pmu.lbr_nr = 0; |
| 6284 | 6327 | } |
| 6285 | 6328 | |
| 6286 | − if (x86_pmu.lbr_nr) | |
| 6329 | + if (x86_pmu.lbr_nr) { | |
| 6287 | 6330 | pr_cont("%d-deep LBR, ", x86_pmu.lbr_nr); |
| 6288 | 6331 | |
| 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 | + | |
| 6289 | 6344 | intel_pmu_check_extra_regs(x86_pmu.extra_regs); |
| 6290 | 6345 | |
| 6291 | 6346 | /* Support full width counters using alternative MSR range */ |
| @@ -1301,7 +1301,7 @@ void intel_pmu_pebs_disable_all(void) · 1300 unmodified lines | ||
| 1301 | 1301 | struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); |
| 1302 | 1302 | |
| 1303 | 1303 | if (cpuc->pebs_enabled) |
| 1304 | − wrmsrl(MSR_IA32_PEBS_ENABLE, 0); | |
| 1304 | + __intel_pmu_pebs_disable_all(); | |
| 1305 | 1305 | } |
| 1306 | 1306 | |
| 1307 | 1307 | static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs) |
| @@ -228,20 +228,6 @@ static void __intel_pmu_lbr_enable(bool pmi) · 227 unmodified lines | ||
| 228 | 228 | wrmsrl(MSR_ARCH_LBR_CTL, lbr_select | ARCH_LBR_CTL_LBREN); |
| 229 | 229 | } |
| 230 | 230 | |
| 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 | − | |
| 245 | 231 | void intel_pmu_lbr_reset_32(void) |
| 246 | 232 | { |
| 247 | 233 | int i; |
| @@ -779,8 +765,12 @@ void intel_pmu_lbr_disable_all(void) · 531 unmodified lines | ||
| 779 | 765 | { |
| 780 | 766 | struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); |
| 781 | 767 | |
| 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 | + | |
| 783 | 772 | __intel_pmu_lbr_disable(); |
| 773 | + } | |
| 784 | 774 | } |
| 785 | 775 | |
| 786 | 776 | void intel_pmu_lbr_read_32(struct cpu_hw_events *cpuc) |
| @@ -1240,6 +1240,25 @@ static inline bool intel_pmu_has_bts(struct perf_event *event) · 1239 unmodified lines | ||
| 1240 | 1240 | return intel_pmu_has_bts_period(event, hwc->sample_period); |
| 1241 | 1241 | } |
| 1242 | 1242 | |
| 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 | + | |
| 1243 | 1262 | int intel_pmu_save_and_restart(struct perf_event *event); |
| 1244 | 1263 | |
| 1245 | 1264 | struct event_constraint * |
| @@ -1070,41 +1070,34 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, · 1069 unmodified lines | ||
| 1070 | 1070 | break; |
| 1071 | 1071 | |
| 1072 | 1072 | case BPF_ALU | BPF_MUL | BPF_K: |
| 1073 | − case BPF_ALU | BPF_MUL | BPF_X: | |
| 1074 | 1073 | 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)); | |
| 1078 | 1078 | |
| 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; | |
| 1083 | 1089 | |
| 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)); | |
| 1086 | 1096 | |
| 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)); | |
| 1106 | 1099 | break; |
| 1107 | − } | |
| 1100 | + | |
| 1108 | 1101 | /* Shifts */ |
| 1109 | 1102 | case BPF_ALU | BPF_LSH | BPF_K: |
| 1110 | 1103 | case BPF_ALU | BPF_RSH | BPF_K: |
| @@ -57,6 +57,7 @@ struct perf_guest_info_callbacks { · 56 unmodified lines | ||
| 57 | 57 | #include <linux/cgroup.h> |
| 58 | 58 | #include <linux/refcount.h> |
| 59 | 59 | #include <linux/security.h> |
| 60 | +#include <linux/static_call.h> | |
| 60 | 61 | #include <asm/local.h> |
| 61 | 62 | |
| 62 | 63 | struct perf_callchain_entry { |
| @@ -1612,4 +1613,26 @@ extern void __weak arch_perf_update_userpage(struct perf_event *event, · 1549 unmodified lines | ||
| 1612 | 1613 | extern __weak u64 arch_perf_get_page_size(struct mm_struct *mm, unsigned long addr); |
| 1613 | 1614 | #endif |
| 1614 | 1615 | |
| 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 | + | |
| 1615 | 1638 | #endif /* _LINUX_PERF_EVENT_H */ |
| @@ -1629,7 +1629,7 @@ union bpf_attr { · 1628 unmodified lines | ||
| 1629 | 1629 | * u32 bpf_get_smp_processor_id(void) |
| 1630 | 1630 | * Description |
| 1631 | 1631 | * 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 | |
| 1633 | 1633 | * SMP processor id is stable during all the execution of the |
| 1634 | 1634 | * program. |
| 1635 | 1635 | * Return |
| @@ -4877,6 +4877,27 @@ union bpf_attr { · 3241 unmodified lines | ||
| 4877 | 4877 | * Get the struct pt_regs associated with **task**. |
| 4878 | 4878 | * Return |
| 4879 | 4879 | * 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. | |
| 4880 | 4901 | */ |
| 4881 | 4902 | #define __BPF_FUNC_MAPPER(FN) \ |
| 4882 | 4903 | FN(unspec), \ |
| @@ -5055,6 +5076,7 @@ union bpf_attr { · 172 unmodified lines | ||
| 5055 | 5076 | FN(get_func_ip), \ |
| 5056 | 5077 | FN(get_attach_cookie), \ |
| 5057 | 5078 | FN(task_pt_regs), \ |
| 5079 | + FN(get_branch_snapshot), \ | |
| 5058 | 5080 | /* */ |
| 5059 | 5081 | |
| 5060 | 5082 | /* integer value in 'imm' field of BPF_CALL instruction selects which helper |
| @@ -5284,6 +5306,8 @@ struct __sk_buff { · 223 unmodified lines | ||
| 5284 | 5306 | __u32 gso_segs; |
| 5285 | 5307 | __bpf_md_ptr(struct bpf_sock *, sk); |
| 5286 | 5308 | __u32 gso_size; |
| 5309 | + __u32 :32; /* Padding, future use. */ | |
| 5310 | + __u64 hwtstamp; | |
| 5287 | 5311 | }; |
| 5288 | 5312 | |
| 5289 | 5313 | struct bpf_tunnel_key { |
| @@ -43,7 +43,7 @@ struct btf_type { · 42 unmodified lines | ||
| 43 | 43 | * "size" tells the size of the type it is describing. |
| 44 | 44 | * |
| 45 | 45 | * "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT, |
| 46 | − * FUNC, FUNC_PROTO and VAR. | |
| 46 | + * FUNC, FUNC_PROTO, VAR and TAG. | |
| 47 | 47 | * "type" is a type_id referring to another type. |
| 48 | 48 | */ |
| 49 | 49 | union { |
| @@ -56,25 +56,29 @@ struct btf_type { · 6 unmodified lines | ||
| 56 | 56 | #define BTF_INFO_VLEN(info) ((info) & 0xffff) |
| 57 | 57 | #define BTF_INFO_KFLAG(info) ((info) >> 31) |
| 58 | 58 | |
| 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 | +}; | |
| 78 | 82 | |
| 79 | 83 | /* For some specific BTF_KIND, "struct btf_type" is immediately |
| 80 | 84 | * followed by extra data. |
| @@ -170,4 +174,15 @@ struct btf_var_secinfo { · 89 unmodified lines | ||
| 170 | 174 | __u32 size; |
| 171 | 175 | }; |
| 172 | 176 | |
| 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 | + | |
| 173 | 188 | #endif /* _UAPI__LINUX_BTF_H__ */ |
| @@ -281,6 +281,7 @@ static const char * const btf_kind_str[NR_BTF_KINDS] = { · 280 unmodified lines | ||
| 281 | 281 | [BTF_KIND_VAR] = "VAR", |
| 282 | 282 | [BTF_KIND_DATASEC] = "DATASEC", |
| 283 | 283 | [BTF_KIND_FLOAT] = "FLOAT", |
| 284 | + [BTF_KIND_TAG] = "TAG", | |
| 284 | 285 | }; |
| 285 | 286 | |
| 286 | 287 | 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 | ||
| 459 | 460 | return BTF_INFO_KIND(t->info) == BTF_KIND_DATASEC; |
| 460 | 461 | } |
| 461 | 462 | |
| 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 | + | |
| 462 | 474 | u32 btf_nr_types(const struct btf *btf) |
| 463 | 475 | { |
| 464 | 476 | u32 total = 0; |
| @@ -537,6 +549,7 @@ const struct btf_type *btf_type_resolve_func_ptr(const struct btf *btf, · 72 unmodified lines | ||
| 537 | 549 | static bool btf_type_is_resolve_source_only(const struct btf_type *t) |
| 538 | 550 | { |
| 539 | 551 | return btf_type_is_var(t) || |
| 552 | + btf_type_is_tag(t) || | |
| 540 | 553 | btf_type_is_datasec(t); |
| 541 | 554 | } |
| 542 | 555 | |
| @@ -563,6 +576,7 @@ static bool btf_type_needs_resolve(const struct btf_type *t) · 20 unmodified lines | ||
| 563 | 576 | btf_type_is_struct(t) || |
| 564 | 577 | btf_type_is_array(t) || |
| 565 | 578 | btf_type_is_var(t) || |
| 579 | + btf_type_is_tag(t) || | |
| 566 | 580 | btf_type_is_datasec(t); |
| 567 | 581 | } |
| 568 | 582 | |
| @@ -616,6 +630,11 @@ static const struct btf_var *btf_type_var(const struct btf_type *t) · 47 unmodified lines | ||
| 616 | 630 | return (const struct btf_var *)(t + 1); |
| 617 | 631 | } |
| 618 | 632 | |
| 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 | + | |
| 619 | 638 | static const struct btf_kind_operations *btf_type_ops(const struct btf_type *t) |
| 620 | 639 | { |
| 621 | 640 | return kind_ops[BTF_INFO_KIND(t->info)]; |
| @@ -3801,6 +3820,110 @@ static const struct btf_kind_operations float_ops = { · 3179 unmodified lines | ||
| 3801 | 3820 | .show = btf_df_show, |
| 3802 | 3821 | }; |
| 3803 | 3822 | |
| 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 | + | |
| 3804 | 3927 | static int btf_func_proto_check(struct btf_verifier_env *env, |
| 3805 | 3928 | const struct btf_type *t) |
| 3806 | 3929 | { |
| @@ -3935,6 +4058,7 @@ static const struct btf_kind_operations * const kind_ops[NR_BTF_KINDS] = { · 128 unmodified lines | ||
| 3935 | 4058 | [BTF_KIND_VAR] = &var_ops, |
| 3936 | 4059 | [BTF_KIND_DATASEC] = &datasec_ops, |
| 3937 | 4060 | [BTF_KIND_FLOAT] = &float_ops, |
| 4061 | + [BTF_KIND_TAG] = &tag_ops, | |
| 3938 | 4062 | }; |
| 3939 | 4063 | |
| 3940 | 4064 | 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 | ||
| 4019 | 4143 | return !btf_resolved_type_id(btf, type_id) && |
| 4020 | 4144 | !btf_resolved_type_size(btf, type_id); |
| 4021 | 4145 | |
| 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 | + | |
| 4022 | 4150 | if (btf_type_is_modifier(t) || btf_type_is_ptr(t) || |
| 4023 | 4151 | btf_type_is_var(t)) { |
| 4024 | 4152 | t = btf_type_id_resolve(btf, &type_id); |
| @@ -10,6 +10,7 @@ · 9 unmodified lines | ||
| 10 | 10 | #include <linux/rcupdate_trace.h> |
| 11 | 11 | #include <linux/rcupdate_wait.h> |
| 12 | 12 | #include <linux/module.h> |
| 13 | +#include <linux/static_call.h> | |
| 13 | 14 | |
| 14 | 15 | /* dummy _ops. The verifier will operate on target program's ops. */ |
| 15 | 16 | const struct bpf_verifier_ops bpf_extension_verifier_ops = { |
| @@ -526,7 +527,7 @@ out: · 510 unmodified lines | ||
| 526 | 527 | } |
| 527 | 528 | |
| 528 | 529 | #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) | |
| 530 | 531 | { |
| 531 | 532 | u64 start = NO_START_TIME; |
| 532 | 533 | |
| @@ -13435,3 +13435,5 @@ struct cgroup_subsys perf_event_cgrp_subsys = { · 13434 unmodified lines | ||
| 13435 | 13435 | .threaded = true, |
| 13436 | 13436 | }; |
| 13437 | 13437 | #endif /* CONFIG_CGROUP_PERF */ |
| 13438 | + | |
| 13439 | +DEFINE_STATIC_CALL_RET0(perf_snapshot_branch_stack, perf_snapshot_branch_stack_t); | |
| @@ -1017,6 +1017,34 @@ static const struct bpf_func_proto bpf_get_attach_cookie_proto_pe = { · 1016 unmodified lines | ||
| 1017 | 1017 | .arg1_type = ARG_PTR_TO_CTX, |
| 1018 | 1018 | }; |
| 1019 | 1019 | |
| 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 | + | |
| 1020 | 1048 | static const struct bpf_func_proto * |
| 1021 | 1049 | bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) |
| 1022 | 1050 | { |
| @@ -1132,6 +1160,8 @@ bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) · 109 unmodified lines | ||
| 1132 | 1160 | return &bpf_snprintf_proto; |
| 1133 | 1161 | case BPF_FUNC_get_func_ip: |
| 1134 | 1162 | return &bpf_get_func_ip_proto_tracing; |
| 1163 | + case BPF_FUNC_get_branch_snapshot: | |
| 1164 | + return &bpf_get_branch_snapshot_proto; | |
| 1135 | 1165 | default: |
| 1136 | 1166 | return bpf_base_func_proto(func_id); |
| 1137 | 1167 | } |
| @@ -8800,6 +8800,7 @@ static __init struct sk_buff *build_test_skb(void) · 8799 unmodified lines | ||
| 8800 | 8800 | skb_shinfo(skb[0])->gso_type |= SKB_GSO_DODGY; |
| 8801 | 8801 | skb_shinfo(skb[0])->gso_segs = 0; |
| 8802 | 8802 | skb_shinfo(skb[0])->frag_list = skb[1]; |
| 8803 | + skb_shinfo(skb[0])->hwtstamps.hwtstamp = 1000; | |
| 8803 | 8804 | |
| 8804 | 8805 | /* adjust skb[0]'s len */ |
| 8805 | 8806 | skb[0]->len += skb[1]->len; |
| @@ -483,11 +483,7 @@ static int convert___skb_to_skb(struct sk_buff *skb, struct __sk_buff *__skb) · 482 unmodified lines | ||
| 483 | 483 | return -EINVAL; |
| 484 | 484 | |
| 485 | 485 | /* 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 */ | |
| 491 | 487 | /* ifindex is allowed */ |
| 492 | 488 | |
| 493 | 489 | 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 | ||
| 511 | 507 | /* gso_size is allowed */ |
| 512 | 508 | |
| 513 | 509 | 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), | |
| 514 | 516 | sizeof(struct __sk_buff))) |
| 515 | 517 | return -EINVAL; |
| 516 | 518 | |
| 517 | 519 | skb->mark = __skb->mark; |
| 518 | 520 | skb->priority = __skb->priority; |
| 521 | + skb->skb_iif = __skb->ingress_ifindex; | |
| 519 | 522 | skb->tstamp = __skb->tstamp; |
| 520 | 523 | memcpy(&cb->data, __skb->cb, QDISC_CB_PRIV_LEN); |
| 521 | 524 | |
| @@ -532,6 +535,7 @@ static int convert___skb_to_skb(struct sk_buff *skb, struct __sk_buff *__skb) · 10 unmodified lines | ||
| 532 | 535 | return -EINVAL; |
| 533 | 536 | skb_shinfo(skb)->gso_segs = __skb->gso_segs; |
| 534 | 537 | skb_shinfo(skb)->gso_size = __skb->gso_size; |
| 538 | + skb_shinfo(skb)->hwtstamps.hwtstamp = __skb->hwtstamp; | |
| 535 | 539 | |
| 536 | 540 | return 0; |
| 537 | 541 | } |
| @@ -545,11 +549,13 @@ static void convert_skb_to___skb(struct sk_buff *skb, struct __sk_buff *__skb) · 7 unmodified lines | ||
| 545 | 549 | |
| 546 | 550 | __skb->mark = skb->mark; |
| 547 | 551 | __skb->priority = skb->priority; |
| 552 | + __skb->ingress_ifindex = skb->skb_iif; | |
| 548 | 553 | __skb->ifindex = skb->dev->ifindex; |
| 549 | 554 | __skb->tstamp = skb->tstamp; |
| 550 | 555 | memcpy(__skb->cb, &cb->data, QDISC_CB_PRIV_LEN); |
| 551 | 556 | __skb->wire_len = cb->pkt_len; |
| 552 | 557 | __skb->gso_segs = skb_shinfo(skb)->gso_segs; |
| 558 | + __skb->hwtstamp = skb_shinfo(skb)->hwtstamps.hwtstamp; | |
| 553 | 559 | } |
| 554 | 560 | |
| 555 | 561 | int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr, |
| @@ -7765,6 +7765,10 @@ static bool bpf_skb_is_valid_access(int off, int size, enum bpf_access_type type · 7764 unmodified lines | ||
| 7765 | 7765 | break; |
| 7766 | 7766 | case bpf_ctx_range_ptr(struct __sk_buff, flow_keys): |
| 7767 | 7767 | return false; |
| 7768 | + case bpf_ctx_range(struct __sk_buff, hwtstamp): | |
| 7769 | + if (type == BPF_WRITE || size != sizeof(__u64)) | |
| 7770 | + return false; | |
| 7771 | + break; | |
| 7768 | 7772 | case bpf_ctx_range(struct __sk_buff, tstamp): |
| 7769 | 7773 | if (size != sizeof(__u64)) |
| 7770 | 7774 | 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 | ||
| 7774 | 7778 | return false; |
| 7775 | 7779 | info->reg_type = PTR_TO_SOCK_COMMON_OR_NULL; |
| 7776 | 7780 | 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; | |
| 7777 | 7784 | default: |
| 7778 | 7785 | /* Only narrow read access allowed for now. */ |
| 7779 | 7786 | if (type == BPF_WRITE) { |
| @@ -7802,6 +7809,7 @@ static bool sk_filter_is_valid_access(int off, int size, · 22 unmodified lines | ||
| 7802 | 7809 | case bpf_ctx_range_till(struct __sk_buff, family, local_port): |
| 7803 | 7810 | case bpf_ctx_range(struct __sk_buff, tstamp): |
| 7804 | 7811 | case bpf_ctx_range(struct __sk_buff, wire_len): |
| 7812 | + case bpf_ctx_range(struct __sk_buff, hwtstamp): | |
| 7805 | 7813 | return false; |
| 7806 | 7814 | } |
| 7807 | 7815 | |
| @@ -7872,6 +7880,7 @@ static bool lwt_is_valid_access(int off, int size, · 64 unmodified lines | ||
| 7872 | 7880 | case bpf_ctx_range(struct __sk_buff, data_meta): |
| 7873 | 7881 | case bpf_ctx_range(struct __sk_buff, tstamp): |
| 7874 | 7882 | case bpf_ctx_range(struct __sk_buff, wire_len): |
| 7883 | + case bpf_ctx_range(struct __sk_buff, hwtstamp): | |
| 7875 | 7884 | return false; |
| 7876 | 7885 | } |
| 7877 | 7886 | |
| @@ -8373,6 +8382,7 @@ static bool sk_skb_is_valid_access(int off, int size, · 495 unmodified lines | ||
| 8373 | 8382 | case bpf_ctx_range(struct __sk_buff, data_meta): |
| 8374 | 8383 | case bpf_ctx_range(struct __sk_buff, tstamp): |
| 8375 | 8384 | case bpf_ctx_range(struct __sk_buff, wire_len): |
| 8385 | + case bpf_ctx_range(struct __sk_buff, hwtstamp): | |
| 8376 | 8386 | return false; |
| 8377 | 8387 | } |
| 8378 | 8388 | |
| @@ -8884,6 +8894,17 @@ static u32 bpf_convert_ctx_access(enum bpf_access_type type, · 505 unmodified lines | ||
| 8884 | 8894 | si->dst_reg, si->src_reg, |
| 8885 | 8895 | offsetof(struct sk_buff, sk)); |
| 8886 | 8896 | 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; | |
| 8887 | 8908 | } |
| 8888 | 8909 | |
| 8889 | 8910 | return insn - insn_buf; |
| @@ -137,7 +137,10 @@ endif · 136 unmodified lines | ||
| 137 | 137 | BPFTOOL_BOOTSTRAP := $(BOOTSTRAP_OUTPUT)bpftool |
| 138 | 138 | |
| 139 | 139 | 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 | + | |
| 140 | 142 | OBJS = $(patsubst %.c,$(OUTPUT)%.o,$(SRCS)) $(OUTPUT)disasm.o |
| 143 | +$(OBJS): $(LIBBPF) | |
| 141 | 144 | |
| 142 | 145 | VMLINUX_BTF_PATHS ?= $(if $(O),$(O)/vmlinux) \ |
| 143 | 146 | $(if $(KBUILD_OUTPUT),$(KBUILD_OUTPUT)/vmlinux) \ |
| @@ -37,6 +37,7 @@ static const char * const btf_kind_str[NR_BTF_KINDS] = { · 36 unmodified lines | ||
| 37 | 37 | [BTF_KIND_VAR] = "VAR", |
| 38 | 38 | [BTF_KIND_DATASEC] = "DATASEC", |
| 39 | 39 | [BTF_KIND_FLOAT] = "FLOAT", |
| 40 | + [BTF_KIND_TAG] = "TAG", | |
| 40 | 41 | }; |
| 41 | 42 | |
| 42 | 43 | struct btf_attach_table { |
| @@ -347,6 +348,17 @@ static int dump_btf_type(const struct btf *btf, __u32 id, · 304 unmodified lines | ||
| 347 | 348 | printf(" size=%u", t->size); |
| 348 | 349 | break; |
| 349 | 350 | } |
| 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 | + } | |
| 350 | 362 | default: |
| 351 | 363 | break; |
| 352 | 364 | } |
| @@ -238,8 +238,8 @@ static void codegen(const char *template, ...) · 237 unmodified lines | ||
| 238 | 238 | } else if (c == '\n') { |
| 239 | 239 | break; |
| 240 | 240 | } 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); | |
| 243 | 243 | free(s); |
| 244 | 244 | exit(-1); |
| 245 | 245 | } |
| @@ -406,7 +406,7 @@ static void codegen_destroy(struct bpf_object *obj, const char *obj_name) · 160 unmodified lines | ||
| 406 | 406 | } |
| 407 | 407 | |
| 408 | 408 | bpf_object__for_each_map(map, obj) { |
| 409 | − const char * ident; | |
| 409 | + const char *ident; | |
| 410 | 410 | |
| 411 | 411 | ident = get_map_ident(map); |
| 412 | 412 | if (!ident) |
| @@ -862,6 +862,8 @@ static int do_skeleton(int argc, char **argv) · 449 unmodified lines | ||
| 862 | 862 | codegen("\ |
| 863 | 863 | \n\ |
| 864 | 864 | \n\ |
| 865 | + static inline const void *%1$s__elf_bytes(size_t *sz); \n\ | |
| 866 | + \n\ | |
| 865 | 867 | static inline int \n\ |
| 866 | 868 | %1$s__create_skeleton(struct %1$s *obj) \n\ |
| 867 | 869 | { \n\ |
| @@ -943,10 +945,20 @@ static int do_skeleton(int argc, char **argv) · 75 unmodified lines | ||
| 943 | 945 | codegen("\ |
| 944 | 946 | \n\ |
| 945 | 947 | \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); | |
| 950 | 962 | |
| 951 | 963 | /* embed contents of BPF object file */ |
| 952 | 964 | print_hex(obj_data, file_sz); |
| @@ -954,11 +966,6 @@ static int do_skeleton(int argc, char **argv) · 1 unmodified line | ||
| 954 | 966 | codegen("\ |
| 955 | 967 | \n\ |
| 956 | 968 | \"; \n\ |
| 957 | − \n\ | |
| 958 | − return 0; \n\ | |
| 959 | − err: \n\ | |
| 960 | − bpf_object__destroy_skeleton(s); \n\ | |
| 961 | − return -ENOMEM; \n\ | |
| 962 | 969 | } \n\ |
| 963 | 970 | \n\ |
| 964 | 971 | #endif /* %s */ \n\ |
| @@ -26,6 +26,7 @@ LIBBPF_SRC := $(srctree)/tools/lib/bpf/ · 25 unmodified lines | ||
| 26 | 26 | SUBCMD_SRC := $(srctree)/tools/lib/subcmd/ |
| 27 | 27 | |
| 28 | 28 | BPFOBJ := $(OUTPUT)/libbpf/libbpf.a |
| 29 | +LIBBPF_OUT := $(abspath $(dir $(BPFOBJ)))/ | |
| 29 | 30 | SUBCMDOBJ := $(OUTPUT)/libsubcmd/libsubcmd.a |
| 30 | 31 | |
| 31 | 32 | BINARY := $(OUTPUT)/resolve_btfids |
| @@ -41,7 +42,7 @@ $(SUBCMDOBJ): fixdep FORCE | $(OUTPUT)/libsubcmd · 9 unmodified lines | ||
| 41 | 42 | $(Q)$(MAKE) -C $(SUBCMD_SRC) OUTPUT=$(abspath $(dir $@))/ $(abspath $@) |
| 42 | 43 | |
| 43 | 44 | $(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 $@) | |
| 45 | 46 | |
| 46 | 47 | CFLAGS := -g \ |
| 47 | 48 | -I$(srctree)/tools/include \ |
| @@ -54,7 +55,7 @@ LIBS = -lelf -lz · 6 unmodified lines | ||
| 54 | 55 | export srctree OUTPUT CFLAGS Q |
| 55 | 56 | include $(srctree)/tools/build/Makefile.include |
| 56 | 57 | |
| 57 | −$(BINARY_IN): fixdep FORCE | $(OUTPUT) | |
| 58 | +$(BINARY_IN): $(BPFOBJ) fixdep FORCE | $(OUTPUT) | |
| 58 | 59 | $(Q)$(MAKE) $(build)=resolve_btfids |
| 59 | 60 | |
| 60 | 61 | $(BINARY): $(BPFOBJ) $(SUBCMDOBJ) $(BINARY_IN) |
| @@ -1629,7 +1629,7 @@ union bpf_attr { · 1628 unmodified lines | ||
| 1629 | 1629 | * u32 bpf_get_smp_processor_id(void) |
| 1630 | 1630 | * Description |
| 1631 | 1631 | * 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 | |
| 1633 | 1633 | * SMP processor id is stable during all the execution of the |
| 1634 | 1634 | * program. |
| 1635 | 1635 | * Return |
| @@ -4877,6 +4877,27 @@ union bpf_attr { · 3241 unmodified lines | ||
| 4877 | 4877 | * Get the struct pt_regs associated with **task**. |
| 4878 | 4878 | * Return |
| 4879 | 4879 | * 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. | |
| 4880 | 4901 | */ |
| 4881 | 4902 | #define __BPF_FUNC_MAPPER(FN) \ |
| 4882 | 4903 | FN(unspec), \ |
| @@ -5055,6 +5076,7 @@ union bpf_attr { · 172 unmodified lines | ||
| 5055 | 5076 | FN(get_func_ip), \ |
| 5056 | 5077 | FN(get_attach_cookie), \ |
| 5057 | 5078 | FN(task_pt_regs), \ |
| 5079 | + FN(get_branch_snapshot), \ | |
| 5058 | 5080 | /* */ |
| 5059 | 5081 | |
| 5060 | 5082 | /* integer value in 'imm' field of BPF_CALL instruction selects which helper |
| @@ -5284,6 +5306,8 @@ struct __sk_buff { · 223 unmodified lines | ||
| 5284 | 5306 | __u32 gso_segs; |
| 5285 | 5307 | __bpf_md_ptr(struct bpf_sock *, sk); |
| 5286 | 5308 | __u32 gso_size; |
| 5309 | + __u32 :32; /* Padding, future use. */ | |
| 5310 | + __u64 hwtstamp; | |
| 5287 | 5311 | }; |
| 5288 | 5312 | |
| 5289 | 5313 | struct bpf_tunnel_key { |
| @@ -43,7 +43,7 @@ struct btf_type { · 42 unmodified lines | ||
| 43 | 43 | * "size" tells the size of the type it is describing. |
| 44 | 44 | * |
| 45 | 45 | * "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT, |
| 46 | − * FUNC, FUNC_PROTO and VAR. | |
| 46 | + * FUNC, FUNC_PROTO, VAR and TAG. | |
| 47 | 47 | * "type" is a type_id referring to another type. |
| 48 | 48 | */ |
| 49 | 49 | union { |
| @@ -56,25 +56,29 @@ struct btf_type { · 6 unmodified lines | ||
| 56 | 56 | #define BTF_INFO_VLEN(info) ((info) & 0xffff) |
| 57 | 57 | #define BTF_INFO_KFLAG(info) ((info) >> 31) |
| 58 | 58 | |
| 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 | +}; | |
| 78 | 82 | |
| 79 | 83 | /* For some specific BTF_KIND, "struct btf_type" is immediately |
| 80 | 84 | * followed by extra data. |
| @@ -170,4 +174,15 @@ struct btf_var_secinfo { · 89 unmodified lines | ||
| 170 | 174 | __u32 size; |
| 171 | 175 | }; |
| 172 | 176 | |
| 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 | + | |
| 173 | 188 | #endif /* _UAPI__LINUX_BTF_H__ */ |
| @@ -1,5 +1,4 @@ | ||
| 1 | 1 | # SPDX-License-Identifier: GPL-2.0-only |
| 2 | −libbpf_version.h | |
| 3 | 2 | libbpf.pc |
| 4 | 3 | libbpf.so.* |
| 5 | 4 | TAGS |
| @@ -8,7 +8,8 @@ VERSION_SCRIPT := libbpf.map · 7 unmodified lines | ||
| 8 | 8 | LIBBPF_VERSION := $(shell \ |
| 9 | 9 | grep -oE '^LIBBPF_([0-9.]+)' $(VERSION_SCRIPT) | \ |
| 10 | 10 | 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))) | |
| 12 | 13 | |
| 13 | 14 | MAKEFLAGS += --no-print-directory |
| 14 | 15 | |
| @@ -59,7 +60,8 @@ ifndef VERBOSE · 44 unmodified lines | ||
| 59 | 60 | VERBOSE = 0 |
| 60 | 61 | endif |
| 61 | 62 | |
| 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 | |
| 63 | 65 | |
| 64 | 66 | export prefix libdir src obj |
| 65 | 67 | |
| @@ -112,6 +114,7 @@ STATIC_OBJDIR := $(OUTPUT)staticobjs/ · 46 unmodified lines | ||
| 112 | 114 | BPF_IN_SHARED := $(SHARED_OBJDIR)libbpf-in.o |
| 113 | 115 | BPF_IN_STATIC := $(STATIC_OBJDIR)libbpf-in.o |
| 114 | 116 | BPF_HELPER_DEFS := $(OUTPUT)bpf_helper_defs.h |
| 117 | +BPF_GENERATED := $(BPF_HELPER_DEFS) | |
| 115 | 118 | |
| 116 | 119 | LIB_TARGET := $(addprefix $(OUTPUT),$(LIB_TARGET)) |
| 117 | 120 | LIB_FILE := $(addprefix $(OUTPUT),$(LIB_FILE)) |
| @@ -136,7 +139,7 @@ all: fixdep · 18 unmodified lines | ||
| 136 | 139 | |
| 137 | 140 | all_cmd: $(CMD_TARGETS) check |
| 138 | 141 | |
| 139 | −$(BPF_IN_SHARED): force $(BPF_HELPER_DEFS) | |
| 142 | +$(BPF_IN_SHARED): force $(BPF_GENERATED) | |
| 140 | 143 | @(test -f ../../include/uapi/linux/bpf.h -a -f ../../../include/uapi/linux/bpf.h && ( \ |
| 141 | 144 | (diff -B ../../include/uapi/linux/bpf.h ../../../include/uapi/linux/bpf.h >/dev/null) || \ |
| 142 | 145 | 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 | ||
| 154 | 157 | 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 |
| 155 | 158 | $(Q)$(MAKE) $(build)=libbpf OUTPUT=$(SHARED_OBJDIR) CFLAGS="$(CFLAGS) $(SHLIB_FLAGS)" |
| 156 | 159 | |
| 157 | −$(BPF_IN_STATIC): force $(BPF_HELPER_DEFS) | |
| 160 | +$(BPF_IN_STATIC): force $(BPF_GENERATED) | |
| 158 | 161 | $(Q)$(MAKE) $(build)=libbpf OUTPUT=$(STATIC_OBJDIR) |
| 159 | 162 | |
| 160 | 163 | $(BPF_HELPER_DEFS): $(srctree)/tools/include/uapi/linux/bpf.h |
| @@ -179,7 +182,7 @@ $(OUTPUT)libbpf.pc: · 18 unmodified lines | ||
| 179 | 182 | -e "s|@VERSION@|$(LIBBPF_VERSION)|" \ |
| 180 | 183 | < libbpf.pc.template > $@ |
| 181 | 184 | |
| 182 | −check: check_abi | |
| 185 | +check: check_abi check_version | |
| 183 | 186 | |
| 184 | 187 | check_abi: $(OUTPUT)libbpf.so $(VERSION_SCRIPT) |
| 185 | 188 | @if [ "$(GLOBAL_SYM_COUNT)" != "$(VERSIONED_SYM_COUNT)" ]; then \ |
| @@ -205,6 +208,21 @@ check_abi: $(OUTPUT)libbpf.so $(VERSION_SCRIPT) · 19 unmodified lines | ||
| 205 | 208 | exit 1; \ |
| 206 | 209 | fi |
| 207 | 210 | |
| 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 | + | |
| 208 | 226 | define do_install_mkdir |
| 209 | 227 | if [ ! -d '$(DESTDIR_SQ)$1' ]; then \ |
| 210 | 228 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$1'; \ |
| @@ -224,10 +242,11 @@ install_lib: all_cmd · 13 unmodified lines | ||
| 224 | 242 | cp -fpR $(LIB_FILE) $(DESTDIR)$(libdir_SQ) |
| 225 | 243 | |
| 226 | 244 | 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 | |
| 229 | 248 | |
| 230 | −install_headers: $(BPF_HELPER_DEFS) | |
| 249 | +install_headers: $(BPF_GENERATED) | |
| 231 | 250 | $(call QUIET_INSTALL, headers) \ |
| 232 | 251 | $(foreach hdr,$(INSTALL_HEADERS), \ |
| 233 | 252 | $(call do_install,$(hdr),$(prefix)/include/bpf,644);) |
| @@ -240,12 +259,12 @@ install: install_lib install_pkgconfig install_headers · 6 unmodified lines | ||
| 240 | 259 | |
| 241 | 260 | clean: |
| 242 | 261 | $(call QUIET_CLEAN, libbpf) $(RM) -rf $(CMD_TARGETS) \ |
| 243 | − *~ .*.d .*.cmd LIBBPF-CFLAGS $(BPF_HELPER_DEFS) \ | |
| 262 | + *~ .*.d .*.cmd LIBBPF-CFLAGS $(BPF_GENERATED) \ | |
| 244 | 263 | $(SHARED_OBJDIR) $(STATIC_OBJDIR) \ |
| 245 | 264 | $(addprefix $(OUTPUT), \ |
| 246 | 265 | *.o *.a *.so *.so.$(LIBBPF_MAJOR_VERSION) *.pc) |
| 247 | 266 | |
| 248 | −PHONY += force cscope tags | |
| 267 | +PHONY += force cscope tags check check_abi check_version | |
| 249 | 268 | force: |
| 250 | 269 | |
| 251 | 270 | cscope: |
| @@ -304,6 +304,8 @@ static int btf_type_size(const struct btf_type *t) · 303 unmodified lines | ||
| 304 | 304 | return base_size + sizeof(struct btf_var); |
| 305 | 305 | case BTF_KIND_DATASEC: |
| 306 | 306 | return base_size + vlen * sizeof(struct btf_var_secinfo); |
| 307 | + case BTF_KIND_TAG: | |
| 308 | + return base_size + sizeof(struct btf_tag); | |
| 307 | 309 | default: |
| 308 | 310 | pr_debug("Unsupported BTF_KIND:%u\n", btf_kind(t)); |
| 309 | 311 | return -EINVAL; |
| @@ -376,6 +378,9 @@ static int btf_bswap_type_rest(struct btf_type *t) · 66 unmodified lines | ||
| 376 | 378 | v->size = bswap_32(v->size); |
| 377 | 379 | } |
| 378 | 380 | return 0; |
| 381 | + case BTF_KIND_TAG: | |
| 382 | + btf_tag(t)->component_idx = bswap_32(btf_tag(t)->component_idx); | |
| 383 | + return 0; | |
| 379 | 384 | default: |
| 380 | 385 | pr_debug("Unsupported BTF_KIND:%u\n", btf_kind(t)); |
| 381 | 386 | return -EINVAL; |
| @@ -586,6 +591,7 @@ __s64 btf__resolve_size(const struct btf *btf, __u32 type_id) · 204 unmodified lines | ||
| 586 | 591 | case BTF_KIND_CONST: |
| 587 | 592 | case BTF_KIND_RESTRICT: |
| 588 | 593 | case BTF_KIND_VAR: |
| 594 | + case BTF_KIND_TAG: | |
| 589 | 595 | type_id = t->type; |
| 590 | 596 | break; |
| 591 | 597 | 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 | ||
| 2440 | 2446 | return 0; |
| 2441 | 2447 | } |
| 2442 | 2448 | |
| 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 | + | |
| 2443 | 2491 | struct btf_ext_sec_setup_param { |
| 2444 | 2492 | __u32 off; |
| 2445 | 2493 | __u32 len; |
| @@ -3256,8 +3304,8 @@ static bool btf_equal_common(struct btf_type *t1, struct btf_type *t2) · 810 unmodified lines | ||
| 3256 | 3304 | t1->size == t2->size; |
| 3257 | 3305 | } |
| 3258 | 3306 | |
| 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) | |
| 3261 | 3309 | { |
| 3262 | 3310 | __u32 info = *(__u32 *)(t + 1); |
| 3263 | 3311 | long h; |
| @@ -3267,8 +3315,8 @@ static long btf_hash_int(struct btf_type *t) · 3 unmodified lines | ||
| 3267 | 3315 | return h; |
| 3268 | 3316 | } |
| 3269 | 3317 | |
| 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) | |
| 3272 | 3320 | { |
| 3273 | 3321 | __u32 info1, info2; |
| 3274 | 3322 | |
| @@ -3535,7 +3583,8 @@ static int btf_dedup_prep(struct btf_dedup *d) · 260 unmodified lines | ||
| 3535 | 3583 | h = btf_hash_common(t); |
| 3536 | 3584 | break; |
| 3537 | 3585 | case BTF_KIND_INT: |
| 3538 | − h = btf_hash_int(t); | |
| 3586 | + case BTF_KIND_TAG: | |
| 3587 | + h = btf_hash_int_tag(t); | |
| 3539 | 3588 | break; |
| 3540 | 3589 | case BTF_KIND_ENUM: |
| 3541 | 3590 | 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 | ||
| 3590 | 3639 | case BTF_KIND_FUNC_PROTO: |
| 3591 | 3640 | case BTF_KIND_VAR: |
| 3592 | 3641 | case BTF_KIND_DATASEC: |
| 3642 | + case BTF_KIND_TAG: | |
| 3593 | 3643 | return 0; |
| 3594 | 3644 | |
| 3595 | 3645 | case BTF_KIND_INT: |
| 3596 | − h = btf_hash_int(t); | |
| 3646 | + h = btf_hash_int_tag(t); | |
| 3597 | 3647 | for_each_dedup_cand(d, hash_entry, h) { |
| 3598 | 3648 | cand_id = (__u32)(long)hash_entry->value; |
| 3599 | 3649 | cand = btf_type_by_id(d->btf, cand_id); |
| 3600 | − if (btf_equal_int(t, cand)) { | |
| 3650 | + if (btf_equal_int_tag(t, cand)) { | |
| 3601 | 3651 | new_id = cand_id; |
| 3602 | 3652 | break; |
| 3603 | 3653 | } |
| @@ -3881,7 +3931,7 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id, · 277 unmodified lines | ||
| 3881 | 3931 | |
| 3882 | 3932 | switch (cand_kind) { |
| 3883 | 3933 | case BTF_KIND_INT: |
| 3884 | − return btf_equal_int(cand_type, canon_type); | |
| 3934 | + return btf_equal_int_tag(cand_type, canon_type); | |
| 3885 | 3935 | |
| 3886 | 3936 | case BTF_KIND_ENUM: |
| 3887 | 3937 | 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 | ||
| 4210 | 4260 | } |
| 4211 | 4261 | break; |
| 4212 | 4262 | |
| 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 | + | |
| 4213 | 4280 | case BTF_KIND_ARRAY: { |
| 4214 | 4281 | struct btf_array *info = btf_array(t); |
| 4215 | 4282 | |
| @@ -4482,6 +4549,7 @@ int btf_type_visit_type_ids(struct btf_type *t, type_id_visit_fn visit, void *ct · 266 unmodified lines | ||
| 4482 | 4549 | case BTF_KIND_TYPEDEF: |
| 4483 | 4550 | case BTF_KIND_FUNC: |
| 4484 | 4551 | case BTF_KIND_VAR: |
| 4552 | + case BTF_KIND_TAG: | |
| 4485 | 4553 | return visit(&t->type, ctx); |
| 4486 | 4554 | |
| 4487 | 4555 | case BTF_KIND_ARRAY: { |
| @@ -1,5 +1,6 @@ | ||
| 1 | 1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ |
| 2 | 2 | /* Copyright (c) 2018 Facebook */ |
| 3 | +/*! \file */ | |
| 3 | 4 | |
| 4 | 5 | #ifndef __LIBBPF_BTF_H |
| 5 | 6 | #define __LIBBPF_BTF_H |
| @@ -30,11 +31,80 @@ enum btf_endianness { · 24 unmodified lines | ||
| 30 | 31 | BTF_BIG_ENDIAN = 1, |
| 31 | 32 | }; |
| 32 | 33 | |
| 34 | +/** | |
| 35 | + * @brief **btf__free()** frees all data of a BTF object | |
| 36 | + * @param btf BTF object to free | |
| 37 | + */ | |
| 33 | 38 | LIBBPF_API void btf__free(struct btf *btf); |
| 34 | 39 | |
| 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 | + */ | |
| 35 | 54 | 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 | + */ | |
| 36 | 76 | 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 | + */ | |
| 37 | 90 | 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 | + */ | |
| 38 | 108 | LIBBPF_API struct btf *btf__new_empty_split(struct btf *base_btf); |
| 39 | 109 | |
| 40 | 110 | 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 | ||
| 50 | 120 | |
| 51 | 121 | LIBBPF_API struct btf *btf__load_from_kernel_by_id(__u32 id); |
| 52 | 122 | 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") | |
| 53 | 124 | LIBBPF_API int btf__get_from_id(__u32 id, struct btf **btf); |
| 54 | 125 | |
| 55 | 126 | 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") | |
| 56 | 128 | LIBBPF_API int btf__load(struct btf *btf); |
| 57 | 129 | LIBBPF_API int btf__load_into_kernel(struct btf *btf); |
| 58 | 130 | 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 | ||
| 141 | 213 | LIBBPF_API int btf__add_datasec_var_info(struct btf *btf, int var_type_id, |
| 142 | 214 | __u32 offset, __u32 byte_sz); |
| 143 | 215 | |
| 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 | + | |
| 144 | 220 | struct btf_dedup_opts { |
| 145 | 221 | unsigned int dedup_table_size; |
| 146 | 222 | bool dont_resolve_fwds; |
| @@ -328,6 +404,11 @@ static inline bool btf_is_float(const struct btf_type *t) · 181 unmodified lines | ||
| 328 | 404 | return btf_kind(t) == BTF_KIND_FLOAT; |
| 329 | 405 | } |
| 330 | 406 | |
| 407 | +static inline bool btf_is_tag(const struct btf_type *t) | |
| 408 | +{ | |
| 409 | + return btf_kind(t) == BTF_KIND_TAG; | |
| 410 | +} | |
| 411 | + | |
| 331 | 412 | static inline __u8 btf_int_encoding(const struct btf_type *t) |
| 332 | 413 | { |
| 333 | 414 | return BTF_INT_ENCODING(*(__u32 *)(t + 1)); |
| @@ -396,6 +477,12 @@ btf_var_secinfos(const struct btf_type *t) · 62 unmodified lines | ||
| 396 | 477 | return (struct btf_var_secinfo *)(t + 1); |
| 397 | 478 | } |
| 398 | 479 | |
| 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 | + | |
| 399 | 486 | #ifdef __cplusplus |
| 400 | 487 | } /* extern "C" */ |
| 401 | 488 | #endif |
| @@ -316,6 +316,7 @@ static int btf_dump_mark_referenced(struct btf_dump *d) · 315 unmodified lines | ||
| 316 | 316 | case BTF_KIND_TYPEDEF: |
| 317 | 317 | case BTF_KIND_FUNC: |
| 318 | 318 | case BTF_KIND_VAR: |
| 319 | + case BTF_KIND_TAG: | |
| 319 | 320 | d->type_states[t->type].referenced = 1; |
| 320 | 321 | break; |
| 321 | 322 | |
| @@ -583,6 +584,7 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr) · 261 unmodified lines | ||
| 583 | 584 | case BTF_KIND_FUNC: |
| 584 | 585 | case BTF_KIND_VAR: |
| 585 | 586 | case BTF_KIND_DATASEC: |
| 587 | + case BTF_KIND_TAG: | |
| 586 | 588 | d->type_states[id].order_state = ORDERED; |
| 587 | 589 | return 0; |
| 588 | 590 | |
| @@ -2215,6 +2217,7 @@ static int btf_dump_dump_type_data(struct btf_dump *d, · 1626 unmodified lines | ||
| 2215 | 2217 | case BTF_KIND_FWD: |
| 2216 | 2218 | case BTF_KIND_FUNC: |
| 2217 | 2219 | case BTF_KIND_FUNC_PROTO: |
| 2220 | + case BTF_KIND_TAG: | |
| 2218 | 2221 | err = btf_dump_unsupported_data(d, t, id); |
| 2219 | 2222 | break; |
| 2220 | 2223 | case BTF_KIND_INT: |
| @@ -195,6 +195,8 @@ enum kern_feature_id { · 194 unmodified lines | ||
| 195 | 195 | FEAT_BTF_FLOAT, |
| 196 | 196 | /* BPF perf link support */ |
| 197 | 197 | FEAT_PERF_LINK, |
| 198 | + /* BTF_KIND_TAG support */ | |
| 199 | + FEAT_BTF_TAG, | |
| 198 | 200 | __FEAT_CNT, |
| 199 | 201 | }; |
| 200 | 202 | |
| @@ -218,8 +220,7 @@ struct reloc_desc { · 17 unmodified lines | ||
| 218 | 220 | |
| 219 | 221 | struct bpf_sec_def; |
| 220 | 222 | |
| 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); | |
| 223 | 224 | |
| 224 | 225 | struct bpf_sec_def { |
| 225 | 226 | const char *sec; |
| @@ -1987,6 +1988,7 @@ static const char *__btf_kind_str(__u16 kind) · 1761 unmodified lines | ||
| 1987 | 1988 | case BTF_KIND_VAR: return "var"; |
| 1988 | 1989 | case BTF_KIND_DATASEC: return "datasec"; |
| 1989 | 1990 | case BTF_KIND_FLOAT: return "float"; |
| 1991 | + case BTF_KIND_TAG: return "tag"; | |
| 1990 | 1992 | default: return "unknown"; |
| 1991 | 1993 | } |
| 1992 | 1994 | } |
| @@ -2486,8 +2488,9 @@ static bool btf_needs_sanitization(struct bpf_object *obj) · 493 unmodified lines | ||
| 2486 | 2488 | bool has_datasec = kernel_supports(obj, FEAT_BTF_DATASEC); |
| 2487 | 2489 | bool has_float = kernel_supports(obj, FEAT_BTF_FLOAT); |
| 2488 | 2490 | bool has_func = kernel_supports(obj, FEAT_BTF_FUNC); |
| 2491 | + bool has_tag = kernel_supports(obj, FEAT_BTF_TAG); | |
| 2489 | 2492 | |
| 2490 | − return !has_func || !has_datasec || !has_func_global || !has_float; | |
| 2493 | + return !has_func || !has_datasec || !has_func_global || !has_float || !has_tag; | |
| 2491 | 2494 | } |
| 2492 | 2495 | |
| 2493 | 2496 | 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 | ||
| 2496 | 2499 | bool has_datasec = kernel_supports(obj, FEAT_BTF_DATASEC); |
| 2497 | 2500 | bool has_float = kernel_supports(obj, FEAT_BTF_FLOAT); |
| 2498 | 2501 | bool has_func = kernel_supports(obj, FEAT_BTF_FUNC); |
| 2502 | + bool has_tag = kernel_supports(obj, FEAT_BTF_TAG); | |
| 2499 | 2503 | struct btf_type *t; |
| 2500 | 2504 | int i, j, vlen; |
| 2501 | 2505 | |
| 2502 | 2506 | for (i = 1; i <= btf__get_nr_types(btf); i++) { |
| 2503 | 2507 | t = (struct btf_type *)btf__type_by_id(btf, i); |
| 2504 | 2508 | |
| 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 */ | |
| 2507 | 2511 | t->info = BTF_INFO_ENC(BTF_KIND_INT, 0, 0); |
| 2508 | 2512 | /* |
| 2509 | 2513 | * 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 | ||
| 2993 | 2997 | } |
| 2994 | 2998 | } |
| 2995 | 2999 | |
| 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 | + | |
| 2996 | 3006 | scn = NULL; |
| 2997 | 3007 | while ((scn = elf_nextscn(elf, scn)) != NULL) { |
| 2998 | 3008 | idx++; |
| @@ -4207,6 +4217,23 @@ static int probe_kern_btf_float(void) · 1208 unmodified lines | ||
| 4207 | 4217 | strs, sizeof(strs))); |
| 4208 | 4218 | } |
| 4209 | 4219 | |
| 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 | + | |
| 4210 | 4237 | static int probe_kern_array_mmap(void) |
| 4211 | 4238 | { |
| 4212 | 4239 | struct bpf_create_map_attr attr = { |
| @@ -4423,6 +4450,9 @@ static struct kern_feature_desc { · 210 unmodified lines | ||
| 4423 | 4450 | [FEAT_PERF_LINK] = { |
| 4424 | 4451 | "BPF perf link support", probe_perf_link, |
| 4425 | 4452 | }, |
| 4453 | + [FEAT_BTF_TAG] = { | |
| 4454 | + "BTF_KIND_TAG support", probe_kern_btf_tag, | |
| 4455 | + }, | |
| 4426 | 4456 | }; |
| 4427 | 4457 | |
| 4428 | 4458 | 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 | ||
| 6367 | 6397 | |
| 6368 | 6398 | static const struct bpf_sec_def *find_sec_def(const char *sec_name); |
| 6369 | 6399 | |
| 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 | + | |
| 6370 | 6429 | static struct bpf_object * |
| 6371 | 6430 | __bpf_object__open(const char *path, const void *obj_buf, size_t obj_buf_sz, |
| 6372 | 6431 | const struct bpf_object_open_opts *opts) |
| 6373 | 6432 | { |
| 6374 | 6433 | const char *obj_name, *kconfig, *btf_tmp_path; |
| 6375 | − struct bpf_program *prog; | |
| 6376 | 6434 | struct bpf_object *obj; |
| 6377 | 6435 | char tmp_name[64]; |
| 6378 | 6436 | int err; |
| @@ -6430,30 +6488,12 @@ __bpf_object__open(const char *path, const void *obj_buf, size_t obj_buf_sz, · 51 unmodified lines | ||
| 6430 | 6488 | err = err ? : bpf_object__collect_externs(obj); |
| 6431 | 6489 | err = err ? : bpf_object__finalize_btf(obj); |
| 6432 | 6490 | err = err ? : bpf_object__init_maps(obj, opts); |
| 6491 | + err = err ? : bpf_object_init_progs(obj, opts); | |
| 6433 | 6492 | err = err ? : bpf_object__collect_relos(obj); |
| 6434 | 6493 | if (err) |
| 6435 | 6494 | goto out; |
| 6436 | − bpf_object__elf_finish(obj); | |
| 6437 | 6495 | |
| 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); | |
| 6457 | 6497 | |
| 6458 | 6498 | return obj; |
| 6459 | 6499 | out: |
| @@ -7907,18 +7947,12 @@ void bpf_program__set_expected_attach_type(struct bpf_program *prog, · 1447 unmodified lines | ||
| 7907 | 7947 | __VA_ARGS__ \ |
| 7908 | 7948 | } |
| 7909 | 7949 | |
| 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); | |
| 7922 | 7956 | |
| 7923 | 7957 | static const struct bpf_sec_def section_defs[] = { |
| 7924 | 7958 | 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 | ||
| 8244 | 8278 | return -EINVAL; |
| 8245 | 8279 | } |
| 8246 | 8280 | |
| 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 | + } | |
| 8257 | 8287 | |
| 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) { | |
| 8259 | 8292 | prog->attach_btf_id = st_ops->type_id; |
| 8260 | 8293 | 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; | |
| 8265 | 8294 | } |
| 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 | + | |
| 8266 | 8308 | st_ops->progs[member_idx] = prog; |
| 8267 | 8309 | } |
| 8268 | 8310 | |
| 8269 | 8311 | 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; | |
| 8276 | 8312 | } |
| 8277 | 8313 | |
| 8278 | 8314 | #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 | ||
| 8428 | 8464 | { |
| 8429 | 8465 | enum bpf_attach_type attach_type = prog->expected_attach_type; |
| 8430 | 8466 | __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 = §ion_defs[i]; | |
| 8445 | − break; | |
| 8446 | − } | |
| 8467 | + const char *attach_name; | |
| 8468 | + int err = 0; | |
| 8447 | 8469 | |
| 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); | |
| 8450 | 8473 | return -ESRCH; |
| 8451 | 8474 | } |
| 8452 | − attach_name = name + sec->len; | |
| 8475 | + attach_name = prog->sec_name + prog->sec_def->len; | |
| 8453 | 8476 | |
| 8454 | 8477 | /* BPF program's BTF ID */ |
| 8455 | 8478 | if (attach_prog_fd) { |
| @@ -8483,27 +8506,28 @@ int libbpf_attach_type_by_name(const char *name, · 27 unmodified lines | ||
| 8483 | 8506 | enum bpf_attach_type *attach_type) |
| 8484 | 8507 | { |
| 8485 | 8508 | char *type_names; |
| 8486 | − int i; | |
| 8509 | + const struct bpf_sec_def *sec_def; | |
| 8487 | 8510 | |
| 8488 | 8511 | if (!name) |
| 8489 | 8512 | return libbpf_err(-EINVAL); |
| 8490 | 8513 | |
| 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); | |
| 8504 | 8524 | } |
| 8505 | 8525 | |
| 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; | |
| 8507 | 8531 | } |
| 8508 | 8532 | |
| 8509 | 8533 | int bpf_map__fd(const struct bpf_map *map) |
| @@ -8987,9 +9011,57 @@ int bpf_link__unpin(struct bpf_link *link) · 477 unmodified lines | ||
| 8987 | 9011 | return 0; |
| 8988 | 9012 | } |
| 8989 | 9013 | |
| 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 | + | |
| 8990 | 9059 | struct bpf_link_perf { |
| 8991 | 9060 | struct bpf_link link; |
| 8992 | 9061 | 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; | |
| 8993 | 9065 | }; |
| 8994 | 9066 | |
| 8995 | 9067 | 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 | ||
| 9004 | 9076 | close(perf_link->perf_event_fd); |
| 9005 | 9077 | close(link->fd); |
| 9006 | 9078 | |
| 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; | |
| 9008 | 9085 | } |
| 9009 | 9086 | |
| 9010 | 9087 | static void bpf_link_perf_dealloc(struct bpf_link *link) |
| 9011 | 9088 | { |
| 9012 | 9089 | struct bpf_link_perf *perf_link = container_of(link, struct bpf_link_perf, link); |
| 9013 | 9090 | |
| 9091 | + free(perf_link->legacy_probe_name); | |
| 9014 | 9092 | free(perf_link); |
| 9015 | 9093 | } |
| 9016 | 9094 | |
| 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, | |
| 9018 | 9096 | const struct bpf_perf_event_opts *opts) |
| 9019 | 9097 | { |
| 9020 | 9098 | char errmsg[STRERR_BUFSIZE]; |
| @@ -9089,7 +9167,7 @@ err_out: · 68 unmodified lines | ||
| 9089 | 9167 | return libbpf_err_ptr(err); |
| 9090 | 9168 | } |
| 9091 | 9169 | |
| 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) | |
| 9093 | 9171 | { |
| 9094 | 9172 | return bpf_program__attach_perf_event_opts(prog, pfd, NULL); |
| 9095 | 9173 | } |
| @@ -9124,6 +9202,18 @@ static int parse_uint_from_file(const char *file, const char *fmt) · 28 unmodified lines | ||
| 9124 | 9202 | return ret; |
| 9125 | 9203 | } |
| 9126 | 9204 | |
| 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 | + | |
| 9127 | 9217 | static int determine_kprobe_perf_type(void) |
| 9128 | 9218 | { |
| 9129 | 9219 | 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 | ||
| 9206 | 9296 | return pfd; |
| 9207 | 9297 | } |
| 9208 | 9298 | |
| 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 | + | |
| 9209 | 9334 | struct bpf_link * |
| 9210 | −bpf_program__attach_kprobe_opts(struct bpf_program *prog, | |
| 9335 | +bpf_program__attach_kprobe_opts(const struct bpf_program *prog, | |
| 9211 | 9336 | const char *func_name, |
| 9212 | 9337 | const struct bpf_kprobe_opts *opts) |
| 9213 | 9338 | { |
| 9214 | 9339 | DECLARE_LIBBPF_OPTS(bpf_perf_event_opts, pe_opts); |
| 9215 | 9340 | char errmsg[STRERR_BUFSIZE]; |
| 9341 | + char *legacy_probe = NULL; | |
| 9216 | 9342 | struct bpf_link *link; |
| 9217 | 9343 | unsigned long offset; |
| 9218 | − bool retprobe; | |
| 9344 | + bool retprobe, legacy; | |
| 9219 | 9345 | int pfd, err; |
| 9220 | 9346 | |
| 9221 | 9347 | if (!OPTS_VALID(opts, bpf_kprobe_opts)) |
| @@ -9225,8 +9351,19 @@ bpf_program__attach_kprobe_opts(struct bpf_program *prog, · 3 unmodified lines | ||
| 9225 | 9351 | offset = OPTS_GET(opts, offset, 0); |
| 9226 | 9352 | pe_opts.bpf_cookie = OPTS_GET(opts, bpf_cookie, 0); |
| 9227 | 9353 | |
| 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 | + } | |
| 9230 | 9367 | if (pfd < 0) { |
| 9231 | 9368 | pr_warn("prog '%s': failed to create %s '%s' perf event: %s\n", |
| 9232 | 9369 | prog->name, retprobe ? "kretprobe" : "kprobe", func_name, |
| @@ -9242,10 +9379,17 @@ bpf_program__attach_kprobe_opts(struct bpf_program *prog, · 9 unmodified lines | ||
| 9242 | 9379 | libbpf_strerror_r(err, errmsg, sizeof(errmsg))); |
| 9243 | 9380 | return libbpf_err_ptr(err); |
| 9244 | 9381 | } |
| 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 | + | |
| 9245 | 9389 | return link; |
| 9246 | 9390 | } |
| 9247 | 9391 | |
| 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, | |
| 9249 | 9393 | bool retprobe, |
| 9250 | 9394 | const char *func_name) |
| 9251 | 9395 | { |
| @@ -9256,8 +9400,7 @@ struct bpf_link *bpf_program__attach_kprobe(struct bpf_program *prog, · 4 unmodified lines | ||
| 9256 | 9400 | return bpf_program__attach_kprobe_opts(prog, func_name, &opts); |
| 9257 | 9401 | } |
| 9258 | 9402 | |
| 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) | |
| 9261 | 9404 | { |
| 9262 | 9405 | DECLARE_LIBBPF_OPTS(bpf_kprobe_opts, opts); |
| 9263 | 9406 | unsigned long offset = 0; |
| @@ -9266,8 +9409,8 @@ static struct bpf_link *attach_kprobe(const struct bpf_sec_def *sec, · 2 unmodified lines | ||
| 9266 | 9409 | char *func; |
| 9267 | 9410 | int n, err; |
| 9268 | 9411 | |
| 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; | |
| 9271 | 9414 | |
| 9272 | 9415 | n = sscanf(func_name, "%m[a-zA-Z0-9_.]+%li", &func, &offset); |
| 9273 | 9416 | if (n < 1) { |
| @@ -9289,7 +9432,7 @@ static struct bpf_link *attach_kprobe(const struct bpf_sec_def *sec, · 15 unmodified lines | ||
| 9289 | 9432 | } |
| 9290 | 9433 | |
| 9291 | 9434 | 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, | |
| 9293 | 9436 | const char *binary_path, size_t func_offset, |
| 9294 | 9437 | const struct bpf_uprobe_opts *opts) |
| 9295 | 9438 | { |
| @@ -9329,7 +9472,7 @@ bpf_program__attach_uprobe_opts(struct bpf_program *prog, pid_t pid, · 33 unmodified lines | ||
| 9329 | 9472 | return link; |
| 9330 | 9473 | } |
| 9331 | 9474 | |
| 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, | |
| 9333 | 9476 | bool retprobe, pid_t pid, |
| 9334 | 9477 | const char *binary_path, |
| 9335 | 9478 | size_t func_offset) |
| @@ -9389,7 +9532,7 @@ static int perf_event_open_tracepoint(const char *tp_category, · 53 unmodified lines | ||
| 9389 | 9532 | return pfd; |
| 9390 | 9533 | } |
| 9391 | 9534 | |
| 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, | |
| 9393 | 9536 | const char *tp_category, |
| 9394 | 9537 | const char *tp_name, |
| 9395 | 9538 | 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 | ||
| 9423 | 9566 | return link; |
| 9424 | 9567 | } |
| 9425 | 9568 | |
| 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, | |
| 9427 | 9570 | const char *tp_category, |
| 9428 | 9571 | const char *tp_name) |
| 9429 | 9572 | { |
| 9430 | 9573 | return bpf_program__attach_tracepoint_opts(prog, tp_category, tp_name, NULL); |
| 9431 | 9574 | } |
| 9432 | 9575 | |
| 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) | |
| 9435 | 9577 | { |
| 9436 | 9578 | char *sec_name, *tp_cat, *tp_name; |
| 9437 | 9579 | struct bpf_link *link; |
| @@ -9441,7 +9583,7 @@ static struct bpf_link *attach_tp(const struct bpf_sec_def *sec, · 3 unmodified lines | ||
| 9441 | 9583 | return libbpf_err_ptr(-ENOMEM); |
| 9442 | 9584 | |
| 9443 | 9585 | /* extract "tp/<category>/<name>" */ |
| 9444 | − tp_cat = sec_name + sec->len; | |
| 9586 | + tp_cat = sec_name + prog->sec_def->len; | |
| 9445 | 9587 | tp_name = strchr(tp_cat, '/'); |
| 9446 | 9588 | if (!tp_name) { |
| 9447 | 9589 | free(sec_name); |
| @@ -9455,7 +9597,7 @@ static struct bpf_link *attach_tp(const struct bpf_sec_def *sec, · 7 unmodified lines | ||
| 9455 | 9597 | return link; |
| 9456 | 9598 | } |
| 9457 | 9599 | |
| 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, | |
| 9459 | 9601 | const char *tp_name) |
| 9460 | 9602 | { |
| 9461 | 9603 | char errmsg[STRERR_BUFSIZE]; |
| @@ -9485,16 +9627,15 @@ struct bpf_link *bpf_program__attach_raw_tracepoint(struct bpf_program *prog, · 23 unmodified lines | ||
| 9485 | 9627 | return link; |
| 9486 | 9628 | } |
| 9487 | 9629 | |
| 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) | |
| 9490 | 9631 | { |
| 9491 | − const char *tp_name = prog->sec_name + sec->len; | |
| 9632 | + const char *tp_name = prog->sec_name + prog->sec_def->len; | |
| 9492 | 9633 | |
| 9493 | 9634 | return bpf_program__attach_raw_tracepoint(prog, tp_name); |
| 9494 | 9635 | } |
| 9495 | 9636 | |
| 9496 | 9637 | /* 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) | |
| 9498 | 9639 | { |
| 9499 | 9640 | char errmsg[STRERR_BUFSIZE]; |
| 9500 | 9641 | struct bpf_link *link; |
| @@ -9523,30 +9664,28 @@ static struct bpf_link *bpf_program__attach_btf_id(struct bpf_program *prog) · 22 unmodified lines | ||
| 9523 | 9664 | return (struct bpf_link *)link; |
| 9524 | 9665 | } |
| 9525 | 9666 | |
| 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) | |
| 9527 | 9668 | { |
| 9528 | 9669 | return bpf_program__attach_btf_id(prog); |
| 9529 | 9670 | } |
| 9530 | 9671 | |
| 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) | |
| 9532 | 9673 | { |
| 9533 | 9674 | return bpf_program__attach_btf_id(prog); |
| 9534 | 9675 | } |
| 9535 | 9676 | |
| 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) | |
| 9538 | 9678 | { |
| 9539 | 9679 | return bpf_program__attach_trace(prog); |
| 9540 | 9680 | } |
| 9541 | 9681 | |
| 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) | |
| 9544 | 9683 | { |
| 9545 | 9684 | return bpf_program__attach_lsm(prog); |
| 9546 | 9685 | } |
| 9547 | 9686 | |
| 9548 | 9687 | 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, | |
| 9550 | 9689 | const char *target_name) |
| 9551 | 9690 | { |
| 9552 | 9691 | 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 | ||
| 9582 | 9721 | } |
| 9583 | 9722 | |
| 9584 | 9723 | 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) | |
| 9586 | 9725 | { |
| 9587 | 9726 | return bpf_program__attach_fd(prog, cgroup_fd, 0, "cgroup"); |
| 9588 | 9727 | } |
| 9589 | 9728 | |
| 9590 | 9729 | 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) | |
| 9592 | 9731 | { |
| 9593 | 9732 | return bpf_program__attach_fd(prog, netns_fd, 0, "netns"); |
| 9594 | 9733 | } |
| 9595 | 9734 | |
| 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) | |
| 9597 | 9736 | { |
| 9598 | 9737 | /* target_fd/target_ifindex use the same field in LINK_CREATE */ |
| 9599 | 9738 | return bpf_program__attach_fd(prog, ifindex, 0, "xdp"); |
| 9600 | 9739 | } |
| 9601 | 9740 | |
| 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, | |
| 9603 | 9742 | int target_fd, |
| 9604 | 9743 | const char *attach_func_name) |
| 9605 | 9744 | { |
| @@ -9632,7 +9771,7 @@ struct bpf_link *bpf_program__attach_freplace(struct bpf_program *prog, · 26 unmodified lines | ||
| 9632 | 9771 | } |
| 9633 | 9772 | |
| 9634 | 9773 | struct bpf_link * |
| 9635 | −bpf_program__attach_iter(struct bpf_program *prog, | |
| 9774 | +bpf_program__attach_iter(const struct bpf_program *prog, | |
| 9636 | 9775 | const struct bpf_iter_attach_opts *opts) |
| 9637 | 9776 | { |
| 9638 | 9777 | 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 | ||
| 9671 | 9810 | return link; |
| 9672 | 9811 | } |
| 9673 | 9812 | |
| 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) | |
| 9676 | 9814 | { |
| 9677 | 9815 | return bpf_program__attach_iter(prog, NULL); |
| 9678 | 9816 | } |
| 9679 | 9817 | |
| 9680 | −struct bpf_link *bpf_program__attach(struct bpf_program *prog) | |
| 9818 | +struct bpf_link *bpf_program__attach(const struct bpf_program *prog) | |
| 9681 | 9819 | { |
| 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) | |
| 9686 | 9821 | return libbpf_err_ptr(-ESRCH); |
| 9687 | 9822 | |
| 9688 | − return sec_def->attach_fn(sec_def, prog); | |
| 9823 | + return prog->sec_def->attach_fn(prog); | |
| 9689 | 9824 | } |
| 9690 | 9825 | |
| 9691 | 9826 | 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 | ||
| 9698 | 9833 | return 0; |
| 9699 | 9834 | } |
| 9700 | 9835 | |
| 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) | |
| 9702 | 9837 | { |
| 9703 | 9838 | struct bpf_struct_ops *st_ops; |
| 9704 | 9839 | struct bpf_link *link; |
| @@ -10511,18 +10646,29 @@ int bpf_program__set_attach_target(struct bpf_program *prog, · 806 unmodified lines | ||
| 10511 | 10646 | { |
| 10512 | 10647 | int btf_obj_fd = 0, btf_id = 0, err; |
| 10513 | 10648 | |
| 10514 | − if (!prog || attach_prog_fd < 0 || !attach_func_name) | |
| 10649 | + if (!prog || attach_prog_fd < 0) | |
| 10515 | 10650 | return libbpf_err(-EINVAL); |
| 10516 | 10651 | |
| 10517 | 10652 | if (prog->obj->loaded) |
| 10518 | 10653 | return libbpf_err(-EINVAL); |
| 10519 | 10654 | |
| 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 | + | |
| 10520 | 10663 | if (attach_prog_fd) { |
| 10521 | 10664 | btf_id = libbpf_find_prog_btf_id(attach_func_name, |
| 10522 | 10665 | attach_prog_fd); |
| 10523 | 10666 | if (btf_id < 0) |
| 10524 | 10667 | return libbpf_err(btf_id); |
| 10525 | 10668 | } else { |
| 10669 | + if (!attach_func_name) | |
| 10670 | + return libbpf_err(-EINVAL); | |
| 10671 | + | |
| 10526 | 10672 | /* load btf_vmlinux, if not yet */ |
| 10527 | 10673 | err = bpf_object__load_vmlinux_btf(prog->obj, true); |
| 10528 | 10674 | if (err) |
| @@ -10764,16 +10910,15 @@ int bpf_object__attach_skeleton(struct bpf_object_skeleton *s) · 235 unmodified lines | ||
| 10764 | 10910 | for (i = 0; i < s->prog_cnt; i++) { |
| 10765 | 10911 | struct bpf_program *prog = *s->progs[i].prog; |
| 10766 | 10912 | struct bpf_link **link = s->progs[i].link; |
| 10767 | − const struct bpf_sec_def *sec_def; | |
| 10768 | 10913 | |
| 10769 | 10914 | if (!prog->load) |
| 10770 | 10915 | continue; |
| 10771 | 10916 | |
| 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) | |
| 10774 | 10919 | continue; |
| 10775 | 10920 | |
| 10776 | − *link = sec_def->attach_fn(sec_def, prog); | |
| 10921 | + *link = bpf_program__attach(prog); | |
| 10777 | 10922 | err = libbpf_get_error(*link); |
| 10778 | 10923 | if (err) { |
| 10779 | 10924 | pr_warn("failed to auto-attach program '%s': %d\n", |
| @@ -83,12 +83,15 @@ struct bpf_object_open_opts { · 82 unmodified lines | ||
| 83 | 83 | * Non-relocatable instructions are replaced with invalid ones to |
| 84 | 84 | * prevent accidental errors. |
| 85 | 85 | * */ |
| 86 | + LIBBPF_DEPRECATED_SINCE(0, 6, "field has no effect") | |
| 86 | 87 | bool relaxed_core_relocs; |
| 87 | 88 | /* maps that set the 'pinning' attribute in their definition will have |
| 88 | 89 | * their pin_path attribute set to a file in this directory, and be |
| 89 | 90 | * auto-pinned to that path on load; defaults to "/sys/fs/bpf". |
| 90 | 91 | */ |
| 91 | 92 | const char *pin_root_path; |
| 93 | + | |
| 94 | + LIBBPF_DEPRECATED_SINCE(0, 7, "use bpf_program__set_attach_target() on each individual bpf_program") | |
| 92 | 95 | __u32 attach_prog_fd; |
| 93 | 96 | /* Additional kernel config content that augments and overrides |
| 94 | 97 | * system Kconfig for CONFIG_xxx externs. |
| @@ -243,7 +246,7 @@ LIBBPF_API int bpf_link__detach(struct bpf_link *link); · 148 unmodified lines | ||
| 243 | 246 | LIBBPF_API int bpf_link__destroy(struct bpf_link *link); |
| 244 | 247 | |
| 245 | 248 | LIBBPF_API struct bpf_link * |
| 246 | −bpf_program__attach(struct bpf_program *prog); | |
| 249 | +bpf_program__attach(const struct bpf_program *prog); | |
| 247 | 250 | |
| 248 | 251 | struct bpf_perf_event_opts { |
| 249 | 252 | /* size of this struct, for forward/backward compatiblity */ |
| @@ -254,10 +257,10 @@ struct bpf_perf_event_opts { · 4 unmodified lines | ||
| 254 | 257 | #define bpf_perf_event_opts__last_field bpf_cookie |
| 255 | 258 | |
| 256 | 259 | 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); | |
| 258 | 261 | |
| 259 | 262 | 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, | |
| 261 | 264 | const struct bpf_perf_event_opts *opts); |
| 262 | 265 | |
| 263 | 266 | struct bpf_kprobe_opts { |
| @@ -274,10 +277,10 @@ struct bpf_kprobe_opts { · 10 unmodified lines | ||
| 274 | 277 | #define bpf_kprobe_opts__last_field retprobe |
| 275 | 278 | |
| 276 | 279 | 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, | |
| 278 | 281 | const char *func_name); |
| 279 | 282 | 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, | |
| 281 | 284 | const char *func_name, |
| 282 | 285 | const struct bpf_kprobe_opts *opts); |
| 283 | 286 | |
| @@ -297,11 +300,11 @@ struct bpf_uprobe_opts { · 13 unmodified lines | ||
| 297 | 300 | #define bpf_uprobe_opts__last_field retprobe |
| 298 | 301 | |
| 299 | 302 | 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, | |
| 301 | 304 | pid_t pid, const char *binary_path, |
| 302 | 305 | size_t func_offset); |
| 303 | 306 | 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, | |
| 305 | 308 | const char *binary_path, size_t func_offset, |
| 306 | 309 | const struct bpf_uprobe_opts *opts); |
| 307 | 310 | |
| @@ -314,35 +317,35 @@ struct bpf_tracepoint_opts { · 6 unmodified lines | ||
| 314 | 317 | #define bpf_tracepoint_opts__last_field bpf_cookie |
| 315 | 318 | |
| 316 | 319 | LIBBPF_API struct bpf_link * |
| 317 | −bpf_program__attach_tracepoint(struct bpf_program *prog, | |
| 320 | +bpf_program__attach_tracepoint(const struct bpf_program *prog, | |
| 318 | 321 | const char *tp_category, |
| 319 | 322 | const char *tp_name); |
| 320 | 323 | 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, | |
| 322 | 325 | const char *tp_category, |
| 323 | 326 | const char *tp_name, |
| 324 | 327 | const struct bpf_tracepoint_opts *opts); |
| 325 | 328 | |
| 326 | 329 | 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, | |
| 328 | 331 | const char *tp_name); |
| 329 | 332 | LIBBPF_API struct bpf_link * |
| 330 | −bpf_program__attach_trace(struct bpf_program *prog); | |
| 333 | +bpf_program__attach_trace(const struct bpf_program *prog); | |
| 331 | 334 | LIBBPF_API struct bpf_link * |
| 332 | −bpf_program__attach_lsm(struct bpf_program *prog); | |
| 335 | +bpf_program__attach_lsm(const struct bpf_program *prog); | |
| 333 | 336 | 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); | |
| 335 | 338 | 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); | |
| 337 | 340 | 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); | |
| 339 | 342 | LIBBPF_API struct bpf_link * |
| 340 | −bpf_program__attach_freplace(struct bpf_program *prog, | |
| 343 | +bpf_program__attach_freplace(const struct bpf_program *prog, | |
| 341 | 344 | int target_fd, const char *attach_func_name); |
| 342 | 345 | |
| 343 | 346 | struct bpf_map; |
| 344 | 347 | |
| 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); | |
| 346 | 349 | |
| 347 | 350 | struct bpf_iter_attach_opts { |
| 348 | 351 | size_t sz; /* size of this struct for forward/backward compatibility */ |
| @@ -352,7 +355,7 @@ struct bpf_iter_attach_opts { · 3 unmodified lines | ||
| 352 | 355 | #define bpf_iter_attach_opts__last_field link_info_len |
| 353 | 356 | |
| 354 | 357 | LIBBPF_API struct bpf_link * |
| 355 | −bpf_program__attach_iter(struct bpf_program *prog, | |
| 358 | +bpf_program__attach_iter(const struct bpf_program *prog, | |
| 356 | 359 | const struct bpf_iter_attach_opts *opts); |
| 357 | 360 | |
| 358 | 361 | struct bpf_insn; |
| @@ -854,7 +857,7 @@ struct bpf_object_skeleton { · 495 unmodified lines | ||
| 854 | 857 | size_t sz; /* size of this struct, for forward/backward compatibility */ |
| 855 | 858 | |
| 856 | 859 | const char *name; |
| 857 | − void *data; | |
| 860 | + const void *data; | |
| 858 | 861 | size_t data_sz; |
| 859 | 862 | |
| 860 | 863 | struct bpf_object **obj; |
| @@ -386,3 +386,8 @@ LIBBPF_0.5.0 { · 385 unmodified lines | ||
| 386 | 386 | btf_dump__dump_type_data; |
| 387 | 387 | libbpf_set_strict_mode; |
| 388 | 388 | } LIBBPF_0.4.0; |
| 389 | + | |
| 390 | +LIBBPF_0.6.0 { | |
| 391 | + global: | |
| 392 | + btf__add_tag; | |
| 393 | +} LIBBPF_0.5.0; | |
| @@ -10,6 +10,7 @@ · 9 unmodified lines | ||
| 10 | 10 | #define __LIBBPF_LIBBPF_COMMON_H |
| 11 | 11 | |
| 12 | 12 | #include <string.h> |
| 13 | +#include "libbpf_version.h" | |
| 13 | 14 | |
| 14 | 15 | #ifndef LIBBPF_API |
| 15 | 16 | #define LIBBPF_API __attribute__((visibility("default"))) |
| @@ -17,6 +18,29 @@ · 1 unmodified line | ||
| 17 | 18 | |
| 18 | 19 | #define LIBBPF_DEPRECATED(msg) __attribute__((deprecated(msg))) |
| 19 | 20 | |
| 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 | + | |
| 20 | 44 | /* Helper macro to declare and initialize libbpf options struct |
| 21 | 45 | * |
| 22 | 46 | * This dance with uninitialized declaration, followed by memset to zero, |
| @@ -69,6 +69,8 @@ · 68 unmodified lines | ||
| 69 | 69 | #define BTF_VAR_SECINFO_ENC(type, offset, size) (type), (offset), (size) |
| 70 | 70 | #define BTF_TYPE_FLOAT_ENC(name, sz) \ |
| 71 | 71 | 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) | |
| 72 | 74 | |
| 73 | 75 | #ifndef likely |
| 74 | 76 | #define likely(x) __builtin_expect(!!(x), 1) |
| @@ -90,17 +92,30 @@ · 15 unmodified lines | ||
| 90 | 92 | /* Symbol versioning is different between static and shared library. |
| 91 | 93 | * Properly versioned symbols are needed for shared library, but |
| 92 | 94 | * 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. | |
| 93 | 97 | */ |
| 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) \ | |
| 96 | 108 | 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) \ | |
| 98 | 110 | 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) \ | |
| 102 | 116 | extern typeof(internal_name) api_name \ |
| 103 | 117 | __attribute__((alias(#internal_name))); |
| 118 | + | |
| 104 | 119 | #endif |
| 105 | 120 | |
| 106 | 121 | extern void libbpf_print(enum libbpf_print_level level, |
| @@ -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 */ | |
| @@ -281,6 +281,7 @@ out_mmap: · 280 unmodified lines | ||
| 281 | 281 | return err; |
| 282 | 282 | } |
| 283 | 283 | |
| 284 | +DEFAULT_VERSION(xsk_umem__create_v0_0_4, xsk_umem__create, LIBBPF_0.0.4) | |
| 284 | 285 | int xsk_umem__create_v0_0_4(struct xsk_umem **umem_ptr, void *umem_area, |
| 285 | 286 | __u64 size, struct xsk_ring_prod *fill, |
| 286 | 287 | struct xsk_ring_cons *comp, |
| @@ -345,6 +346,7 @@ struct xsk_umem_config_v1 { · 58 unmodified lines | ||
| 345 | 346 | __u32 frame_headroom; |
| 346 | 347 | }; |
| 347 | 348 | |
| 349 | +COMPAT_VERSION(xsk_umem__create_v0_0_2, xsk_umem__create, LIBBPF_0.0.2) | |
| 348 | 350 | int xsk_umem__create_v0_0_2(struct xsk_umem **umem_ptr, void *umem_area, |
| 349 | 351 | __u64 size, struct xsk_ring_prod *fill, |
| 350 | 352 | 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 | ||
| 358 | 360 | return xsk_umem__create_v0_0_4(umem_ptr, umem_area, size, fill, comp, |
| 359 | 361 | &config); |
| 360 | 362 | } |
| 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) | |
| 363 | 363 | |
| 364 | 364 | static enum xsk_prog get_xsk_prog(void) |
| 365 | 365 | { |
| @@ -9,8 +9,9 @@ test_tag · 8 unmodified lines | ||
| 9 | 9 | FEATURE-DUMP.libbpf |
| 10 | 10 | fixdep |
| 11 | 11 | test_dev_cgroup |
| 12 | −/test_progs* | |
| 13 | −!test_progs.h | |
| 12 | +/test_progs | |
| 13 | +/test_progs-no_alu32 | |
| 14 | +/test_progs-bpf_gcc | |
| 14 | 15 | test_verifier_log |
| 15 | 16 | feature |
| 16 | 17 | test_sock |
| @@ -512,14 +512,14 @@ $(OUTPUT)/test_cpp: test_cpp.cpp $(OUTPUT)/test_core_extern.skel.h $(BPFOBJ) · 511 unmodified lines | ||
| 512 | 512 | $(Q)$(CXX) $(CFLAGS) $(filter %.a %.o %.cpp,$^) $(LDLIBS) -o $@ |
| 513 | 513 | |
| 514 | 514 | # Benchmark runner |
| 515 | −$(OUTPUT)/bench_%.o: benchs/bench_%.c bench.h | |
| 515 | +$(OUTPUT)/bench_%.o: benchs/bench_%.c bench.h $(BPFOBJ) | |
| 516 | 516 | $(call msg,CC,,$@) |
| 517 | 517 | $(Q)$(CC) $(CFLAGS) -c $(filter %.c,$^) $(LDLIBS) -o $@ |
| 518 | 518 | $(OUTPUT)/bench_rename.o: $(OUTPUT)/test_overhead.skel.h |
| 519 | 519 | $(OUTPUT)/bench_trigger.o: $(OUTPUT)/trigger_bench.skel.h |
| 520 | 520 | $(OUTPUT)/bench_ringbufs.o: $(OUTPUT)/ringbuf_bench.skel.h \ |
| 521 | 521 | $(OUTPUT)/perfbuf_bench.skel.h |
| 522 | −$(OUTPUT)/bench.o: bench.h testing_helpers.h | |
| 522 | +$(OUTPUT)/bench.o: bench.h testing_helpers.h $(BPFOBJ) | |
| 523 | 523 | $(OUTPUT)/bench: LDLIBS += -lm |
| 524 | 524 | $(OUTPUT)/bench: $(OUTPUT)/bench.o $(OUTPUT)/testing_helpers.o \ |
| 525 | 525 | $(OUTPUT)/bench_count.o \ |
| @@ -201,6 +201,20 @@ Without it, the error from compiling bpf selftests looks like: · 200 unmodified lines | ||
| 201 | 201 | |
| 202 | 202 | __ https://reviews.llvm.org/D93563 |
| 203 | 203 | |
| 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 | + | |
| 204 | 218 | Clang dependencies for static linking tests |
| 205 | 219 | =========================================== |
| 206 | 220 | |
| @@ -13,6 +13,18 @@ · 12 unmodified lines | ||
| 13 | 13 | |
| 14 | 14 | DEFINE_PER_CPU(int, bpf_testmod_ksym_percpu) = 123; |
| 15 | 15 | |
| 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 | + | |
| 16 | 28 | noinline ssize_t |
| 17 | 29 | bpf_testmod_test_read(struct file *file, struct kobject *kobj, |
| 18 | 30 | struct bin_attribute *bin_attr, |
| @@ -24,7 +36,11 @@ bpf_testmod_test_read(struct file *file, struct kobject *kobj, · 5 unmodified lines | ||
| 24 | 36 | .len = len, |
| 25 | 37 | }; |
| 26 | 38 | |
| 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); | |
| 28 | 44 | |
| 29 | 45 | return -EIO; /* always fail */ |
| 30 | 46 | } |
| @@ -71,4 +87,3 @@ module_exit(bpf_testmod_exit); · 40 unmodified lines | ||
| 71 | 87 | MODULE_AUTHOR("Andrii Nakryiko"); |
| 72 | 88 | MODULE_DESCRIPTION("BPF selftests module"); |
| 73 | 89 | MODULE_LICENSE("Dual BSD/GPL"); |
| 74 | − | |
| @@ -24,11 +24,12 @@ static const char * const btf_kind_str_mapping[] = { · 23 unmodified lines | ||
| 24 | 24 | [BTF_KIND_VAR] = "VAR", |
| 25 | 25 | [BTF_KIND_DATASEC] = "DATASEC", |
| 26 | 26 | [BTF_KIND_FLOAT] = "FLOAT", |
| 27 | + [BTF_KIND_TAG] = "TAG", | |
| 27 | 28 | }; |
| 28 | 29 | |
| 29 | 30 | static const char *btf_kind_str(__u16 kind) |
| 30 | 31 | { |
| 31 | − if (kind > BTF_KIND_DATASEC) | |
| 32 | + if (kind > BTF_KIND_TAG) | |
| 32 | 33 | return "UNKNOWN"; |
| 33 | 34 | return btf_kind_str_mapping[kind]; |
| 34 | 35 | } |
| @@ -177,6 +178,10 @@ int fprintf_btf_type_raw(FILE *out, const struct btf *btf, __u32 id) · 142 unmodified lines | ||
| 177 | 178 | case BTF_KIND_FLOAT: |
| 178 | 179 | fprintf(out, " size=%u", t->size); |
| 179 | 180 | 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; | |
| 180 | 185 | default: |
| 181 | 186 | break; |
| 182 | 187 | } |
| @@ -589,7 +589,7 @@ out: · 588 unmodified lines | ||
| 589 | 589 | |
| 590 | 590 | static void test_bpf_hash_map(void) |
| 591 | 591 | { |
| 592 | − __u32 expected_key_a = 0, expected_key_b = 0, expected_key_c = 0; | |
| 592 | + __u32 expected_key_a = 0, expected_key_b = 0; | |
| 593 | 593 | DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts); |
| 594 | 594 | struct bpf_iter_bpf_hash_map *skel; |
| 595 | 595 | int err, i, len, map_fd, iter_fd; |
| @@ -638,7 +638,6 @@ static void test_bpf_hash_map(void) · 42 unmodified lines | ||
| 638 | 638 | val = i + 4; |
| 639 | 639 | expected_key_a += key.a; |
| 640 | 640 | expected_key_b += key.b; |
| 641 | − expected_key_c += key.c; | |
| 642 | 641 | expected_val += val; |
| 643 | 642 | |
| 644 | 643 | err = bpf_map_update_elem(map_fd, &key, &val, BPF_ANY); |
| @@ -685,7 +684,7 @@ out: · 40 unmodified lines | ||
| 685 | 684 | |
| 686 | 685 | static void test_bpf_percpu_hash_map(void) |
| 687 | 686 | { |
| 688 | − __u32 expected_key_a = 0, expected_key_b = 0, expected_key_c = 0; | |
| 687 | + __u32 expected_key_a = 0, expected_key_b = 0; | |
| 689 | 688 | DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts); |
| 690 | 689 | struct bpf_iter_bpf_percpu_hash_map *skel; |
| 691 | 690 | int err, i, j, len, map_fd, iter_fd; |
| @@ -722,7 +721,6 @@ static void test_bpf_percpu_hash_map(void) · 30 unmodified lines | ||
| 722 | 721 | key.c = i + 3; |
| 723 | 722 | expected_key_a += key.a; |
| 724 | 723 | expected_key_b += key.b; |
| 725 | − expected_key_c += key.c; | |
| 726 | 724 | |
| 727 | 725 | for (j = 0; j < bpf_num_possible_cpus(); j++) { |
| 728 | 726 | *(__u32 *)(val + j * 8) = i + j; |
| @@ -39,8 +39,8 @@ static bool always_log; · 38 unmodified lines | ||
| 39 | 39 | #define BTF_END_RAW 0xdeadbeef |
| 40 | 40 | #define NAME_TBD 0xdeadb33f |
| 41 | 41 | |
| 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) | |
| 44 | 44 | #define GET_NAME_NTH_IDX(X) (X & 0x0000ffff) |
| 45 | 45 | |
| 46 | 46 | #define MAX_NR_RAW_U32 1024 |
| @@ -3661,6 +3661,249 @@ static struct btf_raw_test raw_tests[] = { · 3614 unmodified lines | ||
| 3661 | 3661 | .err_str = "Invalid type_size", |
| 3662 | 3662 | }, |
| 3663 | 3663 | |
| 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 | + | |
| 3664 | 3907 | }; /* struct btf_raw_test raw_tests[] */ |
| 3665 | 3908 | |
| 3666 | 3909 | 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 | ||
| 6421 | 6664 | BTF_MEMBER_ENC(NAME_NTH(4), 5, 64), /* const int *a; */ |
| 6422 | 6665 | BTF_MEMBER_ENC(NAME_NTH(5), 2, 128), /* int b[16]; */ |
| 6423 | 6666 | 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; */ | |
| 6425 | 6668 | /* ptr -> [3] struct s */ |
| 6426 | 6669 | BTF_PTR_ENC(3), /* [4] */ |
| 6427 | 6670 | /* ptr -> [6] const int */ |
| 6428 | 6671 | BTF_PTR_ENC(6), /* [5] */ |
| 6429 | 6672 | /* const -> [1] int */ |
| 6430 | 6673 | 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] */ | |
| 6431 | 6678 | |
| 6432 | 6679 | /* 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] */ | |
| 6445 | 6694 | BTF_END_RAW, |
| 6446 | 6695 | }, |
| 6447 | 6696 | 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 | ||
| 6458 | 6707 | BTF_MEMBER_ENC(NAME_NTH(1), 5, 64), /* const int *a; */ |
| 6459 | 6708 | BTF_MEMBER_ENC(NAME_NTH(2), 2, 128), /* int b[16]; */ |
| 6460 | 6709 | 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; */ | |
| 6462 | 6711 | /* ptr -> [3] struct s */ |
| 6463 | 6712 | BTF_PTR_ENC(3), /* [4] */ |
| 6464 | 6713 | /* ptr -> [6] const int */ |
| 6465 | 6714 | BTF_PTR_ENC(6), /* [5] */ |
| 6466 | 6715 | /* const -> [1] int */ |
| 6467 | 6716 | 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] */ | |
| 6469 | 6720 | BTF_END_RAW, |
| 6470 | 6721 | }, |
| 6471 | 6722 | 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 | ||
| 6590 | 6841 | BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 8), |
| 6591 | 6842 | BTF_FUNC_ENC(NAME_TBD, 12), /* [13] func */ |
| 6592 | 6843 | 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 */ | |
| 6593 | 6846 | BTF_END_RAW, |
| 6594 | 6847 | }, |
| 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"), | |
| 6596 | 6849 | }, |
| 6597 | 6850 | .expect = { |
| 6598 | 6851 | .raw_types = { |
| @@ -6616,9 +6869,11 @@ const struct btf_dedup_test dedup_tests[] = { · 17 unmodified lines | ||
| 6616 | 6869 | BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 8), |
| 6617 | 6870 | BTF_FUNC_ENC(NAME_TBD, 12), /* [13] func */ |
| 6618 | 6871 | 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 */ | |
| 6619 | 6874 | BTF_END_RAW, |
| 6620 | 6875 | }, |
| 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"), | |
| 6622 | 6877 | }, |
| 6623 | 6878 | .opts = { |
| 6624 | 6879 | .dont_resolve_fwds = false, |
| @@ -6767,6 +7022,152 @@ const struct btf_dedup_test dedup_tests[] = { · 142 unmodified lines | ||
| 6767 | 7022 | .dedup_table_size = 1 |
| 6768 | 7023 | }, |
| 6769 | 7024 | }, |
| 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 | +}, | |
| 6770 | 7171 | |
| 6771 | 7172 | }; |
| 6772 | 7173 | |
| @@ -6801,6 +7202,8 @@ static int btf_type_size(const struct btf_type *t) · 28 unmodified lines | ||
| 6801 | 7202 | return base_size + sizeof(struct btf_var); |
| 6802 | 7203 | case BTF_KIND_DATASEC: |
| 6803 | 7204 | return base_size + vlen * sizeof(struct btf_var_secinfo); |
| 7205 | + case BTF_KIND_TAG: | |
| 7206 | + return base_size + sizeof(struct btf_tag); | |
| 6804 | 7207 | default: |
| 6805 | 7208 | fprintf(stderr, "Unsupported BTF_KIND:%u\n", kind); |
| 6806 | 7209 | return -EINVAL; |
| @@ -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 | +} | |
| @@ -281,5 +281,26 @@ void test_btf_write() { · 280 unmodified lines | ||
| 281 | 281 | "[17] DATASEC 'datasec1' size=12 vlen=1\n" |
| 282 | 282 | "\ttype_id=1 offset=4 size=8", "raw_dump"); |
| 283 | 283 | |
| 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 | + | |
| 284 | 305 | btf__free(btf); |
| 285 | 306 | } |
| @@ -30,7 +30,7 @@ static int duration = 0; · 29 unmodified lines | ||
| 30 | 30 | .output_len = sizeof(struct core_reloc_module_output), \ |
| 31 | 31 | .prog_sec_name = sec_name, \ |
| 32 | 32 | .raw_tp_name = tp_name, \ |
| 33 | − .trigger = trigger_module_test_read, \ | |
| 33 | + .trigger = __trigger_module_test_read, \ | |
| 34 | 34 | .needs_testmod = true, \ |
| 35 | 35 | } |
| 36 | 36 | |
| @@ -249,8 +249,7 @@ static int duration = 0; · 212 unmodified lines | ||
| 249 | 249 | #define SIZE_CASE_COMMON(name) \ |
| 250 | 250 | .case_name = #name, \ |
| 251 | 251 | .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" | |
| 254 | 253 | |
| 255 | 254 | #define SIZE_OUTPUT_DATA(type) \ |
| 256 | 255 | 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 | ||
| 475 | 474 | return 0; |
| 476 | 475 | } |
| 477 | 476 | |
| 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) | |
| 479 | 478 | { |
| 480 | 479 | 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); | |
| 490 | 480 | |
| 481 | + trigger_module_test_read(exp->len); | |
| 491 | 482 | return 0; |
| 492 | 483 | } |
| 493 | 484 | |
| @@ -60,7 +60,7 @@ static void test_fexit_bpf2bpf_common(const char *obj_file, · 59 unmodified lines | ||
| 60 | 60 | struct bpf_object *obj = NULL, *tgt_obj; |
| 61 | 61 | __u32 retval, tgt_prog_id, info_len; |
| 62 | 62 | struct bpf_prog_info prog_info = {}; |
| 63 | − struct bpf_program **prog = NULL; | |
| 63 | + struct bpf_program **prog = NULL, *p; | |
| 64 | 64 | struct bpf_link **link = NULL; |
| 65 | 65 | int err, tgt_fd, i; |
| 66 | 66 | struct btf *btf; |
| @@ -69,9 +69,6 @@ static void test_fexit_bpf2bpf_common(const char *obj_file, · 2 unmodified lines | ||
| 69 | 69 | &tgt_obj, &tgt_fd); |
| 70 | 70 | if (!ASSERT_OK(err, "tgt_prog_load")) |
| 71 | 71 | return; |
| 72 | − DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts, | |
| 73 | − .attach_prog_fd = tgt_fd, | |
| 74 | − ); | |
| 75 | 72 | |
| 76 | 73 | info_len = sizeof(prog_info); |
| 77 | 74 | 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 | ||
| 89 | 86 | if (!ASSERT_OK_PTR(prog, "prog_ptr")) |
| 90 | 87 | goto close_prog; |
| 91 | 88 | |
| 92 | − obj = bpf_object__open_file(obj_file, &opts); | |
| 89 | + obj = bpf_object__open_file(obj_file, NULL); | |
| 93 | 90 | if (!ASSERT_OK_PTR(obj, "obj_open")) |
| 94 | 91 | goto close_prog; |
| 95 | 92 | |
| 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 | + | |
| 96 | 98 | err = bpf_object__load(obj); |
| 97 | 99 | if (!ASSERT_OK(err, "obj_load")) |
| 98 | 100 | goto close_prog; |
| @@ -270,7 +272,7 @@ static void test_fmod_ret_freplace(void) · 171 unmodified lines | ||
| 270 | 272 | struct bpf_link *freplace_link = NULL; |
| 271 | 273 | struct bpf_program *prog; |
| 272 | 274 | __u32 duration = 0; |
| 273 | − int err, pkt_fd; | |
| 275 | + int err, pkt_fd, attach_prog_fd; | |
| 274 | 276 | |
| 275 | 277 | err = bpf_prog_load(tgt_name, BPF_PROG_TYPE_UNSPEC, |
| 276 | 278 | &pkt_obj, &pkt_fd); |
| @@ -278,26 +280,32 @@ static void test_fmod_ret_freplace(void) · 1 unmodified line | ||
| 278 | 280 | if (CHECK(err, "tgt_prog_load", "file %s err %d errno %d\n", |
| 279 | 281 | tgt_name, err, errno)) |
| 280 | 282 | return; |
| 281 | − opts.attach_prog_fd = pkt_fd; | |
| 282 | 283 | |
| 283 | − freplace_obj = bpf_object__open_file(freplace_name, &opts); | |
| 284 | + freplace_obj = bpf_object__open_file(freplace_name, NULL); | |
| 284 | 285 | if (!ASSERT_OK_PTR(freplace_obj, "freplace_obj_open")) |
| 285 | 286 | goto out; |
| 286 | 287 | |
| 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 | + | |
| 287 | 292 | err = bpf_object__load(freplace_obj); |
| 288 | 293 | if (CHECK(err, "freplace_obj_load", "err %d\n", err)) |
| 289 | 294 | goto out; |
| 290 | 295 | |
| 291 | − prog = bpf_program__next(NULL, freplace_obj); | |
| 292 | 296 | freplace_link = bpf_program__attach_trace(prog); |
| 293 | 297 | if (!ASSERT_OK_PTR(freplace_link, "freplace_attach_trace")) |
| 294 | 298 | goto out; |
| 295 | 299 | |
| 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); | |
| 298 | 301 | if (!ASSERT_OK_PTR(fmod_obj, "fmod_obj_open")) |
| 299 | 302 | goto out; |
| 300 | 303 | |
| 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 | + | |
| 301 | 309 | err = bpf_object__load(fmod_obj); |
| 302 | 310 | if (CHECK(!err, "fmod_obj_load", "loading fmod_ret should fail\n")) |
| 303 | 311 | goto out; |
| @@ -322,14 +330,14 @@ static void test_func_sockmap_update(void) · 18 unmodified lines | ||
| 322 | 330 | } |
| 323 | 331 | |
| 324 | 332 | static void test_obj_load_failure_common(const char *obj_file, |
| 325 | − const char *target_obj_file) | |
| 326 | − | |
| 333 | + const char *target_obj_file) | |
| 327 | 334 | { |
| 328 | 335 | /* |
| 329 | 336 | * standalone test that asserts failure to load freplace prog |
| 330 | 337 | * because of invalid return code. |
| 331 | 338 | */ |
| 332 | 339 | struct bpf_object *obj = NULL, *pkt_obj; |
| 340 | + struct bpf_program *prog; | |
| 333 | 341 | int err, pkt_fd; |
| 334 | 342 | __u32 duration = 0; |
| 335 | 343 | |
| @@ -339,14 +347,15 @@ static void test_obj_load_failure_common(const char *obj_file, · 3 unmodified lines | ||
| 339 | 347 | if (CHECK(err, "tgt_prog_load", "file %s err %d errno %d\n", |
| 340 | 348 | target_obj_file, err, errno)) |
| 341 | 349 | return; |
| 342 | − DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts, | |
| 343 | − .attach_prog_fd = pkt_fd, | |
| 344 | − ); | |
| 345 | 350 | |
| 346 | − obj = bpf_object__open_file(obj_file, &opts); | |
| 351 | + obj = bpf_object__open_file(obj_file, NULL); | |
| 347 | 352 | if (!ASSERT_OK_PTR(obj, "obj_open")) |
| 348 | 353 | goto close_prog; |
| 349 | 354 | |
| 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 | + | |
| 350 | 359 | /* It should fail to load the program */ |
| 351 | 360 | err = bpf_object__load(obj); |
| 352 | 361 | if (CHECK(!err, "bpf_obj_load should fail", "err %d\n", err)) |
| @@ -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 | +} | |
| @@ -6,45 +6,6 @@ · 5 unmodified lines | ||
| 6 | 6 | |
| 7 | 7 | static int duration; |
| 8 | 8 | |
| 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 | − | |
| 48 | 9 | static int delete_module(const char *name, int flags) |
| 49 | 10 | { |
| 50 | 11 | return syscall(__NR_delete_module, name, flags); |
| @@ -11,12 +11,14 @@ void test_skb_ctx(void) · 10 unmodified lines | ||
| 11 | 11 | .cb[3] = 4, |
| 12 | 12 | .cb[4] = 5, |
| 13 | 13 | .priority = 6, |
| 14 | + .ingress_ifindex = 11, | |
| 14 | 15 | .ifindex = 1, |
| 15 | 16 | .tstamp = 7, |
| 16 | 17 | .wire_len = 100, |
| 17 | 18 | .gso_segs = 8, |
| 18 | 19 | .mark = 9, |
| 19 | 20 | .gso_size = 10, |
| 21 | + .hwtstamp = 11, | |
| 20 | 22 | }; |
| 21 | 23 | struct bpf_prog_test_run_attr tattr = { |
| 22 | 24 | .data_in = &pkt_v4, |
| @@ -97,6 +99,10 @@ void test_skb_ctx(void) · 74 unmodified lines | ||
| 97 | 99 | "ctx_out_ifindex", |
| 98 | 100 | "skb->ifindex == %d, expected %d\n", |
| 99 | 101 | 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); | |
| 100 | 106 | CHECK_ATTR(skb.tstamp != 8, |
| 101 | 107 | "ctx_out_tstamp", |
| 102 | 108 | "skb->tstamp == %lld, expected %d\n", |
| @@ -18,6 +18,8 @@ void test_skeleton(void) · 17 unmodified lines | ||
| 18 | 18 | struct test_skeleton__data *data; |
| 19 | 19 | struct test_skeleton__rodata *rodata; |
| 20 | 20 | struct test_skeleton__kconfig *kcfg; |
| 21 | + const void *elf_bytes; | |
| 22 | + size_t elf_bytes_sz = 0; | |
| 21 | 23 | |
| 22 | 24 | skel = test_skeleton__open(); |
| 23 | 25 | if (CHECK(!skel, "skel_open", "failed to open skeleton\n")) |
| @@ -91,6 +93,10 @@ void test_skeleton(void) · 67 unmodified lines | ||
| 91 | 93 | CHECK(bss->kern_ver != kcfg->LINUX_KERNEL_VERSION, "ext2", |
| 92 | 94 | "got %d != exp %d\n", bss->kern_ver, kcfg->LINUX_KERNEL_VERSION); |
| 93 | 95 | |
| 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 | + | |
| 94 | 100 | cleanup: |
| 95 | 101 | test_skeleton__destroy(skel); |
| 96 | 102 | } |
| @@ -219,10 +219,7 @@ out: · 218 unmodified lines | ||
| 219 | 219 | bpf_object__close(obj); |
| 220 | 220 | } |
| 221 | 221 | |
| 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) | |
| 226 | 223 | { |
| 227 | 224 | int err, map_fd, prog_fd, main_fd, data_fd, i, val; |
| 228 | 225 | struct bpf_map *prog_array, *data_map; |
| @@ -231,7 +228,7 @@ static void test_tailcall_3(void) · 2 unmodified lines | ||
| 231 | 228 | __u32 retval, duration; |
| 232 | 229 | char buff[128] = {}; |
| 233 | 230 | |
| 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, | |
| 235 | 232 | &prog_fd); |
| 236 | 233 | if (CHECK_FAIL(err)) |
| 237 | 234 | return; |
| @@ -296,6 +293,22 @@ out: · 58 unmodified lines | ||
| 296 | 293 | bpf_object__close(obj); |
| 297 | 294 | } |
| 298 | 295 | |
| 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 | + | |
| 299 | 312 | /* test_tailcall_4 checks that the kernel properly selects indirect jump |
| 300 | 313 | * for the case where the key is not known. Latter is passed via global |
| 301 | 314 | * data to select different targets we can compare return value of. |
| @@ -822,6 +835,8 @@ void test_tailcalls(void) · 520 unmodified lines | ||
| 822 | 835 | test_tailcall_4(); |
| 823 | 836 | if (test__start_subtest("tailcall_5")) |
| 824 | 837 | test_tailcall_5(); |
| 838 | + if (test__start_subtest("tailcall_6")) | |
| 839 | + test_tailcall_6(); | |
| 825 | 840 | if (test__start_subtest("tailcall_bpf2bpf_1")) |
| 826 | 841 | test_tailcall_bpf2bpf_1(); |
| 827 | 842 | if (test__start_subtest("tailcall_bpf2bpf_2")) |
| @@ -633,7 +633,7 @@ static void test_tc_redirect_peer_l3(struct netns_setup_result *setup_result) · 632 unmodified lines | ||
| 633 | 633 | struct nstoken *nstoken = NULL; |
| 634 | 634 | int err; |
| 635 | 635 | int tunnel_pid = -1; |
| 636 | − int src_fd, target_fd; | |
| 636 | + int src_fd, target_fd = -1; | |
| 637 | 637 | int ifindex; |
| 638 | 638 | |
| 639 | 639 | /* Start a L3 TUN/TAP tunnel between the src and dst namespaces. |
| @@ -169,11 +169,7 @@ static __always_inline void bictcp_hystart_reset(struct sock *sk) · 168 unmodified lines | ||
| 169 | 169 | ca->sample_cnt = 0; |
| 170 | 170 | } |
| 171 | 171 | |
| 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 */ | |
| 177 | 173 | SEC("struct_ops/bpf_cubic_init") |
| 178 | 174 | void BPF_PROG(bpf_cubic_init, struct sock *sk) |
| 179 | 175 | { |
| @@ -188,10 +184,8 @@ void BPF_PROG(bpf_cubic_init, struct sock *sk) · 8 unmodified lines | ||
| 188 | 184 | tcp_sk(sk)->snd_ssthresh = initial_ssthresh; |
| 189 | 185 | } |
| 190 | 186 | |
| 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") | |
| 195 | 189 | void BPF_PROG(bpf_cubic_cwnd_event, struct sock *sk, enum tcp_ca_event event) |
| 196 | 190 | { |
| 197 | 191 | if (event == CA_EVENT_TX_START) { |
| @@ -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 | +} | |
| @@ -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 | +} | |
| @@ -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"; | |
| @@ -25,6 +25,12 @@ int process(struct __sk_buff *skb) · 24 unmodified lines | ||
| 25 | 25 | return 1; |
| 26 | 26 | if (skb->gso_size != 10) |
| 27 | 27 | 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; | |
| 28 | 34 | |
| 29 | 35 | return 0; |
| 30 | 36 | } |
| @@ -69,4 +69,7 @@ · 68 unmodified lines | ||
| 69 | 69 | #define BTF_TYPE_FLOAT_ENC(name, sz) \ |
| 70 | 70 | BTF_TYPE_ENC(name, BTF_INFO_ENC(BTF_KIND_FLOAT, 0, 0), sz) |
| 71 | 71 | |
| 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 | + | |
| 72 | 75 | #endif /* _TEST_BTF_H */ |
| @@ -743,6 +743,45 @@ int cd_flavor_subdir(const char *exec_name) · 742 unmodified lines | ||
| 743 | 743 | return chdir(flavor); |
| 744 | 744 | } |
| 745 | 745 | |
| 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 | + | |
| 746 | 785 | #define MAX_BACKTRACE_SZ 128 |
| 747 | 786 | void crash_handler(int signum) |
| 748 | 787 | { |
| @@ -291,6 +291,8 @@ int compare_map_keys(int map1_fd, int map2_fd); · 290 unmodified lines | ||
| 291 | 291 | int compare_stack_ips(int smap_fd, int amap_fd, int stack_trace_len); |
| 292 | 292 | int extract_build_id(char *build_id, size_t size); |
| 293 | 293 | int kern_sync_rcu(void); |
| 294 | +int trigger_module_test_read(int read_sz); | |
| 295 | +int trigger_module_test_write(int write_sz); | |
| 294 | 296 | |
| 295 | 297 | #ifdef __x86_64__ |
| 296 | 298 | #define SYS_NANOSLEEP_KPROBE_NAME "__x64_sys_nanosleep" |
| @@ -1,4 +1,5 @@ | ||
| 1 | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | +#include <ctype.h> | |
| 2 | 3 | #include <stdio.h> |
| 3 | 4 | #include <stdlib.h> |
| 4 | 5 | #include <string.h> |
| @@ -117,6 +118,42 @@ out: · 112 unmodified lines | ||
| 117 | 118 | return err; |
| 118 | 119 | } |
| 119 | 120 | |
| 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 | + | |
| 120 | 157 | void read_trace_pipe(void) |
| 121 | 158 | { |
| 122 | 159 | int trace_fd; |
| @@ -16,6 +16,11 @@ long ksym_get_addr(const char *name); · 15 unmodified lines | ||
| 16 | 16 | /* open kallsyms and find addresses on the fly, faster than load + search. */ |
| 17 | 17 | int kallsyms_find(const char *sym, unsigned long long *addr); |
| 18 | 18 | |
| 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 | + | |
| 19 | 24 | void read_trace_pipe(void); |
| 20 | 25 | |
| 21 | 26 | ssize_t get_uprobe_offset(const void *addr, ssize_t base); |
| @@ -1057,6 +1057,66 @@ · 1056 unmodified lines | ||
| 1057 | 1057 | .result = ACCEPT, |
| 1058 | 1058 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
| 1059 | 1059 | }, |
| 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 | +}, | |
| 1060 | 1120 | { |
| 1061 | 1121 | "check wire_len is not readable by sockets", |
| 1062 | 1122 | .insns = { |
| @@ -62,6 +62,11 @@ · 61 unmodified lines | ||
| 62 | 62 | BPF_JMP_REG(BPF_JEQ, BPF_REG_3, BPF_REG_2, 2), |
| 63 | 63 | BPF_MOV64_IMM(BPF_REG_0, 1), |
| 64 | 64 | 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(), | |
| 65 | 70 | BPF_MOV32_REG(BPF_REG_2, BPF_REG_2), |
| 66 | 71 | BPF_LD_IMM64(BPF_REG_0, 0xfefefeULL), |
| 67 | 72 | BPF_ALU32_REG(BPF_MUL, BPF_REG_0, BPF_REG_1), |
| @@ -73,11 +78,22 @@ · 5 unmodified lines | ||
| 73 | 78 | BPF_JMP_REG(BPF_JEQ, BPF_REG_3, BPF_REG_2, 2), |
| 74 | 79 | BPF_MOV64_IMM(BPF_REG_0, 1), |
| 75 | 80 | 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(), | |
| 76 | 92 | BPF_LD_IMM64(BPF_REG_0, 0x952a7bbcULL), |
| 77 | 93 | 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), | |
| 81 | 97 | BPF_MOV64_IMM(BPF_REG_0, 1), |
| 82 | 98 | BPF_EXIT_INSN(), |
| 83 | 99 | BPF_MOV64_IMM(BPF_REG_0, 2), |
| @@ -19,7 +19,7 @@ · 18 unmodified lines | ||
| 19 | 19 | * Virtual Ethernet interfaces. |
| 20 | 20 | * |
| 21 | 21 | * 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 | |
| 23 | 23 | * b. poll - using poll() syscall |
| 24 | 24 | * c. Socket Teardown |
| 25 | 25 | * Create a Tx and a Rx socket, Tx from one socket, Rx on another. Destroy |
| @@ -45,6 +45,10 @@ · 19 unmodified lines | ||
| 45 | 45 | * Configure sockets at indexes 0 and 1, run a traffic on queue ids 0, |
| 46 | 46 | * then remove xsk sockets from queue 0 on both veth interfaces and |
| 47 | 47 | * 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 | |
| 48 | 52 | * |
| 49 | 53 | * Total tests: 12 |
| 50 | 54 | * |
| @@ -112,13 +116,10 @@ static void __exit_with_error(int error, const char *file, const char *func, int · 61 unmodified lines | ||
| 112 | 116 | |
| 113 | 117 | #define exit_with_error(error) __exit_with_error(error, __FILE__, __func__, __LINE__) |
| 114 | 118 | |
| 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)) | |
| 122 | 123 | |
| 123 | 124 | static void memset32_htonl(void *dest, u32 val, u32 size) |
| 124 | 125 | { |
| @@ -235,80 +236,46 @@ static void gen_udp_csum(struct udphdr *udp_hdr, struct iphdr *ip_hdr) · 110 unmodified lines | ||
| 235 | 236 | udp_csum(ip_hdr->saddr, ip_hdr->daddr, UDP_PKT_SIZE, IPPROTO_UDP, (u16 *)udp_hdr); |
| 236 | 237 | } |
| 237 | 238 | |
| 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) | |
| 239 | 240 | { |
| 240 | 241 | struct xsk_umem_config cfg = { |
| 241 | 242 | .fill_size = XSK_RING_PROD__DEFAULT_NUM_DESCS, |
| 242 | 243 | .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, | |
| 245 | 246 | .flags = XSK_UMEM__DEFAULT_FLAGS |
| 246 | 247 | }; |
| 247 | − struct xsk_umem_info *umem; | |
| 248 | 248 | int ret; |
| 249 | 249 | |
| 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; | |
| 253 | 252 | |
| 254 | 253 | ret = xsk_umem__create(&umem->umem, buffer, size, |
| 255 | 254 | &umem->fq, &umem->cq, &cfg); |
| 256 | 255 | if (ret) |
| 257 | − exit_with_error(-ret); | |
| 256 | + return ret; | |
| 258 | 257 | |
| 259 | 258 | 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; | |
| 275 | 260 | } |
| 276 | 261 | |
| 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) | |
| 278 | 264 | { |
| 279 | 265 | struct xsk_socket_config cfg; |
| 280 | − struct xsk_socket_info *xsk; | |
| 281 | 266 | struct xsk_ring_cons *rxr; |
| 282 | 267 | struct xsk_ring_prod *txr; |
| 283 | − int ret; | |
| 284 | 268 | |
| 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; | |
| 291 | 271 | cfg.tx_size = XSK_RING_PROD__DEFAULT_NUM_DESCS; |
| 292 | 272 | 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; | |
| 308 | 275 | |
| 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); | |
| 312 | 279 | } |
| 313 | 280 | |
| 314 | 281 | static struct option long_options[] = { |
| @@ -354,45 +321,44 @@ static int switch_namespace(const char *nsname) · 39 unmodified lines | ||
| 354 | 321 | return nsfd; |
| 355 | 322 | } |
| 356 | 323 | |
| 357 | −static int validate_interfaces(void) | |
| 324 | +static bool validate_interface(struct ifobject *ifobj) | |
| 358 | 325 | { |
| 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; | |
| 368 | 329 | } |
| 369 | 330 | |
| 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) | |
| 371 | 333 | { |
| 372 | − int option_index, interface_index = 0, c; | |
| 334 | + struct ifobject *ifobj; | |
| 335 | + u32 interface_nb = 0; | |
| 336 | + int option_index, c; | |
| 373 | 337 | |
| 374 | 338 | opterr = 0; |
| 375 | 339 | |
| 376 | 340 | for (;;) { |
| 377 | − c = getopt_long(argc, argv, "i:Dv", long_options, &option_index); | |
| 341 | + char *sptr, *token; | |
| 378 | 342 | |
| 343 | + c = getopt_long(argc, argv, "i:Dv", long_options, &option_index); | |
| 379 | 344 | if (c == -1) |
| 380 | 345 | break; |
| 381 | 346 | |
| 382 | 347 | switch (c) { |
| 383 | 348 | 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 | |
| 385 | 354 | break; |
| 386 | − char *sptr, *token; | |
| 387 | 355 | |
| 388 | 356 | 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); | |
| 391 | 358 | token = strsep(&sptr, ","); |
| 392 | 359 | 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++; | |
| 396 | 362 | break; |
| 397 | 363 | case 'D': |
| 398 | 364 | opt_pkt_dump = true; |
| @@ -405,11 +371,78 @@ static void parse_command_line(int argc, char **argv) · 6 unmodified lines | ||
| 405 | 371 | ksft_exit_xfail(); |
| 406 | 372 | } |
| 407 | 373 | } |
| 374 | +} | |
| 408 | 375 | |
| 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 | + } | |
| 412 | 404 | } |
| 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); | |
| 413 | 446 | } |
| 414 | 447 | |
| 415 | 448 | 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 | ||
| 420 | 453 | return &pkt_stream->pkts[pkt_nb]; |
| 421 | 454 | } |
| 422 | 455 | |
| 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) | |
| 424 | 482 | { |
| 425 | 483 | struct pkt_stream *pkt_stream; |
| 426 | − u32 i; | |
| 427 | 484 | |
| 428 | − pkt_stream = malloc(sizeof(*pkt_stream)); | |
| 485 | + pkt_stream = calloc(1, sizeof(*pkt_stream)); | |
| 429 | 486 | if (!pkt_stream) |
| 430 | − exit_with_error(ENOMEM); | |
| 487 | + return NULL; | |
| 431 | 488 | |
| 432 | 489 | 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) | |
| 434 | 506 | exit_with_error(ENOMEM); |
| 435 | 507 | |
| 436 | 508 | pkt_stream->nb_pkts = nb_pkts; |
| 437 | 509 | 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; | |
| 439 | 512 | pkt_stream->pkts[i].len = pkt_len; |
| 440 | 513 | 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; | |
| 441 | 519 | } |
| 442 | 520 | |
| 443 | 521 | return pkt_stream; |
| 444 | 522 | } |
| 445 | 523 | |
| 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 | + | |
| 446 | 555 | static struct pkt *pkt_generate(struct ifobject *ifobject, u32 pkt_nb) |
| 447 | 556 | { |
| 448 | 557 | 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 | ||
| 453 | 562 | |
| 454 | 563 | if (!pkt) |
| 455 | 564 | return NULL; |
| 565 | + if (!pkt->valid || pkt->len < PKT_SIZE) | |
| 566 | + return pkt; | |
| 456 | 567 | |
| 457 | 568 | data = xsk_umem__get_data(ifobject->umem->buffer, pkt->addr); |
| 458 | 569 | 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 | ||
| 467 | 578 | return pkt; |
| 468 | 579 | } |
| 469 | 580 | |
| 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 | + | |
| 470 | 601 | static void pkt_dump(void *pkt, u32 len) |
| 471 | 602 | { |
| 472 | 603 | char s[INET_ADDRSTRLEN]; |
| @@ -504,9 +635,9 @@ static void pkt_dump(void *pkt, u32 len) · 31 unmodified lines | ||
| 504 | 635 | fprintf(stdout, "---------------------------------------\n"); |
| 505 | 636 | } |
| 506 | 637 | |
| 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) | |
| 508 | 639 | { |
| 509 | − void *data = xsk_umem__get_data(buffer, desc->addr); | |
| 640 | + void *data = xsk_umem__get_data(buffer, addr); | |
| 510 | 641 | struct iphdr *iphdr = (struct iphdr *)(data + sizeof(struct ethhdr)); |
| 511 | 642 | |
| 512 | 643 | if (!pkt) { |
| @@ -514,19 +645,24 @@ static bool is_pkt_valid(struct pkt *pkt, void *buffer, const struct xdp_desc *d · 1 unmodified line | ||
| 514 | 645 | return false; |
| 515 | 646 | } |
| 516 | 647 | |
| 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 | + | |
| 517 | 660 | if (iphdr->version == IP_PKT_VER && iphdr->tos == IP_PKT_TOS) { |
| 518 | 661 | u32 seqnum = ntohl(*((u32 *)(data + PKT_HDR_SIZE))); |
| 519 | 662 | |
| 520 | − if (opt_pkt_dump && test_type != TEST_TYPE_STATS) | |
| 663 | + if (opt_pkt_dump) | |
| 521 | 664 | pkt_dump(data, PKT_SIZE); |
| 522 | 665 | |
| 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 | − | |
| 530 | 666 | if (pkt->payload != seqnum) { |
| 531 | 667 | ksft_test_result_fail |
| 532 | 668 | ("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 | ||
| 558 | 694 | unsigned int rcvd; |
| 559 | 695 | u32 idx; |
| 560 | 696 | |
| 561 | − if (!xsk->outstanding_tx) | |
| 562 | − return; | |
| 563 | − | |
| 564 | 697 | if (xsk_ring_prod__needs_wakeup(&xsk->tx)) |
| 565 | 698 | kick_tx(xsk); |
| 566 | 699 | |
| 567 | 700 | rcvd = xsk_ring_cons__peek(&xsk->umem->cq, batch_size, &idx); |
| 568 | 701 | 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 | + | |
| 569 | 711 | xsk_ring_cons__release(&xsk->umem->cq, rcvd); |
| 570 | 712 | xsk->outstanding_tx -= rcvd; |
| 571 | 713 | } |
| @@ -574,11 +716,10 @@ static void complete_pkts(struct xsk_socket_info *xsk, int batch_size) · 2 unmodified lines | ||
| 574 | 716 | static void receive_pkts(struct pkt_stream *pkt_stream, struct xsk_socket_info *xsk, |
| 575 | 717 | struct pollfd *fds) |
| 576 | 718 | { |
| 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; | |
| 579 | 721 | int ret; |
| 580 | 722 | |
| 581 | − pkt = pkt_stream_get_pkt(pkt_stream, pkt_count++); | |
| 582 | 723 | while (pkt) { |
| 583 | 724 | rcvd = xsk_ring_cons__peek(&xsk->rx, BATCH_SIZE, &idx_rx); |
| 584 | 725 | if (!rcvd) { |
| @@ -606,13 +747,21 @@ static void receive_pkts(struct pkt_stream *pkt_stream, struct xsk_socket_info * · 21 unmodified lines | ||
| 606 | 747 | const struct xdp_desc *desc = xsk_ring_cons__rx_desc(&xsk->rx, idx_rx++); |
| 607 | 748 | u64 addr = desc->addr, orig; |
| 608 | 749 | |
| 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 | + | |
| 609 | 758 | orig = xsk_umem__extract_addr(addr); |
| 610 | 759 | 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)) | |
| 612 | 761 | return; |
| 613 | 762 | |
| 614 | 763 | *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); | |
| 616 | 765 | } |
| 617 | 766 | |
| 618 | 767 | 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 | ||
| 623 | 772 | static u32 __send_pkts(struct ifobject *ifobject, u32 pkt_nb) |
| 624 | 773 | { |
| 625 | 774 | struct xsk_socket_info *xsk = ifobject->xsk; |
| 626 | − u32 i, idx; | |
| 775 | + u32 i, idx, valid_pkts = 0; | |
| 627 | 776 | |
| 628 | 777 | while (xsk_ring_prod__reserve(&xsk->tx, BATCH_SIZE, &idx) < BATCH_SIZE) |
| 629 | 778 | complete_pkts(xsk, BATCH_SIZE); |
| @@ -638,14 +787,13 @@ static u32 __send_pkts(struct ifobject *ifobject, u32 pkt_nb) · 8 unmodified lines | ||
| 638 | 787 | tx_desc->addr = pkt->addr; |
| 639 | 788 | tx_desc->len = pkt->len; |
| 640 | 789 | pkt_nb++; |
| 790 | + if (pkt->valid) | |
| 791 | + valid_pkts++; | |
| 641 | 792 | } |
| 642 | 793 | |
| 643 | 794 | 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); | |
| 649 | 797 | |
| 650 | 798 | return i; |
| 651 | 799 | } |
| @@ -658,23 +806,23 @@ static void wait_for_tx_completion(struct xsk_socket_info *xsk) · 6 unmodified lines | ||
| 658 | 806 | |
| 659 | 807 | static void send_pkts(struct ifobject *ifobject) |
| 660 | 808 | { |
| 661 | − struct pollfd fds[MAX_SOCKS] = { }; | |
| 809 | + struct pollfd fds = { }; | |
| 662 | 810 | u32 pkt_cnt = 0; |
| 663 | 811 | |
| 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; | |
| 666 | 814 | |
| 667 | 815 | while (pkt_cnt < ifobject->pkt_stream->nb_pkts) { |
| 668 | 816 | u32 sent; |
| 669 | 817 | |
| 670 | − if (test_type == TEST_TYPE_POLL) { | |
| 818 | + if (ifobject->use_poll) { | |
| 671 | 819 | int ret; |
| 672 | 820 | |
| 673 | − ret = poll(fds, 1, POLL_TMOUT); | |
| 821 | + ret = poll(&fds, 1, POLL_TMOUT); | |
| 674 | 822 | if (ret <= 0) |
| 675 | 823 | continue; |
| 676 | 824 | |
| 677 | − if (!(fds[0].revents & POLLOUT)) | |
| 825 | + if (!(fds.revents & POLLOUT)) | |
| 678 | 826 | continue; |
| 679 | 827 | } |
| 680 | 828 | |
| @@ -698,7 +846,7 @@ static bool rx_stats_are_valid(struct ifobject *ifobject) · 17 unmodified lines | ||
| 698 | 846 | optlen = sizeof(stats); |
| 699 | 847 | err = getsockopt(fd, SOL_XDP, XDP_STATISTICS, &stats, &optlen); |
| 700 | 848 | 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", | |
| 702 | 850 | __func__, -err, strerror(-err)); |
| 703 | 851 | return true; |
| 704 | 852 | } |
| @@ -739,7 +887,7 @@ static void tx_stats_validate(struct ifobject *ifobject) · 34 unmodified lines | ||
| 739 | 887 | optlen = sizeof(stats); |
| 740 | 888 | err = getsockopt(fd, SOL_XDP, XDP_STATISTICS, &stats, &optlen); |
| 741 | 889 | 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", | |
| 743 | 891 | __func__, -err, strerror(-err)); |
| 744 | 892 | return; |
| 745 | 893 | } |
| @@ -751,71 +899,63 @@ static void tx_stats_validate(struct ifobject *ifobject) · 5 unmodified lines | ||
| 751 | 899 | __func__, stats.tx_invalid_descs, ifobject->pkt_stream->nb_pkts); |
| 752 | 900 | } |
| 753 | 901 | |
| 754 | −static void thread_common_ops(struct ifobject *ifobject, void *bufs) | |
| 902 | +static void thread_common_ops(struct test_spec *test, struct ifobject *ifobject) | |
| 755 | 903 | { |
| 756 | − u64 umem_sz = num_frames * XSK_UMEM__DEFAULT_FRAME_SIZE; | |
| 757 | 904 | 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; | |
| 761 | 906 | |
| 762 | 907 | ifobject->ns_fd = switch_namespace(ifobject->nsname); |
| 763 | 908 | |
| 764 | − if (test_type == TEST_TYPE_BPF_RES) | |
| 765 | − mmap_sz *= 2; | |
| 909 | + if (ifobject->umem->unaligned_mode) | |
| 910 | + mmap_flags |= MAP_HUGETLB; | |
| 766 | 911 | |
| 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; | |
| 770 | 916 | |
| 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); | |
| 777 | 920 | |
| 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; | |
| 783 | 923 | |
| 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); | |
| 786 | 927 | |
| 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; | |
| 792 | 932 | |
| 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 | + } | |
| 798 | 939 | |
| 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]; | |
| 802 | 942 | } |
| 803 | 943 | |
| 804 | 944 | static void testapp_cleanup_xsk_res(struct ifobject *ifobj) |
| 805 | 945 | { |
| 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); | |
| 810 | 950 | } |
| 811 | 951 | |
| 812 | 952 | static void *worker_testapp_validate_tx(void *arg) |
| 813 | 953 | { |
| 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; | |
| 816 | 956 | |
| 817 | − if (!second_step) | |
| 818 | − thread_common_ops(ifobject, bufs); | |
| 957 | + if (test->current_step == 1) | |
| 958 | + thread_common_ops(test, ifobject); | |
| 819 | 959 | |
| 820 | 960 | print_verbose("Sending %d packets on interface %s\n", ifobject->pkt_stream->nb_pkts, |
| 821 | 961 | ifobject->ifname); |
| @@ -824,24 +964,50 @@ static void *worker_testapp_validate_tx(void *arg) · 2 unmodified lines | ||
| 824 | 964 | if (stat_test_type == STAT_TEST_TX_INVALID) |
| 825 | 965 | tx_stats_validate(ifobject); |
| 826 | 966 | |
| 827 | − testapp_cleanup_xsk_res(ifobject); | |
| 967 | + if (test->total_steps == test->current_step) | |
| 968 | + testapp_cleanup_xsk_res(ifobject); | |
| 828 | 969 | pthread_exit(NULL); |
| 829 | 970 | } |
| 830 | 971 | |
| 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 | + | |
| 831 | 998 | static void *worker_testapp_validate_rx(void *arg) |
| 832 | 999 | { |
| 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 = { }; | |
| 836 | 1003 | |
| 837 | − if (!second_step) | |
| 838 | − thread_common_ops(ifobject, bufs); | |
| 1004 | + if (test->current_step == 1) | |
| 1005 | + thread_common_ops(test, ifobject); | |
| 839 | 1006 | |
| 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); | |
| 842 | 1008 | |
| 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; | |
| 845 | 1011 | |
| 846 | 1012 | pthread_barrier_wait(&barr); |
| 847 | 1013 | |
| @@ -849,151 +1015,219 @@ static void *worker_testapp_validate_rx(void *arg) · 1 unmodified line | ||
| 849 | 1015 | while (!rx_stats_are_valid(ifobject)) |
| 850 | 1016 | continue; |
| 851 | 1017 | 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); | |
| 856 | 1019 | |
| 857 | − testapp_cleanup_xsk_res(ifobject); | |
| 1020 | + if (test->total_steps == test->current_step) | |
| 1021 | + testapp_cleanup_xsk_res(ifobject); | |
| 858 | 1022 | pthread_exit(NULL); |
| 859 | 1023 | } |
| 860 | 1024 | |
| 861 | −static void testapp_validate(void) | |
| 1025 | +static void testapp_validate_traffic(struct test_spec *test) | |
| 862 | 1026 | { |
| 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; | |
| 866 | 1030 | |
| 867 | 1031 | if (pthread_barrier_init(&barr, NULL, 2)) |
| 868 | 1032 | exit_with_error(errno); |
| 869 | 1033 | |
| 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++; | |
| 876 | 1035 | |
| 877 | 1036 | /*Spawn RX thread */ |
| 878 | − pthread_create(&t0, NULL, ifdict_rx->func_ptr, ifdict_rx); | |
| 1037 | + pthread_create(&t0, NULL, ifobj_rx->func_ptr, test); | |
| 879 | 1038 | |
| 880 | 1039 | pthread_barrier_wait(&barr); |
| 881 | 1040 | if (pthread_barrier_destroy(&barr)) |
| 882 | 1041 | exit_with_error(errno); |
| 883 | 1042 | |
| 884 | 1043 | /*Spawn TX thread */ |
| 885 | − pthread_create(&t1, NULL, ifdict_tx->func_ptr, ifdict_tx); | |
| 1044 | + pthread_create(&t1, NULL, ifobj_tx->func_ptr, test); | |
| 886 | 1045 | |
| 887 | 1046 | pthread_join(t1, NULL); |
| 888 | 1047 | pthread_join(t0, NULL); |
| 889 | − | |
| 890 | − if (!(test_type == TEST_TYPE_TEARDOWN) && !bidi && !bpf && !(test_type == TEST_TYPE_STATS)) | |
| 891 | − print_ksft_result(); | |
| 892 | 1048 | } |
| 893 | 1049 | |
| 894 | −static void testapp_teardown(void) | |
| 1050 | +static void testapp_teardown(struct test_spec *test) | |
| 895 | 1051 | { |
| 896 | 1052 | int i; |
| 897 | 1053 | |
| 1054 | + test_spec_set_name(test, "TEARDOWN"); | |
| 898 | 1055 | 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); | |
| 901 | 1058 | } |
| 902 | − | |
| 903 | − print_ksft_result(); | |
| 904 | 1059 | } |
| 905 | 1060 | |
| 906 | −static void swap_vectors(struct ifobject *ifobj1, struct ifobject *ifobj2) | |
| 1061 | +static void swap_directions(struct ifobject **ifobj1, struct ifobject **ifobj2) | |
| 907 | 1062 | { |
| 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); | |
| 910 | 1065 | |
| 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; | |
| 913 | 1068 | |
| 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; | |
| 919 | 1071 | } |
| 920 | 1072 | |
| 921 | −static void testapp_bidi(void) | |
| 1073 | +static void testapp_bidi(struct test_spec *test) | |
| 922 | 1074 | { |
| 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); | |
| 932 | 1080 | |
| 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); | |
| 934 | 1084 | |
| 935 | − print_ksft_result(); | |
| 1085 | + swap_directions(&test->ifobj_rx, &test->ifobj_tx); | |
| 936 | 1086 | } |
| 937 | 1087 | |
| 938 | −static void swap_xsk_res(void) | |
| 1088 | +static void swap_xsk_resources(struct ifobject *ifobj_tx, struct ifobject *ifobj_rx) | |
| 939 | 1089 | { |
| 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]; | |
| 948 | 1098 | } |
| 949 | 1099 | |
| 950 | −static void testapp_bpf_res(void) | |
| 1100 | +static void testapp_bpf_res(struct test_spec *test) | |
| 951 | 1101 | { |
| 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); | |
| 953 | 1106 | |
| 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); | |
| 963 | 1109 | } |
| 964 | 1110 | |
| 965 | −static void testapp_stats(void) | |
| 1111 | +static void testapp_stats(struct test_spec *test) | |
| 966 | 1112 | { |
| 967 | − for (int i = 0; i < STAT_TEST_TYPE_MAX; i++) { | |
| 968 | − stat_test_type = i; | |
| 1113 | + int i; | |
| 969 | 1114 | |
| 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; | |
| 973 | 1118 | |
| 974 | 1119 | switch (stat_test_type) { |
| 975 | 1120 | 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); | |
| 978 | 1125 | break; |
| 979 | 1126 | 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); | |
| 981 | 1130 | break; |
| 982 | 1131 | 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; | |
| 984 | 1149 | default: |
| 985 | 1150 | break; |
| 986 | 1151 | } |
| 987 | − testapp_validate(); | |
| 988 | 1152 | } |
| 989 | 1153 | |
| 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); | |
| 991 | 1226 | } |
| 992 | 1227 | |
| 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) | |
| 997 | 1231 | { |
| 998 | 1232 | struct in_addr ip; |
| 999 | 1233 | |
| @@ -1009,58 +1243,73 @@ static void init_iface(struct ifobject *ifobj, const char *dst_mac, · 9 unmodified lines | ||
| 1009 | 1243 | ifobj->dst_port = dst_port; |
| 1010 | 1244 | ifobj->src_port = src_port; |
| 1011 | 1245 | |
| 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; | |
| 1021 | 1247 | } |
| 1022 | 1248 | |
| 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) | |
| 1024 | 1250 | { |
| 1025 | 1251 | test_type = type; |
| 1026 | 1252 | |
| 1027 | 1253 | /* reset defaults after potential previous test */ |
| 1028 | − xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST; | |
| 1029 | − second_step = 0; | |
| 1030 | 1254 | 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 | − } | |
| 1046 | 1255 | |
| 1047 | 1256 | switch (test_type) { |
| 1048 | 1257 | case TEST_TYPE_STATS: |
| 1049 | − testapp_stats(); | |
| 1258 | + testapp_stats(test); | |
| 1050 | 1259 | break; |
| 1051 | 1260 | case TEST_TYPE_TEARDOWN: |
| 1052 | − testapp_teardown(); | |
| 1261 | + testapp_teardown(test); | |
| 1053 | 1262 | break; |
| 1054 | 1263 | case TEST_TYPE_BIDI: |
| 1055 | − testapp_bidi(); | |
| 1264 | + testapp_bidi(test); | |
| 1056 | 1265 | break; |
| 1057 | 1266 | 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; | |
| 1059 | 1307 | break; |
| 1060 | 1308 | default: |
| 1061 | − testapp_validate(); | |
| 1062 | 1309 | break; |
| 1063 | 1310 | } |
| 1311 | + | |
| 1312 | + print_ksft_result(test); | |
| 1064 | 1313 | } |
| 1065 | 1314 | |
| 1066 | 1315 | static struct ifobject *ifobject_create(void) |
| @@ -1071,11 +1320,11 @@ static struct ifobject *ifobject_create(void) · 4 unmodified lines | ||
| 1071 | 1320 | if (!ifobj) |
| 1072 | 1321 | return NULL; |
| 1073 | 1322 | |
| 1074 | − ifobj->xsk_arr = calloc(2, sizeof(struct xsk_socket_info *)); | |
| 1323 | + ifobj->xsk_arr = calloc(MAX_SOCKETS, sizeof(*ifobj->xsk_arr)); | |
| 1075 | 1324 | if (!ifobj->xsk_arr) |
| 1076 | 1325 | goto out_xsk_arr; |
| 1077 | 1326 | |
| 1078 | − ifobj->umem_arr = calloc(2, sizeof(struct xsk_umem_info *)); | |
| 1327 | + ifobj->umem_arr = calloc(MAX_SOCKETS, sizeof(*ifobj->umem_arr)); | |
| 1079 | 1328 | if (!ifobj->umem_arr) |
| 1080 | 1329 | goto out_umem_arr; |
| 1081 | 1330 | |
| @@ -1098,34 +1347,53 @@ static void ifobject_delete(struct ifobject *ifobj) · 16 unmodified lines | ||
| 1098 | 1347 | int main(int argc, char **argv) |
| 1099 | 1348 | { |
| 1100 | 1349 | 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; | |
| 1102 | 1354 | |
| 1103 | 1355 | if (setrlimit(RLIMIT_MEMLOCK, &_rlim)) |
| 1104 | 1356 | exit_with_error(errno); |
| 1105 | 1357 | |
| 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); | |
| 1111 | 1364 | |
| 1112 | 1365 | setlocale(LC_ALL, ""); |
| 1113 | 1366 | |
| 1114 | − parse_command_line(argc, argv); | |
| 1367 | + parse_command_line(ifobj_tx, ifobj_rx, argc, argv); | |
| 1115 | 1368 | |
| 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; | |
| 1118 | 1384 | |
| 1119 | 1385 | ksft_set_plan(TEST_MODE_MAX * TEST_TYPE_MAX); |
| 1120 | 1386 | |
| 1121 | 1387 | for (i = 0; i < TEST_MODE_MAX; i++) |
| 1122 | 1388 | 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); | |
| 1124 | 1391 | usleep(USLEEP_MAX); |
| 1125 | 1392 | } |
| 1126 | 1393 | |
| 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); | |
| 1129 | 1397 | |
| 1130 | 1398 | ksft_exit_pass(); |
| 1131 | 1399 | return 0; |
| @@ -20,10 +20,9 @@ · 19 unmodified lines | ||
| 20 | 20 | #define MAX_INTERFACES 2 |
| 21 | 21 | #define MAX_INTERFACE_NAME_CHARS 7 |
| 22 | 22 | #define MAX_INTERFACES_NAMESPACE_CHARS 10 |
| 23 | −#define MAX_SOCKS 1 | |
| 23 | +#define MAX_SOCKETS 2 | |
| 24 | +#define MAX_TEST_NAME_SIZE 32 | |
| 24 | 25 | #define MAX_TEARDOWN_ITER 10 |
| 25 | −#define MAX_BIDI_ITER 2 | |
| 26 | −#define MAX_BPF_ITER 2 | |
| 27 | 26 | #define PKT_HDR_SIZE (sizeof(struct ethhdr) + sizeof(struct iphdr) + \ |
| 28 | 27 | sizeof(struct udphdr)) |
| 29 | 28 | #define MIN_PKT_SIZE 64 |
| @@ -39,7 +38,10 @@ · 9 unmodified lines | ||
| 39 | 38 | #define BATCH_SIZE 8 |
| 40 | 39 | #define POLL_TMOUT 1000 |
| 41 | 40 | #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) | |
| 42 | 43 | #define RX_FULL_RXQSIZE 32 |
| 44 | +#define DEFAULT_OFFSET 256 | |
| 43 | 45 | #define XSK_UMEM__INVALID_FRAME_SIZE (XSK_UMEM__DEFAULT_FRAME_SIZE + 1) |
| 44 | 46 | |
| 45 | 47 | #define print_verbose(x...) do { if (opt_verbose) ksft_print_msg(x); } while (0) |
| @@ -51,8 +53,13 @@ enum test_mode { · 5 unmodified lines | ||
| 51 | 53 | }; |
| 52 | 54 | |
| 53 | 55 | enum test_type { |
| 54 | − TEST_TYPE_NOPOLL, | |
| 56 | + TEST_TYPE_RUN_TO_COMPLETION, | |
| 57 | + TEST_TYPE_RUN_TO_COMPLETION_2K_FRAME, | |
| 55 | 58 | 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, | |
| 56 | 63 | TEST_TYPE_TEARDOWN, |
| 57 | 64 | TEST_TYPE_BIDI, |
| 58 | 65 | TEST_TYPE_STATS, |
| @@ -68,25 +75,21 @@ enum stat_test_type { · 9 unmodified lines | ||
| 68 | 75 | STAT_TEST_TYPE_MAX |
| 69 | 76 | }; |
| 70 | 77 | |
| 71 | −static int configured_mode; | |
| 72 | 78 | static bool opt_pkt_dump; |
| 73 | −static u32 num_frames = DEFAULT_PKT_CNT / 4; | |
| 74 | −static bool second_step; | |
| 75 | 79 | static int test_type; |
| 76 | 80 | |
| 77 | 81 | 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; | |
| 81 | 82 | static int stat_test_type; |
| 82 | −static u32 rxqsize; | |
| 83 | −static u32 frame_headroom; | |
| 84 | 83 | |
| 85 | 84 | struct xsk_umem_info { |
| 86 | 85 | struct xsk_ring_prod fq; |
| 87 | 86 | struct xsk_ring_cons cq; |
| 88 | 87 | struct xsk_umem *umem; |
| 88 | + u32 num_frames; | |
| 89 | + u32 frame_headroom; | |
| 89 | 90 | void *buffer; |
| 91 | + u32 frame_size; | |
| 92 | + bool unaligned_mode; | |
| 90 | 93 | }; |
| 91 | 94 | |
| 92 | 95 | struct xsk_socket_info { |
| @@ -95,51 +98,58 @@ struct xsk_socket_info { · 2 unmodified lines | ||
| 95 | 98 | struct xsk_umem_info *umem; |
| 96 | 99 | struct xsk_socket *xsk; |
| 97 | 100 | u32 outstanding_tx; |
| 98 | −}; | |
| 99 | − | |
| 100 | −struct flow_vector { | |
| 101 | − enum fvector { | |
| 102 | − tx, | |
| 103 | − rx, | |
| 104 | − } vector; | |
| 101 | + u32 rxqsize; | |
| 105 | 102 | }; |
| 106 | 103 | |
| 107 | 104 | struct pkt { |
| 108 | 105 | u64 addr; |
| 109 | 106 | u32 len; |
| 110 | 107 | u32 payload; |
| 108 | + bool valid; | |
| 111 | 109 | }; |
| 112 | 110 | |
| 113 | 111 | struct pkt_stream { |
| 114 | 112 | u32 nb_pkts; |
| 113 | + u32 rx_pkt_nb; | |
| 115 | 114 | struct pkt *pkts; |
| 115 | + bool use_addr_for_fill; | |
| 116 | 116 | }; |
| 117 | 117 | |
| 118 | +typedef void *(*thread_func_t)(void *arg); | |
| 119 | + | |
| 118 | 120 | struct ifobject { |
| 119 | 121 | char ifname[MAX_INTERFACE_NAME_CHARS]; |
| 120 | 122 | char nsname[MAX_INTERFACES_NAMESPACE_CHARS]; |
| 121 | 123 | 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; | |
| 124 | 125 | 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; | |
| 127 | 128 | struct pkt_stream *pkt_stream; |
| 128 | 129 | int ns_fd; |
| 129 | 130 | u32 dst_ip; |
| 130 | 131 | u32 src_ip; |
| 132 | + u32 xdp_flags; | |
| 133 | + u32 bind_flags; | |
| 131 | 134 | u16 src_port; |
| 132 | 135 | u16 dst_port; |
| 136 | + bool tx_on; | |
| 137 | + bool rx_on; | |
| 138 | + bool use_poll; | |
| 133 | 139 | u8 dst_mac[ETH_ALEN]; |
| 134 | 140 | u8 src_mac[ETH_ALEN]; |
| 135 | 141 | }; |
| 136 | 142 | |
| 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 | +}; | |
| 140 | 152 | |
| 141 | −/*threads*/ | |
| 142 | 153 | pthread_barrier_t barr; |
| 143 | −pthread_t t0, t1; | |
| 144 | 154 | |
| 145 | 155 | #endif /* XDPXCEIVER_H */ |