diff options
author | Ingo Molnar <mingo@kernel.org> | 2018-10-29 02:12:34 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2018-10-29 02:12:34 -0400 |
commit | 97ec37c57dd411d0815455bca07166411c0da1df (patch) | |
tree | d64850c43778d15c137772957788093a8b7d032c /tools | |
parent | ace6485a03266cc3c198ce8e927a1ce0ce139699 (diff) | |
parent | b59dfdaef173677b0b7e10f375226c0a1114fd20 (diff) |
Merge branch 'linus' into x86/urgent, to refresh the tree
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools')
152 files changed, 13324 insertions, 1930 deletions
diff --git a/tools/Makefile b/tools/Makefile index be02c8b904db..abb358a70ad0 100644 --- a/tools/Makefile +++ b/tools/Makefile | |||
@@ -21,6 +21,7 @@ help: | |||
21 | @echo ' leds - LEDs tools' | 21 | @echo ' leds - LEDs tools' |
22 | @echo ' liblockdep - user-space wrapper for kernel locking-validator' | 22 | @echo ' liblockdep - user-space wrapper for kernel locking-validator' |
23 | @echo ' bpf - misc BPF tools' | 23 | @echo ' bpf - misc BPF tools' |
24 | @echo ' pci - PCI tools' | ||
24 | @echo ' perf - Linux performance measurement and analysis tool' | 25 | @echo ' perf - Linux performance measurement and analysis tool' |
25 | @echo ' selftests - various kernel selftests' | 26 | @echo ' selftests - various kernel selftests' |
26 | @echo ' spi - spi tools' | 27 | @echo ' spi - spi tools' |
@@ -59,7 +60,7 @@ acpi: FORCE | |||
59 | cpupower: FORCE | 60 | cpupower: FORCE |
60 | $(call descend,power/$@) | 61 | $(call descend,power/$@) |
61 | 62 | ||
62 | cgroup firewire hv guest spi usb virtio vm bpf iio gpio objtool leds wmi: FORCE | 63 | cgroup firewire hv guest spi usb virtio vm bpf iio gpio objtool leds wmi pci: FORCE |
63 | $(call descend,$@) | 64 | $(call descend,$@) |
64 | 65 | ||
65 | liblockdep: FORCE | 66 | liblockdep: FORCE |
@@ -94,7 +95,7 @@ kvm_stat: FORCE | |||
94 | all: acpi cgroup cpupower gpio hv firewire liblockdep \ | 95 | all: acpi cgroup cpupower gpio hv firewire liblockdep \ |
95 | perf selftests spi turbostat usb \ | 96 | perf selftests spi turbostat usb \ |
96 | virtio vm bpf x86_energy_perf_policy \ | 97 | virtio vm bpf x86_energy_perf_policy \ |
97 | tmon freefall iio objtool kvm_stat wmi | 98 | tmon freefall iio objtool kvm_stat wmi pci |
98 | 99 | ||
99 | acpi_install: | 100 | acpi_install: |
100 | $(call descend,power/$(@:_install=),install) | 101 | $(call descend,power/$(@:_install=),install) |
@@ -102,7 +103,7 @@ acpi_install: | |||
102 | cpupower_install: | 103 | cpupower_install: |
103 | $(call descend,power/$(@:_install=),install) | 104 | $(call descend,power/$(@:_install=),install) |
104 | 105 | ||
105 | cgroup_install firewire_install gpio_install hv_install iio_install perf_install spi_install usb_install virtio_install vm_install bpf_install objtool_install wmi_install: | 106 | cgroup_install firewire_install gpio_install hv_install iio_install perf_install spi_install usb_install virtio_install vm_install bpf_install objtool_install wmi_install pci_install: |
106 | $(call descend,$(@:_install=),install) | 107 | $(call descend,$(@:_install=),install) |
107 | 108 | ||
108 | liblockdep_install: | 109 | liblockdep_install: |
@@ -128,7 +129,7 @@ install: acpi_install cgroup_install cpupower_install gpio_install \ | |||
128 | perf_install selftests_install turbostat_install usb_install \ | 129 | perf_install selftests_install turbostat_install usb_install \ |
129 | virtio_install vm_install bpf_install x86_energy_perf_policy_install \ | 130 | virtio_install vm_install bpf_install x86_energy_perf_policy_install \ |
130 | tmon_install freefall_install objtool_install kvm_stat_install \ | 131 | tmon_install freefall_install objtool_install kvm_stat_install \ |
131 | wmi_install | 132 | wmi_install pci_install |
132 | 133 | ||
133 | acpi_clean: | 134 | acpi_clean: |
134 | $(call descend,power/acpi,clean) | 135 | $(call descend,power/acpi,clean) |
@@ -136,7 +137,7 @@ acpi_clean: | |||
136 | cpupower_clean: | 137 | cpupower_clean: |
137 | $(call descend,power/cpupower,clean) | 138 | $(call descend,power/cpupower,clean) |
138 | 139 | ||
139 | cgroup_clean hv_clean firewire_clean spi_clean usb_clean virtio_clean vm_clean wmi_clean bpf_clean iio_clean gpio_clean objtool_clean leds_clean: | 140 | cgroup_clean hv_clean firewire_clean spi_clean usb_clean virtio_clean vm_clean wmi_clean bpf_clean iio_clean gpio_clean objtool_clean leds_clean pci_clean: |
140 | $(call descend,$(@:_clean=),clean) | 141 | $(call descend,$(@:_clean=),clean) |
141 | 142 | ||
142 | liblockdep_clean: | 143 | liblockdep_clean: |
@@ -174,6 +175,6 @@ clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean \ | |||
174 | perf_clean selftests_clean turbostat_clean spi_clean usb_clean virtio_clean \ | 175 | perf_clean selftests_clean turbostat_clean spi_clean usb_clean virtio_clean \ |
175 | vm_clean bpf_clean iio_clean x86_energy_perf_policy_clean tmon_clean \ | 176 | vm_clean bpf_clean iio_clean x86_energy_perf_policy_clean tmon_clean \ |
176 | freefall_clean build_clean libbpf_clean libsubcmd_clean liblockdep_clean \ | 177 | freefall_clean build_clean libbpf_clean libsubcmd_clean liblockdep_clean \ |
177 | gpio_clean objtool_clean leds_clean wmi_clean | 178 | gpio_clean objtool_clean leds_clean wmi_clean pci_clean |
178 | 179 | ||
179 | .PHONY: FORCE | 180 | .PHONY: FORCE |
diff --git a/tools/accounting/getdelays.c b/tools/accounting/getdelays.c index 9f420d98b5fb..8cb504d30384 100644 --- a/tools/accounting/getdelays.c +++ b/tools/accounting/getdelays.c | |||
@@ -203,6 +203,8 @@ static void print_delayacct(struct taskstats *t) | |||
203 | "SWAP %15s%15s%15s\n" | 203 | "SWAP %15s%15s%15s\n" |
204 | " %15llu%15llu%15llums\n" | 204 | " %15llu%15llu%15llums\n" |
205 | "RECLAIM %12s%15s%15s\n" | 205 | "RECLAIM %12s%15s%15s\n" |
206 | " %15llu%15llu%15llums\n" | ||
207 | "THRASHING%12s%15s%15s\n" | ||
206 | " %15llu%15llu%15llums\n", | 208 | " %15llu%15llu%15llums\n", |
207 | "count", "real total", "virtual total", | 209 | "count", "real total", "virtual total", |
208 | "delay total", "delay average", | 210 | "delay total", "delay average", |
@@ -222,7 +224,11 @@ static void print_delayacct(struct taskstats *t) | |||
222 | "count", "delay total", "delay average", | 224 | "count", "delay total", "delay average", |
223 | (unsigned long long)t->freepages_count, | 225 | (unsigned long long)t->freepages_count, |
224 | (unsigned long long)t->freepages_delay_total, | 226 | (unsigned long long)t->freepages_delay_total, |
225 | average_ms(t->freepages_delay_total, t->freepages_count)); | 227 | average_ms(t->freepages_delay_total, t->freepages_count), |
228 | "count", "delay total", "delay average", | ||
229 | (unsigned long long)t->thrashing_count, | ||
230 | (unsigned long long)t->thrashing_delay_total, | ||
231 | average_ms(t->thrashing_delay_total, t->thrashing_count)); | ||
226 | } | 232 | } |
227 | 233 | ||
228 | static void task_context_switch_counts(struct taskstats *t) | 234 | static void task_context_switch_counts(struct taskstats *t) |
diff --git a/tools/arch/arm64/include/asm/barrier.h b/tools/arch/arm64/include/asm/barrier.h index 40bde6b23501..12835ea0e417 100644 --- a/tools/arch/arm64/include/asm/barrier.h +++ b/tools/arch/arm64/include/asm/barrier.h | |||
@@ -14,4 +14,74 @@ | |||
14 | #define wmb() asm volatile("dmb ishst" ::: "memory") | 14 | #define wmb() asm volatile("dmb ishst" ::: "memory") |
15 | #define rmb() asm volatile("dmb ishld" ::: "memory") | 15 | #define rmb() asm volatile("dmb ishld" ::: "memory") |
16 | 16 | ||
17 | #define smp_store_release(p, v) \ | ||
18 | do { \ | ||
19 | union { typeof(*p) __val; char __c[1]; } __u = \ | ||
20 | { .__val = (__force typeof(*p)) (v) }; \ | ||
21 | \ | ||
22 | switch (sizeof(*p)) { \ | ||
23 | case 1: \ | ||
24 | asm volatile ("stlrb %w1, %0" \ | ||
25 | : "=Q" (*p) \ | ||
26 | : "r" (*(__u8 *)__u.__c) \ | ||
27 | : "memory"); \ | ||
28 | break; \ | ||
29 | case 2: \ | ||
30 | asm volatile ("stlrh %w1, %0" \ | ||
31 | : "=Q" (*p) \ | ||
32 | : "r" (*(__u16 *)__u.__c) \ | ||
33 | : "memory"); \ | ||
34 | break; \ | ||
35 | case 4: \ | ||
36 | asm volatile ("stlr %w1, %0" \ | ||
37 | : "=Q" (*p) \ | ||
38 | : "r" (*(__u32 *)__u.__c) \ | ||
39 | : "memory"); \ | ||
40 | break; \ | ||
41 | case 8: \ | ||
42 | asm volatile ("stlr %1, %0" \ | ||
43 | : "=Q" (*p) \ | ||
44 | : "r" (*(__u64 *)__u.__c) \ | ||
45 | : "memory"); \ | ||
46 | break; \ | ||
47 | default: \ | ||
48 | /* Only to shut up gcc ... */ \ | ||
49 | mb(); \ | ||
50 | break; \ | ||
51 | } \ | ||
52 | } while (0) | ||
53 | |||
54 | #define smp_load_acquire(p) \ | ||
55 | ({ \ | ||
56 | union { typeof(*p) __val; char __c[1]; } __u; \ | ||
57 | \ | ||
58 | switch (sizeof(*p)) { \ | ||
59 | case 1: \ | ||
60 | asm volatile ("ldarb %w0, %1" \ | ||
61 | : "=r" (*(__u8 *)__u.__c) \ | ||
62 | : "Q" (*p) : "memory"); \ | ||
63 | break; \ | ||
64 | case 2: \ | ||
65 | asm volatile ("ldarh %w0, %1" \ | ||
66 | : "=r" (*(__u16 *)__u.__c) \ | ||
67 | : "Q" (*p) : "memory"); \ | ||
68 | break; \ | ||
69 | case 4: \ | ||
70 | asm volatile ("ldar %w0, %1" \ | ||
71 | : "=r" (*(__u32 *)__u.__c) \ | ||
72 | : "Q" (*p) : "memory"); \ | ||
73 | break; \ | ||
74 | case 8: \ | ||
75 | asm volatile ("ldar %0, %1" \ | ||
76 | : "=r" (*(__u64 *)__u.__c) \ | ||
77 | : "Q" (*p) : "memory"); \ | ||
78 | break; \ | ||
79 | default: \ | ||
80 | /* Only to shut up gcc ... */ \ | ||
81 | mb(); \ | ||
82 | break; \ | ||
83 | } \ | ||
84 | __u.__val; \ | ||
85 | }) | ||
86 | |||
17 | #endif /* _TOOLS_LINUX_ASM_AARCH64_BARRIER_H */ | 87 | #endif /* _TOOLS_LINUX_ASM_AARCH64_BARRIER_H */ |
diff --git a/tools/arch/ia64/include/asm/barrier.h b/tools/arch/ia64/include/asm/barrier.h index d808ee0e77b5..4d471d9511a5 100644 --- a/tools/arch/ia64/include/asm/barrier.h +++ b/tools/arch/ia64/include/asm/barrier.h | |||
@@ -46,4 +46,17 @@ | |||
46 | #define rmb() mb() | 46 | #define rmb() mb() |
47 | #define wmb() mb() | 47 | #define wmb() mb() |
48 | 48 | ||
49 | #define smp_store_release(p, v) \ | ||
50 | do { \ | ||
51 | barrier(); \ | ||
52 | WRITE_ONCE(*p, v); \ | ||
53 | } while (0) | ||
54 | |||
55 | #define smp_load_acquire(p) \ | ||
56 | ({ \ | ||
57 | typeof(*p) ___p1 = READ_ONCE(*p); \ | ||
58 | barrier(); \ | ||
59 | ___p1; \ | ||
60 | }) | ||
61 | |||
49 | #endif /* _TOOLS_LINUX_ASM_IA64_BARRIER_H */ | 62 | #endif /* _TOOLS_LINUX_ASM_IA64_BARRIER_H */ |
diff --git a/tools/arch/powerpc/include/asm/barrier.h b/tools/arch/powerpc/include/asm/barrier.h index a634da05bc97..905a2c66d96d 100644 --- a/tools/arch/powerpc/include/asm/barrier.h +++ b/tools/arch/powerpc/include/asm/barrier.h | |||
@@ -27,4 +27,20 @@ | |||
27 | #define rmb() __asm__ __volatile__ ("sync" : : : "memory") | 27 | #define rmb() __asm__ __volatile__ ("sync" : : : "memory") |
28 | #define wmb() __asm__ __volatile__ ("sync" : : : "memory") | 28 | #define wmb() __asm__ __volatile__ ("sync" : : : "memory") |
29 | 29 | ||
30 | #if defined(__powerpc64__) | ||
31 | #define smp_lwsync() __asm__ __volatile__ ("lwsync" : : : "memory") | ||
32 | |||
33 | #define smp_store_release(p, v) \ | ||
34 | do { \ | ||
35 | smp_lwsync(); \ | ||
36 | WRITE_ONCE(*p, v); \ | ||
37 | } while (0) | ||
38 | |||
39 | #define smp_load_acquire(p) \ | ||
40 | ({ \ | ||
41 | typeof(*p) ___p1 = READ_ONCE(*p); \ | ||
42 | smp_lwsync(); \ | ||
43 | ___p1; \ | ||
44 | }) | ||
45 | #endif /* defined(__powerpc64__) */ | ||
30 | #endif /* _TOOLS_LINUX_ASM_POWERPC_BARRIER_H */ | 46 | #endif /* _TOOLS_LINUX_ASM_POWERPC_BARRIER_H */ |
diff --git a/tools/arch/s390/include/asm/barrier.h b/tools/arch/s390/include/asm/barrier.h index 5030c99f47d2..de362fa664d4 100644 --- a/tools/arch/s390/include/asm/barrier.h +++ b/tools/arch/s390/include/asm/barrier.h | |||
@@ -28,4 +28,17 @@ | |||
28 | #define rmb() mb() | 28 | #define rmb() mb() |
29 | #define wmb() mb() | 29 | #define wmb() mb() |
30 | 30 | ||
31 | #define smp_store_release(p, v) \ | ||
32 | do { \ | ||
33 | barrier(); \ | ||
34 | WRITE_ONCE(*p, v); \ | ||
35 | } while (0) | ||
36 | |||
37 | #define smp_load_acquire(p) \ | ||
38 | ({ \ | ||
39 | typeof(*p) ___p1 = READ_ONCE(*p); \ | ||
40 | barrier(); \ | ||
41 | ___p1; \ | ||
42 | }) | ||
43 | |||
31 | #endif /* __TOOLS_LIB_ASM_BARRIER_H */ | 44 | #endif /* __TOOLS_LIB_ASM_BARRIER_H */ |
diff --git a/tools/arch/sparc/include/asm/barrier_64.h b/tools/arch/sparc/include/asm/barrier_64.h index ba61344287d5..cfb0fdc8ccf0 100644 --- a/tools/arch/sparc/include/asm/barrier_64.h +++ b/tools/arch/sparc/include/asm/barrier_64.h | |||
@@ -40,4 +40,17 @@ do { __asm__ __volatile__("ba,pt %%xcc, 1f\n\t" \ | |||
40 | #define rmb() __asm__ __volatile__("":::"memory") | 40 | #define rmb() __asm__ __volatile__("":::"memory") |
41 | #define wmb() __asm__ __volatile__("":::"memory") | 41 | #define wmb() __asm__ __volatile__("":::"memory") |
42 | 42 | ||
43 | #define smp_store_release(p, v) \ | ||
44 | do { \ | ||
45 | barrier(); \ | ||
46 | WRITE_ONCE(*p, v); \ | ||
47 | } while (0) | ||
48 | |||
49 | #define smp_load_acquire(p) \ | ||
50 | ({ \ | ||
51 | typeof(*p) ___p1 = READ_ONCE(*p); \ | ||
52 | barrier(); \ | ||
53 | ___p1; \ | ||
54 | }) | ||
55 | |||
43 | #endif /* !(__TOOLS_LINUX_SPARC64_BARRIER_H) */ | 56 | #endif /* !(__TOOLS_LINUX_SPARC64_BARRIER_H) */ |
diff --git a/tools/arch/x86/include/asm/barrier.h b/tools/arch/x86/include/asm/barrier.h index 8774dee27471..58919868473c 100644 --- a/tools/arch/x86/include/asm/barrier.h +++ b/tools/arch/x86/include/asm/barrier.h | |||
@@ -26,4 +26,18 @@ | |||
26 | #define wmb() asm volatile("sfence" ::: "memory") | 26 | #define wmb() asm volatile("sfence" ::: "memory") |
27 | #endif | 27 | #endif |
28 | 28 | ||
29 | #if defined(__x86_64__) | ||
30 | #define smp_store_release(p, v) \ | ||
31 | do { \ | ||
32 | barrier(); \ | ||
33 | WRITE_ONCE(*p, v); \ | ||
34 | } while (0) | ||
35 | |||
36 | #define smp_load_acquire(p) \ | ||
37 | ({ \ | ||
38 | typeof(*p) ___p1 = READ_ONCE(*p); \ | ||
39 | barrier(); \ | ||
40 | ___p1; \ | ||
41 | }) | ||
42 | #endif /* defined(__x86_64__) */ | ||
29 | #endif /* _TOOLS_LINUX_ASM_X86_BARRIER_H */ | 43 | #endif /* _TOOLS_LINUX_ASM_X86_BARRIER_H */ |
diff --git a/tools/arch/x86/include/uapi/asm/kvm.h b/tools/arch/x86/include/uapi/asm/kvm.h index fd23d5778ea1..8a6eff9c27f3 100644 --- a/tools/arch/x86/include/uapi/asm/kvm.h +++ b/tools/arch/x86/include/uapi/asm/kvm.h | |||
@@ -288,6 +288,7 @@ struct kvm_reinject_control { | |||
288 | #define KVM_VCPUEVENT_VALID_SIPI_VECTOR 0x00000002 | 288 | #define KVM_VCPUEVENT_VALID_SIPI_VECTOR 0x00000002 |
289 | #define KVM_VCPUEVENT_VALID_SHADOW 0x00000004 | 289 | #define KVM_VCPUEVENT_VALID_SHADOW 0x00000004 |
290 | #define KVM_VCPUEVENT_VALID_SMM 0x00000008 | 290 | #define KVM_VCPUEVENT_VALID_SMM 0x00000008 |
291 | #define KVM_VCPUEVENT_VALID_PAYLOAD 0x00000010 | ||
291 | 292 | ||
292 | /* Interrupt shadow states */ | 293 | /* Interrupt shadow states */ |
293 | #define KVM_X86_SHADOW_INT_MOV_SS 0x01 | 294 | #define KVM_X86_SHADOW_INT_MOV_SS 0x01 |
@@ -299,7 +300,10 @@ struct kvm_vcpu_events { | |||
299 | __u8 injected; | 300 | __u8 injected; |
300 | __u8 nr; | 301 | __u8 nr; |
301 | __u8 has_error_code; | 302 | __u8 has_error_code; |
302 | __u8 pad; | 303 | union { |
304 | __u8 pad; | ||
305 | __u8 pending; | ||
306 | }; | ||
303 | __u32 error_code; | 307 | __u32 error_code; |
304 | } exception; | 308 | } exception; |
305 | struct { | 309 | struct { |
@@ -322,7 +326,9 @@ struct kvm_vcpu_events { | |||
322 | __u8 smm_inside_nmi; | 326 | __u8 smm_inside_nmi; |
323 | __u8 latched_init; | 327 | __u8 latched_init; |
324 | } smi; | 328 | } smi; |
325 | __u32 reserved[9]; | 329 | __u8 reserved[27]; |
330 | __u8 exception_has_payload; | ||
331 | __u64 exception_payload; | ||
326 | }; | 332 | }; |
327 | 333 | ||
328 | /* for KVM_GET/SET_DEBUGREGS */ | 334 | /* for KVM_GET/SET_DEBUGREGS */ |
diff --git a/tools/bpf/bpftool/Documentation/bpftool-map.rst b/tools/bpf/bpftool/Documentation/bpftool-map.rst index a6258bc8ec4f..f55a2daed59b 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-map.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-map.rst | |||
@@ -15,13 +15,15 @@ SYNOPSIS | |||
15 | *OPTIONS* := { { **-j** | **--json** } [{ **-p** | **--pretty** }] | { **-f** | **--bpffs** } } | 15 | *OPTIONS* := { { **-j** | **--json** } [{ **-p** | **--pretty** }] | { **-f** | **--bpffs** } } |
16 | 16 | ||
17 | *COMMANDS* := | 17 | *COMMANDS* := |
18 | { **show** | **list** | **dump** | **update** | **lookup** | **getnext** | **delete** | 18 | { **show** | **list** | **create** | **dump** | **update** | **lookup** | **getnext** |
19 | | **pin** | **help** } | 19 | | **delete** | **pin** | **help** } |
20 | 20 | ||
21 | MAP COMMANDS | 21 | MAP COMMANDS |
22 | ============= | 22 | ============= |
23 | 23 | ||
24 | | **bpftool** **map { show | list }** [*MAP*] | 24 | | **bpftool** **map { show | list }** [*MAP*] |
25 | | **bpftool** **map create** *FILE* **type** *TYPE* **key** *KEY_SIZE* **value** *VALUE_SIZE* \ | ||
26 | | **entries** *MAX_ENTRIES* **name** *NAME* [**flags** *FLAGS*] [**dev** *NAME*] | ||
25 | | **bpftool** **map dump** *MAP* | 27 | | **bpftool** **map dump** *MAP* |
26 | | **bpftool** **map update** *MAP* **key** *DATA* **value** *VALUE* [*UPDATE_FLAGS*] | 28 | | **bpftool** **map update** *MAP* **key** *DATA* **value** *VALUE* [*UPDATE_FLAGS*] |
27 | | **bpftool** **map lookup** *MAP* **key** *DATA* | 29 | | **bpftool** **map lookup** *MAP* **key** *DATA* |
@@ -36,6 +38,11 @@ MAP COMMANDS | |||
36 | | *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* } | 38 | | *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* } |
37 | | *VALUE* := { *DATA* | *MAP* | *PROG* } | 39 | | *VALUE* := { *DATA* | *MAP* | *PROG* } |
38 | | *UPDATE_FLAGS* := { **any** | **exist** | **noexist** } | 40 | | *UPDATE_FLAGS* := { **any** | **exist** | **noexist** } |
41 | | *TYPE* := { **hash** | **array** | **prog_array** | **perf_event_array** | **percpu_hash** | ||
42 | | | **percpu_array** | **stack_trace** | **cgroup_array** | **lru_hash** | ||
43 | | | **lru_percpu_hash** | **lpm_trie** | **array_of_maps** | **hash_of_maps** | ||
44 | | | **devmap** | **sockmap** | **cpumap** | **xskmap** | **sockhash** | ||
45 | | | **cgroup_storage** | **reuseport_sockarray** | **percpu_cgroup_storage** } | ||
39 | 46 | ||
40 | DESCRIPTION | 47 | DESCRIPTION |
41 | =========== | 48 | =========== |
@@ -47,6 +54,10 @@ DESCRIPTION | |||
47 | Output will start with map ID followed by map type and | 54 | Output will start with map ID followed by map type and |
48 | zero or more named attributes (depending on kernel version). | 55 | zero or more named attributes (depending on kernel version). |
49 | 56 | ||
57 | **bpftool map create** *FILE* **type** *TYPE* **key** *KEY_SIZE* **value** *VALUE_SIZE* **entries** *MAX_ENTRIES* **name** *NAME* [**flags** *FLAGS*] [**dev** *NAME*] | ||
58 | Create a new map with given parameters and pin it to *bpffs* | ||
59 | as *FILE*. | ||
60 | |||
50 | **bpftool map dump** *MAP* | 61 | **bpftool map dump** *MAP* |
51 | Dump all entries in a given *MAP*. | 62 | Dump all entries in a given *MAP*. |
52 | 63 | ||
@@ -75,7 +86,9 @@ DESCRIPTION | |||
75 | **bpftool map pin** *MAP* *FILE* | 86 | **bpftool map pin** *MAP* *FILE* |
76 | Pin map *MAP* as *FILE*. | 87 | Pin map *MAP* as *FILE*. |
77 | 88 | ||
78 | Note: *FILE* must be located in *bpffs* mount. | 89 | Note: *FILE* must be located in *bpffs* mount. It must not |
90 | contain a dot character ('.'), which is reserved for future | ||
91 | extensions of *bpffs*. | ||
79 | 92 | ||
80 | **bpftool** **map event_pipe** *MAP* [**cpu** *N* **index** *M*] | 93 | **bpftool** **map event_pipe** *MAP* [**cpu** *N* **index** *M*] |
81 | Read events from a BPF_MAP_TYPE_PERF_EVENT_ARRAY map. | 94 | Read events from a BPF_MAP_TYPE_PERF_EVENT_ARRAY map. |
diff --git a/tools/bpf/bpftool/Documentation/bpftool-net.rst b/tools/bpf/bpftool/Documentation/bpftool-net.rst new file mode 100644 index 000000000000..408ec30d8872 --- /dev/null +++ b/tools/bpf/bpftool/Documentation/bpftool-net.rst | |||
@@ -0,0 +1,139 @@ | |||
1 | ================ | ||
2 | bpftool-net | ||
3 | ================ | ||
4 | ------------------------------------------------------------------------------- | ||
5 | tool for inspection of netdev/tc related bpf prog attachments | ||
6 | ------------------------------------------------------------------------------- | ||
7 | |||
8 | :Manual section: 8 | ||
9 | |||
10 | SYNOPSIS | ||
11 | ======== | ||
12 | |||
13 | **bpftool** [*OPTIONS*] **net** *COMMAND* | ||
14 | |||
15 | *OPTIONS* := { [{ **-j** | **--json** }] [{ **-p** | **--pretty** }] } | ||
16 | |||
17 | *COMMANDS* := | ||
18 | { **show** | **list** } [ **dev** name ] | **help** | ||
19 | |||
20 | NET COMMANDS | ||
21 | ============ | ||
22 | |||
23 | | **bpftool** **net { show | list } [ dev name ]** | ||
24 | | **bpftool** **net help** | ||
25 | |||
26 | DESCRIPTION | ||
27 | =========== | ||
28 | **bpftool net { show | list } [ dev name ]** | ||
29 | List bpf program attachments in the kernel networking subsystem. | ||
30 | |||
31 | Currently, only device driver xdp attachments and tc filter | ||
32 | classification/action attachments are implemented, i.e., for | ||
33 | program types **BPF_PROG_TYPE_SCHED_CLS**, | ||
34 | **BPF_PROG_TYPE_SCHED_ACT** and **BPF_PROG_TYPE_XDP**. | ||
35 | For programs attached to a particular cgroup, e.g., | ||
36 | **BPF_PROG_TYPE_CGROUP_SKB**, **BPF_PROG_TYPE_CGROUP_SOCK**, | ||
37 | **BPF_PROG_TYPE_SOCK_OPS** and **BPF_PROG_TYPE_CGROUP_SOCK_ADDR**, | ||
38 | users can use **bpftool cgroup** to dump cgroup attachments. | ||
39 | For sk_{filter, skb, msg, reuseport} and lwt/seg6 | ||
40 | bpf programs, users should consult other tools, e.g., iproute2. | ||
41 | |||
42 | The current output will start with all xdp program attachments, followed by | ||
43 | all tc class/qdisc bpf program attachments. Both xdp programs and | ||
44 | tc programs are ordered based on ifindex number. If multiple bpf | ||
45 | programs attached to the same networking device through **tc filter**, | ||
46 | the order will be first all bpf programs attached to tc classes, then | ||
47 | all bpf programs attached to non clsact qdiscs, and finally all | ||
48 | bpf programs attached to root and clsact qdisc. | ||
49 | |||
50 | **bpftool net help** | ||
51 | Print short help message. | ||
52 | |||
53 | OPTIONS | ||
54 | ======= | ||
55 | -h, --help | ||
56 | Print short generic help message (similar to **bpftool help**). | ||
57 | |||
58 | -v, --version | ||
59 | Print version number (similar to **bpftool version**). | ||
60 | |||
61 | -j, --json | ||
62 | Generate JSON output. For commands that cannot produce JSON, this | ||
63 | option has no effect. | ||
64 | |||
65 | -p, --pretty | ||
66 | Generate human-readable JSON output. Implies **-j**. | ||
67 | |||
68 | EXAMPLES | ||
69 | ======== | ||
70 | |||
71 | | **# bpftool net** | ||
72 | |||
73 | :: | ||
74 | |||
75 | xdp: | ||
76 | eth0(2) driver id 198 | ||
77 | |||
78 | tc: | ||
79 | eth0(2) htb name prefix_matcher.o:[cls_prefix_matcher_htb] id 111727 act [] | ||
80 | eth0(2) clsact/ingress fbflow_icmp id 130246 act [] | ||
81 | eth0(2) clsact/egress prefix_matcher.o:[cls_prefix_matcher_clsact] id 111726 | ||
82 | eth0(2) clsact/egress cls_fg_dscp id 108619 act [] | ||
83 | eth0(2) clsact/egress fbflow_egress id 130245 | ||
84 | |||
85 | | | ||
86 | | **# bpftool -jp net** | ||
87 | |||
88 | :: | ||
89 | |||
90 | [{ | ||
91 | "xdp": [{ | ||
92 | "devname": "eth0", | ||
93 | "ifindex": 2, | ||
94 | "mode": "driver", | ||
95 | "id": 198 | ||
96 | } | ||
97 | ], | ||
98 | "tc": [{ | ||
99 | "devname": "eth0", | ||
100 | "ifindex": 2, | ||
101 | "kind": "htb", | ||
102 | "name": "prefix_matcher.o:[cls_prefix_matcher_htb]", | ||
103 | "id": 111727, | ||
104 | "act": [] | ||
105 | },{ | ||
106 | "devname": "eth0", | ||
107 | "ifindex": 2, | ||
108 | "kind": "clsact/ingress", | ||
109 | "name": "fbflow_icmp", | ||
110 | "id": 130246, | ||
111 | "act": [] | ||
112 | },{ | ||
113 | "devname": "eth0", | ||
114 | "ifindex": 2, | ||
115 | "kind": "clsact/egress", | ||
116 | "name": "prefix_matcher.o:[cls_prefix_matcher_clsact]", | ||
117 | "id": 111726, | ||
118 | },{ | ||
119 | "devname": "eth0", | ||
120 | "ifindex": 2, | ||
121 | "kind": "clsact/egress", | ||
122 | "name": "cls_fg_dscp", | ||
123 | "id": 108619, | ||
124 | "act": [] | ||
125 | },{ | ||
126 | "devname": "eth0", | ||
127 | "ifindex": 2, | ||
128 | "kind": "clsact/egress", | ||
129 | "name": "fbflow_egress", | ||
130 | "id": 130245, | ||
131 | } | ||
132 | ] | ||
133 | } | ||
134 | ] | ||
135 | |||
136 | |||
137 | SEE ALSO | ||
138 | ======== | ||
139 | **bpftool**\ (8), **bpftool-prog**\ (8), **bpftool-map**\ (8) | ||
diff --git a/tools/bpf/bpftool/Documentation/bpftool-prog.rst b/tools/bpf/bpftool/Documentation/bpftool-prog.rst index 64156a16d530..ac4e904b10fb 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-prog.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-prog.rst | |||
@@ -25,6 +25,8 @@ MAP COMMANDS | |||
25 | | **bpftool** **prog dump jited** *PROG* [{**file** *FILE* | **opcodes**}] | 25 | | **bpftool** **prog dump jited** *PROG* [{**file** *FILE* | **opcodes**}] |
26 | | **bpftool** **prog pin** *PROG* *FILE* | 26 | | **bpftool** **prog pin** *PROG* *FILE* |
27 | | **bpftool** **prog load** *OBJ* *FILE* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*] | 27 | | **bpftool** **prog load** *OBJ* *FILE* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*] |
28 | | **bpftool** **prog attach** *PROG* *ATTACH_TYPE* *MAP* | ||
29 | | **bpftool** **prog detach** *PROG* *ATTACH_TYPE* *MAP* | ||
28 | | **bpftool** **prog help** | 30 | | **bpftool** **prog help** |
29 | | | 31 | | |
30 | | *MAP* := { **id** *MAP_ID* | **pinned** *FILE* } | 32 | | *MAP* := { **id** *MAP_ID* | **pinned** *FILE* } |
@@ -37,6 +39,7 @@ MAP COMMANDS | |||
37 | | **cgroup/bind4** | **cgroup/bind6** | **cgroup/post_bind4** | **cgroup/post_bind6** | | 39 | | **cgroup/bind4** | **cgroup/bind6** | **cgroup/post_bind4** | **cgroup/post_bind6** | |
38 | | **cgroup/connect4** | **cgroup/connect6** | **cgroup/sendmsg4** | **cgroup/sendmsg6** | 40 | | **cgroup/connect4** | **cgroup/connect6** | **cgroup/sendmsg4** | **cgroup/sendmsg6** |
39 | | } | 41 | | } |
42 | | *ATTACH_TYPE* := { **msg_verdict** | **skb_verdict** | **skb_parse** } | ||
40 | 43 | ||
41 | 44 | ||
42 | DESCRIPTION | 45 | DESCRIPTION |
@@ -72,7 +75,9 @@ DESCRIPTION | |||
72 | **bpftool prog pin** *PROG* *FILE* | 75 | **bpftool prog pin** *PROG* *FILE* |
73 | Pin program *PROG* as *FILE*. | 76 | Pin program *PROG* as *FILE*. |
74 | 77 | ||
75 | Note: *FILE* must be located in *bpffs* mount. | 78 | Note: *FILE* must be located in *bpffs* mount. It must not |
79 | contain a dot character ('.'), which is reserved for future | ||
80 | extensions of *bpffs*. | ||
76 | 81 | ||
77 | **bpftool prog load** *OBJ* *FILE* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*] | 82 | **bpftool prog load** *OBJ* *FILE* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*] |
78 | Load bpf program from binary *OBJ* and pin as *FILE*. | 83 | Load bpf program from binary *OBJ* and pin as *FILE*. |
@@ -88,7 +93,17 @@ DESCRIPTION | |||
88 | If **dev** *NAME* is specified program will be loaded onto | 93 | If **dev** *NAME* is specified program will be loaded onto |
89 | given networking device (offload). | 94 | given networking device (offload). |
90 | 95 | ||
91 | Note: *FILE* must be located in *bpffs* mount. | 96 | Note: *FILE* must be located in *bpffs* mount. It must not |
97 | contain a dot character ('.'), which is reserved for future | ||
98 | extensions of *bpffs*. | ||
99 | |||
100 | **bpftool prog attach** *PROG* *ATTACH_TYPE* *MAP* | ||
101 | Attach bpf program *PROG* (with type specified by *ATTACH_TYPE*) | ||
102 | to the map *MAP*. | ||
103 | |||
104 | **bpftool prog detach** *PROG* *ATTACH_TYPE* *MAP* | ||
105 | Detach bpf program *PROG* (with type specified by *ATTACH_TYPE*) | ||
106 | from the map *MAP*. | ||
92 | 107 | ||
93 | **bpftool prog help** | 108 | **bpftool prog help** |
94 | Print short help message. | 109 | Print short help message. |
diff --git a/tools/bpf/bpftool/Documentation/bpftool.rst b/tools/bpf/bpftool/Documentation/bpftool.rst index b6f5d560460d..04cd4f92ab89 100644 --- a/tools/bpf/bpftool/Documentation/bpftool.rst +++ b/tools/bpf/bpftool/Documentation/bpftool.rst | |||
@@ -16,22 +16,24 @@ SYNOPSIS | |||
16 | 16 | ||
17 | **bpftool** **version** | 17 | **bpftool** **version** |
18 | 18 | ||
19 | *OBJECT* := { **map** | **program** | **cgroup** | **perf** } | 19 | *OBJECT* := { **map** | **program** | **cgroup** | **perf** | **net** } |
20 | 20 | ||
21 | *OPTIONS* := { { **-V** | **--version** } | { **-h** | **--help** } | 21 | *OPTIONS* := { { **-V** | **--version** } | { **-h** | **--help** } |
22 | | { **-j** | **--json** } [{ **-p** | **--pretty** }] } | 22 | | { **-j** | **--json** } [{ **-p** | **--pretty** }] } |
23 | 23 | ||
24 | *MAP-COMMANDS* := | 24 | *MAP-COMMANDS* := |
25 | { **show** | **list** | **dump** | **update** | **lookup** | **getnext** | **delete** | 25 | { **show** | **list** | **create** | **dump** | **update** | **lookup** | **getnext** |
26 | | **pin** | **event_pipe** | **help** } | 26 | | **delete** | **pin** | **event_pipe** | **help** } |
27 | 27 | ||
28 | *PROG-COMMANDS* := { **show** | **list** | **dump jited** | **dump xlated** | **pin** | 28 | *PROG-COMMANDS* := { **show** | **list** | **dump jited** | **dump xlated** | **pin** |
29 | | **load** | **help** } | 29 | | **load** | **attach** | **detach** | **help** } |
30 | 30 | ||
31 | *CGROUP-COMMANDS* := { **show** | **list** | **attach** | **detach** | **help** } | 31 | *CGROUP-COMMANDS* := { **show** | **list** | **attach** | **detach** | **help** } |
32 | 32 | ||
33 | *PERF-COMMANDS* := { **show** | **list** | **help** } | 33 | *PERF-COMMANDS* := { **show** | **list** | **help** } |
34 | 34 | ||
35 | *NET-COMMANDS* := { **show** | **list** | **help** } | ||
36 | |||
35 | DESCRIPTION | 37 | DESCRIPTION |
36 | =========== | 38 | =========== |
37 | *bpftool* allows for inspection and simple modification of BPF objects | 39 | *bpftool* allows for inspection and simple modification of BPF objects |
@@ -55,7 +57,11 @@ OPTIONS | |||
55 | -p, --pretty | 57 | -p, --pretty |
56 | Generate human-readable JSON output. Implies **-j**. | 58 | Generate human-readable JSON output. Implies **-j**. |
57 | 59 | ||
60 | -m, --mapcompat | ||
61 | Allow loading maps with unknown map definitions. | ||
62 | |||
63 | |||
58 | SEE ALSO | 64 | SEE ALSO |
59 | ======== | 65 | ======== |
60 | **bpftool-map**\ (8), **bpftool-prog**\ (8), **bpftool-cgroup**\ (8) | 66 | **bpftool-map**\ (8), **bpftool-prog**\ (8), **bpftool-cgroup**\ (8) |
61 | **bpftool-perf**\ (8) | 67 | **bpftool-perf**\ (8), **bpftool-net**\ (8) |
diff --git a/tools/bpf/bpftool/Makefile b/tools/bpf/bpftool/Makefile index 74288a2197ab..dac7eff4c7e5 100644 --- a/tools/bpf/bpftool/Makefile +++ b/tools/bpf/bpftool/Makefile | |||
@@ -46,6 +46,13 @@ CFLAGS += -DPACKAGE='"bpftool"' -D__EXPORTED_HEADERS__ \ | |||
46 | -I$(srctree)/tools/lib/bpf \ | 46 | -I$(srctree)/tools/lib/bpf \ |
47 | -I$(srctree)/tools/perf | 47 | -I$(srctree)/tools/perf |
48 | CFLAGS += -DBPFTOOL_VERSION='"$(BPFTOOL_VERSION)"' | 48 | CFLAGS += -DBPFTOOL_VERSION='"$(BPFTOOL_VERSION)"' |
49 | ifneq ($(EXTRA_CFLAGS),) | ||
50 | CFLAGS += $(EXTRA_CFLAGS) | ||
51 | endif | ||
52 | ifneq ($(EXTRA_LDFLAGS),) | ||
53 | LDFLAGS += $(EXTRA_LDFLAGS) | ||
54 | endif | ||
55 | |||
49 | LIBS = -lelf -lbfd -lopcodes $(LIBBPF) | 56 | LIBS = -lelf -lbfd -lopcodes $(LIBBPF) |
50 | 57 | ||
51 | INSTALL ?= install | 58 | INSTALL ?= install |
@@ -90,7 +97,7 @@ $(OUTPUT)disasm.o: $(srctree)/kernel/bpf/disasm.c | |||
90 | $(QUIET_CC)$(COMPILE.c) -MMD -o $@ $< | 97 | $(QUIET_CC)$(COMPILE.c) -MMD -o $@ $< |
91 | 98 | ||
92 | $(OUTPUT)bpftool: $(OBJS) $(LIBBPF) | 99 | $(OUTPUT)bpftool: $(OBJS) $(LIBBPF) |
93 | $(QUIET_LINK)$(CC) $(CFLAGS) -o $@ $^ $(LIBS) | 100 | $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) |
94 | 101 | ||
95 | $(OUTPUT)%.o: %.c | 102 | $(OUTPUT)%.o: %.c |
96 | $(QUIET_CC)$(COMPILE.c) -MMD -o $@ $< | 103 | $(QUIET_CC)$(COMPILE.c) -MMD -o $@ $< |
diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool index 598066c40191..3f78e6404589 100644 --- a/tools/bpf/bpftool/bash-completion/bpftool +++ b/tools/bpf/bpftool/bash-completion/bpftool | |||
@@ -143,7 +143,7 @@ _bpftool_map_update_map_type() | |||
143 | local type | 143 | local type |
144 | type=$(bpftool -jp map show $keyword $ref | \ | 144 | type=$(bpftool -jp map show $keyword $ref | \ |
145 | command sed -n 's/.*"type": "\(.*\)",$/\1/p') | 145 | command sed -n 's/.*"type": "\(.*\)",$/\1/p') |
146 | printf $type | 146 | [[ -n $type ]] && printf $type |
147 | } | 147 | } |
148 | 148 | ||
149 | _bpftool_map_update_get_id() | 149 | _bpftool_map_update_get_id() |
@@ -184,7 +184,7 @@ _bpftool() | |||
184 | 184 | ||
185 | # Deal with options | 185 | # Deal with options |
186 | if [[ ${words[cword]} == -* ]]; then | 186 | if [[ ${words[cword]} == -* ]]; then |
187 | local c='--version --json --pretty --bpffs' | 187 | local c='--version --json --pretty --bpffs --mapcompat' |
188 | COMPREPLY=( $( compgen -W "$c" -- "$cur" ) ) | 188 | COMPREPLY=( $( compgen -W "$c" -- "$cur" ) ) |
189 | return 0 | 189 | return 0 |
190 | fi | 190 | fi |
@@ -292,6 +292,23 @@ _bpftool() | |||
292 | fi | 292 | fi |
293 | return 0 | 293 | return 0 |
294 | ;; | 294 | ;; |
295 | attach|detach) | ||
296 | if [[ ${#words[@]} == 7 ]]; then | ||
297 | COMPREPLY=( $( compgen -W "id pinned" -- "$cur" ) ) | ||
298 | return 0 | ||
299 | fi | ||
300 | |||
301 | if [[ ${#words[@]} == 6 ]]; then | ||
302 | COMPREPLY=( $( compgen -W "msg_verdict skb_verdict skb_parse" -- "$cur" ) ) | ||
303 | return 0 | ||
304 | fi | ||
305 | |||
306 | if [[ $prev == "$command" ]]; then | ||
307 | COMPREPLY=( $( compgen -W "id pinned" -- "$cur" ) ) | ||
308 | return 0 | ||
309 | fi | ||
310 | return 0 | ||
311 | ;; | ||
295 | load) | 312 | load) |
296 | local obj | 313 | local obj |
297 | 314 | ||
@@ -347,7 +364,7 @@ _bpftool() | |||
347 | ;; | 364 | ;; |
348 | *) | 365 | *) |
349 | [[ $prev == $object ]] && \ | 366 | [[ $prev == $object ]] && \ |
350 | COMPREPLY=( $( compgen -W 'dump help pin load \ | 367 | COMPREPLY=( $( compgen -W 'dump help pin attach detach load \ |
351 | show list' -- "$cur" ) ) | 368 | show list' -- "$cur" ) ) |
352 | ;; | 369 | ;; |
353 | esac | 370 | esac |
@@ -370,6 +387,42 @@ _bpftool() | |||
370 | ;; | 387 | ;; |
371 | esac | 388 | esac |
372 | ;; | 389 | ;; |
390 | create) | ||
391 | case $prev in | ||
392 | $command) | ||
393 | _filedir | ||
394 | return 0 | ||
395 | ;; | ||
396 | type) | ||
397 | COMPREPLY=( $( compgen -W 'hash array prog_array \ | ||
398 | perf_event_array percpu_hash percpu_array \ | ||
399 | stack_trace cgroup_array lru_hash \ | ||
400 | lru_percpu_hash lpm_trie array_of_maps \ | ||
401 | hash_of_maps devmap sockmap cpumap xskmap \ | ||
402 | sockhash cgroup_storage reuseport_sockarray \ | ||
403 | percpu_cgroup_storage' -- \ | ||
404 | "$cur" ) ) | ||
405 | return 0 | ||
406 | ;; | ||
407 | key|value|flags|name|entries) | ||
408 | return 0 | ||
409 | ;; | ||
410 | dev) | ||
411 | _sysfs_get_netdevs | ||
412 | return 0 | ||
413 | ;; | ||
414 | *) | ||
415 | _bpftool_once_attr 'type' | ||
416 | _bpftool_once_attr 'key' | ||
417 | _bpftool_once_attr 'value' | ||
418 | _bpftool_once_attr 'entries' | ||
419 | _bpftool_once_attr 'name' | ||
420 | _bpftool_once_attr 'flags' | ||
421 | _bpftool_once_attr 'dev' | ||
422 | return 0 | ||
423 | ;; | ||
424 | esac | ||
425 | ;; | ||
373 | lookup|getnext|delete) | 426 | lookup|getnext|delete) |
374 | case $prev in | 427 | case $prev in |
375 | $command) | 428 | $command) |
@@ -483,7 +536,7 @@ _bpftool() | |||
483 | *) | 536 | *) |
484 | [[ $prev == $object ]] && \ | 537 | [[ $prev == $object ]] && \ |
485 | COMPREPLY=( $( compgen -W 'delete dump getnext help \ | 538 | COMPREPLY=( $( compgen -W 'delete dump getnext help \ |
486 | lookup pin event_pipe show list update' -- \ | 539 | lookup pin event_pipe show list update create' -- \ |
487 | "$cur" ) ) | 540 | "$cur" ) ) |
488 | ;; | 541 | ;; |
489 | esac | 542 | esac |
@@ -494,10 +547,10 @@ _bpftool() | |||
494 | _filedir | 547 | _filedir |
495 | return 0 | 548 | return 0 |
496 | ;; | 549 | ;; |
497 | tree) | 550 | tree) |
498 | _filedir | 551 | _filedir |
499 | return 0 | 552 | return 0 |
500 | ;; | 553 | ;; |
501 | attach|detach) | 554 | attach|detach) |
502 | local ATTACH_TYPES='ingress egress sock_create sock_ops \ | 555 | local ATTACH_TYPES='ingress egress sock_create sock_ops \ |
503 | device bind4 bind6 post_bind4 post_bind6 connect4 \ | 556 | device bind4 bind6 post_bind4 post_bind6 connect4 \ |
@@ -552,6 +605,15 @@ _bpftool() | |||
552 | ;; | 605 | ;; |
553 | esac | 606 | esac |
554 | ;; | 607 | ;; |
608 | net) | ||
609 | case $command in | ||
610 | *) | ||
611 | [[ $prev == $object ]] && \ | ||
612 | COMPREPLY=( $( compgen -W 'help \ | ||
613 | show list' -- "$cur" ) ) | ||
614 | ;; | ||
615 | esac | ||
616 | ;; | ||
555 | esac | 617 | esac |
556 | } && | 618 | } && |
557 | complete -F _bpftool bpftool | 619 | complete -F _bpftool bpftool |
diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c index b3a0709ea7ed..25af85304ebe 100644 --- a/tools/bpf/bpftool/common.c +++ b/tools/bpf/bpftool/common.c | |||
@@ -554,7 +554,9 @@ static int read_sysfs_netdev_hex_int(char *devname, const char *entry_name) | |||
554 | return read_sysfs_hex_int(full_path); | 554 | return read_sysfs_hex_int(full_path); |
555 | } | 555 | } |
556 | 556 | ||
557 | const char *ifindex_to_bfd_name_ns(__u32 ifindex, __u64 ns_dev, __u64 ns_ino) | 557 | const char * |
558 | ifindex_to_bfd_params(__u32 ifindex, __u64 ns_dev, __u64 ns_ino, | ||
559 | const char **opt) | ||
558 | { | 560 | { |
559 | char devname[IF_NAMESIZE]; | 561 | char devname[IF_NAMESIZE]; |
560 | int vendor_id; | 562 | int vendor_id; |
@@ -579,6 +581,7 @@ const char *ifindex_to_bfd_name_ns(__u32 ifindex, __u64 ns_dev, __u64 ns_ino) | |||
579 | device_id != 0x6000 && | 581 | device_id != 0x6000 && |
580 | device_id != 0x6003) | 582 | device_id != 0x6003) |
581 | p_info("Unknown NFP device ID, assuming it is NFP-6xxx arch"); | 583 | p_info("Unknown NFP device ID, assuming it is NFP-6xxx arch"); |
584 | *opt = "ctx4"; | ||
582 | return "NFP-6xxx"; | 585 | return "NFP-6xxx"; |
583 | default: | 586 | default: |
584 | p_err("Can't get bfd arch name for device vendor id 0x%04x", | 587 | p_err("Can't get bfd arch name for device vendor id 0x%04x", |
@@ -618,3 +621,24 @@ void print_dev_json(__u32 ifindex, __u64 ns_dev, __u64 ns_inode) | |||
618 | jsonw_string_field(json_wtr, "ifname", name); | 621 | jsonw_string_field(json_wtr, "ifname", name); |
619 | jsonw_end_object(json_wtr); | 622 | jsonw_end_object(json_wtr); |
620 | } | 623 | } |
624 | |||
625 | int parse_u32_arg(int *argc, char ***argv, __u32 *val, const char *what) | ||
626 | { | ||
627 | char *endptr; | ||
628 | |||
629 | NEXT_ARGP(); | ||
630 | |||
631 | if (*val) { | ||
632 | p_err("%s already specified", what); | ||
633 | return -1; | ||
634 | } | ||
635 | |||
636 | *val = strtoul(**argv, &endptr, 0); | ||
637 | if (*endptr) { | ||
638 | p_err("can't parse %s as %s", **argv, what); | ||
639 | return -1; | ||
640 | } | ||
641 | NEXT_ARGP(); | ||
642 | |||
643 | return 0; | ||
644 | } | ||
diff --git a/tools/bpf/bpftool/jit_disasm.c b/tools/bpf/bpftool/jit_disasm.c index 87439320ef70..c75ffd9ce2bb 100644 --- a/tools/bpf/bpftool/jit_disasm.c +++ b/tools/bpf/bpftool/jit_disasm.c | |||
@@ -77,7 +77,7 @@ static int fprintf_json(void *out, const char *fmt, ...) | |||
77 | } | 77 | } |
78 | 78 | ||
79 | void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, | 79 | void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, |
80 | const char *arch) | 80 | const char *arch, const char *disassembler_options) |
81 | { | 81 | { |
82 | disassembler_ftype disassemble; | 82 | disassembler_ftype disassemble; |
83 | struct disassemble_info info; | 83 | struct disassemble_info info; |
@@ -116,6 +116,8 @@ void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, | |||
116 | 116 | ||
117 | info.arch = bfd_get_arch(bfdf); | 117 | info.arch = bfd_get_arch(bfdf); |
118 | info.mach = bfd_get_mach(bfdf); | 118 | info.mach = bfd_get_mach(bfdf); |
119 | if (disassembler_options) | ||
120 | info.disassembler_options = disassembler_options; | ||
119 | info.buffer = image; | 121 | info.buffer = image; |
120 | info.buffer_length = len; | 122 | info.buffer_length = len; |
121 | 123 | ||
diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c index d15a62be6cf0..75a3296dc0bc 100644 --- a/tools/bpf/bpftool/main.c +++ b/tools/bpf/bpftool/main.c | |||
@@ -55,6 +55,7 @@ json_writer_t *json_wtr; | |||
55 | bool pretty_output; | 55 | bool pretty_output; |
56 | bool json_output; | 56 | bool json_output; |
57 | bool show_pinned; | 57 | bool show_pinned; |
58 | int bpf_flags; | ||
58 | struct pinned_obj_table prog_table; | 59 | struct pinned_obj_table prog_table; |
59 | struct pinned_obj_table map_table; | 60 | struct pinned_obj_table map_table; |
60 | 61 | ||
@@ -85,7 +86,7 @@ static int do_help(int argc, char **argv) | |||
85 | " %s batch file FILE\n" | 86 | " %s batch file FILE\n" |
86 | " %s version\n" | 87 | " %s version\n" |
87 | "\n" | 88 | "\n" |
88 | " OBJECT := { prog | map | cgroup | perf }\n" | 89 | " OBJECT := { prog | map | cgroup | perf | net }\n" |
89 | " " HELP_SPEC_OPTIONS "\n" | 90 | " " HELP_SPEC_OPTIONS "\n" |
90 | "", | 91 | "", |
91 | bin_name, bin_name, bin_name); | 92 | bin_name, bin_name, bin_name); |
@@ -215,6 +216,7 @@ static const struct cmd cmds[] = { | |||
215 | { "map", do_map }, | 216 | { "map", do_map }, |
216 | { "cgroup", do_cgroup }, | 217 | { "cgroup", do_cgroup }, |
217 | { "perf", do_perf }, | 218 | { "perf", do_perf }, |
219 | { "net", do_net }, | ||
218 | { "version", do_version }, | 220 | { "version", do_version }, |
219 | { 0 } | 221 | { 0 } |
220 | }; | 222 | }; |
@@ -319,7 +321,8 @@ static int do_batch(int argc, char **argv) | |||
319 | p_err("reading batch file failed: %s", strerror(errno)); | 321 | p_err("reading batch file failed: %s", strerror(errno)); |
320 | err = -1; | 322 | err = -1; |
321 | } else { | 323 | } else { |
322 | p_info("processed %d commands", lines); | 324 | if (!json_output) |
325 | printf("processed %d commands\n", lines); | ||
323 | err = 0; | 326 | err = 0; |
324 | } | 327 | } |
325 | err_close: | 328 | err_close: |
@@ -340,6 +343,7 @@ int main(int argc, char **argv) | |||
340 | { "pretty", no_argument, NULL, 'p' }, | 343 | { "pretty", no_argument, NULL, 'p' }, |
341 | { "version", no_argument, NULL, 'V' }, | 344 | { "version", no_argument, NULL, 'V' }, |
342 | { "bpffs", no_argument, NULL, 'f' }, | 345 | { "bpffs", no_argument, NULL, 'f' }, |
346 | { "mapcompat", no_argument, NULL, 'm' }, | ||
343 | { 0 } | 347 | { 0 } |
344 | }; | 348 | }; |
345 | int opt, ret; | 349 | int opt, ret; |
@@ -354,7 +358,7 @@ int main(int argc, char **argv) | |||
354 | hash_init(map_table.table); | 358 | hash_init(map_table.table); |
355 | 359 | ||
356 | opterr = 0; | 360 | opterr = 0; |
357 | while ((opt = getopt_long(argc, argv, "Vhpjf", | 361 | while ((opt = getopt_long(argc, argv, "Vhpjfm", |
358 | options, NULL)) >= 0) { | 362 | options, NULL)) >= 0) { |
359 | switch (opt) { | 363 | switch (opt) { |
360 | case 'V': | 364 | case 'V': |
@@ -378,6 +382,9 @@ int main(int argc, char **argv) | |||
378 | case 'f': | 382 | case 'f': |
379 | show_pinned = true; | 383 | show_pinned = true; |
380 | break; | 384 | break; |
385 | case 'm': | ||
386 | bpf_flags = MAPS_RELAX_COMPAT; | ||
387 | break; | ||
381 | default: | 388 | default: |
382 | p_err("unrecognized option '%s'", argv[optind - 1]); | 389 | p_err("unrecognized option '%s'", argv[optind - 1]); |
383 | if (json_output) | 390 | if (json_output) |
diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h index 238e734d75b3..28322ace2856 100644 --- a/tools/bpf/bpftool/main.h +++ b/tools/bpf/bpftool/main.h | |||
@@ -74,7 +74,7 @@ | |||
74 | #define HELP_SPEC_PROGRAM \ | 74 | #define HELP_SPEC_PROGRAM \ |
75 | "PROG := { id PROG_ID | pinned FILE | tag PROG_TAG }" | 75 | "PROG := { id PROG_ID | pinned FILE | tag PROG_TAG }" |
76 | #define HELP_SPEC_OPTIONS \ | 76 | #define HELP_SPEC_OPTIONS \ |
77 | "OPTIONS := { {-j|--json} [{-p|--pretty}] | {-f|--bpffs} }" | 77 | "OPTIONS := { {-j|--json} [{-p|--pretty}] | {-f|--bpffs} | {-m|--mapcompat}" |
78 | #define HELP_SPEC_MAP \ | 78 | #define HELP_SPEC_MAP \ |
79 | "MAP := { id MAP_ID | pinned FILE }" | 79 | "MAP := { id MAP_ID | pinned FILE }" |
80 | 80 | ||
@@ -89,6 +89,7 @@ extern const char *bin_name; | |||
89 | extern json_writer_t *json_wtr; | 89 | extern json_writer_t *json_wtr; |
90 | extern bool json_output; | 90 | extern bool json_output; |
91 | extern bool show_pinned; | 91 | extern bool show_pinned; |
92 | extern int bpf_flags; | ||
92 | extern struct pinned_obj_table prog_table; | 93 | extern struct pinned_obj_table prog_table; |
93 | extern struct pinned_obj_table map_table; | 94 | extern struct pinned_obj_table map_table; |
94 | 95 | ||
@@ -136,19 +137,23 @@ int do_map(int argc, char **arg); | |||
136 | int do_event_pipe(int argc, char **argv); | 137 | int do_event_pipe(int argc, char **argv); |
137 | int do_cgroup(int argc, char **arg); | 138 | int do_cgroup(int argc, char **arg); |
138 | int do_perf(int argc, char **arg); | 139 | int do_perf(int argc, char **arg); |
140 | int do_net(int argc, char **arg); | ||
139 | 141 | ||
142 | int parse_u32_arg(int *argc, char ***argv, __u32 *val, const char *what); | ||
140 | int prog_parse_fd(int *argc, char ***argv); | 143 | int prog_parse_fd(int *argc, char ***argv); |
141 | int map_parse_fd(int *argc, char ***argv); | 144 | int map_parse_fd(int *argc, char ***argv); |
142 | int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len); | 145 | int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len); |
143 | 146 | ||
144 | void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, | 147 | void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, |
145 | const char *arch); | 148 | const char *arch, const char *disassembler_options); |
146 | void print_data_json(uint8_t *data, size_t len); | 149 | void print_data_json(uint8_t *data, size_t len); |
147 | void print_hex_data_json(uint8_t *data, size_t len); | 150 | void print_hex_data_json(uint8_t *data, size_t len); |
148 | 151 | ||
149 | unsigned int get_page_size(void); | 152 | unsigned int get_page_size(void); |
150 | unsigned int get_possible_cpus(void); | 153 | unsigned int get_possible_cpus(void); |
151 | const char *ifindex_to_bfd_name_ns(__u32 ifindex, __u64 ns_dev, __u64 ns_ino); | 154 | const char * |
155 | ifindex_to_bfd_params(__u32 ifindex, __u64 ns_dev, __u64 ns_ino, | ||
156 | const char **opt); | ||
152 | 157 | ||
153 | struct btf_dumper { | 158 | struct btf_dumper { |
154 | const struct btf *btf; | 159 | const struct btf *btf; |
@@ -165,4 +170,11 @@ struct btf_dumper { | |||
165 | */ | 170 | */ |
166 | int btf_dumper_type(const struct btf_dumper *d, __u32 type_id, | 171 | int btf_dumper_type(const struct btf_dumper *d, __u32 type_id, |
167 | const void *data); | 172 | const void *data); |
173 | |||
174 | struct nlattr; | ||
175 | struct ifinfomsg; | ||
176 | struct tcmsg; | ||
177 | int do_xdp_dump(struct ifinfomsg *ifinfo, struct nlattr **tb); | ||
178 | int do_filter_dump(struct tcmsg *ifinfo, struct nlattr **tb, const char *kind, | ||
179 | const char *devname, int ifindex); | ||
168 | #endif | 180 | #endif |
diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c index b455930a3eaf..7bf38f0e152e 100644 --- a/tools/bpf/bpftool/map.c +++ b/tools/bpf/bpftool/map.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <fcntl.h> | 36 | #include <fcntl.h> |
37 | #include <linux/err.h> | 37 | #include <linux/err.h> |
38 | #include <linux/kernel.h> | 38 | #include <linux/kernel.h> |
39 | #include <net/if.h> | ||
39 | #include <stdbool.h> | 40 | #include <stdbool.h> |
40 | #include <stdio.h> | 41 | #include <stdio.h> |
41 | #include <stdlib.h> | 42 | #include <stdlib.h> |
@@ -71,13 +72,16 @@ static const char * const map_type_name[] = { | |||
71 | [BPF_MAP_TYPE_XSKMAP] = "xskmap", | 72 | [BPF_MAP_TYPE_XSKMAP] = "xskmap", |
72 | [BPF_MAP_TYPE_SOCKHASH] = "sockhash", | 73 | [BPF_MAP_TYPE_SOCKHASH] = "sockhash", |
73 | [BPF_MAP_TYPE_CGROUP_STORAGE] = "cgroup_storage", | 74 | [BPF_MAP_TYPE_CGROUP_STORAGE] = "cgroup_storage", |
75 | [BPF_MAP_TYPE_REUSEPORT_SOCKARRAY] = "reuseport_sockarray", | ||
76 | [BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE] = "percpu_cgroup_storage", | ||
74 | }; | 77 | }; |
75 | 78 | ||
76 | static bool map_is_per_cpu(__u32 type) | 79 | static bool map_is_per_cpu(__u32 type) |
77 | { | 80 | { |
78 | return type == BPF_MAP_TYPE_PERCPU_HASH || | 81 | return type == BPF_MAP_TYPE_PERCPU_HASH || |
79 | type == BPF_MAP_TYPE_PERCPU_ARRAY || | 82 | type == BPF_MAP_TYPE_PERCPU_ARRAY || |
80 | type == BPF_MAP_TYPE_LRU_PERCPU_HASH; | 83 | type == BPF_MAP_TYPE_LRU_PERCPU_HASH || |
84 | type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE; | ||
81 | } | 85 | } |
82 | 86 | ||
83 | static bool map_is_map_of_maps(__u32 type) | 87 | static bool map_is_map_of_maps(__u32 type) |
@@ -91,6 +95,17 @@ static bool map_is_map_of_progs(__u32 type) | |||
91 | return type == BPF_MAP_TYPE_PROG_ARRAY; | 95 | return type == BPF_MAP_TYPE_PROG_ARRAY; |
92 | } | 96 | } |
93 | 97 | ||
98 | static int map_type_from_str(const char *type) | ||
99 | { | ||
100 | unsigned int i; | ||
101 | |||
102 | for (i = 0; i < ARRAY_SIZE(map_type_name); i++) | ||
103 | /* Don't allow prefixing in case of possible future shadowing */ | ||
104 | if (map_type_name[i] && !strcmp(map_type_name[i], type)) | ||
105 | return i; | ||
106 | return -1; | ||
107 | } | ||
108 | |||
94 | static void *alloc_value(struct bpf_map_info *info) | 109 | static void *alloc_value(struct bpf_map_info *info) |
95 | { | 110 | { |
96 | if (map_is_per_cpu(info->type)) | 111 | if (map_is_per_cpu(info->type)) |
@@ -170,9 +185,28 @@ static int do_dump_btf(const struct btf_dumper *d, | |||
170 | if (ret) | 185 | if (ret) |
171 | goto err_end_obj; | 186 | goto err_end_obj; |
172 | 187 | ||
173 | jsonw_name(d->jw, "value"); | 188 | if (!map_is_per_cpu(map_info->type)) { |
189 | jsonw_name(d->jw, "value"); | ||
190 | ret = btf_dumper_type(d, map_info->btf_value_type_id, value); | ||
191 | } else { | ||
192 | unsigned int i, n, step; | ||
174 | 193 | ||
175 | ret = btf_dumper_type(d, map_info->btf_value_type_id, value); | 194 | jsonw_name(d->jw, "values"); |
195 | jsonw_start_array(d->jw); | ||
196 | n = get_possible_cpus(); | ||
197 | step = round_up(map_info->value_size, 8); | ||
198 | for (i = 0; i < n; i++) { | ||
199 | jsonw_start_object(d->jw); | ||
200 | jsonw_int_field(d->jw, "cpu", i); | ||
201 | jsonw_name(d->jw, "value"); | ||
202 | ret = btf_dumper_type(d, map_info->btf_value_type_id, | ||
203 | value + i * step); | ||
204 | jsonw_end_object(d->jw); | ||
205 | if (ret) | ||
206 | break; | ||
207 | } | ||
208 | jsonw_end_array(d->jw); | ||
209 | } | ||
176 | 210 | ||
177 | err_end_obj: | 211 | err_end_obj: |
178 | /* end of key-value pair */ | 212 | /* end of key-value pair */ |
@@ -299,11 +333,40 @@ static void print_entry_json(struct bpf_map_info *info, unsigned char *key, | |||
299 | jsonw_end_object(json_wtr); | 333 | jsonw_end_object(json_wtr); |
300 | } | 334 | } |
301 | jsonw_end_array(json_wtr); | 335 | jsonw_end_array(json_wtr); |
336 | if (btf) { | ||
337 | struct btf_dumper d = { | ||
338 | .btf = btf, | ||
339 | .jw = json_wtr, | ||
340 | .is_plain_text = false, | ||
341 | }; | ||
342 | |||
343 | jsonw_name(json_wtr, "formatted"); | ||
344 | do_dump_btf(&d, info, key, value); | ||
345 | } | ||
302 | } | 346 | } |
303 | 347 | ||
304 | jsonw_end_object(json_wtr); | 348 | jsonw_end_object(json_wtr); |
305 | } | 349 | } |
306 | 350 | ||
351 | static void print_entry_error(struct bpf_map_info *info, unsigned char *key, | ||
352 | const char *value) | ||
353 | { | ||
354 | int value_size = strlen(value); | ||
355 | bool single_line, break_names; | ||
356 | |||
357 | break_names = info->key_size > 16 || value_size > 16; | ||
358 | single_line = info->key_size + value_size <= 24 && !break_names; | ||
359 | |||
360 | printf("key:%c", break_names ? '\n' : ' '); | ||
361 | fprint_hex(stdout, key, info->key_size, " "); | ||
362 | |||
363 | printf(single_line ? " " : "\n"); | ||
364 | |||
365 | printf("value:%c%s", break_names ? '\n' : ' ', value); | ||
366 | |||
367 | printf("\n"); | ||
368 | } | ||
369 | |||
307 | static void print_entry_plain(struct bpf_map_info *info, unsigned char *key, | 370 | static void print_entry_plain(struct bpf_map_info *info, unsigned char *key, |
308 | unsigned char *value) | 371 | unsigned char *value) |
309 | { | 372 | { |
@@ -626,6 +689,54 @@ static int do_show(int argc, char **argv) | |||
626 | return errno == ENOENT ? 0 : -1; | 689 | return errno == ENOENT ? 0 : -1; |
627 | } | 690 | } |
628 | 691 | ||
692 | static int dump_map_elem(int fd, void *key, void *value, | ||
693 | struct bpf_map_info *map_info, struct btf *btf, | ||
694 | json_writer_t *btf_wtr) | ||
695 | { | ||
696 | int num_elems = 0; | ||
697 | int lookup_errno; | ||
698 | |||
699 | if (!bpf_map_lookup_elem(fd, key, value)) { | ||
700 | if (json_output) { | ||
701 | print_entry_json(map_info, key, value, btf); | ||
702 | } else { | ||
703 | if (btf) { | ||
704 | struct btf_dumper d = { | ||
705 | .btf = btf, | ||
706 | .jw = btf_wtr, | ||
707 | .is_plain_text = true, | ||
708 | }; | ||
709 | |||
710 | do_dump_btf(&d, map_info, key, value); | ||
711 | } else { | ||
712 | print_entry_plain(map_info, key, value); | ||
713 | } | ||
714 | num_elems++; | ||
715 | } | ||
716 | return num_elems; | ||
717 | } | ||
718 | |||
719 | /* lookup error handling */ | ||
720 | lookup_errno = errno; | ||
721 | |||
722 | if (map_is_map_of_maps(map_info->type) || | ||
723 | map_is_map_of_progs(map_info->type)) | ||
724 | return 0; | ||
725 | |||
726 | if (json_output) { | ||
727 | jsonw_name(json_wtr, "key"); | ||
728 | print_hex_data_json(key, map_info->key_size); | ||
729 | jsonw_name(json_wtr, "value"); | ||
730 | jsonw_start_object(json_wtr); | ||
731 | jsonw_string_field(json_wtr, "error", strerror(lookup_errno)); | ||
732 | jsonw_end_object(json_wtr); | ||
733 | } else { | ||
734 | print_entry_error(map_info, key, strerror(lookup_errno)); | ||
735 | } | ||
736 | |||
737 | return 0; | ||
738 | } | ||
739 | |||
629 | static int do_dump(int argc, char **argv) | 740 | static int do_dump(int argc, char **argv) |
630 | { | 741 | { |
631 | struct bpf_map_info info = {}; | 742 | struct bpf_map_info info = {}; |
@@ -644,12 +755,6 @@ static int do_dump(int argc, char **argv) | |||
644 | if (fd < 0) | 755 | if (fd < 0) |
645 | return -1; | 756 | return -1; |
646 | 757 | ||
647 | if (map_is_map_of_maps(info.type) || map_is_map_of_progs(info.type)) { | ||
648 | p_err("Dumping maps of maps and program maps not supported"); | ||
649 | close(fd); | ||
650 | return -1; | ||
651 | } | ||
652 | |||
653 | key = malloc(info.key_size); | 758 | key = malloc(info.key_size); |
654 | value = alloc_value(&info); | 759 | value = alloc_value(&info); |
655 | if (!key || !value) { | 760 | if (!key || !value) { |
@@ -687,40 +792,8 @@ static int do_dump(int argc, char **argv) | |||
687 | err = 0; | 792 | err = 0; |
688 | break; | 793 | break; |
689 | } | 794 | } |
690 | 795 | num_elems += dump_map_elem(fd, key, value, &info, btf, btf_wtr); | |
691 | if (!bpf_map_lookup_elem(fd, key, value)) { | ||
692 | if (json_output) | ||
693 | print_entry_json(&info, key, value, btf); | ||
694 | else | ||
695 | if (btf) { | ||
696 | struct btf_dumper d = { | ||
697 | .btf = btf, | ||
698 | .jw = btf_wtr, | ||
699 | .is_plain_text = true, | ||
700 | }; | ||
701 | |||
702 | do_dump_btf(&d, &info, key, value); | ||
703 | } else { | ||
704 | print_entry_plain(&info, key, value); | ||
705 | } | ||
706 | } else { | ||
707 | if (json_output) { | ||
708 | jsonw_name(json_wtr, "key"); | ||
709 | print_hex_data_json(key, info.key_size); | ||
710 | jsonw_name(json_wtr, "value"); | ||
711 | jsonw_start_object(json_wtr); | ||
712 | jsonw_string_field(json_wtr, "error", | ||
713 | "can't lookup element"); | ||
714 | jsonw_end_object(json_wtr); | ||
715 | } else { | ||
716 | p_info("can't lookup element with key: "); | ||
717 | fprint_hex(stderr, key, info.key_size, " "); | ||
718 | fprintf(stderr, "\n"); | ||
719 | } | ||
720 | } | ||
721 | |||
722 | prev_key = key; | 796 | prev_key = key; |
723 | num_elems++; | ||
724 | } | 797 | } |
725 | 798 | ||
726 | if (json_output) | 799 | if (json_output) |
@@ -997,6 +1070,92 @@ static int do_pin(int argc, char **argv) | |||
997 | return err; | 1070 | return err; |
998 | } | 1071 | } |
999 | 1072 | ||
1073 | static int do_create(int argc, char **argv) | ||
1074 | { | ||
1075 | struct bpf_create_map_attr attr = { NULL, }; | ||
1076 | const char *pinfile; | ||
1077 | int err, fd; | ||
1078 | |||
1079 | if (!REQ_ARGS(7)) | ||
1080 | return -1; | ||
1081 | pinfile = GET_ARG(); | ||
1082 | |||
1083 | while (argc) { | ||
1084 | if (!REQ_ARGS(2)) | ||
1085 | return -1; | ||
1086 | |||
1087 | if (is_prefix(*argv, "type")) { | ||
1088 | NEXT_ARG(); | ||
1089 | |||
1090 | if (attr.map_type) { | ||
1091 | p_err("map type already specified"); | ||
1092 | return -1; | ||
1093 | } | ||
1094 | |||
1095 | attr.map_type = map_type_from_str(*argv); | ||
1096 | if ((int)attr.map_type < 0) { | ||
1097 | p_err("unrecognized map type: %s", *argv); | ||
1098 | return -1; | ||
1099 | } | ||
1100 | NEXT_ARG(); | ||
1101 | } else if (is_prefix(*argv, "name")) { | ||
1102 | NEXT_ARG(); | ||
1103 | attr.name = GET_ARG(); | ||
1104 | } else if (is_prefix(*argv, "key")) { | ||
1105 | if (parse_u32_arg(&argc, &argv, &attr.key_size, | ||
1106 | "key size")) | ||
1107 | return -1; | ||
1108 | } else if (is_prefix(*argv, "value")) { | ||
1109 | if (parse_u32_arg(&argc, &argv, &attr.value_size, | ||
1110 | "value size")) | ||
1111 | return -1; | ||
1112 | } else if (is_prefix(*argv, "entries")) { | ||
1113 | if (parse_u32_arg(&argc, &argv, &attr.max_entries, | ||
1114 | "max entries")) | ||
1115 | return -1; | ||
1116 | } else if (is_prefix(*argv, "flags")) { | ||
1117 | if (parse_u32_arg(&argc, &argv, &attr.map_flags, | ||
1118 | "flags")) | ||
1119 | return -1; | ||
1120 | } else if (is_prefix(*argv, "dev")) { | ||
1121 | NEXT_ARG(); | ||
1122 | |||
1123 | if (attr.map_ifindex) { | ||
1124 | p_err("offload device already specified"); | ||
1125 | return -1; | ||
1126 | } | ||
1127 | |||
1128 | attr.map_ifindex = if_nametoindex(*argv); | ||
1129 | if (!attr.map_ifindex) { | ||
1130 | p_err("unrecognized netdevice '%s': %s", | ||
1131 | *argv, strerror(errno)); | ||
1132 | return -1; | ||
1133 | } | ||
1134 | NEXT_ARG(); | ||
1135 | } | ||
1136 | } | ||
1137 | |||
1138 | if (!attr.name) { | ||
1139 | p_err("map name not specified"); | ||
1140 | return -1; | ||
1141 | } | ||
1142 | |||
1143 | fd = bpf_create_map_xattr(&attr); | ||
1144 | if (fd < 0) { | ||
1145 | p_err("map create failed: %s", strerror(errno)); | ||
1146 | return -1; | ||
1147 | } | ||
1148 | |||
1149 | err = do_pin_fd(fd, pinfile); | ||
1150 | close(fd); | ||
1151 | if (err) | ||
1152 | return err; | ||
1153 | |||
1154 | if (json_output) | ||
1155 | jsonw_null(json_wtr); | ||
1156 | return 0; | ||
1157 | } | ||
1158 | |||
1000 | static int do_help(int argc, char **argv) | 1159 | static int do_help(int argc, char **argv) |
1001 | { | 1160 | { |
1002 | if (json_output) { | 1161 | if (json_output) { |
@@ -1006,6 +1165,9 @@ static int do_help(int argc, char **argv) | |||
1006 | 1165 | ||
1007 | fprintf(stderr, | 1166 | fprintf(stderr, |
1008 | "Usage: %s %s { show | list } [MAP]\n" | 1167 | "Usage: %s %s { show | list } [MAP]\n" |
1168 | " %s %s create FILE type TYPE key KEY_SIZE value VALUE_SIZE \\\n" | ||
1169 | " entries MAX_ENTRIES name NAME [flags FLAGS] \\\n" | ||
1170 | " [dev NAME]\n" | ||
1009 | " %s %s dump MAP\n" | 1171 | " %s %s dump MAP\n" |
1010 | " %s %s update MAP key DATA value VALUE [UPDATE_FLAGS]\n" | 1172 | " %s %s update MAP key DATA value VALUE [UPDATE_FLAGS]\n" |
1011 | " %s %s lookup MAP key DATA\n" | 1173 | " %s %s lookup MAP key DATA\n" |
@@ -1020,11 +1182,17 @@ static int do_help(int argc, char **argv) | |||
1020 | " " HELP_SPEC_PROGRAM "\n" | 1182 | " " HELP_SPEC_PROGRAM "\n" |
1021 | " VALUE := { DATA | MAP | PROG }\n" | 1183 | " VALUE := { DATA | MAP | PROG }\n" |
1022 | " UPDATE_FLAGS := { any | exist | noexist }\n" | 1184 | " UPDATE_FLAGS := { any | exist | noexist }\n" |
1185 | " TYPE := { hash | array | prog_array | perf_event_array | percpu_hash |\n" | ||
1186 | " percpu_array | stack_trace | cgroup_array | lru_hash |\n" | ||
1187 | " lru_percpu_hash | lpm_trie | array_of_maps | hash_of_maps |\n" | ||
1188 | " devmap | sockmap | cpumap | xskmap | sockhash |\n" | ||
1189 | " cgroup_storage | reuseport_sockarray | percpu_cgroup_storage }\n" | ||
1023 | " " HELP_SPEC_OPTIONS "\n" | 1190 | " " HELP_SPEC_OPTIONS "\n" |
1024 | "", | 1191 | "", |
1025 | bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], | 1192 | bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], |
1026 | bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], | 1193 | bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], |
1027 | bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]); | 1194 | bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], |
1195 | bin_name, argv[-2]); | ||
1028 | 1196 | ||
1029 | return 0; | 1197 | return 0; |
1030 | } | 1198 | } |
@@ -1040,6 +1208,7 @@ static const struct cmd cmds[] = { | |||
1040 | { "delete", do_delete }, | 1208 | { "delete", do_delete }, |
1041 | { "pin", do_pin }, | 1209 | { "pin", do_pin }, |
1042 | { "event_pipe", do_event_pipe }, | 1210 | { "event_pipe", do_event_pipe }, |
1211 | { "create", do_create }, | ||
1043 | { 0 } | 1212 | { 0 } |
1044 | }; | 1213 | }; |
1045 | 1214 | ||
diff --git a/tools/bpf/bpftool/map_perf_ring.c b/tools/bpf/bpftool/map_perf_ring.c index 6d41323be291..bdaf4062e26e 100644 --- a/tools/bpf/bpftool/map_perf_ring.c +++ b/tools/bpf/bpftool/map_perf_ring.c | |||
@@ -50,15 +50,17 @@ static void int_exit(int signo) | |||
50 | stop = true; | 50 | stop = true; |
51 | } | 51 | } |
52 | 52 | ||
53 | static enum bpf_perf_event_ret print_bpf_output(void *event, void *priv) | 53 | static enum bpf_perf_event_ret |
54 | print_bpf_output(struct perf_event_header *event, void *private_data) | ||
54 | { | 55 | { |
55 | struct event_ring_info *ring = priv; | 56 | struct perf_event_sample *e = container_of(event, struct perf_event_sample, |
56 | struct perf_event_sample *e = event; | 57 | header); |
58 | struct event_ring_info *ring = private_data; | ||
57 | struct { | 59 | struct { |
58 | struct perf_event_header header; | 60 | struct perf_event_header header; |
59 | __u64 id; | 61 | __u64 id; |
60 | __u64 lost; | 62 | __u64 lost; |
61 | } *lost = event; | 63 | } *lost = (typeof(lost))event; |
62 | 64 | ||
63 | if (json_output) { | 65 | if (json_output) { |
64 | jsonw_start_object(json_wtr); | 66 | jsonw_start_object(json_wtr); |
diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c new file mode 100644 index 000000000000..d441bb7035ca --- /dev/null +++ b/tools/bpf/bpftool/net.c | |||
@@ -0,0 +1,275 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0+ | ||
2 | // Copyright (C) 2018 Facebook | ||
3 | |||
4 | #define _GNU_SOURCE | ||
5 | #include <errno.h> | ||
6 | #include <stdlib.h> | ||
7 | #include <string.h> | ||
8 | #include <unistd.h> | ||
9 | #include <libbpf.h> | ||
10 | #include <net/if.h> | ||
11 | #include <linux/if.h> | ||
12 | #include <linux/rtnetlink.h> | ||
13 | #include <linux/tc_act/tc_bpf.h> | ||
14 | #include <sys/socket.h> | ||
15 | |||
16 | #include <bpf.h> | ||
17 | #include <nlattr.h> | ||
18 | #include "main.h" | ||
19 | #include "netlink_dumper.h" | ||
20 | |||
21 | struct ip_devname_ifindex { | ||
22 | char devname[64]; | ||
23 | int ifindex; | ||
24 | }; | ||
25 | |||
26 | struct bpf_netdev_t { | ||
27 | struct ip_devname_ifindex *devices; | ||
28 | int used_len; | ||
29 | int array_len; | ||
30 | int filter_idx; | ||
31 | }; | ||
32 | |||
33 | struct tc_kind_handle { | ||
34 | char kind[64]; | ||
35 | int handle; | ||
36 | }; | ||
37 | |||
38 | struct bpf_tcinfo_t { | ||
39 | struct tc_kind_handle *handle_array; | ||
40 | int used_len; | ||
41 | int array_len; | ||
42 | bool is_qdisc; | ||
43 | }; | ||
44 | |||
45 | struct bpf_filter_t { | ||
46 | const char *kind; | ||
47 | const char *devname; | ||
48 | int ifindex; | ||
49 | }; | ||
50 | |||
51 | static int dump_link_nlmsg(void *cookie, void *msg, struct nlattr **tb) | ||
52 | { | ||
53 | struct bpf_netdev_t *netinfo = cookie; | ||
54 | struct ifinfomsg *ifinfo = msg; | ||
55 | |||
56 | if (netinfo->filter_idx > 0 && netinfo->filter_idx != ifinfo->ifi_index) | ||
57 | return 0; | ||
58 | |||
59 | if (netinfo->used_len == netinfo->array_len) { | ||
60 | netinfo->devices = realloc(netinfo->devices, | ||
61 | (netinfo->array_len + 16) * | ||
62 | sizeof(struct ip_devname_ifindex)); | ||
63 | if (!netinfo->devices) | ||
64 | return -ENOMEM; | ||
65 | |||
66 | netinfo->array_len += 16; | ||
67 | } | ||
68 | netinfo->devices[netinfo->used_len].ifindex = ifinfo->ifi_index; | ||
69 | snprintf(netinfo->devices[netinfo->used_len].devname, | ||
70 | sizeof(netinfo->devices[netinfo->used_len].devname), | ||
71 | "%s", | ||
72 | tb[IFLA_IFNAME] | ||
73 | ? libbpf_nla_getattr_str(tb[IFLA_IFNAME]) | ||
74 | : ""); | ||
75 | netinfo->used_len++; | ||
76 | |||
77 | return do_xdp_dump(ifinfo, tb); | ||
78 | } | ||
79 | |||
80 | static int dump_class_qdisc_nlmsg(void *cookie, void *msg, struct nlattr **tb) | ||
81 | { | ||
82 | struct bpf_tcinfo_t *tcinfo = cookie; | ||
83 | struct tcmsg *info = msg; | ||
84 | |||
85 | if (tcinfo->is_qdisc) { | ||
86 | /* skip clsact qdisc */ | ||
87 | if (tb[TCA_KIND] && | ||
88 | strcmp(libbpf_nla_data(tb[TCA_KIND]), "clsact") == 0) | ||
89 | return 0; | ||
90 | if (info->tcm_handle == 0) | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | if (tcinfo->used_len == tcinfo->array_len) { | ||
95 | tcinfo->handle_array = realloc(tcinfo->handle_array, | ||
96 | (tcinfo->array_len + 16) * sizeof(struct tc_kind_handle)); | ||
97 | if (!tcinfo->handle_array) | ||
98 | return -ENOMEM; | ||
99 | |||
100 | tcinfo->array_len += 16; | ||
101 | } | ||
102 | tcinfo->handle_array[tcinfo->used_len].handle = info->tcm_handle; | ||
103 | snprintf(tcinfo->handle_array[tcinfo->used_len].kind, | ||
104 | sizeof(tcinfo->handle_array[tcinfo->used_len].kind), | ||
105 | "%s", | ||
106 | tb[TCA_KIND] | ||
107 | ? libbpf_nla_getattr_str(tb[TCA_KIND]) | ||
108 | : "unknown"); | ||
109 | tcinfo->used_len++; | ||
110 | |||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | static int dump_filter_nlmsg(void *cookie, void *msg, struct nlattr **tb) | ||
115 | { | ||
116 | const struct bpf_filter_t *filter_info = cookie; | ||
117 | |||
118 | return do_filter_dump((struct tcmsg *)msg, tb, filter_info->kind, | ||
119 | filter_info->devname, filter_info->ifindex); | ||
120 | } | ||
121 | |||
122 | static int show_dev_tc_bpf(int sock, unsigned int nl_pid, | ||
123 | struct ip_devname_ifindex *dev) | ||
124 | { | ||
125 | struct bpf_filter_t filter_info; | ||
126 | struct bpf_tcinfo_t tcinfo; | ||
127 | int i, handle, ret = 0; | ||
128 | |||
129 | tcinfo.handle_array = NULL; | ||
130 | tcinfo.used_len = 0; | ||
131 | tcinfo.array_len = 0; | ||
132 | |||
133 | tcinfo.is_qdisc = false; | ||
134 | ret = libbpf_nl_get_class(sock, nl_pid, dev->ifindex, | ||
135 | dump_class_qdisc_nlmsg, &tcinfo); | ||
136 | if (ret) | ||
137 | goto out; | ||
138 | |||
139 | tcinfo.is_qdisc = true; | ||
140 | ret = libbpf_nl_get_qdisc(sock, nl_pid, dev->ifindex, | ||
141 | dump_class_qdisc_nlmsg, &tcinfo); | ||
142 | if (ret) | ||
143 | goto out; | ||
144 | |||
145 | filter_info.devname = dev->devname; | ||
146 | filter_info.ifindex = dev->ifindex; | ||
147 | for (i = 0; i < tcinfo.used_len; i++) { | ||
148 | filter_info.kind = tcinfo.handle_array[i].kind; | ||
149 | ret = libbpf_nl_get_filter(sock, nl_pid, dev->ifindex, | ||
150 | tcinfo.handle_array[i].handle, | ||
151 | dump_filter_nlmsg, &filter_info); | ||
152 | if (ret) | ||
153 | goto out; | ||
154 | } | ||
155 | |||
156 | /* root, ingress and egress handle */ | ||
157 | handle = TC_H_ROOT; | ||
158 | filter_info.kind = "root"; | ||
159 | ret = libbpf_nl_get_filter(sock, nl_pid, dev->ifindex, handle, | ||
160 | dump_filter_nlmsg, &filter_info); | ||
161 | if (ret) | ||
162 | goto out; | ||
163 | |||
164 | handle = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS); | ||
165 | filter_info.kind = "clsact/ingress"; | ||
166 | ret = libbpf_nl_get_filter(sock, nl_pid, dev->ifindex, handle, | ||
167 | dump_filter_nlmsg, &filter_info); | ||
168 | if (ret) | ||
169 | goto out; | ||
170 | |||
171 | handle = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_EGRESS); | ||
172 | filter_info.kind = "clsact/egress"; | ||
173 | ret = libbpf_nl_get_filter(sock, nl_pid, dev->ifindex, handle, | ||
174 | dump_filter_nlmsg, &filter_info); | ||
175 | if (ret) | ||
176 | goto out; | ||
177 | |||
178 | out: | ||
179 | free(tcinfo.handle_array); | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | static int do_show(int argc, char **argv) | ||
184 | { | ||
185 | int i, sock, ret, filter_idx = -1; | ||
186 | struct bpf_netdev_t dev_array; | ||
187 | unsigned int nl_pid; | ||
188 | char err_buf[256]; | ||
189 | |||
190 | if (argc == 2) { | ||
191 | if (strcmp(argv[0], "dev") != 0) | ||
192 | usage(); | ||
193 | filter_idx = if_nametoindex(argv[1]); | ||
194 | if (filter_idx == 0) { | ||
195 | fprintf(stderr, "invalid dev name %s\n", argv[1]); | ||
196 | return -1; | ||
197 | } | ||
198 | } else if (argc != 0) { | ||
199 | usage(); | ||
200 | } | ||
201 | |||
202 | sock = libbpf_netlink_open(&nl_pid); | ||
203 | if (sock < 0) { | ||
204 | fprintf(stderr, "failed to open netlink sock\n"); | ||
205 | return -1; | ||
206 | } | ||
207 | |||
208 | dev_array.devices = NULL; | ||
209 | dev_array.used_len = 0; | ||
210 | dev_array.array_len = 0; | ||
211 | dev_array.filter_idx = filter_idx; | ||
212 | |||
213 | if (json_output) | ||
214 | jsonw_start_array(json_wtr); | ||
215 | NET_START_OBJECT; | ||
216 | NET_START_ARRAY("xdp", "%s:\n"); | ||
217 | ret = libbpf_nl_get_link(sock, nl_pid, dump_link_nlmsg, &dev_array); | ||
218 | NET_END_ARRAY("\n"); | ||
219 | |||
220 | if (!ret) { | ||
221 | NET_START_ARRAY("tc", "%s:\n"); | ||
222 | for (i = 0; i < dev_array.used_len; i++) { | ||
223 | ret = show_dev_tc_bpf(sock, nl_pid, | ||
224 | &dev_array.devices[i]); | ||
225 | if (ret) | ||
226 | break; | ||
227 | } | ||
228 | NET_END_ARRAY("\n"); | ||
229 | } | ||
230 | NET_END_OBJECT; | ||
231 | if (json_output) | ||
232 | jsonw_end_array(json_wtr); | ||
233 | |||
234 | if (ret) { | ||
235 | if (json_output) | ||
236 | jsonw_null(json_wtr); | ||
237 | libbpf_strerror(ret, err_buf, sizeof(err_buf)); | ||
238 | fprintf(stderr, "Error: %s\n", err_buf); | ||
239 | } | ||
240 | free(dev_array.devices); | ||
241 | close(sock); | ||
242 | return ret; | ||
243 | } | ||
244 | |||
245 | static int do_help(int argc, char **argv) | ||
246 | { | ||
247 | if (json_output) { | ||
248 | jsonw_null(json_wtr); | ||
249 | return 0; | ||
250 | } | ||
251 | |||
252 | fprintf(stderr, | ||
253 | "Usage: %s %s { show | list } [dev <devname>]\n" | ||
254 | " %s %s help\n" | ||
255 | "Note: Only xdp and tc attachments are supported now.\n" | ||
256 | " For progs attached to cgroups, use \"bpftool cgroup\"\n" | ||
257 | " to dump program attachments. For program types\n" | ||
258 | " sk_{filter,skb,msg,reuseport} and lwt/seg6, please\n" | ||
259 | " consult iproute2.\n", | ||
260 | bin_name, argv[-2], bin_name, argv[-2]); | ||
261 | |||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | static const struct cmd cmds[] = { | ||
266 | { "show", do_show }, | ||
267 | { "list", do_show }, | ||
268 | { "help", do_help }, | ||
269 | { 0 } | ||
270 | }; | ||
271 | |||
272 | int do_net(int argc, char **argv) | ||
273 | { | ||
274 | return cmd_select(cmds, argc, argv, do_help); | ||
275 | } | ||
diff --git a/tools/bpf/bpftool/netlink_dumper.c b/tools/bpf/bpftool/netlink_dumper.c new file mode 100644 index 000000000000..4e9f4531269f --- /dev/null +++ b/tools/bpf/bpftool/netlink_dumper.c | |||
@@ -0,0 +1,178 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0+ | ||
2 | // Copyright (C) 2018 Facebook | ||
3 | |||
4 | #include <stdlib.h> | ||
5 | #include <string.h> | ||
6 | #include <libbpf.h> | ||
7 | #include <linux/rtnetlink.h> | ||
8 | #include <linux/tc_act/tc_bpf.h> | ||
9 | |||
10 | #include <nlattr.h> | ||
11 | #include "main.h" | ||
12 | #include "netlink_dumper.h" | ||
13 | |||
14 | static void xdp_dump_prog_id(struct nlattr **tb, int attr, | ||
15 | const char *mode, | ||
16 | bool new_json_object) | ||
17 | { | ||
18 | if (!tb[attr]) | ||
19 | return; | ||
20 | |||
21 | if (new_json_object) | ||
22 | NET_START_OBJECT | ||
23 | NET_DUMP_STR("mode", " %s", mode); | ||
24 | NET_DUMP_UINT("id", " id %u", libbpf_nla_getattr_u32(tb[attr])) | ||
25 | if (new_json_object) | ||
26 | NET_END_OBJECT | ||
27 | } | ||
28 | |||
29 | static int do_xdp_dump_one(struct nlattr *attr, unsigned int ifindex, | ||
30 | const char *name) | ||
31 | { | ||
32 | struct nlattr *tb[IFLA_XDP_MAX + 1]; | ||
33 | unsigned char mode; | ||
34 | |||
35 | if (libbpf_nla_parse_nested(tb, IFLA_XDP_MAX, attr, NULL) < 0) | ||
36 | return -1; | ||
37 | |||
38 | if (!tb[IFLA_XDP_ATTACHED]) | ||
39 | return 0; | ||
40 | |||
41 | mode = libbpf_nla_getattr_u8(tb[IFLA_XDP_ATTACHED]); | ||
42 | if (mode == XDP_ATTACHED_NONE) | ||
43 | return 0; | ||
44 | |||
45 | NET_START_OBJECT; | ||
46 | if (name) | ||
47 | NET_DUMP_STR("devname", "%s", name); | ||
48 | NET_DUMP_UINT("ifindex", "(%d)", ifindex); | ||
49 | |||
50 | if (mode == XDP_ATTACHED_MULTI) { | ||
51 | if (json_output) { | ||
52 | jsonw_name(json_wtr, "multi_attachments"); | ||
53 | jsonw_start_array(json_wtr); | ||
54 | } | ||
55 | xdp_dump_prog_id(tb, IFLA_XDP_SKB_PROG_ID, "generic", true); | ||
56 | xdp_dump_prog_id(tb, IFLA_XDP_DRV_PROG_ID, "driver", true); | ||
57 | xdp_dump_prog_id(tb, IFLA_XDP_HW_PROG_ID, "offload", true); | ||
58 | if (json_output) | ||
59 | jsonw_end_array(json_wtr); | ||
60 | } else if (mode == XDP_ATTACHED_DRV) { | ||
61 | xdp_dump_prog_id(tb, IFLA_XDP_PROG_ID, "driver", false); | ||
62 | } else if (mode == XDP_ATTACHED_SKB) { | ||
63 | xdp_dump_prog_id(tb, IFLA_XDP_PROG_ID, "generic", false); | ||
64 | } else if (mode == XDP_ATTACHED_HW) { | ||
65 | xdp_dump_prog_id(tb, IFLA_XDP_PROG_ID, "offload", false); | ||
66 | } | ||
67 | |||
68 | NET_END_OBJECT_FINAL; | ||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | int do_xdp_dump(struct ifinfomsg *ifinfo, struct nlattr **tb) | ||
73 | { | ||
74 | if (!tb[IFLA_XDP]) | ||
75 | return 0; | ||
76 | |||
77 | return do_xdp_dump_one(tb[IFLA_XDP], ifinfo->ifi_index, | ||
78 | libbpf_nla_getattr_str(tb[IFLA_IFNAME])); | ||
79 | } | ||
80 | |||
81 | static int do_bpf_dump_one_act(struct nlattr *attr) | ||
82 | { | ||
83 | struct nlattr *tb[TCA_ACT_BPF_MAX + 1]; | ||
84 | |||
85 | if (libbpf_nla_parse_nested(tb, TCA_ACT_BPF_MAX, attr, NULL) < 0) | ||
86 | return -LIBBPF_ERRNO__NLPARSE; | ||
87 | |||
88 | if (!tb[TCA_ACT_BPF_PARMS]) | ||
89 | return -LIBBPF_ERRNO__NLPARSE; | ||
90 | |||
91 | NET_START_OBJECT_NESTED2; | ||
92 | if (tb[TCA_ACT_BPF_NAME]) | ||
93 | NET_DUMP_STR("name", "%s", | ||
94 | libbpf_nla_getattr_str(tb[TCA_ACT_BPF_NAME])); | ||
95 | if (tb[TCA_ACT_BPF_ID]) | ||
96 | NET_DUMP_UINT("id", " id %u", | ||
97 | libbpf_nla_getattr_u32(tb[TCA_ACT_BPF_ID])); | ||
98 | NET_END_OBJECT_NESTED; | ||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static int do_dump_one_act(struct nlattr *attr) | ||
103 | { | ||
104 | struct nlattr *tb[TCA_ACT_MAX + 1]; | ||
105 | |||
106 | if (!attr) | ||
107 | return 0; | ||
108 | |||
109 | if (libbpf_nla_parse_nested(tb, TCA_ACT_MAX, attr, NULL) < 0) | ||
110 | return -LIBBPF_ERRNO__NLPARSE; | ||
111 | |||
112 | if (tb[TCA_ACT_KIND] && | ||
113 | strcmp(libbpf_nla_data(tb[TCA_ACT_KIND]), "bpf") == 0) | ||
114 | return do_bpf_dump_one_act(tb[TCA_ACT_OPTIONS]); | ||
115 | |||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static int do_bpf_act_dump(struct nlattr *attr) | ||
120 | { | ||
121 | struct nlattr *tb[TCA_ACT_MAX_PRIO + 1]; | ||
122 | int act, ret; | ||
123 | |||
124 | if (libbpf_nla_parse_nested(tb, TCA_ACT_MAX_PRIO, attr, NULL) < 0) | ||
125 | return -LIBBPF_ERRNO__NLPARSE; | ||
126 | |||
127 | NET_START_ARRAY("act", " %s ["); | ||
128 | for (act = 0; act <= TCA_ACT_MAX_PRIO; act++) { | ||
129 | ret = do_dump_one_act(tb[act]); | ||
130 | if (ret) | ||
131 | break; | ||
132 | } | ||
133 | NET_END_ARRAY("] "); | ||
134 | |||
135 | return ret; | ||
136 | } | ||
137 | |||
138 | static int do_bpf_filter_dump(struct nlattr *attr) | ||
139 | { | ||
140 | struct nlattr *tb[TCA_BPF_MAX + 1]; | ||
141 | int ret; | ||
142 | |||
143 | if (libbpf_nla_parse_nested(tb, TCA_BPF_MAX, attr, NULL) < 0) | ||
144 | return -LIBBPF_ERRNO__NLPARSE; | ||
145 | |||
146 | if (tb[TCA_BPF_NAME]) | ||
147 | NET_DUMP_STR("name", " %s", | ||
148 | libbpf_nla_getattr_str(tb[TCA_BPF_NAME])); | ||
149 | if (tb[TCA_BPF_ID]) | ||
150 | NET_DUMP_UINT("id", " id %u", | ||
151 | libbpf_nla_getattr_u32(tb[TCA_BPF_ID])); | ||
152 | if (tb[TCA_BPF_ACT]) { | ||
153 | ret = do_bpf_act_dump(tb[TCA_BPF_ACT]); | ||
154 | if (ret) | ||
155 | return ret; | ||
156 | } | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | int do_filter_dump(struct tcmsg *info, struct nlattr **tb, const char *kind, | ||
162 | const char *devname, int ifindex) | ||
163 | { | ||
164 | int ret = 0; | ||
165 | |||
166 | if (tb[TCA_OPTIONS] && | ||
167 | strcmp(libbpf_nla_data(tb[TCA_KIND]), "bpf") == 0) { | ||
168 | NET_START_OBJECT; | ||
169 | if (devname[0] != '\0') | ||
170 | NET_DUMP_STR("devname", "%s", devname); | ||
171 | NET_DUMP_UINT("ifindex", "(%u)", ifindex); | ||
172 | NET_DUMP_STR("kind", " %s", kind); | ||
173 | ret = do_bpf_filter_dump(tb[TCA_OPTIONS]); | ||
174 | NET_END_OBJECT_FINAL; | ||
175 | } | ||
176 | |||
177 | return ret; | ||
178 | } | ||
diff --git a/tools/bpf/bpftool/netlink_dumper.h b/tools/bpf/bpftool/netlink_dumper.h new file mode 100644 index 000000000000..e3516b586a34 --- /dev/null +++ b/tools/bpf/bpftool/netlink_dumper.h | |||
@@ -0,0 +1,95 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0+ | ||
2 | // Copyright (C) 2018 Facebook | ||
3 | |||
4 | #ifndef _NETLINK_DUMPER_H_ | ||
5 | #define _NETLINK_DUMPER_H_ | ||
6 | |||
7 | #define NET_START_OBJECT \ | ||
8 | { \ | ||
9 | if (json_output) \ | ||
10 | jsonw_start_object(json_wtr); \ | ||
11 | } | ||
12 | |||
13 | #define NET_START_OBJECT_NESTED(name) \ | ||
14 | { \ | ||
15 | if (json_output) { \ | ||
16 | jsonw_name(json_wtr, name); \ | ||
17 | jsonw_start_object(json_wtr); \ | ||
18 | } else { \ | ||
19 | fprintf(stdout, "%s {", name); \ | ||
20 | } \ | ||
21 | } | ||
22 | |||
23 | #define NET_START_OBJECT_NESTED2 \ | ||
24 | { \ | ||
25 | if (json_output) \ | ||
26 | jsonw_start_object(json_wtr); \ | ||
27 | else \ | ||
28 | fprintf(stdout, "{"); \ | ||
29 | } | ||
30 | |||
31 | #define NET_END_OBJECT_NESTED \ | ||
32 | { \ | ||
33 | if (json_output) \ | ||
34 | jsonw_end_object(json_wtr); \ | ||
35 | else \ | ||
36 | fprintf(stdout, "}"); \ | ||
37 | } | ||
38 | |||
39 | #define NET_END_OBJECT \ | ||
40 | { \ | ||
41 | if (json_output) \ | ||
42 | jsonw_end_object(json_wtr); \ | ||
43 | } | ||
44 | |||
45 | #define NET_END_OBJECT_FINAL \ | ||
46 | { \ | ||
47 | if (json_output) \ | ||
48 | jsonw_end_object(json_wtr); \ | ||
49 | else \ | ||
50 | fprintf(stdout, "\n"); \ | ||
51 | } | ||
52 | |||
53 | #define NET_START_ARRAY(name, fmt_str) \ | ||
54 | { \ | ||
55 | if (json_output) { \ | ||
56 | jsonw_name(json_wtr, name); \ | ||
57 | jsonw_start_array(json_wtr); \ | ||
58 | } else { \ | ||
59 | fprintf(stdout, fmt_str, name); \ | ||
60 | } \ | ||
61 | } | ||
62 | |||
63 | #define NET_END_ARRAY(endstr) \ | ||
64 | { \ | ||
65 | if (json_output) \ | ||
66 | jsonw_end_array(json_wtr); \ | ||
67 | else \ | ||
68 | fprintf(stdout, "%s", endstr); \ | ||
69 | } | ||
70 | |||
71 | #define NET_DUMP_UINT(name, fmt_str, val) \ | ||
72 | { \ | ||
73 | if (json_output) \ | ||
74 | jsonw_uint_field(json_wtr, name, val); \ | ||
75 | else \ | ||
76 | fprintf(stdout, fmt_str, val); \ | ||
77 | } | ||
78 | |||
79 | #define NET_DUMP_STR(name, fmt_str, str) \ | ||
80 | { \ | ||
81 | if (json_output) \ | ||
82 | jsonw_string_field(json_wtr, name, str);\ | ||
83 | else \ | ||
84 | fprintf(stdout, fmt_str, str); \ | ||
85 | } | ||
86 | |||
87 | #define NET_DUMP_STR_ONLY(str) \ | ||
88 | { \ | ||
89 | if (json_output) \ | ||
90 | jsonw_string(json_wtr, str); \ | ||
91 | else \ | ||
92 | fprintf(stdout, "%s ", str); \ | ||
93 | } | ||
94 | |||
95 | #endif | ||
diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c index dce960d22106..5302ee282409 100644 --- a/tools/bpf/bpftool/prog.c +++ b/tools/bpf/bpftool/prog.c | |||
@@ -74,8 +74,29 @@ static const char * const prog_type_name[] = { | |||
74 | [BPF_PROG_TYPE_RAW_TRACEPOINT] = "raw_tracepoint", | 74 | [BPF_PROG_TYPE_RAW_TRACEPOINT] = "raw_tracepoint", |
75 | [BPF_PROG_TYPE_CGROUP_SOCK_ADDR] = "cgroup_sock_addr", | 75 | [BPF_PROG_TYPE_CGROUP_SOCK_ADDR] = "cgroup_sock_addr", |
76 | [BPF_PROG_TYPE_LIRC_MODE2] = "lirc_mode2", | 76 | [BPF_PROG_TYPE_LIRC_MODE2] = "lirc_mode2", |
77 | [BPF_PROG_TYPE_FLOW_DISSECTOR] = "flow_dissector", | ||
77 | }; | 78 | }; |
78 | 79 | ||
80 | static const char * const attach_type_strings[] = { | ||
81 | [BPF_SK_SKB_STREAM_PARSER] = "stream_parser", | ||
82 | [BPF_SK_SKB_STREAM_VERDICT] = "stream_verdict", | ||
83 | [BPF_SK_MSG_VERDICT] = "msg_verdict", | ||
84 | [__MAX_BPF_ATTACH_TYPE] = NULL, | ||
85 | }; | ||
86 | |||
87 | enum bpf_attach_type parse_attach_type(const char *str) | ||
88 | { | ||
89 | enum bpf_attach_type type; | ||
90 | |||
91 | for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { | ||
92 | if (attach_type_strings[type] && | ||
93 | is_prefix(str, attach_type_strings[type])) | ||
94 | return type; | ||
95 | } | ||
96 | |||
97 | return __MAX_BPF_ATTACH_TYPE; | ||
98 | } | ||
99 | |||
79 | static void print_boot_time(__u64 nsecs, char *buf, unsigned int size) | 100 | static void print_boot_time(__u64 nsecs, char *buf, unsigned int size) |
80 | { | 101 | { |
81 | struct timespec real_time_ts, boot_time_ts; | 102 | struct timespec real_time_ts, boot_time_ts; |
@@ -428,6 +449,7 @@ static int do_dump(int argc, char **argv) | |||
428 | unsigned long *func_ksyms = NULL; | 449 | unsigned long *func_ksyms = NULL; |
429 | struct bpf_prog_info info = {}; | 450 | struct bpf_prog_info info = {}; |
430 | unsigned int *func_lens = NULL; | 451 | unsigned int *func_lens = NULL; |
452 | const char *disasm_opt = NULL; | ||
431 | unsigned int nr_func_ksyms; | 453 | unsigned int nr_func_ksyms; |
432 | unsigned int nr_func_lens; | 454 | unsigned int nr_func_lens; |
433 | struct dump_data dd = {}; | 455 | struct dump_data dd = {}; |
@@ -586,9 +608,10 @@ static int do_dump(int argc, char **argv) | |||
586 | const char *name = NULL; | 608 | const char *name = NULL; |
587 | 609 | ||
588 | if (info.ifindex) { | 610 | if (info.ifindex) { |
589 | name = ifindex_to_bfd_name_ns(info.ifindex, | 611 | name = ifindex_to_bfd_params(info.ifindex, |
590 | info.netns_dev, | 612 | info.netns_dev, |
591 | info.netns_ino); | 613 | info.netns_ino, |
614 | &disasm_opt); | ||
592 | if (!name) | 615 | if (!name) |
593 | goto err_free; | 616 | goto err_free; |
594 | } | 617 | } |
@@ -630,7 +653,8 @@ static int do_dump(int argc, char **argv) | |||
630 | printf("%s:\n", sym_name); | 653 | printf("%s:\n", sym_name); |
631 | } | 654 | } |
632 | 655 | ||
633 | disasm_print_insn(img, lens[i], opcodes, name); | 656 | disasm_print_insn(img, lens[i], opcodes, name, |
657 | disasm_opt); | ||
634 | img += lens[i]; | 658 | img += lens[i]; |
635 | 659 | ||
636 | if (json_output) | 660 | if (json_output) |
@@ -642,7 +666,8 @@ static int do_dump(int argc, char **argv) | |||
642 | if (json_output) | 666 | if (json_output) |
643 | jsonw_end_array(json_wtr); | 667 | jsonw_end_array(json_wtr); |
644 | } else { | 668 | } else { |
645 | disasm_print_insn(buf, *member_len, opcodes, name); | 669 | disasm_print_insn(buf, *member_len, opcodes, name, |
670 | disasm_opt); | ||
646 | } | 671 | } |
647 | } else if (visual) { | 672 | } else if (visual) { |
648 | if (json_output) | 673 | if (json_output) |
@@ -696,6 +721,77 @@ int map_replace_compar(const void *p1, const void *p2) | |||
696 | return a->idx - b->idx; | 721 | return a->idx - b->idx; |
697 | } | 722 | } |
698 | 723 | ||
724 | static int do_attach(int argc, char **argv) | ||
725 | { | ||
726 | enum bpf_attach_type attach_type; | ||
727 | int err, mapfd, progfd; | ||
728 | |||
729 | if (!REQ_ARGS(5)) { | ||
730 | p_err("too few parameters for map attach"); | ||
731 | return -EINVAL; | ||
732 | } | ||
733 | |||
734 | progfd = prog_parse_fd(&argc, &argv); | ||
735 | if (progfd < 0) | ||
736 | return progfd; | ||
737 | |||
738 | attach_type = parse_attach_type(*argv); | ||
739 | if (attach_type == __MAX_BPF_ATTACH_TYPE) { | ||
740 | p_err("invalid attach type"); | ||
741 | return -EINVAL; | ||
742 | } | ||
743 | NEXT_ARG(); | ||
744 | |||
745 | mapfd = map_parse_fd(&argc, &argv); | ||
746 | if (mapfd < 0) | ||
747 | return mapfd; | ||
748 | |||
749 | err = bpf_prog_attach(progfd, mapfd, attach_type, 0); | ||
750 | if (err) { | ||
751 | p_err("failed prog attach to map"); | ||
752 | return -EINVAL; | ||
753 | } | ||
754 | |||
755 | if (json_output) | ||
756 | jsonw_null(json_wtr); | ||
757 | return 0; | ||
758 | } | ||
759 | |||
760 | static int do_detach(int argc, char **argv) | ||
761 | { | ||
762 | enum bpf_attach_type attach_type; | ||
763 | int err, mapfd, progfd; | ||
764 | |||
765 | if (!REQ_ARGS(5)) { | ||
766 | p_err("too few parameters for map detach"); | ||
767 | return -EINVAL; | ||
768 | } | ||
769 | |||
770 | progfd = prog_parse_fd(&argc, &argv); | ||
771 | if (progfd < 0) | ||
772 | return progfd; | ||
773 | |||
774 | attach_type = parse_attach_type(*argv); | ||
775 | if (attach_type == __MAX_BPF_ATTACH_TYPE) { | ||
776 | p_err("invalid attach type"); | ||
777 | return -EINVAL; | ||
778 | } | ||
779 | NEXT_ARG(); | ||
780 | |||
781 | mapfd = map_parse_fd(&argc, &argv); | ||
782 | if (mapfd < 0) | ||
783 | return mapfd; | ||
784 | |||
785 | err = bpf_prog_detach2(progfd, mapfd, attach_type); | ||
786 | if (err) { | ||
787 | p_err("failed prog detach from map"); | ||
788 | return -EINVAL; | ||
789 | } | ||
790 | |||
791 | if (json_output) | ||
792 | jsonw_null(json_wtr); | ||
793 | return 0; | ||
794 | } | ||
699 | static int do_load(int argc, char **argv) | 795 | static int do_load(int argc, char **argv) |
700 | { | 796 | { |
701 | enum bpf_attach_type expected_attach_type; | 797 | enum bpf_attach_type expected_attach_type; |
@@ -816,7 +912,7 @@ static int do_load(int argc, char **argv) | |||
816 | } | 912 | } |
817 | } | 913 | } |
818 | 914 | ||
819 | obj = bpf_object__open_xattr(&attr); | 915 | obj = __bpf_object__open_xattr(&attr, bpf_flags); |
820 | if (IS_ERR_OR_NULL(obj)) { | 916 | if (IS_ERR_OR_NULL(obj)) { |
821 | p_err("failed to open object file"); | 917 | p_err("failed to open object file"); |
822 | goto err_free_reuse_maps; | 918 | goto err_free_reuse_maps; |
@@ -941,6 +1037,8 @@ static int do_help(int argc, char **argv) | |||
941 | " %s %s pin PROG FILE\n" | 1037 | " %s %s pin PROG FILE\n" |
942 | " %s %s load OBJ FILE [type TYPE] [dev NAME] \\\n" | 1038 | " %s %s load OBJ FILE [type TYPE] [dev NAME] \\\n" |
943 | " [map { idx IDX | name NAME } MAP]\n" | 1039 | " [map { idx IDX | name NAME } MAP]\n" |
1040 | " %s %s attach PROG ATTACH_TYPE MAP\n" | ||
1041 | " %s %s detach PROG ATTACH_TYPE MAP\n" | ||
944 | " %s %s help\n" | 1042 | " %s %s help\n" |
945 | "\n" | 1043 | "\n" |
946 | " " HELP_SPEC_MAP "\n" | 1044 | " " HELP_SPEC_MAP "\n" |
@@ -952,10 +1050,12 @@ static int do_help(int argc, char **argv) | |||
952 | " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n" | 1050 | " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n" |
953 | " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n" | 1051 | " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n" |
954 | " cgroup/sendmsg4 | cgroup/sendmsg6 }\n" | 1052 | " cgroup/sendmsg4 | cgroup/sendmsg6 }\n" |
1053 | " ATTACH_TYPE := { msg_verdict | skb_verdict | skb_parse }\n" | ||
955 | " " HELP_SPEC_OPTIONS "\n" | 1054 | " " HELP_SPEC_OPTIONS "\n" |
956 | "", | 1055 | "", |
957 | bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], | 1056 | bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], |
958 | bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]); | 1057 | bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], |
1058 | bin_name, argv[-2], bin_name, argv[-2]); | ||
959 | 1059 | ||
960 | return 0; | 1060 | return 0; |
961 | } | 1061 | } |
@@ -967,6 +1067,8 @@ static const struct cmd cmds[] = { | |||
967 | { "dump", do_dump }, | 1067 | { "dump", do_dump }, |
968 | { "pin", do_pin }, | 1068 | { "pin", do_pin }, |
969 | { "load", do_load }, | 1069 | { "load", do_load }, |
1070 | { "attach", do_attach }, | ||
1071 | { "detach", do_detach }, | ||
970 | { 0 } | 1072 | { 0 } |
971 | }; | 1073 | }; |
972 | 1074 | ||
diff --git a/tools/crypto/getstat.c b/tools/crypto/getstat.c new file mode 100644 index 000000000000..24115173a483 --- /dev/null +++ b/tools/crypto/getstat.c | |||
@@ -0,0 +1,294 @@ | |||
1 | /* Heavily copied from libkcapi 2015 - 2017, Stephan Mueller <smueller@chronox.de> */ | ||
2 | #include <errno.h> | ||
3 | #include <linux/cryptouser.h> | ||
4 | #include <linux/netlink.h> | ||
5 | #include <linux/rtnetlink.h> | ||
6 | #include <sys/types.h> | ||
7 | #include <sys/socket.h> | ||
8 | #include <stdlib.h> | ||
9 | #include <stdio.h> | ||
10 | #include <string.h> | ||
11 | #include <time.h> | ||
12 | #include <unistd.h> | ||
13 | |||
14 | #define CR_RTA(x) ((struct rtattr *)(((char *)(x)) + NLMSG_ALIGN(sizeof(struct crypto_user_alg)))) | ||
15 | |||
16 | static int get_stat(const char *drivername) | ||
17 | { | ||
18 | struct { | ||
19 | struct nlmsghdr n; | ||
20 | struct crypto_user_alg cru; | ||
21 | } req; | ||
22 | struct sockaddr_nl nl; | ||
23 | int sd = 0, ret; | ||
24 | socklen_t addr_len; | ||
25 | struct iovec iov; | ||
26 | struct msghdr msg; | ||
27 | char buf[4096]; | ||
28 | struct nlmsghdr *res_n = (struct nlmsghdr *)buf; | ||
29 | struct crypto_user_alg *cru_res = NULL; | ||
30 | int res_len = 0; | ||
31 | struct rtattr *tb[CRYPTOCFGA_MAX + 1]; | ||
32 | struct rtattr *rta; | ||
33 | struct nlmsgerr *errmsg; | ||
34 | |||
35 | memset(&req, 0, sizeof(req)); | ||
36 | memset(&buf, 0, sizeof(buf)); | ||
37 | memset(&msg, 0, sizeof(msg)); | ||
38 | |||
39 | req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.cru)); | ||
40 | req.n.nlmsg_flags = NLM_F_REQUEST; | ||
41 | req.n.nlmsg_type = CRYPTO_MSG_GETSTAT; | ||
42 | req.n.nlmsg_seq = time(NULL); | ||
43 | |||
44 | strncpy(req.cru.cru_driver_name, drivername, strlen(drivername)); | ||
45 | |||
46 | sd = socket(AF_NETLINK, SOCK_RAW, NETLINK_CRYPTO); | ||
47 | if (sd < 0) { | ||
48 | fprintf(stderr, "Netlink error: cannot open netlink socket"); | ||
49 | return -errno; | ||
50 | } | ||
51 | memset(&nl, 0, sizeof(nl)); | ||
52 | nl.nl_family = AF_NETLINK; | ||
53 | if (bind(sd, (struct sockaddr *)&nl, sizeof(nl)) < 0) { | ||
54 | ret = -errno; | ||
55 | fprintf(stderr, "Netlink error: cannot bind netlink socket"); | ||
56 | goto out; | ||
57 | } | ||
58 | |||
59 | /* sanity check that netlink socket was successfully opened */ | ||
60 | addr_len = sizeof(nl); | ||
61 | if (getsockname(sd, (struct sockaddr *)&nl, &addr_len) < 0) { | ||
62 | ret = -errno; | ||
63 | printf("Netlink error: cannot getsockname"); | ||
64 | goto out; | ||
65 | } | ||
66 | if (addr_len != sizeof(nl)) { | ||
67 | ret = -errno; | ||
68 | printf("Netlink error: wrong address length %d", addr_len); | ||
69 | goto out; | ||
70 | } | ||
71 | if (nl.nl_family != AF_NETLINK) { | ||
72 | ret = -errno; | ||
73 | printf("Netlink error: wrong address family %d", | ||
74 | nl.nl_family); | ||
75 | goto out; | ||
76 | } | ||
77 | |||
78 | memset(&nl, 0, sizeof(nl)); | ||
79 | nl.nl_family = AF_NETLINK; | ||
80 | iov.iov_base = (void *)&req.n; | ||
81 | iov.iov_len = req.n.nlmsg_len; | ||
82 | msg.msg_name = &nl; | ||
83 | msg.msg_namelen = sizeof(nl); | ||
84 | msg.msg_iov = &iov; | ||
85 | msg.msg_iovlen = 1; | ||
86 | if (sendmsg(sd, &msg, 0) < 0) { | ||
87 | ret = -errno; | ||
88 | printf("Netlink error: sendmsg failed"); | ||
89 | goto out; | ||
90 | } | ||
91 | memset(buf, 0, sizeof(buf)); | ||
92 | iov.iov_base = buf; | ||
93 | while (1) { | ||
94 | iov.iov_len = sizeof(buf); | ||
95 | ret = recvmsg(sd, &msg, 0); | ||
96 | if (ret < 0) { | ||
97 | if (errno == EINTR || errno == EAGAIN) | ||
98 | continue; | ||
99 | ret = -errno; | ||
100 | printf("Netlink error: netlink receive error"); | ||
101 | goto out; | ||
102 | } | ||
103 | if (ret == 0) { | ||
104 | ret = -errno; | ||
105 | printf("Netlink error: no data"); | ||
106 | goto out; | ||
107 | } | ||
108 | if (ret > sizeof(buf)) { | ||
109 | ret = -errno; | ||
110 | printf("Netlink error: received too much data"); | ||
111 | goto out; | ||
112 | } | ||
113 | break; | ||
114 | } | ||
115 | |||
116 | ret = -EFAULT; | ||
117 | res_len = res_n->nlmsg_len; | ||
118 | if (res_n->nlmsg_type == NLMSG_ERROR) { | ||
119 | errmsg = NLMSG_DATA(res_n); | ||
120 | fprintf(stderr, "Fail with %d\n", errmsg->error); | ||
121 | ret = errmsg->error; | ||
122 | goto out; | ||
123 | } | ||
124 | |||
125 | if (res_n->nlmsg_type == CRYPTO_MSG_GETSTAT) { | ||
126 | cru_res = NLMSG_DATA(res_n); | ||
127 | res_len -= NLMSG_SPACE(sizeof(*cru_res)); | ||
128 | } | ||
129 | if (res_len < 0) { | ||
130 | printf("Netlink error: nlmsg len %d\n", res_len); | ||
131 | goto out; | ||
132 | } | ||
133 | |||
134 | if (!cru_res) { | ||
135 | ret = -EFAULT; | ||
136 | printf("Netlink error: no cru_res\n"); | ||
137 | goto out; | ||
138 | } | ||
139 | |||
140 | rta = CR_RTA(cru_res); | ||
141 | memset(tb, 0, sizeof(struct rtattr *) * (CRYPTOCFGA_MAX + 1)); | ||
142 | while (RTA_OK(rta, res_len)) { | ||
143 | if ((rta->rta_type <= CRYPTOCFGA_MAX) && (!tb[rta->rta_type])) | ||
144 | tb[rta->rta_type] = rta; | ||
145 | rta = RTA_NEXT(rta, res_len); | ||
146 | } | ||
147 | if (res_len) { | ||
148 | printf("Netlink error: unprocessed data %d", | ||
149 | res_len); | ||
150 | goto out; | ||
151 | } | ||
152 | |||
153 | if (tb[CRYPTOCFGA_STAT_HASH]) { | ||
154 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_HASH]; | ||
155 | struct crypto_stat *rhash = | ||
156 | (struct crypto_stat *)RTA_DATA(rta); | ||
157 | printf("%s\tHash\n\tHash: %u bytes: %llu\n\tErrors: %u\n", | ||
158 | drivername, | ||
159 | rhash->stat_hash_cnt, rhash->stat_hash_tlen, | ||
160 | rhash->stat_hash_err_cnt); | ||
161 | } else if (tb[CRYPTOCFGA_STAT_COMPRESS]) { | ||
162 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_COMPRESS]; | ||
163 | struct crypto_stat *rblk = | ||
164 | (struct crypto_stat *)RTA_DATA(rta); | ||
165 | printf("%s\tCompress\n\tCompress: %u bytes: %llu\n\tDecompress: %u bytes: %llu\n\tErrors: %u\n", | ||
166 | drivername, | ||
167 | rblk->stat_compress_cnt, rblk->stat_compress_tlen, | ||
168 | rblk->stat_decompress_cnt, rblk->stat_decompress_tlen, | ||
169 | rblk->stat_compress_err_cnt); | ||
170 | } else if (tb[CRYPTOCFGA_STAT_ACOMP]) { | ||
171 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_ACOMP]; | ||
172 | struct crypto_stat *rcomp = | ||
173 | (struct crypto_stat *)RTA_DATA(rta); | ||
174 | printf("%s\tACompress\n\tCompress: %u bytes: %llu\n\tDecompress: %u bytes: %llu\n\tErrors: %u\n", | ||
175 | drivername, | ||
176 | rcomp->stat_compress_cnt, rcomp->stat_compress_tlen, | ||
177 | rcomp->stat_decompress_cnt, rcomp->stat_decompress_tlen, | ||
178 | rcomp->stat_compress_err_cnt); | ||
179 | } else if (tb[CRYPTOCFGA_STAT_AEAD]) { | ||
180 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_AEAD]; | ||
181 | struct crypto_stat *raead = | ||
182 | (struct crypto_stat *)RTA_DATA(rta); | ||
183 | printf("%s\tAEAD\n\tEncrypt: %u bytes: %llu\n\tDecrypt: %u bytes: %llu\n\tErrors: %u\n", | ||
184 | drivername, | ||
185 | raead->stat_encrypt_cnt, raead->stat_encrypt_tlen, | ||
186 | raead->stat_decrypt_cnt, raead->stat_decrypt_tlen, | ||
187 | raead->stat_aead_err_cnt); | ||
188 | } else if (tb[CRYPTOCFGA_STAT_BLKCIPHER]) { | ||
189 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_BLKCIPHER]; | ||
190 | struct crypto_stat *rblk = | ||
191 | (struct crypto_stat *)RTA_DATA(rta); | ||
192 | printf("%s\tCipher\n\tEncrypt: %u bytes: %llu\n\tDecrypt: %u bytes: %llu\n\tErrors: %u\n", | ||
193 | drivername, | ||
194 | rblk->stat_encrypt_cnt, rblk->stat_encrypt_tlen, | ||
195 | rblk->stat_decrypt_cnt, rblk->stat_decrypt_tlen, | ||
196 | rblk->stat_cipher_err_cnt); | ||
197 | } else if (tb[CRYPTOCFGA_STAT_AKCIPHER]) { | ||
198 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_AKCIPHER]; | ||
199 | struct crypto_stat *rblk = | ||
200 | (struct crypto_stat *)RTA_DATA(rta); | ||
201 | printf("%s\tAkcipher\n\tEncrypt: %u bytes: %llu\n\tDecrypt: %u bytes: %llu\n\tSign: %u\n\tVerify: %u\n\tErrors: %u\n", | ||
202 | drivername, | ||
203 | rblk->stat_encrypt_cnt, rblk->stat_encrypt_tlen, | ||
204 | rblk->stat_decrypt_cnt, rblk->stat_decrypt_tlen, | ||
205 | rblk->stat_sign_cnt, rblk->stat_verify_cnt, | ||
206 | rblk->stat_akcipher_err_cnt); | ||
207 | } else if (tb[CRYPTOCFGA_STAT_CIPHER]) { | ||
208 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_CIPHER]; | ||
209 | struct crypto_stat *rblk = | ||
210 | (struct crypto_stat *)RTA_DATA(rta); | ||
211 | printf("%s\tcipher\n\tEncrypt: %u bytes: %llu\n\tDecrypt: %u bytes: %llu\n\tErrors: %u\n", | ||
212 | drivername, | ||
213 | rblk->stat_encrypt_cnt, rblk->stat_encrypt_tlen, | ||
214 | rblk->stat_decrypt_cnt, rblk->stat_decrypt_tlen, | ||
215 | rblk->stat_cipher_err_cnt); | ||
216 | } else if (tb[CRYPTOCFGA_STAT_RNG]) { | ||
217 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_RNG]; | ||
218 | struct crypto_stat *rrng = | ||
219 | (struct crypto_stat *)RTA_DATA(rta); | ||
220 | printf("%s\tRNG\n\tSeed: %u\n\tGenerate: %u bytes: %llu\n\tErrors: %u\n", | ||
221 | drivername, | ||
222 | rrng->stat_seed_cnt, | ||
223 | rrng->stat_generate_cnt, rrng->stat_generate_tlen, | ||
224 | rrng->stat_rng_err_cnt); | ||
225 | } else if (tb[CRYPTOCFGA_STAT_KPP]) { | ||
226 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_KPP]; | ||
227 | struct crypto_stat *rkpp = | ||
228 | (struct crypto_stat *)RTA_DATA(rta); | ||
229 | printf("%s\tKPP\n\tSetsecret: %u\n\tGenerate public key: %u\n\tCompute_shared_secret: %u\n\tErrors: %u\n", | ||
230 | drivername, | ||
231 | rkpp->stat_setsecret_cnt, | ||
232 | rkpp->stat_generate_public_key_cnt, | ||
233 | rkpp->stat_compute_shared_secret_cnt, | ||
234 | rkpp->stat_kpp_err_cnt); | ||
235 | } else { | ||
236 | fprintf(stderr, "%s is of an unknown algorithm\n", drivername); | ||
237 | } | ||
238 | ret = 0; | ||
239 | out: | ||
240 | close(sd); | ||
241 | return ret; | ||
242 | } | ||
243 | |||
244 | int main(int argc, const char *argv[]) | ||
245 | { | ||
246 | char buf[4096]; | ||
247 | FILE *procfd; | ||
248 | int i, lastspace; | ||
249 | int ret; | ||
250 | |||
251 | procfd = fopen("/proc/crypto", "r"); | ||
252 | if (!procfd) { | ||
253 | ret = errno; | ||
254 | fprintf(stderr, "Cannot open /proc/crypto %s\n", strerror(errno)); | ||
255 | return ret; | ||
256 | } | ||
257 | if (argc > 1) { | ||
258 | if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { | ||
259 | printf("Usage: %s [-h|--help] display this help\n", argv[0]); | ||
260 | printf("Usage: %s display all crypto statistics\n", argv[0]); | ||
261 | printf("Usage: %s drivername1 drivername2 ... = display crypto statistics about drivername1 ...\n", argv[0]); | ||
262 | return 0; | ||
263 | } | ||
264 | for (i = 1; i < argc; i++) { | ||
265 | ret = get_stat(argv[i]); | ||
266 | if (ret) { | ||
267 | fprintf(stderr, "Failed with %s\n", strerror(-ret)); | ||
268 | return ret; | ||
269 | } | ||
270 | } | ||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | while (fgets(buf, sizeof(buf), procfd)) { | ||
275 | if (!strncmp(buf, "driver", 6)) { | ||
276 | lastspace = 0; | ||
277 | i = 0; | ||
278 | while (i < strlen(buf)) { | ||
279 | i++; | ||
280 | if (buf[i] == ' ') | ||
281 | lastspace = i; | ||
282 | } | ||
283 | buf[strlen(buf) - 1] = '\0'; | ||
284 | ret = get_stat(buf + lastspace + 1); | ||
285 | if (ret) { | ||
286 | fprintf(stderr, "Failed with %s\n", strerror(-ret)); | ||
287 | goto out; | ||
288 | } | ||
289 | } | ||
290 | } | ||
291 | out: | ||
292 | fclose(procfd); | ||
293 | return ret; | ||
294 | } | ||
diff --git a/tools/include/asm/barrier.h b/tools/include/asm/barrier.h index 391d942536e5..8d378c57cb01 100644 --- a/tools/include/asm/barrier.h +++ b/tools/include/asm/barrier.h | |||
@@ -1,4 +1,5 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | #include <linux/compiler.h> | ||
2 | #if defined(__i386__) || defined(__x86_64__) | 3 | #if defined(__i386__) || defined(__x86_64__) |
3 | #include "../../arch/x86/include/asm/barrier.h" | 4 | #include "../../arch/x86/include/asm/barrier.h" |
4 | #elif defined(__arm__) | 5 | #elif defined(__arm__) |
@@ -26,3 +27,37 @@ | |||
26 | #else | 27 | #else |
27 | #include <asm-generic/barrier.h> | 28 | #include <asm-generic/barrier.h> |
28 | #endif | 29 | #endif |
30 | |||
31 | /* | ||
32 | * Generic fallback smp_*() definitions for archs that haven't | ||
33 | * been updated yet. | ||
34 | */ | ||
35 | |||
36 | #ifndef smp_rmb | ||
37 | # define smp_rmb() rmb() | ||
38 | #endif | ||
39 | |||
40 | #ifndef smp_wmb | ||
41 | # define smp_wmb() wmb() | ||
42 | #endif | ||
43 | |||
44 | #ifndef smp_mb | ||
45 | # define smp_mb() mb() | ||
46 | #endif | ||
47 | |||
48 | #ifndef smp_store_release | ||
49 | # define smp_store_release(p, v) \ | ||
50 | do { \ | ||
51 | smp_mb(); \ | ||
52 | WRITE_ONCE(*p, v); \ | ||
53 | } while (0) | ||
54 | #endif | ||
55 | |||
56 | #ifndef smp_load_acquire | ||
57 | # define smp_load_acquire(p) \ | ||
58 | ({ \ | ||
59 | typeof(*p) ___p1 = READ_ONCE(*p); \ | ||
60 | smp_mb(); \ | ||
61 | ___p1; \ | ||
62 | }) | ||
63 | #endif | ||
diff --git a/tools/include/linux/ring_buffer.h b/tools/include/linux/ring_buffer.h new file mode 100644 index 000000000000..9a083ae60473 --- /dev/null +++ b/tools/include/linux/ring_buffer.h | |||
@@ -0,0 +1,73 @@ | |||
1 | #ifndef _TOOLS_LINUX_RING_BUFFER_H_ | ||
2 | #define _TOOLS_LINUX_RING_BUFFER_H_ | ||
3 | |||
4 | #include <asm/barrier.h> | ||
5 | |||
6 | /* | ||
7 | * Contract with kernel for walking the perf ring buffer from | ||
8 | * user space requires the following barrier pairing (quote | ||
9 | * from kernel/events/ring_buffer.c): | ||
10 | * | ||
11 | * Since the mmap() consumer (userspace) can run on a | ||
12 | * different CPU: | ||
13 | * | ||
14 | * kernel user | ||
15 | * | ||
16 | * if (LOAD ->data_tail) { LOAD ->data_head | ||
17 | * (A) smp_rmb() (C) | ||
18 | * STORE $data LOAD $data | ||
19 | * smp_wmb() (B) smp_mb() (D) | ||
20 | * STORE ->data_head STORE ->data_tail | ||
21 | * } | ||
22 | * | ||
23 | * Where A pairs with D, and B pairs with C. | ||
24 | * | ||
25 | * In our case A is a control dependency that separates the | ||
26 | * load of the ->data_tail and the stores of $data. In case | ||
27 | * ->data_tail indicates there is no room in the buffer to | ||
28 | * store $data we do not. | ||
29 | * | ||
30 | * D needs to be a full barrier since it separates the data | ||
31 | * READ from the tail WRITE. | ||
32 | * | ||
33 | * For B a WMB is sufficient since it separates two WRITEs, | ||
34 | * and for C an RMB is sufficient since it separates two READs. | ||
35 | * | ||
36 | * Note, instead of B, C, D we could also use smp_store_release() | ||
37 | * in B and D as well as smp_load_acquire() in C. | ||
38 | * | ||
39 | * However, this optimization does not make sense for all kernel | ||
40 | * supported architectures since for a fair number it would | ||
41 | * resolve into READ_ONCE() + smp_mb() pair for smp_load_acquire(), | ||
42 | * and smp_mb() + WRITE_ONCE() pair for smp_store_release(). | ||
43 | * | ||
44 | * Thus for those smp_wmb() in B and smp_rmb() in C would still | ||
45 | * be less expensive. For the case of D this has either the same | ||
46 | * cost or is less expensive, for example, due to TSO x86 can | ||
47 | * avoid the CPU barrier entirely. | ||
48 | */ | ||
49 | |||
50 | static inline u64 ring_buffer_read_head(struct perf_event_mmap_page *base) | ||
51 | { | ||
52 | /* | ||
53 | * Architectures where smp_load_acquire() does not fallback to | ||
54 | * READ_ONCE() + smp_mb() pair. | ||
55 | */ | ||
56 | #if defined(__x86_64__) || defined(__aarch64__) || defined(__powerpc64__) || \ | ||
57 | defined(__ia64__) || defined(__sparc__) && defined(__arch64__) | ||
58 | return smp_load_acquire(&base->data_head); | ||
59 | #else | ||
60 | u64 head = READ_ONCE(base->data_head); | ||
61 | |||
62 | smp_rmb(); | ||
63 | return head; | ||
64 | #endif | ||
65 | } | ||
66 | |||
67 | static inline void ring_buffer_write_tail(struct perf_event_mmap_page *base, | ||
68 | u64 tail) | ||
69 | { | ||
70 | smp_store_release(&base->data_tail, tail); | ||
71 | } | ||
72 | |||
73 | #endif /* _TOOLS_LINUX_RING_BUFFER_H_ */ | ||
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 66917a4eba27..852dc17ab47a 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h | |||
@@ -103,6 +103,7 @@ enum bpf_cmd { | |||
103 | BPF_BTF_LOAD, | 103 | BPF_BTF_LOAD, |
104 | BPF_BTF_GET_FD_BY_ID, | 104 | BPF_BTF_GET_FD_BY_ID, |
105 | BPF_TASK_FD_QUERY, | 105 | BPF_TASK_FD_QUERY, |
106 | BPF_MAP_LOOKUP_AND_DELETE_ELEM, | ||
106 | }; | 107 | }; |
107 | 108 | ||
108 | enum bpf_map_type { | 109 | enum bpf_map_type { |
@@ -127,6 +128,9 @@ enum bpf_map_type { | |||
127 | BPF_MAP_TYPE_SOCKHASH, | 128 | BPF_MAP_TYPE_SOCKHASH, |
128 | BPF_MAP_TYPE_CGROUP_STORAGE, | 129 | BPF_MAP_TYPE_CGROUP_STORAGE, |
129 | BPF_MAP_TYPE_REUSEPORT_SOCKARRAY, | 130 | BPF_MAP_TYPE_REUSEPORT_SOCKARRAY, |
131 | BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE, | ||
132 | BPF_MAP_TYPE_QUEUE, | ||
133 | BPF_MAP_TYPE_STACK, | ||
130 | }; | 134 | }; |
131 | 135 | ||
132 | enum bpf_prog_type { | 136 | enum bpf_prog_type { |
@@ -152,6 +156,7 @@ enum bpf_prog_type { | |||
152 | BPF_PROG_TYPE_LWT_SEG6LOCAL, | 156 | BPF_PROG_TYPE_LWT_SEG6LOCAL, |
153 | BPF_PROG_TYPE_LIRC_MODE2, | 157 | BPF_PROG_TYPE_LIRC_MODE2, |
154 | BPF_PROG_TYPE_SK_REUSEPORT, | 158 | BPF_PROG_TYPE_SK_REUSEPORT, |
159 | BPF_PROG_TYPE_FLOW_DISSECTOR, | ||
155 | }; | 160 | }; |
156 | 161 | ||
157 | enum bpf_attach_type { | 162 | enum bpf_attach_type { |
@@ -172,6 +177,7 @@ enum bpf_attach_type { | |||
172 | BPF_CGROUP_UDP4_SENDMSG, | 177 | BPF_CGROUP_UDP4_SENDMSG, |
173 | BPF_CGROUP_UDP6_SENDMSG, | 178 | BPF_CGROUP_UDP6_SENDMSG, |
174 | BPF_LIRC_MODE2, | 179 | BPF_LIRC_MODE2, |
180 | BPF_FLOW_DISSECTOR, | ||
175 | __MAX_BPF_ATTACH_TYPE | 181 | __MAX_BPF_ATTACH_TYPE |
176 | }; | 182 | }; |
177 | 183 | ||
@@ -459,6 +465,28 @@ union bpf_attr { | |||
459 | * Return | 465 | * Return |
460 | * 0 on success, or a negative error in case of failure. | 466 | * 0 on success, or a negative error in case of failure. |
461 | * | 467 | * |
468 | * int bpf_map_push_elem(struct bpf_map *map, const void *value, u64 flags) | ||
469 | * Description | ||
470 | * Push an element *value* in *map*. *flags* is one of: | ||
471 | * | ||
472 | * **BPF_EXIST** | ||
473 | * If the queue/stack is full, the oldest element is removed to | ||
474 | * make room for this. | ||
475 | * Return | ||
476 | * 0 on success, or a negative error in case of failure. | ||
477 | * | ||
478 | * int bpf_map_pop_elem(struct bpf_map *map, void *value) | ||
479 | * Description | ||
480 | * Pop an element from *map*. | ||
481 | * Return | ||
482 | * 0 on success, or a negative error in case of failure. | ||
483 | * | ||
484 | * int bpf_map_peek_elem(struct bpf_map *map, void *value) | ||
485 | * Description | ||
486 | * Get an element from *map* without removing it. | ||
487 | * Return | ||
488 | * 0 on success, or a negative error in case of failure. | ||
489 | * | ||
462 | * int bpf_probe_read(void *dst, u32 size, const void *src) | 490 | * int bpf_probe_read(void *dst, u32 size, const void *src) |
463 | * Description | 491 | * Description |
464 | * For tracing programs, safely attempt to read *size* bytes from | 492 | * For tracing programs, safely attempt to read *size* bytes from |
@@ -1430,7 +1458,7 @@ union bpf_attr { | |||
1430 | * Return | 1458 | * Return |
1431 | * 0 on success, or a negative error in case of failure. | 1459 | * 0 on success, or a negative error in case of failure. |
1432 | * | 1460 | * |
1433 | * int bpf_skb_adjust_room(struct sk_buff *skb, u32 len_diff, u32 mode, u64 flags) | 1461 | * int bpf_skb_adjust_room(struct sk_buff *skb, s32 len_diff, u32 mode, u64 flags) |
1434 | * Description | 1462 | * Description |
1435 | * Grow or shrink the room for data in the packet associated to | 1463 | * Grow or shrink the room for data in the packet associated to |
1436 | * *skb* by *len_diff*, and according to the selected *mode*. | 1464 | * *skb* by *len_diff*, and according to the selected *mode*. |
@@ -2141,6 +2169,94 @@ union bpf_attr { | |||
2141 | * request in the skb. | 2169 | * request in the skb. |
2142 | * Return | 2170 | * Return |
2143 | * 0 on success, or a negative error in case of failure. | 2171 | * 0 on success, or a negative error in case of failure. |
2172 | * | ||
2173 | * struct bpf_sock *bpf_sk_lookup_tcp(void *ctx, struct bpf_sock_tuple *tuple, u32 tuple_size, u32 netns, u64 flags) | ||
2174 | * Description | ||
2175 | * Look for TCP socket matching *tuple*, optionally in a child | ||
2176 | * network namespace *netns*. The return value must be checked, | ||
2177 | * and if non-NULL, released via **bpf_sk_release**\ (). | ||
2178 | * | ||
2179 | * The *ctx* should point to the context of the program, such as | ||
2180 | * the skb or socket (depending on the hook in use). This is used | ||
2181 | * to determine the base network namespace for the lookup. | ||
2182 | * | ||
2183 | * *tuple_size* must be one of: | ||
2184 | * | ||
2185 | * **sizeof**\ (*tuple*\ **->ipv4**) | ||
2186 | * Look for an IPv4 socket. | ||
2187 | * **sizeof**\ (*tuple*\ **->ipv6**) | ||
2188 | * Look for an IPv6 socket. | ||
2189 | * | ||
2190 | * If the *netns* is zero, then the socket lookup table in the | ||
2191 | * netns associated with the *ctx* will be used. For the TC hooks, | ||
2192 | * this in the netns of the device in the skb. For socket hooks, | ||
2193 | * this in the netns of the socket. If *netns* is non-zero, then | ||
2194 | * it specifies the ID of the netns relative to the netns | ||
2195 | * associated with the *ctx*. | ||
2196 | * | ||
2197 | * All values for *flags* are reserved for future usage, and must | ||
2198 | * be left at zero. | ||
2199 | * | ||
2200 | * This helper is available only if the kernel was compiled with | ||
2201 | * **CONFIG_NET** configuration option. | ||
2202 | * Return | ||
2203 | * Pointer to *struct bpf_sock*, or NULL in case of failure. | ||
2204 | * | ||
2205 | * struct bpf_sock *bpf_sk_lookup_udp(void *ctx, struct bpf_sock_tuple *tuple, u32 tuple_size, u32 netns, u64 flags) | ||
2206 | * Description | ||
2207 | * Look for UDP socket matching *tuple*, optionally in a child | ||
2208 | * network namespace *netns*. The return value must be checked, | ||
2209 | * and if non-NULL, released via **bpf_sk_release**\ (). | ||
2210 | * | ||
2211 | * The *ctx* should point to the context of the program, such as | ||
2212 | * the skb or socket (depending on the hook in use). This is used | ||
2213 | * to determine the base network namespace for the lookup. | ||
2214 | * | ||
2215 | * *tuple_size* must be one of: | ||
2216 | * | ||
2217 | * **sizeof**\ (*tuple*\ **->ipv4**) | ||
2218 | * Look for an IPv4 socket. | ||
2219 | * **sizeof**\ (*tuple*\ **->ipv6**) | ||
2220 | * Look for an IPv6 socket. | ||
2221 | * | ||
2222 | * If the *netns* is zero, then the socket lookup table in the | ||
2223 | * netns associated with the *ctx* will be used. For the TC hooks, | ||
2224 | * this in the netns of the device in the skb. For socket hooks, | ||
2225 | * this in the netns of the socket. If *netns* is non-zero, then | ||
2226 | * it specifies the ID of the netns relative to the netns | ||
2227 | * associated with the *ctx*. | ||
2228 | * | ||
2229 | * All values for *flags* are reserved for future usage, and must | ||
2230 | * be left at zero. | ||
2231 | * | ||
2232 | * This helper is available only if the kernel was compiled with | ||
2233 | * **CONFIG_NET** configuration option. | ||
2234 | * Return | ||
2235 | * Pointer to *struct bpf_sock*, or NULL in case of failure. | ||
2236 | * | ||
2237 | * int bpf_sk_release(struct bpf_sock *sk) | ||
2238 | * Description | ||
2239 | * Release the reference held by *sock*. *sock* must be a non-NULL | ||
2240 | * pointer that was returned from bpf_sk_lookup_xxx\ (). | ||
2241 | * Return | ||
2242 | * 0 on success, or a negative error in case of failure. | ||
2243 | * | ||
2244 | * int bpf_msg_push_data(struct sk_buff *skb, u32 start, u32 len, u64 flags) | ||
2245 | * Description | ||
2246 | * For socket policies, insert *len* bytes into msg at offset | ||
2247 | * *start*. | ||
2248 | * | ||
2249 | * If a program of type **BPF_PROG_TYPE_SK_MSG** is run on a | ||
2250 | * *msg* it may want to insert metadata or options into the msg. | ||
2251 | * This can later be read and used by any of the lower layer BPF | ||
2252 | * hooks. | ||
2253 | * | ||
2254 | * This helper may fail if under memory pressure (a malloc | ||
2255 | * fails) in these cases BPF programs will get an appropriate | ||
2256 | * error and BPF programs will need to handle them. | ||
2257 | * | ||
2258 | * Return | ||
2259 | * 0 on success, or a negative error in case of failure. | ||
2144 | */ | 2260 | */ |
2145 | #define __BPF_FUNC_MAPPER(FN) \ | 2261 | #define __BPF_FUNC_MAPPER(FN) \ |
2146 | FN(unspec), \ | 2262 | FN(unspec), \ |
@@ -2226,7 +2342,14 @@ union bpf_attr { | |||
2226 | FN(get_current_cgroup_id), \ | 2342 | FN(get_current_cgroup_id), \ |
2227 | FN(get_local_storage), \ | 2343 | FN(get_local_storage), \ |
2228 | FN(sk_select_reuseport), \ | 2344 | FN(sk_select_reuseport), \ |
2229 | FN(skb_ancestor_cgroup_id), | 2345 | FN(skb_ancestor_cgroup_id), \ |
2346 | FN(sk_lookup_tcp), \ | ||
2347 | FN(sk_lookup_udp), \ | ||
2348 | FN(sk_release), \ | ||
2349 | FN(map_push_elem), \ | ||
2350 | FN(map_pop_elem), \ | ||
2351 | FN(map_peek_elem), \ | ||
2352 | FN(msg_push_data), | ||
2230 | 2353 | ||
2231 | /* integer value in 'imm' field of BPF_CALL instruction selects which helper | 2354 | /* integer value in 'imm' field of BPF_CALL instruction selects which helper |
2232 | * function eBPF program intends to call | 2355 | * function eBPF program intends to call |
@@ -2333,6 +2456,7 @@ struct __sk_buff { | |||
2333 | /* ... here. */ | 2456 | /* ... here. */ |
2334 | 2457 | ||
2335 | __u32 data_meta; | 2458 | __u32 data_meta; |
2459 | struct bpf_flow_keys *flow_keys; | ||
2336 | }; | 2460 | }; |
2337 | 2461 | ||
2338 | struct bpf_tunnel_key { | 2462 | struct bpf_tunnel_key { |
@@ -2395,6 +2519,23 @@ struct bpf_sock { | |||
2395 | */ | 2519 | */ |
2396 | }; | 2520 | }; |
2397 | 2521 | ||
2522 | struct bpf_sock_tuple { | ||
2523 | union { | ||
2524 | struct { | ||
2525 | __be32 saddr; | ||
2526 | __be32 daddr; | ||
2527 | __be16 sport; | ||
2528 | __be16 dport; | ||
2529 | } ipv4; | ||
2530 | struct { | ||
2531 | __be32 saddr[4]; | ||
2532 | __be32 daddr[4]; | ||
2533 | __be16 sport; | ||
2534 | __be16 dport; | ||
2535 | } ipv6; | ||
2536 | }; | ||
2537 | }; | ||
2538 | |||
2398 | #define XDP_PACKET_HEADROOM 256 | 2539 | #define XDP_PACKET_HEADROOM 256 |
2399 | 2540 | ||
2400 | /* User return codes for XDP prog type. | 2541 | /* User return codes for XDP prog type. |
@@ -2778,4 +2919,27 @@ enum bpf_task_fd_type { | |||
2778 | BPF_FD_TYPE_URETPROBE, /* filename + offset */ | 2919 | BPF_FD_TYPE_URETPROBE, /* filename + offset */ |
2779 | }; | 2920 | }; |
2780 | 2921 | ||
2922 | struct bpf_flow_keys { | ||
2923 | __u16 nhoff; | ||
2924 | __u16 thoff; | ||
2925 | __u16 addr_proto; /* ETH_P_* of valid addrs */ | ||
2926 | __u8 is_frag; | ||
2927 | __u8 is_first_frag; | ||
2928 | __u8 is_encap; | ||
2929 | __u8 ip_proto; | ||
2930 | __be16 n_proto; | ||
2931 | __be16 sport; | ||
2932 | __be16 dport; | ||
2933 | union { | ||
2934 | struct { | ||
2935 | __be32 ipv4_src; | ||
2936 | __be32 ipv4_dst; | ||
2937 | }; | ||
2938 | struct { | ||
2939 | __u32 ipv6_src[4]; /* in6_addr; network order */ | ||
2940 | __u32 ipv6_dst[4]; /* in6_addr; network order */ | ||
2941 | }; | ||
2942 | }; | ||
2943 | }; | ||
2944 | |||
2781 | #endif /* _UAPI__LINUX_BPF_H__ */ | 2945 | #endif /* _UAPI__LINUX_BPF_H__ */ |
diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h index 43391e2d1153..58faab897201 100644 --- a/tools/include/uapi/linux/if_link.h +++ b/tools/include/uapi/linux/if_link.h | |||
@@ -161,6 +161,7 @@ enum { | |||
161 | IFLA_EVENT, | 161 | IFLA_EVENT, |
162 | IFLA_NEW_NETNSID, | 162 | IFLA_NEW_NETNSID, |
163 | IFLA_IF_NETNSID, | 163 | IFLA_IF_NETNSID, |
164 | IFLA_TARGET_NETNSID = IFLA_IF_NETNSID, /* new alias */ | ||
164 | IFLA_CARRIER_UP_COUNT, | 165 | IFLA_CARRIER_UP_COUNT, |
165 | IFLA_CARRIER_DOWN_COUNT, | 166 | IFLA_CARRIER_DOWN_COUNT, |
166 | IFLA_NEW_IFINDEX, | 167 | IFLA_NEW_IFINDEX, |
@@ -554,6 +555,7 @@ enum { | |||
554 | IFLA_GENEVE_UDP_ZERO_CSUM6_TX, | 555 | IFLA_GENEVE_UDP_ZERO_CSUM6_TX, |
555 | IFLA_GENEVE_UDP_ZERO_CSUM6_RX, | 556 | IFLA_GENEVE_UDP_ZERO_CSUM6_RX, |
556 | IFLA_GENEVE_LABEL, | 557 | IFLA_GENEVE_LABEL, |
558 | IFLA_GENEVE_TTL_INHERIT, | ||
557 | __IFLA_GENEVE_MAX | 559 | __IFLA_GENEVE_MAX |
558 | }; | 560 | }; |
559 | #define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1) | 561 | #define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1) |
diff --git a/tools/include/uapi/linux/kvm.h b/tools/include/uapi/linux/kvm.h index 251be353f950..2875ce85b322 100644 --- a/tools/include/uapi/linux/kvm.h +++ b/tools/include/uapi/linux/kvm.h | |||
@@ -719,6 +719,7 @@ struct kvm_ppc_one_seg_page_size { | |||
719 | 719 | ||
720 | #define KVM_PPC_PAGE_SIZES_REAL 0x00000001 | 720 | #define KVM_PPC_PAGE_SIZES_REAL 0x00000001 |
721 | #define KVM_PPC_1T_SEGMENTS 0x00000002 | 721 | #define KVM_PPC_1T_SEGMENTS 0x00000002 |
722 | #define KVM_PPC_NO_HASH 0x00000004 | ||
722 | 723 | ||
723 | struct kvm_ppc_smmu_info { | 724 | struct kvm_ppc_smmu_info { |
724 | __u64 flags; | 725 | __u64 flags; |
@@ -953,6 +954,10 @@ struct kvm_ppc_resize_hpt { | |||
953 | #define KVM_CAP_NESTED_STATE 157 | 954 | #define KVM_CAP_NESTED_STATE 157 |
954 | #define KVM_CAP_ARM_INJECT_SERROR_ESR 158 | 955 | #define KVM_CAP_ARM_INJECT_SERROR_ESR 158 |
955 | #define KVM_CAP_MSR_PLATFORM_INFO 159 | 956 | #define KVM_CAP_MSR_PLATFORM_INFO 159 |
957 | #define KVM_CAP_PPC_NESTED_HV 160 | ||
958 | #define KVM_CAP_HYPERV_SEND_IPI 161 | ||
959 | #define KVM_CAP_COALESCED_PIO 162 | ||
960 | #define KVM_CAP_HYPERV_ENLIGHTENED_VMCS 163 | ||
956 | 961 | ||
957 | #ifdef KVM_CAP_IRQ_ROUTING | 962 | #ifdef KVM_CAP_IRQ_ROUTING |
958 | 963 | ||
diff --git a/tools/include/uapi/linux/tls.h b/tools/include/uapi/linux/tls.h new file mode 100644 index 000000000000..ff02287495ac --- /dev/null +++ b/tools/include/uapi/linux/tls.h | |||
@@ -0,0 +1,78 @@ | |||
1 | /* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR Linux-OpenIB) */ | ||
2 | /* | ||
3 | * Copyright (c) 2016-2017, Mellanox Technologies. All rights reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the | ||
9 | * OpenIB.org BSD license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or | ||
12 | * without modification, are permitted provided that the following | ||
13 | * conditions are met: | ||
14 | * | ||
15 | * - Redistributions of source code must retain the above | ||
16 | * copyright notice, this list of conditions and the following | ||
17 | * disclaimer. | ||
18 | * | ||
19 | * - Redistributions in binary form must reproduce the above | ||
20 | * copyright notice, this list of conditions and the following | ||
21 | * disclaimer in the documentation and/or other materials | ||
22 | * provided with the distribution. | ||
23 | * | ||
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
28 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
29 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
31 | * SOFTWARE. | ||
32 | */ | ||
33 | |||
34 | #ifndef _UAPI_LINUX_TLS_H | ||
35 | #define _UAPI_LINUX_TLS_H | ||
36 | |||
37 | #include <linux/types.h> | ||
38 | |||
39 | /* TLS socket options */ | ||
40 | #define TLS_TX 1 /* Set transmit parameters */ | ||
41 | #define TLS_RX 2 /* Set receive parameters */ | ||
42 | |||
43 | /* Supported versions */ | ||
44 | #define TLS_VERSION_MINOR(ver) ((ver) & 0xFF) | ||
45 | #define TLS_VERSION_MAJOR(ver) (((ver) >> 8) & 0xFF) | ||
46 | |||
47 | #define TLS_VERSION_NUMBER(id) ((((id##_VERSION_MAJOR) & 0xFF) << 8) | \ | ||
48 | ((id##_VERSION_MINOR) & 0xFF)) | ||
49 | |||
50 | #define TLS_1_2_VERSION_MAJOR 0x3 | ||
51 | #define TLS_1_2_VERSION_MINOR 0x3 | ||
52 | #define TLS_1_2_VERSION TLS_VERSION_NUMBER(TLS_1_2) | ||
53 | |||
54 | /* Supported ciphers */ | ||
55 | #define TLS_CIPHER_AES_GCM_128 51 | ||
56 | #define TLS_CIPHER_AES_GCM_128_IV_SIZE 8 | ||
57 | #define TLS_CIPHER_AES_GCM_128_KEY_SIZE 16 | ||
58 | #define TLS_CIPHER_AES_GCM_128_SALT_SIZE 4 | ||
59 | #define TLS_CIPHER_AES_GCM_128_TAG_SIZE 16 | ||
60 | #define TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE 8 | ||
61 | |||
62 | #define TLS_SET_RECORD_TYPE 1 | ||
63 | #define TLS_GET_RECORD_TYPE 2 | ||
64 | |||
65 | struct tls_crypto_info { | ||
66 | __u16 version; | ||
67 | __u16 cipher_type; | ||
68 | }; | ||
69 | |||
70 | struct tls12_crypto_info_aes_gcm_128 { | ||
71 | struct tls_crypto_info info; | ||
72 | unsigned char iv[TLS_CIPHER_AES_GCM_128_IV_SIZE]; | ||
73 | unsigned char key[TLS_CIPHER_AES_GCM_128_KEY_SIZE]; | ||
74 | unsigned char salt[TLS_CIPHER_AES_GCM_128_SALT_SIZE]; | ||
75 | unsigned char rec_seq[TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE]; | ||
76 | }; | ||
77 | |||
78 | #endif /* _UAPI_LINUX_TLS_H */ | ||
diff --git a/tools/lib/bpf/Build b/tools/lib/bpf/Build index 6eb9bacd1948..7bc31c905018 100644 --- a/tools/lib/bpf/Build +++ b/tools/lib/bpf/Build | |||
@@ -1 +1 @@ | |||
libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf_errno.o str_error.o | libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf_errno.o str_error.o netlink.o | ||
diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile index d49902e818b5..425b480bda75 100644 --- a/tools/lib/bpf/Makefile +++ b/tools/lib/bpf/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 | 1 | # SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) |
2 | # Most of this file is copied from tools/lib/traceevent/Makefile | 2 | # Most of this file is copied from tools/lib/traceevent/Makefile |
3 | 3 | ||
4 | BPF_VERSION = 0 | 4 | BPF_VERSION = 0 |
@@ -69,7 +69,7 @@ FEATURE_USER = .libbpf | |||
69 | FEATURE_TESTS = libelf libelf-mmap bpf reallocarray | 69 | FEATURE_TESTS = libelf libelf-mmap bpf reallocarray |
70 | FEATURE_DISPLAY = libelf bpf | 70 | FEATURE_DISPLAY = libelf bpf |
71 | 71 | ||
72 | INCLUDES = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(ARCH)/include/uapi -I$(srctree)/tools/include/uapi -I$(srctree)/tools/perf | 72 | INCLUDES = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(ARCH)/include/uapi -I$(srctree)/tools/include/uapi |
73 | FEATURE_CHECK_CFLAGS-bpf = $(INCLUDES) | 73 | FEATURE_CHECK_CFLAGS-bpf = $(INCLUDES) |
74 | 74 | ||
75 | check_feat := 1 | 75 | check_feat := 1 |
@@ -125,6 +125,7 @@ override CFLAGS += $(EXTRA_WARNINGS) | |||
125 | override CFLAGS += -Werror -Wall | 125 | override CFLAGS += -Werror -Wall |
126 | override CFLAGS += -fPIC | 126 | override CFLAGS += -fPIC |
127 | override CFLAGS += $(INCLUDES) | 127 | override CFLAGS += $(INCLUDES) |
128 | override CFLAGS += -fvisibility=hidden | ||
128 | 129 | ||
129 | ifeq ($(VERBOSE),1) | 130 | ifeq ($(VERBOSE),1) |
130 | Q = | 131 | Q = |
diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 60aa4ca8b2c5..03f9bcc4ef50 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c | |||
@@ -1,4 +1,4 @@ | |||
1 | // SPDX-License-Identifier: LGPL-2.1 | 1 | // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * common eBPF ELF operations. | 4 | * common eBPF ELF operations. |
@@ -28,16 +28,8 @@ | |||
28 | #include <linux/bpf.h> | 28 | #include <linux/bpf.h> |
29 | #include "bpf.h" | 29 | #include "bpf.h" |
30 | #include "libbpf.h" | 30 | #include "libbpf.h" |
31 | #include "nlattr.h" | ||
32 | #include <linux/rtnetlink.h> | ||
33 | #include <linux/if_link.h> | ||
34 | #include <sys/socket.h> | ||
35 | #include <errno.h> | 31 | #include <errno.h> |
36 | 32 | ||
37 | #ifndef SOL_NETLINK | ||
38 | #define SOL_NETLINK 270 | ||
39 | #endif | ||
40 | |||
41 | /* | 33 | /* |
42 | * When building perf, unistd.h is overridden. __NR_bpf is | 34 | * When building perf, unistd.h is overridden. __NR_bpf is |
43 | * required to be defined explicitly. | 35 | * required to be defined explicitly. |
@@ -286,6 +278,18 @@ int bpf_map_lookup_elem(int fd, const void *key, void *value) | |||
286 | return sys_bpf(BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr)); | 278 | return sys_bpf(BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr)); |
287 | } | 279 | } |
288 | 280 | ||
281 | int bpf_map_lookup_and_delete_elem(int fd, const void *key, void *value) | ||
282 | { | ||
283 | union bpf_attr attr; | ||
284 | |||
285 | bzero(&attr, sizeof(attr)); | ||
286 | attr.map_fd = fd; | ||
287 | attr.key = ptr_to_u64(key); | ||
288 | attr.value = ptr_to_u64(value); | ||
289 | |||
290 | return sys_bpf(BPF_MAP_LOOKUP_AND_DELETE_ELEM, &attr, sizeof(attr)); | ||
291 | } | ||
292 | |||
289 | int bpf_map_delete_elem(int fd, const void *key) | 293 | int bpf_map_delete_elem(int fd, const void *key) |
290 | { | 294 | { |
291 | union bpf_attr attr; | 295 | union bpf_attr attr; |
@@ -499,127 +503,6 @@ int bpf_raw_tracepoint_open(const char *name, int prog_fd) | |||
499 | return sys_bpf(BPF_RAW_TRACEPOINT_OPEN, &attr, sizeof(attr)); | 503 | return sys_bpf(BPF_RAW_TRACEPOINT_OPEN, &attr, sizeof(attr)); |
500 | } | 504 | } |
501 | 505 | ||
502 | int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags) | ||
503 | { | ||
504 | struct sockaddr_nl sa; | ||
505 | int sock, seq = 0, len, ret = -1; | ||
506 | char buf[4096]; | ||
507 | struct nlattr *nla, *nla_xdp; | ||
508 | struct { | ||
509 | struct nlmsghdr nh; | ||
510 | struct ifinfomsg ifinfo; | ||
511 | char attrbuf[64]; | ||
512 | } req; | ||
513 | struct nlmsghdr *nh; | ||
514 | struct nlmsgerr *err; | ||
515 | socklen_t addrlen; | ||
516 | int one = 1; | ||
517 | |||
518 | memset(&sa, 0, sizeof(sa)); | ||
519 | sa.nl_family = AF_NETLINK; | ||
520 | |||
521 | sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); | ||
522 | if (sock < 0) { | ||
523 | return -errno; | ||
524 | } | ||
525 | |||
526 | if (setsockopt(sock, SOL_NETLINK, NETLINK_EXT_ACK, | ||
527 | &one, sizeof(one)) < 0) { | ||
528 | fprintf(stderr, "Netlink error reporting not supported\n"); | ||
529 | } | ||
530 | |||
531 | if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) { | ||
532 | ret = -errno; | ||
533 | goto cleanup; | ||
534 | } | ||
535 | |||
536 | addrlen = sizeof(sa); | ||
537 | if (getsockname(sock, (struct sockaddr *)&sa, &addrlen) < 0) { | ||
538 | ret = -errno; | ||
539 | goto cleanup; | ||
540 | } | ||
541 | |||
542 | if (addrlen != sizeof(sa)) { | ||
543 | ret = -LIBBPF_ERRNO__INTERNAL; | ||
544 | goto cleanup; | ||
545 | } | ||
546 | |||
547 | memset(&req, 0, sizeof(req)); | ||
548 | req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); | ||
549 | req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; | ||
550 | req.nh.nlmsg_type = RTM_SETLINK; | ||
551 | req.nh.nlmsg_pid = 0; | ||
552 | req.nh.nlmsg_seq = ++seq; | ||
553 | req.ifinfo.ifi_family = AF_UNSPEC; | ||
554 | req.ifinfo.ifi_index = ifindex; | ||
555 | |||
556 | /* started nested attribute for XDP */ | ||
557 | nla = (struct nlattr *)(((char *)&req) | ||
558 | + NLMSG_ALIGN(req.nh.nlmsg_len)); | ||
559 | nla->nla_type = NLA_F_NESTED | IFLA_XDP; | ||
560 | nla->nla_len = NLA_HDRLEN; | ||
561 | |||
562 | /* add XDP fd */ | ||
563 | nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len); | ||
564 | nla_xdp->nla_type = IFLA_XDP_FD; | ||
565 | nla_xdp->nla_len = NLA_HDRLEN + sizeof(int); | ||
566 | memcpy((char *)nla_xdp + NLA_HDRLEN, &fd, sizeof(fd)); | ||
567 | nla->nla_len += nla_xdp->nla_len; | ||
568 | |||
569 | /* if user passed in any flags, add those too */ | ||
570 | if (flags) { | ||
571 | nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len); | ||
572 | nla_xdp->nla_type = IFLA_XDP_FLAGS; | ||
573 | nla_xdp->nla_len = NLA_HDRLEN + sizeof(flags); | ||
574 | memcpy((char *)nla_xdp + NLA_HDRLEN, &flags, sizeof(flags)); | ||
575 | nla->nla_len += nla_xdp->nla_len; | ||
576 | } | ||
577 | |||
578 | req.nh.nlmsg_len += NLA_ALIGN(nla->nla_len); | ||
579 | |||
580 | if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) { | ||
581 | ret = -errno; | ||
582 | goto cleanup; | ||
583 | } | ||
584 | |||
585 | len = recv(sock, buf, sizeof(buf), 0); | ||
586 | if (len < 0) { | ||
587 | ret = -errno; | ||
588 | goto cleanup; | ||
589 | } | ||
590 | |||
591 | for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); | ||
592 | nh = NLMSG_NEXT(nh, len)) { | ||
593 | if (nh->nlmsg_pid != sa.nl_pid) { | ||
594 | ret = -LIBBPF_ERRNO__WRNGPID; | ||
595 | goto cleanup; | ||
596 | } | ||
597 | if (nh->nlmsg_seq != seq) { | ||
598 | ret = -LIBBPF_ERRNO__INVSEQ; | ||
599 | goto cleanup; | ||
600 | } | ||
601 | switch (nh->nlmsg_type) { | ||
602 | case NLMSG_ERROR: | ||
603 | err = (struct nlmsgerr *)NLMSG_DATA(nh); | ||
604 | if (!err->error) | ||
605 | continue; | ||
606 | ret = err->error; | ||
607 | nla_dump_errormsg(nh); | ||
608 | goto cleanup; | ||
609 | case NLMSG_DONE: | ||
610 | break; | ||
611 | default: | ||
612 | break; | ||
613 | } | ||
614 | } | ||
615 | |||
616 | ret = 0; | ||
617 | |||
618 | cleanup: | ||
619 | close(sock); | ||
620 | return ret; | ||
621 | } | ||
622 | |||
623 | int bpf_load_btf(void *btf, __u32 btf_size, char *log_buf, __u32 log_buf_size, | 506 | int bpf_load_btf(void *btf, __u32 btf_size, char *log_buf, __u32 log_buf_size, |
624 | bool do_log) | 507 | bool do_log) |
625 | { | 508 | { |
diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index 6f38164b2618..26a51538213c 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* SPDX-License-Identifier: LGPL-2.1 */ | 1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * common eBPF ELF operations. | 4 | * common eBPF ELF operations. |
@@ -20,13 +20,17 @@ | |||
20 | * You should have received a copy of the GNU Lesser General Public | 20 | * You should have received a copy of the GNU Lesser General Public |
21 | * License along with this program; if not, see <http://www.gnu.org/licenses> | 21 | * License along with this program; if not, see <http://www.gnu.org/licenses> |
22 | */ | 22 | */ |
23 | #ifndef __BPF_BPF_H | 23 | #ifndef __LIBBPF_BPF_H |
24 | #define __BPF_BPF_H | 24 | #define __LIBBPF_BPF_H |
25 | 25 | ||
26 | #include <linux/bpf.h> | 26 | #include <linux/bpf.h> |
27 | #include <stdbool.h> | 27 | #include <stdbool.h> |
28 | #include <stddef.h> | 28 | #include <stddef.h> |
29 | 29 | ||
30 | #ifndef LIBBPF_API | ||
31 | #define LIBBPF_API __attribute__((visibility("default"))) | ||
32 | #endif | ||
33 | |||
30 | struct bpf_create_map_attr { | 34 | struct bpf_create_map_attr { |
31 | const char *name; | 35 | const char *name; |
32 | enum bpf_map_type map_type; | 36 | enum bpf_map_type map_type; |
@@ -42,21 +46,24 @@ struct bpf_create_map_attr { | |||
42 | __u32 inner_map_fd; | 46 | __u32 inner_map_fd; |
43 | }; | 47 | }; |
44 | 48 | ||
45 | int bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr); | 49 | LIBBPF_API int |
46 | int bpf_create_map_node(enum bpf_map_type map_type, const char *name, | 50 | bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr); |
47 | int key_size, int value_size, int max_entries, | 51 | LIBBPF_API int bpf_create_map_node(enum bpf_map_type map_type, const char *name, |
48 | __u32 map_flags, int node); | 52 | int key_size, int value_size, |
49 | int bpf_create_map_name(enum bpf_map_type map_type, const char *name, | 53 | int max_entries, __u32 map_flags, int node); |
50 | int key_size, int value_size, int max_entries, | 54 | LIBBPF_API int bpf_create_map_name(enum bpf_map_type map_type, const char *name, |
51 | __u32 map_flags); | 55 | int key_size, int value_size, |
52 | int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size, | 56 | int max_entries, __u32 map_flags); |
53 | int max_entries, __u32 map_flags); | 57 | LIBBPF_API int bpf_create_map(enum bpf_map_type map_type, int key_size, |
54 | int bpf_create_map_in_map_node(enum bpf_map_type map_type, const char *name, | 58 | int value_size, int max_entries, __u32 map_flags); |
55 | int key_size, int inner_map_fd, int max_entries, | 59 | LIBBPF_API int bpf_create_map_in_map_node(enum bpf_map_type map_type, |
56 | __u32 map_flags, int node); | 60 | const char *name, int key_size, |
57 | int bpf_create_map_in_map(enum bpf_map_type map_type, const char *name, | 61 | int inner_map_fd, int max_entries, |
58 | int key_size, int inner_map_fd, int max_entries, | 62 | __u32 map_flags, int node); |
59 | __u32 map_flags); | 63 | LIBBPF_API int bpf_create_map_in_map(enum bpf_map_type map_type, |
64 | const char *name, int key_size, | ||
65 | int inner_map_fd, int max_entries, | ||
66 | __u32 map_flags); | ||
60 | 67 | ||
61 | struct bpf_load_program_attr { | 68 | struct bpf_load_program_attr { |
62 | enum bpf_prog_type prog_type; | 69 | enum bpf_prog_type prog_type; |
@@ -69,46 +76,56 @@ struct bpf_load_program_attr { | |||
69 | __u32 prog_ifindex; | 76 | __u32 prog_ifindex; |
70 | }; | 77 | }; |
71 | 78 | ||
79 | /* Flags to direct loading requirements */ | ||
80 | #define MAPS_RELAX_COMPAT 0x01 | ||
81 | |||
72 | /* Recommend log buffer size */ | 82 | /* Recommend log buffer size */ |
73 | #define BPF_LOG_BUF_SIZE (256 * 1024) | 83 | #define BPF_LOG_BUF_SIZE (256 * 1024) |
74 | int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr, | 84 | LIBBPF_API int |
75 | char *log_buf, size_t log_buf_sz); | 85 | bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr, |
76 | int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns, | 86 | char *log_buf, size_t log_buf_sz); |
77 | size_t insns_cnt, const char *license, | 87 | LIBBPF_API int bpf_load_program(enum bpf_prog_type type, |
78 | __u32 kern_version, char *log_buf, | 88 | const struct bpf_insn *insns, size_t insns_cnt, |
79 | size_t log_buf_sz); | 89 | const char *license, __u32 kern_version, |
80 | int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns, | 90 | char *log_buf, size_t log_buf_sz); |
81 | size_t insns_cnt, int strict_alignment, | 91 | LIBBPF_API int bpf_verify_program(enum bpf_prog_type type, |
82 | const char *license, __u32 kern_version, | 92 | const struct bpf_insn *insns, |
83 | char *log_buf, size_t log_buf_sz, int log_level); | 93 | size_t insns_cnt, int strict_alignment, |
94 | const char *license, __u32 kern_version, | ||
95 | char *log_buf, size_t log_buf_sz, | ||
96 | int log_level); | ||
84 | 97 | ||
85 | int bpf_map_update_elem(int fd, const void *key, const void *value, | 98 | LIBBPF_API int bpf_map_update_elem(int fd, const void *key, const void *value, |
86 | __u64 flags); | 99 | __u64 flags); |
87 | 100 | ||
88 | int bpf_map_lookup_elem(int fd, const void *key, void *value); | 101 | LIBBPF_API int bpf_map_lookup_elem(int fd, const void *key, void *value); |
89 | int bpf_map_delete_elem(int fd, const void *key); | 102 | LIBBPF_API int bpf_map_lookup_and_delete_elem(int fd, const void *key, |
90 | int bpf_map_get_next_key(int fd, const void *key, void *next_key); | 103 | void *value); |
91 | int bpf_obj_pin(int fd, const char *pathname); | 104 | LIBBPF_API int bpf_map_delete_elem(int fd, const void *key); |
92 | int bpf_obj_get(const char *pathname); | 105 | LIBBPF_API int bpf_map_get_next_key(int fd, const void *key, void *next_key); |
93 | int bpf_prog_attach(int prog_fd, int attachable_fd, enum bpf_attach_type type, | 106 | LIBBPF_API int bpf_obj_pin(int fd, const char *pathname); |
94 | unsigned int flags); | 107 | LIBBPF_API int bpf_obj_get(const char *pathname); |
95 | int bpf_prog_detach(int attachable_fd, enum bpf_attach_type type); | 108 | LIBBPF_API int bpf_prog_attach(int prog_fd, int attachable_fd, |
96 | int bpf_prog_detach2(int prog_fd, int attachable_fd, enum bpf_attach_type type); | 109 | enum bpf_attach_type type, unsigned int flags); |
97 | int bpf_prog_test_run(int prog_fd, int repeat, void *data, __u32 size, | 110 | LIBBPF_API int bpf_prog_detach(int attachable_fd, enum bpf_attach_type type); |
98 | void *data_out, __u32 *size_out, __u32 *retval, | 111 | LIBBPF_API int bpf_prog_detach2(int prog_fd, int attachable_fd, |
99 | __u32 *duration); | 112 | enum bpf_attach_type type); |
100 | int bpf_prog_get_next_id(__u32 start_id, __u32 *next_id); | 113 | LIBBPF_API int bpf_prog_test_run(int prog_fd, int repeat, void *data, |
101 | int bpf_map_get_next_id(__u32 start_id, __u32 *next_id); | 114 | __u32 size, void *data_out, __u32 *size_out, |
102 | int bpf_prog_get_fd_by_id(__u32 id); | 115 | __u32 *retval, __u32 *duration); |
103 | int bpf_map_get_fd_by_id(__u32 id); | 116 | LIBBPF_API int bpf_prog_get_next_id(__u32 start_id, __u32 *next_id); |
104 | int bpf_btf_get_fd_by_id(__u32 id); | 117 | LIBBPF_API int bpf_map_get_next_id(__u32 start_id, __u32 *next_id); |
105 | int bpf_obj_get_info_by_fd(int prog_fd, void *info, __u32 *info_len); | 118 | LIBBPF_API int bpf_prog_get_fd_by_id(__u32 id); |
106 | int bpf_prog_query(int target_fd, enum bpf_attach_type type, __u32 query_flags, | 119 | LIBBPF_API int bpf_map_get_fd_by_id(__u32 id); |
107 | __u32 *attach_flags, __u32 *prog_ids, __u32 *prog_cnt); | 120 | LIBBPF_API int bpf_btf_get_fd_by_id(__u32 id); |
108 | int bpf_raw_tracepoint_open(const char *name, int prog_fd); | 121 | LIBBPF_API int bpf_obj_get_info_by_fd(int prog_fd, void *info, __u32 *info_len); |
109 | int bpf_load_btf(void *btf, __u32 btf_size, char *log_buf, __u32 log_buf_size, | 122 | LIBBPF_API int bpf_prog_query(int target_fd, enum bpf_attach_type type, |
110 | bool do_log); | 123 | __u32 query_flags, __u32 *attach_flags, |
111 | int bpf_task_fd_query(int pid, int fd, __u32 flags, char *buf, __u32 *buf_len, | 124 | __u32 *prog_ids, __u32 *prog_cnt); |
112 | __u32 *prog_id, __u32 *fd_type, __u64 *probe_offset, | 125 | LIBBPF_API int bpf_raw_tracepoint_open(const char *name, int prog_fd); |
113 | __u64 *probe_addr); | 126 | LIBBPF_API int bpf_load_btf(void *btf, __u32 btf_size, char *log_buf, |
114 | #endif | 127 | __u32 log_buf_size, bool do_log); |
128 | LIBBPF_API int bpf_task_fd_query(int pid, int fd, __u32 flags, char *buf, | ||
129 | __u32 *buf_len, __u32 *prog_id, __u32 *fd_type, | ||
130 | __u64 *probe_offset, __u64 *probe_addr); | ||
131 | #endif /* __LIBBPF_BPF_H */ | ||
diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c index cf94b0770522..449591aa9900 100644 --- a/tools/lib/bpf/btf.c +++ b/tools/lib/bpf/btf.c | |||
@@ -1,4 +1,4 @@ | |||
1 | // SPDX-License-Identifier: LGPL-2.1 | 1 | // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) |
2 | /* Copyright (c) 2018 Facebook */ | 2 | /* Copyright (c) 2018 Facebook */ |
3 | 3 | ||
4 | #include <stdlib.h> | 4 | #include <stdlib.h> |
diff --git a/tools/lib/bpf/btf.h b/tools/lib/bpf/btf.h index 4897e0724d4e..b77e7080f7e7 100644 --- a/tools/lib/bpf/btf.h +++ b/tools/lib/bpf/btf.h | |||
@@ -1,11 +1,15 @@ | |||
1 | /* SPDX-License-Identifier: LGPL-2.1 */ | 1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ |
2 | /* Copyright (c) 2018 Facebook */ | 2 | /* Copyright (c) 2018 Facebook */ |
3 | 3 | ||
4 | #ifndef __BPF_BTF_H | 4 | #ifndef __LIBBPF_BTF_H |
5 | #define __BPF_BTF_H | 5 | #define __LIBBPF_BTF_H |
6 | 6 | ||
7 | #include <linux/types.h> | 7 | #include <linux/types.h> |
8 | 8 | ||
9 | #ifndef LIBBPF_API | ||
10 | #define LIBBPF_API __attribute__((visibility("default"))) | ||
11 | #endif | ||
12 | |||
9 | #define BTF_ELF_SEC ".BTF" | 13 | #define BTF_ELF_SEC ".BTF" |
10 | 14 | ||
11 | struct btf; | 15 | struct btf; |
@@ -14,13 +18,15 @@ struct btf_type; | |||
14 | typedef int (*btf_print_fn_t)(const char *, ...) | 18 | typedef int (*btf_print_fn_t)(const char *, ...) |
15 | __attribute__((format(printf, 1, 2))); | 19 | __attribute__((format(printf, 1, 2))); |
16 | 20 | ||
17 | void btf__free(struct btf *btf); | 21 | LIBBPF_API void btf__free(struct btf *btf); |
18 | struct btf *btf__new(__u8 *data, __u32 size, btf_print_fn_t err_log); | 22 | LIBBPF_API struct btf *btf__new(__u8 *data, __u32 size, btf_print_fn_t err_log); |
19 | __s32 btf__find_by_name(const struct btf *btf, const char *type_name); | 23 | LIBBPF_API __s32 btf__find_by_name(const struct btf *btf, |
20 | const struct btf_type *btf__type_by_id(const struct btf *btf, __u32 id); | 24 | const char *type_name); |
21 | __s64 btf__resolve_size(const struct btf *btf, __u32 type_id); | 25 | LIBBPF_API const struct btf_type *btf__type_by_id(const struct btf *btf, |
22 | int btf__resolve_type(const struct btf *btf, __u32 type_id); | 26 | __u32 id); |
23 | int btf__fd(const struct btf *btf); | 27 | LIBBPF_API __s64 btf__resolve_size(const struct btf *btf, __u32 type_id); |
24 | const char *btf__name_by_offset(const struct btf *btf, __u32 offset); | 28 | LIBBPF_API int btf__resolve_type(const struct btf *btf, __u32 type_id); |
29 | LIBBPF_API int btf__fd(const struct btf *btf); | ||
30 | LIBBPF_API const char *btf__name_by_offset(const struct btf *btf, __u32 offset); | ||
25 | 31 | ||
26 | #endif | 32 | #endif /* __LIBBPF_BTF_H */ |
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index bdb94939fd60..b607be7236d3 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c | |||
@@ -1,4 +1,4 @@ | |||
1 | // SPDX-License-Identifier: LGPL-2.1 | 1 | // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Common eBPF ELF object loading operations. | 4 | * Common eBPF ELF object loading operations. |
@@ -7,19 +7,6 @@ | |||
7 | * Copyright (C) 2015 Wang Nan <wangnan0@huawei.com> | 7 | * Copyright (C) 2015 Wang Nan <wangnan0@huawei.com> |
8 | * Copyright (C) 2015 Huawei Inc. | 8 | * Copyright (C) 2015 Huawei Inc. |
9 | * Copyright (C) 2017 Nicira, Inc. | 9 | * Copyright (C) 2017 Nicira, Inc. |
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU Lesser General Public | ||
13 | * License as published by the Free Software Foundation; | ||
14 | * version 2.1 of the License (not later!) | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU Lesser General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU Lesser General Public | ||
22 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
23 | */ | 10 | */ |
24 | 11 | ||
25 | #define _GNU_SOURCE | 12 | #define _GNU_SOURCE |
@@ -32,7 +19,6 @@ | |||
32 | #include <unistd.h> | 19 | #include <unistd.h> |
33 | #include <fcntl.h> | 20 | #include <fcntl.h> |
34 | #include <errno.h> | 21 | #include <errno.h> |
35 | #include <perf-sys.h> | ||
36 | #include <asm/unistd.h> | 22 | #include <asm/unistd.h> |
37 | #include <linux/err.h> | 23 | #include <linux/err.h> |
38 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
@@ -40,6 +26,8 @@ | |||
40 | #include <linux/btf.h> | 26 | #include <linux/btf.h> |
41 | #include <linux/list.h> | 27 | #include <linux/list.h> |
42 | #include <linux/limits.h> | 28 | #include <linux/limits.h> |
29 | #include <linux/perf_event.h> | ||
30 | #include <linux/ring_buffer.h> | ||
43 | #include <sys/stat.h> | 31 | #include <sys/stat.h> |
44 | #include <sys/types.h> | 32 | #include <sys/types.h> |
45 | #include <sys/vfs.h> | 33 | #include <sys/vfs.h> |
@@ -182,7 +170,7 @@ static LIST_HEAD(bpf_objects_list); | |||
182 | 170 | ||
183 | struct bpf_object { | 171 | struct bpf_object { |
184 | char license[64]; | 172 | char license[64]; |
185 | u32 kern_version; | 173 | __u32 kern_version; |
186 | 174 | ||
187 | struct bpf_program *programs; | 175 | struct bpf_program *programs; |
188 | size_t nr_programs; | 176 | size_t nr_programs; |
@@ -228,7 +216,7 @@ struct bpf_object { | |||
228 | }; | 216 | }; |
229 | #define obj_elf_valid(o) ((o)->efile.elf) | 217 | #define obj_elf_valid(o) ((o)->efile.elf) |
230 | 218 | ||
231 | static void bpf_program__unload(struct bpf_program *prog) | 219 | void bpf_program__unload(struct bpf_program *prog) |
232 | { | 220 | { |
233 | int i; | 221 | int i; |
234 | 222 | ||
@@ -470,7 +458,8 @@ static int bpf_object__elf_init(struct bpf_object *obj) | |||
470 | obj->efile.fd = open(obj->path, O_RDONLY); | 458 | obj->efile.fd = open(obj->path, O_RDONLY); |
471 | if (obj->efile.fd < 0) { | 459 | if (obj->efile.fd < 0) { |
472 | char errmsg[STRERR_BUFSIZE]; | 460 | char errmsg[STRERR_BUFSIZE]; |
473 | char *cp = str_error(errno, errmsg, sizeof(errmsg)); | 461 | char *cp = libbpf_strerror_r(errno, errmsg, |
462 | sizeof(errmsg)); | ||
474 | 463 | ||
475 | pr_warning("failed to open %s: %s\n", obj->path, cp); | 464 | pr_warning("failed to open %s: %s\n", obj->path, cp); |
476 | return -errno; | 465 | return -errno; |
@@ -552,7 +541,7 @@ static int | |||
552 | bpf_object__init_kversion(struct bpf_object *obj, | 541 | bpf_object__init_kversion(struct bpf_object *obj, |
553 | void *data, size_t size) | 542 | void *data, size_t size) |
554 | { | 543 | { |
555 | u32 kver; | 544 | __u32 kver; |
556 | 545 | ||
557 | if (size != sizeof(kver)) { | 546 | if (size != sizeof(kver)) { |
558 | pr_warning("invalid kver section in %s\n", obj->path); | 547 | pr_warning("invalid kver section in %s\n", obj->path); |
@@ -574,8 +563,9 @@ static int compare_bpf_map(const void *_a, const void *_b) | |||
574 | } | 563 | } |
575 | 564 | ||
576 | static int | 565 | static int |
577 | bpf_object__init_maps(struct bpf_object *obj) | 566 | bpf_object__init_maps(struct bpf_object *obj, int flags) |
578 | { | 567 | { |
568 | bool strict = !(flags & MAPS_RELAX_COMPAT); | ||
579 | int i, map_idx, map_def_sz, nr_maps = 0; | 569 | int i, map_idx, map_def_sz, nr_maps = 0; |
580 | Elf_Scn *scn; | 570 | Elf_Scn *scn; |
581 | Elf_Data *data; | 571 | Elf_Data *data; |
@@ -697,7 +687,8 @@ bpf_object__init_maps(struct bpf_object *obj) | |||
697 | "has unrecognized, non-zero " | 687 | "has unrecognized, non-zero " |
698 | "options\n", | 688 | "options\n", |
699 | obj->path, map_name); | 689 | obj->path, map_name); |
700 | return -EINVAL; | 690 | if (strict) |
691 | return -EINVAL; | ||
701 | } | 692 | } |
702 | } | 693 | } |
703 | memcpy(&obj->maps[map_idx].def, def, | 694 | memcpy(&obj->maps[map_idx].def, def, |
@@ -728,7 +719,7 @@ static bool section_have_execinstr(struct bpf_object *obj, int idx) | |||
728 | return false; | 719 | return false; |
729 | } | 720 | } |
730 | 721 | ||
731 | static int bpf_object__elf_collect(struct bpf_object *obj) | 722 | static int bpf_object__elf_collect(struct bpf_object *obj, int flags) |
732 | { | 723 | { |
733 | Elf *elf = obj->efile.elf; | 724 | Elf *elf = obj->efile.elf; |
734 | GElf_Ehdr *ep = &obj->efile.ehdr; | 725 | GElf_Ehdr *ep = &obj->efile.ehdr; |
@@ -811,7 +802,8 @@ static int bpf_object__elf_collect(struct bpf_object *obj) | |||
811 | data->d_size, name, idx); | 802 | data->d_size, name, idx); |
812 | if (err) { | 803 | if (err) { |
813 | char errmsg[STRERR_BUFSIZE]; | 804 | char errmsg[STRERR_BUFSIZE]; |
814 | char *cp = str_error(-err, errmsg, sizeof(errmsg)); | 805 | char *cp = libbpf_strerror_r(-err, errmsg, |
806 | sizeof(errmsg)); | ||
815 | 807 | ||
816 | pr_warning("failed to alloc program %s (%s): %s", | 808 | pr_warning("failed to alloc program %s (%s): %s", |
817 | name, obj->path, cp); | 809 | name, obj->path, cp); |
@@ -854,7 +846,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj) | |||
854 | return LIBBPF_ERRNO__FORMAT; | 846 | return LIBBPF_ERRNO__FORMAT; |
855 | } | 847 | } |
856 | if (obj->efile.maps_shndx >= 0) { | 848 | if (obj->efile.maps_shndx >= 0) { |
857 | err = bpf_object__init_maps(obj); | 849 | err = bpf_object__init_maps(obj, flags); |
858 | if (err) | 850 | if (err) |
859 | goto out; | 851 | goto out; |
860 | } | 852 | } |
@@ -1140,7 +1132,7 @@ bpf_object__create_maps(struct bpf_object *obj) | |||
1140 | 1132 | ||
1141 | *pfd = bpf_create_map_xattr(&create_attr); | 1133 | *pfd = bpf_create_map_xattr(&create_attr); |
1142 | if (*pfd < 0 && create_attr.btf_key_type_id) { | 1134 | if (*pfd < 0 && create_attr.btf_key_type_id) { |
1143 | cp = str_error(errno, errmsg, sizeof(errmsg)); | 1135 | cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg)); |
1144 | pr_warning("Error in bpf_create_map_xattr(%s):%s(%d). Retrying without BTF.\n", | 1136 | pr_warning("Error in bpf_create_map_xattr(%s):%s(%d). Retrying without BTF.\n", |
1145 | map->name, cp, errno); | 1137 | map->name, cp, errno); |
1146 | create_attr.btf_fd = 0; | 1138 | create_attr.btf_fd = 0; |
@@ -1155,7 +1147,7 @@ bpf_object__create_maps(struct bpf_object *obj) | |||
1155 | size_t j; | 1147 | size_t j; |
1156 | 1148 | ||
1157 | err = *pfd; | 1149 | err = *pfd; |
1158 | cp = str_error(errno, errmsg, sizeof(errmsg)); | 1150 | cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg)); |
1159 | pr_warning("failed to create map (name: '%s'): %s\n", | 1151 | pr_warning("failed to create map (name: '%s'): %s\n", |
1160 | map->name, cp); | 1152 | map->name, cp); |
1161 | for (j = 0; j < i; j++) | 1153 | for (j = 0; j < i; j++) |
@@ -1306,7 +1298,7 @@ static int bpf_object__collect_reloc(struct bpf_object *obj) | |||
1306 | static int | 1298 | static int |
1307 | load_program(enum bpf_prog_type type, enum bpf_attach_type expected_attach_type, | 1299 | load_program(enum bpf_prog_type type, enum bpf_attach_type expected_attach_type, |
1308 | const char *name, struct bpf_insn *insns, int insns_cnt, | 1300 | const char *name, struct bpf_insn *insns, int insns_cnt, |
1309 | char *license, u32 kern_version, int *pfd, int prog_ifindex) | 1301 | char *license, __u32 kern_version, int *pfd, int prog_ifindex) |
1310 | { | 1302 | { |
1311 | struct bpf_load_program_attr load_attr; | 1303 | struct bpf_load_program_attr load_attr; |
1312 | char *cp, errmsg[STRERR_BUFSIZE]; | 1304 | char *cp, errmsg[STRERR_BUFSIZE]; |
@@ -1339,7 +1331,7 @@ load_program(enum bpf_prog_type type, enum bpf_attach_type expected_attach_type, | |||
1339 | } | 1331 | } |
1340 | 1332 | ||
1341 | ret = -LIBBPF_ERRNO__LOAD; | 1333 | ret = -LIBBPF_ERRNO__LOAD; |
1342 | cp = str_error(errno, errmsg, sizeof(errmsg)); | 1334 | cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg)); |
1343 | pr_warning("load bpf program failed: %s\n", cp); | 1335 | pr_warning("load bpf program failed: %s\n", cp); |
1344 | 1336 | ||
1345 | if (log_buf && log_buf[0] != '\0') { | 1337 | if (log_buf && log_buf[0] != '\0') { |
@@ -1375,9 +1367,9 @@ out: | |||
1375 | return ret; | 1367 | return ret; |
1376 | } | 1368 | } |
1377 | 1369 | ||
1378 | static int | 1370 | int |
1379 | bpf_program__load(struct bpf_program *prog, | 1371 | bpf_program__load(struct bpf_program *prog, |
1380 | char *license, u32 kern_version) | 1372 | char *license, __u32 kern_version) |
1381 | { | 1373 | { |
1382 | int err = 0, fd, i; | 1374 | int err = 0, fd, i; |
1383 | 1375 | ||
@@ -1502,6 +1494,7 @@ static bool bpf_prog_type__needs_kver(enum bpf_prog_type type) | |||
1502 | case BPF_PROG_TYPE_CGROUP_SOCK_ADDR: | 1494 | case BPF_PROG_TYPE_CGROUP_SOCK_ADDR: |
1503 | case BPF_PROG_TYPE_LIRC_MODE2: | 1495 | case BPF_PROG_TYPE_LIRC_MODE2: |
1504 | case BPF_PROG_TYPE_SK_REUSEPORT: | 1496 | case BPF_PROG_TYPE_SK_REUSEPORT: |
1497 | case BPF_PROG_TYPE_FLOW_DISSECTOR: | ||
1505 | return false; | 1498 | return false; |
1506 | case BPF_PROG_TYPE_UNSPEC: | 1499 | case BPF_PROG_TYPE_UNSPEC: |
1507 | case BPF_PROG_TYPE_KPROBE: | 1500 | case BPF_PROG_TYPE_KPROBE: |
@@ -1525,7 +1518,7 @@ static int bpf_object__validate(struct bpf_object *obj, bool needs_kver) | |||
1525 | 1518 | ||
1526 | static struct bpf_object * | 1519 | static struct bpf_object * |
1527 | __bpf_object__open(const char *path, void *obj_buf, size_t obj_buf_sz, | 1520 | __bpf_object__open(const char *path, void *obj_buf, size_t obj_buf_sz, |
1528 | bool needs_kver) | 1521 | bool needs_kver, int flags) |
1529 | { | 1522 | { |
1530 | struct bpf_object *obj; | 1523 | struct bpf_object *obj; |
1531 | int err; | 1524 | int err; |
@@ -1541,7 +1534,7 @@ __bpf_object__open(const char *path, void *obj_buf, size_t obj_buf_sz, | |||
1541 | 1534 | ||
1542 | CHECK_ERR(bpf_object__elf_init(obj), err, out); | 1535 | CHECK_ERR(bpf_object__elf_init(obj), err, out); |
1543 | CHECK_ERR(bpf_object__check_endianness(obj), err, out); | 1536 | CHECK_ERR(bpf_object__check_endianness(obj), err, out); |
1544 | CHECK_ERR(bpf_object__elf_collect(obj), err, out); | 1537 | CHECK_ERR(bpf_object__elf_collect(obj, flags), err, out); |
1545 | CHECK_ERR(bpf_object__collect_reloc(obj), err, out); | 1538 | CHECK_ERR(bpf_object__collect_reloc(obj), err, out); |
1546 | CHECK_ERR(bpf_object__validate(obj, needs_kver), err, out); | 1539 | CHECK_ERR(bpf_object__validate(obj, needs_kver), err, out); |
1547 | 1540 | ||
@@ -1552,7 +1545,8 @@ out: | |||
1552 | return ERR_PTR(err); | 1545 | return ERR_PTR(err); |
1553 | } | 1546 | } |
1554 | 1547 | ||
1555 | struct bpf_object *bpf_object__open_xattr(struct bpf_object_open_attr *attr) | 1548 | struct bpf_object *__bpf_object__open_xattr(struct bpf_object_open_attr *attr, |
1549 | int flags) | ||
1556 | { | 1550 | { |
1557 | /* param validation */ | 1551 | /* param validation */ |
1558 | if (!attr->file) | 1552 | if (!attr->file) |
@@ -1561,7 +1555,13 @@ struct bpf_object *bpf_object__open_xattr(struct bpf_object_open_attr *attr) | |||
1561 | pr_debug("loading %s\n", attr->file); | 1555 | pr_debug("loading %s\n", attr->file); |
1562 | 1556 | ||
1563 | return __bpf_object__open(attr->file, NULL, 0, | 1557 | return __bpf_object__open(attr->file, NULL, 0, |
1564 | bpf_prog_type__needs_kver(attr->prog_type)); | 1558 | bpf_prog_type__needs_kver(attr->prog_type), |
1559 | flags); | ||
1560 | } | ||
1561 | |||
1562 | struct bpf_object *bpf_object__open_xattr(struct bpf_object_open_attr *attr) | ||
1563 | { | ||
1564 | return __bpf_object__open_xattr(attr, 0); | ||
1565 | } | 1565 | } |
1566 | 1566 | ||
1567 | struct bpf_object *bpf_object__open(const char *path) | 1567 | struct bpf_object *bpf_object__open(const char *path) |
@@ -1594,7 +1594,7 @@ struct bpf_object *bpf_object__open_buffer(void *obj_buf, | |||
1594 | pr_debug("loading object '%s' from buffer\n", | 1594 | pr_debug("loading object '%s' from buffer\n", |
1595 | name); | 1595 | name); |
1596 | 1596 | ||
1597 | return __bpf_object__open(name, obj_buf, obj_buf_sz, true); | 1597 | return __bpf_object__open(name, obj_buf, obj_buf_sz, true, true); |
1598 | } | 1598 | } |
1599 | 1599 | ||
1600 | int bpf_object__unload(struct bpf_object *obj) | 1600 | int bpf_object__unload(struct bpf_object *obj) |
@@ -1654,7 +1654,7 @@ static int check_path(const char *path) | |||
1654 | 1654 | ||
1655 | dir = dirname(dname); | 1655 | dir = dirname(dname); |
1656 | if (statfs(dir, &st_fs)) { | 1656 | if (statfs(dir, &st_fs)) { |
1657 | cp = str_error(errno, errmsg, sizeof(errmsg)); | 1657 | cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg)); |
1658 | pr_warning("failed to statfs %s: %s\n", dir, cp); | 1658 | pr_warning("failed to statfs %s: %s\n", dir, cp); |
1659 | err = -errno; | 1659 | err = -errno; |
1660 | } | 1660 | } |
@@ -1690,7 +1690,7 @@ int bpf_program__pin_instance(struct bpf_program *prog, const char *path, | |||
1690 | } | 1690 | } |
1691 | 1691 | ||
1692 | if (bpf_obj_pin(prog->instances.fds[instance], path)) { | 1692 | if (bpf_obj_pin(prog->instances.fds[instance], path)) { |
1693 | cp = str_error(errno, errmsg, sizeof(errmsg)); | 1693 | cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg)); |
1694 | pr_warning("failed to pin program: %s\n", cp); | 1694 | pr_warning("failed to pin program: %s\n", cp); |
1695 | return -errno; | 1695 | return -errno; |
1696 | } | 1696 | } |
@@ -1708,7 +1708,7 @@ static int make_dir(const char *path) | |||
1708 | err = -errno; | 1708 | err = -errno; |
1709 | 1709 | ||
1710 | if (err) { | 1710 | if (err) { |
1711 | cp = str_error(-err, errmsg, sizeof(errmsg)); | 1711 | cp = libbpf_strerror_r(-err, errmsg, sizeof(errmsg)); |
1712 | pr_warning("failed to mkdir %s: %s\n", path, cp); | 1712 | pr_warning("failed to mkdir %s: %s\n", path, cp); |
1713 | } | 1713 | } |
1714 | return err; | 1714 | return err; |
@@ -1770,7 +1770,7 @@ int bpf_map__pin(struct bpf_map *map, const char *path) | |||
1770 | } | 1770 | } |
1771 | 1771 | ||
1772 | if (bpf_obj_pin(map->fd, path)) { | 1772 | if (bpf_obj_pin(map->fd, path)) { |
1773 | cp = str_error(errno, errmsg, sizeof(errmsg)); | 1773 | cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg)); |
1774 | pr_warning("failed to pin map: %s\n", cp); | 1774 | pr_warning("failed to pin map: %s\n", cp); |
1775 | return -errno; | 1775 | return -errno; |
1776 | } | 1776 | } |
@@ -2084,57 +2084,90 @@ void bpf_program__set_expected_attach_type(struct bpf_program *prog, | |||
2084 | prog->expected_attach_type = type; | 2084 | prog->expected_attach_type = type; |
2085 | } | 2085 | } |
2086 | 2086 | ||
2087 | #define BPF_PROG_SEC_FULL(string, ptype, atype) \ | 2087 | #define BPF_PROG_SEC_IMPL(string, ptype, eatype, atype) \ |
2088 | { string, sizeof(string) - 1, ptype, atype } | 2088 | { string, sizeof(string) - 1, ptype, eatype, atype } |
2089 | 2089 | ||
2090 | #define BPF_PROG_SEC(string, ptype) BPF_PROG_SEC_FULL(string, ptype, 0) | 2090 | /* Programs that can NOT be attached. */ |
2091 | #define BPF_PROG_SEC(string, ptype) BPF_PROG_SEC_IMPL(string, ptype, 0, -EINVAL) | ||
2091 | 2092 | ||
2092 | #define BPF_S_PROG_SEC(string, ptype) \ | 2093 | /* Programs that can be attached. */ |
2093 | BPF_PROG_SEC_FULL(string, BPF_PROG_TYPE_CGROUP_SOCK, ptype) | 2094 | #define BPF_APROG_SEC(string, ptype, atype) \ |
2095 | BPF_PROG_SEC_IMPL(string, ptype, 0, atype) | ||
2094 | 2096 | ||
2095 | #define BPF_SA_PROG_SEC(string, ptype) \ | 2097 | /* Programs that must specify expected attach type at load time. */ |
2096 | BPF_PROG_SEC_FULL(string, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, ptype) | 2098 | #define BPF_EAPROG_SEC(string, ptype, eatype) \ |
2099 | BPF_PROG_SEC_IMPL(string, ptype, eatype, eatype) | ||
2100 | |||
2101 | /* Programs that can be attached but attach type can't be identified by section | ||
2102 | * name. Kept for backward compatibility. | ||
2103 | */ | ||
2104 | #define BPF_APROG_COMPAT(string, ptype) BPF_PROG_SEC(string, ptype) | ||
2097 | 2105 | ||
2098 | static const struct { | 2106 | static const struct { |
2099 | const char *sec; | 2107 | const char *sec; |
2100 | size_t len; | 2108 | size_t len; |
2101 | enum bpf_prog_type prog_type; | 2109 | enum bpf_prog_type prog_type; |
2102 | enum bpf_attach_type expected_attach_type; | 2110 | enum bpf_attach_type expected_attach_type; |
2111 | enum bpf_attach_type attach_type; | ||
2103 | } section_names[] = { | 2112 | } section_names[] = { |
2104 | BPF_PROG_SEC("socket", BPF_PROG_TYPE_SOCKET_FILTER), | 2113 | BPF_PROG_SEC("socket", BPF_PROG_TYPE_SOCKET_FILTER), |
2105 | BPF_PROG_SEC("kprobe/", BPF_PROG_TYPE_KPROBE), | 2114 | BPF_PROG_SEC("kprobe/", BPF_PROG_TYPE_KPROBE), |
2106 | BPF_PROG_SEC("kretprobe/", BPF_PROG_TYPE_KPROBE), | 2115 | BPF_PROG_SEC("kretprobe/", BPF_PROG_TYPE_KPROBE), |
2107 | BPF_PROG_SEC("classifier", BPF_PROG_TYPE_SCHED_CLS), | 2116 | BPF_PROG_SEC("classifier", BPF_PROG_TYPE_SCHED_CLS), |
2108 | BPF_PROG_SEC("action", BPF_PROG_TYPE_SCHED_ACT), | 2117 | BPF_PROG_SEC("action", BPF_PROG_TYPE_SCHED_ACT), |
2109 | BPF_PROG_SEC("tracepoint/", BPF_PROG_TYPE_TRACEPOINT), | 2118 | BPF_PROG_SEC("tracepoint/", BPF_PROG_TYPE_TRACEPOINT), |
2110 | BPF_PROG_SEC("raw_tracepoint/", BPF_PROG_TYPE_RAW_TRACEPOINT), | 2119 | BPF_PROG_SEC("raw_tracepoint/", BPF_PROG_TYPE_RAW_TRACEPOINT), |
2111 | BPF_PROG_SEC("xdp", BPF_PROG_TYPE_XDP), | 2120 | BPF_PROG_SEC("xdp", BPF_PROG_TYPE_XDP), |
2112 | BPF_PROG_SEC("perf_event", BPF_PROG_TYPE_PERF_EVENT), | 2121 | BPF_PROG_SEC("perf_event", BPF_PROG_TYPE_PERF_EVENT), |
2113 | BPF_PROG_SEC("cgroup/skb", BPF_PROG_TYPE_CGROUP_SKB), | 2122 | BPF_PROG_SEC("lwt_in", BPF_PROG_TYPE_LWT_IN), |
2114 | BPF_PROG_SEC("cgroup/sock", BPF_PROG_TYPE_CGROUP_SOCK), | 2123 | BPF_PROG_SEC("lwt_out", BPF_PROG_TYPE_LWT_OUT), |
2115 | BPF_PROG_SEC("cgroup/dev", BPF_PROG_TYPE_CGROUP_DEVICE), | 2124 | BPF_PROG_SEC("lwt_xmit", BPF_PROG_TYPE_LWT_XMIT), |
2116 | BPF_PROG_SEC("lwt_in", BPF_PROG_TYPE_LWT_IN), | 2125 | BPF_PROG_SEC("lwt_seg6local", BPF_PROG_TYPE_LWT_SEG6LOCAL), |
2117 | BPF_PROG_SEC("lwt_out", BPF_PROG_TYPE_LWT_OUT), | 2126 | BPF_APROG_SEC("cgroup_skb/ingress", BPF_PROG_TYPE_CGROUP_SKB, |
2118 | BPF_PROG_SEC("lwt_xmit", BPF_PROG_TYPE_LWT_XMIT), | 2127 | BPF_CGROUP_INET_INGRESS), |
2119 | BPF_PROG_SEC("lwt_seg6local", BPF_PROG_TYPE_LWT_SEG6LOCAL), | 2128 | BPF_APROG_SEC("cgroup_skb/egress", BPF_PROG_TYPE_CGROUP_SKB, |
2120 | BPF_PROG_SEC("sockops", BPF_PROG_TYPE_SOCK_OPS), | 2129 | BPF_CGROUP_INET_EGRESS), |
2121 | BPF_PROG_SEC("sk_skb", BPF_PROG_TYPE_SK_SKB), | 2130 | BPF_APROG_COMPAT("cgroup/skb", BPF_PROG_TYPE_CGROUP_SKB), |
2122 | BPF_PROG_SEC("sk_msg", BPF_PROG_TYPE_SK_MSG), | 2131 | BPF_APROG_SEC("cgroup/sock", BPF_PROG_TYPE_CGROUP_SOCK, |
2123 | BPF_PROG_SEC("lirc_mode2", BPF_PROG_TYPE_LIRC_MODE2), | 2132 | BPF_CGROUP_INET_SOCK_CREATE), |
2124 | BPF_SA_PROG_SEC("cgroup/bind4", BPF_CGROUP_INET4_BIND), | 2133 | BPF_EAPROG_SEC("cgroup/post_bind4", BPF_PROG_TYPE_CGROUP_SOCK, |
2125 | BPF_SA_PROG_SEC("cgroup/bind6", BPF_CGROUP_INET6_BIND), | 2134 | BPF_CGROUP_INET4_POST_BIND), |
2126 | BPF_SA_PROG_SEC("cgroup/connect4", BPF_CGROUP_INET4_CONNECT), | 2135 | BPF_EAPROG_SEC("cgroup/post_bind6", BPF_PROG_TYPE_CGROUP_SOCK, |
2127 | BPF_SA_PROG_SEC("cgroup/connect6", BPF_CGROUP_INET6_CONNECT), | 2136 | BPF_CGROUP_INET6_POST_BIND), |
2128 | BPF_SA_PROG_SEC("cgroup/sendmsg4", BPF_CGROUP_UDP4_SENDMSG), | 2137 | BPF_APROG_SEC("cgroup/dev", BPF_PROG_TYPE_CGROUP_DEVICE, |
2129 | BPF_SA_PROG_SEC("cgroup/sendmsg6", BPF_CGROUP_UDP6_SENDMSG), | 2138 | BPF_CGROUP_DEVICE), |
2130 | BPF_S_PROG_SEC("cgroup/post_bind4", BPF_CGROUP_INET4_POST_BIND), | 2139 | BPF_APROG_SEC("sockops", BPF_PROG_TYPE_SOCK_OPS, |
2131 | BPF_S_PROG_SEC("cgroup/post_bind6", BPF_CGROUP_INET6_POST_BIND), | 2140 | BPF_CGROUP_SOCK_OPS), |
2141 | BPF_APROG_SEC("sk_skb/stream_parser", BPF_PROG_TYPE_SK_SKB, | ||
2142 | BPF_SK_SKB_STREAM_PARSER), | ||
2143 | BPF_APROG_SEC("sk_skb/stream_verdict", BPF_PROG_TYPE_SK_SKB, | ||
2144 | BPF_SK_SKB_STREAM_VERDICT), | ||
2145 | BPF_APROG_COMPAT("sk_skb", BPF_PROG_TYPE_SK_SKB), | ||
2146 | BPF_APROG_SEC("sk_msg", BPF_PROG_TYPE_SK_MSG, | ||
2147 | BPF_SK_MSG_VERDICT), | ||
2148 | BPF_APROG_SEC("lirc_mode2", BPF_PROG_TYPE_LIRC_MODE2, | ||
2149 | BPF_LIRC_MODE2), | ||
2150 | BPF_APROG_SEC("flow_dissector", BPF_PROG_TYPE_FLOW_DISSECTOR, | ||
2151 | BPF_FLOW_DISSECTOR), | ||
2152 | BPF_EAPROG_SEC("cgroup/bind4", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, | ||
2153 | BPF_CGROUP_INET4_BIND), | ||
2154 | BPF_EAPROG_SEC("cgroup/bind6", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, | ||
2155 | BPF_CGROUP_INET6_BIND), | ||
2156 | BPF_EAPROG_SEC("cgroup/connect4", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, | ||
2157 | BPF_CGROUP_INET4_CONNECT), | ||
2158 | BPF_EAPROG_SEC("cgroup/connect6", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, | ||
2159 | BPF_CGROUP_INET6_CONNECT), | ||
2160 | BPF_EAPROG_SEC("cgroup/sendmsg4", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, | ||
2161 | BPF_CGROUP_UDP4_SENDMSG), | ||
2162 | BPF_EAPROG_SEC("cgroup/sendmsg6", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, | ||
2163 | BPF_CGROUP_UDP6_SENDMSG), | ||
2132 | }; | 2164 | }; |
2133 | 2165 | ||
2166 | #undef BPF_PROG_SEC_IMPL | ||
2134 | #undef BPF_PROG_SEC | 2167 | #undef BPF_PROG_SEC |
2135 | #undef BPF_PROG_SEC_FULL | 2168 | #undef BPF_APROG_SEC |
2136 | #undef BPF_S_PROG_SEC | 2169 | #undef BPF_EAPROG_SEC |
2137 | #undef BPF_SA_PROG_SEC | 2170 | #undef BPF_APROG_COMPAT |
2138 | 2171 | ||
2139 | int libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type, | 2172 | int libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type, |
2140 | enum bpf_attach_type *expected_attach_type) | 2173 | enum bpf_attach_type *expected_attach_type) |
@@ -2154,6 +2187,25 @@ int libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type, | |||
2154 | return -EINVAL; | 2187 | return -EINVAL; |
2155 | } | 2188 | } |
2156 | 2189 | ||
2190 | int libbpf_attach_type_by_name(const char *name, | ||
2191 | enum bpf_attach_type *attach_type) | ||
2192 | { | ||
2193 | int i; | ||
2194 | |||
2195 | if (!name) | ||
2196 | return -EINVAL; | ||
2197 | |||
2198 | for (i = 0; i < ARRAY_SIZE(section_names); i++) { | ||
2199 | if (strncmp(name, section_names[i].sec, section_names[i].len)) | ||
2200 | continue; | ||
2201 | if (section_names[i].attach_type == -EINVAL) | ||
2202 | return -EINVAL; | ||
2203 | *attach_type = section_names[i].attach_type; | ||
2204 | return 0; | ||
2205 | } | ||
2206 | return -EINVAL; | ||
2207 | } | ||
2208 | |||
2157 | static int | 2209 | static int |
2158 | bpf_program__identify_section(struct bpf_program *prog, | 2210 | bpf_program__identify_section(struct bpf_program *prog, |
2159 | enum bpf_prog_type *prog_type, | 2211 | enum bpf_prog_type *prog_type, |
@@ -2336,7 +2388,7 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr, | |||
2336 | bpf_program__set_expected_attach_type(prog, | 2388 | bpf_program__set_expected_attach_type(prog, |
2337 | expected_attach_type); | 2389 | expected_attach_type); |
2338 | 2390 | ||
2339 | if (!bpf_program__is_function_storage(prog, obj) && !first_prog) | 2391 | if (!first_prog) |
2340 | first_prog = prog; | 2392 | first_prog = prog; |
2341 | } | 2393 | } |
2342 | 2394 | ||
@@ -2363,61 +2415,49 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr, | |||
2363 | } | 2415 | } |
2364 | 2416 | ||
2365 | enum bpf_perf_event_ret | 2417 | enum bpf_perf_event_ret |
2366 | bpf_perf_event_read_simple(void *mem, unsigned long size, | 2418 | bpf_perf_event_read_simple(void *mmap_mem, size_t mmap_size, size_t page_size, |
2367 | unsigned long page_size, void **buf, size_t *buf_len, | 2419 | void **copy_mem, size_t *copy_size, |
2368 | bpf_perf_event_print_t fn, void *priv) | 2420 | bpf_perf_event_print_t fn, void *private_data) |
2369 | { | 2421 | { |
2370 | volatile struct perf_event_mmap_page *header = mem; | 2422 | struct perf_event_mmap_page *header = mmap_mem; |
2423 | __u64 data_head = ring_buffer_read_head(header); | ||
2371 | __u64 data_tail = header->data_tail; | 2424 | __u64 data_tail = header->data_tail; |
2372 | __u64 data_head = header->data_head; | 2425 | void *base = ((__u8 *)header) + page_size; |
2373 | int ret = LIBBPF_PERF_EVENT_ERROR; | 2426 | int ret = LIBBPF_PERF_EVENT_CONT; |
2374 | void *base, *begin, *end; | 2427 | struct perf_event_header *ehdr; |
2375 | 2428 | size_t ehdr_size; | |
2376 | asm volatile("" ::: "memory"); /* in real code it should be smp_rmb() */ | 2429 | |
2377 | if (data_head == data_tail) | 2430 | while (data_head != data_tail) { |
2378 | return LIBBPF_PERF_EVENT_CONT; | 2431 | ehdr = base + (data_tail & (mmap_size - 1)); |
2379 | 2432 | ehdr_size = ehdr->size; | |
2380 | base = ((char *)header) + page_size; | 2433 | |
2381 | 2434 | if (((void *)ehdr) + ehdr_size > base + mmap_size) { | |
2382 | begin = base + data_tail % size; | 2435 | void *copy_start = ehdr; |
2383 | end = base + data_head % size; | 2436 | size_t len_first = base + mmap_size - copy_start; |
2384 | 2437 | size_t len_secnd = ehdr_size - len_first; | |
2385 | while (begin != end) { | 2438 | |
2386 | struct perf_event_header *ehdr; | 2439 | if (*copy_size < ehdr_size) { |
2387 | 2440 | free(*copy_mem); | |
2388 | ehdr = begin; | 2441 | *copy_mem = malloc(ehdr_size); |
2389 | if (begin + ehdr->size > base + size) { | 2442 | if (!*copy_mem) { |
2390 | long len = base + size - begin; | 2443 | *copy_size = 0; |
2391 | |||
2392 | if (*buf_len < ehdr->size) { | ||
2393 | free(*buf); | ||
2394 | *buf = malloc(ehdr->size); | ||
2395 | if (!*buf) { | ||
2396 | ret = LIBBPF_PERF_EVENT_ERROR; | 2444 | ret = LIBBPF_PERF_EVENT_ERROR; |
2397 | break; | 2445 | break; |
2398 | } | 2446 | } |
2399 | *buf_len = ehdr->size; | 2447 | *copy_size = ehdr_size; |
2400 | } | 2448 | } |
2401 | 2449 | ||
2402 | memcpy(*buf, begin, len); | 2450 | memcpy(*copy_mem, copy_start, len_first); |
2403 | memcpy(*buf + len, base, ehdr->size - len); | 2451 | memcpy(*copy_mem + len_first, base, len_secnd); |
2404 | ehdr = (void *)*buf; | 2452 | ehdr = *copy_mem; |
2405 | begin = base + ehdr->size - len; | ||
2406 | } else if (begin + ehdr->size == base + size) { | ||
2407 | begin = base; | ||
2408 | } else { | ||
2409 | begin += ehdr->size; | ||
2410 | } | 2453 | } |
2411 | 2454 | ||
2412 | ret = fn(ehdr, priv); | 2455 | ret = fn(ehdr, private_data); |
2456 | data_tail += ehdr_size; | ||
2413 | if (ret != LIBBPF_PERF_EVENT_CONT) | 2457 | if (ret != LIBBPF_PERF_EVENT_CONT) |
2414 | break; | 2458 | break; |
2415 | |||
2416 | data_tail += ehdr->size; | ||
2417 | } | 2459 | } |
2418 | 2460 | ||
2419 | __sync_synchronize(); /* smp_mb() */ | 2461 | ring_buffer_write_tail(header, data_tail); |
2420 | header->data_tail = data_tail; | ||
2421 | |||
2422 | return ret; | 2462 | return ret; |
2423 | } | 2463 | } |
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 96c55fac54c3..1f3468dad8b2 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* SPDX-License-Identifier: LGPL-2.1 */ | 1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Common eBPF ELF object loading operations. | 4 | * Common eBPF ELF object loading operations. |
@@ -6,22 +6,9 @@ | |||
6 | * Copyright (C) 2013-2015 Alexei Starovoitov <ast@kernel.org> | 6 | * Copyright (C) 2013-2015 Alexei Starovoitov <ast@kernel.org> |
7 | * Copyright (C) 2015 Wang Nan <wangnan0@huawei.com> | 7 | * Copyright (C) 2015 Wang Nan <wangnan0@huawei.com> |
8 | * Copyright (C) 2015 Huawei Inc. | 8 | * Copyright (C) 2015 Huawei Inc. |
9 | * | ||
10 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU Lesser General Public | ||
12 | * License as published by the Free Software Foundation; | ||
13 | * version 2.1 of the License (not later!) | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU Lesser General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU Lesser General Public | ||
21 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
22 | */ | 9 | */ |
23 | #ifndef __BPF_LIBBPF_H | 10 | #ifndef __LIBBPF_LIBBPF_H |
24 | #define __BPF_LIBBPF_H | 11 | #define __LIBBPF_LIBBPF_H |
25 | 12 | ||
26 | #include <stdio.h> | 13 | #include <stdio.h> |
27 | #include <stdint.h> | 14 | #include <stdint.h> |
@@ -29,6 +16,10 @@ | |||
29 | #include <sys/types.h> // for size_t | 16 | #include <sys/types.h> // for size_t |
30 | #include <linux/bpf.h> | 17 | #include <linux/bpf.h> |
31 | 18 | ||
19 | #ifndef LIBBPF_API | ||
20 | #define LIBBPF_API __attribute__((visibility("default"))) | ||
21 | #endif | ||
22 | |||
32 | enum libbpf_errno { | 23 | enum libbpf_errno { |
33 | __LIBBPF_ERRNO__START = 4000, | 24 | __LIBBPF_ERRNO__START = 4000, |
34 | 25 | ||
@@ -46,10 +37,11 @@ enum libbpf_errno { | |||
46 | LIBBPF_ERRNO__PROGTYPE, /* Kernel doesn't support this program type */ | 37 | LIBBPF_ERRNO__PROGTYPE, /* Kernel doesn't support this program type */ |
47 | LIBBPF_ERRNO__WRNGPID, /* Wrong pid in netlink message */ | 38 | LIBBPF_ERRNO__WRNGPID, /* Wrong pid in netlink message */ |
48 | LIBBPF_ERRNO__INVSEQ, /* Invalid netlink sequence */ | 39 | LIBBPF_ERRNO__INVSEQ, /* Invalid netlink sequence */ |
40 | LIBBPF_ERRNO__NLPARSE, /* netlink parsing error */ | ||
49 | __LIBBPF_ERRNO__END, | 41 | __LIBBPF_ERRNO__END, |
50 | }; | 42 | }; |
51 | 43 | ||
52 | int libbpf_strerror(int err, char *buf, size_t size); | 44 | LIBBPF_API int libbpf_strerror(int err, char *buf, size_t size); |
53 | 45 | ||
54 | /* | 46 | /* |
55 | * __printf is defined in include/linux/compiler-gcc.h. However, | 47 | * __printf is defined in include/linux/compiler-gcc.h. However, |
@@ -59,9 +51,9 @@ int libbpf_strerror(int err, char *buf, size_t size); | |||
59 | typedef int (*libbpf_print_fn_t)(const char *, ...) | 51 | typedef int (*libbpf_print_fn_t)(const char *, ...) |
60 | __attribute__((format(printf, 1, 2))); | 52 | __attribute__((format(printf, 1, 2))); |
61 | 53 | ||
62 | void libbpf_set_print(libbpf_print_fn_t warn, | 54 | LIBBPF_API void libbpf_set_print(libbpf_print_fn_t warn, |
63 | libbpf_print_fn_t info, | 55 | libbpf_print_fn_t info, |
64 | libbpf_print_fn_t debug); | 56 | libbpf_print_fn_t debug); |
65 | 57 | ||
66 | /* Hide internal to user */ | 58 | /* Hide internal to user */ |
67 | struct bpf_object; | 59 | struct bpf_object; |
@@ -71,25 +63,28 @@ struct bpf_object_open_attr { | |||
71 | enum bpf_prog_type prog_type; | 63 | enum bpf_prog_type prog_type; |
72 | }; | 64 | }; |
73 | 65 | ||
74 | struct bpf_object *bpf_object__open(const char *path); | 66 | LIBBPF_API struct bpf_object *bpf_object__open(const char *path); |
75 | struct bpf_object *bpf_object__open_xattr(struct bpf_object_open_attr *attr); | 67 | LIBBPF_API struct bpf_object * |
76 | struct bpf_object *bpf_object__open_buffer(void *obj_buf, | 68 | bpf_object__open_xattr(struct bpf_object_open_attr *attr); |
77 | size_t obj_buf_sz, | 69 | struct bpf_object *__bpf_object__open_xattr(struct bpf_object_open_attr *attr, |
78 | const char *name); | 70 | int flags); |
79 | int bpf_object__pin(struct bpf_object *object, const char *path); | 71 | LIBBPF_API struct bpf_object *bpf_object__open_buffer(void *obj_buf, |
80 | void bpf_object__close(struct bpf_object *object); | 72 | size_t obj_buf_sz, |
73 | const char *name); | ||
74 | LIBBPF_API int bpf_object__pin(struct bpf_object *object, const char *path); | ||
75 | LIBBPF_API void bpf_object__close(struct bpf_object *object); | ||
81 | 76 | ||
82 | /* Load/unload object into/from kernel */ | 77 | /* Load/unload object into/from kernel */ |
83 | int bpf_object__load(struct bpf_object *obj); | 78 | LIBBPF_API int bpf_object__load(struct bpf_object *obj); |
84 | int bpf_object__unload(struct bpf_object *obj); | 79 | LIBBPF_API int bpf_object__unload(struct bpf_object *obj); |
85 | const char *bpf_object__name(struct bpf_object *obj); | 80 | LIBBPF_API const char *bpf_object__name(struct bpf_object *obj); |
86 | unsigned int bpf_object__kversion(struct bpf_object *obj); | 81 | LIBBPF_API unsigned int bpf_object__kversion(struct bpf_object *obj); |
87 | int bpf_object__btf_fd(const struct bpf_object *obj); | 82 | LIBBPF_API int bpf_object__btf_fd(const struct bpf_object *obj); |
88 | 83 | ||
89 | struct bpf_program * | 84 | LIBBPF_API struct bpf_program * |
90 | bpf_object__find_program_by_title(struct bpf_object *obj, const char *title); | 85 | bpf_object__find_program_by_title(struct bpf_object *obj, const char *title); |
91 | 86 | ||
92 | struct bpf_object *bpf_object__next(struct bpf_object *prev); | 87 | LIBBPF_API struct bpf_object *bpf_object__next(struct bpf_object *prev); |
93 | #define bpf_object__for_each_safe(pos, tmp) \ | 88 | #define bpf_object__for_each_safe(pos, tmp) \ |
94 | for ((pos) = bpf_object__next(NULL), \ | 89 | for ((pos) = bpf_object__next(NULL), \ |
95 | (tmp) = bpf_object__next(pos); \ | 90 | (tmp) = bpf_object__next(pos); \ |
@@ -97,17 +92,20 @@ struct bpf_object *bpf_object__next(struct bpf_object *prev); | |||
97 | (pos) = (tmp), (tmp) = bpf_object__next(tmp)) | 92 | (pos) = (tmp), (tmp) = bpf_object__next(tmp)) |
98 | 93 | ||
99 | typedef void (*bpf_object_clear_priv_t)(struct bpf_object *, void *); | 94 | typedef void (*bpf_object_clear_priv_t)(struct bpf_object *, void *); |
100 | int bpf_object__set_priv(struct bpf_object *obj, void *priv, | 95 | LIBBPF_API int bpf_object__set_priv(struct bpf_object *obj, void *priv, |
101 | bpf_object_clear_priv_t clear_priv); | 96 | bpf_object_clear_priv_t clear_priv); |
102 | void *bpf_object__priv(struct bpf_object *prog); | 97 | LIBBPF_API void *bpf_object__priv(struct bpf_object *prog); |
103 | 98 | ||
104 | int libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type, | 99 | LIBBPF_API int |
105 | enum bpf_attach_type *expected_attach_type); | 100 | libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type, |
101 | enum bpf_attach_type *expected_attach_type); | ||
102 | LIBBPF_API int libbpf_attach_type_by_name(const char *name, | ||
103 | enum bpf_attach_type *attach_type); | ||
106 | 104 | ||
107 | /* Accessors of bpf_program */ | 105 | /* Accessors of bpf_program */ |
108 | struct bpf_program; | 106 | struct bpf_program; |
109 | struct bpf_program *bpf_program__next(struct bpf_program *prog, | 107 | LIBBPF_API struct bpf_program *bpf_program__next(struct bpf_program *prog, |
110 | struct bpf_object *obj); | 108 | struct bpf_object *obj); |
111 | 109 | ||
112 | #define bpf_object__for_each_program(pos, obj) \ | 110 | #define bpf_object__for_each_program(pos, obj) \ |
113 | for ((pos) = bpf_program__next(NULL, (obj)); \ | 111 | for ((pos) = bpf_program__next(NULL, (obj)); \ |
@@ -117,18 +115,24 @@ struct bpf_program *bpf_program__next(struct bpf_program *prog, | |||
117 | typedef void (*bpf_program_clear_priv_t)(struct bpf_program *, | 115 | typedef void (*bpf_program_clear_priv_t)(struct bpf_program *, |
118 | void *); | 116 | void *); |
119 | 117 | ||
120 | int bpf_program__set_priv(struct bpf_program *prog, void *priv, | 118 | LIBBPF_API int bpf_program__set_priv(struct bpf_program *prog, void *priv, |
121 | bpf_program_clear_priv_t clear_priv); | 119 | bpf_program_clear_priv_t clear_priv); |
122 | 120 | ||
123 | void *bpf_program__priv(struct bpf_program *prog); | 121 | LIBBPF_API void *bpf_program__priv(struct bpf_program *prog); |
124 | void bpf_program__set_ifindex(struct bpf_program *prog, __u32 ifindex); | 122 | LIBBPF_API void bpf_program__set_ifindex(struct bpf_program *prog, |
123 | __u32 ifindex); | ||
125 | 124 | ||
126 | const char *bpf_program__title(struct bpf_program *prog, bool needs_copy); | 125 | LIBBPF_API const char *bpf_program__title(struct bpf_program *prog, |
126 | bool needs_copy); | ||
127 | 127 | ||
128 | int bpf_program__fd(struct bpf_program *prog); | 128 | LIBBPF_API int bpf_program__load(struct bpf_program *prog, char *license, |
129 | int bpf_program__pin_instance(struct bpf_program *prog, const char *path, | 129 | __u32 kern_version); |
130 | int instance); | 130 | LIBBPF_API int bpf_program__fd(struct bpf_program *prog); |
131 | int bpf_program__pin(struct bpf_program *prog, const char *path); | 131 | LIBBPF_API int bpf_program__pin_instance(struct bpf_program *prog, |
132 | const char *path, | ||
133 | int instance); | ||
134 | LIBBPF_API int bpf_program__pin(struct bpf_program *prog, const char *path); | ||
135 | LIBBPF_API void bpf_program__unload(struct bpf_program *prog); | ||
132 | 136 | ||
133 | struct bpf_insn; | 137 | struct bpf_insn; |
134 | 138 | ||
@@ -189,34 +193,36 @@ typedef int (*bpf_program_prep_t)(struct bpf_program *prog, int n, | |||
189 | struct bpf_insn *insns, int insns_cnt, | 193 | struct bpf_insn *insns, int insns_cnt, |
190 | struct bpf_prog_prep_result *res); | 194 | struct bpf_prog_prep_result *res); |
191 | 195 | ||
192 | int bpf_program__set_prep(struct bpf_program *prog, int nr_instance, | 196 | LIBBPF_API int bpf_program__set_prep(struct bpf_program *prog, int nr_instance, |
193 | bpf_program_prep_t prep); | 197 | bpf_program_prep_t prep); |
194 | 198 | ||
195 | int bpf_program__nth_fd(struct bpf_program *prog, int n); | 199 | LIBBPF_API int bpf_program__nth_fd(struct bpf_program *prog, int n); |
196 | 200 | ||
197 | /* | 201 | /* |
198 | * Adjust type of BPF program. Default is kprobe. | 202 | * Adjust type of BPF program. Default is kprobe. |
199 | */ | 203 | */ |
200 | int bpf_program__set_socket_filter(struct bpf_program *prog); | 204 | LIBBPF_API int bpf_program__set_socket_filter(struct bpf_program *prog); |
201 | int bpf_program__set_tracepoint(struct bpf_program *prog); | 205 | LIBBPF_API int bpf_program__set_tracepoint(struct bpf_program *prog); |
202 | int bpf_program__set_raw_tracepoint(struct bpf_program *prog); | 206 | LIBBPF_API int bpf_program__set_raw_tracepoint(struct bpf_program *prog); |
203 | int bpf_program__set_kprobe(struct bpf_program *prog); | 207 | LIBBPF_API int bpf_program__set_kprobe(struct bpf_program *prog); |
204 | int bpf_program__set_sched_cls(struct bpf_program *prog); | 208 | LIBBPF_API int bpf_program__set_sched_cls(struct bpf_program *prog); |
205 | int bpf_program__set_sched_act(struct bpf_program *prog); | 209 | LIBBPF_API int bpf_program__set_sched_act(struct bpf_program *prog); |
206 | int bpf_program__set_xdp(struct bpf_program *prog); | 210 | LIBBPF_API int bpf_program__set_xdp(struct bpf_program *prog); |
207 | int bpf_program__set_perf_event(struct bpf_program *prog); | 211 | LIBBPF_API int bpf_program__set_perf_event(struct bpf_program *prog); |
208 | void bpf_program__set_type(struct bpf_program *prog, enum bpf_prog_type type); | 212 | LIBBPF_API void bpf_program__set_type(struct bpf_program *prog, |
209 | void bpf_program__set_expected_attach_type(struct bpf_program *prog, | 213 | enum bpf_prog_type type); |
210 | enum bpf_attach_type type); | 214 | LIBBPF_API void |
211 | 215 | bpf_program__set_expected_attach_type(struct bpf_program *prog, | |
212 | bool bpf_program__is_socket_filter(struct bpf_program *prog); | 216 | enum bpf_attach_type type); |
213 | bool bpf_program__is_tracepoint(struct bpf_program *prog); | 217 | |
214 | bool bpf_program__is_raw_tracepoint(struct bpf_program *prog); | 218 | LIBBPF_API bool bpf_program__is_socket_filter(struct bpf_program *prog); |
215 | bool bpf_program__is_kprobe(struct bpf_program *prog); | 219 | LIBBPF_API bool bpf_program__is_tracepoint(struct bpf_program *prog); |
216 | bool bpf_program__is_sched_cls(struct bpf_program *prog); | 220 | LIBBPF_API bool bpf_program__is_raw_tracepoint(struct bpf_program *prog); |
217 | bool bpf_program__is_sched_act(struct bpf_program *prog); | 221 | LIBBPF_API bool bpf_program__is_kprobe(struct bpf_program *prog); |
218 | bool bpf_program__is_xdp(struct bpf_program *prog); | 222 | LIBBPF_API bool bpf_program__is_sched_cls(struct bpf_program *prog); |
219 | bool bpf_program__is_perf_event(struct bpf_program *prog); | 223 | LIBBPF_API bool bpf_program__is_sched_act(struct bpf_program *prog); |
224 | LIBBPF_API bool bpf_program__is_xdp(struct bpf_program *prog); | ||
225 | LIBBPF_API bool bpf_program__is_perf_event(struct bpf_program *prog); | ||
220 | 226 | ||
221 | /* | 227 | /* |
222 | * No need for __attribute__((packed)), all members of 'bpf_map_def' | 228 | * No need for __attribute__((packed)), all members of 'bpf_map_def' |
@@ -237,39 +243,39 @@ struct bpf_map_def { | |||
237 | * so no need to worry about a name clash. | 243 | * so no need to worry about a name clash. |
238 | */ | 244 | */ |
239 | struct bpf_map; | 245 | struct bpf_map; |
240 | struct bpf_map * | 246 | LIBBPF_API struct bpf_map * |
241 | bpf_object__find_map_by_name(struct bpf_object *obj, const char *name); | 247 | bpf_object__find_map_by_name(struct bpf_object *obj, const char *name); |
242 | 248 | ||
243 | /* | 249 | /* |
244 | * Get bpf_map through the offset of corresponding struct bpf_map_def | 250 | * Get bpf_map through the offset of corresponding struct bpf_map_def |
245 | * in the BPF object file. | 251 | * in the BPF object file. |
246 | */ | 252 | */ |
247 | struct bpf_map * | 253 | LIBBPF_API struct bpf_map * |
248 | bpf_object__find_map_by_offset(struct bpf_object *obj, size_t offset); | 254 | bpf_object__find_map_by_offset(struct bpf_object *obj, size_t offset); |
249 | 255 | ||
250 | struct bpf_map * | 256 | LIBBPF_API struct bpf_map * |
251 | bpf_map__next(struct bpf_map *map, struct bpf_object *obj); | 257 | bpf_map__next(struct bpf_map *map, struct bpf_object *obj); |
252 | #define bpf_map__for_each(pos, obj) \ | 258 | #define bpf_map__for_each(pos, obj) \ |
253 | for ((pos) = bpf_map__next(NULL, (obj)); \ | 259 | for ((pos) = bpf_map__next(NULL, (obj)); \ |
254 | (pos) != NULL; \ | 260 | (pos) != NULL; \ |
255 | (pos) = bpf_map__next((pos), (obj))) | 261 | (pos) = bpf_map__next((pos), (obj))) |
256 | 262 | ||
257 | int bpf_map__fd(struct bpf_map *map); | 263 | LIBBPF_API int bpf_map__fd(struct bpf_map *map); |
258 | const struct bpf_map_def *bpf_map__def(struct bpf_map *map); | 264 | LIBBPF_API const struct bpf_map_def *bpf_map__def(struct bpf_map *map); |
259 | const char *bpf_map__name(struct bpf_map *map); | 265 | LIBBPF_API const char *bpf_map__name(struct bpf_map *map); |
260 | __u32 bpf_map__btf_key_type_id(const struct bpf_map *map); | 266 | LIBBPF_API __u32 bpf_map__btf_key_type_id(const struct bpf_map *map); |
261 | __u32 bpf_map__btf_value_type_id(const struct bpf_map *map); | 267 | LIBBPF_API __u32 bpf_map__btf_value_type_id(const struct bpf_map *map); |
262 | 268 | ||
263 | typedef void (*bpf_map_clear_priv_t)(struct bpf_map *, void *); | 269 | typedef void (*bpf_map_clear_priv_t)(struct bpf_map *, void *); |
264 | int bpf_map__set_priv(struct bpf_map *map, void *priv, | 270 | LIBBPF_API int bpf_map__set_priv(struct bpf_map *map, void *priv, |
265 | bpf_map_clear_priv_t clear_priv); | 271 | bpf_map_clear_priv_t clear_priv); |
266 | void *bpf_map__priv(struct bpf_map *map); | 272 | LIBBPF_API void *bpf_map__priv(struct bpf_map *map); |
267 | int bpf_map__reuse_fd(struct bpf_map *map, int fd); | 273 | LIBBPF_API int bpf_map__reuse_fd(struct bpf_map *map, int fd); |
268 | bool bpf_map__is_offload_neutral(struct bpf_map *map); | 274 | LIBBPF_API bool bpf_map__is_offload_neutral(struct bpf_map *map); |
269 | void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex); | 275 | LIBBPF_API void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex); |
270 | int bpf_map__pin(struct bpf_map *map, const char *path); | 276 | LIBBPF_API int bpf_map__pin(struct bpf_map *map, const char *path); |
271 | 277 | ||
272 | long libbpf_get_error(const void *ptr); | 278 | LIBBPF_API long libbpf_get_error(const void *ptr); |
273 | 279 | ||
274 | struct bpf_prog_load_attr { | 280 | struct bpf_prog_load_attr { |
275 | const char *file; | 281 | const char *file; |
@@ -278,12 +284,12 @@ struct bpf_prog_load_attr { | |||
278 | int ifindex; | 284 | int ifindex; |
279 | }; | 285 | }; |
280 | 286 | ||
281 | int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr, | 287 | LIBBPF_API int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr, |
282 | struct bpf_object **pobj, int *prog_fd); | 288 | struct bpf_object **pobj, int *prog_fd); |
283 | int bpf_prog_load(const char *file, enum bpf_prog_type type, | 289 | LIBBPF_API int bpf_prog_load(const char *file, enum bpf_prog_type type, |
284 | struct bpf_object **pobj, int *prog_fd); | 290 | struct bpf_object **pobj, int *prog_fd); |
285 | 291 | ||
286 | int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags); | 292 | LIBBPF_API int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags); |
287 | 293 | ||
288 | enum bpf_perf_event_ret { | 294 | enum bpf_perf_event_ret { |
289 | LIBBPF_PERF_EVENT_DONE = 0, | 295 | LIBBPF_PERF_EVENT_DONE = 0, |
@@ -291,10 +297,24 @@ enum bpf_perf_event_ret { | |||
291 | LIBBPF_PERF_EVENT_CONT = -2, | 297 | LIBBPF_PERF_EVENT_CONT = -2, |
292 | }; | 298 | }; |
293 | 299 | ||
294 | typedef enum bpf_perf_event_ret (*bpf_perf_event_print_t)(void *event, | 300 | struct perf_event_header; |
295 | void *priv); | 301 | typedef enum bpf_perf_event_ret |
296 | int bpf_perf_event_read_simple(void *mem, unsigned long size, | 302 | (*bpf_perf_event_print_t)(struct perf_event_header *hdr, |
297 | unsigned long page_size, | 303 | void *private_data); |
298 | void **buf, size_t *buf_len, | 304 | LIBBPF_API enum bpf_perf_event_ret |
299 | bpf_perf_event_print_t fn, void *priv); | 305 | bpf_perf_event_read_simple(void *mmap_mem, size_t mmap_size, size_t page_size, |
300 | #endif | 306 | void **copy_mem, size_t *copy_size, |
307 | bpf_perf_event_print_t fn, void *private_data); | ||
308 | |||
309 | struct nlattr; | ||
310 | typedef int (*libbpf_dump_nlmsg_t)(void *cookie, void *msg, struct nlattr **tb); | ||
311 | int libbpf_netlink_open(unsigned int *nl_pid); | ||
312 | int libbpf_nl_get_link(int sock, unsigned int nl_pid, | ||
313 | libbpf_dump_nlmsg_t dump_link_nlmsg, void *cookie); | ||
314 | int libbpf_nl_get_class(int sock, unsigned int nl_pid, int ifindex, | ||
315 | libbpf_dump_nlmsg_t dump_class_nlmsg, void *cookie); | ||
316 | int libbpf_nl_get_qdisc(int sock, unsigned int nl_pid, int ifindex, | ||
317 | libbpf_dump_nlmsg_t dump_qdisc_nlmsg, void *cookie); | ||
318 | int libbpf_nl_get_filter(int sock, unsigned int nl_pid, int ifindex, int handle, | ||
319 | libbpf_dump_nlmsg_t dump_filter_nlmsg, void *cookie); | ||
320 | #endif /* __LIBBPF_LIBBPF_H */ | ||
diff --git a/tools/lib/bpf/libbpf_errno.c b/tools/lib/bpf/libbpf_errno.c index d9ba851bd7f9..d83b17f8435c 100644 --- a/tools/lib/bpf/libbpf_errno.c +++ b/tools/lib/bpf/libbpf_errno.c | |||
@@ -1,23 +1,10 @@ | |||
1 | // SPDX-License-Identifier: LGPL-2.1 | 1 | // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (C) 2013-2015 Alexei Starovoitov <ast@kernel.org> | 4 | * Copyright (C) 2013-2015 Alexei Starovoitov <ast@kernel.org> |
5 | * Copyright (C) 2015 Wang Nan <wangnan0@huawei.com> | 5 | * Copyright (C) 2015 Wang Nan <wangnan0@huawei.com> |
6 | * Copyright (C) 2015 Huawei Inc. | 6 | * Copyright (C) 2015 Huawei Inc. |
7 | * Copyright (C) 2017 Nicira, Inc. | 7 | * Copyright (C) 2017 Nicira, Inc. |
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU Lesser General Public | ||
11 | * License as published by the Free Software Foundation; | ||
12 | * version 2.1 of the License (not later!) | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU Lesser General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU Lesser General Public | ||
20 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
21 | */ | 8 | */ |
22 | 9 | ||
23 | #include <stdio.h> | 10 | #include <stdio.h> |
@@ -42,6 +29,7 @@ static const char *libbpf_strerror_table[NR_ERRNO] = { | |||
42 | [ERRCODE_OFFSET(PROGTYPE)] = "Kernel doesn't support this program type", | 29 | [ERRCODE_OFFSET(PROGTYPE)] = "Kernel doesn't support this program type", |
43 | [ERRCODE_OFFSET(WRNGPID)] = "Wrong pid in netlink message", | 30 | [ERRCODE_OFFSET(WRNGPID)] = "Wrong pid in netlink message", |
44 | [ERRCODE_OFFSET(INVSEQ)] = "Invalid netlink sequence", | 31 | [ERRCODE_OFFSET(INVSEQ)] = "Invalid netlink sequence", |
32 | [ERRCODE_OFFSET(NLPARSE)] = "Incorrect netlink message parsing", | ||
45 | }; | 33 | }; |
46 | 34 | ||
47 | int libbpf_strerror(int err, char *buf, size_t size) | 35 | int libbpf_strerror(int err, char *buf, size_t size) |
diff --git a/tools/lib/bpf/netlink.c b/tools/lib/bpf/netlink.c new file mode 100644 index 000000000000..0ce67aea8f3b --- /dev/null +++ b/tools/lib/bpf/netlink.c | |||
@@ -0,0 +1,337 @@ | |||
1 | // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) | ||
2 | /* Copyright (c) 2018 Facebook */ | ||
3 | |||
4 | #include <stdlib.h> | ||
5 | #include <memory.h> | ||
6 | #include <unistd.h> | ||
7 | #include <linux/bpf.h> | ||
8 | #include <linux/rtnetlink.h> | ||
9 | #include <sys/socket.h> | ||
10 | #include <errno.h> | ||
11 | #include <time.h> | ||
12 | |||
13 | #include "bpf.h" | ||
14 | #include "libbpf.h" | ||
15 | #include "nlattr.h" | ||
16 | |||
17 | #ifndef SOL_NETLINK | ||
18 | #define SOL_NETLINK 270 | ||
19 | #endif | ||
20 | |||
21 | typedef int (*__dump_nlmsg_t)(struct nlmsghdr *nlmsg, libbpf_dump_nlmsg_t, | ||
22 | void *cookie); | ||
23 | |||
24 | int libbpf_netlink_open(__u32 *nl_pid) | ||
25 | { | ||
26 | struct sockaddr_nl sa; | ||
27 | socklen_t addrlen; | ||
28 | int one = 1, ret; | ||
29 | int sock; | ||
30 | |||
31 | memset(&sa, 0, sizeof(sa)); | ||
32 | sa.nl_family = AF_NETLINK; | ||
33 | |||
34 | sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); | ||
35 | if (sock < 0) | ||
36 | return -errno; | ||
37 | |||
38 | if (setsockopt(sock, SOL_NETLINK, NETLINK_EXT_ACK, | ||
39 | &one, sizeof(one)) < 0) { | ||
40 | fprintf(stderr, "Netlink error reporting not supported\n"); | ||
41 | } | ||
42 | |||
43 | if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) { | ||
44 | ret = -errno; | ||
45 | goto cleanup; | ||
46 | } | ||
47 | |||
48 | addrlen = sizeof(sa); | ||
49 | if (getsockname(sock, (struct sockaddr *)&sa, &addrlen) < 0) { | ||
50 | ret = -errno; | ||
51 | goto cleanup; | ||
52 | } | ||
53 | |||
54 | if (addrlen != sizeof(sa)) { | ||
55 | ret = -LIBBPF_ERRNO__INTERNAL; | ||
56 | goto cleanup; | ||
57 | } | ||
58 | |||
59 | *nl_pid = sa.nl_pid; | ||
60 | return sock; | ||
61 | |||
62 | cleanup: | ||
63 | close(sock); | ||
64 | return ret; | ||
65 | } | ||
66 | |||
67 | static int bpf_netlink_recv(int sock, __u32 nl_pid, int seq, | ||
68 | __dump_nlmsg_t _fn, libbpf_dump_nlmsg_t fn, | ||
69 | void *cookie) | ||
70 | { | ||
71 | bool multipart = true; | ||
72 | struct nlmsgerr *err; | ||
73 | struct nlmsghdr *nh; | ||
74 | char buf[4096]; | ||
75 | int len, ret; | ||
76 | |||
77 | while (multipart) { | ||
78 | multipart = false; | ||
79 | len = recv(sock, buf, sizeof(buf), 0); | ||
80 | if (len < 0) { | ||
81 | ret = -errno; | ||
82 | goto done; | ||
83 | } | ||
84 | |||
85 | if (len == 0) | ||
86 | break; | ||
87 | |||
88 | for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); | ||
89 | nh = NLMSG_NEXT(nh, len)) { | ||
90 | if (nh->nlmsg_pid != nl_pid) { | ||
91 | ret = -LIBBPF_ERRNO__WRNGPID; | ||
92 | goto done; | ||
93 | } | ||
94 | if (nh->nlmsg_seq != seq) { | ||
95 | ret = -LIBBPF_ERRNO__INVSEQ; | ||
96 | goto done; | ||
97 | } | ||
98 | if (nh->nlmsg_flags & NLM_F_MULTI) | ||
99 | multipart = true; | ||
100 | switch (nh->nlmsg_type) { | ||
101 | case NLMSG_ERROR: | ||
102 | err = (struct nlmsgerr *)NLMSG_DATA(nh); | ||
103 | if (!err->error) | ||
104 | continue; | ||
105 | ret = err->error; | ||
106 | libbpf_nla_dump_errormsg(nh); | ||
107 | goto done; | ||
108 | case NLMSG_DONE: | ||
109 | return 0; | ||
110 | default: | ||
111 | break; | ||
112 | } | ||
113 | if (_fn) { | ||
114 | ret = _fn(nh, fn, cookie); | ||
115 | if (ret) | ||
116 | return ret; | ||
117 | } | ||
118 | } | ||
119 | } | ||
120 | ret = 0; | ||
121 | done: | ||
122 | return ret; | ||
123 | } | ||
124 | |||
125 | int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags) | ||
126 | { | ||
127 | int sock, seq = 0, ret; | ||
128 | struct nlattr *nla, *nla_xdp; | ||
129 | struct { | ||
130 | struct nlmsghdr nh; | ||
131 | struct ifinfomsg ifinfo; | ||
132 | char attrbuf[64]; | ||
133 | } req; | ||
134 | __u32 nl_pid; | ||
135 | |||
136 | sock = libbpf_netlink_open(&nl_pid); | ||
137 | if (sock < 0) | ||
138 | return sock; | ||
139 | |||
140 | memset(&req, 0, sizeof(req)); | ||
141 | req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); | ||
142 | req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; | ||
143 | req.nh.nlmsg_type = RTM_SETLINK; | ||
144 | req.nh.nlmsg_pid = 0; | ||
145 | req.nh.nlmsg_seq = ++seq; | ||
146 | req.ifinfo.ifi_family = AF_UNSPEC; | ||
147 | req.ifinfo.ifi_index = ifindex; | ||
148 | |||
149 | /* started nested attribute for XDP */ | ||
150 | nla = (struct nlattr *)(((char *)&req) | ||
151 | + NLMSG_ALIGN(req.nh.nlmsg_len)); | ||
152 | nla->nla_type = NLA_F_NESTED | IFLA_XDP; | ||
153 | nla->nla_len = NLA_HDRLEN; | ||
154 | |||
155 | /* add XDP fd */ | ||
156 | nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len); | ||
157 | nla_xdp->nla_type = IFLA_XDP_FD; | ||
158 | nla_xdp->nla_len = NLA_HDRLEN + sizeof(int); | ||
159 | memcpy((char *)nla_xdp + NLA_HDRLEN, &fd, sizeof(fd)); | ||
160 | nla->nla_len += nla_xdp->nla_len; | ||
161 | |||
162 | /* if user passed in any flags, add those too */ | ||
163 | if (flags) { | ||
164 | nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len); | ||
165 | nla_xdp->nla_type = IFLA_XDP_FLAGS; | ||
166 | nla_xdp->nla_len = NLA_HDRLEN + sizeof(flags); | ||
167 | memcpy((char *)nla_xdp + NLA_HDRLEN, &flags, sizeof(flags)); | ||
168 | nla->nla_len += nla_xdp->nla_len; | ||
169 | } | ||
170 | |||
171 | req.nh.nlmsg_len += NLA_ALIGN(nla->nla_len); | ||
172 | |||
173 | if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) { | ||
174 | ret = -errno; | ||
175 | goto cleanup; | ||
176 | } | ||
177 | ret = bpf_netlink_recv(sock, nl_pid, seq, NULL, NULL, NULL); | ||
178 | |||
179 | cleanup: | ||
180 | close(sock); | ||
181 | return ret; | ||
182 | } | ||
183 | |||
184 | static int __dump_link_nlmsg(struct nlmsghdr *nlh, | ||
185 | libbpf_dump_nlmsg_t dump_link_nlmsg, void *cookie) | ||
186 | { | ||
187 | struct nlattr *tb[IFLA_MAX + 1], *attr; | ||
188 | struct ifinfomsg *ifi = NLMSG_DATA(nlh); | ||
189 | int len; | ||
190 | |||
191 | len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)); | ||
192 | attr = (struct nlattr *) ((void *) ifi + NLMSG_ALIGN(sizeof(*ifi))); | ||
193 | if (libbpf_nla_parse(tb, IFLA_MAX, attr, len, NULL) != 0) | ||
194 | return -LIBBPF_ERRNO__NLPARSE; | ||
195 | |||
196 | return dump_link_nlmsg(cookie, ifi, tb); | ||
197 | } | ||
198 | |||
199 | int libbpf_nl_get_link(int sock, unsigned int nl_pid, | ||
200 | libbpf_dump_nlmsg_t dump_link_nlmsg, void *cookie) | ||
201 | { | ||
202 | struct { | ||
203 | struct nlmsghdr nlh; | ||
204 | struct ifinfomsg ifm; | ||
205 | } req = { | ||
206 | .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)), | ||
207 | .nlh.nlmsg_type = RTM_GETLINK, | ||
208 | .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, | ||
209 | .ifm.ifi_family = AF_PACKET, | ||
210 | }; | ||
211 | int seq = time(NULL); | ||
212 | |||
213 | req.nlh.nlmsg_seq = seq; | ||
214 | if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0) | ||
215 | return -errno; | ||
216 | |||
217 | return bpf_netlink_recv(sock, nl_pid, seq, __dump_link_nlmsg, | ||
218 | dump_link_nlmsg, cookie); | ||
219 | } | ||
220 | |||
221 | static int __dump_class_nlmsg(struct nlmsghdr *nlh, | ||
222 | libbpf_dump_nlmsg_t dump_class_nlmsg, | ||
223 | void *cookie) | ||
224 | { | ||
225 | struct nlattr *tb[TCA_MAX + 1], *attr; | ||
226 | struct tcmsg *t = NLMSG_DATA(nlh); | ||
227 | int len; | ||
228 | |||
229 | len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*t)); | ||
230 | attr = (struct nlattr *) ((void *) t + NLMSG_ALIGN(sizeof(*t))); | ||
231 | if (libbpf_nla_parse(tb, TCA_MAX, attr, len, NULL) != 0) | ||
232 | return -LIBBPF_ERRNO__NLPARSE; | ||
233 | |||
234 | return dump_class_nlmsg(cookie, t, tb); | ||
235 | } | ||
236 | |||
237 | int libbpf_nl_get_class(int sock, unsigned int nl_pid, int ifindex, | ||
238 | libbpf_dump_nlmsg_t dump_class_nlmsg, void *cookie) | ||
239 | { | ||
240 | struct { | ||
241 | struct nlmsghdr nlh; | ||
242 | struct tcmsg t; | ||
243 | } req = { | ||
244 | .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)), | ||
245 | .nlh.nlmsg_type = RTM_GETTCLASS, | ||
246 | .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, | ||
247 | .t.tcm_family = AF_UNSPEC, | ||
248 | .t.tcm_ifindex = ifindex, | ||
249 | }; | ||
250 | int seq = time(NULL); | ||
251 | |||
252 | req.nlh.nlmsg_seq = seq; | ||
253 | if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0) | ||
254 | return -errno; | ||
255 | |||
256 | return bpf_netlink_recv(sock, nl_pid, seq, __dump_class_nlmsg, | ||
257 | dump_class_nlmsg, cookie); | ||
258 | } | ||
259 | |||
260 | static int __dump_qdisc_nlmsg(struct nlmsghdr *nlh, | ||
261 | libbpf_dump_nlmsg_t dump_qdisc_nlmsg, | ||
262 | void *cookie) | ||
263 | { | ||
264 | struct nlattr *tb[TCA_MAX + 1], *attr; | ||
265 | struct tcmsg *t = NLMSG_DATA(nlh); | ||
266 | int len; | ||
267 | |||
268 | len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*t)); | ||
269 | attr = (struct nlattr *) ((void *) t + NLMSG_ALIGN(sizeof(*t))); | ||
270 | if (libbpf_nla_parse(tb, TCA_MAX, attr, len, NULL) != 0) | ||
271 | return -LIBBPF_ERRNO__NLPARSE; | ||
272 | |||
273 | return dump_qdisc_nlmsg(cookie, t, tb); | ||
274 | } | ||
275 | |||
276 | int libbpf_nl_get_qdisc(int sock, unsigned int nl_pid, int ifindex, | ||
277 | libbpf_dump_nlmsg_t dump_qdisc_nlmsg, void *cookie) | ||
278 | { | ||
279 | struct { | ||
280 | struct nlmsghdr nlh; | ||
281 | struct tcmsg t; | ||
282 | } req = { | ||
283 | .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)), | ||
284 | .nlh.nlmsg_type = RTM_GETQDISC, | ||
285 | .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, | ||
286 | .t.tcm_family = AF_UNSPEC, | ||
287 | .t.tcm_ifindex = ifindex, | ||
288 | }; | ||
289 | int seq = time(NULL); | ||
290 | |||
291 | req.nlh.nlmsg_seq = seq; | ||
292 | if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0) | ||
293 | return -errno; | ||
294 | |||
295 | return bpf_netlink_recv(sock, nl_pid, seq, __dump_qdisc_nlmsg, | ||
296 | dump_qdisc_nlmsg, cookie); | ||
297 | } | ||
298 | |||
299 | static int __dump_filter_nlmsg(struct nlmsghdr *nlh, | ||
300 | libbpf_dump_nlmsg_t dump_filter_nlmsg, | ||
301 | void *cookie) | ||
302 | { | ||
303 | struct nlattr *tb[TCA_MAX + 1], *attr; | ||
304 | struct tcmsg *t = NLMSG_DATA(nlh); | ||
305 | int len; | ||
306 | |||
307 | len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*t)); | ||
308 | attr = (struct nlattr *) ((void *) t + NLMSG_ALIGN(sizeof(*t))); | ||
309 | if (libbpf_nla_parse(tb, TCA_MAX, attr, len, NULL) != 0) | ||
310 | return -LIBBPF_ERRNO__NLPARSE; | ||
311 | |||
312 | return dump_filter_nlmsg(cookie, t, tb); | ||
313 | } | ||
314 | |||
315 | int libbpf_nl_get_filter(int sock, unsigned int nl_pid, int ifindex, int handle, | ||
316 | libbpf_dump_nlmsg_t dump_filter_nlmsg, void *cookie) | ||
317 | { | ||
318 | struct { | ||
319 | struct nlmsghdr nlh; | ||
320 | struct tcmsg t; | ||
321 | } req = { | ||
322 | .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)), | ||
323 | .nlh.nlmsg_type = RTM_GETTFILTER, | ||
324 | .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, | ||
325 | .t.tcm_family = AF_UNSPEC, | ||
326 | .t.tcm_ifindex = ifindex, | ||
327 | .t.tcm_parent = handle, | ||
328 | }; | ||
329 | int seq = time(NULL); | ||
330 | |||
331 | req.nlh.nlmsg_seq = seq; | ||
332 | if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0) | ||
333 | return -errno; | ||
334 | |||
335 | return bpf_netlink_recv(sock, nl_pid, seq, __dump_filter_nlmsg, | ||
336 | dump_filter_nlmsg, cookie); | ||
337 | } | ||
diff --git a/tools/lib/bpf/nlattr.c b/tools/lib/bpf/nlattr.c index 4719434278b2..1e69c0c8d413 100644 --- a/tools/lib/bpf/nlattr.c +++ b/tools/lib/bpf/nlattr.c | |||
@@ -1,13 +1,8 @@ | |||
1 | // SPDX-License-Identifier: LGPL-2.1 | 1 | // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * NETLINK Netlink attributes | 4 | * NETLINK Netlink attributes |
5 | * | 5 | * |
6 | * This library is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU Lesser General Public | ||
8 | * License as published by the Free Software Foundation version 2.1 | ||
9 | * of the License. | ||
10 | * | ||
11 | * Copyright (c) 2003-2013 Thomas Graf <tgraf@suug.ch> | 6 | * Copyright (c) 2003-2013 Thomas Graf <tgraf@suug.ch> |
12 | */ | 7 | */ |
13 | 8 | ||
@@ -17,20 +12,15 @@ | |||
17 | #include <string.h> | 12 | #include <string.h> |
18 | #include <stdio.h> | 13 | #include <stdio.h> |
19 | 14 | ||
20 | static uint16_t nla_attr_minlen[NLA_TYPE_MAX+1] = { | 15 | static uint16_t nla_attr_minlen[LIBBPF_NLA_TYPE_MAX+1] = { |
21 | [NLA_U8] = sizeof(uint8_t), | 16 | [LIBBPF_NLA_U8] = sizeof(uint8_t), |
22 | [NLA_U16] = sizeof(uint16_t), | 17 | [LIBBPF_NLA_U16] = sizeof(uint16_t), |
23 | [NLA_U32] = sizeof(uint32_t), | 18 | [LIBBPF_NLA_U32] = sizeof(uint32_t), |
24 | [NLA_U64] = sizeof(uint64_t), | 19 | [LIBBPF_NLA_U64] = sizeof(uint64_t), |
25 | [NLA_STRING] = 1, | 20 | [LIBBPF_NLA_STRING] = 1, |
26 | [NLA_FLAG] = 0, | 21 | [LIBBPF_NLA_FLAG] = 0, |
27 | }; | 22 | }; |
28 | 23 | ||
29 | static int nla_len(const struct nlattr *nla) | ||
30 | { | ||
31 | return nla->nla_len - NLA_HDRLEN; | ||
32 | } | ||
33 | |||
34 | static struct nlattr *nla_next(const struct nlattr *nla, int *remaining) | 24 | static struct nlattr *nla_next(const struct nlattr *nla, int *remaining) |
35 | { | 25 | { |
36 | int totlen = NLA_ALIGN(nla->nla_len); | 26 | int totlen = NLA_ALIGN(nla->nla_len); |
@@ -46,20 +36,15 @@ static int nla_ok(const struct nlattr *nla, int remaining) | |||
46 | nla->nla_len <= remaining; | 36 | nla->nla_len <= remaining; |
47 | } | 37 | } |
48 | 38 | ||
49 | static void *nla_data(const struct nlattr *nla) | ||
50 | { | ||
51 | return (char *) nla + NLA_HDRLEN; | ||
52 | } | ||
53 | |||
54 | static int nla_type(const struct nlattr *nla) | 39 | static int nla_type(const struct nlattr *nla) |
55 | { | 40 | { |
56 | return nla->nla_type & NLA_TYPE_MASK; | 41 | return nla->nla_type & NLA_TYPE_MASK; |
57 | } | 42 | } |
58 | 43 | ||
59 | static int validate_nla(struct nlattr *nla, int maxtype, | 44 | static int validate_nla(struct nlattr *nla, int maxtype, |
60 | struct nla_policy *policy) | 45 | struct libbpf_nla_policy *policy) |
61 | { | 46 | { |
62 | struct nla_policy *pt; | 47 | struct libbpf_nla_policy *pt; |
63 | unsigned int minlen = 0; | 48 | unsigned int minlen = 0; |
64 | int type = nla_type(nla); | 49 | int type = nla_type(nla); |
65 | 50 | ||
@@ -68,23 +53,24 @@ static int validate_nla(struct nlattr *nla, int maxtype, | |||
68 | 53 | ||
69 | pt = &policy[type]; | 54 | pt = &policy[type]; |
70 | 55 | ||
71 | if (pt->type > NLA_TYPE_MAX) | 56 | if (pt->type > LIBBPF_NLA_TYPE_MAX) |
72 | return 0; | 57 | return 0; |
73 | 58 | ||
74 | if (pt->minlen) | 59 | if (pt->minlen) |
75 | minlen = pt->minlen; | 60 | minlen = pt->minlen; |
76 | else if (pt->type != NLA_UNSPEC) | 61 | else if (pt->type != LIBBPF_NLA_UNSPEC) |
77 | minlen = nla_attr_minlen[pt->type]; | 62 | minlen = nla_attr_minlen[pt->type]; |
78 | 63 | ||
79 | if (nla_len(nla) < minlen) | 64 | if (libbpf_nla_len(nla) < minlen) |
80 | return -1; | 65 | return -1; |
81 | 66 | ||
82 | if (pt->maxlen && nla_len(nla) > pt->maxlen) | 67 | if (pt->maxlen && libbpf_nla_len(nla) > pt->maxlen) |
83 | return -1; | 68 | return -1; |
84 | 69 | ||
85 | if (pt->type == NLA_STRING) { | 70 | if (pt->type == LIBBPF_NLA_STRING) { |
86 | char *data = nla_data(nla); | 71 | char *data = libbpf_nla_data(nla); |
87 | if (data[nla_len(nla) - 1] != '\0') | 72 | |
73 | if (data[libbpf_nla_len(nla) - 1] != '\0') | ||
88 | return -1; | 74 | return -1; |
89 | } | 75 | } |
90 | 76 | ||
@@ -114,15 +100,15 @@ static inline int nlmsg_len(const struct nlmsghdr *nlh) | |||
114 | * @see nla_validate | 100 | * @see nla_validate |
115 | * @return 0 on success or a negative error code. | 101 | * @return 0 on success or a negative error code. |
116 | */ | 102 | */ |
117 | static int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len, | 103 | int libbpf_nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, |
118 | struct nla_policy *policy) | 104 | int len, struct libbpf_nla_policy *policy) |
119 | { | 105 | { |
120 | struct nlattr *nla; | 106 | struct nlattr *nla; |
121 | int rem, err; | 107 | int rem, err; |
122 | 108 | ||
123 | memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1)); | 109 | memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1)); |
124 | 110 | ||
125 | nla_for_each_attr(nla, head, len, rem) { | 111 | libbpf_nla_for_each_attr(nla, head, len, rem) { |
126 | int type = nla_type(nla); | 112 | int type = nla_type(nla); |
127 | 113 | ||
128 | if (type > maxtype) | 114 | if (type > maxtype) |
@@ -146,12 +132,33 @@ errout: | |||
146 | return err; | 132 | return err; |
147 | } | 133 | } |
148 | 134 | ||
135 | /** | ||
136 | * Create attribute index based on nested attribute | ||
137 | * @arg tb Index array to be filled (maxtype+1 elements). | ||
138 | * @arg maxtype Maximum attribute type expected and accepted. | ||
139 | * @arg nla Nested Attribute. | ||
140 | * @arg policy Attribute validation policy. | ||
141 | * | ||
142 | * Feeds the stream of attributes nested into the specified attribute | ||
143 | * to libbpf_nla_parse(). | ||
144 | * | ||
145 | * @see libbpf_nla_parse | ||
146 | * @return 0 on success or a negative error code. | ||
147 | */ | ||
148 | int libbpf_nla_parse_nested(struct nlattr *tb[], int maxtype, | ||
149 | struct nlattr *nla, | ||
150 | struct libbpf_nla_policy *policy) | ||
151 | { | ||
152 | return libbpf_nla_parse(tb, maxtype, libbpf_nla_data(nla), | ||
153 | libbpf_nla_len(nla), policy); | ||
154 | } | ||
155 | |||
149 | /* dump netlink extended ack error message */ | 156 | /* dump netlink extended ack error message */ |
150 | int nla_dump_errormsg(struct nlmsghdr *nlh) | 157 | int libbpf_nla_dump_errormsg(struct nlmsghdr *nlh) |
151 | { | 158 | { |
152 | struct nla_policy extack_policy[NLMSGERR_ATTR_MAX + 1] = { | 159 | struct libbpf_nla_policy extack_policy[NLMSGERR_ATTR_MAX + 1] = { |
153 | [NLMSGERR_ATTR_MSG] = { .type = NLA_STRING }, | 160 | [NLMSGERR_ATTR_MSG] = { .type = LIBBPF_NLA_STRING }, |
154 | [NLMSGERR_ATTR_OFFS] = { .type = NLA_U32 }, | 161 | [NLMSGERR_ATTR_OFFS] = { .type = LIBBPF_NLA_U32 }, |
155 | }; | 162 | }; |
156 | struct nlattr *tb[NLMSGERR_ATTR_MAX + 1], *attr; | 163 | struct nlattr *tb[NLMSGERR_ATTR_MAX + 1], *attr; |
157 | struct nlmsgerr *err; | 164 | struct nlmsgerr *err; |
@@ -172,14 +179,15 @@ int nla_dump_errormsg(struct nlmsghdr *nlh) | |||
172 | attr = (struct nlattr *) ((void *) err + hlen); | 179 | attr = (struct nlattr *) ((void *) err + hlen); |
173 | alen = nlh->nlmsg_len - hlen; | 180 | alen = nlh->nlmsg_len - hlen; |
174 | 181 | ||
175 | if (nla_parse(tb, NLMSGERR_ATTR_MAX, attr, alen, extack_policy) != 0) { | 182 | if (libbpf_nla_parse(tb, NLMSGERR_ATTR_MAX, attr, alen, |
183 | extack_policy) != 0) { | ||
176 | fprintf(stderr, | 184 | fprintf(stderr, |
177 | "Failed to parse extended error attributes\n"); | 185 | "Failed to parse extended error attributes\n"); |
178 | return 0; | 186 | return 0; |
179 | } | 187 | } |
180 | 188 | ||
181 | if (tb[NLMSGERR_ATTR_MSG]) | 189 | if (tb[NLMSGERR_ATTR_MSG]) |
182 | errmsg = (char *) nla_data(tb[NLMSGERR_ATTR_MSG]); | 190 | errmsg = (char *) libbpf_nla_data(tb[NLMSGERR_ATTR_MSG]); |
183 | 191 | ||
184 | fprintf(stderr, "Kernel error message: %s\n", errmsg); | 192 | fprintf(stderr, "Kernel error message: %s\n", errmsg); |
185 | 193 | ||
diff --git a/tools/lib/bpf/nlattr.h b/tools/lib/bpf/nlattr.h index 931a71f68f93..6cc3ac91690f 100644 --- a/tools/lib/bpf/nlattr.h +++ b/tools/lib/bpf/nlattr.h | |||
@@ -1,18 +1,13 @@ | |||
1 | /* SPDX-License-Identifier: LGPL-2.1 */ | 1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * NETLINK Netlink attributes | 4 | * NETLINK Netlink attributes |
5 | * | 5 | * |
6 | * This library is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU Lesser General Public | ||
8 | * License as published by the Free Software Foundation version 2.1 | ||
9 | * of the License. | ||
10 | * | ||
11 | * Copyright (c) 2003-2013 Thomas Graf <tgraf@suug.ch> | 6 | * Copyright (c) 2003-2013 Thomas Graf <tgraf@suug.ch> |
12 | */ | 7 | */ |
13 | 8 | ||
14 | #ifndef __NLATTR_H | 9 | #ifndef __LIBBPF_NLATTR_H |
15 | #define __NLATTR_H | 10 | #define __LIBBPF_NLATTR_H |
16 | 11 | ||
17 | #include <stdint.h> | 12 | #include <stdint.h> |
18 | #include <linux/netlink.h> | 13 | #include <linux/netlink.h> |
@@ -23,19 +18,19 @@ | |||
23 | * Standard attribute types to specify validation policy | 18 | * Standard attribute types to specify validation policy |
24 | */ | 19 | */ |
25 | enum { | 20 | enum { |
26 | NLA_UNSPEC, /**< Unspecified type, binary data chunk */ | 21 | LIBBPF_NLA_UNSPEC, /**< Unspecified type, binary data chunk */ |
27 | NLA_U8, /**< 8 bit integer */ | 22 | LIBBPF_NLA_U8, /**< 8 bit integer */ |
28 | NLA_U16, /**< 16 bit integer */ | 23 | LIBBPF_NLA_U16, /**< 16 bit integer */ |
29 | NLA_U32, /**< 32 bit integer */ | 24 | LIBBPF_NLA_U32, /**< 32 bit integer */ |
30 | NLA_U64, /**< 64 bit integer */ | 25 | LIBBPF_NLA_U64, /**< 64 bit integer */ |
31 | NLA_STRING, /**< NUL terminated character string */ | 26 | LIBBPF_NLA_STRING, /**< NUL terminated character string */ |
32 | NLA_FLAG, /**< Flag */ | 27 | LIBBPF_NLA_FLAG, /**< Flag */ |
33 | NLA_MSECS, /**< Micro seconds (64bit) */ | 28 | LIBBPF_NLA_MSECS, /**< Micro seconds (64bit) */ |
34 | NLA_NESTED, /**< Nested attributes */ | 29 | LIBBPF_NLA_NESTED, /**< Nested attributes */ |
35 | __NLA_TYPE_MAX, | 30 | __LIBBPF_NLA_TYPE_MAX, |
36 | }; | 31 | }; |
37 | 32 | ||
38 | #define NLA_TYPE_MAX (__NLA_TYPE_MAX - 1) | 33 | #define LIBBPF_NLA_TYPE_MAX (__LIBBPF_NLA_TYPE_MAX - 1) |
39 | 34 | ||
40 | /** | 35 | /** |
41 | * @ingroup attr | 36 | * @ingroup attr |
@@ -43,8 +38,8 @@ enum { | |||
43 | * | 38 | * |
44 | * See section @core_doc{core_attr_parse,Attribute Parsing} for more details. | 39 | * See section @core_doc{core_attr_parse,Attribute Parsing} for more details. |
45 | */ | 40 | */ |
46 | struct nla_policy { | 41 | struct libbpf_nla_policy { |
47 | /** Type of attribute or NLA_UNSPEC */ | 42 | /** Type of attribute or LIBBPF_NLA_UNSPEC */ |
48 | uint16_t type; | 43 | uint16_t type; |
49 | 44 | ||
50 | /** Minimal length of payload required */ | 45 | /** Minimal length of payload required */ |
@@ -62,11 +57,50 @@ struct nla_policy { | |||
62 | * @arg len length of attribute stream | 57 | * @arg len length of attribute stream |
63 | * @arg rem initialized to len, holds bytes currently remaining in stream | 58 | * @arg rem initialized to len, holds bytes currently remaining in stream |
64 | */ | 59 | */ |
65 | #define nla_for_each_attr(pos, head, len, rem) \ | 60 | #define libbpf_nla_for_each_attr(pos, head, len, rem) \ |
66 | for (pos = head, rem = len; \ | 61 | for (pos = head, rem = len; \ |
67 | nla_ok(pos, rem); \ | 62 | nla_ok(pos, rem); \ |
68 | pos = nla_next(pos, &(rem))) | 63 | pos = nla_next(pos, &(rem))) |
69 | 64 | ||
70 | int nla_dump_errormsg(struct nlmsghdr *nlh); | 65 | /** |
66 | * libbpf_nla_data - head of payload | ||
67 | * @nla: netlink attribute | ||
68 | */ | ||
69 | static inline void *libbpf_nla_data(const struct nlattr *nla) | ||
70 | { | ||
71 | return (char *) nla + NLA_HDRLEN; | ||
72 | } | ||
73 | |||
74 | static inline uint8_t libbpf_nla_getattr_u8(const struct nlattr *nla) | ||
75 | { | ||
76 | return *(uint8_t *)libbpf_nla_data(nla); | ||
77 | } | ||
78 | |||
79 | static inline uint32_t libbpf_nla_getattr_u32(const struct nlattr *nla) | ||
80 | { | ||
81 | return *(uint32_t *)libbpf_nla_data(nla); | ||
82 | } | ||
83 | |||
84 | static inline const char *libbpf_nla_getattr_str(const struct nlattr *nla) | ||
85 | { | ||
86 | return (const char *)libbpf_nla_data(nla); | ||
87 | } | ||
88 | |||
89 | /** | ||
90 | * libbpf_nla_len - length of payload | ||
91 | * @nla: netlink attribute | ||
92 | */ | ||
93 | static inline int libbpf_nla_len(const struct nlattr *nla) | ||
94 | { | ||
95 | return nla->nla_len - NLA_HDRLEN; | ||
96 | } | ||
97 | |||
98 | int libbpf_nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, | ||
99 | int len, struct libbpf_nla_policy *policy); | ||
100 | int libbpf_nla_parse_nested(struct nlattr *tb[], int maxtype, | ||
101 | struct nlattr *nla, | ||
102 | struct libbpf_nla_policy *policy); | ||
103 | |||
104 | int libbpf_nla_dump_errormsg(struct nlmsghdr *nlh); | ||
71 | 105 | ||
72 | #endif /* __NLATTR_H */ | 106 | #endif /* __LIBBPF_NLATTR_H */ |
diff --git a/tools/lib/bpf/str_error.c b/tools/lib/bpf/str_error.c index b8798114a357..00e48ac5b806 100644 --- a/tools/lib/bpf/str_error.c +++ b/tools/lib/bpf/str_error.c | |||
@@ -1,4 +1,4 @@ | |||
1 | // SPDX-License-Identifier: LGPL-2.1 | 1 | // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) |
2 | #undef _GNU_SOURCE | 2 | #undef _GNU_SOURCE |
3 | #include <string.h> | 3 | #include <string.h> |
4 | #include <stdio.h> | 4 | #include <stdio.h> |
@@ -9,7 +9,7 @@ | |||
9 | * libc, while checking strerror_r() return to avoid having to check this in | 9 | * libc, while checking strerror_r() return to avoid having to check this in |
10 | * all places calling it. | 10 | * all places calling it. |
11 | */ | 11 | */ |
12 | char *str_error(int err, char *dst, int len) | 12 | char *libbpf_strerror_r(int err, char *dst, int len) |
13 | { | 13 | { |
14 | int ret = strerror_r(err, dst, len); | 14 | int ret = strerror_r(err, dst, len); |
15 | if (ret) | 15 | if (ret) |
diff --git a/tools/lib/bpf/str_error.h b/tools/lib/bpf/str_error.h index 355b1db571d1..a139334d57b6 100644 --- a/tools/lib/bpf/str_error.h +++ b/tools/lib/bpf/str_error.h | |||
@@ -1,6 +1,6 @@ | |||
1 | // SPDX-License-Identifier: LGPL-2.1 | 1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ |
2 | #ifndef BPF_STR_ERROR | 2 | #ifndef __LIBBPF_STR_ERROR_H |
3 | #define BPF_STR_ERROR | 3 | #define __LIBBPF_STR_ERROR_H |
4 | 4 | ||
5 | char *str_error(int err, char *dst, int len); | 5 | char *libbpf_strerror_r(int err, char *dst, int len); |
6 | #endif // BPF_STR_ERROR | 6 | #endif /* __LIBBPF_STR_ERROR_H */ |
diff --git a/tools/pci/Build b/tools/pci/Build new file mode 100644 index 000000000000..c375aea21790 --- /dev/null +++ b/tools/pci/Build | |||
@@ -0,0 +1 @@ | |||
pcitest-y += pcitest.o | |||
diff --git a/tools/pci/Makefile b/tools/pci/Makefile new file mode 100644 index 000000000000..46e4c2f318c9 --- /dev/null +++ b/tools/pci/Makefile | |||
@@ -0,0 +1,53 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 | ||
2 | include ../scripts/Makefile.include | ||
3 | |||
4 | bindir ?= /usr/bin | ||
5 | |||
6 | ifeq ($(srctree),) | ||
7 | srctree := $(patsubst %/,%,$(dir $(CURDIR))) | ||
8 | srctree := $(patsubst %/,%,$(dir $(srctree))) | ||
9 | endif | ||
10 | |||
11 | # Do not use make's built-in rules | ||
12 | # (this improves performance and avoids hard-to-debug behaviour); | ||
13 | MAKEFLAGS += -r | ||
14 | |||
15 | CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include | ||
16 | |||
17 | ALL_TARGETS := pcitest pcitest.sh | ||
18 | ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS)) | ||
19 | |||
20 | all: $(ALL_PROGRAMS) | ||
21 | |||
22 | export srctree OUTPUT CC LD CFLAGS | ||
23 | include $(srctree)/tools/build/Makefile.include | ||
24 | |||
25 | # | ||
26 | # We need the following to be outside of kernel tree | ||
27 | # | ||
28 | $(OUTPUT)include/linux/: ../../include/uapi/linux/ | ||
29 | mkdir -p $(OUTPUT)include/linux/ 2>&1 || true | ||
30 | ln -sf $(CURDIR)/../../include/uapi/linux/pcitest.h $@ | ||
31 | |||
32 | prepare: $(OUTPUT)include/linux/ | ||
33 | |||
34 | PCITEST_IN := $(OUTPUT)pcitest-in.o | ||
35 | $(PCITEST_IN): prepare FORCE | ||
36 | $(Q)$(MAKE) $(build)=pcitest | ||
37 | $(OUTPUT)pcitest: $(PCITEST_IN) | ||
38 | $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ | ||
39 | |||
40 | clean: | ||
41 | rm -f $(ALL_PROGRAMS) | ||
42 | rm -rf $(OUTPUT)include/ | ||
43 | find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.d' -delete | ||
44 | |||
45 | install: $(ALL_PROGRAMS) | ||
46 | install -d -m 755 $(DESTDIR)$(bindir); \ | ||
47 | for program in $(ALL_PROGRAMS); do \ | ||
48 | install $$program $(DESTDIR)$(bindir); \ | ||
49 | done | ||
50 | |||
51 | FORCE: | ||
52 | |||
53 | .PHONY: all install clean FORCE prepare | ||
diff --git a/tools/pci/pcitest.c b/tools/pci/pcitest.c index af146bb03b4d..ec4d51f3308b 100644 --- a/tools/pci/pcitest.c +++ b/tools/pci/pcitest.c | |||
@@ -23,7 +23,6 @@ | |||
23 | #include <stdio.h> | 23 | #include <stdio.h> |
24 | #include <stdlib.h> | 24 | #include <stdlib.h> |
25 | #include <sys/ioctl.h> | 25 | #include <sys/ioctl.h> |
26 | #include <time.h> | ||
27 | #include <unistd.h> | 26 | #include <unistd.h> |
28 | 27 | ||
29 | #include <linux/pcitest.h> | 28 | #include <linux/pcitest.h> |
@@ -48,17 +47,15 @@ struct pci_test { | |||
48 | unsigned long size; | 47 | unsigned long size; |
49 | }; | 48 | }; |
50 | 49 | ||
51 | static int run_test(struct pci_test *test) | 50 | static void run_test(struct pci_test *test) |
52 | { | 51 | { |
53 | long ret; | 52 | long ret; |
54 | int fd; | 53 | int fd; |
55 | struct timespec start, end; | ||
56 | double time; | ||
57 | 54 | ||
58 | fd = open(test->device, O_RDWR); | 55 | fd = open(test->device, O_RDWR); |
59 | if (fd < 0) { | 56 | if (fd < 0) { |
60 | perror("can't open PCI Endpoint Test device"); | 57 | perror("can't open PCI Endpoint Test device"); |
61 | return fd; | 58 | return; |
62 | } | 59 | } |
63 | 60 | ||
64 | if (test->barnum >= 0 && test->barnum <= 5) { | 61 | if (test->barnum >= 0 && test->barnum <= 5) { |
diff --git a/tools/perf/arch/powerpc/util/book3s_hv_exits.h b/tools/perf/arch/powerpc/util/book3s_hv_exits.h index 853b95d1e139..2011376c7ab5 100644 --- a/tools/perf/arch/powerpc/util/book3s_hv_exits.h +++ b/tools/perf/arch/powerpc/util/book3s_hv_exits.h | |||
@@ -15,7 +15,6 @@ | |||
15 | {0x400, "INST_STORAGE"}, \ | 15 | {0x400, "INST_STORAGE"}, \ |
16 | {0x480, "INST_SEGMENT"}, \ | 16 | {0x480, "INST_SEGMENT"}, \ |
17 | {0x500, "EXTERNAL"}, \ | 17 | {0x500, "EXTERNAL"}, \ |
18 | {0x501, "EXTERNAL_LEVEL"}, \ | ||
19 | {0x502, "EXTERNAL_HV"}, \ | 18 | {0x502, "EXTERNAL_HV"}, \ |
20 | {0x600, "ALIGNMENT"}, \ | 19 | {0x600, "ALIGNMENT"}, \ |
21 | {0x700, "PROGRAM"}, \ | 20 | {0x700, "PROGRAM"}, \ |
diff --git a/tools/perf/util/mmap.h b/tools/perf/util/mmap.h index e603314dc792..cc5e2d6d17a9 100644 --- a/tools/perf/util/mmap.h +++ b/tools/perf/util/mmap.h | |||
@@ -4,7 +4,7 @@ | |||
4 | #include <linux/compiler.h> | 4 | #include <linux/compiler.h> |
5 | #include <linux/refcount.h> | 5 | #include <linux/refcount.h> |
6 | #include <linux/types.h> | 6 | #include <linux/types.h> |
7 | #include <asm/barrier.h> | 7 | #include <linux/ring_buffer.h> |
8 | #include <stdbool.h> | 8 | #include <stdbool.h> |
9 | #include "auxtrace.h" | 9 | #include "auxtrace.h" |
10 | #include "event.h" | 10 | #include "event.h" |
@@ -71,21 +71,12 @@ void perf_mmap__consume(struct perf_mmap *map); | |||
71 | 71 | ||
72 | static inline u64 perf_mmap__read_head(struct perf_mmap *mm) | 72 | static inline u64 perf_mmap__read_head(struct perf_mmap *mm) |
73 | { | 73 | { |
74 | struct perf_event_mmap_page *pc = mm->base; | 74 | return ring_buffer_read_head(mm->base); |
75 | u64 head = READ_ONCE(pc->data_head); | ||
76 | rmb(); | ||
77 | return head; | ||
78 | } | 75 | } |
79 | 76 | ||
80 | static inline void perf_mmap__write_tail(struct perf_mmap *md, u64 tail) | 77 | static inline void perf_mmap__write_tail(struct perf_mmap *md, u64 tail) |
81 | { | 78 | { |
82 | struct perf_event_mmap_page *pc = md->base; | 79 | ring_buffer_write_tail(md->base, tail); |
83 | |||
84 | /* | ||
85 | * ensure all reads are done before we write the tail out. | ||
86 | */ | ||
87 | mb(); | ||
88 | pc->data_tail = tail; | ||
89 | } | 80 | } |
90 | 81 | ||
91 | union perf_event *perf_mmap__read_forward(struct perf_mmap *map); | 82 | union perf_event *perf_mmap__read_forward(struct perf_mmap *map); |
diff --git a/tools/testing/nvdimm/Kbuild b/tools/testing/nvdimm/Kbuild index 0392153a0009..778ceb651000 100644 --- a/tools/testing/nvdimm/Kbuild +++ b/tools/testing/nvdimm/Kbuild | |||
@@ -22,6 +22,7 @@ NVDIMM_SRC := $(DRIVERS)/nvdimm | |||
22 | ACPI_SRC := $(DRIVERS)/acpi/nfit | 22 | ACPI_SRC := $(DRIVERS)/acpi/nfit |
23 | DAX_SRC := $(DRIVERS)/dax | 23 | DAX_SRC := $(DRIVERS)/dax |
24 | ccflags-y := -I$(src)/$(NVDIMM_SRC)/ | 24 | ccflags-y := -I$(src)/$(NVDIMM_SRC)/ |
25 | ccflags-y += -I$(src)/$(ACPI_SRC)/ | ||
25 | 26 | ||
26 | obj-$(CONFIG_LIBNVDIMM) += libnvdimm.o | 27 | obj-$(CONFIG_LIBNVDIMM) += libnvdimm.o |
27 | obj-$(CONFIG_BLK_DEV_PMEM) += nd_pmem.o | 28 | obj-$(CONFIG_BLK_DEV_PMEM) += nd_pmem.o |
diff --git a/tools/testing/nvdimm/acpi_nfit_test.c b/tools/testing/nvdimm/acpi_nfit_test.c index 43521512e577..fec8fb1b7715 100644 --- a/tools/testing/nvdimm/acpi_nfit_test.c +++ b/tools/testing/nvdimm/acpi_nfit_test.c | |||
@@ -4,5 +4,13 @@ | |||
4 | #include <linux/module.h> | 4 | #include <linux/module.h> |
5 | #include <linux/printk.h> | 5 | #include <linux/printk.h> |
6 | #include "watermark.h" | 6 | #include "watermark.h" |
7 | #include <nfit.h> | ||
7 | 8 | ||
8 | nfit_test_watermark(acpi_nfit); | 9 | nfit_test_watermark(acpi_nfit); |
10 | |||
11 | /* strong / override definition of nfit_intel_shutdown_status */ | ||
12 | void nfit_intel_shutdown_status(struct nfit_mem *nfit_mem) | ||
13 | { | ||
14 | set_bit(NFIT_MEM_DIRTY_COUNT, &nfit_mem->flags); | ||
15 | nfit_mem->dirty_shutdown = 42; | ||
16 | } | ||
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index cffc2c5a778d..9527d47a1070 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/list.h> | 24 | #include <linux/list.h> |
25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
26 | #include <nd-core.h> | 26 | #include <nd-core.h> |
27 | #include <intel.h> | ||
27 | #include <nfit.h> | 28 | #include <nfit.h> |
28 | #include <nd.h> | 29 | #include <nd.h> |
29 | #include "nfit_test.h" | 30 | #include "nfit_test.h" |
@@ -148,6 +149,7 @@ static const struct nd_intel_smart smart_def = { | |||
148 | | ND_INTEL_SMART_ALARM_VALID | 149 | | ND_INTEL_SMART_ALARM_VALID |
149 | | ND_INTEL_SMART_USED_VALID | 150 | | ND_INTEL_SMART_USED_VALID |
150 | | ND_INTEL_SMART_SHUTDOWN_VALID | 151 | | ND_INTEL_SMART_SHUTDOWN_VALID |
152 | | ND_INTEL_SMART_SHUTDOWN_COUNT_VALID | ||
151 | | ND_INTEL_SMART_MTEMP_VALID | 153 | | ND_INTEL_SMART_MTEMP_VALID |
152 | | ND_INTEL_SMART_CTEMP_VALID, | 154 | | ND_INTEL_SMART_CTEMP_VALID, |
153 | .health = ND_INTEL_SMART_NON_CRITICAL_HEALTH, | 155 | .health = ND_INTEL_SMART_NON_CRITICAL_HEALTH, |
@@ -160,8 +162,8 @@ static const struct nd_intel_smart smart_def = { | |||
160 | .ait_status = 1, | 162 | .ait_status = 1, |
161 | .life_used = 5, | 163 | .life_used = 5, |
162 | .shutdown_state = 0, | 164 | .shutdown_state = 0, |
165 | .shutdown_count = 42, | ||
163 | .vendor_size = 0, | 166 | .vendor_size = 0, |
164 | .shutdown_count = 100, | ||
165 | }; | 167 | }; |
166 | 168 | ||
167 | struct nfit_test_fw { | 169 | struct nfit_test_fw { |
diff --git a/tools/testing/nvdimm/test/nfit_test.h b/tools/testing/nvdimm/test/nfit_test.h index 33752e06ff8d..ade14fe3837e 100644 --- a/tools/testing/nvdimm/test/nfit_test.h +++ b/tools/testing/nvdimm/test/nfit_test.h | |||
@@ -117,30 +117,6 @@ struct nd_cmd_ars_err_inj_stat { | |||
117 | #define ND_INTEL_SMART_INJECT_FATAL (1 << 2) | 117 | #define ND_INTEL_SMART_INJECT_FATAL (1 << 2) |
118 | #define ND_INTEL_SMART_INJECT_SHUTDOWN (1 << 3) | 118 | #define ND_INTEL_SMART_INJECT_SHUTDOWN (1 << 3) |
119 | 119 | ||
120 | struct nd_intel_smart { | ||
121 | __u32 status; | ||
122 | union { | ||
123 | struct { | ||
124 | __u32 flags; | ||
125 | __u8 reserved0[4]; | ||
126 | __u8 health; | ||
127 | __u8 spares; | ||
128 | __u8 life_used; | ||
129 | __u8 alarm_flags; | ||
130 | __u16 media_temperature; | ||
131 | __u16 ctrl_temperature; | ||
132 | __u32 shutdown_count; | ||
133 | __u8 ait_status; | ||
134 | __u16 pmic_temperature; | ||
135 | __u8 reserved1[8]; | ||
136 | __u8 shutdown_state; | ||
137 | __u32 vendor_size; | ||
138 | __u8 vendor_data[92]; | ||
139 | } __packed; | ||
140 | __u8 data[128]; | ||
141 | }; | ||
142 | } __packed; | ||
143 | |||
144 | struct nd_intel_smart_threshold { | 120 | struct nd_intel_smart_threshold { |
145 | __u32 status; | 121 | __u32 status; |
146 | union { | 122 | union { |
diff --git a/tools/testing/selftests/bpf/.gitignore b/tools/testing/selftests/bpf/.gitignore index 49938d72cf63..1b799e30c06d 100644 --- a/tools/testing/selftests/bpf/.gitignore +++ b/tools/testing/selftests/bpf/.gitignore | |||
@@ -19,3 +19,11 @@ test_btf | |||
19 | test_sockmap | 19 | test_sockmap |
20 | test_lirc_mode2_user | 20 | test_lirc_mode2_user |
21 | get_cgroup_id_user | 21 | get_cgroup_id_user |
22 | test_skb_cgroup_id_user | ||
23 | test_socket_cookie | ||
24 | test_cgroup_storage | ||
25 | test_select_reuseport | ||
26 | test_flow_dissector | ||
27 | flow_dissector_load | ||
28 | test_netcnt | ||
29 | test_section_names | ||
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index fff7fb1285fc..e39dfb4e7970 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile | |||
@@ -23,7 +23,8 @@ $(TEST_CUSTOM_PROGS): $(OUTPUT)/%: %.c | |||
23 | TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \ | 23 | TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \ |
24 | test_align test_verifier_log test_dev_cgroup test_tcpbpf_user \ | 24 | test_align test_verifier_log test_dev_cgroup test_tcpbpf_user \ |
25 | test_sock test_btf test_sockmap test_lirc_mode2_user get_cgroup_id_user \ | 25 | test_sock test_btf test_sockmap test_lirc_mode2_user get_cgroup_id_user \ |
26 | test_socket_cookie test_cgroup_storage test_select_reuseport | 26 | test_socket_cookie test_cgroup_storage test_select_reuseport test_section_names \ |
27 | test_netcnt | ||
27 | 28 | ||
28 | TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o \ | 29 | TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o \ |
29 | test_pkt_md_access.o test_xdp_redirect.o test_xdp_meta.o sockmap_parse_prog.o \ | 30 | test_pkt_md_access.o test_xdp_redirect.o test_xdp_meta.o sockmap_parse_prog.o \ |
@@ -35,7 +36,8 @@ TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test | |||
35 | test_get_stack_rawtp.o test_sockmap_kern.o test_sockhash_kern.o \ | 36 | test_get_stack_rawtp.o test_sockmap_kern.o test_sockhash_kern.o \ |
36 | test_lwt_seg6local.o sendmsg4_prog.o sendmsg6_prog.o test_lirc_mode2_kern.o \ | 37 | test_lwt_seg6local.o sendmsg4_prog.o sendmsg6_prog.o test_lirc_mode2_kern.o \ |
37 | get_cgroup_id_kern.o socket_cookie_prog.o test_select_reuseport_kern.o \ | 38 | get_cgroup_id_kern.o socket_cookie_prog.o test_select_reuseport_kern.o \ |
38 | test_skb_cgroup_id_kern.o | 39 | test_skb_cgroup_id_kern.o bpf_flow.o netcnt_prog.o \ |
40 | test_sk_lookup_kern.o test_xdp_vlan.o test_queue_map.o test_stack_map.o | ||
39 | 41 | ||
40 | # Order correspond to 'make run_tests' order | 42 | # Order correspond to 'make run_tests' order |
41 | TEST_PROGS := test_kmod.sh \ | 43 | TEST_PROGS := test_kmod.sh \ |
@@ -47,10 +49,15 @@ TEST_PROGS := test_kmod.sh \ | |||
47 | test_tunnel.sh \ | 49 | test_tunnel.sh \ |
48 | test_lwt_seg6local.sh \ | 50 | test_lwt_seg6local.sh \ |
49 | test_lirc_mode2.sh \ | 51 | test_lirc_mode2.sh \ |
50 | test_skb_cgroup_id.sh | 52 | test_skb_cgroup_id.sh \ |
53 | test_flow_dissector.sh \ | ||
54 | test_xdp_vlan.sh | ||
55 | |||
56 | TEST_PROGS_EXTENDED := with_addr.sh | ||
51 | 57 | ||
52 | # Compile but not part of 'make run_tests' | 58 | # Compile but not part of 'make run_tests' |
53 | TEST_GEN_PROGS_EXTENDED = test_libbpf_open test_sock_addr test_skb_cgroup_id_user | 59 | TEST_GEN_PROGS_EXTENDED = test_libbpf_open test_sock_addr test_skb_cgroup_id_user \ |
60 | flow_dissector_load test_flow_dissector | ||
54 | 61 | ||
55 | include ../lib.mk | 62 | include ../lib.mk |
56 | 63 | ||
@@ -70,6 +77,7 @@ $(OUTPUT)/test_tcpbpf_user: cgroup_helpers.c | |||
70 | $(OUTPUT)/test_progs: trace_helpers.c | 77 | $(OUTPUT)/test_progs: trace_helpers.c |
71 | $(OUTPUT)/get_cgroup_id_user: cgroup_helpers.c | 78 | $(OUTPUT)/get_cgroup_id_user: cgroup_helpers.c |
72 | $(OUTPUT)/test_cgroup_storage: cgroup_helpers.c | 79 | $(OUTPUT)/test_cgroup_storage: cgroup_helpers.c |
80 | $(OUTPUT)/test_netcnt: cgroup_helpers.c | ||
73 | 81 | ||
74 | .PHONY: force | 82 | .PHONY: force |
75 | 83 | ||
@@ -110,6 +118,9 @@ CLANG_FLAGS = -I. -I./include/uapi -I../../../include/uapi \ | |||
110 | $(OUTPUT)/test_l4lb_noinline.o: CLANG_FLAGS += -fno-inline | 118 | $(OUTPUT)/test_l4lb_noinline.o: CLANG_FLAGS += -fno-inline |
111 | $(OUTPUT)/test_xdp_noinline.o: CLANG_FLAGS += -fno-inline | 119 | $(OUTPUT)/test_xdp_noinline.o: CLANG_FLAGS += -fno-inline |
112 | 120 | ||
121 | $(OUTPUT)/test_queue_map.o: test_queue_stack_map.h | ||
122 | $(OUTPUT)/test_stack_map.o: test_queue_stack_map.h | ||
123 | |||
113 | BTF_LLC_PROBE := $(shell $(LLC) -march=bpf -mattr=help 2>&1 | grep dwarfris) | 124 | BTF_LLC_PROBE := $(shell $(LLC) -march=bpf -mattr=help 2>&1 | grep dwarfris) |
114 | BTF_PAHOLE_PROBE := $(shell $(BTF_PAHOLE) --help 2>&1 | grep BTF) | 125 | BTF_PAHOLE_PROBE := $(shell $(BTF_PAHOLE) --help 2>&1 | grep BTF) |
115 | BTF_OBJCOPY_PROBE := $(shell $(LLVM_OBJCOPY) --help 2>&1 | grep -i 'usage.*llvm') | 126 | BTF_OBJCOPY_PROBE := $(shell $(LLVM_OBJCOPY) --help 2>&1 | grep -i 'usage.*llvm') |
diff --git a/tools/testing/selftests/bpf/bpf_flow.c b/tools/testing/selftests/bpf/bpf_flow.c new file mode 100644 index 000000000000..107350a7821d --- /dev/null +++ b/tools/testing/selftests/bpf/bpf_flow.c | |||
@@ -0,0 +1,373 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | #include <limits.h> | ||
3 | #include <stddef.h> | ||
4 | #include <stdbool.h> | ||
5 | #include <string.h> | ||
6 | #include <linux/pkt_cls.h> | ||
7 | #include <linux/bpf.h> | ||
8 | #include <linux/in.h> | ||
9 | #include <linux/if_ether.h> | ||
10 | #include <linux/icmp.h> | ||
11 | #include <linux/ip.h> | ||
12 | #include <linux/ipv6.h> | ||
13 | #include <linux/tcp.h> | ||
14 | #include <linux/udp.h> | ||
15 | #include <linux/if_packet.h> | ||
16 | #include <sys/socket.h> | ||
17 | #include <linux/if_tunnel.h> | ||
18 | #include <linux/mpls.h> | ||
19 | #include "bpf_helpers.h" | ||
20 | #include "bpf_endian.h" | ||
21 | |||
22 | int _version SEC("version") = 1; | ||
23 | #define PROG(F) SEC(#F) int bpf_func_##F | ||
24 | |||
25 | /* These are the identifiers of the BPF programs that will be used in tail | ||
26 | * calls. Name is limited to 16 characters, with the terminating character and | ||
27 | * bpf_func_ above, we have only 6 to work with, anything after will be cropped. | ||
28 | */ | ||
29 | enum { | ||
30 | IP, | ||
31 | IPV6, | ||
32 | IPV6OP, /* Destination/Hop-by-Hop Options IPv6 Extension header */ | ||
33 | IPV6FR, /* Fragmentation IPv6 Extension Header */ | ||
34 | MPLS, | ||
35 | VLAN, | ||
36 | }; | ||
37 | |||
38 | #define IP_MF 0x2000 | ||
39 | #define IP_OFFSET 0x1FFF | ||
40 | #define IP6_MF 0x0001 | ||
41 | #define IP6_OFFSET 0xFFF8 | ||
42 | |||
43 | struct vlan_hdr { | ||
44 | __be16 h_vlan_TCI; | ||
45 | __be16 h_vlan_encapsulated_proto; | ||
46 | }; | ||
47 | |||
48 | struct gre_hdr { | ||
49 | __be16 flags; | ||
50 | __be16 proto; | ||
51 | }; | ||
52 | |||
53 | struct frag_hdr { | ||
54 | __u8 nexthdr; | ||
55 | __u8 reserved; | ||
56 | __be16 frag_off; | ||
57 | __be32 identification; | ||
58 | }; | ||
59 | |||
60 | struct bpf_map_def SEC("maps") jmp_table = { | ||
61 | .type = BPF_MAP_TYPE_PROG_ARRAY, | ||
62 | .key_size = sizeof(__u32), | ||
63 | .value_size = sizeof(__u32), | ||
64 | .max_entries = 8 | ||
65 | }; | ||
66 | |||
67 | static __always_inline void *bpf_flow_dissect_get_header(struct __sk_buff *skb, | ||
68 | __u16 hdr_size, | ||
69 | void *buffer) | ||
70 | { | ||
71 | void *data_end = (void *)(long)skb->data_end; | ||
72 | void *data = (void *)(long)skb->data; | ||
73 | __u16 nhoff = skb->flow_keys->nhoff; | ||
74 | __u8 *hdr; | ||
75 | |||
76 | /* Verifies this variable offset does not overflow */ | ||
77 | if (nhoff > (USHRT_MAX - hdr_size)) | ||
78 | return NULL; | ||
79 | |||
80 | hdr = data + nhoff; | ||
81 | if (hdr + hdr_size <= data_end) | ||
82 | return hdr; | ||
83 | |||
84 | if (bpf_skb_load_bytes(skb, nhoff, buffer, hdr_size)) | ||
85 | return NULL; | ||
86 | |||
87 | return buffer; | ||
88 | } | ||
89 | |||
90 | /* Dispatches on ETHERTYPE */ | ||
91 | static __always_inline int parse_eth_proto(struct __sk_buff *skb, __be16 proto) | ||
92 | { | ||
93 | struct bpf_flow_keys *keys = skb->flow_keys; | ||
94 | |||
95 | keys->n_proto = proto; | ||
96 | switch (proto) { | ||
97 | case bpf_htons(ETH_P_IP): | ||
98 | bpf_tail_call(skb, &jmp_table, IP); | ||
99 | break; | ||
100 | case bpf_htons(ETH_P_IPV6): | ||
101 | bpf_tail_call(skb, &jmp_table, IPV6); | ||
102 | break; | ||
103 | case bpf_htons(ETH_P_MPLS_MC): | ||
104 | case bpf_htons(ETH_P_MPLS_UC): | ||
105 | bpf_tail_call(skb, &jmp_table, MPLS); | ||
106 | break; | ||
107 | case bpf_htons(ETH_P_8021Q): | ||
108 | case bpf_htons(ETH_P_8021AD): | ||
109 | bpf_tail_call(skb, &jmp_table, VLAN); | ||
110 | break; | ||
111 | default: | ||
112 | /* Protocol not supported */ | ||
113 | return BPF_DROP; | ||
114 | } | ||
115 | |||
116 | return BPF_DROP; | ||
117 | } | ||
118 | |||
119 | SEC("dissect") | ||
120 | int _dissect(struct __sk_buff *skb) | ||
121 | { | ||
122 | if (!skb->vlan_present) | ||
123 | return parse_eth_proto(skb, skb->protocol); | ||
124 | else | ||
125 | return parse_eth_proto(skb, skb->vlan_proto); | ||
126 | } | ||
127 | |||
128 | /* Parses on IPPROTO_* */ | ||
129 | static __always_inline int parse_ip_proto(struct __sk_buff *skb, __u8 proto) | ||
130 | { | ||
131 | struct bpf_flow_keys *keys = skb->flow_keys; | ||
132 | void *data_end = (void *)(long)skb->data_end; | ||
133 | struct icmphdr *icmp, _icmp; | ||
134 | struct gre_hdr *gre, _gre; | ||
135 | struct ethhdr *eth, _eth; | ||
136 | struct tcphdr *tcp, _tcp; | ||
137 | struct udphdr *udp, _udp; | ||
138 | |||
139 | keys->ip_proto = proto; | ||
140 | switch (proto) { | ||
141 | case IPPROTO_ICMP: | ||
142 | icmp = bpf_flow_dissect_get_header(skb, sizeof(*icmp), &_icmp); | ||
143 | if (!icmp) | ||
144 | return BPF_DROP; | ||
145 | return BPF_OK; | ||
146 | case IPPROTO_IPIP: | ||
147 | keys->is_encap = true; | ||
148 | return parse_eth_proto(skb, bpf_htons(ETH_P_IP)); | ||
149 | case IPPROTO_IPV6: | ||
150 | keys->is_encap = true; | ||
151 | return parse_eth_proto(skb, bpf_htons(ETH_P_IPV6)); | ||
152 | case IPPROTO_GRE: | ||
153 | gre = bpf_flow_dissect_get_header(skb, sizeof(*gre), &_gre); | ||
154 | if (!gre) | ||
155 | return BPF_DROP; | ||
156 | |||
157 | if (bpf_htons(gre->flags & GRE_VERSION)) | ||
158 | /* Only inspect standard GRE packets with version 0 */ | ||
159 | return BPF_OK; | ||
160 | |||
161 | keys->nhoff += sizeof(*gre); /* Step over GRE Flags and Proto */ | ||
162 | if (GRE_IS_CSUM(gre->flags)) | ||
163 | keys->nhoff += 4; /* Step over chksum and Padding */ | ||
164 | if (GRE_IS_KEY(gre->flags)) | ||
165 | keys->nhoff += 4; /* Step over key */ | ||
166 | if (GRE_IS_SEQ(gre->flags)) | ||
167 | keys->nhoff += 4; /* Step over sequence number */ | ||
168 | |||
169 | keys->is_encap = true; | ||
170 | |||
171 | if (gre->proto == bpf_htons(ETH_P_TEB)) { | ||
172 | eth = bpf_flow_dissect_get_header(skb, sizeof(*eth), | ||
173 | &_eth); | ||
174 | if (!eth) | ||
175 | return BPF_DROP; | ||
176 | |||
177 | keys->nhoff += sizeof(*eth); | ||
178 | |||
179 | return parse_eth_proto(skb, eth->h_proto); | ||
180 | } else { | ||
181 | return parse_eth_proto(skb, gre->proto); | ||
182 | } | ||
183 | case IPPROTO_TCP: | ||
184 | tcp = bpf_flow_dissect_get_header(skb, sizeof(*tcp), &_tcp); | ||
185 | if (!tcp) | ||
186 | return BPF_DROP; | ||
187 | |||
188 | if (tcp->doff < 5) | ||
189 | return BPF_DROP; | ||
190 | |||
191 | if ((__u8 *)tcp + (tcp->doff << 2) > data_end) | ||
192 | return BPF_DROP; | ||
193 | |||
194 | keys->thoff = keys->nhoff; | ||
195 | keys->sport = tcp->source; | ||
196 | keys->dport = tcp->dest; | ||
197 | return BPF_OK; | ||
198 | case IPPROTO_UDP: | ||
199 | case IPPROTO_UDPLITE: | ||
200 | udp = bpf_flow_dissect_get_header(skb, sizeof(*udp), &_udp); | ||
201 | if (!udp) | ||
202 | return BPF_DROP; | ||
203 | |||
204 | keys->thoff = keys->nhoff; | ||
205 | keys->sport = udp->source; | ||
206 | keys->dport = udp->dest; | ||
207 | return BPF_OK; | ||
208 | default: | ||
209 | return BPF_DROP; | ||
210 | } | ||
211 | |||
212 | return BPF_DROP; | ||
213 | } | ||
214 | |||
215 | static __always_inline int parse_ipv6_proto(struct __sk_buff *skb, __u8 nexthdr) | ||
216 | { | ||
217 | struct bpf_flow_keys *keys = skb->flow_keys; | ||
218 | |||
219 | keys->ip_proto = nexthdr; | ||
220 | switch (nexthdr) { | ||
221 | case IPPROTO_HOPOPTS: | ||
222 | case IPPROTO_DSTOPTS: | ||
223 | bpf_tail_call(skb, &jmp_table, IPV6OP); | ||
224 | break; | ||
225 | case IPPROTO_FRAGMENT: | ||
226 | bpf_tail_call(skb, &jmp_table, IPV6FR); | ||
227 | break; | ||
228 | default: | ||
229 | return parse_ip_proto(skb, nexthdr); | ||
230 | } | ||
231 | |||
232 | return BPF_DROP; | ||
233 | } | ||
234 | |||
235 | PROG(IP)(struct __sk_buff *skb) | ||
236 | { | ||
237 | void *data_end = (void *)(long)skb->data_end; | ||
238 | struct bpf_flow_keys *keys = skb->flow_keys; | ||
239 | void *data = (void *)(long)skb->data; | ||
240 | struct iphdr *iph, _iph; | ||
241 | bool done = false; | ||
242 | |||
243 | iph = bpf_flow_dissect_get_header(skb, sizeof(*iph), &_iph); | ||
244 | if (!iph) | ||
245 | return BPF_DROP; | ||
246 | |||
247 | /* IP header cannot be smaller than 20 bytes */ | ||
248 | if (iph->ihl < 5) | ||
249 | return BPF_DROP; | ||
250 | |||
251 | keys->addr_proto = ETH_P_IP; | ||
252 | keys->ipv4_src = iph->saddr; | ||
253 | keys->ipv4_dst = iph->daddr; | ||
254 | |||
255 | keys->nhoff += iph->ihl << 2; | ||
256 | if (data + keys->nhoff > data_end) | ||
257 | return BPF_DROP; | ||
258 | |||
259 | if (iph->frag_off & bpf_htons(IP_MF | IP_OFFSET)) { | ||
260 | keys->is_frag = true; | ||
261 | if (iph->frag_off & bpf_htons(IP_OFFSET)) | ||
262 | /* From second fragment on, packets do not have headers | ||
263 | * we can parse. | ||
264 | */ | ||
265 | done = true; | ||
266 | else | ||
267 | keys->is_first_frag = true; | ||
268 | } | ||
269 | |||
270 | if (done) | ||
271 | return BPF_OK; | ||
272 | |||
273 | return parse_ip_proto(skb, iph->protocol); | ||
274 | } | ||
275 | |||
276 | PROG(IPV6)(struct __sk_buff *skb) | ||
277 | { | ||
278 | struct bpf_flow_keys *keys = skb->flow_keys; | ||
279 | struct ipv6hdr *ip6h, _ip6h; | ||
280 | |||
281 | ip6h = bpf_flow_dissect_get_header(skb, sizeof(*ip6h), &_ip6h); | ||
282 | if (!ip6h) | ||
283 | return BPF_DROP; | ||
284 | |||
285 | keys->addr_proto = ETH_P_IPV6; | ||
286 | memcpy(&keys->ipv6_src, &ip6h->saddr, 2*sizeof(ip6h->saddr)); | ||
287 | |||
288 | keys->nhoff += sizeof(struct ipv6hdr); | ||
289 | |||
290 | return parse_ipv6_proto(skb, ip6h->nexthdr); | ||
291 | } | ||
292 | |||
293 | PROG(IPV6OP)(struct __sk_buff *skb) | ||
294 | { | ||
295 | struct ipv6_opt_hdr *ip6h, _ip6h; | ||
296 | |||
297 | ip6h = bpf_flow_dissect_get_header(skb, sizeof(*ip6h), &_ip6h); | ||
298 | if (!ip6h) | ||
299 | return BPF_DROP; | ||
300 | |||
301 | /* hlen is in 8-octets and does not include the first 8 bytes | ||
302 | * of the header | ||
303 | */ | ||
304 | skb->flow_keys->nhoff += (1 + ip6h->hdrlen) << 3; | ||
305 | |||
306 | return parse_ipv6_proto(skb, ip6h->nexthdr); | ||
307 | } | ||
308 | |||
309 | PROG(IPV6FR)(struct __sk_buff *skb) | ||
310 | { | ||
311 | struct bpf_flow_keys *keys = skb->flow_keys; | ||
312 | struct frag_hdr *fragh, _fragh; | ||
313 | |||
314 | fragh = bpf_flow_dissect_get_header(skb, sizeof(*fragh), &_fragh); | ||
315 | if (!fragh) | ||
316 | return BPF_DROP; | ||
317 | |||
318 | keys->nhoff += sizeof(*fragh); | ||
319 | keys->is_frag = true; | ||
320 | if (!(fragh->frag_off & bpf_htons(IP6_OFFSET))) | ||
321 | keys->is_first_frag = true; | ||
322 | |||
323 | return parse_ipv6_proto(skb, fragh->nexthdr); | ||
324 | } | ||
325 | |||
326 | PROG(MPLS)(struct __sk_buff *skb) | ||
327 | { | ||
328 | struct mpls_label *mpls, _mpls; | ||
329 | |||
330 | mpls = bpf_flow_dissect_get_header(skb, sizeof(*mpls), &_mpls); | ||
331 | if (!mpls) | ||
332 | return BPF_DROP; | ||
333 | |||
334 | return BPF_OK; | ||
335 | } | ||
336 | |||
337 | PROG(VLAN)(struct __sk_buff *skb) | ||
338 | { | ||
339 | struct bpf_flow_keys *keys = skb->flow_keys; | ||
340 | struct vlan_hdr *vlan, _vlan; | ||
341 | __be16 proto; | ||
342 | |||
343 | /* Peek back to see if single or double-tagging */ | ||
344 | if (bpf_skb_load_bytes(skb, keys->nhoff - sizeof(proto), &proto, | ||
345 | sizeof(proto))) | ||
346 | return BPF_DROP; | ||
347 | |||
348 | /* Account for double-tagging */ | ||
349 | if (proto == bpf_htons(ETH_P_8021AD)) { | ||
350 | vlan = bpf_flow_dissect_get_header(skb, sizeof(*vlan), &_vlan); | ||
351 | if (!vlan) | ||
352 | return BPF_DROP; | ||
353 | |||
354 | if (vlan->h_vlan_encapsulated_proto != bpf_htons(ETH_P_8021Q)) | ||
355 | return BPF_DROP; | ||
356 | |||
357 | keys->nhoff += sizeof(*vlan); | ||
358 | } | ||
359 | |||
360 | vlan = bpf_flow_dissect_get_header(skb, sizeof(*vlan), &_vlan); | ||
361 | if (!vlan) | ||
362 | return BPF_DROP; | ||
363 | |||
364 | keys->nhoff += sizeof(*vlan); | ||
365 | /* Only allow 8021AD + 8021Q double tagging and no triple tagging.*/ | ||
366 | if (vlan->h_vlan_encapsulated_proto == bpf_htons(ETH_P_8021AD) || | ||
367 | vlan->h_vlan_encapsulated_proto == bpf_htons(ETH_P_8021Q)) | ||
368 | return BPF_DROP; | ||
369 | |||
370 | return parse_eth_proto(skb, vlan->h_vlan_encapsulated_proto); | ||
371 | } | ||
372 | |||
373 | char __license[] SEC("license") = "GPL"; | ||
diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h index e4be7730222d..686e57ce40f4 100644 --- a/tools/testing/selftests/bpf/bpf_helpers.h +++ b/tools/testing/selftests/bpf/bpf_helpers.h | |||
@@ -16,6 +16,13 @@ static int (*bpf_map_update_elem)(void *map, void *key, void *value, | |||
16 | (void *) BPF_FUNC_map_update_elem; | 16 | (void *) BPF_FUNC_map_update_elem; |
17 | static int (*bpf_map_delete_elem)(void *map, void *key) = | 17 | static int (*bpf_map_delete_elem)(void *map, void *key) = |
18 | (void *) BPF_FUNC_map_delete_elem; | 18 | (void *) BPF_FUNC_map_delete_elem; |
19 | static int (*bpf_map_push_elem)(void *map, void *value, | ||
20 | unsigned long long flags) = | ||
21 | (void *) BPF_FUNC_map_push_elem; | ||
22 | static int (*bpf_map_pop_elem)(void *map, void *value) = | ||
23 | (void *) BPF_FUNC_map_pop_elem; | ||
24 | static int (*bpf_map_peek_elem)(void *map, void *value) = | ||
25 | (void *) BPF_FUNC_map_peek_elem; | ||
19 | static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) = | 26 | static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) = |
20 | (void *) BPF_FUNC_probe_read; | 27 | (void *) BPF_FUNC_probe_read; |
21 | static unsigned long long (*bpf_ktime_get_ns)(void) = | 28 | static unsigned long long (*bpf_ktime_get_ns)(void) = |
@@ -104,6 +111,8 @@ static int (*bpf_msg_cork_bytes)(void *ctx, int len) = | |||
104 | (void *) BPF_FUNC_msg_cork_bytes; | 111 | (void *) BPF_FUNC_msg_cork_bytes; |
105 | static int (*bpf_msg_pull_data)(void *ctx, int start, int end, int flags) = | 112 | static int (*bpf_msg_pull_data)(void *ctx, int start, int end, int flags) = |
106 | (void *) BPF_FUNC_msg_pull_data; | 113 | (void *) BPF_FUNC_msg_pull_data; |
114 | static int (*bpf_msg_push_data)(void *ctx, int start, int end, int flags) = | ||
115 | (void *) BPF_FUNC_msg_push_data; | ||
107 | static int (*bpf_bind)(void *ctx, void *addr, int addr_len) = | 116 | static int (*bpf_bind)(void *ctx, void *addr, int addr_len) = |
108 | (void *) BPF_FUNC_bind; | 117 | (void *) BPF_FUNC_bind; |
109 | static int (*bpf_xdp_adjust_tail)(void *ctx, int offset) = | 118 | static int (*bpf_xdp_adjust_tail)(void *ctx, int offset) = |
@@ -143,6 +152,22 @@ static unsigned long long (*bpf_skb_cgroup_id)(void *ctx) = | |||
143 | (void *) BPF_FUNC_skb_cgroup_id; | 152 | (void *) BPF_FUNC_skb_cgroup_id; |
144 | static unsigned long long (*bpf_skb_ancestor_cgroup_id)(void *ctx, int level) = | 153 | static unsigned long long (*bpf_skb_ancestor_cgroup_id)(void *ctx, int level) = |
145 | (void *) BPF_FUNC_skb_ancestor_cgroup_id; | 154 | (void *) BPF_FUNC_skb_ancestor_cgroup_id; |
155 | static struct bpf_sock *(*bpf_sk_lookup_tcp)(void *ctx, | ||
156 | struct bpf_sock_tuple *tuple, | ||
157 | int size, unsigned int netns_id, | ||
158 | unsigned long long flags) = | ||
159 | (void *) BPF_FUNC_sk_lookup_tcp; | ||
160 | static struct bpf_sock *(*bpf_sk_lookup_udp)(void *ctx, | ||
161 | struct bpf_sock_tuple *tuple, | ||
162 | int size, unsigned int netns_id, | ||
163 | unsigned long long flags) = | ||
164 | (void *) BPF_FUNC_sk_lookup_udp; | ||
165 | static int (*bpf_sk_release)(struct bpf_sock *sk) = | ||
166 | (void *) BPF_FUNC_sk_release; | ||
167 | static int (*bpf_skb_vlan_push)(void *ctx, __be16 vlan_proto, __u16 vlan_tci) = | ||
168 | (void *) BPF_FUNC_skb_vlan_push; | ||
169 | static int (*bpf_skb_vlan_pop)(void *ctx) = | ||
170 | (void *) BPF_FUNC_skb_vlan_pop; | ||
146 | 171 | ||
147 | /* llvm builtin functions that eBPF C program may use to | 172 | /* llvm builtin functions that eBPF C program may use to |
148 | * emit BPF_LD_ABS and BPF_LD_IND instructions | 173 | * emit BPF_LD_ABS and BPF_LD_IND instructions |
diff --git a/tools/testing/selftests/bpf/config b/tools/testing/selftests/bpf/config index b4994a94968b..dd49df5e2df4 100644 --- a/tools/testing/selftests/bpf/config +++ b/tools/testing/selftests/bpf/config | |||
@@ -18,3 +18,5 @@ CONFIG_CRYPTO_HMAC=m | |||
18 | CONFIG_CRYPTO_SHA256=m | 18 | CONFIG_CRYPTO_SHA256=m |
19 | CONFIG_VXLAN=y | 19 | CONFIG_VXLAN=y |
20 | CONFIG_GENEVE=y | 20 | CONFIG_GENEVE=y |
21 | CONFIG_NET_CLS_FLOWER=m | ||
22 | CONFIG_LWTUNNEL=y | ||
diff --git a/tools/testing/selftests/bpf/flow_dissector_load.c b/tools/testing/selftests/bpf/flow_dissector_load.c new file mode 100644 index 000000000000..d3273b5b3173 --- /dev/null +++ b/tools/testing/selftests/bpf/flow_dissector_load.c | |||
@@ -0,0 +1,140 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | #include <error.h> | ||
3 | #include <errno.h> | ||
4 | #include <getopt.h> | ||
5 | #include <stdio.h> | ||
6 | #include <stdlib.h> | ||
7 | #include <string.h> | ||
8 | #include <sys/stat.h> | ||
9 | #include <fcntl.h> | ||
10 | #include <unistd.h> | ||
11 | #include <bpf/bpf.h> | ||
12 | #include <bpf/libbpf.h> | ||
13 | |||
14 | const char *cfg_pin_path = "/sys/fs/bpf/flow_dissector"; | ||
15 | const char *cfg_map_name = "jmp_table"; | ||
16 | bool cfg_attach = true; | ||
17 | char *cfg_section_name; | ||
18 | char *cfg_path_name; | ||
19 | |||
20 | static void load_and_attach_program(void) | ||
21 | { | ||
22 | struct bpf_program *prog, *main_prog; | ||
23 | struct bpf_map *prog_array; | ||
24 | int i, fd, prog_fd, ret; | ||
25 | struct bpf_object *obj; | ||
26 | int prog_array_fd; | ||
27 | |||
28 | ret = bpf_prog_load(cfg_path_name, BPF_PROG_TYPE_FLOW_DISSECTOR, &obj, | ||
29 | &prog_fd); | ||
30 | if (ret) | ||
31 | error(1, 0, "bpf_prog_load %s", cfg_path_name); | ||
32 | |||
33 | main_prog = bpf_object__find_program_by_title(obj, cfg_section_name); | ||
34 | if (!main_prog) | ||
35 | error(1, 0, "bpf_object__find_program_by_title %s", | ||
36 | cfg_section_name); | ||
37 | |||
38 | prog_fd = bpf_program__fd(main_prog); | ||
39 | if (prog_fd < 0) | ||
40 | error(1, 0, "bpf_program__fd"); | ||
41 | |||
42 | prog_array = bpf_object__find_map_by_name(obj, cfg_map_name); | ||
43 | if (!prog_array) | ||
44 | error(1, 0, "bpf_object__find_map_by_name %s", cfg_map_name); | ||
45 | |||
46 | prog_array_fd = bpf_map__fd(prog_array); | ||
47 | if (prog_array_fd < 0) | ||
48 | error(1, 0, "bpf_map__fd %s", cfg_map_name); | ||
49 | |||
50 | i = 0; | ||
51 | bpf_object__for_each_program(prog, obj) { | ||
52 | fd = bpf_program__fd(prog); | ||
53 | if (fd < 0) | ||
54 | error(1, 0, "bpf_program__fd"); | ||
55 | |||
56 | if (fd != prog_fd) { | ||
57 | printf("%d: %s\n", i, bpf_program__title(prog, false)); | ||
58 | bpf_map_update_elem(prog_array_fd, &i, &fd, BPF_ANY); | ||
59 | ++i; | ||
60 | } | ||
61 | } | ||
62 | |||
63 | ret = bpf_prog_attach(prog_fd, 0 /* Ignore */, BPF_FLOW_DISSECTOR, 0); | ||
64 | if (ret) | ||
65 | error(1, 0, "bpf_prog_attach %s", cfg_path_name); | ||
66 | |||
67 | ret = bpf_object__pin(obj, cfg_pin_path); | ||
68 | if (ret) | ||
69 | error(1, 0, "bpf_object__pin %s", cfg_pin_path); | ||
70 | |||
71 | } | ||
72 | |||
73 | static void detach_program(void) | ||
74 | { | ||
75 | char command[64]; | ||
76 | int ret; | ||
77 | |||
78 | ret = bpf_prog_detach(0, BPF_FLOW_DISSECTOR); | ||
79 | if (ret) | ||
80 | error(1, 0, "bpf_prog_detach"); | ||
81 | |||
82 | /* To unpin, it is necessary and sufficient to just remove this dir */ | ||
83 | sprintf(command, "rm -r %s", cfg_pin_path); | ||
84 | ret = system(command); | ||
85 | if (ret) | ||
86 | error(1, errno, command); | ||
87 | } | ||
88 | |||
89 | static void parse_opts(int argc, char **argv) | ||
90 | { | ||
91 | bool attach = false; | ||
92 | bool detach = false; | ||
93 | int c; | ||
94 | |||
95 | while ((c = getopt(argc, argv, "adp:s:")) != -1) { | ||
96 | switch (c) { | ||
97 | case 'a': | ||
98 | if (detach) | ||
99 | error(1, 0, "attach/detach are exclusive"); | ||
100 | attach = true; | ||
101 | break; | ||
102 | case 'd': | ||
103 | if (attach) | ||
104 | error(1, 0, "attach/detach are exclusive"); | ||
105 | detach = true; | ||
106 | break; | ||
107 | case 'p': | ||
108 | if (cfg_path_name) | ||
109 | error(1, 0, "only one prog name can be given"); | ||
110 | |||
111 | cfg_path_name = optarg; | ||
112 | break; | ||
113 | case 's': | ||
114 | if (cfg_section_name) | ||
115 | error(1, 0, "only one section can be given"); | ||
116 | |||
117 | cfg_section_name = optarg; | ||
118 | break; | ||
119 | } | ||
120 | } | ||
121 | |||
122 | if (detach) | ||
123 | cfg_attach = false; | ||
124 | |||
125 | if (cfg_attach && !cfg_path_name) | ||
126 | error(1, 0, "must provide a path to the BPF program"); | ||
127 | |||
128 | if (cfg_attach && !cfg_section_name) | ||
129 | error(1, 0, "must provide a section name"); | ||
130 | } | ||
131 | |||
132 | int main(int argc, char **argv) | ||
133 | { | ||
134 | parse_opts(argc, argv); | ||
135 | if (cfg_attach) | ||
136 | load_and_attach_program(); | ||
137 | else | ||
138 | detach_program(); | ||
139 | return 0; | ||
140 | } | ||
diff --git a/tools/testing/selftests/bpf/netcnt_common.h b/tools/testing/selftests/bpf/netcnt_common.h new file mode 100644 index 000000000000..81084c1c2c23 --- /dev/null +++ b/tools/testing/selftests/bpf/netcnt_common.h | |||
@@ -0,0 +1,24 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | #ifndef __NETCNT_COMMON_H | ||
3 | #define __NETCNT_COMMON_H | ||
4 | |||
5 | #include <linux/types.h> | ||
6 | |||
7 | #define MAX_PERCPU_PACKETS 32 | ||
8 | |||
9 | struct percpu_net_cnt { | ||
10 | __u64 packets; | ||
11 | __u64 bytes; | ||
12 | |||
13 | __u64 prev_ts; | ||
14 | |||
15 | __u64 prev_packets; | ||
16 | __u64 prev_bytes; | ||
17 | }; | ||
18 | |||
19 | struct net_cnt { | ||
20 | __u64 packets; | ||
21 | __u64 bytes; | ||
22 | }; | ||
23 | |||
24 | #endif | ||
diff --git a/tools/testing/selftests/bpf/netcnt_prog.c b/tools/testing/selftests/bpf/netcnt_prog.c new file mode 100644 index 000000000000..1198abca1360 --- /dev/null +++ b/tools/testing/selftests/bpf/netcnt_prog.c | |||
@@ -0,0 +1,71 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | #include <linux/bpf.h> | ||
3 | #include <linux/version.h> | ||
4 | |||
5 | #include "bpf_helpers.h" | ||
6 | #include "netcnt_common.h" | ||
7 | |||
8 | #define MAX_BPS (3 * 1024 * 1024) | ||
9 | |||
10 | #define REFRESH_TIME_NS 100000000 | ||
11 | #define NS_PER_SEC 1000000000 | ||
12 | |||
13 | struct bpf_map_def SEC("maps") percpu_netcnt = { | ||
14 | .type = BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE, | ||
15 | .key_size = sizeof(struct bpf_cgroup_storage_key), | ||
16 | .value_size = sizeof(struct percpu_net_cnt), | ||
17 | }; | ||
18 | |||
19 | struct bpf_map_def SEC("maps") netcnt = { | ||
20 | .type = BPF_MAP_TYPE_CGROUP_STORAGE, | ||
21 | .key_size = sizeof(struct bpf_cgroup_storage_key), | ||
22 | .value_size = sizeof(struct net_cnt), | ||
23 | }; | ||
24 | |||
25 | SEC("cgroup/skb") | ||
26 | int bpf_nextcnt(struct __sk_buff *skb) | ||
27 | { | ||
28 | struct percpu_net_cnt *percpu_cnt; | ||
29 | char fmt[] = "%d %llu %llu\n"; | ||
30 | struct net_cnt *cnt; | ||
31 | __u64 ts, dt; | ||
32 | int ret; | ||
33 | |||
34 | cnt = bpf_get_local_storage(&netcnt, 0); | ||
35 | percpu_cnt = bpf_get_local_storage(&percpu_netcnt, 0); | ||
36 | |||
37 | percpu_cnt->packets++; | ||
38 | percpu_cnt->bytes += skb->len; | ||
39 | |||
40 | if (percpu_cnt->packets > MAX_PERCPU_PACKETS) { | ||
41 | __sync_fetch_and_add(&cnt->packets, | ||
42 | percpu_cnt->packets); | ||
43 | percpu_cnt->packets = 0; | ||
44 | |||
45 | __sync_fetch_and_add(&cnt->bytes, | ||
46 | percpu_cnt->bytes); | ||
47 | percpu_cnt->bytes = 0; | ||
48 | } | ||
49 | |||
50 | ts = bpf_ktime_get_ns(); | ||
51 | dt = ts - percpu_cnt->prev_ts; | ||
52 | |||
53 | dt *= MAX_BPS; | ||
54 | dt /= NS_PER_SEC; | ||
55 | |||
56 | if (cnt->bytes + percpu_cnt->bytes - percpu_cnt->prev_bytes < dt) | ||
57 | ret = 1; | ||
58 | else | ||
59 | ret = 0; | ||
60 | |||
61 | if (dt > REFRESH_TIME_NS) { | ||
62 | percpu_cnt->prev_ts = ts; | ||
63 | percpu_cnt->prev_packets = cnt->packets; | ||
64 | percpu_cnt->prev_bytes = cnt->bytes; | ||
65 | } | ||
66 | |||
67 | return !!ret; | ||
68 | } | ||
69 | |||
70 | char _license[] SEC("license") = "GPL"; | ||
71 | __u32 _version SEC("version") = LINUX_VERSION_CODE; | ||
diff --git a/tools/testing/selftests/bpf/test_btf.c b/tools/testing/selftests/bpf/test_btf.c index 6b5cfeb7a9cc..f42b3396d622 100644 --- a/tools/testing/selftests/bpf/test_btf.c +++ b/tools/testing/selftests/bpf/test_btf.c | |||
@@ -4,6 +4,7 @@ | |||
4 | #include <linux/bpf.h> | 4 | #include <linux/bpf.h> |
5 | #include <linux/btf.h> | 5 | #include <linux/btf.h> |
6 | #include <linux/err.h> | 6 | #include <linux/err.h> |
7 | #include <linux/kernel.h> | ||
7 | #include <bpf/bpf.h> | 8 | #include <bpf/bpf.h> |
8 | #include <sys/resource.h> | 9 | #include <sys/resource.h> |
9 | #include <libelf.h> | 10 | #include <libelf.h> |
@@ -45,7 +46,6 @@ static int count_result(int err) | |||
45 | return err; | 46 | return err; |
46 | } | 47 | } |
47 | 48 | ||
48 | #define min(a, b) ((a) < (b) ? (a) : (b)) | ||
49 | #define __printf(a, b) __attribute__((format(printf, a, b))) | 49 | #define __printf(a, b) __attribute__((format(printf, a, b))) |
50 | 50 | ||
51 | __printf(1, 2) | 51 | __printf(1, 2) |
@@ -130,6 +130,7 @@ struct btf_raw_test { | |||
130 | bool map_create_err; | 130 | bool map_create_err; |
131 | bool ordered_map; | 131 | bool ordered_map; |
132 | bool lossless_map; | 132 | bool lossless_map; |
133 | bool percpu_map; | ||
133 | int hdr_len_delta; | 134 | int hdr_len_delta; |
134 | int type_off_delta; | 135 | int type_off_delta; |
135 | int str_off_delta; | 136 | int str_off_delta; |
@@ -2157,6 +2158,7 @@ static struct btf_pprint_test_meta { | |||
2157 | const char *map_name; | 2158 | const char *map_name; |
2158 | bool ordered_map; | 2159 | bool ordered_map; |
2159 | bool lossless_map; | 2160 | bool lossless_map; |
2161 | bool percpu_map; | ||
2160 | } pprint_tests_meta[] = { | 2162 | } pprint_tests_meta[] = { |
2161 | { | 2163 | { |
2162 | .descr = "BTF pretty print array", | 2164 | .descr = "BTF pretty print array", |
@@ -2164,6 +2166,7 @@ static struct btf_pprint_test_meta { | |||
2164 | .map_name = "pprint_test_array", | 2166 | .map_name = "pprint_test_array", |
2165 | .ordered_map = true, | 2167 | .ordered_map = true, |
2166 | .lossless_map = true, | 2168 | .lossless_map = true, |
2169 | .percpu_map = false, | ||
2167 | }, | 2170 | }, |
2168 | 2171 | ||
2169 | { | 2172 | { |
@@ -2172,6 +2175,7 @@ static struct btf_pprint_test_meta { | |||
2172 | .map_name = "pprint_test_hash", | 2175 | .map_name = "pprint_test_hash", |
2173 | .ordered_map = false, | 2176 | .ordered_map = false, |
2174 | .lossless_map = true, | 2177 | .lossless_map = true, |
2178 | .percpu_map = false, | ||
2175 | }, | 2179 | }, |
2176 | 2180 | ||
2177 | { | 2181 | { |
@@ -2180,30 +2184,83 @@ static struct btf_pprint_test_meta { | |||
2180 | .map_name = "pprint_test_lru_hash", | 2184 | .map_name = "pprint_test_lru_hash", |
2181 | .ordered_map = false, | 2185 | .ordered_map = false, |
2182 | .lossless_map = false, | 2186 | .lossless_map = false, |
2187 | .percpu_map = false, | ||
2188 | }, | ||
2189 | |||
2190 | { | ||
2191 | .descr = "BTF pretty print percpu array", | ||
2192 | .map_type = BPF_MAP_TYPE_PERCPU_ARRAY, | ||
2193 | .map_name = "pprint_test_percpu_array", | ||
2194 | .ordered_map = true, | ||
2195 | .lossless_map = true, | ||
2196 | .percpu_map = true, | ||
2197 | }, | ||
2198 | |||
2199 | { | ||
2200 | .descr = "BTF pretty print percpu hash", | ||
2201 | .map_type = BPF_MAP_TYPE_PERCPU_HASH, | ||
2202 | .map_name = "pprint_test_percpu_hash", | ||
2203 | .ordered_map = false, | ||
2204 | .lossless_map = true, | ||
2205 | .percpu_map = true, | ||
2206 | }, | ||
2207 | |||
2208 | { | ||
2209 | .descr = "BTF pretty print lru percpu hash", | ||
2210 | .map_type = BPF_MAP_TYPE_LRU_PERCPU_HASH, | ||
2211 | .map_name = "pprint_test_lru_percpu_hash", | ||
2212 | .ordered_map = false, | ||
2213 | .lossless_map = false, | ||
2214 | .percpu_map = true, | ||
2183 | }, | 2215 | }, |
2184 | 2216 | ||
2185 | }; | 2217 | }; |
2186 | 2218 | ||
2187 | 2219 | ||
2188 | static void set_pprint_mapv(struct pprint_mapv *v, uint32_t i) | 2220 | static void set_pprint_mapv(struct pprint_mapv *v, uint32_t i, |
2221 | int num_cpus, int rounded_value_size) | ||
2189 | { | 2222 | { |
2190 | v->ui32 = i; | 2223 | int cpu; |
2191 | v->si32 = -i; | 2224 | |
2192 | v->unused_bits2a = 3; | 2225 | for (cpu = 0; cpu < num_cpus; cpu++) { |
2193 | v->bits28 = i; | 2226 | v->ui32 = i + cpu; |
2194 | v->unused_bits2b = 3; | 2227 | v->si32 = -i; |
2195 | v->ui64 = i; | 2228 | v->unused_bits2a = 3; |
2196 | v->aenum = i & 0x03; | 2229 | v->bits28 = i; |
2230 | v->unused_bits2b = 3; | ||
2231 | v->ui64 = i; | ||
2232 | v->aenum = i & 0x03; | ||
2233 | v = (void *)v + rounded_value_size; | ||
2234 | } | ||
2197 | } | 2235 | } |
2198 | 2236 | ||
2237 | static int check_line(const char *expected_line, int nexpected_line, | ||
2238 | int expected_line_len, const char *line) | ||
2239 | { | ||
2240 | if (CHECK(nexpected_line == expected_line_len, | ||
2241 | "expected_line is too long")) | ||
2242 | return -1; | ||
2243 | |||
2244 | if (strcmp(expected_line, line)) { | ||
2245 | fprintf(stderr, "unexpected pprint output\n"); | ||
2246 | fprintf(stderr, "expected: %s", expected_line); | ||
2247 | fprintf(stderr, " read: %s", line); | ||
2248 | return -1; | ||
2249 | } | ||
2250 | |||
2251 | return 0; | ||
2252 | } | ||
2253 | |||
2254 | |||
2199 | static int do_test_pprint(void) | 2255 | static int do_test_pprint(void) |
2200 | { | 2256 | { |
2201 | const struct btf_raw_test *test = &pprint_test_template; | 2257 | const struct btf_raw_test *test = &pprint_test_template; |
2202 | struct bpf_create_map_attr create_attr = {}; | 2258 | struct bpf_create_map_attr create_attr = {}; |
2259 | bool ordered_map, lossless_map, percpu_map; | ||
2260 | int err, ret, num_cpus, rounded_value_size; | ||
2261 | struct pprint_mapv *mapv = NULL; | ||
2203 | unsigned int key, nr_read_elems; | 2262 | unsigned int key, nr_read_elems; |
2204 | bool ordered_map, lossless_map; | ||
2205 | int map_fd = -1, btf_fd = -1; | 2263 | int map_fd = -1, btf_fd = -1; |
2206 | struct pprint_mapv mapv = {}; | ||
2207 | unsigned int raw_btf_size; | 2264 | unsigned int raw_btf_size; |
2208 | char expected_line[255]; | 2265 | char expected_line[255]; |
2209 | FILE *pin_file = NULL; | 2266 | FILE *pin_file = NULL; |
@@ -2212,7 +2269,6 @@ static int do_test_pprint(void) | |||
2212 | char *line = NULL; | 2269 | char *line = NULL; |
2213 | uint8_t *raw_btf; | 2270 | uint8_t *raw_btf; |
2214 | ssize_t nread; | 2271 | ssize_t nread; |
2215 | int err, ret; | ||
2216 | 2272 | ||
2217 | fprintf(stderr, "%s......", test->descr); | 2273 | fprintf(stderr, "%s......", test->descr); |
2218 | raw_btf = btf_raw_create(&hdr_tmpl, test->raw_types, | 2274 | raw_btf = btf_raw_create(&hdr_tmpl, test->raw_types, |
@@ -2261,9 +2317,18 @@ static int do_test_pprint(void) | |||
2261 | if (CHECK(err, "bpf_obj_pin(%s): errno:%d.", pin_path, errno)) | 2317 | if (CHECK(err, "bpf_obj_pin(%s): errno:%d.", pin_path, errno)) |
2262 | goto done; | 2318 | goto done; |
2263 | 2319 | ||
2320 | percpu_map = test->percpu_map; | ||
2321 | num_cpus = percpu_map ? bpf_num_possible_cpus() : 1; | ||
2322 | rounded_value_size = round_up(sizeof(struct pprint_mapv), 8); | ||
2323 | mapv = calloc(num_cpus, rounded_value_size); | ||
2324 | if (CHECK(!mapv, "mapv allocation failure")) { | ||
2325 | err = -1; | ||
2326 | goto done; | ||
2327 | } | ||
2328 | |||
2264 | for (key = 0; key < test->max_entries; key++) { | 2329 | for (key = 0; key < test->max_entries; key++) { |
2265 | set_pprint_mapv(&mapv, key); | 2330 | set_pprint_mapv(mapv, key, num_cpus, rounded_value_size); |
2266 | bpf_map_update_elem(map_fd, &key, &mapv, 0); | 2331 | bpf_map_update_elem(map_fd, &key, mapv, 0); |
2267 | } | 2332 | } |
2268 | 2333 | ||
2269 | pin_file = fopen(pin_path, "r"); | 2334 | pin_file = fopen(pin_path, "r"); |
@@ -2286,33 +2351,74 @@ static int do_test_pprint(void) | |||
2286 | ordered_map = test->ordered_map; | 2351 | ordered_map = test->ordered_map; |
2287 | lossless_map = test->lossless_map; | 2352 | lossless_map = test->lossless_map; |
2288 | do { | 2353 | do { |
2354 | struct pprint_mapv *cmapv; | ||
2289 | ssize_t nexpected_line; | 2355 | ssize_t nexpected_line; |
2290 | unsigned int next_key; | 2356 | unsigned int next_key; |
2357 | int cpu; | ||
2291 | 2358 | ||
2292 | next_key = ordered_map ? nr_read_elems : atoi(line); | 2359 | next_key = ordered_map ? nr_read_elems : atoi(line); |
2293 | set_pprint_mapv(&mapv, next_key); | 2360 | set_pprint_mapv(mapv, next_key, num_cpus, rounded_value_size); |
2294 | nexpected_line = snprintf(expected_line, sizeof(expected_line), | 2361 | cmapv = mapv; |
2295 | "%u: {%u,0,%d,0x%x,0x%x,0x%x,{%lu|[%u,%u,%u,%u,%u,%u,%u,%u]},%s}\n", | 2362 | |
2296 | next_key, | 2363 | for (cpu = 0; cpu < num_cpus; cpu++) { |
2297 | mapv.ui32, mapv.si32, | 2364 | if (percpu_map) { |
2298 | mapv.unused_bits2a, mapv.bits28, mapv.unused_bits2b, | 2365 | /* for percpu map, the format looks like: |
2299 | mapv.ui64, | 2366 | * <key>: { |
2300 | mapv.ui8a[0], mapv.ui8a[1], mapv.ui8a[2], mapv.ui8a[3], | 2367 | * cpu0: <value_on_cpu0> |
2301 | mapv.ui8a[4], mapv.ui8a[5], mapv.ui8a[6], mapv.ui8a[7], | 2368 | * cpu1: <value_on_cpu1> |
2302 | pprint_enum_str[mapv.aenum]); | 2369 | * ... |
2303 | 2370 | * cpun: <value_on_cpun> | |
2304 | if (CHECK(nexpected_line == sizeof(expected_line), | 2371 | * } |
2305 | "expected_line is too long")) { | 2372 | * |
2306 | err = -1; | 2373 | * let us verify the line containing the key here. |
2307 | goto done; | 2374 | */ |
2375 | if (cpu == 0) { | ||
2376 | nexpected_line = snprintf(expected_line, | ||
2377 | sizeof(expected_line), | ||
2378 | "%u: {\n", | ||
2379 | next_key); | ||
2380 | |||
2381 | err = check_line(expected_line, nexpected_line, | ||
2382 | sizeof(expected_line), line); | ||
2383 | if (err == -1) | ||
2384 | goto done; | ||
2385 | } | ||
2386 | |||
2387 | /* read value@cpu */ | ||
2388 | nread = getline(&line, &line_len, pin_file); | ||
2389 | if (nread < 0) | ||
2390 | break; | ||
2391 | } | ||
2392 | |||
2393 | nexpected_line = snprintf(expected_line, sizeof(expected_line), | ||
2394 | "%s%u: {%u,0,%d,0x%x,0x%x,0x%x," | ||
2395 | "{%lu|[%u,%u,%u,%u,%u,%u,%u,%u]},%s}\n", | ||
2396 | percpu_map ? "\tcpu" : "", | ||
2397 | percpu_map ? cpu : next_key, | ||
2398 | cmapv->ui32, cmapv->si32, | ||
2399 | cmapv->unused_bits2a, | ||
2400 | cmapv->bits28, | ||
2401 | cmapv->unused_bits2b, | ||
2402 | cmapv->ui64, | ||
2403 | cmapv->ui8a[0], cmapv->ui8a[1], | ||
2404 | cmapv->ui8a[2], cmapv->ui8a[3], | ||
2405 | cmapv->ui8a[4], cmapv->ui8a[5], | ||
2406 | cmapv->ui8a[6], cmapv->ui8a[7], | ||
2407 | pprint_enum_str[cmapv->aenum]); | ||
2408 | |||
2409 | err = check_line(expected_line, nexpected_line, | ||
2410 | sizeof(expected_line), line); | ||
2411 | if (err == -1) | ||
2412 | goto done; | ||
2413 | |||
2414 | cmapv = (void *)cmapv + rounded_value_size; | ||
2308 | } | 2415 | } |
2309 | 2416 | ||
2310 | if (strcmp(expected_line, line)) { | 2417 | if (percpu_map) { |
2311 | err = -1; | 2418 | /* skip the last bracket for the percpu map */ |
2312 | fprintf(stderr, "unexpected pprint output\n"); | 2419 | nread = getline(&line, &line_len, pin_file); |
2313 | fprintf(stderr, "expected: %s", expected_line); | 2420 | if (nread < 0) |
2314 | fprintf(stderr, " read: %s", line); | 2421 | break; |
2315 | goto done; | ||
2316 | } | 2422 | } |
2317 | 2423 | ||
2318 | nread = getline(&line, &line_len, pin_file); | 2424 | nread = getline(&line, &line_len, pin_file); |
@@ -2334,6 +2440,8 @@ static int do_test_pprint(void) | |||
2334 | err = 0; | 2440 | err = 0; |
2335 | 2441 | ||
2336 | done: | 2442 | done: |
2443 | if (mapv) | ||
2444 | free(mapv); | ||
2337 | if (!err) | 2445 | if (!err) |
2338 | fprintf(stderr, "OK"); | 2446 | fprintf(stderr, "OK"); |
2339 | if (*btf_log_buf && (err || args.always_log)) | 2447 | if (*btf_log_buf && (err || args.always_log)) |
@@ -2361,6 +2469,7 @@ static int test_pprint(void) | |||
2361 | pprint_test_template.map_name = pprint_tests_meta[i].map_name; | 2469 | pprint_test_template.map_name = pprint_tests_meta[i].map_name; |
2362 | pprint_test_template.ordered_map = pprint_tests_meta[i].ordered_map; | 2470 | pprint_test_template.ordered_map = pprint_tests_meta[i].ordered_map; |
2363 | pprint_test_template.lossless_map = pprint_tests_meta[i].lossless_map; | 2471 | pprint_test_template.lossless_map = pprint_tests_meta[i].lossless_map; |
2472 | pprint_test_template.percpu_map = pprint_tests_meta[i].percpu_map; | ||
2364 | 2473 | ||
2365 | err |= count_result(do_test_pprint()); | 2474 | err |= count_result(do_test_pprint()); |
2366 | } | 2475 | } |
diff --git a/tools/testing/selftests/bpf/test_cgroup_storage.c b/tools/testing/selftests/bpf/test_cgroup_storage.c index 4e196e3bfecf..f44834155f25 100644 --- a/tools/testing/selftests/bpf/test_cgroup_storage.c +++ b/tools/testing/selftests/bpf/test_cgroup_storage.c | |||
@@ -4,6 +4,7 @@ | |||
4 | #include <linux/filter.h> | 4 | #include <linux/filter.h> |
5 | #include <stdio.h> | 5 | #include <stdio.h> |
6 | #include <stdlib.h> | 6 | #include <stdlib.h> |
7 | #include <sys/sysinfo.h> | ||
7 | 8 | ||
8 | #include "bpf_rlimit.h" | 9 | #include "bpf_rlimit.h" |
9 | #include "cgroup_helpers.h" | 10 | #include "cgroup_helpers.h" |
@@ -15,6 +16,14 @@ char bpf_log_buf[BPF_LOG_BUF_SIZE]; | |||
15 | int main(int argc, char **argv) | 16 | int main(int argc, char **argv) |
16 | { | 17 | { |
17 | struct bpf_insn prog[] = { | 18 | struct bpf_insn prog[] = { |
19 | BPF_LD_MAP_FD(BPF_REG_1, 0), /* percpu map fd */ | ||
20 | BPF_MOV64_IMM(BPF_REG_2, 0), /* flags, not used */ | ||
21 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
22 | BPF_FUNC_get_local_storage), | ||
23 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_0, 0), | ||
24 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, 0x1), | ||
25 | BPF_STX_MEM(BPF_W, BPF_REG_0, BPF_REG_3, 0), | ||
26 | |||
18 | BPF_LD_MAP_FD(BPF_REG_1, 0), /* map fd */ | 27 | BPF_LD_MAP_FD(BPF_REG_1, 0), /* map fd */ |
19 | BPF_MOV64_IMM(BPF_REG_2, 0), /* flags, not used */ | 28 | BPF_MOV64_IMM(BPF_REG_2, 0), /* flags, not used */ |
20 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | 29 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, |
@@ -28,9 +37,18 @@ int main(int argc, char **argv) | |||
28 | }; | 37 | }; |
29 | size_t insns_cnt = sizeof(prog) / sizeof(struct bpf_insn); | 38 | size_t insns_cnt = sizeof(prog) / sizeof(struct bpf_insn); |
30 | int error = EXIT_FAILURE; | 39 | int error = EXIT_FAILURE; |
31 | int map_fd, prog_fd, cgroup_fd; | 40 | int map_fd, percpu_map_fd, prog_fd, cgroup_fd; |
32 | struct bpf_cgroup_storage_key key; | 41 | struct bpf_cgroup_storage_key key; |
33 | unsigned long long value; | 42 | unsigned long long value; |
43 | unsigned long long *percpu_value; | ||
44 | int cpu, nproc; | ||
45 | |||
46 | nproc = get_nprocs_conf(); | ||
47 | percpu_value = malloc(sizeof(*percpu_value) * nproc); | ||
48 | if (!percpu_value) { | ||
49 | printf("Not enough memory for per-cpu area (%d cpus)\n", nproc); | ||
50 | goto err; | ||
51 | } | ||
34 | 52 | ||
35 | map_fd = bpf_create_map(BPF_MAP_TYPE_CGROUP_STORAGE, sizeof(key), | 53 | map_fd = bpf_create_map(BPF_MAP_TYPE_CGROUP_STORAGE, sizeof(key), |
36 | sizeof(value), 0, 0); | 54 | sizeof(value), 0, 0); |
@@ -39,7 +57,15 @@ int main(int argc, char **argv) | |||
39 | goto out; | 57 | goto out; |
40 | } | 58 | } |
41 | 59 | ||
42 | prog[0].imm = map_fd; | 60 | percpu_map_fd = bpf_create_map(BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE, |
61 | sizeof(key), sizeof(value), 0, 0); | ||
62 | if (percpu_map_fd < 0) { | ||
63 | printf("Failed to create map: %s\n", strerror(errno)); | ||
64 | goto out; | ||
65 | } | ||
66 | |||
67 | prog[0].imm = percpu_map_fd; | ||
68 | prog[7].imm = map_fd; | ||
43 | prog_fd = bpf_load_program(BPF_PROG_TYPE_CGROUP_SKB, | 69 | prog_fd = bpf_load_program(BPF_PROG_TYPE_CGROUP_SKB, |
44 | prog, insns_cnt, "GPL", 0, | 70 | prog, insns_cnt, "GPL", 0, |
45 | bpf_log_buf, BPF_LOG_BUF_SIZE); | 71 | bpf_log_buf, BPF_LOG_BUF_SIZE); |
@@ -77,7 +103,15 @@ int main(int argc, char **argv) | |||
77 | } | 103 | } |
78 | 104 | ||
79 | if (bpf_map_lookup_elem(map_fd, &key, &value)) { | 105 | if (bpf_map_lookup_elem(map_fd, &key, &value)) { |
80 | printf("Failed to lookup cgroup storage\n"); | 106 | printf("Failed to lookup cgroup storage 0\n"); |
107 | goto err; | ||
108 | } | ||
109 | |||
110 | for (cpu = 0; cpu < nproc; cpu++) | ||
111 | percpu_value[cpu] = 1000; | ||
112 | |||
113 | if (bpf_map_update_elem(percpu_map_fd, &key, percpu_value, 0)) { | ||
114 | printf("Failed to update the data in the cgroup storage\n"); | ||
81 | goto err; | 115 | goto err; |
82 | } | 116 | } |
83 | 117 | ||
@@ -120,11 +154,31 @@ int main(int argc, char **argv) | |||
120 | goto err; | 154 | goto err; |
121 | } | 155 | } |
122 | 156 | ||
157 | /* Check the final value of the counter in the percpu local storage */ | ||
158 | |||
159 | for (cpu = 0; cpu < nproc; cpu++) | ||
160 | percpu_value[cpu] = 0; | ||
161 | |||
162 | if (bpf_map_lookup_elem(percpu_map_fd, &key, percpu_value)) { | ||
163 | printf("Failed to lookup the per-cpu cgroup storage\n"); | ||
164 | goto err; | ||
165 | } | ||
166 | |||
167 | value = 0; | ||
168 | for (cpu = 0; cpu < nproc; cpu++) | ||
169 | value += percpu_value[cpu]; | ||
170 | |||
171 | if (value != nproc * 1000 + 6) { | ||
172 | printf("Unexpected data in the per-cpu cgroup storage\n"); | ||
173 | goto err; | ||
174 | } | ||
175 | |||
123 | error = 0; | 176 | error = 0; |
124 | printf("test_cgroup_storage:PASS\n"); | 177 | printf("test_cgroup_storage:PASS\n"); |
125 | 178 | ||
126 | err: | 179 | err: |
127 | cleanup_cgroup_environment(); | 180 | cleanup_cgroup_environment(); |
181 | free(percpu_value); | ||
128 | 182 | ||
129 | out: | 183 | out: |
130 | return error; | 184 | return error; |
diff --git a/tools/testing/selftests/bpf/test_flow_dissector.c b/tools/testing/selftests/bpf/test_flow_dissector.c new file mode 100644 index 000000000000..12b784afba31 --- /dev/null +++ b/tools/testing/selftests/bpf/test_flow_dissector.c | |||
@@ -0,0 +1,782 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * Inject packets with all sorts of encapsulation into the kernel. | ||
4 | * | ||
5 | * IPv4/IPv6 outer layer 3 | ||
6 | * GRE/GUE/BARE outer layer 4, where bare is IPIP/SIT/IPv4-in-IPv6/.. | ||
7 | * IPv4/IPv6 inner layer 3 | ||
8 | */ | ||
9 | |||
10 | #define _GNU_SOURCE | ||
11 | |||
12 | #include <stddef.h> | ||
13 | #include <arpa/inet.h> | ||
14 | #include <asm/byteorder.h> | ||
15 | #include <error.h> | ||
16 | #include <errno.h> | ||
17 | #include <linux/if_packet.h> | ||
18 | #include <linux/if_ether.h> | ||
19 | #include <linux/if_packet.h> | ||
20 | #include <linux/ipv6.h> | ||
21 | #include <netinet/ip.h> | ||
22 | #include <netinet/in.h> | ||
23 | #include <netinet/udp.h> | ||
24 | #include <poll.h> | ||
25 | #include <stdbool.h> | ||
26 | #include <stdlib.h> | ||
27 | #include <stdio.h> | ||
28 | #include <stdlib.h> | ||
29 | #include <string.h> | ||
30 | #include <sys/ioctl.h> | ||
31 | #include <sys/socket.h> | ||
32 | #include <sys/stat.h> | ||
33 | #include <sys/time.h> | ||
34 | #include <sys/types.h> | ||
35 | #include <unistd.h> | ||
36 | |||
37 | #define CFG_PORT_INNER 8000 | ||
38 | |||
39 | /* Add some protocol definitions that do not exist in userspace */ | ||
40 | |||
41 | struct grehdr { | ||
42 | uint16_t unused; | ||
43 | uint16_t protocol; | ||
44 | } __attribute__((packed)); | ||
45 | |||
46 | struct guehdr { | ||
47 | union { | ||
48 | struct { | ||
49 | #if defined(__LITTLE_ENDIAN_BITFIELD) | ||
50 | __u8 hlen:5, | ||
51 | control:1, | ||
52 | version:2; | ||
53 | #elif defined (__BIG_ENDIAN_BITFIELD) | ||
54 | __u8 version:2, | ||
55 | control:1, | ||
56 | hlen:5; | ||
57 | #else | ||
58 | #error "Please fix <asm/byteorder.h>" | ||
59 | #endif | ||
60 | __u8 proto_ctype; | ||
61 | __be16 flags; | ||
62 | }; | ||
63 | __be32 word; | ||
64 | }; | ||
65 | }; | ||
66 | |||
67 | static uint8_t cfg_dsfield_inner; | ||
68 | static uint8_t cfg_dsfield_outer; | ||
69 | static uint8_t cfg_encap_proto; | ||
70 | static bool cfg_expect_failure = false; | ||
71 | static int cfg_l3_extra = AF_UNSPEC; /* optional SIT prefix */ | ||
72 | static int cfg_l3_inner = AF_UNSPEC; | ||
73 | static int cfg_l3_outer = AF_UNSPEC; | ||
74 | static int cfg_num_pkt = 10; | ||
75 | static int cfg_num_secs = 0; | ||
76 | static char cfg_payload_char = 'a'; | ||
77 | static int cfg_payload_len = 100; | ||
78 | static int cfg_port_gue = 6080; | ||
79 | static bool cfg_only_rx; | ||
80 | static bool cfg_only_tx; | ||
81 | static int cfg_src_port = 9; | ||
82 | |||
83 | static char buf[ETH_DATA_LEN]; | ||
84 | |||
85 | #define INIT_ADDR4(name, addr4, port) \ | ||
86 | static struct sockaddr_in name = { \ | ||
87 | .sin_family = AF_INET, \ | ||
88 | .sin_port = __constant_htons(port), \ | ||
89 | .sin_addr.s_addr = __constant_htonl(addr4), \ | ||
90 | }; | ||
91 | |||
92 | #define INIT_ADDR6(name, addr6, port) \ | ||
93 | static struct sockaddr_in6 name = { \ | ||
94 | .sin6_family = AF_INET6, \ | ||
95 | .sin6_port = __constant_htons(port), \ | ||
96 | .sin6_addr = addr6, \ | ||
97 | }; | ||
98 | |||
99 | INIT_ADDR4(in_daddr4, INADDR_LOOPBACK, CFG_PORT_INNER) | ||
100 | INIT_ADDR4(in_saddr4, INADDR_LOOPBACK + 2, 0) | ||
101 | INIT_ADDR4(out_daddr4, INADDR_LOOPBACK, 0) | ||
102 | INIT_ADDR4(out_saddr4, INADDR_LOOPBACK + 1, 0) | ||
103 | INIT_ADDR4(extra_daddr4, INADDR_LOOPBACK, 0) | ||
104 | INIT_ADDR4(extra_saddr4, INADDR_LOOPBACK + 1, 0) | ||
105 | |||
106 | INIT_ADDR6(in_daddr6, IN6ADDR_LOOPBACK_INIT, CFG_PORT_INNER) | ||
107 | INIT_ADDR6(in_saddr6, IN6ADDR_LOOPBACK_INIT, 0) | ||
108 | INIT_ADDR6(out_daddr6, IN6ADDR_LOOPBACK_INIT, 0) | ||
109 | INIT_ADDR6(out_saddr6, IN6ADDR_LOOPBACK_INIT, 0) | ||
110 | INIT_ADDR6(extra_daddr6, IN6ADDR_LOOPBACK_INIT, 0) | ||
111 | INIT_ADDR6(extra_saddr6, IN6ADDR_LOOPBACK_INIT, 0) | ||
112 | |||
113 | static unsigned long util_gettime(void) | ||
114 | { | ||
115 | struct timeval tv; | ||
116 | |||
117 | gettimeofday(&tv, NULL); | ||
118 | return (tv.tv_sec * 1000) + (tv.tv_usec / 1000); | ||
119 | } | ||
120 | |||
121 | static void util_printaddr(const char *msg, struct sockaddr *addr) | ||
122 | { | ||
123 | unsigned long off = 0; | ||
124 | char nbuf[INET6_ADDRSTRLEN]; | ||
125 | |||
126 | switch (addr->sa_family) { | ||
127 | case PF_INET: | ||
128 | off = __builtin_offsetof(struct sockaddr_in, sin_addr); | ||
129 | break; | ||
130 | case PF_INET6: | ||
131 | off = __builtin_offsetof(struct sockaddr_in6, sin6_addr); | ||
132 | break; | ||
133 | default: | ||
134 | error(1, 0, "printaddr: unsupported family %u\n", | ||
135 | addr->sa_family); | ||
136 | } | ||
137 | |||
138 | if (!inet_ntop(addr->sa_family, ((void *) addr) + off, nbuf, | ||
139 | sizeof(nbuf))) | ||
140 | error(1, errno, "inet_ntop"); | ||
141 | |||
142 | fprintf(stderr, "%s: %s\n", msg, nbuf); | ||
143 | } | ||
144 | |||
145 | static unsigned long add_csum_hword(const uint16_t *start, int num_u16) | ||
146 | { | ||
147 | unsigned long sum = 0; | ||
148 | int i; | ||
149 | |||
150 | for (i = 0; i < num_u16; i++) | ||
151 | sum += start[i]; | ||
152 | |||
153 | return sum; | ||
154 | } | ||
155 | |||
156 | static uint16_t build_ip_csum(const uint16_t *start, int num_u16, | ||
157 | unsigned long sum) | ||
158 | { | ||
159 | sum += add_csum_hword(start, num_u16); | ||
160 | |||
161 | while (sum >> 16) | ||
162 | sum = (sum & 0xffff) + (sum >> 16); | ||
163 | |||
164 | return ~sum; | ||
165 | } | ||
166 | |||
167 | static void build_ipv4_header(void *header, uint8_t proto, | ||
168 | uint32_t src, uint32_t dst, | ||
169 | int payload_len, uint8_t tos) | ||
170 | { | ||
171 | struct iphdr *iph = header; | ||
172 | |||
173 | iph->ihl = 5; | ||
174 | iph->version = 4; | ||
175 | iph->tos = tos; | ||
176 | iph->ttl = 8; | ||
177 | iph->tot_len = htons(sizeof(*iph) + payload_len); | ||
178 | iph->id = htons(1337); | ||
179 | iph->protocol = proto; | ||
180 | iph->saddr = src; | ||
181 | iph->daddr = dst; | ||
182 | iph->check = build_ip_csum((void *) iph, iph->ihl << 1, 0); | ||
183 | } | ||
184 | |||
185 | static void ipv6_set_dsfield(struct ipv6hdr *ip6h, uint8_t dsfield) | ||
186 | { | ||
187 | uint16_t val, *ptr = (uint16_t *)ip6h; | ||
188 | |||
189 | val = ntohs(*ptr); | ||
190 | val &= 0xF00F; | ||
191 | val |= ((uint16_t) dsfield) << 4; | ||
192 | *ptr = htons(val); | ||
193 | } | ||
194 | |||
195 | static void build_ipv6_header(void *header, uint8_t proto, | ||
196 | struct sockaddr_in6 *src, | ||
197 | struct sockaddr_in6 *dst, | ||
198 | int payload_len, uint8_t dsfield) | ||
199 | { | ||
200 | struct ipv6hdr *ip6h = header; | ||
201 | |||
202 | ip6h->version = 6; | ||
203 | ip6h->payload_len = htons(payload_len); | ||
204 | ip6h->nexthdr = proto; | ||
205 | ip6h->hop_limit = 8; | ||
206 | ipv6_set_dsfield(ip6h, dsfield); | ||
207 | |||
208 | memcpy(&ip6h->saddr, &src->sin6_addr, sizeof(ip6h->saddr)); | ||
209 | memcpy(&ip6h->daddr, &dst->sin6_addr, sizeof(ip6h->daddr)); | ||
210 | } | ||
211 | |||
212 | static uint16_t build_udp_v4_csum(const struct iphdr *iph, | ||
213 | const struct udphdr *udph, | ||
214 | int num_words) | ||
215 | { | ||
216 | unsigned long pseudo_sum; | ||
217 | int num_u16 = sizeof(iph->saddr); /* halfwords: twice byte len */ | ||
218 | |||
219 | pseudo_sum = add_csum_hword((void *) &iph->saddr, num_u16); | ||
220 | pseudo_sum += htons(IPPROTO_UDP); | ||
221 | pseudo_sum += udph->len; | ||
222 | return build_ip_csum((void *) udph, num_words, pseudo_sum); | ||
223 | } | ||
224 | |||
225 | static uint16_t build_udp_v6_csum(const struct ipv6hdr *ip6h, | ||
226 | const struct udphdr *udph, | ||
227 | int num_words) | ||
228 | { | ||
229 | unsigned long pseudo_sum; | ||
230 | int num_u16 = sizeof(ip6h->saddr); /* halfwords: twice byte len */ | ||
231 | |||
232 | pseudo_sum = add_csum_hword((void *) &ip6h->saddr, num_u16); | ||
233 | pseudo_sum += htons(ip6h->nexthdr); | ||
234 | pseudo_sum += ip6h->payload_len; | ||
235 | return build_ip_csum((void *) udph, num_words, pseudo_sum); | ||
236 | } | ||
237 | |||
238 | static void build_udp_header(void *header, int payload_len, | ||
239 | uint16_t dport, int family) | ||
240 | { | ||
241 | struct udphdr *udph = header; | ||
242 | int len = sizeof(*udph) + payload_len; | ||
243 | |||
244 | udph->source = htons(cfg_src_port); | ||
245 | udph->dest = htons(dport); | ||
246 | udph->len = htons(len); | ||
247 | udph->check = 0; | ||
248 | if (family == AF_INET) | ||
249 | udph->check = build_udp_v4_csum(header - sizeof(struct iphdr), | ||
250 | udph, len >> 1); | ||
251 | else | ||
252 | udph->check = build_udp_v6_csum(header - sizeof(struct ipv6hdr), | ||
253 | udph, len >> 1); | ||
254 | } | ||
255 | |||
256 | static void build_gue_header(void *header, uint8_t proto) | ||
257 | { | ||
258 | struct guehdr *gueh = header; | ||
259 | |||
260 | gueh->proto_ctype = proto; | ||
261 | } | ||
262 | |||
263 | static void build_gre_header(void *header, uint16_t proto) | ||
264 | { | ||
265 | struct grehdr *greh = header; | ||
266 | |||
267 | greh->protocol = htons(proto); | ||
268 | } | ||
269 | |||
270 | static int l3_length(int family) | ||
271 | { | ||
272 | if (family == AF_INET) | ||
273 | return sizeof(struct iphdr); | ||
274 | else | ||
275 | return sizeof(struct ipv6hdr); | ||
276 | } | ||
277 | |||
278 | static int build_packet(void) | ||
279 | { | ||
280 | int ol3_len = 0, ol4_len = 0, il3_len = 0, il4_len = 0; | ||
281 | int el3_len = 0; | ||
282 | |||
283 | if (cfg_l3_extra) | ||
284 | el3_len = l3_length(cfg_l3_extra); | ||
285 | |||
286 | /* calculate header offsets */ | ||
287 | if (cfg_encap_proto) { | ||
288 | ol3_len = l3_length(cfg_l3_outer); | ||
289 | |||
290 | if (cfg_encap_proto == IPPROTO_GRE) | ||
291 | ol4_len = sizeof(struct grehdr); | ||
292 | else if (cfg_encap_proto == IPPROTO_UDP) | ||
293 | ol4_len = sizeof(struct udphdr) + sizeof(struct guehdr); | ||
294 | } | ||
295 | |||
296 | il3_len = l3_length(cfg_l3_inner); | ||
297 | il4_len = sizeof(struct udphdr); | ||
298 | |||
299 | if (el3_len + ol3_len + ol4_len + il3_len + il4_len + cfg_payload_len >= | ||
300 | sizeof(buf)) | ||
301 | error(1, 0, "packet too large\n"); | ||
302 | |||
303 | /* | ||
304 | * Fill packet from inside out, to calculate correct checksums. | ||
305 | * But create ip before udp headers, as udp uses ip for pseudo-sum. | ||
306 | */ | ||
307 | memset(buf + el3_len + ol3_len + ol4_len + il3_len + il4_len, | ||
308 | cfg_payload_char, cfg_payload_len); | ||
309 | |||
310 | /* add zero byte for udp csum padding */ | ||
311 | buf[el3_len + ol3_len + ol4_len + il3_len + il4_len + cfg_payload_len] = 0; | ||
312 | |||
313 | switch (cfg_l3_inner) { | ||
314 | case PF_INET: | ||
315 | build_ipv4_header(buf + el3_len + ol3_len + ol4_len, | ||
316 | IPPROTO_UDP, | ||
317 | in_saddr4.sin_addr.s_addr, | ||
318 | in_daddr4.sin_addr.s_addr, | ||
319 | il4_len + cfg_payload_len, | ||
320 | cfg_dsfield_inner); | ||
321 | break; | ||
322 | case PF_INET6: | ||
323 | build_ipv6_header(buf + el3_len + ol3_len + ol4_len, | ||
324 | IPPROTO_UDP, | ||
325 | &in_saddr6, &in_daddr6, | ||
326 | il4_len + cfg_payload_len, | ||
327 | cfg_dsfield_inner); | ||
328 | break; | ||
329 | } | ||
330 | |||
331 | build_udp_header(buf + el3_len + ol3_len + ol4_len + il3_len, | ||
332 | cfg_payload_len, CFG_PORT_INNER, cfg_l3_inner); | ||
333 | |||
334 | if (!cfg_encap_proto) | ||
335 | return il3_len + il4_len + cfg_payload_len; | ||
336 | |||
337 | switch (cfg_l3_outer) { | ||
338 | case PF_INET: | ||
339 | build_ipv4_header(buf + el3_len, cfg_encap_proto, | ||
340 | out_saddr4.sin_addr.s_addr, | ||
341 | out_daddr4.sin_addr.s_addr, | ||
342 | ol4_len + il3_len + il4_len + cfg_payload_len, | ||
343 | cfg_dsfield_outer); | ||
344 | break; | ||
345 | case PF_INET6: | ||
346 | build_ipv6_header(buf + el3_len, cfg_encap_proto, | ||
347 | &out_saddr6, &out_daddr6, | ||
348 | ol4_len + il3_len + il4_len + cfg_payload_len, | ||
349 | cfg_dsfield_outer); | ||
350 | break; | ||
351 | } | ||
352 | |||
353 | switch (cfg_encap_proto) { | ||
354 | case IPPROTO_UDP: | ||
355 | build_gue_header(buf + el3_len + ol3_len + ol4_len - | ||
356 | sizeof(struct guehdr), | ||
357 | cfg_l3_inner == PF_INET ? IPPROTO_IPIP | ||
358 | : IPPROTO_IPV6); | ||
359 | build_udp_header(buf + el3_len + ol3_len, | ||
360 | sizeof(struct guehdr) + il3_len + il4_len + | ||
361 | cfg_payload_len, | ||
362 | cfg_port_gue, cfg_l3_outer); | ||
363 | break; | ||
364 | case IPPROTO_GRE: | ||
365 | build_gre_header(buf + el3_len + ol3_len, | ||
366 | cfg_l3_inner == PF_INET ? ETH_P_IP | ||
367 | : ETH_P_IPV6); | ||
368 | break; | ||
369 | } | ||
370 | |||
371 | switch (cfg_l3_extra) { | ||
372 | case PF_INET: | ||
373 | build_ipv4_header(buf, | ||
374 | cfg_l3_outer == PF_INET ? IPPROTO_IPIP | ||
375 | : IPPROTO_IPV6, | ||
376 | extra_saddr4.sin_addr.s_addr, | ||
377 | extra_daddr4.sin_addr.s_addr, | ||
378 | ol3_len + ol4_len + il3_len + il4_len + | ||
379 | cfg_payload_len, 0); | ||
380 | break; | ||
381 | case PF_INET6: | ||
382 | build_ipv6_header(buf, | ||
383 | cfg_l3_outer == PF_INET ? IPPROTO_IPIP | ||
384 | : IPPROTO_IPV6, | ||
385 | &extra_saddr6, &extra_daddr6, | ||
386 | ol3_len + ol4_len + il3_len + il4_len + | ||
387 | cfg_payload_len, 0); | ||
388 | break; | ||
389 | } | ||
390 | |||
391 | return el3_len + ol3_len + ol4_len + il3_len + il4_len + | ||
392 | cfg_payload_len; | ||
393 | } | ||
394 | |||
395 | /* sender transmits encapsulated over RAW or unencap'd over UDP */ | ||
396 | static int setup_tx(void) | ||
397 | { | ||
398 | int family, fd, ret; | ||
399 | |||
400 | if (cfg_l3_extra) | ||
401 | family = cfg_l3_extra; | ||
402 | else if (cfg_l3_outer) | ||
403 | family = cfg_l3_outer; | ||
404 | else | ||
405 | family = cfg_l3_inner; | ||
406 | |||
407 | fd = socket(family, SOCK_RAW, IPPROTO_RAW); | ||
408 | if (fd == -1) | ||
409 | error(1, errno, "socket tx"); | ||
410 | |||
411 | if (cfg_l3_extra) { | ||
412 | if (cfg_l3_extra == PF_INET) | ||
413 | ret = connect(fd, (void *) &extra_daddr4, | ||
414 | sizeof(extra_daddr4)); | ||
415 | else | ||
416 | ret = connect(fd, (void *) &extra_daddr6, | ||
417 | sizeof(extra_daddr6)); | ||
418 | if (ret) | ||
419 | error(1, errno, "connect tx"); | ||
420 | } else if (cfg_l3_outer) { | ||
421 | /* connect to destination if not encapsulated */ | ||
422 | if (cfg_l3_outer == PF_INET) | ||
423 | ret = connect(fd, (void *) &out_daddr4, | ||
424 | sizeof(out_daddr4)); | ||
425 | else | ||
426 | ret = connect(fd, (void *) &out_daddr6, | ||
427 | sizeof(out_daddr6)); | ||
428 | if (ret) | ||
429 | error(1, errno, "connect tx"); | ||
430 | } else { | ||
431 | /* otherwise using loopback */ | ||
432 | if (cfg_l3_inner == PF_INET) | ||
433 | ret = connect(fd, (void *) &in_daddr4, | ||
434 | sizeof(in_daddr4)); | ||
435 | else | ||
436 | ret = connect(fd, (void *) &in_daddr6, | ||
437 | sizeof(in_daddr6)); | ||
438 | if (ret) | ||
439 | error(1, errno, "connect tx"); | ||
440 | } | ||
441 | |||
442 | return fd; | ||
443 | } | ||
444 | |||
445 | /* receiver reads unencapsulated UDP */ | ||
446 | static int setup_rx(void) | ||
447 | { | ||
448 | int fd, ret; | ||
449 | |||
450 | fd = socket(cfg_l3_inner, SOCK_DGRAM, 0); | ||
451 | if (fd == -1) | ||
452 | error(1, errno, "socket rx"); | ||
453 | |||
454 | if (cfg_l3_inner == PF_INET) | ||
455 | ret = bind(fd, (void *) &in_daddr4, sizeof(in_daddr4)); | ||
456 | else | ||
457 | ret = bind(fd, (void *) &in_daddr6, sizeof(in_daddr6)); | ||
458 | if (ret) | ||
459 | error(1, errno, "bind rx"); | ||
460 | |||
461 | return fd; | ||
462 | } | ||
463 | |||
464 | static int do_tx(int fd, const char *pkt, int len) | ||
465 | { | ||
466 | int ret; | ||
467 | |||
468 | ret = write(fd, pkt, len); | ||
469 | if (ret == -1) | ||
470 | error(1, errno, "send"); | ||
471 | if (ret != len) | ||
472 | error(1, errno, "send: len (%d < %d)\n", ret, len); | ||
473 | |||
474 | return 1; | ||
475 | } | ||
476 | |||
477 | static int do_poll(int fd, short events, int timeout) | ||
478 | { | ||
479 | struct pollfd pfd; | ||
480 | int ret; | ||
481 | |||
482 | pfd.fd = fd; | ||
483 | pfd.events = events; | ||
484 | |||
485 | ret = poll(&pfd, 1, timeout); | ||
486 | if (ret == -1) | ||
487 | error(1, errno, "poll"); | ||
488 | if (ret && !(pfd.revents & POLLIN)) | ||
489 | error(1, errno, "poll: unexpected event 0x%x\n", pfd.revents); | ||
490 | |||
491 | return ret; | ||
492 | } | ||
493 | |||
494 | static int do_rx(int fd) | ||
495 | { | ||
496 | char rbuf; | ||
497 | int ret, num = 0; | ||
498 | |||
499 | while (1) { | ||
500 | ret = recv(fd, &rbuf, 1, MSG_DONTWAIT); | ||
501 | if (ret == -1 && errno == EAGAIN) | ||
502 | break; | ||
503 | if (ret == -1) | ||
504 | error(1, errno, "recv"); | ||
505 | if (rbuf != cfg_payload_char) | ||
506 | error(1, 0, "recv: payload mismatch"); | ||
507 | num++; | ||
508 | }; | ||
509 | |||
510 | return num; | ||
511 | } | ||
512 | |||
513 | static int do_main(void) | ||
514 | { | ||
515 | unsigned long tstop, treport, tcur; | ||
516 | int fdt = -1, fdr = -1, len, tx = 0, rx = 0; | ||
517 | |||
518 | if (!cfg_only_tx) | ||
519 | fdr = setup_rx(); | ||
520 | if (!cfg_only_rx) | ||
521 | fdt = setup_tx(); | ||
522 | |||
523 | len = build_packet(); | ||
524 | |||
525 | tcur = util_gettime(); | ||
526 | treport = tcur + 1000; | ||
527 | tstop = tcur + (cfg_num_secs * 1000); | ||
528 | |||
529 | while (1) { | ||
530 | if (!cfg_only_rx) | ||
531 | tx += do_tx(fdt, buf, len); | ||
532 | |||
533 | if (!cfg_only_tx) | ||
534 | rx += do_rx(fdr); | ||
535 | |||
536 | if (cfg_num_secs) { | ||
537 | tcur = util_gettime(); | ||
538 | if (tcur >= tstop) | ||
539 | break; | ||
540 | if (tcur >= treport) { | ||
541 | fprintf(stderr, "pkts: tx=%u rx=%u\n", tx, rx); | ||
542 | tx = 0; | ||
543 | rx = 0; | ||
544 | treport = tcur + 1000; | ||
545 | } | ||
546 | } else { | ||
547 | if (tx == cfg_num_pkt) | ||
548 | break; | ||
549 | } | ||
550 | } | ||
551 | |||
552 | /* read straggler packets, if any */ | ||
553 | if (rx < tx) { | ||
554 | tstop = util_gettime() + 100; | ||
555 | while (rx < tx) { | ||
556 | tcur = util_gettime(); | ||
557 | if (tcur >= tstop) | ||
558 | break; | ||
559 | |||
560 | do_poll(fdr, POLLIN, tstop - tcur); | ||
561 | rx += do_rx(fdr); | ||
562 | } | ||
563 | } | ||
564 | |||
565 | fprintf(stderr, "pkts: tx=%u rx=%u\n", tx, rx); | ||
566 | |||
567 | if (fdr != -1 && close(fdr)) | ||
568 | error(1, errno, "close rx"); | ||
569 | if (fdt != -1 && close(fdt)) | ||
570 | error(1, errno, "close tx"); | ||
571 | |||
572 | /* | ||
573 | * success (== 0) only if received all packets | ||
574 | * unless failure is expected, in which case none must arrive. | ||
575 | */ | ||
576 | if (cfg_expect_failure) | ||
577 | return rx != 0; | ||
578 | else | ||
579 | return rx != tx; | ||
580 | } | ||
581 | |||
582 | |||
583 | static void __attribute__((noreturn)) usage(const char *filepath) | ||
584 | { | ||
585 | fprintf(stderr, "Usage: %s [-e gre|gue|bare|none] [-i 4|6] [-l len] " | ||
586 | "[-O 4|6] [-o 4|6] [-n num] [-t secs] [-R] [-T] " | ||
587 | "[-s <osrc> [-d <odst>] [-S <isrc>] [-D <idst>] " | ||
588 | "[-x <otos>] [-X <itos>] [-f <isport>] [-F]\n", | ||
589 | filepath); | ||
590 | exit(1); | ||
591 | } | ||
592 | |||
593 | static void parse_addr(int family, void *addr, const char *optarg) | ||
594 | { | ||
595 | int ret; | ||
596 | |||
597 | ret = inet_pton(family, optarg, addr); | ||
598 | if (ret == -1) | ||
599 | error(1, errno, "inet_pton"); | ||
600 | if (ret == 0) | ||
601 | error(1, 0, "inet_pton: bad string"); | ||
602 | } | ||
603 | |||
604 | static void parse_addr4(struct sockaddr_in *addr, const char *optarg) | ||
605 | { | ||
606 | parse_addr(AF_INET, &addr->sin_addr, optarg); | ||
607 | } | ||
608 | |||
609 | static void parse_addr6(struct sockaddr_in6 *addr, const char *optarg) | ||
610 | { | ||
611 | parse_addr(AF_INET6, &addr->sin6_addr, optarg); | ||
612 | } | ||
613 | |||
614 | static int parse_protocol_family(const char *filepath, const char *optarg) | ||
615 | { | ||
616 | if (!strcmp(optarg, "4")) | ||
617 | return PF_INET; | ||
618 | if (!strcmp(optarg, "6")) | ||
619 | return PF_INET6; | ||
620 | |||
621 | usage(filepath); | ||
622 | } | ||
623 | |||
624 | static void parse_opts(int argc, char **argv) | ||
625 | { | ||
626 | int c; | ||
627 | |||
628 | while ((c = getopt(argc, argv, "d:D:e:f:Fhi:l:n:o:O:Rs:S:t:Tx:X:")) != -1) { | ||
629 | switch (c) { | ||
630 | case 'd': | ||
631 | if (cfg_l3_outer == AF_UNSPEC) | ||
632 | error(1, 0, "-d must be preceded by -o"); | ||
633 | if (cfg_l3_outer == AF_INET) | ||
634 | parse_addr4(&out_daddr4, optarg); | ||
635 | else | ||
636 | parse_addr6(&out_daddr6, optarg); | ||
637 | break; | ||
638 | case 'D': | ||
639 | if (cfg_l3_inner == AF_UNSPEC) | ||
640 | error(1, 0, "-D must be preceded by -i"); | ||
641 | if (cfg_l3_inner == AF_INET) | ||
642 | parse_addr4(&in_daddr4, optarg); | ||
643 | else | ||
644 | parse_addr6(&in_daddr6, optarg); | ||
645 | break; | ||
646 | case 'e': | ||
647 | if (!strcmp(optarg, "gre")) | ||
648 | cfg_encap_proto = IPPROTO_GRE; | ||
649 | else if (!strcmp(optarg, "gue")) | ||
650 | cfg_encap_proto = IPPROTO_UDP; | ||
651 | else if (!strcmp(optarg, "bare")) | ||
652 | cfg_encap_proto = IPPROTO_IPIP; | ||
653 | else if (!strcmp(optarg, "none")) | ||
654 | cfg_encap_proto = IPPROTO_IP; /* == 0 */ | ||
655 | else | ||
656 | usage(argv[0]); | ||
657 | break; | ||
658 | case 'f': | ||
659 | cfg_src_port = strtol(optarg, NULL, 0); | ||
660 | break; | ||
661 | case 'F': | ||
662 | cfg_expect_failure = true; | ||
663 | break; | ||
664 | case 'h': | ||
665 | usage(argv[0]); | ||
666 | break; | ||
667 | case 'i': | ||
668 | if (!strcmp(optarg, "4")) | ||
669 | cfg_l3_inner = PF_INET; | ||
670 | else if (!strcmp(optarg, "6")) | ||
671 | cfg_l3_inner = PF_INET6; | ||
672 | else | ||
673 | usage(argv[0]); | ||
674 | break; | ||
675 | case 'l': | ||
676 | cfg_payload_len = strtol(optarg, NULL, 0); | ||
677 | break; | ||
678 | case 'n': | ||
679 | cfg_num_pkt = strtol(optarg, NULL, 0); | ||
680 | break; | ||
681 | case 'o': | ||
682 | cfg_l3_outer = parse_protocol_family(argv[0], optarg); | ||
683 | break; | ||
684 | case 'O': | ||
685 | cfg_l3_extra = parse_protocol_family(argv[0], optarg); | ||
686 | break; | ||
687 | case 'R': | ||
688 | cfg_only_rx = true; | ||
689 | break; | ||
690 | case 's': | ||
691 | if (cfg_l3_outer == AF_INET) | ||
692 | parse_addr4(&out_saddr4, optarg); | ||
693 | else | ||
694 | parse_addr6(&out_saddr6, optarg); | ||
695 | break; | ||
696 | case 'S': | ||
697 | if (cfg_l3_inner == AF_INET) | ||
698 | parse_addr4(&in_saddr4, optarg); | ||
699 | else | ||
700 | parse_addr6(&in_saddr6, optarg); | ||
701 | break; | ||
702 | case 't': | ||
703 | cfg_num_secs = strtol(optarg, NULL, 0); | ||
704 | break; | ||
705 | case 'T': | ||
706 | cfg_only_tx = true; | ||
707 | break; | ||
708 | case 'x': | ||
709 | cfg_dsfield_outer = strtol(optarg, NULL, 0); | ||
710 | break; | ||
711 | case 'X': | ||
712 | cfg_dsfield_inner = strtol(optarg, NULL, 0); | ||
713 | break; | ||
714 | } | ||
715 | } | ||
716 | |||
717 | if (cfg_only_rx && cfg_only_tx) | ||
718 | error(1, 0, "options: cannot combine rx-only and tx-only"); | ||
719 | |||
720 | if (cfg_encap_proto && cfg_l3_outer == AF_UNSPEC) | ||
721 | error(1, 0, "options: must specify outer with encap"); | ||
722 | else if ((!cfg_encap_proto) && cfg_l3_outer != AF_UNSPEC) | ||
723 | error(1, 0, "options: cannot combine no-encap and outer"); | ||
724 | else if ((!cfg_encap_proto) && cfg_l3_extra != AF_UNSPEC) | ||
725 | error(1, 0, "options: cannot combine no-encap and extra"); | ||
726 | |||
727 | if (cfg_l3_inner == AF_UNSPEC) | ||
728 | cfg_l3_inner = AF_INET6; | ||
729 | if (cfg_l3_inner == AF_INET6 && cfg_encap_proto == IPPROTO_IPIP) | ||
730 | cfg_encap_proto = IPPROTO_IPV6; | ||
731 | |||
732 | /* RFC 6040 4.2: | ||
733 | * on decap, if outer encountered congestion (CE == 0x3), | ||
734 | * but inner cannot encode ECN (NoECT == 0x0), then drop packet. | ||
735 | */ | ||
736 | if (((cfg_dsfield_outer & 0x3) == 0x3) && | ||
737 | ((cfg_dsfield_inner & 0x3) == 0x0)) | ||
738 | cfg_expect_failure = true; | ||
739 | } | ||
740 | |||
741 | static void print_opts(void) | ||
742 | { | ||
743 | if (cfg_l3_inner == PF_INET6) { | ||
744 | util_printaddr("inner.dest6", (void *) &in_daddr6); | ||
745 | util_printaddr("inner.source6", (void *) &in_saddr6); | ||
746 | } else { | ||
747 | util_printaddr("inner.dest4", (void *) &in_daddr4); | ||
748 | util_printaddr("inner.source4", (void *) &in_saddr4); | ||
749 | } | ||
750 | |||
751 | if (!cfg_l3_outer) | ||
752 | return; | ||
753 | |||
754 | fprintf(stderr, "encap proto: %u\n", cfg_encap_proto); | ||
755 | |||
756 | if (cfg_l3_outer == PF_INET6) { | ||
757 | util_printaddr("outer.dest6", (void *) &out_daddr6); | ||
758 | util_printaddr("outer.source6", (void *) &out_saddr6); | ||
759 | } else { | ||
760 | util_printaddr("outer.dest4", (void *) &out_daddr4); | ||
761 | util_printaddr("outer.source4", (void *) &out_saddr4); | ||
762 | } | ||
763 | |||
764 | if (!cfg_l3_extra) | ||
765 | return; | ||
766 | |||
767 | if (cfg_l3_outer == PF_INET6) { | ||
768 | util_printaddr("extra.dest6", (void *) &extra_daddr6); | ||
769 | util_printaddr("extra.source6", (void *) &extra_saddr6); | ||
770 | } else { | ||
771 | util_printaddr("extra.dest4", (void *) &extra_daddr4); | ||
772 | util_printaddr("extra.source4", (void *) &extra_saddr4); | ||
773 | } | ||
774 | |||
775 | } | ||
776 | |||
777 | int main(int argc, char **argv) | ||
778 | { | ||
779 | parse_opts(argc, argv); | ||
780 | print_opts(); | ||
781 | return do_main(); | ||
782 | } | ||
diff --git a/tools/testing/selftests/bpf/test_flow_dissector.sh b/tools/testing/selftests/bpf/test_flow_dissector.sh new file mode 100755 index 000000000000..c0fb073b5eab --- /dev/null +++ b/tools/testing/selftests/bpf/test_flow_dissector.sh | |||
@@ -0,0 +1,115 @@ | |||
1 | #!/bin/bash | ||
2 | # SPDX-License-Identifier: GPL-2.0 | ||
3 | # | ||
4 | # Load BPF flow dissector and verify it correctly dissects traffic | ||
5 | export TESTNAME=test_flow_dissector | ||
6 | unmount=0 | ||
7 | |||
8 | # Kselftest framework requirement - SKIP code is 4. | ||
9 | ksft_skip=4 | ||
10 | |||
11 | msg="skip all tests:" | ||
12 | if [ $UID != 0 ]; then | ||
13 | echo $msg please run this as root >&2 | ||
14 | exit $ksft_skip | ||
15 | fi | ||
16 | |||
17 | # This test needs to be run in a network namespace with in_netns.sh. Check if | ||
18 | # this is the case and run it with in_netns.sh if it is being run in the root | ||
19 | # namespace. | ||
20 | if [[ -z $(ip netns identify $$) ]]; then | ||
21 | ../net/in_netns.sh "$0" "$@" | ||
22 | exit $? | ||
23 | fi | ||
24 | |||
25 | # Determine selftest success via shell exit code | ||
26 | exit_handler() | ||
27 | { | ||
28 | if (( $? == 0 )); then | ||
29 | echo "selftests: $TESTNAME [PASS]"; | ||
30 | else | ||
31 | echo "selftests: $TESTNAME [FAILED]"; | ||
32 | fi | ||
33 | |||
34 | set +e | ||
35 | |||
36 | # Cleanup | ||
37 | tc filter del dev lo ingress pref 1337 2> /dev/null | ||
38 | tc qdisc del dev lo ingress 2> /dev/null | ||
39 | ./flow_dissector_load -d 2> /dev/null | ||
40 | if [ $unmount -ne 0 ]; then | ||
41 | umount bpffs 2> /dev/null | ||
42 | fi | ||
43 | } | ||
44 | |||
45 | # Exit script immediately (well catched by trap handler) if any | ||
46 | # program/thing exits with a non-zero status. | ||
47 | set -e | ||
48 | |||
49 | # (Use 'trap -l' to list meaning of numbers) | ||
50 | trap exit_handler 0 2 3 6 9 | ||
51 | |||
52 | # Mount BPF file system | ||
53 | if /bin/mount | grep /sys/fs/bpf > /dev/null; then | ||
54 | echo "bpffs already mounted" | ||
55 | else | ||
56 | echo "bpffs not mounted. Mounting..." | ||
57 | unmount=1 | ||
58 | /bin/mount bpffs /sys/fs/bpf -t bpf | ||
59 | fi | ||
60 | |||
61 | # Attach BPF program | ||
62 | ./flow_dissector_load -p bpf_flow.o -s dissect | ||
63 | |||
64 | # Setup | ||
65 | tc qdisc add dev lo ingress | ||
66 | |||
67 | echo "Testing IPv4..." | ||
68 | # Drops all IP/UDP packets coming from port 9 | ||
69 | tc filter add dev lo parent ffff: protocol ip pref 1337 flower ip_proto \ | ||
70 | udp src_port 9 action drop | ||
71 | |||
72 | # Send 10 IPv4/UDP packets from port 8. Filter should not drop any. | ||
73 | ./test_flow_dissector -i 4 -f 8 | ||
74 | # Send 10 IPv4/UDP packets from port 9. Filter should drop all. | ||
75 | ./test_flow_dissector -i 4 -f 9 -F | ||
76 | # Send 10 IPv4/UDP packets from port 10. Filter should not drop any. | ||
77 | ./test_flow_dissector -i 4 -f 10 | ||
78 | |||
79 | echo "Testing IPIP..." | ||
80 | # Send 10 IPv4/IPv4/UDP packets from port 8. Filter should not drop any. | ||
81 | ./with_addr.sh ./with_tunnels.sh ./test_flow_dissector -o 4 -e bare -i 4 \ | ||
82 | -D 192.168.0.1 -S 1.1.1.1 -f 8 | ||
83 | # Send 10 IPv4/IPv4/UDP packets from port 9. Filter should drop all. | ||
84 | ./with_addr.sh ./with_tunnels.sh ./test_flow_dissector -o 4 -e bare -i 4 \ | ||
85 | -D 192.168.0.1 -S 1.1.1.1 -f 9 -F | ||
86 | # Send 10 IPv4/IPv4/UDP packets from port 10. Filter should not drop any. | ||
87 | ./with_addr.sh ./with_tunnels.sh ./test_flow_dissector -o 4 -e bare -i 4 \ | ||
88 | -D 192.168.0.1 -S 1.1.1.1 -f 10 | ||
89 | |||
90 | echo "Testing IPv4 + GRE..." | ||
91 | # Send 10 IPv4/GRE/IPv4/UDP packets from port 8. Filter should not drop any. | ||
92 | ./with_addr.sh ./with_tunnels.sh ./test_flow_dissector -o 4 -e gre -i 4 \ | ||
93 | -D 192.168.0.1 -S 1.1.1.1 -f 8 | ||
94 | # Send 10 IPv4/GRE/IPv4/UDP packets from port 9. Filter should drop all. | ||
95 | ./with_addr.sh ./with_tunnels.sh ./test_flow_dissector -o 4 -e gre -i 4 \ | ||
96 | -D 192.168.0.1 -S 1.1.1.1 -f 9 -F | ||
97 | # Send 10 IPv4/GRE/IPv4/UDP packets from port 10. Filter should not drop any. | ||
98 | ./with_addr.sh ./with_tunnels.sh ./test_flow_dissector -o 4 -e gre -i 4 \ | ||
99 | -D 192.168.0.1 -S 1.1.1.1 -f 10 | ||
100 | |||
101 | tc filter del dev lo ingress pref 1337 | ||
102 | |||
103 | echo "Testing IPv6..." | ||
104 | # Drops all IPv6/UDP packets coming from port 9 | ||
105 | tc filter add dev lo parent ffff: protocol ipv6 pref 1337 flower ip_proto \ | ||
106 | udp src_port 9 action drop | ||
107 | |||
108 | # Send 10 IPv6/UDP packets from port 8. Filter should not drop any. | ||
109 | ./test_flow_dissector -i 6 -f 8 | ||
110 | # Send 10 IPv6/UDP packets from port 9. Filter should drop all. | ||
111 | ./test_flow_dissector -i 6 -f 9 -F | ||
112 | # Send 10 IPv6/UDP packets from port 10. Filter should not drop any. | ||
113 | ./test_flow_dissector -i 6 -f 10 | ||
114 | |||
115 | exit 0 | ||
diff --git a/tools/testing/selftests/bpf/test_libbpf.sh b/tools/testing/selftests/bpf/test_libbpf.sh index d97dc914cd49..156d89f1edcc 100755 --- a/tools/testing/selftests/bpf/test_libbpf.sh +++ b/tools/testing/selftests/bpf/test_libbpf.sh | |||
@@ -6,7 +6,7 @@ export TESTNAME=test_libbpf | |||
6 | # Determine selftest success via shell exit code | 6 | # Determine selftest success via shell exit code |
7 | exit_handler() | 7 | exit_handler() |
8 | { | 8 | { |
9 | if (( $? == 0 )); then | 9 | if [ $? -eq 0 ]; then |
10 | echo "selftests: $TESTNAME [PASS]"; | 10 | echo "selftests: $TESTNAME [PASS]"; |
11 | else | 11 | else |
12 | echo "$TESTNAME: failed at file $LAST_LOADED" 1>&2 | 12 | echo "$TESTNAME: failed at file $LAST_LOADED" 1>&2 |
diff --git a/tools/testing/selftests/bpf/test_maps.c b/tools/testing/selftests/bpf/test_maps.c index 9b552c0fc47d..4db2116e52be 100644 --- a/tools/testing/selftests/bpf/test_maps.c +++ b/tools/testing/selftests/bpf/test_maps.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <string.h> | 15 | #include <string.h> |
16 | #include <assert.h> | 16 | #include <assert.h> |
17 | #include <stdlib.h> | 17 | #include <stdlib.h> |
18 | #include <time.h> | ||
18 | 19 | ||
19 | #include <sys/wait.h> | 20 | #include <sys/wait.h> |
20 | #include <sys/socket.h> | 21 | #include <sys/socket.h> |
@@ -471,6 +472,122 @@ static void test_devmap(int task, void *data) | |||
471 | close(fd); | 472 | close(fd); |
472 | } | 473 | } |
473 | 474 | ||
475 | static void test_queuemap(int task, void *data) | ||
476 | { | ||
477 | const int MAP_SIZE = 32; | ||
478 | __u32 vals[MAP_SIZE + MAP_SIZE/2], val; | ||
479 | int fd, i; | ||
480 | |||
481 | /* Fill test values to be used */ | ||
482 | for (i = 0; i < MAP_SIZE + MAP_SIZE/2; i++) | ||
483 | vals[i] = rand(); | ||
484 | |||
485 | /* Invalid key size */ | ||
486 | fd = bpf_create_map(BPF_MAP_TYPE_QUEUE, 4, sizeof(val), MAP_SIZE, | ||
487 | map_flags); | ||
488 | assert(fd < 0 && errno == EINVAL); | ||
489 | |||
490 | fd = bpf_create_map(BPF_MAP_TYPE_QUEUE, 0, sizeof(val), MAP_SIZE, | ||
491 | map_flags); | ||
492 | /* Queue map does not support BPF_F_NO_PREALLOC */ | ||
493 | if (map_flags & BPF_F_NO_PREALLOC) { | ||
494 | assert(fd < 0 && errno == EINVAL); | ||
495 | return; | ||
496 | } | ||
497 | if (fd < 0) { | ||
498 | printf("Failed to create queuemap '%s'!\n", strerror(errno)); | ||
499 | exit(1); | ||
500 | } | ||
501 | |||
502 | /* Push MAP_SIZE elements */ | ||
503 | for (i = 0; i < MAP_SIZE; i++) | ||
504 | assert(bpf_map_update_elem(fd, NULL, &vals[i], 0) == 0); | ||
505 | |||
506 | /* Check that element cannot be pushed due to max_entries limit */ | ||
507 | assert(bpf_map_update_elem(fd, NULL, &val, 0) == -1 && | ||
508 | errno == E2BIG); | ||
509 | |||
510 | /* Peek element */ | ||
511 | assert(bpf_map_lookup_elem(fd, NULL, &val) == 0 && val == vals[0]); | ||
512 | |||
513 | /* Replace half elements */ | ||
514 | for (i = MAP_SIZE; i < MAP_SIZE + MAP_SIZE/2; i++) | ||
515 | assert(bpf_map_update_elem(fd, NULL, &vals[i], BPF_EXIST) == 0); | ||
516 | |||
517 | /* Pop all elements */ | ||
518 | for (i = MAP_SIZE/2; i < MAP_SIZE + MAP_SIZE/2; i++) | ||
519 | assert(bpf_map_lookup_and_delete_elem(fd, NULL, &val) == 0 && | ||
520 | val == vals[i]); | ||
521 | |||
522 | /* Check that there are not elements left */ | ||
523 | assert(bpf_map_lookup_and_delete_elem(fd, NULL, &val) == -1 && | ||
524 | errno == ENOENT); | ||
525 | |||
526 | /* Check that non supported functions set errno to EINVAL */ | ||
527 | assert(bpf_map_delete_elem(fd, NULL) == -1 && errno == EINVAL); | ||
528 | assert(bpf_map_get_next_key(fd, NULL, NULL) == -1 && errno == EINVAL); | ||
529 | |||
530 | close(fd); | ||
531 | } | ||
532 | |||
533 | static void test_stackmap(int task, void *data) | ||
534 | { | ||
535 | const int MAP_SIZE = 32; | ||
536 | __u32 vals[MAP_SIZE + MAP_SIZE/2], val; | ||
537 | int fd, i; | ||
538 | |||
539 | /* Fill test values to be used */ | ||
540 | for (i = 0; i < MAP_SIZE + MAP_SIZE/2; i++) | ||
541 | vals[i] = rand(); | ||
542 | |||
543 | /* Invalid key size */ | ||
544 | fd = bpf_create_map(BPF_MAP_TYPE_STACK, 4, sizeof(val), MAP_SIZE, | ||
545 | map_flags); | ||
546 | assert(fd < 0 && errno == EINVAL); | ||
547 | |||
548 | fd = bpf_create_map(BPF_MAP_TYPE_STACK, 0, sizeof(val), MAP_SIZE, | ||
549 | map_flags); | ||
550 | /* Stack map does not support BPF_F_NO_PREALLOC */ | ||
551 | if (map_flags & BPF_F_NO_PREALLOC) { | ||
552 | assert(fd < 0 && errno == EINVAL); | ||
553 | return; | ||
554 | } | ||
555 | if (fd < 0) { | ||
556 | printf("Failed to create stackmap '%s'!\n", strerror(errno)); | ||
557 | exit(1); | ||
558 | } | ||
559 | |||
560 | /* Push MAP_SIZE elements */ | ||
561 | for (i = 0; i < MAP_SIZE; i++) | ||
562 | assert(bpf_map_update_elem(fd, NULL, &vals[i], 0) == 0); | ||
563 | |||
564 | /* Check that element cannot be pushed due to max_entries limit */ | ||
565 | assert(bpf_map_update_elem(fd, NULL, &val, 0) == -1 && | ||
566 | errno == E2BIG); | ||
567 | |||
568 | /* Peek element */ | ||
569 | assert(bpf_map_lookup_elem(fd, NULL, &val) == 0 && val == vals[i - 1]); | ||
570 | |||
571 | /* Replace half elements */ | ||
572 | for (i = MAP_SIZE; i < MAP_SIZE + MAP_SIZE/2; i++) | ||
573 | assert(bpf_map_update_elem(fd, NULL, &vals[i], BPF_EXIST) == 0); | ||
574 | |||
575 | /* Pop all elements */ | ||
576 | for (i = MAP_SIZE + MAP_SIZE/2 - 1; i >= MAP_SIZE/2; i--) | ||
577 | assert(bpf_map_lookup_and_delete_elem(fd, NULL, &val) == 0 && | ||
578 | val == vals[i]); | ||
579 | |||
580 | /* Check that there are not elements left */ | ||
581 | assert(bpf_map_lookup_and_delete_elem(fd, NULL, &val) == -1 && | ||
582 | errno == ENOENT); | ||
583 | |||
584 | /* Check that non supported functions set errno to EINVAL */ | ||
585 | assert(bpf_map_delete_elem(fd, NULL) == -1 && errno == EINVAL); | ||
586 | assert(bpf_map_get_next_key(fd, NULL, NULL) == -1 && errno == EINVAL); | ||
587 | |||
588 | close(fd); | ||
589 | } | ||
590 | |||
474 | #include <sys/socket.h> | 591 | #include <sys/socket.h> |
475 | #include <sys/ioctl.h> | 592 | #include <sys/ioctl.h> |
476 | #include <arpa/inet.h> | 593 | #include <arpa/inet.h> |
@@ -1434,10 +1551,15 @@ static void run_all_tests(void) | |||
1434 | test_map_wronly(); | 1551 | test_map_wronly(); |
1435 | 1552 | ||
1436 | test_reuseport_array(); | 1553 | test_reuseport_array(); |
1554 | |||
1555 | test_queuemap(0, NULL); | ||
1556 | test_stackmap(0, NULL); | ||
1437 | } | 1557 | } |
1438 | 1558 | ||
1439 | int main(void) | 1559 | int main(void) |
1440 | { | 1560 | { |
1561 | srand(time(NULL)); | ||
1562 | |||
1441 | map_flags = 0; | 1563 | map_flags = 0; |
1442 | run_all_tests(); | 1564 | run_all_tests(); |
1443 | 1565 | ||
diff --git a/tools/testing/selftests/bpf/test_netcnt.c b/tools/testing/selftests/bpf/test_netcnt.c new file mode 100644 index 000000000000..7887df693399 --- /dev/null +++ b/tools/testing/selftests/bpf/test_netcnt.c | |||
@@ -0,0 +1,158 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | #include <stdio.h> | ||
3 | #include <stdlib.h> | ||
4 | #include <string.h> | ||
5 | #include <errno.h> | ||
6 | #include <assert.h> | ||
7 | #include <sys/sysinfo.h> | ||
8 | #include <sys/time.h> | ||
9 | |||
10 | #include <linux/bpf.h> | ||
11 | #include <bpf/bpf.h> | ||
12 | #include <bpf/libbpf.h> | ||
13 | |||
14 | #include "cgroup_helpers.h" | ||
15 | #include "bpf_rlimit.h" | ||
16 | #include "netcnt_common.h" | ||
17 | |||
18 | #define BPF_PROG "./netcnt_prog.o" | ||
19 | #define TEST_CGROUP "/test-network-counters/" | ||
20 | |||
21 | static int bpf_find_map(const char *test, struct bpf_object *obj, | ||
22 | const char *name) | ||
23 | { | ||
24 | struct bpf_map *map; | ||
25 | |||
26 | map = bpf_object__find_map_by_name(obj, name); | ||
27 | if (!map) { | ||
28 | printf("%s:FAIL:map '%s' not found\n", test, name); | ||
29 | return -1; | ||
30 | } | ||
31 | return bpf_map__fd(map); | ||
32 | } | ||
33 | |||
34 | int main(int argc, char **argv) | ||
35 | { | ||
36 | struct percpu_net_cnt *percpu_netcnt; | ||
37 | struct bpf_cgroup_storage_key key; | ||
38 | int map_fd, percpu_map_fd; | ||
39 | int error = EXIT_FAILURE; | ||
40 | struct net_cnt netcnt; | ||
41 | struct bpf_object *obj; | ||
42 | int prog_fd, cgroup_fd; | ||
43 | unsigned long packets; | ||
44 | unsigned long bytes; | ||
45 | int cpu, nproc; | ||
46 | __u32 prog_cnt; | ||
47 | |||
48 | nproc = get_nprocs_conf(); | ||
49 | percpu_netcnt = malloc(sizeof(*percpu_netcnt) * nproc); | ||
50 | if (!percpu_netcnt) { | ||
51 | printf("Not enough memory for per-cpu area (%d cpus)\n", nproc); | ||
52 | goto err; | ||
53 | } | ||
54 | |||
55 | if (bpf_prog_load(BPF_PROG, BPF_PROG_TYPE_CGROUP_SKB, | ||
56 | &obj, &prog_fd)) { | ||
57 | printf("Failed to load bpf program\n"); | ||
58 | goto out; | ||
59 | } | ||
60 | |||
61 | if (setup_cgroup_environment()) { | ||
62 | printf("Failed to load bpf program\n"); | ||
63 | goto err; | ||
64 | } | ||
65 | |||
66 | /* Create a cgroup, get fd, and join it */ | ||
67 | cgroup_fd = create_and_get_cgroup(TEST_CGROUP); | ||
68 | if (!cgroup_fd) { | ||
69 | printf("Failed to create test cgroup\n"); | ||
70 | goto err; | ||
71 | } | ||
72 | |||
73 | if (join_cgroup(TEST_CGROUP)) { | ||
74 | printf("Failed to join cgroup\n"); | ||
75 | goto err; | ||
76 | } | ||
77 | |||
78 | /* Attach bpf program */ | ||
79 | if (bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_INET_EGRESS, 0)) { | ||
80 | printf("Failed to attach bpf program"); | ||
81 | goto err; | ||
82 | } | ||
83 | |||
84 | assert(system("ping localhost -6 -c 10000 -f -q > /dev/null") == 0); | ||
85 | |||
86 | if (bpf_prog_query(cgroup_fd, BPF_CGROUP_INET_EGRESS, 0, NULL, NULL, | ||
87 | &prog_cnt)) { | ||
88 | printf("Failed to query attached programs"); | ||
89 | goto err; | ||
90 | } | ||
91 | |||
92 | map_fd = bpf_find_map(__func__, obj, "netcnt"); | ||
93 | if (map_fd < 0) { | ||
94 | printf("Failed to find bpf map with net counters"); | ||
95 | goto err; | ||
96 | } | ||
97 | |||
98 | percpu_map_fd = bpf_find_map(__func__, obj, "percpu_netcnt"); | ||
99 | if (percpu_map_fd < 0) { | ||
100 | printf("Failed to find bpf map with percpu net counters"); | ||
101 | goto err; | ||
102 | } | ||
103 | |||
104 | if (bpf_map_get_next_key(map_fd, NULL, &key)) { | ||
105 | printf("Failed to get key in cgroup storage\n"); | ||
106 | goto err; | ||
107 | } | ||
108 | |||
109 | if (bpf_map_lookup_elem(map_fd, &key, &netcnt)) { | ||
110 | printf("Failed to lookup cgroup storage\n"); | ||
111 | goto err; | ||
112 | } | ||
113 | |||
114 | if (bpf_map_lookup_elem(percpu_map_fd, &key, &percpu_netcnt[0])) { | ||
115 | printf("Failed to lookup percpu cgroup storage\n"); | ||
116 | goto err; | ||
117 | } | ||
118 | |||
119 | /* Some packets can be still in per-cpu cache, but not more than | ||
120 | * MAX_PERCPU_PACKETS. | ||
121 | */ | ||
122 | packets = netcnt.packets; | ||
123 | bytes = netcnt.bytes; | ||
124 | for (cpu = 0; cpu < nproc; cpu++) { | ||
125 | if (percpu_netcnt[cpu].packets > MAX_PERCPU_PACKETS) { | ||
126 | printf("Unexpected percpu value: %llu\n", | ||
127 | percpu_netcnt[cpu].packets); | ||
128 | goto err; | ||
129 | } | ||
130 | |||
131 | packets += percpu_netcnt[cpu].packets; | ||
132 | bytes += percpu_netcnt[cpu].bytes; | ||
133 | } | ||
134 | |||
135 | /* No packets should be lost */ | ||
136 | if (packets != 10000) { | ||
137 | printf("Unexpected packet count: %lu\n", packets); | ||
138 | goto err; | ||
139 | } | ||
140 | |||
141 | /* Let's check that bytes counter matches the number of packets | ||
142 | * multiplied by the size of ipv6 ICMP packet. | ||
143 | */ | ||
144 | if (bytes != packets * 104) { | ||
145 | printf("Unexpected bytes count: %lu\n", bytes); | ||
146 | goto err; | ||
147 | } | ||
148 | |||
149 | error = 0; | ||
150 | printf("test_netcnt:PASS\n"); | ||
151 | |||
152 | err: | ||
153 | cleanup_cgroup_environment(); | ||
154 | free(percpu_netcnt); | ||
155 | |||
156 | out: | ||
157 | return error; | ||
158 | } | ||
diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c index 0ef68204c84b..2d3c04f45530 100644 --- a/tools/testing/selftests/bpf/test_progs.c +++ b/tools/testing/selftests/bpf/test_progs.c | |||
@@ -112,13 +112,13 @@ static void test_pkt_access(void) | |||
112 | 112 | ||
113 | err = bpf_prog_test_run(prog_fd, 100000, &pkt_v4, sizeof(pkt_v4), | 113 | err = bpf_prog_test_run(prog_fd, 100000, &pkt_v4, sizeof(pkt_v4), |
114 | NULL, NULL, &retval, &duration); | 114 | NULL, NULL, &retval, &duration); |
115 | CHECK(err || errno || retval, "ipv4", | 115 | CHECK(err || retval, "ipv4", |
116 | "err %d errno %d retval %d duration %d\n", | 116 | "err %d errno %d retval %d duration %d\n", |
117 | err, errno, retval, duration); | 117 | err, errno, retval, duration); |
118 | 118 | ||
119 | err = bpf_prog_test_run(prog_fd, 100000, &pkt_v6, sizeof(pkt_v6), | 119 | err = bpf_prog_test_run(prog_fd, 100000, &pkt_v6, sizeof(pkt_v6), |
120 | NULL, NULL, &retval, &duration); | 120 | NULL, NULL, &retval, &duration); |
121 | CHECK(err || errno || retval, "ipv6", | 121 | CHECK(err || retval, "ipv6", |
122 | "err %d errno %d retval %d duration %d\n", | 122 | "err %d errno %d retval %d duration %d\n", |
123 | err, errno, retval, duration); | 123 | err, errno, retval, duration); |
124 | bpf_object__close(obj); | 124 | bpf_object__close(obj); |
@@ -153,14 +153,14 @@ static void test_xdp(void) | |||
153 | err = bpf_prog_test_run(prog_fd, 1, &pkt_v4, sizeof(pkt_v4), | 153 | err = bpf_prog_test_run(prog_fd, 1, &pkt_v4, sizeof(pkt_v4), |
154 | buf, &size, &retval, &duration); | 154 | buf, &size, &retval, &duration); |
155 | 155 | ||
156 | CHECK(err || errno || retval != XDP_TX || size != 74 || | 156 | CHECK(err || retval != XDP_TX || size != 74 || |
157 | iph->protocol != IPPROTO_IPIP, "ipv4", | 157 | iph->protocol != IPPROTO_IPIP, "ipv4", |
158 | "err %d errno %d retval %d size %d\n", | 158 | "err %d errno %d retval %d size %d\n", |
159 | err, errno, retval, size); | 159 | err, errno, retval, size); |
160 | 160 | ||
161 | err = bpf_prog_test_run(prog_fd, 1, &pkt_v6, sizeof(pkt_v6), | 161 | err = bpf_prog_test_run(prog_fd, 1, &pkt_v6, sizeof(pkt_v6), |
162 | buf, &size, &retval, &duration); | 162 | buf, &size, &retval, &duration); |
163 | CHECK(err || errno || retval != XDP_TX || size != 114 || | 163 | CHECK(err || retval != XDP_TX || size != 114 || |
164 | iph6->nexthdr != IPPROTO_IPV6, "ipv6", | 164 | iph6->nexthdr != IPPROTO_IPV6, "ipv6", |
165 | "err %d errno %d retval %d size %d\n", | 165 | "err %d errno %d retval %d size %d\n", |
166 | err, errno, retval, size); | 166 | err, errno, retval, size); |
@@ -185,13 +185,13 @@ static void test_xdp_adjust_tail(void) | |||
185 | err = bpf_prog_test_run(prog_fd, 1, &pkt_v4, sizeof(pkt_v4), | 185 | err = bpf_prog_test_run(prog_fd, 1, &pkt_v4, sizeof(pkt_v4), |
186 | buf, &size, &retval, &duration); | 186 | buf, &size, &retval, &duration); |
187 | 187 | ||
188 | CHECK(err || errno || retval != XDP_DROP, | 188 | CHECK(err || retval != XDP_DROP, |
189 | "ipv4", "err %d errno %d retval %d size %d\n", | 189 | "ipv4", "err %d errno %d retval %d size %d\n", |
190 | err, errno, retval, size); | 190 | err, errno, retval, size); |
191 | 191 | ||
192 | err = bpf_prog_test_run(prog_fd, 1, &pkt_v6, sizeof(pkt_v6), | 192 | err = bpf_prog_test_run(prog_fd, 1, &pkt_v6, sizeof(pkt_v6), |
193 | buf, &size, &retval, &duration); | 193 | buf, &size, &retval, &duration); |
194 | CHECK(err || errno || retval != XDP_TX || size != 54, | 194 | CHECK(err || retval != XDP_TX || size != 54, |
195 | "ipv6", "err %d errno %d retval %d size %d\n", | 195 | "ipv6", "err %d errno %d retval %d size %d\n", |
196 | err, errno, retval, size); | 196 | err, errno, retval, size); |
197 | bpf_object__close(obj); | 197 | bpf_object__close(obj); |
@@ -254,14 +254,14 @@ static void test_l4lb(const char *file) | |||
254 | 254 | ||
255 | err = bpf_prog_test_run(prog_fd, NUM_ITER, &pkt_v4, sizeof(pkt_v4), | 255 | err = bpf_prog_test_run(prog_fd, NUM_ITER, &pkt_v4, sizeof(pkt_v4), |
256 | buf, &size, &retval, &duration); | 256 | buf, &size, &retval, &duration); |
257 | CHECK(err || errno || retval != 7/*TC_ACT_REDIRECT*/ || size != 54 || | 257 | CHECK(err || retval != 7/*TC_ACT_REDIRECT*/ || size != 54 || |
258 | *magic != MAGIC_VAL, "ipv4", | 258 | *magic != MAGIC_VAL, "ipv4", |
259 | "err %d errno %d retval %d size %d magic %x\n", | 259 | "err %d errno %d retval %d size %d magic %x\n", |
260 | err, errno, retval, size, *magic); | 260 | err, errno, retval, size, *magic); |
261 | 261 | ||
262 | err = bpf_prog_test_run(prog_fd, NUM_ITER, &pkt_v6, sizeof(pkt_v6), | 262 | err = bpf_prog_test_run(prog_fd, NUM_ITER, &pkt_v6, sizeof(pkt_v6), |
263 | buf, &size, &retval, &duration); | 263 | buf, &size, &retval, &duration); |
264 | CHECK(err || errno || retval != 7/*TC_ACT_REDIRECT*/ || size != 74 || | 264 | CHECK(err || retval != 7/*TC_ACT_REDIRECT*/ || size != 74 || |
265 | *magic != MAGIC_VAL, "ipv6", | 265 | *magic != MAGIC_VAL, "ipv6", |
266 | "err %d errno %d retval %d size %d magic %x\n", | 266 | "err %d errno %d retval %d size %d magic %x\n", |
267 | err, errno, retval, size, *magic); | 267 | err, errno, retval, size, *magic); |
@@ -343,14 +343,14 @@ static void test_xdp_noinline(void) | |||
343 | 343 | ||
344 | err = bpf_prog_test_run(prog_fd, NUM_ITER, &pkt_v4, sizeof(pkt_v4), | 344 | err = bpf_prog_test_run(prog_fd, NUM_ITER, &pkt_v4, sizeof(pkt_v4), |
345 | buf, &size, &retval, &duration); | 345 | buf, &size, &retval, &duration); |
346 | CHECK(err || errno || retval != 1 || size != 54 || | 346 | CHECK(err || retval != 1 || size != 54 || |
347 | *magic != MAGIC_VAL, "ipv4", | 347 | *magic != MAGIC_VAL, "ipv4", |
348 | "err %d errno %d retval %d size %d magic %x\n", | 348 | "err %d errno %d retval %d size %d magic %x\n", |
349 | err, errno, retval, size, *magic); | 349 | err, errno, retval, size, *magic); |
350 | 350 | ||
351 | err = bpf_prog_test_run(prog_fd, NUM_ITER, &pkt_v6, sizeof(pkt_v6), | 351 | err = bpf_prog_test_run(prog_fd, NUM_ITER, &pkt_v6, sizeof(pkt_v6), |
352 | buf, &size, &retval, &duration); | 352 | buf, &size, &retval, &duration); |
353 | CHECK(err || errno || retval != 1 || size != 74 || | 353 | CHECK(err || retval != 1 || size != 74 || |
354 | *magic != MAGIC_VAL, "ipv6", | 354 | *magic != MAGIC_VAL, "ipv6", |
355 | "err %d errno %d retval %d size %d magic %x\n", | 355 | "err %d errno %d retval %d size %d magic %x\n", |
356 | err, errno, retval, size, *magic); | 356 | err, errno, retval, size, *magic); |
@@ -1698,8 +1698,142 @@ static void test_task_fd_query_tp(void) | |||
1698 | "sys_enter_read"); | 1698 | "sys_enter_read"); |
1699 | } | 1699 | } |
1700 | 1700 | ||
1701 | static void test_reference_tracking() | ||
1702 | { | ||
1703 | const char *file = "./test_sk_lookup_kern.o"; | ||
1704 | struct bpf_object *obj; | ||
1705 | struct bpf_program *prog; | ||
1706 | __u32 duration; | ||
1707 | int err = 0; | ||
1708 | |||
1709 | obj = bpf_object__open(file); | ||
1710 | if (IS_ERR(obj)) { | ||
1711 | error_cnt++; | ||
1712 | return; | ||
1713 | } | ||
1714 | |||
1715 | bpf_object__for_each_program(prog, obj) { | ||
1716 | const char *title; | ||
1717 | |||
1718 | /* Ignore .text sections */ | ||
1719 | title = bpf_program__title(prog, false); | ||
1720 | if (strstr(title, ".text") != NULL) | ||
1721 | continue; | ||
1722 | |||
1723 | bpf_program__set_type(prog, BPF_PROG_TYPE_SCHED_CLS); | ||
1724 | |||
1725 | /* Expect verifier failure if test name has 'fail' */ | ||
1726 | if (strstr(title, "fail") != NULL) { | ||
1727 | libbpf_set_print(NULL, NULL, NULL); | ||
1728 | err = !bpf_program__load(prog, "GPL", 0); | ||
1729 | libbpf_set_print(printf, printf, NULL); | ||
1730 | } else { | ||
1731 | err = bpf_program__load(prog, "GPL", 0); | ||
1732 | } | ||
1733 | CHECK(err, title, "\n"); | ||
1734 | } | ||
1735 | bpf_object__close(obj); | ||
1736 | } | ||
1737 | |||
1738 | enum { | ||
1739 | QUEUE, | ||
1740 | STACK, | ||
1741 | }; | ||
1742 | |||
1743 | static void test_queue_stack_map(int type) | ||
1744 | { | ||
1745 | const int MAP_SIZE = 32; | ||
1746 | __u32 vals[MAP_SIZE], duration, retval, size, val; | ||
1747 | int i, err, prog_fd, map_in_fd, map_out_fd; | ||
1748 | char file[32], buf[128]; | ||
1749 | struct bpf_object *obj; | ||
1750 | struct iphdr *iph = (void *)buf + sizeof(struct ethhdr); | ||
1751 | |||
1752 | /* Fill test values to be used */ | ||
1753 | for (i = 0; i < MAP_SIZE; i++) | ||
1754 | vals[i] = rand(); | ||
1755 | |||
1756 | if (type == QUEUE) | ||
1757 | strncpy(file, "./test_queue_map.o", sizeof(file)); | ||
1758 | else if (type == STACK) | ||
1759 | strncpy(file, "./test_stack_map.o", sizeof(file)); | ||
1760 | else | ||
1761 | return; | ||
1762 | |||
1763 | err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd); | ||
1764 | if (err) { | ||
1765 | error_cnt++; | ||
1766 | return; | ||
1767 | } | ||
1768 | |||
1769 | map_in_fd = bpf_find_map(__func__, obj, "map_in"); | ||
1770 | if (map_in_fd < 0) | ||
1771 | goto out; | ||
1772 | |||
1773 | map_out_fd = bpf_find_map(__func__, obj, "map_out"); | ||
1774 | if (map_out_fd < 0) | ||
1775 | goto out; | ||
1776 | |||
1777 | /* Push 32 elements to the input map */ | ||
1778 | for (i = 0; i < MAP_SIZE; i++) { | ||
1779 | err = bpf_map_update_elem(map_in_fd, NULL, &vals[i], 0); | ||
1780 | if (err) { | ||
1781 | error_cnt++; | ||
1782 | goto out; | ||
1783 | } | ||
1784 | } | ||
1785 | |||
1786 | /* The eBPF program pushes iph.saddr in the output map, | ||
1787 | * pops the input map and saves this value in iph.daddr | ||
1788 | */ | ||
1789 | for (i = 0; i < MAP_SIZE; i++) { | ||
1790 | if (type == QUEUE) { | ||
1791 | val = vals[i]; | ||
1792 | pkt_v4.iph.saddr = vals[i] * 5; | ||
1793 | } else if (type == STACK) { | ||
1794 | val = vals[MAP_SIZE - 1 - i]; | ||
1795 | pkt_v4.iph.saddr = vals[MAP_SIZE - 1 - i] * 5; | ||
1796 | } | ||
1797 | |||
1798 | err = bpf_prog_test_run(prog_fd, 1, &pkt_v4, sizeof(pkt_v4), | ||
1799 | buf, &size, &retval, &duration); | ||
1800 | if (err || retval || size != sizeof(pkt_v4) || | ||
1801 | iph->daddr != val) | ||
1802 | break; | ||
1803 | } | ||
1804 | |||
1805 | CHECK(err || retval || size != sizeof(pkt_v4) || iph->daddr != val, | ||
1806 | "bpf_map_pop_elem", | ||
1807 | "err %d errno %d retval %d size %d iph->daddr %u\n", | ||
1808 | err, errno, retval, size, iph->daddr); | ||
1809 | |||
1810 | /* Queue is empty, program should return TC_ACT_SHOT */ | ||
1811 | err = bpf_prog_test_run(prog_fd, 1, &pkt_v4, sizeof(pkt_v4), | ||
1812 | buf, &size, &retval, &duration); | ||
1813 | CHECK(err || retval != 2 /* TC_ACT_SHOT */|| size != sizeof(pkt_v4), | ||
1814 | "check-queue-stack-map-empty", | ||
1815 | "err %d errno %d retval %d size %d\n", | ||
1816 | err, errno, retval, size); | ||
1817 | |||
1818 | /* Check that the program pushed elements correctly */ | ||
1819 | for (i = 0; i < MAP_SIZE; i++) { | ||
1820 | err = bpf_map_lookup_and_delete_elem(map_out_fd, NULL, &val); | ||
1821 | if (err || val != vals[i] * 5) | ||
1822 | break; | ||
1823 | } | ||
1824 | |||
1825 | CHECK(i != MAP_SIZE && (err || val != vals[i] * 5), | ||
1826 | "bpf_map_push_elem", "err %d value %u\n", err, val); | ||
1827 | |||
1828 | out: | ||
1829 | pkt_v4.iph.saddr = 0; | ||
1830 | bpf_object__close(obj); | ||
1831 | } | ||
1832 | |||
1701 | int main(void) | 1833 | int main(void) |
1702 | { | 1834 | { |
1835 | srand(time(NULL)); | ||
1836 | |||
1703 | jit_enabled = is_jit_enabled(); | 1837 | jit_enabled = is_jit_enabled(); |
1704 | 1838 | ||
1705 | test_pkt_access(); | 1839 | test_pkt_access(); |
@@ -1719,6 +1853,9 @@ int main(void) | |||
1719 | test_get_stack_raw_tp(); | 1853 | test_get_stack_raw_tp(); |
1720 | test_task_fd_query_rawtp(); | 1854 | test_task_fd_query_rawtp(); |
1721 | test_task_fd_query_tp(); | 1855 | test_task_fd_query_tp(); |
1856 | test_reference_tracking(); | ||
1857 | test_queue_stack_map(QUEUE); | ||
1858 | test_queue_stack_map(STACK); | ||
1722 | 1859 | ||
1723 | printf("Summary: %d PASSED, %d FAILED\n", pass_cnt, error_cnt); | 1860 | printf("Summary: %d PASSED, %d FAILED\n", pass_cnt, error_cnt); |
1724 | return error_cnt ? EXIT_FAILURE : EXIT_SUCCESS; | 1861 | return error_cnt ? EXIT_FAILURE : EXIT_SUCCESS; |
diff --git a/tools/testing/selftests/bpf/test_queue_map.c b/tools/testing/selftests/bpf/test_queue_map.c new file mode 100644 index 000000000000..87db1f9da33d --- /dev/null +++ b/tools/testing/selftests/bpf/test_queue_map.c | |||
@@ -0,0 +1,4 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | // Copyright (c) 2018 Politecnico di Torino | ||
3 | #define MAP_TYPE BPF_MAP_TYPE_QUEUE | ||
4 | #include "test_queue_stack_map.h" | ||
diff --git a/tools/testing/selftests/bpf/test_queue_stack_map.h b/tools/testing/selftests/bpf/test_queue_stack_map.h new file mode 100644 index 000000000000..295b9b3bc5c7 --- /dev/null +++ b/tools/testing/selftests/bpf/test_queue_stack_map.h | |||
@@ -0,0 +1,59 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | // Copyright (c) 2018 Politecnico di Torino | ||
3 | #include <stddef.h> | ||
4 | #include <string.h> | ||
5 | #include <linux/bpf.h> | ||
6 | #include <linux/if_ether.h> | ||
7 | #include <linux/ip.h> | ||
8 | #include <linux/pkt_cls.h> | ||
9 | #include "bpf_helpers.h" | ||
10 | |||
11 | int _version SEC("version") = 1; | ||
12 | |||
13 | struct bpf_map_def __attribute__ ((section("maps"), used)) map_in = { | ||
14 | .type = MAP_TYPE, | ||
15 | .key_size = 0, | ||
16 | .value_size = sizeof(__u32), | ||
17 | .max_entries = 32, | ||
18 | .map_flags = 0, | ||
19 | }; | ||
20 | |||
21 | struct bpf_map_def __attribute__ ((section("maps"), used)) map_out = { | ||
22 | .type = MAP_TYPE, | ||
23 | .key_size = 0, | ||
24 | .value_size = sizeof(__u32), | ||
25 | .max_entries = 32, | ||
26 | .map_flags = 0, | ||
27 | }; | ||
28 | |||
29 | SEC("test") | ||
30 | int _test(struct __sk_buff *skb) | ||
31 | { | ||
32 | void *data_end = (void *)(long)skb->data_end; | ||
33 | void *data = (void *)(long)skb->data; | ||
34 | struct ethhdr *eth = (struct ethhdr *)(data); | ||
35 | __u32 value; | ||
36 | int err; | ||
37 | |||
38 | if (eth + 1 > data_end) | ||
39 | return TC_ACT_SHOT; | ||
40 | |||
41 | struct iphdr *iph = (struct iphdr *)(eth + 1); | ||
42 | |||
43 | if (iph + 1 > data_end) | ||
44 | return TC_ACT_SHOT; | ||
45 | |||
46 | err = bpf_map_pop_elem(&map_in, &value); | ||
47 | if (err) | ||
48 | return TC_ACT_SHOT; | ||
49 | |||
50 | iph->daddr = value; | ||
51 | |||
52 | err = bpf_map_push_elem(&map_out, &iph->saddr, 0); | ||
53 | if (err) | ||
54 | return TC_ACT_SHOT; | ||
55 | |||
56 | return TC_ACT_OK; | ||
57 | } | ||
58 | |||
59 | char _license[] SEC("license") = "GPL"; | ||
diff --git a/tools/testing/selftests/bpf/test_section_names.c b/tools/testing/selftests/bpf/test_section_names.c new file mode 100644 index 000000000000..7c4f41572b1c --- /dev/null +++ b/tools/testing/selftests/bpf/test_section_names.c | |||
@@ -0,0 +1,208 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | // Copyright (c) 2018 Facebook | ||
3 | |||
4 | #include <err.h> | ||
5 | #include <bpf/libbpf.h> | ||
6 | |||
7 | #include "bpf_util.h" | ||
8 | |||
9 | struct sec_name_test { | ||
10 | const char sec_name[32]; | ||
11 | struct { | ||
12 | int rc; | ||
13 | enum bpf_prog_type prog_type; | ||
14 | enum bpf_attach_type expected_attach_type; | ||
15 | } expected_load; | ||
16 | struct { | ||
17 | int rc; | ||
18 | enum bpf_attach_type attach_type; | ||
19 | } expected_attach; | ||
20 | }; | ||
21 | |||
22 | static struct sec_name_test tests[] = { | ||
23 | {"InvAliD", {-EINVAL, 0, 0}, {-EINVAL, 0} }, | ||
24 | {"cgroup", {-EINVAL, 0, 0}, {-EINVAL, 0} }, | ||
25 | {"socket", {0, BPF_PROG_TYPE_SOCKET_FILTER, 0}, {-EINVAL, 0} }, | ||
26 | {"kprobe/", {0, BPF_PROG_TYPE_KPROBE, 0}, {-EINVAL, 0} }, | ||
27 | {"kretprobe/", {0, BPF_PROG_TYPE_KPROBE, 0}, {-EINVAL, 0} }, | ||
28 | {"classifier", {0, BPF_PROG_TYPE_SCHED_CLS, 0}, {-EINVAL, 0} }, | ||
29 | {"action", {0, BPF_PROG_TYPE_SCHED_ACT, 0}, {-EINVAL, 0} }, | ||
30 | {"tracepoint/", {0, BPF_PROG_TYPE_TRACEPOINT, 0}, {-EINVAL, 0} }, | ||
31 | { | ||
32 | "raw_tracepoint/", | ||
33 | {0, BPF_PROG_TYPE_RAW_TRACEPOINT, 0}, | ||
34 | {-EINVAL, 0}, | ||
35 | }, | ||
36 | {"xdp", {0, BPF_PROG_TYPE_XDP, 0}, {-EINVAL, 0} }, | ||
37 | {"perf_event", {0, BPF_PROG_TYPE_PERF_EVENT, 0}, {-EINVAL, 0} }, | ||
38 | {"lwt_in", {0, BPF_PROG_TYPE_LWT_IN, 0}, {-EINVAL, 0} }, | ||
39 | {"lwt_out", {0, BPF_PROG_TYPE_LWT_OUT, 0}, {-EINVAL, 0} }, | ||
40 | {"lwt_xmit", {0, BPF_PROG_TYPE_LWT_XMIT, 0}, {-EINVAL, 0} }, | ||
41 | {"lwt_seg6local", {0, BPF_PROG_TYPE_LWT_SEG6LOCAL, 0}, {-EINVAL, 0} }, | ||
42 | { | ||
43 | "cgroup_skb/ingress", | ||
44 | {0, BPF_PROG_TYPE_CGROUP_SKB, 0}, | ||
45 | {0, BPF_CGROUP_INET_INGRESS}, | ||
46 | }, | ||
47 | { | ||
48 | "cgroup_skb/egress", | ||
49 | {0, BPF_PROG_TYPE_CGROUP_SKB, 0}, | ||
50 | {0, BPF_CGROUP_INET_EGRESS}, | ||
51 | }, | ||
52 | {"cgroup/skb", {0, BPF_PROG_TYPE_CGROUP_SKB, 0}, {-EINVAL, 0} }, | ||
53 | { | ||
54 | "cgroup/sock", | ||
55 | {0, BPF_PROG_TYPE_CGROUP_SOCK, 0}, | ||
56 | {0, BPF_CGROUP_INET_SOCK_CREATE}, | ||
57 | }, | ||
58 | { | ||
59 | "cgroup/post_bind4", | ||
60 | {0, BPF_PROG_TYPE_CGROUP_SOCK, BPF_CGROUP_INET4_POST_BIND}, | ||
61 | {0, BPF_CGROUP_INET4_POST_BIND}, | ||
62 | }, | ||
63 | { | ||
64 | "cgroup/post_bind6", | ||
65 | {0, BPF_PROG_TYPE_CGROUP_SOCK, BPF_CGROUP_INET6_POST_BIND}, | ||
66 | {0, BPF_CGROUP_INET6_POST_BIND}, | ||
67 | }, | ||
68 | { | ||
69 | "cgroup/dev", | ||
70 | {0, BPF_PROG_TYPE_CGROUP_DEVICE, 0}, | ||
71 | {0, BPF_CGROUP_DEVICE}, | ||
72 | }, | ||
73 | {"sockops", {0, BPF_PROG_TYPE_SOCK_OPS, 0}, {0, BPF_CGROUP_SOCK_OPS} }, | ||
74 | { | ||
75 | "sk_skb/stream_parser", | ||
76 | {0, BPF_PROG_TYPE_SK_SKB, 0}, | ||
77 | {0, BPF_SK_SKB_STREAM_PARSER}, | ||
78 | }, | ||
79 | { | ||
80 | "sk_skb/stream_verdict", | ||
81 | {0, BPF_PROG_TYPE_SK_SKB, 0}, | ||
82 | {0, BPF_SK_SKB_STREAM_VERDICT}, | ||
83 | }, | ||
84 | {"sk_skb", {0, BPF_PROG_TYPE_SK_SKB, 0}, {-EINVAL, 0} }, | ||
85 | {"sk_msg", {0, BPF_PROG_TYPE_SK_MSG, 0}, {0, BPF_SK_MSG_VERDICT} }, | ||
86 | {"lirc_mode2", {0, BPF_PROG_TYPE_LIRC_MODE2, 0}, {0, BPF_LIRC_MODE2} }, | ||
87 | { | ||
88 | "flow_dissector", | ||
89 | {0, BPF_PROG_TYPE_FLOW_DISSECTOR, 0}, | ||
90 | {0, BPF_FLOW_DISSECTOR}, | ||
91 | }, | ||
92 | { | ||
93 | "cgroup/bind4", | ||
94 | {0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET4_BIND}, | ||
95 | {0, BPF_CGROUP_INET4_BIND}, | ||
96 | }, | ||
97 | { | ||
98 | "cgroup/bind6", | ||
99 | {0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET6_BIND}, | ||
100 | {0, BPF_CGROUP_INET6_BIND}, | ||
101 | }, | ||
102 | { | ||
103 | "cgroup/connect4", | ||
104 | {0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET4_CONNECT}, | ||
105 | {0, BPF_CGROUP_INET4_CONNECT}, | ||
106 | }, | ||
107 | { | ||
108 | "cgroup/connect6", | ||
109 | {0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET6_CONNECT}, | ||
110 | {0, BPF_CGROUP_INET6_CONNECT}, | ||
111 | }, | ||
112 | { | ||
113 | "cgroup/sendmsg4", | ||
114 | {0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UDP4_SENDMSG}, | ||
115 | {0, BPF_CGROUP_UDP4_SENDMSG}, | ||
116 | }, | ||
117 | { | ||
118 | "cgroup/sendmsg6", | ||
119 | {0, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UDP6_SENDMSG}, | ||
120 | {0, BPF_CGROUP_UDP6_SENDMSG}, | ||
121 | }, | ||
122 | }; | ||
123 | |||
124 | static int test_prog_type_by_name(const struct sec_name_test *test) | ||
125 | { | ||
126 | enum bpf_attach_type expected_attach_type; | ||
127 | enum bpf_prog_type prog_type; | ||
128 | int rc; | ||
129 | |||
130 | rc = libbpf_prog_type_by_name(test->sec_name, &prog_type, | ||
131 | &expected_attach_type); | ||
132 | |||
133 | if (rc != test->expected_load.rc) { | ||
134 | warnx("prog: unexpected rc=%d for %s", rc, test->sec_name); | ||
135 | return -1; | ||
136 | } | ||
137 | |||
138 | if (rc) | ||
139 | return 0; | ||
140 | |||
141 | if (prog_type != test->expected_load.prog_type) { | ||
142 | warnx("prog: unexpected prog_type=%d for %s", prog_type, | ||
143 | test->sec_name); | ||
144 | return -1; | ||
145 | } | ||
146 | |||
147 | if (expected_attach_type != test->expected_load.expected_attach_type) { | ||
148 | warnx("prog: unexpected expected_attach_type=%d for %s", | ||
149 | expected_attach_type, test->sec_name); | ||
150 | return -1; | ||
151 | } | ||
152 | |||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | static int test_attach_type_by_name(const struct sec_name_test *test) | ||
157 | { | ||
158 | enum bpf_attach_type attach_type; | ||
159 | int rc; | ||
160 | |||
161 | rc = libbpf_attach_type_by_name(test->sec_name, &attach_type); | ||
162 | |||
163 | if (rc != test->expected_attach.rc) { | ||
164 | warnx("attach: unexpected rc=%d for %s", rc, test->sec_name); | ||
165 | return -1; | ||
166 | } | ||
167 | |||
168 | if (rc) | ||
169 | return 0; | ||
170 | |||
171 | if (attach_type != test->expected_attach.attach_type) { | ||
172 | warnx("attach: unexpected attach_type=%d for %s", attach_type, | ||
173 | test->sec_name); | ||
174 | return -1; | ||
175 | } | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | static int run_test_case(const struct sec_name_test *test) | ||
181 | { | ||
182 | if (test_prog_type_by_name(test)) | ||
183 | return -1; | ||
184 | if (test_attach_type_by_name(test)) | ||
185 | return -1; | ||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | static int run_tests(void) | ||
190 | { | ||
191 | int passes = 0; | ||
192 | int fails = 0; | ||
193 | int i; | ||
194 | |||
195 | for (i = 0; i < ARRAY_SIZE(tests); ++i) { | ||
196 | if (run_test_case(&tests[i])) | ||
197 | ++fails; | ||
198 | else | ||
199 | ++passes; | ||
200 | } | ||
201 | printf("Summary: %d PASSED, %d FAILED\n", passes, fails); | ||
202 | return fails ? -1 : 0; | ||
203 | } | ||
204 | |||
205 | int main(int argc, char **argv) | ||
206 | { | ||
207 | return run_tests(); | ||
208 | } | ||
diff --git a/tools/testing/selftests/bpf/test_sk_lookup_kern.c b/tools/testing/selftests/bpf/test_sk_lookup_kern.c new file mode 100644 index 000000000000..b745bdc08c2b --- /dev/null +++ b/tools/testing/selftests/bpf/test_sk_lookup_kern.c | |||
@@ -0,0 +1,180 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | // Copyright (c) 2018 Covalent IO, Inc. http://covalent.io | ||
3 | |||
4 | #include <stddef.h> | ||
5 | #include <stdbool.h> | ||
6 | #include <string.h> | ||
7 | #include <linux/bpf.h> | ||
8 | #include <linux/if_ether.h> | ||
9 | #include <linux/in.h> | ||
10 | #include <linux/ip.h> | ||
11 | #include <linux/ipv6.h> | ||
12 | #include <linux/pkt_cls.h> | ||
13 | #include <linux/tcp.h> | ||
14 | #include <sys/socket.h> | ||
15 | #include "bpf_helpers.h" | ||
16 | #include "bpf_endian.h" | ||
17 | |||
18 | int _version SEC("version") = 1; | ||
19 | char _license[] SEC("license") = "GPL"; | ||
20 | |||
21 | /* Fill 'tuple' with L3 info, and attempt to find L4. On fail, return NULL. */ | ||
22 | static struct bpf_sock_tuple *get_tuple(void *data, __u64 nh_off, | ||
23 | void *data_end, __u16 eth_proto, | ||
24 | bool *ipv4) | ||
25 | { | ||
26 | struct bpf_sock_tuple *result; | ||
27 | __u8 proto = 0; | ||
28 | __u64 ihl_len; | ||
29 | |||
30 | if (eth_proto == bpf_htons(ETH_P_IP)) { | ||
31 | struct iphdr *iph = (struct iphdr *)(data + nh_off); | ||
32 | |||
33 | if (iph + 1 > data_end) | ||
34 | return NULL; | ||
35 | ihl_len = iph->ihl * 4; | ||
36 | proto = iph->protocol; | ||
37 | *ipv4 = true; | ||
38 | result = (struct bpf_sock_tuple *)&iph->saddr; | ||
39 | } else if (eth_proto == bpf_htons(ETH_P_IPV6)) { | ||
40 | struct ipv6hdr *ip6h = (struct ipv6hdr *)(data + nh_off); | ||
41 | |||
42 | if (ip6h + 1 > data_end) | ||
43 | return NULL; | ||
44 | ihl_len = sizeof(*ip6h); | ||
45 | proto = ip6h->nexthdr; | ||
46 | *ipv4 = true; | ||
47 | result = (struct bpf_sock_tuple *)&ip6h->saddr; | ||
48 | } | ||
49 | |||
50 | if (data + nh_off + ihl_len > data_end || proto != IPPROTO_TCP) | ||
51 | return NULL; | ||
52 | |||
53 | return result; | ||
54 | } | ||
55 | |||
56 | SEC("sk_lookup_success") | ||
57 | int bpf_sk_lookup_test0(struct __sk_buff *skb) | ||
58 | { | ||
59 | void *data_end = (void *)(long)skb->data_end; | ||
60 | void *data = (void *)(long)skb->data; | ||
61 | struct ethhdr *eth = (struct ethhdr *)(data); | ||
62 | struct bpf_sock_tuple *tuple; | ||
63 | struct bpf_sock *sk; | ||
64 | size_t tuple_len; | ||
65 | bool ipv4; | ||
66 | |||
67 | if (eth + 1 > data_end) | ||
68 | return TC_ACT_SHOT; | ||
69 | |||
70 | tuple = get_tuple(data, sizeof(*eth), data_end, eth->h_proto, &ipv4); | ||
71 | if (!tuple || tuple + sizeof *tuple > data_end) | ||
72 | return TC_ACT_SHOT; | ||
73 | |||
74 | tuple_len = ipv4 ? sizeof(tuple->ipv4) : sizeof(tuple->ipv6); | ||
75 | sk = bpf_sk_lookup_tcp(skb, tuple, tuple_len, 0, 0); | ||
76 | if (sk) | ||
77 | bpf_sk_release(sk); | ||
78 | return sk ? TC_ACT_OK : TC_ACT_UNSPEC; | ||
79 | } | ||
80 | |||
81 | SEC("sk_lookup_success_simple") | ||
82 | int bpf_sk_lookup_test1(struct __sk_buff *skb) | ||
83 | { | ||
84 | struct bpf_sock_tuple tuple = {}; | ||
85 | struct bpf_sock *sk; | ||
86 | |||
87 | sk = bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), 0, 0); | ||
88 | if (sk) | ||
89 | bpf_sk_release(sk); | ||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | SEC("fail_use_after_free") | ||
94 | int bpf_sk_lookup_uaf(struct __sk_buff *skb) | ||
95 | { | ||
96 | struct bpf_sock_tuple tuple = {}; | ||
97 | struct bpf_sock *sk; | ||
98 | __u32 family = 0; | ||
99 | |||
100 | sk = bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), 0, 0); | ||
101 | if (sk) { | ||
102 | bpf_sk_release(sk); | ||
103 | family = sk->family; | ||
104 | } | ||
105 | return family; | ||
106 | } | ||
107 | |||
108 | SEC("fail_modify_sk_pointer") | ||
109 | int bpf_sk_lookup_modptr(struct __sk_buff *skb) | ||
110 | { | ||
111 | struct bpf_sock_tuple tuple = {}; | ||
112 | struct bpf_sock *sk; | ||
113 | __u32 family; | ||
114 | |||
115 | sk = bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), 0, 0); | ||
116 | if (sk) { | ||
117 | sk += 1; | ||
118 | bpf_sk_release(sk); | ||
119 | } | ||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | SEC("fail_modify_sk_or_null_pointer") | ||
124 | int bpf_sk_lookup_modptr_or_null(struct __sk_buff *skb) | ||
125 | { | ||
126 | struct bpf_sock_tuple tuple = {}; | ||
127 | struct bpf_sock *sk; | ||
128 | __u32 family; | ||
129 | |||
130 | sk = bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), 0, 0); | ||
131 | sk += 1; | ||
132 | if (sk) | ||
133 | bpf_sk_release(sk); | ||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | SEC("fail_no_release") | ||
138 | int bpf_sk_lookup_test2(struct __sk_buff *skb) | ||
139 | { | ||
140 | struct bpf_sock_tuple tuple = {}; | ||
141 | |||
142 | bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), 0, 0); | ||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | SEC("fail_release_twice") | ||
147 | int bpf_sk_lookup_test3(struct __sk_buff *skb) | ||
148 | { | ||
149 | struct bpf_sock_tuple tuple = {}; | ||
150 | struct bpf_sock *sk; | ||
151 | |||
152 | sk = bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), 0, 0); | ||
153 | bpf_sk_release(sk); | ||
154 | bpf_sk_release(sk); | ||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | SEC("fail_release_unchecked") | ||
159 | int bpf_sk_lookup_test4(struct __sk_buff *skb) | ||
160 | { | ||
161 | struct bpf_sock_tuple tuple = {}; | ||
162 | struct bpf_sock *sk; | ||
163 | |||
164 | sk = bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), 0, 0); | ||
165 | bpf_sk_release(sk); | ||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | void lookup_no_release(struct __sk_buff *skb) | ||
170 | { | ||
171 | struct bpf_sock_tuple tuple = {}; | ||
172 | bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), 0, 0); | ||
173 | } | ||
174 | |||
175 | SEC("fail_no_release_subcall") | ||
176 | int bpf_sk_lookup_test5(struct __sk_buff *skb) | ||
177 | { | ||
178 | lookup_no_release(skb); | ||
179 | return 0; | ||
180 | } | ||
diff --git a/tools/testing/selftests/bpf/test_socket_cookie.c b/tools/testing/selftests/bpf/test_socket_cookie.c index 68e108e4687a..b6c2c605d8c0 100644 --- a/tools/testing/selftests/bpf/test_socket_cookie.c +++ b/tools/testing/selftests/bpf/test_socket_cookie.c | |||
@@ -158,11 +158,7 @@ static int run_test(int cgfd) | |||
158 | bpf_object__for_each_program(prog, pobj) { | 158 | bpf_object__for_each_program(prog, pobj) { |
159 | prog_name = bpf_program__title(prog, /*needs_copy*/ false); | 159 | prog_name = bpf_program__title(prog, /*needs_copy*/ false); |
160 | 160 | ||
161 | if (strcmp(prog_name, "cgroup/connect6") == 0) { | 161 | if (libbpf_attach_type_by_name(prog_name, &attach_type)) { |
162 | attach_type = BPF_CGROUP_INET6_CONNECT; | ||
163 | } else if (strcmp(prog_name, "sockops") == 0) { | ||
164 | attach_type = BPF_CGROUP_SOCK_OPS; | ||
165 | } else { | ||
166 | log_err("Unexpected prog: %s", prog_name); | 162 | log_err("Unexpected prog: %s", prog_name); |
167 | goto err; | 163 | goto err; |
168 | } | 164 | } |
diff --git a/tools/testing/selftests/bpf/test_sockmap.c b/tools/testing/selftests/bpf/test_sockmap.c index 0c7d9e556b47..622ade0a0957 100644 --- a/tools/testing/selftests/bpf/test_sockmap.c +++ b/tools/testing/selftests/bpf/test_sockmap.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/sock_diag.h> | 28 | #include <linux/sock_diag.h> |
29 | #include <linux/bpf.h> | 29 | #include <linux/bpf.h> |
30 | #include <linux/if_link.h> | 30 | #include <linux/if_link.h> |
31 | #include <linux/tls.h> | ||
31 | #include <assert.h> | 32 | #include <assert.h> |
32 | #include <libgen.h> | 33 | #include <libgen.h> |
33 | 34 | ||
@@ -43,6 +44,13 @@ | |||
43 | int running; | 44 | int running; |
44 | static void running_handler(int a); | 45 | static void running_handler(int a); |
45 | 46 | ||
47 | #ifndef TCP_ULP | ||
48 | # define TCP_ULP 31 | ||
49 | #endif | ||
50 | #ifndef SOL_TLS | ||
51 | # define SOL_TLS 282 | ||
52 | #endif | ||
53 | |||
46 | /* randomly selected ports for testing on lo */ | 54 | /* randomly selected ports for testing on lo */ |
47 | #define S1_PORT 10000 | 55 | #define S1_PORT 10000 |
48 | #define S2_PORT 10001 | 56 | #define S2_PORT 10001 |
@@ -69,8 +77,12 @@ int txmsg_apply; | |||
69 | int txmsg_cork; | 77 | int txmsg_cork; |
70 | int txmsg_start; | 78 | int txmsg_start; |
71 | int txmsg_end; | 79 | int txmsg_end; |
80 | int txmsg_start_push; | ||
81 | int txmsg_end_push; | ||
72 | int txmsg_ingress; | 82 | int txmsg_ingress; |
73 | int txmsg_skb; | 83 | int txmsg_skb; |
84 | int ktls; | ||
85 | int peek_flag; | ||
74 | 86 | ||
75 | static const struct option long_options[] = { | 87 | static const struct option long_options[] = { |
76 | {"help", no_argument, NULL, 'h' }, | 88 | {"help", no_argument, NULL, 'h' }, |
@@ -90,8 +102,12 @@ static const struct option long_options[] = { | |||
90 | {"txmsg_cork", required_argument, NULL, 'k'}, | 102 | {"txmsg_cork", required_argument, NULL, 'k'}, |
91 | {"txmsg_start", required_argument, NULL, 's'}, | 103 | {"txmsg_start", required_argument, NULL, 's'}, |
92 | {"txmsg_end", required_argument, NULL, 'e'}, | 104 | {"txmsg_end", required_argument, NULL, 'e'}, |
105 | {"txmsg_start_push", required_argument, NULL, 'p'}, | ||
106 | {"txmsg_end_push", required_argument, NULL, 'q'}, | ||
93 | {"txmsg_ingress", no_argument, &txmsg_ingress, 1 }, | 107 | {"txmsg_ingress", no_argument, &txmsg_ingress, 1 }, |
94 | {"txmsg_skb", no_argument, &txmsg_skb, 1 }, | 108 | {"txmsg_skb", no_argument, &txmsg_skb, 1 }, |
109 | {"ktls", no_argument, &ktls, 1 }, | ||
110 | {"peek", no_argument, &peek_flag, 1 }, | ||
95 | {0, 0, NULL, 0 } | 111 | {0, 0, NULL, 0 } |
96 | }; | 112 | }; |
97 | 113 | ||
@@ -112,6 +128,71 @@ static void usage(char *argv[]) | |||
112 | printf("\n"); | 128 | printf("\n"); |
113 | } | 129 | } |
114 | 130 | ||
131 | char *sock_to_string(int s) | ||
132 | { | ||
133 | if (s == c1) | ||
134 | return "client1"; | ||
135 | else if (s == c2) | ||
136 | return "client2"; | ||
137 | else if (s == s1) | ||
138 | return "server1"; | ||
139 | else if (s == s2) | ||
140 | return "server2"; | ||
141 | else if (s == p1) | ||
142 | return "peer1"; | ||
143 | else if (s == p2) | ||
144 | return "peer2"; | ||
145 | else | ||
146 | return "unknown"; | ||
147 | } | ||
148 | |||
149 | static int sockmap_init_ktls(int verbose, int s) | ||
150 | { | ||
151 | struct tls12_crypto_info_aes_gcm_128 tls_tx = { | ||
152 | .info = { | ||
153 | .version = TLS_1_2_VERSION, | ||
154 | .cipher_type = TLS_CIPHER_AES_GCM_128, | ||
155 | }, | ||
156 | }; | ||
157 | struct tls12_crypto_info_aes_gcm_128 tls_rx = { | ||
158 | .info = { | ||
159 | .version = TLS_1_2_VERSION, | ||
160 | .cipher_type = TLS_CIPHER_AES_GCM_128, | ||
161 | }, | ||
162 | }; | ||
163 | int so_buf = 6553500; | ||
164 | int err; | ||
165 | |||
166 | err = setsockopt(s, 6, TCP_ULP, "tls", sizeof("tls")); | ||
167 | if (err) { | ||
168 | fprintf(stderr, "setsockopt: TCP_ULP(%s) failed with error %i\n", sock_to_string(s), err); | ||
169 | return -EINVAL; | ||
170 | } | ||
171 | err = setsockopt(s, SOL_TLS, TLS_TX, (void *)&tls_tx, sizeof(tls_tx)); | ||
172 | if (err) { | ||
173 | fprintf(stderr, "setsockopt: TLS_TX(%s) failed with error %i\n", sock_to_string(s), err); | ||
174 | return -EINVAL; | ||
175 | } | ||
176 | err = setsockopt(s, SOL_TLS, TLS_RX, (void *)&tls_rx, sizeof(tls_rx)); | ||
177 | if (err) { | ||
178 | fprintf(stderr, "setsockopt: TLS_RX(%s) failed with error %i\n", sock_to_string(s), err); | ||
179 | return -EINVAL; | ||
180 | } | ||
181 | err = setsockopt(s, SOL_SOCKET, SO_SNDBUF, &so_buf, sizeof(so_buf)); | ||
182 | if (err) { | ||
183 | fprintf(stderr, "setsockopt: (%s) failed sndbuf with error %i\n", sock_to_string(s), err); | ||
184 | return -EINVAL; | ||
185 | } | ||
186 | err = setsockopt(s, SOL_SOCKET, SO_RCVBUF, &so_buf, sizeof(so_buf)); | ||
187 | if (err) { | ||
188 | fprintf(stderr, "setsockopt: (%s) failed rcvbuf with error %i\n", sock_to_string(s), err); | ||
189 | return -EINVAL; | ||
190 | } | ||
191 | |||
192 | if (verbose) | ||
193 | fprintf(stdout, "socket(%s) kTLS enabled\n", sock_to_string(s)); | ||
194 | return 0; | ||
195 | } | ||
115 | static int sockmap_init_sockets(int verbose) | 196 | static int sockmap_init_sockets(int verbose) |
116 | { | 197 | { |
117 | int i, err, one = 1; | 198 | int i, err, one = 1; |
@@ -277,33 +358,40 @@ static int msg_loop_sendpage(int fd, int iov_length, int cnt, | |||
277 | return 0; | 358 | return 0; |
278 | } | 359 | } |
279 | 360 | ||
280 | static int msg_loop(int fd, int iov_count, int iov_length, int cnt, | 361 | static void msg_free_iov(struct msghdr *msg) |
281 | struct msg_stats *s, bool tx, | ||
282 | struct sockmap_options *opt) | ||
283 | { | 362 | { |
284 | struct msghdr msg = {0}; | 363 | int i; |
285 | int err, i, flags = MSG_NOSIGNAL; | 364 | |
365 | for (i = 0; i < msg->msg_iovlen; i++) | ||
366 | free(msg->msg_iov[i].iov_base); | ||
367 | free(msg->msg_iov); | ||
368 | msg->msg_iov = NULL; | ||
369 | msg->msg_iovlen = 0; | ||
370 | } | ||
371 | |||
372 | static int msg_alloc_iov(struct msghdr *msg, | ||
373 | int iov_count, int iov_length, | ||
374 | bool data, bool xmit) | ||
375 | { | ||
376 | unsigned char k = 0; | ||
286 | struct iovec *iov; | 377 | struct iovec *iov; |
287 | unsigned char k; | 378 | int i; |
288 | bool data_test = opt->data_test; | ||
289 | bool drop = opt->drop_expected; | ||
290 | 379 | ||
291 | iov = calloc(iov_count, sizeof(struct iovec)); | 380 | iov = calloc(iov_count, sizeof(struct iovec)); |
292 | if (!iov) | 381 | if (!iov) |
293 | return errno; | 382 | return errno; |
294 | 383 | ||
295 | k = 0; | ||
296 | for (i = 0; i < iov_count; i++) { | 384 | for (i = 0; i < iov_count; i++) { |
297 | unsigned char *d = calloc(iov_length, sizeof(char)); | 385 | unsigned char *d = calloc(iov_length, sizeof(char)); |
298 | 386 | ||
299 | if (!d) { | 387 | if (!d) { |
300 | fprintf(stderr, "iov_count %i/%i OOM\n", i, iov_count); | 388 | fprintf(stderr, "iov_count %i/%i OOM\n", i, iov_count); |
301 | goto out_errno; | 389 | goto unwind_iov; |
302 | } | 390 | } |
303 | iov[i].iov_base = d; | 391 | iov[i].iov_base = d; |
304 | iov[i].iov_len = iov_length; | 392 | iov[i].iov_len = iov_length; |
305 | 393 | ||
306 | if (data_test && tx) { | 394 | if (data && xmit) { |
307 | int j; | 395 | int j; |
308 | 396 | ||
309 | for (j = 0; j < iov_length; j++) | 397 | for (j = 0; j < iov_length; j++) |
@@ -311,9 +399,60 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt, | |||
311 | } | 399 | } |
312 | } | 400 | } |
313 | 401 | ||
314 | msg.msg_iov = iov; | 402 | msg->msg_iov = iov; |
315 | msg.msg_iovlen = iov_count; | 403 | msg->msg_iovlen = iov_count; |
316 | k = 0; | 404 | |
405 | return 0; | ||
406 | unwind_iov: | ||
407 | for (i--; i >= 0 ; i--) | ||
408 | free(msg->msg_iov[i].iov_base); | ||
409 | return -ENOMEM; | ||
410 | } | ||
411 | |||
412 | static int msg_verify_data(struct msghdr *msg, int size, int chunk_sz) | ||
413 | { | ||
414 | int i, j, bytes_cnt = 0; | ||
415 | unsigned char k = 0; | ||
416 | |||
417 | for (i = 0; i < msg->msg_iovlen; i++) { | ||
418 | unsigned char *d = msg->msg_iov[i].iov_base; | ||
419 | |||
420 | for (j = 0; | ||
421 | j < msg->msg_iov[i].iov_len && size; j++) { | ||
422 | if (d[j] != k++) { | ||
423 | fprintf(stderr, | ||
424 | "detected data corruption @iov[%i]:%i %02x != %02x, %02x ?= %02x\n", | ||
425 | i, j, d[j], k - 1, d[j+1], k); | ||
426 | return -EIO; | ||
427 | } | ||
428 | bytes_cnt++; | ||
429 | if (bytes_cnt == chunk_sz) { | ||
430 | k = 0; | ||
431 | bytes_cnt = 0; | ||
432 | } | ||
433 | size--; | ||
434 | } | ||
435 | } | ||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | static int msg_loop(int fd, int iov_count, int iov_length, int cnt, | ||
440 | struct msg_stats *s, bool tx, | ||
441 | struct sockmap_options *opt) | ||
442 | { | ||
443 | struct msghdr msg = {0}, msg_peek = {0}; | ||
444 | int err, i, flags = MSG_NOSIGNAL; | ||
445 | bool drop = opt->drop_expected; | ||
446 | bool data = opt->data_test; | ||
447 | |||
448 | err = msg_alloc_iov(&msg, iov_count, iov_length, data, tx); | ||
449 | if (err) | ||
450 | goto out_errno; | ||
451 | if (peek_flag) { | ||
452 | err = msg_alloc_iov(&msg_peek, iov_count, iov_length, data, tx); | ||
453 | if (err) | ||
454 | goto out_errno; | ||
455 | } | ||
317 | 456 | ||
318 | if (tx) { | 457 | if (tx) { |
319 | clock_gettime(CLOCK_MONOTONIC, &s->start); | 458 | clock_gettime(CLOCK_MONOTONIC, &s->start); |
@@ -333,19 +472,12 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt, | |||
333 | } | 472 | } |
334 | clock_gettime(CLOCK_MONOTONIC, &s->end); | 473 | clock_gettime(CLOCK_MONOTONIC, &s->end); |
335 | } else { | 474 | } else { |
336 | int slct, recv, max_fd = fd; | 475 | int slct, recvp = 0, recv, max_fd = fd; |
337 | int fd_flags = O_NONBLOCK; | 476 | int fd_flags = O_NONBLOCK; |
338 | struct timeval timeout; | 477 | struct timeval timeout; |
339 | float total_bytes; | 478 | float total_bytes; |
340 | int bytes_cnt = 0; | ||
341 | int chunk_sz; | ||
342 | fd_set w; | 479 | fd_set w; |
343 | 480 | ||
344 | if (opt->sendpage) | ||
345 | chunk_sz = iov_length * cnt; | ||
346 | else | ||
347 | chunk_sz = iov_length * iov_count; | ||
348 | |||
349 | fcntl(fd, fd_flags); | 481 | fcntl(fd, fd_flags); |
350 | total_bytes = (float)iov_count * (float)iov_length * (float)cnt; | 482 | total_bytes = (float)iov_count * (float)iov_length * (float)cnt; |
351 | err = clock_gettime(CLOCK_MONOTONIC, &s->start); | 483 | err = clock_gettime(CLOCK_MONOTONIC, &s->start); |
@@ -377,6 +509,19 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt, | |||
377 | goto out_errno; | 509 | goto out_errno; |
378 | } | 510 | } |
379 | 511 | ||
512 | errno = 0; | ||
513 | if (peek_flag) { | ||
514 | flags |= MSG_PEEK; | ||
515 | recvp = recvmsg(fd, &msg_peek, flags); | ||
516 | if (recvp < 0) { | ||
517 | if (errno != EWOULDBLOCK) { | ||
518 | clock_gettime(CLOCK_MONOTONIC, &s->end); | ||
519 | goto out_errno; | ||
520 | } | ||
521 | } | ||
522 | flags = 0; | ||
523 | } | ||
524 | |||
380 | recv = recvmsg(fd, &msg, flags); | 525 | recv = recvmsg(fd, &msg, flags); |
381 | if (recv < 0) { | 526 | if (recv < 0) { |
382 | if (errno != EWOULDBLOCK) { | 527 | if (errno != EWOULDBLOCK) { |
@@ -388,27 +533,23 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt, | |||
388 | 533 | ||
389 | s->bytes_recvd += recv; | 534 | s->bytes_recvd += recv; |
390 | 535 | ||
391 | if (data_test) { | 536 | if (data) { |
392 | int j; | 537 | int chunk_sz = opt->sendpage ? |
393 | 538 | iov_length * cnt : | |
394 | for (i = 0; i < msg.msg_iovlen; i++) { | 539 | iov_length * iov_count; |
395 | unsigned char *d = iov[i].iov_base; | 540 | |
396 | 541 | errno = msg_verify_data(&msg, recv, chunk_sz); | |
397 | for (j = 0; | 542 | if (errno) { |
398 | j < iov[i].iov_len && recv; j++) { | 543 | perror("data verify msg failed\n"); |
399 | if (d[j] != k++) { | 544 | goto out_errno; |
400 | errno = -EIO; | 545 | } |
401 | fprintf(stderr, | 546 | if (recvp) { |
402 | "detected data corruption @iov[%i]:%i %02x != %02x, %02x ?= %02x\n", | 547 | errno = msg_verify_data(&msg_peek, |
403 | i, j, d[j], k - 1, d[j+1], k); | 548 | recvp, |
404 | goto out_errno; | 549 | chunk_sz); |
405 | } | 550 | if (errno) { |
406 | bytes_cnt++; | 551 | perror("data verify msg_peek failed\n"); |
407 | if (bytes_cnt == chunk_sz) { | 552 | goto out_errno; |
408 | k = 0; | ||
409 | bytes_cnt = 0; | ||
410 | } | ||
411 | recv--; | ||
412 | } | 553 | } |
413 | } | 554 | } |
414 | } | 555 | } |
@@ -416,14 +557,12 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt, | |||
416 | clock_gettime(CLOCK_MONOTONIC, &s->end); | 557 | clock_gettime(CLOCK_MONOTONIC, &s->end); |
417 | } | 558 | } |
418 | 559 | ||
419 | for (i = 0; i < iov_count; i++) | 560 | msg_free_iov(&msg); |
420 | free(iov[i].iov_base); | 561 | msg_free_iov(&msg_peek); |
421 | free(iov); | 562 | return err; |
422 | return 0; | ||
423 | out_errno: | 563 | out_errno: |
424 | for (i = 0; i < iov_count; i++) | 564 | msg_free_iov(&msg); |
425 | free(iov[i].iov_base); | 565 | msg_free_iov(&msg_peek); |
426 | free(iov); | ||
427 | return errno; | 566 | return errno; |
428 | } | 567 | } |
429 | 568 | ||
@@ -456,6 +595,21 @@ static int sendmsg_test(struct sockmap_options *opt) | |||
456 | else | 595 | else |
457 | rx_fd = p2; | 596 | rx_fd = p2; |
458 | 597 | ||
598 | if (ktls) { | ||
599 | /* Redirecting into non-TLS socket which sends into a TLS | ||
600 | * socket is not a valid test. So in this case lets not | ||
601 | * enable kTLS but still run the test. | ||
602 | */ | ||
603 | if (!txmsg_redir || (txmsg_redir && txmsg_ingress)) { | ||
604 | err = sockmap_init_ktls(opt->verbose, rx_fd); | ||
605 | if (err) | ||
606 | return err; | ||
607 | } | ||
608 | err = sockmap_init_ktls(opt->verbose, c1); | ||
609 | if (err) | ||
610 | return err; | ||
611 | } | ||
612 | |||
459 | rxpid = fork(); | 613 | rxpid = fork(); |
460 | if (rxpid == 0) { | 614 | if (rxpid == 0) { |
461 | if (opt->drop_expected) | 615 | if (opt->drop_expected) |
@@ -469,17 +623,16 @@ static int sendmsg_test(struct sockmap_options *opt) | |||
469 | fprintf(stderr, | 623 | fprintf(stderr, |
470 | "msg_loop_rx: iov_count %i iov_buf %i cnt %i err %i\n", | 624 | "msg_loop_rx: iov_count %i iov_buf %i cnt %i err %i\n", |
471 | iov_count, iov_buf, cnt, err); | 625 | iov_count, iov_buf, cnt, err); |
472 | shutdown(p2, SHUT_RDWR); | ||
473 | shutdown(p1, SHUT_RDWR); | ||
474 | if (s.end.tv_sec - s.start.tv_sec) { | 626 | if (s.end.tv_sec - s.start.tv_sec) { |
475 | sent_Bps = sentBps(s); | 627 | sent_Bps = sentBps(s); |
476 | recvd_Bps = recvdBps(s); | 628 | recvd_Bps = recvdBps(s); |
477 | } | 629 | } |
478 | if (opt->verbose) | 630 | if (opt->verbose) |
479 | fprintf(stdout, | 631 | fprintf(stdout, |
480 | "rx_sendmsg: TX: %zuB %fB/s %fGB/s RX: %zuB %fB/s %fGB/s\n", | 632 | "rx_sendmsg: TX: %zuB %fB/s %fGB/s RX: %zuB %fB/s %fGB/s %s\n", |
481 | s.bytes_sent, sent_Bps, sent_Bps/giga, | 633 | s.bytes_sent, sent_Bps, sent_Bps/giga, |
482 | s.bytes_recvd, recvd_Bps, recvd_Bps/giga); | 634 | s.bytes_recvd, recvd_Bps, recvd_Bps/giga, |
635 | peek_flag ? "(peek_msg)" : ""); | ||
483 | if (err && txmsg_cork) | 636 | if (err && txmsg_cork) |
484 | err = 0; | 637 | err = 0; |
485 | exit(err ? 1 : 0); | 638 | exit(err ? 1 : 0); |
@@ -500,7 +653,6 @@ static int sendmsg_test(struct sockmap_options *opt) | |||
500 | fprintf(stderr, | 653 | fprintf(stderr, |
501 | "msg_loop_tx: iov_count %i iov_buf %i cnt %i err %i\n", | 654 | "msg_loop_tx: iov_count %i iov_buf %i cnt %i err %i\n", |
502 | iov_count, iov_buf, cnt, err); | 655 | iov_count, iov_buf, cnt, err); |
503 | shutdown(c1, SHUT_RDWR); | ||
504 | if (s.end.tv_sec - s.start.tv_sec) { | 656 | if (s.end.tv_sec - s.start.tv_sec) { |
505 | sent_Bps = sentBps(s); | 657 | sent_Bps = sentBps(s); |
506 | recvd_Bps = recvdBps(s); | 658 | recvd_Bps = recvdBps(s); |
@@ -755,6 +907,30 @@ run: | |||
755 | } | 907 | } |
756 | } | 908 | } |
757 | 909 | ||
910 | if (txmsg_start_push) { | ||
911 | i = 2; | ||
912 | err = bpf_map_update_elem(map_fd[5], | ||
913 | &i, &txmsg_start_push, BPF_ANY); | ||
914 | if (err) { | ||
915 | fprintf(stderr, | ||
916 | "ERROR: bpf_map_update_elem (txmsg_start_push): %d (%s)\n", | ||
917 | err, strerror(errno)); | ||
918 | goto out; | ||
919 | } | ||
920 | } | ||
921 | |||
922 | if (txmsg_end_push) { | ||
923 | i = 3; | ||
924 | err = bpf_map_update_elem(map_fd[5], | ||
925 | &i, &txmsg_end_push, BPF_ANY); | ||
926 | if (err) { | ||
927 | fprintf(stderr, | ||
928 | "ERROR: bpf_map_update_elem %i@%i (txmsg_end_push): %d (%s)\n", | ||
929 | txmsg_end_push, i, err, strerror(errno)); | ||
930 | goto out; | ||
931 | } | ||
932 | } | ||
933 | |||
758 | if (txmsg_ingress) { | 934 | if (txmsg_ingress) { |
759 | int in = BPF_F_INGRESS; | 935 | int in = BPF_F_INGRESS; |
760 | 936 | ||
@@ -910,6 +1086,10 @@ static void test_options(char *options) | |||
910 | strncat(options, "ingress,", OPTSTRING); | 1086 | strncat(options, "ingress,", OPTSTRING); |
911 | if (txmsg_skb) | 1087 | if (txmsg_skb) |
912 | strncat(options, "skb,", OPTSTRING); | 1088 | strncat(options, "skb,", OPTSTRING); |
1089 | if (ktls) | ||
1090 | strncat(options, "ktls,", OPTSTRING); | ||
1091 | if (peek_flag) | ||
1092 | strncat(options, "peek,", OPTSTRING); | ||
913 | } | 1093 | } |
914 | 1094 | ||
915 | static int __test_exec(int cgrp, int test, struct sockmap_options *opt) | 1095 | static int __test_exec(int cgrp, int test, struct sockmap_options *opt) |
@@ -1083,6 +1263,8 @@ static int test_mixed(int cgrp) | |||
1083 | txmsg_pass = txmsg_noisy = txmsg_redir_noisy = txmsg_drop = 0; | 1263 | txmsg_pass = txmsg_noisy = txmsg_redir_noisy = txmsg_drop = 0; |
1084 | txmsg_apply = txmsg_cork = 0; | 1264 | txmsg_apply = txmsg_cork = 0; |
1085 | txmsg_start = txmsg_end = 0; | 1265 | txmsg_start = txmsg_end = 0; |
1266 | txmsg_start_push = txmsg_end_push = 0; | ||
1267 | |||
1086 | /* Test small and large iov_count values with pass/redir/apply/cork */ | 1268 | /* Test small and large iov_count values with pass/redir/apply/cork */ |
1087 | txmsg_pass = 1; | 1269 | txmsg_pass = 1; |
1088 | txmsg_redir = 0; | 1270 | txmsg_redir = 0; |
@@ -1199,6 +1381,8 @@ static int test_start_end(int cgrp) | |||
1199 | /* Test basic start/end with lots of iov_count and iov_lengths */ | 1381 | /* Test basic start/end with lots of iov_count and iov_lengths */ |
1200 | txmsg_start = 1; | 1382 | txmsg_start = 1; |
1201 | txmsg_end = 2; | 1383 | txmsg_end = 2; |
1384 | txmsg_start_push = 1; | ||
1385 | txmsg_end_push = 2; | ||
1202 | err = test_txmsg(cgrp); | 1386 | err = test_txmsg(cgrp); |
1203 | if (err) | 1387 | if (err) |
1204 | goto out; | 1388 | goto out; |
@@ -1212,6 +1396,8 @@ static int test_start_end(int cgrp) | |||
1212 | for (i = 99; i <= 1600; i += 500) { | 1396 | for (i = 99; i <= 1600; i += 500) { |
1213 | txmsg_start = 0; | 1397 | txmsg_start = 0; |
1214 | txmsg_end = i; | 1398 | txmsg_end = i; |
1399 | txmsg_start_push = 0; | ||
1400 | txmsg_end_push = i; | ||
1215 | err = test_exec(cgrp, &opt); | 1401 | err = test_exec(cgrp, &opt); |
1216 | if (err) | 1402 | if (err) |
1217 | goto out; | 1403 | goto out; |
@@ -1221,6 +1407,8 @@ static int test_start_end(int cgrp) | |||
1221 | for (i = 199; i <= 1600; i += 500) { | 1407 | for (i = 199; i <= 1600; i += 500) { |
1222 | txmsg_start = 100; | 1408 | txmsg_start = 100; |
1223 | txmsg_end = i; | 1409 | txmsg_end = i; |
1410 | txmsg_start_push = 100; | ||
1411 | txmsg_end_push = i; | ||
1224 | err = test_exec(cgrp, &opt); | 1412 | err = test_exec(cgrp, &opt); |
1225 | if (err) | 1413 | if (err) |
1226 | goto out; | 1414 | goto out; |
@@ -1229,6 +1417,8 @@ static int test_start_end(int cgrp) | |||
1229 | /* Test start/end with cork pulling last sg entry */ | 1417 | /* Test start/end with cork pulling last sg entry */ |
1230 | txmsg_start = 1500; | 1418 | txmsg_start = 1500; |
1231 | txmsg_end = 1600; | 1419 | txmsg_end = 1600; |
1420 | txmsg_start_push = 1500; | ||
1421 | txmsg_end_push = 1600; | ||
1232 | err = test_exec(cgrp, &opt); | 1422 | err = test_exec(cgrp, &opt); |
1233 | if (err) | 1423 | if (err) |
1234 | goto out; | 1424 | goto out; |
@@ -1236,6 +1426,8 @@ static int test_start_end(int cgrp) | |||
1236 | /* Test start/end pull of single byte in last page */ | 1426 | /* Test start/end pull of single byte in last page */ |
1237 | txmsg_start = 1111; | 1427 | txmsg_start = 1111; |
1238 | txmsg_end = 1112; | 1428 | txmsg_end = 1112; |
1429 | txmsg_start_push = 1111; | ||
1430 | txmsg_end_push = 1112; | ||
1239 | err = test_exec(cgrp, &opt); | 1431 | err = test_exec(cgrp, &opt); |
1240 | if (err) | 1432 | if (err) |
1241 | goto out; | 1433 | goto out; |
@@ -1243,6 +1435,8 @@ static int test_start_end(int cgrp) | |||
1243 | /* Test start/end with end < start */ | 1435 | /* Test start/end with end < start */ |
1244 | txmsg_start = 1111; | 1436 | txmsg_start = 1111; |
1245 | txmsg_end = 0; | 1437 | txmsg_end = 0; |
1438 | txmsg_start_push = 1111; | ||
1439 | txmsg_end_push = 0; | ||
1246 | err = test_exec(cgrp, &opt); | 1440 | err = test_exec(cgrp, &opt); |
1247 | if (err) | 1441 | if (err) |
1248 | goto out; | 1442 | goto out; |
@@ -1250,6 +1444,8 @@ static int test_start_end(int cgrp) | |||
1250 | /* Test start/end with end > data */ | 1444 | /* Test start/end with end > data */ |
1251 | txmsg_start = 0; | 1445 | txmsg_start = 0; |
1252 | txmsg_end = 1601; | 1446 | txmsg_end = 1601; |
1447 | txmsg_start_push = 0; | ||
1448 | txmsg_end_push = 1601; | ||
1253 | err = test_exec(cgrp, &opt); | 1449 | err = test_exec(cgrp, &opt); |
1254 | if (err) | 1450 | if (err) |
1255 | goto out; | 1451 | goto out; |
@@ -1257,6 +1453,8 @@ static int test_start_end(int cgrp) | |||
1257 | /* Test start/end with start > data */ | 1453 | /* Test start/end with start > data */ |
1258 | txmsg_start = 1601; | 1454 | txmsg_start = 1601; |
1259 | txmsg_end = 1600; | 1455 | txmsg_end = 1600; |
1456 | txmsg_start_push = 1601; | ||
1457 | txmsg_end_push = 1600; | ||
1260 | err = test_exec(cgrp, &opt); | 1458 | err = test_exec(cgrp, &opt); |
1261 | 1459 | ||
1262 | out: | 1460 | out: |
@@ -1272,7 +1470,7 @@ char *map_names[] = { | |||
1272 | "sock_map_redir", | 1470 | "sock_map_redir", |
1273 | "sock_apply_bytes", | 1471 | "sock_apply_bytes", |
1274 | "sock_cork_bytes", | 1472 | "sock_cork_bytes", |
1275 | "sock_pull_bytes", | 1473 | "sock_bytes", |
1276 | "sock_redir_flags", | 1474 | "sock_redir_flags", |
1277 | "sock_skb_opts", | 1475 | "sock_skb_opts", |
1278 | }; | 1476 | }; |
@@ -1348,9 +1546,9 @@ static int populate_progs(char *bpf_file) | |||
1348 | return 0; | 1546 | return 0; |
1349 | } | 1547 | } |
1350 | 1548 | ||
1351 | static int __test_suite(char *bpf_file) | 1549 | static int __test_suite(int cg_fd, char *bpf_file) |
1352 | { | 1550 | { |
1353 | int cg_fd, err; | 1551 | int err, cleanup = cg_fd; |
1354 | 1552 | ||
1355 | err = populate_progs(bpf_file); | 1553 | err = populate_progs(bpf_file); |
1356 | if (err < 0) { | 1554 | if (err < 0) { |
@@ -1358,26 +1556,28 @@ static int __test_suite(char *bpf_file) | |||
1358 | return err; | 1556 | return err; |
1359 | } | 1557 | } |
1360 | 1558 | ||
1361 | if (setup_cgroup_environment()) { | ||
1362 | fprintf(stderr, "ERROR: cgroup env failed\n"); | ||
1363 | return -EINVAL; | ||
1364 | } | ||
1365 | |||
1366 | cg_fd = create_and_get_cgroup(CG_PATH); | ||
1367 | if (cg_fd < 0) { | 1559 | if (cg_fd < 0) { |
1368 | fprintf(stderr, | 1560 | if (setup_cgroup_environment()) { |
1369 | "ERROR: (%i) open cg path failed: %s\n", | 1561 | fprintf(stderr, "ERROR: cgroup env failed\n"); |
1370 | cg_fd, optarg); | 1562 | return -EINVAL; |
1371 | return cg_fd; | 1563 | } |
1372 | } | ||
1373 | 1564 | ||
1374 | if (join_cgroup(CG_PATH)) { | 1565 | cg_fd = create_and_get_cgroup(CG_PATH); |
1375 | fprintf(stderr, "ERROR: failed to join cgroup\n"); | 1566 | if (cg_fd < 0) { |
1376 | return -EINVAL; | 1567 | fprintf(stderr, |
1568 | "ERROR: (%i) open cg path failed: %s\n", | ||
1569 | cg_fd, optarg); | ||
1570 | return cg_fd; | ||
1571 | } | ||
1572 | |||
1573 | if (join_cgroup(CG_PATH)) { | ||
1574 | fprintf(stderr, "ERROR: failed to join cgroup\n"); | ||
1575 | return -EINVAL; | ||
1576 | } | ||
1377 | } | 1577 | } |
1378 | 1578 | ||
1379 | /* Tests basic commands and APIs with range of iov values */ | 1579 | /* Tests basic commands and APIs with range of iov values */ |
1380 | txmsg_start = txmsg_end = 0; | 1580 | txmsg_start = txmsg_end = txmsg_start_push = txmsg_end_push = 0; |
1381 | err = test_txmsg(cg_fd); | 1581 | err = test_txmsg(cg_fd); |
1382 | if (err) | 1582 | if (err) |
1383 | goto out; | 1583 | goto out; |
@@ -1394,20 +1594,24 @@ static int __test_suite(char *bpf_file) | |||
1394 | 1594 | ||
1395 | out: | 1595 | out: |
1396 | printf("Summary: %i PASSED %i FAILED\n", passed, failed); | 1596 | printf("Summary: %i PASSED %i FAILED\n", passed, failed); |
1397 | cleanup_cgroup_environment(); | 1597 | if (cleanup < 0) { |
1398 | close(cg_fd); | 1598 | cleanup_cgroup_environment(); |
1599 | close(cg_fd); | ||
1600 | } | ||
1399 | return err; | 1601 | return err; |
1400 | } | 1602 | } |
1401 | 1603 | ||
1402 | static int test_suite(void) | 1604 | static int test_suite(int cg_fd) |
1403 | { | 1605 | { |
1404 | int err; | 1606 | int err; |
1405 | 1607 | ||
1406 | err = __test_suite(BPF_SOCKMAP_FILENAME); | 1608 | err = __test_suite(cg_fd, BPF_SOCKMAP_FILENAME); |
1407 | if (err) | 1609 | if (err) |
1408 | goto out; | 1610 | goto out; |
1409 | err = __test_suite(BPF_SOCKHASH_FILENAME); | 1611 | err = __test_suite(cg_fd, BPF_SOCKHASH_FILENAME); |
1410 | out: | 1612 | out: |
1613 | if (cg_fd > -1) | ||
1614 | close(cg_fd); | ||
1411 | return err; | 1615 | return err; |
1412 | } | 1616 | } |
1413 | 1617 | ||
@@ -1420,9 +1624,9 @@ int main(int argc, char **argv) | |||
1420 | int test = PING_PONG; | 1624 | int test = PING_PONG; |
1421 | 1625 | ||
1422 | if (argc < 2) | 1626 | if (argc < 2) |
1423 | return test_suite(); | 1627 | return test_suite(-1); |
1424 | 1628 | ||
1425 | while ((opt = getopt_long(argc, argv, ":dhvc:r:i:l:t:", | 1629 | while ((opt = getopt_long(argc, argv, ":dhvc:r:i:l:t:p:q:", |
1426 | long_options, &longindex)) != -1) { | 1630 | long_options, &longindex)) != -1) { |
1427 | switch (opt) { | 1631 | switch (opt) { |
1428 | case 's': | 1632 | case 's': |
@@ -1431,6 +1635,12 @@ int main(int argc, char **argv) | |||
1431 | case 'e': | 1635 | case 'e': |
1432 | txmsg_end = atoi(optarg); | 1636 | txmsg_end = atoi(optarg); |
1433 | break; | 1637 | break; |
1638 | case 'p': | ||
1639 | txmsg_start_push = atoi(optarg); | ||
1640 | break; | ||
1641 | case 'q': | ||
1642 | txmsg_end_push = atoi(optarg); | ||
1643 | break; | ||
1434 | case 'a': | 1644 | case 'a': |
1435 | txmsg_apply = atoi(optarg); | 1645 | txmsg_apply = atoi(optarg); |
1436 | break; | 1646 | break; |
@@ -1486,6 +1696,9 @@ int main(int argc, char **argv) | |||
1486 | } | 1696 | } |
1487 | } | 1697 | } |
1488 | 1698 | ||
1699 | if (argc <= 3 && cg_fd) | ||
1700 | return test_suite(cg_fd); | ||
1701 | |||
1489 | if (!cg_fd) { | 1702 | if (!cg_fd) { |
1490 | fprintf(stderr, "%s requires cgroup option: --cgroup <path>\n", | 1703 | fprintf(stderr, "%s requires cgroup option: --cgroup <path>\n", |
1491 | argv[0]); | 1704 | argv[0]); |
diff --git a/tools/testing/selftests/bpf/test_sockmap_kern.h b/tools/testing/selftests/bpf/test_sockmap_kern.h index 8e8e41780bb9..14b8bbac004f 100644 --- a/tools/testing/selftests/bpf/test_sockmap_kern.h +++ b/tools/testing/selftests/bpf/test_sockmap_kern.h | |||
@@ -70,11 +70,11 @@ struct bpf_map_def SEC("maps") sock_cork_bytes = { | |||
70 | .max_entries = 1 | 70 | .max_entries = 1 |
71 | }; | 71 | }; |
72 | 72 | ||
73 | struct bpf_map_def SEC("maps") sock_pull_bytes = { | 73 | struct bpf_map_def SEC("maps") sock_bytes = { |
74 | .type = BPF_MAP_TYPE_ARRAY, | 74 | .type = BPF_MAP_TYPE_ARRAY, |
75 | .key_size = sizeof(int), | 75 | .key_size = sizeof(int), |
76 | .value_size = sizeof(int), | 76 | .value_size = sizeof(int), |
77 | .max_entries = 2 | 77 | .max_entries = 4 |
78 | }; | 78 | }; |
79 | 79 | ||
80 | struct bpf_map_def SEC("maps") sock_redir_flags = { | 80 | struct bpf_map_def SEC("maps") sock_redir_flags = { |
@@ -181,8 +181,8 @@ int bpf_sockmap(struct bpf_sock_ops *skops) | |||
181 | SEC("sk_msg1") | 181 | SEC("sk_msg1") |
182 | int bpf_prog4(struct sk_msg_md *msg) | 182 | int bpf_prog4(struct sk_msg_md *msg) |
183 | { | 183 | { |
184 | int *bytes, zero = 0, one = 1; | 184 | int *bytes, zero = 0, one = 1, two = 2, three = 3; |
185 | int *start, *end; | 185 | int *start, *end, *start_push, *end_push; |
186 | 186 | ||
187 | bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); | 187 | bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); |
188 | if (bytes) | 188 | if (bytes) |
@@ -190,18 +190,24 @@ int bpf_prog4(struct sk_msg_md *msg) | |||
190 | bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); | 190 | bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); |
191 | if (bytes) | 191 | if (bytes) |
192 | bpf_msg_cork_bytes(msg, *bytes); | 192 | bpf_msg_cork_bytes(msg, *bytes); |
193 | start = bpf_map_lookup_elem(&sock_pull_bytes, &zero); | 193 | start = bpf_map_lookup_elem(&sock_bytes, &zero); |
194 | end = bpf_map_lookup_elem(&sock_pull_bytes, &one); | 194 | end = bpf_map_lookup_elem(&sock_bytes, &one); |
195 | if (start && end) | 195 | if (start && end) |
196 | bpf_msg_pull_data(msg, *start, *end, 0); | 196 | bpf_msg_pull_data(msg, *start, *end, 0); |
197 | start_push = bpf_map_lookup_elem(&sock_bytes, &two); | ||
198 | end_push = bpf_map_lookup_elem(&sock_bytes, &three); | ||
199 | if (start_push && end_push) | ||
200 | bpf_msg_push_data(msg, *start_push, *end_push, 0); | ||
197 | return SK_PASS; | 201 | return SK_PASS; |
198 | } | 202 | } |
199 | 203 | ||
200 | SEC("sk_msg2") | 204 | SEC("sk_msg2") |
201 | int bpf_prog5(struct sk_msg_md *msg) | 205 | int bpf_prog5(struct sk_msg_md *msg) |
202 | { | 206 | { |
203 | int err1 = -1, err2 = -1, zero = 0, one = 1; | 207 | int zero = 0, one = 1, two = 2, three = 3; |
204 | int *bytes, *start, *end, len1, len2; | 208 | int *start, *end, *start_push, *end_push; |
209 | int *bytes, len1, len2 = 0, len3; | ||
210 | int err1 = -1, err2 = -1; | ||
205 | 211 | ||
206 | bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); | 212 | bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); |
207 | if (bytes) | 213 | if (bytes) |
@@ -210,8 +216,8 @@ int bpf_prog5(struct sk_msg_md *msg) | |||
210 | if (bytes) | 216 | if (bytes) |
211 | err2 = bpf_msg_cork_bytes(msg, *bytes); | 217 | err2 = bpf_msg_cork_bytes(msg, *bytes); |
212 | len1 = (__u64)msg->data_end - (__u64)msg->data; | 218 | len1 = (__u64)msg->data_end - (__u64)msg->data; |
213 | start = bpf_map_lookup_elem(&sock_pull_bytes, &zero); | 219 | start = bpf_map_lookup_elem(&sock_bytes, &zero); |
214 | end = bpf_map_lookup_elem(&sock_pull_bytes, &one); | 220 | end = bpf_map_lookup_elem(&sock_bytes, &one); |
215 | if (start && end) { | 221 | if (start && end) { |
216 | int err; | 222 | int err; |
217 | 223 | ||
@@ -225,6 +231,23 @@ int bpf_prog5(struct sk_msg_md *msg) | |||
225 | bpf_printk("sk_msg2: length update %i->%i\n", | 231 | bpf_printk("sk_msg2: length update %i->%i\n", |
226 | len1, len2); | 232 | len1, len2); |
227 | } | 233 | } |
234 | |||
235 | start_push = bpf_map_lookup_elem(&sock_bytes, &two); | ||
236 | end_push = bpf_map_lookup_elem(&sock_bytes, &three); | ||
237 | if (start_push && end_push) { | ||
238 | int err; | ||
239 | |||
240 | bpf_printk("sk_msg2: push(%i:%i)\n", | ||
241 | start_push ? *start_push : 0, | ||
242 | end_push ? *end_push : 0); | ||
243 | err = bpf_msg_push_data(msg, *start_push, *end_push, 0); | ||
244 | if (err) | ||
245 | bpf_printk("sk_msg2: push_data err %i\n", err); | ||
246 | len3 = (__u64)msg->data_end - (__u64)msg->data; | ||
247 | bpf_printk("sk_msg2: length push_update %i->%i\n", | ||
248 | len2 ? len2 : len1, len3); | ||
249 | } | ||
250 | |||
228 | bpf_printk("sk_msg2: data length %i err1 %i err2 %i\n", | 251 | bpf_printk("sk_msg2: data length %i err1 %i err2 %i\n", |
229 | len1, err1, err2); | 252 | len1, err1, err2); |
230 | return SK_PASS; | 253 | return SK_PASS; |
@@ -233,8 +256,8 @@ int bpf_prog5(struct sk_msg_md *msg) | |||
233 | SEC("sk_msg3") | 256 | SEC("sk_msg3") |
234 | int bpf_prog6(struct sk_msg_md *msg) | 257 | int bpf_prog6(struct sk_msg_md *msg) |
235 | { | 258 | { |
236 | int *bytes, zero = 0, one = 1, key = 0; | 259 | int *bytes, *start, *end, *start_push, *end_push, *f; |
237 | int *start, *end, *f; | 260 | int zero = 0, one = 1, two = 2, three = 3, key = 0; |
238 | __u64 flags = 0; | 261 | __u64 flags = 0; |
239 | 262 | ||
240 | bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); | 263 | bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); |
@@ -243,10 +266,17 @@ int bpf_prog6(struct sk_msg_md *msg) | |||
243 | bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); | 266 | bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); |
244 | if (bytes) | 267 | if (bytes) |
245 | bpf_msg_cork_bytes(msg, *bytes); | 268 | bpf_msg_cork_bytes(msg, *bytes); |
246 | start = bpf_map_lookup_elem(&sock_pull_bytes, &zero); | 269 | |
247 | end = bpf_map_lookup_elem(&sock_pull_bytes, &one); | 270 | start = bpf_map_lookup_elem(&sock_bytes, &zero); |
271 | end = bpf_map_lookup_elem(&sock_bytes, &one); | ||
248 | if (start && end) | 272 | if (start && end) |
249 | bpf_msg_pull_data(msg, *start, *end, 0); | 273 | bpf_msg_pull_data(msg, *start, *end, 0); |
274 | |||
275 | start_push = bpf_map_lookup_elem(&sock_bytes, &two); | ||
276 | end_push = bpf_map_lookup_elem(&sock_bytes, &three); | ||
277 | if (start_push && end_push) | ||
278 | bpf_msg_push_data(msg, *start_push, *end_push, 0); | ||
279 | |||
250 | f = bpf_map_lookup_elem(&sock_redir_flags, &zero); | 280 | f = bpf_map_lookup_elem(&sock_redir_flags, &zero); |
251 | if (f && *f) { | 281 | if (f && *f) { |
252 | key = 2; | 282 | key = 2; |
@@ -262,8 +292,9 @@ int bpf_prog6(struct sk_msg_md *msg) | |||
262 | SEC("sk_msg4") | 292 | SEC("sk_msg4") |
263 | int bpf_prog7(struct sk_msg_md *msg) | 293 | int bpf_prog7(struct sk_msg_md *msg) |
264 | { | 294 | { |
265 | int err1 = 0, err2 = 0, zero = 0, one = 1, key = 0; | 295 | int zero = 0, one = 1, two = 2, three = 3, len1, len2 = 0, len3; |
266 | int *f, *bytes, *start, *end, len1, len2; | 296 | int *bytes, *start, *end, *start_push, *end_push, *f; |
297 | int err1 = 0, err2 = 0, key = 0; | ||
267 | __u64 flags = 0; | 298 | __u64 flags = 0; |
268 | 299 | ||
269 | int err; | 300 | int err; |
@@ -274,10 +305,10 @@ int bpf_prog7(struct sk_msg_md *msg) | |||
274 | if (bytes) | 305 | if (bytes) |
275 | err2 = bpf_msg_cork_bytes(msg, *bytes); | 306 | err2 = bpf_msg_cork_bytes(msg, *bytes); |
276 | len1 = (__u64)msg->data_end - (__u64)msg->data; | 307 | len1 = (__u64)msg->data_end - (__u64)msg->data; |
277 | start = bpf_map_lookup_elem(&sock_pull_bytes, &zero); | ||
278 | end = bpf_map_lookup_elem(&sock_pull_bytes, &one); | ||
279 | if (start && end) { | ||
280 | 308 | ||
309 | start = bpf_map_lookup_elem(&sock_bytes, &zero); | ||
310 | end = bpf_map_lookup_elem(&sock_bytes, &one); | ||
311 | if (start && end) { | ||
281 | bpf_printk("sk_msg2: pull(%i:%i)\n", | 312 | bpf_printk("sk_msg2: pull(%i:%i)\n", |
282 | start ? *start : 0, end ? *end : 0); | 313 | start ? *start : 0, end ? *end : 0); |
283 | err = bpf_msg_pull_data(msg, *start, *end, 0); | 314 | err = bpf_msg_pull_data(msg, *start, *end, 0); |
@@ -288,6 +319,22 @@ int bpf_prog7(struct sk_msg_md *msg) | |||
288 | bpf_printk("sk_msg2: length update %i->%i\n", | 319 | bpf_printk("sk_msg2: length update %i->%i\n", |
289 | len1, len2); | 320 | len1, len2); |
290 | } | 321 | } |
322 | |||
323 | start_push = bpf_map_lookup_elem(&sock_bytes, &two); | ||
324 | end_push = bpf_map_lookup_elem(&sock_bytes, &three); | ||
325 | if (start_push && end_push) { | ||
326 | bpf_printk("sk_msg4: push(%i:%i)\n", | ||
327 | start_push ? *start_push : 0, | ||
328 | end_push ? *end_push : 0); | ||
329 | err = bpf_msg_push_data(msg, *start_push, *end_push, 0); | ||
330 | if (err) | ||
331 | bpf_printk("sk_msg4: push_data err %i\n", | ||
332 | err); | ||
333 | len3 = (__u64)msg->data_end - (__u64)msg->data; | ||
334 | bpf_printk("sk_msg4: length push_update %i->%i\n", | ||
335 | len2 ? len2 : len1, len3); | ||
336 | } | ||
337 | |||
291 | f = bpf_map_lookup_elem(&sock_redir_flags, &zero); | 338 | f = bpf_map_lookup_elem(&sock_redir_flags, &zero); |
292 | if (f && *f) { | 339 | if (f && *f) { |
293 | key = 2; | 340 | key = 2; |
@@ -342,8 +389,8 @@ int bpf_prog9(struct sk_msg_md *msg) | |||
342 | SEC("sk_msg7") | 389 | SEC("sk_msg7") |
343 | int bpf_prog10(struct sk_msg_md *msg) | 390 | int bpf_prog10(struct sk_msg_md *msg) |
344 | { | 391 | { |
345 | int *bytes, zero = 0, one = 1; | 392 | int *bytes, *start, *end, *start_push, *end_push; |
346 | int *start, *end; | 393 | int zero = 0, one = 1, two = 2, three = 3; |
347 | 394 | ||
348 | bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); | 395 | bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); |
349 | if (bytes) | 396 | if (bytes) |
@@ -351,10 +398,14 @@ int bpf_prog10(struct sk_msg_md *msg) | |||
351 | bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); | 398 | bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); |
352 | if (bytes) | 399 | if (bytes) |
353 | bpf_msg_cork_bytes(msg, *bytes); | 400 | bpf_msg_cork_bytes(msg, *bytes); |
354 | start = bpf_map_lookup_elem(&sock_pull_bytes, &zero); | 401 | start = bpf_map_lookup_elem(&sock_bytes, &zero); |
355 | end = bpf_map_lookup_elem(&sock_pull_bytes, &one); | 402 | end = bpf_map_lookup_elem(&sock_bytes, &one); |
356 | if (start && end) | 403 | if (start && end) |
357 | bpf_msg_pull_data(msg, *start, *end, 0); | 404 | bpf_msg_pull_data(msg, *start, *end, 0); |
405 | start_push = bpf_map_lookup_elem(&sock_bytes, &two); | ||
406 | end_push = bpf_map_lookup_elem(&sock_bytes, &three); | ||
407 | if (start_push && end_push) | ||
408 | bpf_msg_push_data(msg, *start_push, *end_push, 0); | ||
358 | 409 | ||
359 | return SK_DROP; | 410 | return SK_DROP; |
360 | } | 411 | } |
diff --git a/tools/testing/selftests/bpf/test_stack_map.c b/tools/testing/selftests/bpf/test_stack_map.c new file mode 100644 index 000000000000..31c3880e6da0 --- /dev/null +++ b/tools/testing/selftests/bpf/test_stack_map.c | |||
@@ -0,0 +1,4 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | // Copyright (c) 2018 Politecnico di Torino | ||
3 | #define MAP_TYPE BPF_MAP_TYPE_STACK | ||
4 | #include "test_queue_stack_map.h" | ||
diff --git a/tools/testing/selftests/bpf/test_tcpbpf_kern.c b/tools/testing/selftests/bpf/test_tcpbpf_kern.c index 4b7fd540cea9..74f73b33a7b0 100644 --- a/tools/testing/selftests/bpf/test_tcpbpf_kern.c +++ b/tools/testing/selftests/bpf/test_tcpbpf_kern.c | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <linux/if_ether.h> | 5 | #include <linux/if_ether.h> |
6 | #include <linux/if_packet.h> | 6 | #include <linux/if_packet.h> |
7 | #include <linux/ip.h> | 7 | #include <linux/ip.h> |
8 | #include <linux/ipv6.h> | ||
8 | #include <linux/types.h> | 9 | #include <linux/types.h> |
9 | #include <linux/socket.h> | 10 | #include <linux/socket.h> |
10 | #include <linux/tcp.h> | 11 | #include <linux/tcp.h> |
@@ -17,6 +18,13 @@ struct bpf_map_def SEC("maps") global_map = { | |||
17 | .type = BPF_MAP_TYPE_ARRAY, | 18 | .type = BPF_MAP_TYPE_ARRAY, |
18 | .key_size = sizeof(__u32), | 19 | .key_size = sizeof(__u32), |
19 | .value_size = sizeof(struct tcpbpf_globals), | 20 | .value_size = sizeof(struct tcpbpf_globals), |
21 | .max_entries = 4, | ||
22 | }; | ||
23 | |||
24 | struct bpf_map_def SEC("maps") sockopt_results = { | ||
25 | .type = BPF_MAP_TYPE_ARRAY, | ||
26 | .key_size = sizeof(__u32), | ||
27 | .value_size = sizeof(int), | ||
20 | .max_entries = 2, | 28 | .max_entries = 2, |
21 | }; | 29 | }; |
22 | 30 | ||
@@ -45,11 +53,14 @@ int _version SEC("version") = 1; | |||
45 | SEC("sockops") | 53 | SEC("sockops") |
46 | int bpf_testcb(struct bpf_sock_ops *skops) | 54 | int bpf_testcb(struct bpf_sock_ops *skops) |
47 | { | 55 | { |
48 | int rv = -1; | 56 | char header[sizeof(struct ipv6hdr) + sizeof(struct tcphdr)]; |
49 | int bad_call_rv = 0; | 57 | struct tcphdr *thdr; |
50 | int good_call_rv = 0; | 58 | int good_call_rv = 0; |
51 | int op; | 59 | int bad_call_rv = 0; |
60 | int save_syn = 1; | ||
61 | int rv = -1; | ||
52 | int v = 0; | 62 | int v = 0; |
63 | int op; | ||
53 | 64 | ||
54 | op = (int) skops->op; | 65 | op = (int) skops->op; |
55 | 66 | ||
@@ -82,6 +93,21 @@ int bpf_testcb(struct bpf_sock_ops *skops) | |||
82 | v = 0xff; | 93 | v = 0xff; |
83 | rv = bpf_setsockopt(skops, SOL_IPV6, IPV6_TCLASS, &v, | 94 | rv = bpf_setsockopt(skops, SOL_IPV6, IPV6_TCLASS, &v, |
84 | sizeof(v)); | 95 | sizeof(v)); |
96 | if (skops->family == AF_INET6) { | ||
97 | v = bpf_getsockopt(skops, IPPROTO_TCP, TCP_SAVED_SYN, | ||
98 | header, (sizeof(struct ipv6hdr) + | ||
99 | sizeof(struct tcphdr))); | ||
100 | if (!v) { | ||
101 | int offset = sizeof(struct ipv6hdr); | ||
102 | |||
103 | thdr = (struct tcphdr *)(header + offset); | ||
104 | v = thdr->syn; | ||
105 | __u32 key = 1; | ||
106 | |||
107 | bpf_map_update_elem(&sockopt_results, &key, &v, | ||
108 | BPF_ANY); | ||
109 | } | ||
110 | } | ||
85 | break; | 111 | break; |
86 | case BPF_SOCK_OPS_RTO_CB: | 112 | case BPF_SOCK_OPS_RTO_CB: |
87 | break; | 113 | break; |
@@ -111,6 +137,12 @@ int bpf_testcb(struct bpf_sock_ops *skops) | |||
111 | break; | 137 | break; |
112 | case BPF_SOCK_OPS_TCP_LISTEN_CB: | 138 | case BPF_SOCK_OPS_TCP_LISTEN_CB: |
113 | bpf_sock_ops_cb_flags_set(skops, BPF_SOCK_OPS_STATE_CB_FLAG); | 139 | bpf_sock_ops_cb_flags_set(skops, BPF_SOCK_OPS_STATE_CB_FLAG); |
140 | v = bpf_setsockopt(skops, IPPROTO_TCP, TCP_SAVE_SYN, | ||
141 | &save_syn, sizeof(save_syn)); | ||
142 | /* Update global map w/ result of setsock opt */ | ||
143 | __u32 key = 0; | ||
144 | |||
145 | bpf_map_update_elem(&sockopt_results, &key, &v, BPF_ANY); | ||
114 | break; | 146 | break; |
115 | default: | 147 | default: |
116 | rv = -1; | 148 | rv = -1; |
diff --git a/tools/testing/selftests/bpf/test_tcpbpf_user.c b/tools/testing/selftests/bpf/test_tcpbpf_user.c index a275c2971376..e6eebda7d112 100644 --- a/tools/testing/selftests/bpf/test_tcpbpf_user.c +++ b/tools/testing/selftests/bpf/test_tcpbpf_user.c | |||
@@ -54,6 +54,26 @@ err: | |||
54 | return -1; | 54 | return -1; |
55 | } | 55 | } |
56 | 56 | ||
57 | int verify_sockopt_result(int sock_map_fd) | ||
58 | { | ||
59 | __u32 key = 0; | ||
60 | int res; | ||
61 | int rv; | ||
62 | |||
63 | /* check setsockopt for SAVE_SYN */ | ||
64 | rv = bpf_map_lookup_elem(sock_map_fd, &key, &res); | ||
65 | EXPECT_EQ(0, rv, "d"); | ||
66 | EXPECT_EQ(0, res, "d"); | ||
67 | key = 1; | ||
68 | /* check getsockopt for SAVED_SYN */ | ||
69 | rv = bpf_map_lookup_elem(sock_map_fd, &key, &res); | ||
70 | EXPECT_EQ(0, rv, "d"); | ||
71 | EXPECT_EQ(1, res, "d"); | ||
72 | return 0; | ||
73 | err: | ||
74 | return -1; | ||
75 | } | ||
76 | |||
57 | static int bpf_find_map(const char *test, struct bpf_object *obj, | 77 | static int bpf_find_map(const char *test, struct bpf_object *obj, |
58 | const char *name) | 78 | const char *name) |
59 | { | 79 | { |
@@ -70,11 +90,11 @@ static int bpf_find_map(const char *test, struct bpf_object *obj, | |||
70 | int main(int argc, char **argv) | 90 | int main(int argc, char **argv) |
71 | { | 91 | { |
72 | const char *file = "test_tcpbpf_kern.o"; | 92 | const char *file = "test_tcpbpf_kern.o"; |
93 | int prog_fd, map_fd, sock_map_fd; | ||
73 | struct tcpbpf_globals g = {0}; | 94 | struct tcpbpf_globals g = {0}; |
74 | const char *cg_path = "/foo"; | 95 | const char *cg_path = "/foo"; |
75 | int error = EXIT_FAILURE; | 96 | int error = EXIT_FAILURE; |
76 | struct bpf_object *obj; | 97 | struct bpf_object *obj; |
77 | int prog_fd, map_fd; | ||
78 | int cg_fd = -1; | 98 | int cg_fd = -1; |
79 | __u32 key = 0; | 99 | __u32 key = 0; |
80 | int rv; | 100 | int rv; |
@@ -110,6 +130,10 @@ int main(int argc, char **argv) | |||
110 | if (map_fd < 0) | 130 | if (map_fd < 0) |
111 | goto err; | 131 | goto err; |
112 | 132 | ||
133 | sock_map_fd = bpf_find_map(__func__, obj, "sockopt_results"); | ||
134 | if (sock_map_fd < 0) | ||
135 | goto err; | ||
136 | |||
113 | rv = bpf_map_lookup_elem(map_fd, &key, &g); | 137 | rv = bpf_map_lookup_elem(map_fd, &key, &g); |
114 | if (rv != 0) { | 138 | if (rv != 0) { |
115 | printf("FAILED: bpf_map_lookup_elem returns %d\n", rv); | 139 | printf("FAILED: bpf_map_lookup_elem returns %d\n", rv); |
@@ -121,6 +145,11 @@ int main(int argc, char **argv) | |||
121 | goto err; | 145 | goto err; |
122 | } | 146 | } |
123 | 147 | ||
148 | if (verify_sockopt_result(sock_map_fd)) { | ||
149 | printf("FAILED: Wrong sockopt stats\n"); | ||
150 | goto err; | ||
151 | } | ||
152 | |||
124 | printf("PASSED!\n"); | 153 | printf("PASSED!\n"); |
125 | error = 0; | 154 | error = 0; |
126 | err: | 155 | err: |
diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 67c412d19c09..769d68a48f30 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c | |||
@@ -3,6 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright (c) 2014 PLUMgrid, http://plumgrid.com | 4 | * Copyright (c) 2014 PLUMgrid, http://plumgrid.com |
5 | * Copyright (c) 2017 Facebook | 5 | * Copyright (c) 2017 Facebook |
6 | * Copyright (c) 2018 Covalent IO, Inc. http://covalent.io | ||
6 | * | 7 | * |
7 | * This program is free software; you can redistribute it and/or | 8 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of version 2 of the GNU General Public | 9 | * modify it under the terms of version 2 of the GNU General Public |
@@ -47,7 +48,7 @@ | |||
47 | 48 | ||
48 | #define MAX_INSNS BPF_MAXINSNS | 49 | #define MAX_INSNS BPF_MAXINSNS |
49 | #define MAX_FIXUPS 8 | 50 | #define MAX_FIXUPS 8 |
50 | #define MAX_NR_MAPS 8 | 51 | #define MAX_NR_MAPS 13 |
51 | #define POINTER_VALUE 0xcafe4all | 52 | #define POINTER_VALUE 0xcafe4all |
52 | #define TEST_DATA_LEN 64 | 53 | #define TEST_DATA_LEN 64 |
53 | 54 | ||
@@ -60,14 +61,19 @@ static bool unpriv_disabled = false; | |||
60 | struct bpf_test { | 61 | struct bpf_test { |
61 | const char *descr; | 62 | const char *descr; |
62 | struct bpf_insn insns[MAX_INSNS]; | 63 | struct bpf_insn insns[MAX_INSNS]; |
63 | int fixup_map1[MAX_FIXUPS]; | 64 | int fixup_map_hash_8b[MAX_FIXUPS]; |
64 | int fixup_map2[MAX_FIXUPS]; | 65 | int fixup_map_hash_48b[MAX_FIXUPS]; |
65 | int fixup_map3[MAX_FIXUPS]; | 66 | int fixup_map_hash_16b[MAX_FIXUPS]; |
66 | int fixup_map4[MAX_FIXUPS]; | 67 | int fixup_map_array_48b[MAX_FIXUPS]; |
68 | int fixup_map_sockmap[MAX_FIXUPS]; | ||
69 | int fixup_map_sockhash[MAX_FIXUPS]; | ||
70 | int fixup_map_xskmap[MAX_FIXUPS]; | ||
71 | int fixup_map_stacktrace[MAX_FIXUPS]; | ||
67 | int fixup_prog1[MAX_FIXUPS]; | 72 | int fixup_prog1[MAX_FIXUPS]; |
68 | int fixup_prog2[MAX_FIXUPS]; | 73 | int fixup_prog2[MAX_FIXUPS]; |
69 | int fixup_map_in_map[MAX_FIXUPS]; | 74 | int fixup_map_in_map[MAX_FIXUPS]; |
70 | int fixup_cgroup_storage[MAX_FIXUPS]; | 75 | int fixup_cgroup_storage[MAX_FIXUPS]; |
76 | int fixup_percpu_cgroup_storage[MAX_FIXUPS]; | ||
71 | const char *errstr; | 77 | const char *errstr; |
72 | const char *errstr_unpriv; | 78 | const char *errstr_unpriv; |
73 | uint32_t retval; | 79 | uint32_t retval; |
@@ -177,6 +183,24 @@ static void bpf_fill_rand_ld_dw(struct bpf_test *self) | |||
177 | self->retval = (uint32_t)res; | 183 | self->retval = (uint32_t)res; |
178 | } | 184 | } |
179 | 185 | ||
186 | /* BPF_SK_LOOKUP contains 13 instructions, if you need to fix up maps */ | ||
187 | #define BPF_SK_LOOKUP \ | ||
188 | /* struct bpf_sock_tuple tuple = {} */ \ | ||
189 | BPF_MOV64_IMM(BPF_REG_2, 0), \ | ||
190 | BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_2, -8), \ | ||
191 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -16), \ | ||
192 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -24), \ | ||
193 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -32), \ | ||
194 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -40), \ | ||
195 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -48), \ | ||
196 | /* sk = sk_lookup_tcp(ctx, &tuple, sizeof tuple, 0, 0) */ \ | ||
197 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), \ | ||
198 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -48), \ | ||
199 | BPF_MOV64_IMM(BPF_REG_3, sizeof(struct bpf_sock_tuple)), \ | ||
200 | BPF_MOV64_IMM(BPF_REG_4, 0), \ | ||
201 | BPF_MOV64_IMM(BPF_REG_5, 0), \ | ||
202 | BPF_EMIT_CALL(BPF_FUNC_sk_lookup_tcp) | ||
203 | |||
180 | static struct bpf_test tests[] = { | 204 | static struct bpf_test tests[] = { |
181 | { | 205 | { |
182 | "add+sub+mul", | 206 | "add+sub+mul", |
@@ -856,7 +880,7 @@ static struct bpf_test tests[] = { | |||
856 | BPF_FUNC_map_lookup_elem), | 880 | BPF_FUNC_map_lookup_elem), |
857 | BPF_EXIT_INSN(), | 881 | BPF_EXIT_INSN(), |
858 | }, | 882 | }, |
859 | .fixup_map1 = { 2 }, | 883 | .fixup_map_hash_8b = { 2 }, |
860 | .errstr = "invalid indirect read from stack", | 884 | .errstr = "invalid indirect read from stack", |
861 | .result = REJECT, | 885 | .result = REJECT, |
862 | }, | 886 | }, |
@@ -1090,7 +1114,7 @@ static struct bpf_test tests[] = { | |||
1090 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 0), | 1114 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 0), |
1091 | BPF_EXIT_INSN(), | 1115 | BPF_EXIT_INSN(), |
1092 | }, | 1116 | }, |
1093 | .fixup_map1 = { 3 }, | 1117 | .fixup_map_hash_8b = { 3 }, |
1094 | .errstr = "R0 invalid mem access 'map_value_or_null'", | 1118 | .errstr = "R0 invalid mem access 'map_value_or_null'", |
1095 | .result = REJECT, | 1119 | .result = REJECT, |
1096 | }, | 1120 | }, |
@@ -1107,7 +1131,7 @@ static struct bpf_test tests[] = { | |||
1107 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 4, 0), | 1131 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 4, 0), |
1108 | BPF_EXIT_INSN(), | 1132 | BPF_EXIT_INSN(), |
1109 | }, | 1133 | }, |
1110 | .fixup_map1 = { 3 }, | 1134 | .fixup_map_hash_8b = { 3 }, |
1111 | .errstr = "misaligned value access", | 1135 | .errstr = "misaligned value access", |
1112 | .result = REJECT, | 1136 | .result = REJECT, |
1113 | .flags = F_LOAD_WITH_STRICT_ALIGNMENT, | 1137 | .flags = F_LOAD_WITH_STRICT_ALIGNMENT, |
@@ -1127,7 +1151,7 @@ static struct bpf_test tests[] = { | |||
1127 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 1), | 1151 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 1), |
1128 | BPF_EXIT_INSN(), | 1152 | BPF_EXIT_INSN(), |
1129 | }, | 1153 | }, |
1130 | .fixup_map1 = { 3 }, | 1154 | .fixup_map_hash_8b = { 3 }, |
1131 | .errstr = "R0 invalid mem access", | 1155 | .errstr = "R0 invalid mem access", |
1132 | .errstr_unpriv = "R0 leaks addr", | 1156 | .errstr_unpriv = "R0 leaks addr", |
1133 | .result = REJECT, | 1157 | .result = REJECT, |
@@ -1217,7 +1241,7 @@ static struct bpf_test tests[] = { | |||
1217 | BPF_FUNC_map_delete_elem), | 1241 | BPF_FUNC_map_delete_elem), |
1218 | BPF_EXIT_INSN(), | 1242 | BPF_EXIT_INSN(), |
1219 | }, | 1243 | }, |
1220 | .fixup_map1 = { 24 }, | 1244 | .fixup_map_hash_8b = { 24 }, |
1221 | .errstr_unpriv = "R1 pointer comparison", | 1245 | .errstr_unpriv = "R1 pointer comparison", |
1222 | .result_unpriv = REJECT, | 1246 | .result_unpriv = REJECT, |
1223 | .result = ACCEPT, | 1247 | .result = ACCEPT, |
@@ -1371,7 +1395,7 @@ static struct bpf_test tests[] = { | |||
1371 | offsetof(struct __sk_buff, pkt_type)), | 1395 | offsetof(struct __sk_buff, pkt_type)), |
1372 | BPF_EXIT_INSN(), | 1396 | BPF_EXIT_INSN(), |
1373 | }, | 1397 | }, |
1374 | .fixup_map1 = { 4 }, | 1398 | .fixup_map_hash_8b = { 4 }, |
1375 | .errstr = "different pointers", | 1399 | .errstr = "different pointers", |
1376 | .errstr_unpriv = "R1 pointer comparison", | 1400 | .errstr_unpriv = "R1 pointer comparison", |
1377 | .result = REJECT, | 1401 | .result = REJECT, |
@@ -1394,7 +1418,7 @@ static struct bpf_test tests[] = { | |||
1394 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | 1418 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), |
1395 | BPF_JMP_IMM(BPF_JA, 0, 0, -12), | 1419 | BPF_JMP_IMM(BPF_JA, 0, 0, -12), |
1396 | }, | 1420 | }, |
1397 | .fixup_map1 = { 6 }, | 1421 | .fixup_map_hash_8b = { 6 }, |
1398 | .errstr = "different pointers", | 1422 | .errstr = "different pointers", |
1399 | .errstr_unpriv = "R1 pointer comparison", | 1423 | .errstr_unpriv = "R1 pointer comparison", |
1400 | .result = REJECT, | 1424 | .result = REJECT, |
@@ -1418,7 +1442,7 @@ static struct bpf_test tests[] = { | |||
1418 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | 1442 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), |
1419 | BPF_JMP_IMM(BPF_JA, 0, 0, -13), | 1443 | BPF_JMP_IMM(BPF_JA, 0, 0, -13), |
1420 | }, | 1444 | }, |
1421 | .fixup_map1 = { 7 }, | 1445 | .fixup_map_hash_8b = { 7 }, |
1422 | .errstr = "different pointers", | 1446 | .errstr = "different pointers", |
1423 | .errstr_unpriv = "R1 pointer comparison", | 1447 | .errstr_unpriv = "R1 pointer comparison", |
1424 | .result = REJECT, | 1448 | .result = REJECT, |
@@ -2555,7 +2579,7 @@ static struct bpf_test tests[] = { | |||
2555 | BPF_MOV64_IMM(BPF_REG_0, 0), | 2579 | BPF_MOV64_IMM(BPF_REG_0, 0), |
2556 | BPF_EXIT_INSN(), | 2580 | BPF_EXIT_INSN(), |
2557 | }, | 2581 | }, |
2558 | .fixup_map1 = { 3 }, | 2582 | .fixup_map_hash_8b = { 3 }, |
2559 | .errstr_unpriv = "R4 leaks addr", | 2583 | .errstr_unpriv = "R4 leaks addr", |
2560 | .result_unpriv = REJECT, | 2584 | .result_unpriv = REJECT, |
2561 | .result = ACCEPT, | 2585 | .result = ACCEPT, |
@@ -2572,7 +2596,7 @@ static struct bpf_test tests[] = { | |||
2572 | BPF_MOV64_IMM(BPF_REG_0, 0), | 2596 | BPF_MOV64_IMM(BPF_REG_0, 0), |
2573 | BPF_EXIT_INSN(), | 2597 | BPF_EXIT_INSN(), |
2574 | }, | 2598 | }, |
2575 | .fixup_map1 = { 3 }, | 2599 | .fixup_map_hash_8b = { 3 }, |
2576 | .errstr = "invalid indirect read from stack off -8+0 size 8", | 2600 | .errstr = "invalid indirect read from stack off -8+0 size 8", |
2577 | .result = REJECT, | 2601 | .result = REJECT, |
2578 | }, | 2602 | }, |
@@ -2707,6 +2731,137 @@ static struct bpf_test tests[] = { | |||
2707 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 2731 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
2708 | }, | 2732 | }, |
2709 | { | 2733 | { |
2734 | "unpriv: spill/fill of different pointers stx - ctx and sock", | ||
2735 | .insns = { | ||
2736 | BPF_MOV64_REG(BPF_REG_8, BPF_REG_1), | ||
2737 | /* struct bpf_sock *sock = bpf_sock_lookup(...); */ | ||
2738 | BPF_SK_LOOKUP, | ||
2739 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_0), | ||
2740 | /* u64 foo; */ | ||
2741 | /* void *target = &foo; */ | ||
2742 | BPF_ALU64_REG(BPF_MOV, BPF_REG_6, BPF_REG_10), | ||
2743 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, -8), | ||
2744 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_8), | ||
2745 | /* if (skb == NULL) *target = sock; */ | ||
2746 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 1), | ||
2747 | BPF_STX_MEM(BPF_DW, BPF_REG_6, BPF_REG_2, 0), | ||
2748 | /* else *target = skb; */ | ||
2749 | BPF_JMP_IMM(BPF_JNE, BPF_REG_1, 0, 1), | ||
2750 | BPF_STX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, 0), | ||
2751 | /* struct __sk_buff *skb = *target; */ | ||
2752 | BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6, 0), | ||
2753 | /* skb->mark = 42; */ | ||
2754 | BPF_MOV64_IMM(BPF_REG_3, 42), | ||
2755 | BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_3, | ||
2756 | offsetof(struct __sk_buff, mark)), | ||
2757 | /* if (sk) bpf_sk_release(sk) */ | ||
2758 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 1), | ||
2759 | BPF_EMIT_CALL(BPF_FUNC_sk_release), | ||
2760 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
2761 | BPF_EXIT_INSN(), | ||
2762 | }, | ||
2763 | .result = REJECT, | ||
2764 | .errstr = "type=ctx expected=sock", | ||
2765 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
2766 | }, | ||
2767 | { | ||
2768 | "unpriv: spill/fill of different pointers stx - leak sock", | ||
2769 | .insns = { | ||
2770 | BPF_MOV64_REG(BPF_REG_8, BPF_REG_1), | ||
2771 | /* struct bpf_sock *sock = bpf_sock_lookup(...); */ | ||
2772 | BPF_SK_LOOKUP, | ||
2773 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_0), | ||
2774 | /* u64 foo; */ | ||
2775 | /* void *target = &foo; */ | ||
2776 | BPF_ALU64_REG(BPF_MOV, BPF_REG_6, BPF_REG_10), | ||
2777 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, -8), | ||
2778 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_8), | ||
2779 | /* if (skb == NULL) *target = sock; */ | ||
2780 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 1), | ||
2781 | BPF_STX_MEM(BPF_DW, BPF_REG_6, BPF_REG_2, 0), | ||
2782 | /* else *target = skb; */ | ||
2783 | BPF_JMP_IMM(BPF_JNE, BPF_REG_1, 0, 1), | ||
2784 | BPF_STX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, 0), | ||
2785 | /* struct __sk_buff *skb = *target; */ | ||
2786 | BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6, 0), | ||
2787 | /* skb->mark = 42; */ | ||
2788 | BPF_MOV64_IMM(BPF_REG_3, 42), | ||
2789 | BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_3, | ||
2790 | offsetof(struct __sk_buff, mark)), | ||
2791 | BPF_EXIT_INSN(), | ||
2792 | }, | ||
2793 | .result = REJECT, | ||
2794 | //.errstr = "same insn cannot be used with different pointers", | ||
2795 | .errstr = "Unreleased reference", | ||
2796 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
2797 | }, | ||
2798 | { | ||
2799 | "unpriv: spill/fill of different pointers stx - sock and ctx (read)", | ||
2800 | .insns = { | ||
2801 | BPF_MOV64_REG(BPF_REG_8, BPF_REG_1), | ||
2802 | /* struct bpf_sock *sock = bpf_sock_lookup(...); */ | ||
2803 | BPF_SK_LOOKUP, | ||
2804 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_0), | ||
2805 | /* u64 foo; */ | ||
2806 | /* void *target = &foo; */ | ||
2807 | BPF_ALU64_REG(BPF_MOV, BPF_REG_6, BPF_REG_10), | ||
2808 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, -8), | ||
2809 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_8), | ||
2810 | /* if (skb) *target = skb */ | ||
2811 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 1), | ||
2812 | BPF_STX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, 0), | ||
2813 | /* else *target = sock */ | ||
2814 | BPF_JMP_IMM(BPF_JNE, BPF_REG_1, 0, 1), | ||
2815 | BPF_STX_MEM(BPF_DW, BPF_REG_6, BPF_REG_2, 0), | ||
2816 | /* struct bpf_sock *sk = *target; */ | ||
2817 | BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6, 0), | ||
2818 | /* if (sk) u32 foo = sk->mark; bpf_sk_release(sk); */ | ||
2819 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 2), | ||
2820 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
2821 | offsetof(struct bpf_sock, mark)), | ||
2822 | BPF_EMIT_CALL(BPF_FUNC_sk_release), | ||
2823 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
2824 | BPF_EXIT_INSN(), | ||
2825 | }, | ||
2826 | .result = REJECT, | ||
2827 | .errstr = "same insn cannot be used with different pointers", | ||
2828 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
2829 | }, | ||
2830 | { | ||
2831 | "unpriv: spill/fill of different pointers stx - sock and ctx (write)", | ||
2832 | .insns = { | ||
2833 | BPF_MOV64_REG(BPF_REG_8, BPF_REG_1), | ||
2834 | /* struct bpf_sock *sock = bpf_sock_lookup(...); */ | ||
2835 | BPF_SK_LOOKUP, | ||
2836 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_0), | ||
2837 | /* u64 foo; */ | ||
2838 | /* void *target = &foo; */ | ||
2839 | BPF_ALU64_REG(BPF_MOV, BPF_REG_6, BPF_REG_10), | ||
2840 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, -8), | ||
2841 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_8), | ||
2842 | /* if (skb) *target = skb */ | ||
2843 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 1), | ||
2844 | BPF_STX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, 0), | ||
2845 | /* else *target = sock */ | ||
2846 | BPF_JMP_IMM(BPF_JNE, BPF_REG_1, 0, 1), | ||
2847 | BPF_STX_MEM(BPF_DW, BPF_REG_6, BPF_REG_2, 0), | ||
2848 | /* struct bpf_sock *sk = *target; */ | ||
2849 | BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6, 0), | ||
2850 | /* if (sk) sk->mark = 42; bpf_sk_release(sk); */ | ||
2851 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 3), | ||
2852 | BPF_MOV64_IMM(BPF_REG_3, 42), | ||
2853 | BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_3, | ||
2854 | offsetof(struct bpf_sock, mark)), | ||
2855 | BPF_EMIT_CALL(BPF_FUNC_sk_release), | ||
2856 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
2857 | BPF_EXIT_INSN(), | ||
2858 | }, | ||
2859 | .result = REJECT, | ||
2860 | //.errstr = "same insn cannot be used with different pointers", | ||
2861 | .errstr = "cannot write into socket", | ||
2862 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
2863 | }, | ||
2864 | { | ||
2710 | "unpriv: spill/fill of different pointers ldx", | 2865 | "unpriv: spill/fill of different pointers ldx", |
2711 | .insns = { | 2866 | .insns = { |
2712 | BPF_ALU64_REG(BPF_MOV, BPF_REG_6, BPF_REG_10), | 2867 | BPF_ALU64_REG(BPF_MOV, BPF_REG_6, BPF_REG_10), |
@@ -2743,7 +2898,7 @@ static struct bpf_test tests[] = { | |||
2743 | BPF_STX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0), | 2898 | BPF_STX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0), |
2744 | BPF_EXIT_INSN(), | 2899 | BPF_EXIT_INSN(), |
2745 | }, | 2900 | }, |
2746 | .fixup_map1 = { 3 }, | 2901 | .fixup_map_hash_8b = { 3 }, |
2747 | .errstr_unpriv = "R0 leaks addr", | 2902 | .errstr_unpriv = "R0 leaks addr", |
2748 | .result_unpriv = REJECT, | 2903 | .result_unpriv = REJECT, |
2749 | .result = ACCEPT, | 2904 | .result = ACCEPT, |
@@ -2783,7 +2938,7 @@ static struct bpf_test tests[] = { | |||
2783 | BPF_MOV64_IMM(BPF_REG_0, 0), | 2938 | BPF_MOV64_IMM(BPF_REG_0, 0), |
2784 | BPF_EXIT_INSN(), | 2939 | BPF_EXIT_INSN(), |
2785 | }, | 2940 | }, |
2786 | .fixup_map1 = { 1 }, | 2941 | .fixup_map_hash_8b = { 1 }, |
2787 | .errstr_unpriv = "R1 pointer comparison", | 2942 | .errstr_unpriv = "R1 pointer comparison", |
2788 | .result_unpriv = REJECT, | 2943 | .result_unpriv = REJECT, |
2789 | .result = ACCEPT, | 2944 | .result = ACCEPT, |
@@ -3275,7 +3430,7 @@ static struct bpf_test tests[] = { | |||
3275 | BPF_ST_MEM(BPF_DW, BPF_REG_1, offsetof(struct __sk_buff, mark), 0), | 3430 | BPF_ST_MEM(BPF_DW, BPF_REG_1, offsetof(struct __sk_buff, mark), 0), |
3276 | BPF_EXIT_INSN(), | 3431 | BPF_EXIT_INSN(), |
3277 | }, | 3432 | }, |
3278 | .errstr = "BPF_ST stores into R1 context is not allowed", | 3433 | .errstr = "BPF_ST stores into R1 ctx is not allowed", |
3279 | .result = REJECT, | 3434 | .result = REJECT, |
3280 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 3435 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
3281 | }, | 3436 | }, |
@@ -3287,7 +3442,7 @@ static struct bpf_test tests[] = { | |||
3287 | BPF_REG_0, offsetof(struct __sk_buff, mark), 0), | 3442 | BPF_REG_0, offsetof(struct __sk_buff, mark), 0), |
3288 | BPF_EXIT_INSN(), | 3443 | BPF_EXIT_INSN(), |
3289 | }, | 3444 | }, |
3290 | .errstr = "BPF_XADD stores into R1 context is not allowed", | 3445 | .errstr = "BPF_XADD stores into R1 ctx is not allowed", |
3291 | .result = REJECT, | 3446 | .result = REJECT, |
3292 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 3447 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
3293 | }, | 3448 | }, |
@@ -3637,7 +3792,7 @@ static struct bpf_test tests[] = { | |||
3637 | BPF_MOV64_IMM(BPF_REG_0, 0), | 3792 | BPF_MOV64_IMM(BPF_REG_0, 0), |
3638 | BPF_EXIT_INSN(), | 3793 | BPF_EXIT_INSN(), |
3639 | }, | 3794 | }, |
3640 | .errstr = "R3 pointer arithmetic on PTR_TO_PACKET_END", | 3795 | .errstr = "R3 pointer arithmetic on pkt_end", |
3641 | .result = REJECT, | 3796 | .result = REJECT, |
3642 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 3797 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
3643 | }, | 3798 | }, |
@@ -3922,7 +4077,7 @@ static struct bpf_test tests[] = { | |||
3922 | BPF_MOV64_IMM(BPF_REG_0, 0), | 4077 | BPF_MOV64_IMM(BPF_REG_0, 0), |
3923 | BPF_EXIT_INSN(), | 4078 | BPF_EXIT_INSN(), |
3924 | }, | 4079 | }, |
3925 | .fixup_map1 = { 5 }, | 4080 | .fixup_map_hash_8b = { 5 }, |
3926 | .result_unpriv = ACCEPT, | 4081 | .result_unpriv = ACCEPT, |
3927 | .result = ACCEPT, | 4082 | .result = ACCEPT, |
3928 | .prog_type = BPF_PROG_TYPE_XDP, | 4083 | .prog_type = BPF_PROG_TYPE_XDP, |
@@ -3938,7 +4093,7 @@ static struct bpf_test tests[] = { | |||
3938 | BPF_MOV64_IMM(BPF_REG_0, 0), | 4093 | BPF_MOV64_IMM(BPF_REG_0, 0), |
3939 | BPF_EXIT_INSN(), | 4094 | BPF_EXIT_INSN(), |
3940 | }, | 4095 | }, |
3941 | .fixup_map1 = { 1 }, | 4096 | .fixup_map_hash_8b = { 1 }, |
3942 | .result = REJECT, | 4097 | .result = REJECT, |
3943 | .errstr = "invalid access to packet", | 4098 | .errstr = "invalid access to packet", |
3944 | .prog_type = BPF_PROG_TYPE_XDP, | 4099 | .prog_type = BPF_PROG_TYPE_XDP, |
@@ -3966,7 +4121,7 @@ static struct bpf_test tests[] = { | |||
3966 | BPF_MOV64_IMM(BPF_REG_0, 0), | 4121 | BPF_MOV64_IMM(BPF_REG_0, 0), |
3967 | BPF_EXIT_INSN(), | 4122 | BPF_EXIT_INSN(), |
3968 | }, | 4123 | }, |
3969 | .fixup_map1 = { 11 }, | 4124 | .fixup_map_hash_8b = { 11 }, |
3970 | .result = ACCEPT, | 4125 | .result = ACCEPT, |
3971 | .prog_type = BPF_PROG_TYPE_XDP, | 4126 | .prog_type = BPF_PROG_TYPE_XDP, |
3972 | }, | 4127 | }, |
@@ -3988,7 +4143,7 @@ static struct bpf_test tests[] = { | |||
3988 | BPF_MOV64_IMM(BPF_REG_0, 0), | 4143 | BPF_MOV64_IMM(BPF_REG_0, 0), |
3989 | BPF_EXIT_INSN(), | 4144 | BPF_EXIT_INSN(), |
3990 | }, | 4145 | }, |
3991 | .fixup_map1 = { 7 }, | 4146 | .fixup_map_hash_8b = { 7 }, |
3992 | .result = REJECT, | 4147 | .result = REJECT, |
3993 | .errstr = "invalid access to packet", | 4148 | .errstr = "invalid access to packet", |
3994 | .prog_type = BPF_PROG_TYPE_XDP, | 4149 | .prog_type = BPF_PROG_TYPE_XDP, |
@@ -4010,7 +4165,7 @@ static struct bpf_test tests[] = { | |||
4010 | BPF_MOV64_IMM(BPF_REG_0, 0), | 4165 | BPF_MOV64_IMM(BPF_REG_0, 0), |
4011 | BPF_EXIT_INSN(), | 4166 | BPF_EXIT_INSN(), |
4012 | }, | 4167 | }, |
4013 | .fixup_map1 = { 6 }, | 4168 | .fixup_map_hash_8b = { 6 }, |
4014 | .result = REJECT, | 4169 | .result = REJECT, |
4015 | .errstr = "invalid access to packet", | 4170 | .errstr = "invalid access to packet", |
4016 | .prog_type = BPF_PROG_TYPE_XDP, | 4171 | .prog_type = BPF_PROG_TYPE_XDP, |
@@ -4033,7 +4188,7 @@ static struct bpf_test tests[] = { | |||
4033 | BPF_MOV64_IMM(BPF_REG_0, 0), | 4188 | BPF_MOV64_IMM(BPF_REG_0, 0), |
4034 | BPF_EXIT_INSN(), | 4189 | BPF_EXIT_INSN(), |
4035 | }, | 4190 | }, |
4036 | .fixup_map1 = { 5 }, | 4191 | .fixup_map_hash_8b = { 5 }, |
4037 | .result = ACCEPT, | 4192 | .result = ACCEPT, |
4038 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 4193 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
4039 | }, | 4194 | }, |
@@ -4048,7 +4203,7 @@ static struct bpf_test tests[] = { | |||
4048 | BPF_MOV64_IMM(BPF_REG_0, 0), | 4203 | BPF_MOV64_IMM(BPF_REG_0, 0), |
4049 | BPF_EXIT_INSN(), | 4204 | BPF_EXIT_INSN(), |
4050 | }, | 4205 | }, |
4051 | .fixup_map1 = { 1 }, | 4206 | .fixup_map_hash_8b = { 1 }, |
4052 | .result = REJECT, | 4207 | .result = REJECT, |
4053 | .errstr = "invalid access to packet", | 4208 | .errstr = "invalid access to packet", |
4054 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 4209 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
@@ -4076,7 +4231,7 @@ static struct bpf_test tests[] = { | |||
4076 | BPF_MOV64_IMM(BPF_REG_0, 0), | 4231 | BPF_MOV64_IMM(BPF_REG_0, 0), |
4077 | BPF_EXIT_INSN(), | 4232 | BPF_EXIT_INSN(), |
4078 | }, | 4233 | }, |
4079 | .fixup_map1 = { 11 }, | 4234 | .fixup_map_hash_8b = { 11 }, |
4080 | .result = ACCEPT, | 4235 | .result = ACCEPT, |
4081 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 4236 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
4082 | }, | 4237 | }, |
@@ -4098,7 +4253,7 @@ static struct bpf_test tests[] = { | |||
4098 | BPF_MOV64_IMM(BPF_REG_0, 0), | 4253 | BPF_MOV64_IMM(BPF_REG_0, 0), |
4099 | BPF_EXIT_INSN(), | 4254 | BPF_EXIT_INSN(), |
4100 | }, | 4255 | }, |
4101 | .fixup_map1 = { 7 }, | 4256 | .fixup_map_hash_8b = { 7 }, |
4102 | .result = REJECT, | 4257 | .result = REJECT, |
4103 | .errstr = "invalid access to packet", | 4258 | .errstr = "invalid access to packet", |
4104 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 4259 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
@@ -4120,7 +4275,7 @@ static struct bpf_test tests[] = { | |||
4120 | BPF_MOV64_IMM(BPF_REG_0, 0), | 4275 | BPF_MOV64_IMM(BPF_REG_0, 0), |
4121 | BPF_EXIT_INSN(), | 4276 | BPF_EXIT_INSN(), |
4122 | }, | 4277 | }, |
4123 | .fixup_map1 = { 6 }, | 4278 | .fixup_map_hash_8b = { 6 }, |
4124 | .result = REJECT, | 4279 | .result = REJECT, |
4125 | .errstr = "invalid access to packet", | 4280 | .errstr = "invalid access to packet", |
4126 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 4281 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
@@ -4391,6 +4546,85 @@ static struct bpf_test tests[] = { | |||
4391 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 4546 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
4392 | }, | 4547 | }, |
4393 | { | 4548 | { |
4549 | "prevent map lookup in sockmap", | ||
4550 | .insns = { | ||
4551 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
4552 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
4553 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
4554 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
4555 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
4556 | BPF_FUNC_map_lookup_elem), | ||
4557 | BPF_EXIT_INSN(), | ||
4558 | }, | ||
4559 | .fixup_map_sockmap = { 3 }, | ||
4560 | .result = REJECT, | ||
4561 | .errstr = "cannot pass map_type 15 into func bpf_map_lookup_elem", | ||
4562 | .prog_type = BPF_PROG_TYPE_SOCK_OPS, | ||
4563 | }, | ||
4564 | { | ||
4565 | "prevent map lookup in sockhash", | ||
4566 | .insns = { | ||
4567 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
4568 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
4569 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
4570 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
4571 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
4572 | BPF_FUNC_map_lookup_elem), | ||
4573 | BPF_EXIT_INSN(), | ||
4574 | }, | ||
4575 | .fixup_map_sockhash = { 3 }, | ||
4576 | .result = REJECT, | ||
4577 | .errstr = "cannot pass map_type 18 into func bpf_map_lookup_elem", | ||
4578 | .prog_type = BPF_PROG_TYPE_SOCK_OPS, | ||
4579 | }, | ||
4580 | { | ||
4581 | "prevent map lookup in xskmap", | ||
4582 | .insns = { | ||
4583 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
4584 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
4585 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
4586 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
4587 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
4588 | BPF_FUNC_map_lookup_elem), | ||
4589 | BPF_EXIT_INSN(), | ||
4590 | }, | ||
4591 | .fixup_map_xskmap = { 3 }, | ||
4592 | .result = REJECT, | ||
4593 | .errstr = "cannot pass map_type 17 into func bpf_map_lookup_elem", | ||
4594 | .prog_type = BPF_PROG_TYPE_XDP, | ||
4595 | }, | ||
4596 | { | ||
4597 | "prevent map lookup in stack trace", | ||
4598 | .insns = { | ||
4599 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
4600 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
4601 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
4602 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
4603 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
4604 | BPF_FUNC_map_lookup_elem), | ||
4605 | BPF_EXIT_INSN(), | ||
4606 | }, | ||
4607 | .fixup_map_stacktrace = { 3 }, | ||
4608 | .result = REJECT, | ||
4609 | .errstr = "cannot pass map_type 7 into func bpf_map_lookup_elem", | ||
4610 | .prog_type = BPF_PROG_TYPE_PERF_EVENT, | ||
4611 | }, | ||
4612 | { | ||
4613 | "prevent map lookup in prog array", | ||
4614 | .insns = { | ||
4615 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
4616 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
4617 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
4618 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
4619 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
4620 | BPF_FUNC_map_lookup_elem), | ||
4621 | BPF_EXIT_INSN(), | ||
4622 | }, | ||
4623 | .fixup_prog2 = { 3 }, | ||
4624 | .result = REJECT, | ||
4625 | .errstr = "cannot pass map_type 3 into func bpf_map_lookup_elem", | ||
4626 | }, | ||
4627 | { | ||
4394 | "valid map access into an array with a constant", | 4628 | "valid map access into an array with a constant", |
4395 | .insns = { | 4629 | .insns = { |
4396 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | 4630 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), |
@@ -4404,7 +4638,7 @@ static struct bpf_test tests[] = { | |||
4404 | offsetof(struct test_val, foo)), | 4638 | offsetof(struct test_val, foo)), |
4405 | BPF_EXIT_INSN(), | 4639 | BPF_EXIT_INSN(), |
4406 | }, | 4640 | }, |
4407 | .fixup_map2 = { 3 }, | 4641 | .fixup_map_hash_48b = { 3 }, |
4408 | .errstr_unpriv = "R0 leaks addr", | 4642 | .errstr_unpriv = "R0 leaks addr", |
4409 | .result_unpriv = REJECT, | 4643 | .result_unpriv = REJECT, |
4410 | .result = ACCEPT, | 4644 | .result = ACCEPT, |
@@ -4426,7 +4660,7 @@ static struct bpf_test tests[] = { | |||
4426 | offsetof(struct test_val, foo)), | 4660 | offsetof(struct test_val, foo)), |
4427 | BPF_EXIT_INSN(), | 4661 | BPF_EXIT_INSN(), |
4428 | }, | 4662 | }, |
4429 | .fixup_map2 = { 3 }, | 4663 | .fixup_map_hash_48b = { 3 }, |
4430 | .errstr_unpriv = "R0 leaks addr", | 4664 | .errstr_unpriv = "R0 leaks addr", |
4431 | .result_unpriv = REJECT, | 4665 | .result_unpriv = REJECT, |
4432 | .result = ACCEPT, | 4666 | .result = ACCEPT, |
@@ -4450,7 +4684,7 @@ static struct bpf_test tests[] = { | |||
4450 | offsetof(struct test_val, foo)), | 4684 | offsetof(struct test_val, foo)), |
4451 | BPF_EXIT_INSN(), | 4685 | BPF_EXIT_INSN(), |
4452 | }, | 4686 | }, |
4453 | .fixup_map2 = { 3 }, | 4687 | .fixup_map_hash_48b = { 3 }, |
4454 | .errstr_unpriv = "R0 leaks addr", | 4688 | .errstr_unpriv = "R0 leaks addr", |
4455 | .result_unpriv = REJECT, | 4689 | .result_unpriv = REJECT, |
4456 | .result = ACCEPT, | 4690 | .result = ACCEPT, |
@@ -4478,7 +4712,7 @@ static struct bpf_test tests[] = { | |||
4478 | offsetof(struct test_val, foo)), | 4712 | offsetof(struct test_val, foo)), |
4479 | BPF_EXIT_INSN(), | 4713 | BPF_EXIT_INSN(), |
4480 | }, | 4714 | }, |
4481 | .fixup_map2 = { 3 }, | 4715 | .fixup_map_hash_48b = { 3 }, |
4482 | .errstr_unpriv = "R0 leaks addr", | 4716 | .errstr_unpriv = "R0 leaks addr", |
4483 | .result_unpriv = REJECT, | 4717 | .result_unpriv = REJECT, |
4484 | .result = ACCEPT, | 4718 | .result = ACCEPT, |
@@ -4498,7 +4732,7 @@ static struct bpf_test tests[] = { | |||
4498 | offsetof(struct test_val, foo)), | 4732 | offsetof(struct test_val, foo)), |
4499 | BPF_EXIT_INSN(), | 4733 | BPF_EXIT_INSN(), |
4500 | }, | 4734 | }, |
4501 | .fixup_map2 = { 3 }, | 4735 | .fixup_map_hash_48b = { 3 }, |
4502 | .errstr = "invalid access to map value, value_size=48 off=48 size=8", | 4736 | .errstr = "invalid access to map value, value_size=48 off=48 size=8", |
4503 | .result = REJECT, | 4737 | .result = REJECT, |
4504 | }, | 4738 | }, |
@@ -4519,7 +4753,7 @@ static struct bpf_test tests[] = { | |||
4519 | offsetof(struct test_val, foo)), | 4753 | offsetof(struct test_val, foo)), |
4520 | BPF_EXIT_INSN(), | 4754 | BPF_EXIT_INSN(), |
4521 | }, | 4755 | }, |
4522 | .fixup_map2 = { 3 }, | 4756 | .fixup_map_hash_48b = { 3 }, |
4523 | .errstr = "R0 min value is outside of the array range", | 4757 | .errstr = "R0 min value is outside of the array range", |
4524 | .result = REJECT, | 4758 | .result = REJECT, |
4525 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | 4759 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |
@@ -4541,7 +4775,7 @@ static struct bpf_test tests[] = { | |||
4541 | offsetof(struct test_val, foo)), | 4775 | offsetof(struct test_val, foo)), |
4542 | BPF_EXIT_INSN(), | 4776 | BPF_EXIT_INSN(), |
4543 | }, | 4777 | }, |
4544 | .fixup_map2 = { 3 }, | 4778 | .fixup_map_hash_48b = { 3 }, |
4545 | .errstr = "R0 unbounded memory access, make sure to bounds check any array access into a map", | 4779 | .errstr = "R0 unbounded memory access, make sure to bounds check any array access into a map", |
4546 | .result = REJECT, | 4780 | .result = REJECT, |
4547 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | 4781 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |
@@ -4566,7 +4800,7 @@ static struct bpf_test tests[] = { | |||
4566 | offsetof(struct test_val, foo)), | 4800 | offsetof(struct test_val, foo)), |
4567 | BPF_EXIT_INSN(), | 4801 | BPF_EXIT_INSN(), |
4568 | }, | 4802 | }, |
4569 | .fixup_map2 = { 3 }, | 4803 | .fixup_map_hash_48b = { 3 }, |
4570 | .errstr_unpriv = "R0 leaks addr", | 4804 | .errstr_unpriv = "R0 leaks addr", |
4571 | .errstr = "R0 unbounded memory access", | 4805 | .errstr = "R0 unbounded memory access", |
4572 | .result_unpriv = REJECT, | 4806 | .result_unpriv = REJECT, |
@@ -4593,7 +4827,7 @@ static struct bpf_test tests[] = { | |||
4593 | offsetof(struct test_val, foo)), | 4827 | offsetof(struct test_val, foo)), |
4594 | BPF_EXIT_INSN(), | 4828 | BPF_EXIT_INSN(), |
4595 | }, | 4829 | }, |
4596 | .fixup_map2 = { 3 }, | 4830 | .fixup_map_hash_48b = { 3 }, |
4597 | .errstr_unpriv = "R0 leaks addr", | 4831 | .errstr_unpriv = "R0 leaks addr", |
4598 | .errstr = "invalid access to map value, value_size=48 off=44 size=8", | 4832 | .errstr = "invalid access to map value, value_size=48 off=44 size=8", |
4599 | .result_unpriv = REJECT, | 4833 | .result_unpriv = REJECT, |
@@ -4623,12 +4857,183 @@ static struct bpf_test tests[] = { | |||
4623 | offsetof(struct test_val, foo)), | 4857 | offsetof(struct test_val, foo)), |
4624 | BPF_EXIT_INSN(), | 4858 | BPF_EXIT_INSN(), |
4625 | }, | 4859 | }, |
4626 | .fixup_map2 = { 3, 11 }, | 4860 | .fixup_map_hash_48b = { 3, 11 }, |
4627 | .errstr = "R0 pointer += pointer", | 4861 | .errstr = "R0 pointer += pointer", |
4628 | .result = REJECT, | 4862 | .result = REJECT, |
4629 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | 4863 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |
4630 | }, | 4864 | }, |
4631 | { | 4865 | { |
4866 | "direct packet read test#1 for CGROUP_SKB", | ||
4867 | .insns = { | ||
4868 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
4869 | offsetof(struct __sk_buff, data)), | ||
4870 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
4871 | offsetof(struct __sk_buff, data_end)), | ||
4872 | BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_1, | ||
4873 | offsetof(struct __sk_buff, len)), | ||
4874 | BPF_LDX_MEM(BPF_W, BPF_REG_5, BPF_REG_1, | ||
4875 | offsetof(struct __sk_buff, pkt_type)), | ||
4876 | BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, | ||
4877 | offsetof(struct __sk_buff, mark)), | ||
4878 | BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_6, | ||
4879 | offsetof(struct __sk_buff, mark)), | ||
4880 | BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_1, | ||
4881 | offsetof(struct __sk_buff, queue_mapping)), | ||
4882 | BPF_LDX_MEM(BPF_W, BPF_REG_8, BPF_REG_1, | ||
4883 | offsetof(struct __sk_buff, protocol)), | ||
4884 | BPF_LDX_MEM(BPF_W, BPF_REG_9, BPF_REG_1, | ||
4885 | offsetof(struct __sk_buff, vlan_present)), | ||
4886 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), | ||
4887 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), | ||
4888 | BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 1), | ||
4889 | BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_2, 0), | ||
4890 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
4891 | BPF_EXIT_INSN(), | ||
4892 | }, | ||
4893 | .result = ACCEPT, | ||
4894 | .prog_type = BPF_PROG_TYPE_CGROUP_SKB, | ||
4895 | }, | ||
4896 | { | ||
4897 | "direct packet read test#2 for CGROUP_SKB", | ||
4898 | .insns = { | ||
4899 | BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_1, | ||
4900 | offsetof(struct __sk_buff, vlan_tci)), | ||
4901 | BPF_LDX_MEM(BPF_W, BPF_REG_5, BPF_REG_1, | ||
4902 | offsetof(struct __sk_buff, vlan_proto)), | ||
4903 | BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, | ||
4904 | offsetof(struct __sk_buff, priority)), | ||
4905 | BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_6, | ||
4906 | offsetof(struct __sk_buff, priority)), | ||
4907 | BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_1, | ||
4908 | offsetof(struct __sk_buff, | ||
4909 | ingress_ifindex)), | ||
4910 | BPF_LDX_MEM(BPF_W, BPF_REG_8, BPF_REG_1, | ||
4911 | offsetof(struct __sk_buff, tc_index)), | ||
4912 | BPF_LDX_MEM(BPF_W, BPF_REG_9, BPF_REG_1, | ||
4913 | offsetof(struct __sk_buff, hash)), | ||
4914 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
4915 | BPF_EXIT_INSN(), | ||
4916 | }, | ||
4917 | .result = ACCEPT, | ||
4918 | .prog_type = BPF_PROG_TYPE_CGROUP_SKB, | ||
4919 | }, | ||
4920 | { | ||
4921 | "direct packet read test#3 for CGROUP_SKB", | ||
4922 | .insns = { | ||
4923 | BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_1, | ||
4924 | offsetof(struct __sk_buff, cb[0])), | ||
4925 | BPF_LDX_MEM(BPF_W, BPF_REG_5, BPF_REG_1, | ||
4926 | offsetof(struct __sk_buff, cb[1])), | ||
4927 | BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, | ||
4928 | offsetof(struct __sk_buff, cb[2])), | ||
4929 | BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_1, | ||
4930 | offsetof(struct __sk_buff, cb[3])), | ||
4931 | BPF_LDX_MEM(BPF_W, BPF_REG_8, BPF_REG_1, | ||
4932 | offsetof(struct __sk_buff, cb[4])), | ||
4933 | BPF_LDX_MEM(BPF_W, BPF_REG_9, BPF_REG_1, | ||
4934 | offsetof(struct __sk_buff, napi_id)), | ||
4935 | BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_4, | ||
4936 | offsetof(struct __sk_buff, cb[0])), | ||
4937 | BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_5, | ||
4938 | offsetof(struct __sk_buff, cb[1])), | ||
4939 | BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_6, | ||
4940 | offsetof(struct __sk_buff, cb[2])), | ||
4941 | BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_7, | ||
4942 | offsetof(struct __sk_buff, cb[3])), | ||
4943 | BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_8, | ||
4944 | offsetof(struct __sk_buff, cb[4])), | ||
4945 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
4946 | BPF_EXIT_INSN(), | ||
4947 | }, | ||
4948 | .result = ACCEPT, | ||
4949 | .prog_type = BPF_PROG_TYPE_CGROUP_SKB, | ||
4950 | }, | ||
4951 | { | ||
4952 | "direct packet read test#4 for CGROUP_SKB", | ||
4953 | .insns = { | ||
4954 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
4955 | offsetof(struct __sk_buff, family)), | ||
4956 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
4957 | offsetof(struct __sk_buff, remote_ip4)), | ||
4958 | BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_1, | ||
4959 | offsetof(struct __sk_buff, local_ip4)), | ||
4960 | BPF_LDX_MEM(BPF_W, BPF_REG_5, BPF_REG_1, | ||
4961 | offsetof(struct __sk_buff, remote_ip6[0])), | ||
4962 | BPF_LDX_MEM(BPF_W, BPF_REG_5, BPF_REG_1, | ||
4963 | offsetof(struct __sk_buff, remote_ip6[1])), | ||
4964 | BPF_LDX_MEM(BPF_W, BPF_REG_5, BPF_REG_1, | ||
4965 | offsetof(struct __sk_buff, remote_ip6[2])), | ||
4966 | BPF_LDX_MEM(BPF_W, BPF_REG_5, BPF_REG_1, | ||
4967 | offsetof(struct __sk_buff, remote_ip6[3])), | ||
4968 | BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, | ||
4969 | offsetof(struct __sk_buff, local_ip6[0])), | ||
4970 | BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, | ||
4971 | offsetof(struct __sk_buff, local_ip6[1])), | ||
4972 | BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, | ||
4973 | offsetof(struct __sk_buff, local_ip6[2])), | ||
4974 | BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, | ||
4975 | offsetof(struct __sk_buff, local_ip6[3])), | ||
4976 | BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_1, | ||
4977 | offsetof(struct __sk_buff, remote_port)), | ||
4978 | BPF_LDX_MEM(BPF_W, BPF_REG_8, BPF_REG_1, | ||
4979 | offsetof(struct __sk_buff, local_port)), | ||
4980 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
4981 | BPF_EXIT_INSN(), | ||
4982 | }, | ||
4983 | .result = ACCEPT, | ||
4984 | .prog_type = BPF_PROG_TYPE_CGROUP_SKB, | ||
4985 | }, | ||
4986 | { | ||
4987 | "invalid access of tc_classid for CGROUP_SKB", | ||
4988 | .insns = { | ||
4989 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | ||
4990 | offsetof(struct __sk_buff, tc_classid)), | ||
4991 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
4992 | BPF_EXIT_INSN(), | ||
4993 | }, | ||
4994 | .result = REJECT, | ||
4995 | .errstr = "invalid bpf_context access", | ||
4996 | .prog_type = BPF_PROG_TYPE_CGROUP_SKB, | ||
4997 | }, | ||
4998 | { | ||
4999 | "invalid access of data_meta for CGROUP_SKB", | ||
5000 | .insns = { | ||
5001 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | ||
5002 | offsetof(struct __sk_buff, data_meta)), | ||
5003 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
5004 | BPF_EXIT_INSN(), | ||
5005 | }, | ||
5006 | .result = REJECT, | ||
5007 | .errstr = "invalid bpf_context access", | ||
5008 | .prog_type = BPF_PROG_TYPE_CGROUP_SKB, | ||
5009 | }, | ||
5010 | { | ||
5011 | "invalid access of flow_keys for CGROUP_SKB", | ||
5012 | .insns = { | ||
5013 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | ||
5014 | offsetof(struct __sk_buff, flow_keys)), | ||
5015 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
5016 | BPF_EXIT_INSN(), | ||
5017 | }, | ||
5018 | .result = REJECT, | ||
5019 | .errstr = "invalid bpf_context access", | ||
5020 | .prog_type = BPF_PROG_TYPE_CGROUP_SKB, | ||
5021 | }, | ||
5022 | { | ||
5023 | "invalid write access to napi_id for CGROUP_SKB", | ||
5024 | .insns = { | ||
5025 | BPF_LDX_MEM(BPF_W, BPF_REG_9, BPF_REG_1, | ||
5026 | offsetof(struct __sk_buff, napi_id)), | ||
5027 | BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_9, | ||
5028 | offsetof(struct __sk_buff, napi_id)), | ||
5029 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
5030 | BPF_EXIT_INSN(), | ||
5031 | }, | ||
5032 | .result = REJECT, | ||
5033 | .errstr = "invalid bpf_context access", | ||
5034 | .prog_type = BPF_PROG_TYPE_CGROUP_SKB, | ||
5035 | }, | ||
5036 | { | ||
4632 | "valid cgroup storage access", | 5037 | "valid cgroup storage access", |
4633 | .insns = { | 5038 | .insns = { |
4634 | BPF_MOV64_IMM(BPF_REG_2, 0), | 5039 | BPF_MOV64_IMM(BPF_REG_2, 0), |
@@ -4656,7 +5061,7 @@ static struct bpf_test tests[] = { | |||
4656 | BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1), | 5061 | BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1), |
4657 | BPF_EXIT_INSN(), | 5062 | BPF_EXIT_INSN(), |
4658 | }, | 5063 | }, |
4659 | .fixup_map1 = { 1 }, | 5064 | .fixup_map_hash_8b = { 1 }, |
4660 | .result = REJECT, | 5065 | .result = REJECT, |
4661 | .errstr = "cannot pass map_type 1 into func bpf_get_local_storage", | 5066 | .errstr = "cannot pass map_type 1 into func bpf_get_local_storage", |
4662 | .prog_type = BPF_PROG_TYPE_CGROUP_SKB, | 5067 | .prog_type = BPF_PROG_TYPE_CGROUP_SKB, |
@@ -4676,7 +5081,7 @@ static struct bpf_test tests[] = { | |||
4676 | .prog_type = BPF_PROG_TYPE_CGROUP_SKB, | 5081 | .prog_type = BPF_PROG_TYPE_CGROUP_SKB, |
4677 | }, | 5082 | }, |
4678 | { | 5083 | { |
4679 | "invalid per-cgroup storage access 3", | 5084 | "invalid cgroup storage access 3", |
4680 | .insns = { | 5085 | .insns = { |
4681 | BPF_MOV64_IMM(BPF_REG_2, 0), | 5086 | BPF_MOV64_IMM(BPF_REG_2, 0), |
4682 | BPF_LD_MAP_FD(BPF_REG_1, 0), | 5087 | BPF_LD_MAP_FD(BPF_REG_1, 0), |
@@ -4744,6 +5149,121 @@ static struct bpf_test tests[] = { | |||
4744 | .prog_type = BPF_PROG_TYPE_CGROUP_SKB, | 5149 | .prog_type = BPF_PROG_TYPE_CGROUP_SKB, |
4745 | }, | 5150 | }, |
4746 | { | 5151 | { |
5152 | "valid per-cpu cgroup storage access", | ||
5153 | .insns = { | ||
5154 | BPF_MOV64_IMM(BPF_REG_2, 0), | ||
5155 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
5156 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
5157 | BPF_FUNC_get_local_storage), | ||
5158 | BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0), | ||
5159 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_1), | ||
5160 | BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1), | ||
5161 | BPF_EXIT_INSN(), | ||
5162 | }, | ||
5163 | .fixup_percpu_cgroup_storage = { 1 }, | ||
5164 | .result = ACCEPT, | ||
5165 | .prog_type = BPF_PROG_TYPE_CGROUP_SKB, | ||
5166 | }, | ||
5167 | { | ||
5168 | "invalid per-cpu cgroup storage access 1", | ||
5169 | .insns = { | ||
5170 | BPF_MOV64_IMM(BPF_REG_2, 0), | ||
5171 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
5172 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
5173 | BPF_FUNC_get_local_storage), | ||
5174 | BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0), | ||
5175 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_1), | ||
5176 | BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1), | ||
5177 | BPF_EXIT_INSN(), | ||
5178 | }, | ||
5179 | .fixup_map_hash_8b = { 1 }, | ||
5180 | .result = REJECT, | ||
5181 | .errstr = "cannot pass map_type 1 into func bpf_get_local_storage", | ||
5182 | .prog_type = BPF_PROG_TYPE_CGROUP_SKB, | ||
5183 | }, | ||
5184 | { | ||
5185 | "invalid per-cpu cgroup storage access 2", | ||
5186 | .insns = { | ||
5187 | BPF_MOV64_IMM(BPF_REG_2, 0), | ||
5188 | BPF_LD_MAP_FD(BPF_REG_1, 1), | ||
5189 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
5190 | BPF_FUNC_get_local_storage), | ||
5191 | BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1), | ||
5192 | BPF_EXIT_INSN(), | ||
5193 | }, | ||
5194 | .result = REJECT, | ||
5195 | .errstr = "fd 1 is not pointing to valid bpf_map", | ||
5196 | .prog_type = BPF_PROG_TYPE_CGROUP_SKB, | ||
5197 | }, | ||
5198 | { | ||
5199 | "invalid per-cpu cgroup storage access 3", | ||
5200 | .insns = { | ||
5201 | BPF_MOV64_IMM(BPF_REG_2, 0), | ||
5202 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
5203 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
5204 | BPF_FUNC_get_local_storage), | ||
5205 | BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 256), | ||
5206 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 1), | ||
5207 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
5208 | BPF_EXIT_INSN(), | ||
5209 | }, | ||
5210 | .fixup_percpu_cgroup_storage = { 1 }, | ||
5211 | .result = REJECT, | ||
5212 | .errstr = "invalid access to map value, value_size=64 off=256 size=4", | ||
5213 | .prog_type = BPF_PROG_TYPE_CGROUP_SKB, | ||
5214 | }, | ||
5215 | { | ||
5216 | "invalid per-cpu cgroup storage access 4", | ||
5217 | .insns = { | ||
5218 | BPF_MOV64_IMM(BPF_REG_2, 0), | ||
5219 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
5220 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
5221 | BPF_FUNC_get_local_storage), | ||
5222 | BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, -2), | ||
5223 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_1), | ||
5224 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 1), | ||
5225 | BPF_EXIT_INSN(), | ||
5226 | }, | ||
5227 | .fixup_cgroup_storage = { 1 }, | ||
5228 | .result = REJECT, | ||
5229 | .errstr = "invalid access to map value, value_size=64 off=-2 size=4", | ||
5230 | .prog_type = BPF_PROG_TYPE_CGROUP_SKB, | ||
5231 | }, | ||
5232 | { | ||
5233 | "invalid per-cpu cgroup storage access 5", | ||
5234 | .insns = { | ||
5235 | BPF_MOV64_IMM(BPF_REG_2, 7), | ||
5236 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
5237 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
5238 | BPF_FUNC_get_local_storage), | ||
5239 | BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0), | ||
5240 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_1), | ||
5241 | BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1), | ||
5242 | BPF_EXIT_INSN(), | ||
5243 | }, | ||
5244 | .fixup_percpu_cgroup_storage = { 1 }, | ||
5245 | .result = REJECT, | ||
5246 | .errstr = "get_local_storage() doesn't support non-zero flags", | ||
5247 | .prog_type = BPF_PROG_TYPE_CGROUP_SKB, | ||
5248 | }, | ||
5249 | { | ||
5250 | "invalid per-cpu cgroup storage access 6", | ||
5251 | .insns = { | ||
5252 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_1), | ||
5253 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
5254 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
5255 | BPF_FUNC_get_local_storage), | ||
5256 | BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0), | ||
5257 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_1), | ||
5258 | BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1), | ||
5259 | BPF_EXIT_INSN(), | ||
5260 | }, | ||
5261 | .fixup_percpu_cgroup_storage = { 1 }, | ||
5262 | .result = REJECT, | ||
5263 | .errstr = "get_local_storage() doesn't support non-zero flags", | ||
5264 | .prog_type = BPF_PROG_TYPE_CGROUP_SKB, | ||
5265 | }, | ||
5266 | { | ||
4747 | "multiple registers share map_lookup_elem result", | 5267 | "multiple registers share map_lookup_elem result", |
4748 | .insns = { | 5268 | .insns = { |
4749 | BPF_MOV64_IMM(BPF_REG_1, 10), | 5269 | BPF_MOV64_IMM(BPF_REG_1, 10), |
@@ -4758,7 +5278,7 @@ static struct bpf_test tests[] = { | |||
4758 | BPF_ST_MEM(BPF_DW, BPF_REG_4, 0, 0), | 5278 | BPF_ST_MEM(BPF_DW, BPF_REG_4, 0, 0), |
4759 | BPF_EXIT_INSN(), | 5279 | BPF_EXIT_INSN(), |
4760 | }, | 5280 | }, |
4761 | .fixup_map1 = { 4 }, | 5281 | .fixup_map_hash_8b = { 4 }, |
4762 | .result = ACCEPT, | 5282 | .result = ACCEPT, |
4763 | .prog_type = BPF_PROG_TYPE_SCHED_CLS | 5283 | .prog_type = BPF_PROG_TYPE_SCHED_CLS |
4764 | }, | 5284 | }, |
@@ -4779,8 +5299,8 @@ static struct bpf_test tests[] = { | |||
4779 | BPF_ST_MEM(BPF_DW, BPF_REG_4, 0, 0), | 5299 | BPF_ST_MEM(BPF_DW, BPF_REG_4, 0, 0), |
4780 | BPF_EXIT_INSN(), | 5300 | BPF_EXIT_INSN(), |
4781 | }, | 5301 | }, |
4782 | .fixup_map1 = { 4 }, | 5302 | .fixup_map_hash_8b = { 4 }, |
4783 | .errstr = "R4 pointer arithmetic on PTR_TO_MAP_VALUE_OR_NULL", | 5303 | .errstr = "R4 pointer arithmetic on map_value_or_null", |
4784 | .result = REJECT, | 5304 | .result = REJECT, |
4785 | .prog_type = BPF_PROG_TYPE_SCHED_CLS | 5305 | .prog_type = BPF_PROG_TYPE_SCHED_CLS |
4786 | }, | 5306 | }, |
@@ -4800,8 +5320,8 @@ static struct bpf_test tests[] = { | |||
4800 | BPF_ST_MEM(BPF_DW, BPF_REG_4, 0, 0), | 5320 | BPF_ST_MEM(BPF_DW, BPF_REG_4, 0, 0), |
4801 | BPF_EXIT_INSN(), | 5321 | BPF_EXIT_INSN(), |
4802 | }, | 5322 | }, |
4803 | .fixup_map1 = { 4 }, | 5323 | .fixup_map_hash_8b = { 4 }, |
4804 | .errstr = "R4 pointer arithmetic on PTR_TO_MAP_VALUE_OR_NULL", | 5324 | .errstr = "R4 pointer arithmetic on map_value_or_null", |
4805 | .result = REJECT, | 5325 | .result = REJECT, |
4806 | .prog_type = BPF_PROG_TYPE_SCHED_CLS | 5326 | .prog_type = BPF_PROG_TYPE_SCHED_CLS |
4807 | }, | 5327 | }, |
@@ -4821,8 +5341,8 @@ static struct bpf_test tests[] = { | |||
4821 | BPF_ST_MEM(BPF_DW, BPF_REG_4, 0, 0), | 5341 | BPF_ST_MEM(BPF_DW, BPF_REG_4, 0, 0), |
4822 | BPF_EXIT_INSN(), | 5342 | BPF_EXIT_INSN(), |
4823 | }, | 5343 | }, |
4824 | .fixup_map1 = { 4 }, | 5344 | .fixup_map_hash_8b = { 4 }, |
4825 | .errstr = "R4 pointer arithmetic on PTR_TO_MAP_VALUE_OR_NULL", | 5345 | .errstr = "R4 pointer arithmetic on map_value_or_null", |
4826 | .result = REJECT, | 5346 | .result = REJECT, |
4827 | .prog_type = BPF_PROG_TYPE_SCHED_CLS | 5347 | .prog_type = BPF_PROG_TYPE_SCHED_CLS |
4828 | }, | 5348 | }, |
@@ -4847,7 +5367,7 @@ static struct bpf_test tests[] = { | |||
4847 | BPF_ST_MEM(BPF_DW, BPF_REG_4, 0, 0), | 5367 | BPF_ST_MEM(BPF_DW, BPF_REG_4, 0, 0), |
4848 | BPF_EXIT_INSN(), | 5368 | BPF_EXIT_INSN(), |
4849 | }, | 5369 | }, |
4850 | .fixup_map1 = { 4 }, | 5370 | .fixup_map_hash_8b = { 4 }, |
4851 | .result = REJECT, | 5371 | .result = REJECT, |
4852 | .errstr = "R4 !read_ok", | 5372 | .errstr = "R4 !read_ok", |
4853 | .prog_type = BPF_PROG_TYPE_SCHED_CLS | 5373 | .prog_type = BPF_PROG_TYPE_SCHED_CLS |
@@ -4875,7 +5395,7 @@ static struct bpf_test tests[] = { | |||
4875 | BPF_ST_MEM(BPF_DW, BPF_REG_4, 0, 0), | 5395 | BPF_ST_MEM(BPF_DW, BPF_REG_4, 0, 0), |
4876 | BPF_EXIT_INSN(), | 5396 | BPF_EXIT_INSN(), |
4877 | }, | 5397 | }, |
4878 | .fixup_map1 = { 4 }, | 5398 | .fixup_map_hash_8b = { 4 }, |
4879 | .result = ACCEPT, | 5399 | .result = ACCEPT, |
4880 | .prog_type = BPF_PROG_TYPE_SCHED_CLS | 5400 | .prog_type = BPF_PROG_TYPE_SCHED_CLS |
4881 | }, | 5401 | }, |
@@ -4896,7 +5416,7 @@ static struct bpf_test tests[] = { | |||
4896 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, offsetof(struct test_val, foo)), | 5416 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, offsetof(struct test_val, foo)), |
4897 | BPF_EXIT_INSN(), | 5417 | BPF_EXIT_INSN(), |
4898 | }, | 5418 | }, |
4899 | .fixup_map2 = { 3 }, | 5419 | .fixup_map_hash_48b = { 3 }, |
4900 | .errstr = "R0 unbounded memory access", | 5420 | .errstr = "R0 unbounded memory access", |
4901 | .result = REJECT, | 5421 | .result = REJECT, |
4902 | .errstr_unpriv = "R0 leaks addr", | 5422 | .errstr_unpriv = "R0 leaks addr", |
@@ -5146,11 +5666,11 @@ static struct bpf_test tests[] = { | |||
5146 | offsetof(struct __sk_buff, cb[0])), | 5666 | offsetof(struct __sk_buff, cb[0])), |
5147 | BPF_EXIT_INSN(), | 5667 | BPF_EXIT_INSN(), |
5148 | }, | 5668 | }, |
5149 | .fixup_map1 = { 2 }, | 5669 | .fixup_map_hash_8b = { 2 }, |
5150 | .errstr_unpriv = "R2 leaks addr into mem", | 5670 | .errstr_unpriv = "R2 leaks addr into mem", |
5151 | .result_unpriv = REJECT, | 5671 | .result_unpriv = REJECT, |
5152 | .result = REJECT, | 5672 | .result = REJECT, |
5153 | .errstr = "BPF_XADD stores into R1 context is not allowed", | 5673 | .errstr = "BPF_XADD stores into R1 ctx is not allowed", |
5154 | }, | 5674 | }, |
5155 | { | 5675 | { |
5156 | "leak pointer into ctx 2", | 5676 | "leak pointer into ctx 2", |
@@ -5165,7 +5685,7 @@ static struct bpf_test tests[] = { | |||
5165 | .errstr_unpriv = "R10 leaks addr into mem", | 5685 | .errstr_unpriv = "R10 leaks addr into mem", |
5166 | .result_unpriv = REJECT, | 5686 | .result_unpriv = REJECT, |
5167 | .result = REJECT, | 5687 | .result = REJECT, |
5168 | .errstr = "BPF_XADD stores into R1 context is not allowed", | 5688 | .errstr = "BPF_XADD stores into R1 ctx is not allowed", |
5169 | }, | 5689 | }, |
5170 | { | 5690 | { |
5171 | "leak pointer into ctx 3", | 5691 | "leak pointer into ctx 3", |
@@ -5176,7 +5696,7 @@ static struct bpf_test tests[] = { | |||
5176 | offsetof(struct __sk_buff, cb[0])), | 5696 | offsetof(struct __sk_buff, cb[0])), |
5177 | BPF_EXIT_INSN(), | 5697 | BPF_EXIT_INSN(), |
5178 | }, | 5698 | }, |
5179 | .fixup_map1 = { 1 }, | 5699 | .fixup_map_hash_8b = { 1 }, |
5180 | .errstr_unpriv = "R2 leaks addr into ctx", | 5700 | .errstr_unpriv = "R2 leaks addr into ctx", |
5181 | .result_unpriv = REJECT, | 5701 | .result_unpriv = REJECT, |
5182 | .result = ACCEPT, | 5702 | .result = ACCEPT, |
@@ -5198,7 +5718,7 @@ static struct bpf_test tests[] = { | |||
5198 | BPF_MOV64_IMM(BPF_REG_0, 0), | 5718 | BPF_MOV64_IMM(BPF_REG_0, 0), |
5199 | BPF_EXIT_INSN(), | 5719 | BPF_EXIT_INSN(), |
5200 | }, | 5720 | }, |
5201 | .fixup_map1 = { 4 }, | 5721 | .fixup_map_hash_8b = { 4 }, |
5202 | .errstr_unpriv = "R6 leaks addr into mem", | 5722 | .errstr_unpriv = "R6 leaks addr into mem", |
5203 | .result_unpriv = REJECT, | 5723 | .result_unpriv = REJECT, |
5204 | .result = ACCEPT, | 5724 | .result = ACCEPT, |
@@ -5218,7 +5738,7 @@ static struct bpf_test tests[] = { | |||
5218 | BPF_EMIT_CALL(BPF_FUNC_probe_read), | 5738 | BPF_EMIT_CALL(BPF_FUNC_probe_read), |
5219 | BPF_EXIT_INSN(), | 5739 | BPF_EXIT_INSN(), |
5220 | }, | 5740 | }, |
5221 | .fixup_map2 = { 3 }, | 5741 | .fixup_map_hash_48b = { 3 }, |
5222 | .result = ACCEPT, | 5742 | .result = ACCEPT, |
5223 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 5743 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
5224 | }, | 5744 | }, |
@@ -5237,7 +5757,7 @@ static struct bpf_test tests[] = { | |||
5237 | BPF_EMIT_CALL(BPF_FUNC_probe_read), | 5757 | BPF_EMIT_CALL(BPF_FUNC_probe_read), |
5238 | BPF_EXIT_INSN(), | 5758 | BPF_EXIT_INSN(), |
5239 | }, | 5759 | }, |
5240 | .fixup_map2 = { 3 }, | 5760 | .fixup_map_hash_48b = { 3 }, |
5241 | .result = ACCEPT, | 5761 | .result = ACCEPT, |
5242 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 5762 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
5243 | }, | 5763 | }, |
@@ -5255,7 +5775,7 @@ static struct bpf_test tests[] = { | |||
5255 | BPF_EMIT_CALL(BPF_FUNC_trace_printk), | 5775 | BPF_EMIT_CALL(BPF_FUNC_trace_printk), |
5256 | BPF_EXIT_INSN(), | 5776 | BPF_EXIT_INSN(), |
5257 | }, | 5777 | }, |
5258 | .fixup_map2 = { 3 }, | 5778 | .fixup_map_hash_48b = { 3 }, |
5259 | .errstr = "invalid access to map value, value_size=48 off=0 size=0", | 5779 | .errstr = "invalid access to map value, value_size=48 off=0 size=0", |
5260 | .result = REJECT, | 5780 | .result = REJECT, |
5261 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 5781 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
@@ -5275,7 +5795,7 @@ static struct bpf_test tests[] = { | |||
5275 | BPF_EMIT_CALL(BPF_FUNC_probe_read), | 5795 | BPF_EMIT_CALL(BPF_FUNC_probe_read), |
5276 | BPF_EXIT_INSN(), | 5796 | BPF_EXIT_INSN(), |
5277 | }, | 5797 | }, |
5278 | .fixup_map2 = { 3 }, | 5798 | .fixup_map_hash_48b = { 3 }, |
5279 | .errstr = "invalid access to map value, value_size=48 off=0 size=56", | 5799 | .errstr = "invalid access to map value, value_size=48 off=0 size=56", |
5280 | .result = REJECT, | 5800 | .result = REJECT, |
5281 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 5801 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
@@ -5295,7 +5815,7 @@ static struct bpf_test tests[] = { | |||
5295 | BPF_EMIT_CALL(BPF_FUNC_probe_read), | 5815 | BPF_EMIT_CALL(BPF_FUNC_probe_read), |
5296 | BPF_EXIT_INSN(), | 5816 | BPF_EXIT_INSN(), |
5297 | }, | 5817 | }, |
5298 | .fixup_map2 = { 3 }, | 5818 | .fixup_map_hash_48b = { 3 }, |
5299 | .errstr = "R2 min value is negative", | 5819 | .errstr = "R2 min value is negative", |
5300 | .result = REJECT, | 5820 | .result = REJECT, |
5301 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 5821 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
@@ -5319,7 +5839,7 @@ static struct bpf_test tests[] = { | |||
5319 | BPF_EMIT_CALL(BPF_FUNC_probe_read), | 5839 | BPF_EMIT_CALL(BPF_FUNC_probe_read), |
5320 | BPF_EXIT_INSN(), | 5840 | BPF_EXIT_INSN(), |
5321 | }, | 5841 | }, |
5322 | .fixup_map2 = { 3 }, | 5842 | .fixup_map_hash_48b = { 3 }, |
5323 | .result = ACCEPT, | 5843 | .result = ACCEPT, |
5324 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 5844 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
5325 | }, | 5845 | }, |
@@ -5340,7 +5860,7 @@ static struct bpf_test tests[] = { | |||
5340 | BPF_EMIT_CALL(BPF_FUNC_probe_read), | 5860 | BPF_EMIT_CALL(BPF_FUNC_probe_read), |
5341 | BPF_EXIT_INSN(), | 5861 | BPF_EXIT_INSN(), |
5342 | }, | 5862 | }, |
5343 | .fixup_map2 = { 3 }, | 5863 | .fixup_map_hash_48b = { 3 }, |
5344 | .result = ACCEPT, | 5864 | .result = ACCEPT, |
5345 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 5865 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
5346 | }, | 5866 | }, |
@@ -5360,7 +5880,7 @@ static struct bpf_test tests[] = { | |||
5360 | BPF_EMIT_CALL(BPF_FUNC_trace_printk), | 5880 | BPF_EMIT_CALL(BPF_FUNC_trace_printk), |
5361 | BPF_EXIT_INSN(), | 5881 | BPF_EXIT_INSN(), |
5362 | }, | 5882 | }, |
5363 | .fixup_map2 = { 3 }, | 5883 | .fixup_map_hash_48b = { 3 }, |
5364 | .errstr = "invalid access to map value, value_size=48 off=4 size=0", | 5884 | .errstr = "invalid access to map value, value_size=48 off=4 size=0", |
5365 | .result = REJECT, | 5885 | .result = REJECT, |
5366 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 5886 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
@@ -5384,7 +5904,7 @@ static struct bpf_test tests[] = { | |||
5384 | BPF_EMIT_CALL(BPF_FUNC_probe_read), | 5904 | BPF_EMIT_CALL(BPF_FUNC_probe_read), |
5385 | BPF_EXIT_INSN(), | 5905 | BPF_EXIT_INSN(), |
5386 | }, | 5906 | }, |
5387 | .fixup_map2 = { 3 }, | 5907 | .fixup_map_hash_48b = { 3 }, |
5388 | .errstr = "invalid access to map value, value_size=48 off=4 size=52", | 5908 | .errstr = "invalid access to map value, value_size=48 off=4 size=52", |
5389 | .result = REJECT, | 5909 | .result = REJECT, |
5390 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 5910 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
@@ -5406,7 +5926,7 @@ static struct bpf_test tests[] = { | |||
5406 | BPF_EMIT_CALL(BPF_FUNC_probe_read), | 5926 | BPF_EMIT_CALL(BPF_FUNC_probe_read), |
5407 | BPF_EXIT_INSN(), | 5927 | BPF_EXIT_INSN(), |
5408 | }, | 5928 | }, |
5409 | .fixup_map2 = { 3 }, | 5929 | .fixup_map_hash_48b = { 3 }, |
5410 | .errstr = "R2 min value is negative", | 5930 | .errstr = "R2 min value is negative", |
5411 | .result = REJECT, | 5931 | .result = REJECT, |
5412 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 5932 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
@@ -5428,7 +5948,7 @@ static struct bpf_test tests[] = { | |||
5428 | BPF_EMIT_CALL(BPF_FUNC_probe_read), | 5948 | BPF_EMIT_CALL(BPF_FUNC_probe_read), |
5429 | BPF_EXIT_INSN(), | 5949 | BPF_EXIT_INSN(), |
5430 | }, | 5950 | }, |
5431 | .fixup_map2 = { 3 }, | 5951 | .fixup_map_hash_48b = { 3 }, |
5432 | .errstr = "R2 min value is negative", | 5952 | .errstr = "R2 min value is negative", |
5433 | .result = REJECT, | 5953 | .result = REJECT, |
5434 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 5954 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
@@ -5453,7 +5973,7 @@ static struct bpf_test tests[] = { | |||
5453 | BPF_EMIT_CALL(BPF_FUNC_probe_read), | 5973 | BPF_EMIT_CALL(BPF_FUNC_probe_read), |
5454 | BPF_EXIT_INSN(), | 5974 | BPF_EXIT_INSN(), |
5455 | }, | 5975 | }, |
5456 | .fixup_map2 = { 3 }, | 5976 | .fixup_map_hash_48b = { 3 }, |
5457 | .result = ACCEPT, | 5977 | .result = ACCEPT, |
5458 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 5978 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
5459 | }, | 5979 | }, |
@@ -5475,7 +5995,7 @@ static struct bpf_test tests[] = { | |||
5475 | BPF_EMIT_CALL(BPF_FUNC_probe_read), | 5995 | BPF_EMIT_CALL(BPF_FUNC_probe_read), |
5476 | BPF_EXIT_INSN(), | 5996 | BPF_EXIT_INSN(), |
5477 | }, | 5997 | }, |
5478 | .fixup_map2 = { 3 }, | 5998 | .fixup_map_hash_48b = { 3 }, |
5479 | .result = ACCEPT, | 5999 | .result = ACCEPT, |
5480 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 6000 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
5481 | }, | 6001 | }, |
@@ -5495,7 +6015,7 @@ static struct bpf_test tests[] = { | |||
5495 | BPF_EMIT_CALL(BPF_FUNC_trace_printk), | 6015 | BPF_EMIT_CALL(BPF_FUNC_trace_printk), |
5496 | BPF_EXIT_INSN(), | 6016 | BPF_EXIT_INSN(), |
5497 | }, | 6017 | }, |
5498 | .fixup_map2 = { 3 }, | 6018 | .fixup_map_hash_48b = { 3 }, |
5499 | .errstr = "R1 min value is outside of the array range", | 6019 | .errstr = "R1 min value is outside of the array range", |
5500 | .result = REJECT, | 6020 | .result = REJECT, |
5501 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 6021 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
@@ -5520,7 +6040,7 @@ static struct bpf_test tests[] = { | |||
5520 | BPF_EMIT_CALL(BPF_FUNC_probe_read), | 6040 | BPF_EMIT_CALL(BPF_FUNC_probe_read), |
5521 | BPF_EXIT_INSN(), | 6041 | BPF_EXIT_INSN(), |
5522 | }, | 6042 | }, |
5523 | .fixup_map2 = { 3 }, | 6043 | .fixup_map_hash_48b = { 3 }, |
5524 | .errstr = "invalid access to map value, value_size=48 off=4 size=52", | 6044 | .errstr = "invalid access to map value, value_size=48 off=4 size=52", |
5525 | .result = REJECT, | 6045 | .result = REJECT, |
5526 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 6046 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
@@ -5543,7 +6063,7 @@ static struct bpf_test tests[] = { | |||
5543 | BPF_EMIT_CALL(BPF_FUNC_probe_read), | 6063 | BPF_EMIT_CALL(BPF_FUNC_probe_read), |
5544 | BPF_EXIT_INSN(), | 6064 | BPF_EXIT_INSN(), |
5545 | }, | 6065 | }, |
5546 | .fixup_map2 = { 3 }, | 6066 | .fixup_map_hash_48b = { 3 }, |
5547 | .errstr = "R2 min value is negative", | 6067 | .errstr = "R2 min value is negative", |
5548 | .result = REJECT, | 6068 | .result = REJECT, |
5549 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 6069 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
@@ -5566,7 +6086,7 @@ static struct bpf_test tests[] = { | |||
5566 | BPF_EMIT_CALL(BPF_FUNC_probe_read), | 6086 | BPF_EMIT_CALL(BPF_FUNC_probe_read), |
5567 | BPF_EXIT_INSN(), | 6087 | BPF_EXIT_INSN(), |
5568 | }, | 6088 | }, |
5569 | .fixup_map2 = { 3 }, | 6089 | .fixup_map_hash_48b = { 3 }, |
5570 | .errstr = "R2 min value is negative", | 6090 | .errstr = "R2 min value is negative", |
5571 | .result = REJECT, | 6091 | .result = REJECT, |
5572 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 6092 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
@@ -5592,7 +6112,7 @@ static struct bpf_test tests[] = { | |||
5592 | BPF_EMIT_CALL(BPF_FUNC_probe_read), | 6112 | BPF_EMIT_CALL(BPF_FUNC_probe_read), |
5593 | BPF_EXIT_INSN(), | 6113 | BPF_EXIT_INSN(), |
5594 | }, | 6114 | }, |
5595 | .fixup_map2 = { 3 }, | 6115 | .fixup_map_hash_48b = { 3 }, |
5596 | .result = ACCEPT, | 6116 | .result = ACCEPT, |
5597 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 6117 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
5598 | }, | 6118 | }, |
@@ -5615,7 +6135,7 @@ static struct bpf_test tests[] = { | |||
5615 | BPF_EMIT_CALL(BPF_FUNC_probe_read), | 6135 | BPF_EMIT_CALL(BPF_FUNC_probe_read), |
5616 | BPF_EXIT_INSN(), | 6136 | BPF_EXIT_INSN(), |
5617 | }, | 6137 | }, |
5618 | .fixup_map2 = { 3 }, | 6138 | .fixup_map_hash_48b = { 3 }, |
5619 | .result = ACCEPT, | 6139 | .result = ACCEPT, |
5620 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 6140 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
5621 | }, | 6141 | }, |
@@ -5637,7 +6157,7 @@ static struct bpf_test tests[] = { | |||
5637 | BPF_EMIT_CALL(BPF_FUNC_trace_printk), | 6157 | BPF_EMIT_CALL(BPF_FUNC_trace_printk), |
5638 | BPF_EXIT_INSN(), | 6158 | BPF_EXIT_INSN(), |
5639 | }, | 6159 | }, |
5640 | .fixup_map2 = { 3 }, | 6160 | .fixup_map_hash_48b = { 3 }, |
5641 | .errstr = "R1 min value is outside of the array range", | 6161 | .errstr = "R1 min value is outside of the array range", |
5642 | .result = REJECT, | 6162 | .result = REJECT, |
5643 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 6163 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
@@ -5659,7 +6179,7 @@ static struct bpf_test tests[] = { | |||
5659 | BPF_EMIT_CALL(BPF_FUNC_probe_read), | 6179 | BPF_EMIT_CALL(BPF_FUNC_probe_read), |
5660 | BPF_EXIT_INSN(), | 6180 | BPF_EXIT_INSN(), |
5661 | }, | 6181 | }, |
5662 | .fixup_map2 = { 3 }, | 6182 | .fixup_map_hash_48b = { 3 }, |
5663 | .errstr = "R1 unbounded memory access", | 6183 | .errstr = "R1 unbounded memory access", |
5664 | .result = REJECT, | 6184 | .result = REJECT, |
5665 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 6185 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
@@ -5685,7 +6205,7 @@ static struct bpf_test tests[] = { | |||
5685 | BPF_EMIT_CALL(BPF_FUNC_probe_read), | 6205 | BPF_EMIT_CALL(BPF_FUNC_probe_read), |
5686 | BPF_EXIT_INSN(), | 6206 | BPF_EXIT_INSN(), |
5687 | }, | 6207 | }, |
5688 | .fixup_map2 = { 3 }, | 6208 | .fixup_map_hash_48b = { 3 }, |
5689 | .errstr = "invalid access to map value, value_size=48 off=4 size=45", | 6209 | .errstr = "invalid access to map value, value_size=48 off=4 size=45", |
5690 | .result = REJECT, | 6210 | .result = REJECT, |
5691 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 6211 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
@@ -5709,7 +6229,7 @@ static struct bpf_test tests[] = { | |||
5709 | BPF_MOV64_IMM(BPF_REG_0, 0), | 6229 | BPF_MOV64_IMM(BPF_REG_0, 0), |
5710 | BPF_EXIT_INSN(), | 6230 | BPF_EXIT_INSN(), |
5711 | }, | 6231 | }, |
5712 | .fixup_map2 = { 3 }, | 6232 | .fixup_map_hash_48b = { 3 }, |
5713 | .result = ACCEPT, | 6233 | .result = ACCEPT, |
5714 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 6234 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
5715 | }, | 6235 | }, |
@@ -5732,7 +6252,7 @@ static struct bpf_test tests[] = { | |||
5732 | BPF_MOV64_IMM(BPF_REG_0, 0), | 6252 | BPF_MOV64_IMM(BPF_REG_0, 0), |
5733 | BPF_EXIT_INSN(), | 6253 | BPF_EXIT_INSN(), |
5734 | }, | 6254 | }, |
5735 | .fixup_map2 = { 3 }, | 6255 | .fixup_map_hash_48b = { 3 }, |
5736 | .result = REJECT, | 6256 | .result = REJECT, |
5737 | .errstr = "R1 unbounded memory access", | 6257 | .errstr = "R1 unbounded memory access", |
5738 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 6258 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
@@ -5756,7 +6276,7 @@ static struct bpf_test tests[] = { | |||
5756 | BPF_MOV64_IMM(BPF_REG_0, 0), | 6276 | BPF_MOV64_IMM(BPF_REG_0, 0), |
5757 | BPF_EXIT_INSN(), | 6277 | BPF_EXIT_INSN(), |
5758 | }, | 6278 | }, |
5759 | .fixup_map2 = { 3 }, | 6279 | .fixup_map_hash_48b = { 3 }, |
5760 | .result = ACCEPT, | 6280 | .result = ACCEPT, |
5761 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 6281 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
5762 | }, | 6282 | }, |
@@ -5779,7 +6299,7 @@ static struct bpf_test tests[] = { | |||
5779 | BPF_MOV64_IMM(BPF_REG_0, 0), | 6299 | BPF_MOV64_IMM(BPF_REG_0, 0), |
5780 | BPF_EXIT_INSN(), | 6300 | BPF_EXIT_INSN(), |
5781 | }, | 6301 | }, |
5782 | .fixup_map2 = { 3 }, | 6302 | .fixup_map_hash_48b = { 3 }, |
5783 | .result = REJECT, | 6303 | .result = REJECT, |
5784 | .errstr = "R1 unbounded memory access", | 6304 | .errstr = "R1 unbounded memory access", |
5785 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 6305 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
@@ -5804,7 +6324,7 @@ static struct bpf_test tests[] = { | |||
5804 | BPF_MOV64_IMM(BPF_REG_0, 0), | 6324 | BPF_MOV64_IMM(BPF_REG_0, 0), |
5805 | BPF_EXIT_INSN(), | 6325 | BPF_EXIT_INSN(), |
5806 | }, | 6326 | }, |
5807 | .fixup_map2 = { 3 }, | 6327 | .fixup_map_hash_48b = { 3 }, |
5808 | .result = ACCEPT, | 6328 | .result = ACCEPT, |
5809 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 6329 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
5810 | }, | 6330 | }, |
@@ -5828,7 +6348,7 @@ static struct bpf_test tests[] = { | |||
5828 | BPF_MOV64_IMM(BPF_REG_0, 0), | 6348 | BPF_MOV64_IMM(BPF_REG_0, 0), |
5829 | BPF_EXIT_INSN(), | 6349 | BPF_EXIT_INSN(), |
5830 | }, | 6350 | }, |
5831 | .fixup_map2 = { 3 }, | 6351 | .fixup_map_hash_48b = { 3 }, |
5832 | .result = ACCEPT, | 6352 | .result = ACCEPT, |
5833 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 6353 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
5834 | }, | 6354 | }, |
@@ -5852,7 +6372,7 @@ static struct bpf_test tests[] = { | |||
5852 | BPF_MOV64_IMM(BPF_REG_0, 0), | 6372 | BPF_MOV64_IMM(BPF_REG_0, 0), |
5853 | BPF_EXIT_INSN(), | 6373 | BPF_EXIT_INSN(), |
5854 | }, | 6374 | }, |
5855 | .fixup_map2 = { 3 }, | 6375 | .fixup_map_hash_48b = { 3 }, |
5856 | .result = REJECT, | 6376 | .result = REJECT, |
5857 | .errstr = "R1 min value is negative", | 6377 | .errstr = "R1 min value is negative", |
5858 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 6378 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
@@ -5877,7 +6397,7 @@ static struct bpf_test tests[] = { | |||
5877 | BPF_MOV64_IMM(BPF_REG_0, 0), | 6397 | BPF_MOV64_IMM(BPF_REG_0, 0), |
5878 | BPF_EXIT_INSN(), | 6398 | BPF_EXIT_INSN(), |
5879 | }, | 6399 | }, |
5880 | .fixup_map2 = { 3 }, | 6400 | .fixup_map_hash_48b = { 3 }, |
5881 | .result = ACCEPT, | 6401 | .result = ACCEPT, |
5882 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 6402 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
5883 | }, | 6403 | }, |
@@ -5901,7 +6421,7 @@ static struct bpf_test tests[] = { | |||
5901 | BPF_MOV64_IMM(BPF_REG_0, 0), | 6421 | BPF_MOV64_IMM(BPF_REG_0, 0), |
5902 | BPF_EXIT_INSN(), | 6422 | BPF_EXIT_INSN(), |
5903 | }, | 6423 | }, |
5904 | .fixup_map2 = { 3 }, | 6424 | .fixup_map_hash_48b = { 3 }, |
5905 | .result = ACCEPT, | 6425 | .result = ACCEPT, |
5906 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 6426 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
5907 | }, | 6427 | }, |
@@ -5925,7 +6445,7 @@ static struct bpf_test tests[] = { | |||
5925 | BPF_MOV64_IMM(BPF_REG_0, 0), | 6445 | BPF_MOV64_IMM(BPF_REG_0, 0), |
5926 | BPF_EXIT_INSN(), | 6446 | BPF_EXIT_INSN(), |
5927 | }, | 6447 | }, |
5928 | .fixup_map2 = { 3 }, | 6448 | .fixup_map_hash_48b = { 3 }, |
5929 | .result = REJECT, | 6449 | .result = REJECT, |
5930 | .errstr = "R1 min value is negative", | 6450 | .errstr = "R1 min value is negative", |
5931 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 6451 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
@@ -5944,7 +6464,7 @@ static struct bpf_test tests[] = { | |||
5944 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | 6464 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), |
5945 | BPF_EXIT_INSN(), | 6465 | BPF_EXIT_INSN(), |
5946 | }, | 6466 | }, |
5947 | .fixup_map3 = { 3, 8 }, | 6467 | .fixup_map_hash_16b = { 3, 8 }, |
5948 | .result = ACCEPT, | 6468 | .result = ACCEPT, |
5949 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 6469 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
5950 | }, | 6470 | }, |
@@ -5964,7 +6484,7 @@ static struct bpf_test tests[] = { | |||
5964 | BPF_EMIT_CALL(BPF_FUNC_map_update_elem), | 6484 | BPF_EMIT_CALL(BPF_FUNC_map_update_elem), |
5965 | BPF_EXIT_INSN(), | 6485 | BPF_EXIT_INSN(), |
5966 | }, | 6486 | }, |
5967 | .fixup_map3 = { 3, 10 }, | 6487 | .fixup_map_hash_16b = { 3, 10 }, |
5968 | .result = ACCEPT, | 6488 | .result = ACCEPT, |
5969 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 6489 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
5970 | }, | 6490 | }, |
@@ -5984,8 +6504,8 @@ static struct bpf_test tests[] = { | |||
5984 | BPF_EMIT_CALL(BPF_FUNC_map_update_elem), | 6504 | BPF_EMIT_CALL(BPF_FUNC_map_update_elem), |
5985 | BPF_EXIT_INSN(), | 6505 | BPF_EXIT_INSN(), |
5986 | }, | 6506 | }, |
5987 | .fixup_map1 = { 3 }, | 6507 | .fixup_map_hash_8b = { 3 }, |
5988 | .fixup_map3 = { 10 }, | 6508 | .fixup_map_hash_16b = { 10 }, |
5989 | .result = REJECT, | 6509 | .result = REJECT, |
5990 | .errstr = "invalid access to map value, value_size=8 off=0 size=16", | 6510 | .errstr = "invalid access to map value, value_size=8 off=0 size=16", |
5991 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 6511 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
@@ -6006,7 +6526,7 @@ static struct bpf_test tests[] = { | |||
6006 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | 6526 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), |
6007 | BPF_EXIT_INSN(), | 6527 | BPF_EXIT_INSN(), |
6008 | }, | 6528 | }, |
6009 | .fixup_map3 = { 3, 9 }, | 6529 | .fixup_map_hash_16b = { 3, 9 }, |
6010 | .result = ACCEPT, | 6530 | .result = ACCEPT, |
6011 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 6531 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
6012 | }, | 6532 | }, |
@@ -6026,7 +6546,7 @@ static struct bpf_test tests[] = { | |||
6026 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | 6546 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), |
6027 | BPF_EXIT_INSN(), | 6547 | BPF_EXIT_INSN(), |
6028 | }, | 6548 | }, |
6029 | .fixup_map3 = { 3, 9 }, | 6549 | .fixup_map_hash_16b = { 3, 9 }, |
6030 | .result = REJECT, | 6550 | .result = REJECT, |
6031 | .errstr = "invalid access to map value, value_size=16 off=12 size=8", | 6551 | .errstr = "invalid access to map value, value_size=16 off=12 size=8", |
6032 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 6552 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
@@ -6046,7 +6566,7 @@ static struct bpf_test tests[] = { | |||
6046 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | 6566 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), |
6047 | BPF_EXIT_INSN(), | 6567 | BPF_EXIT_INSN(), |
6048 | }, | 6568 | }, |
6049 | .fixup_map3 = { 3, 9 }, | 6569 | .fixup_map_hash_16b = { 3, 9 }, |
6050 | .result = REJECT, | 6570 | .result = REJECT, |
6051 | .errstr = "invalid access to map value, value_size=16 off=-4 size=8", | 6571 | .errstr = "invalid access to map value, value_size=16 off=-4 size=8", |
6052 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 6572 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
@@ -6068,7 +6588,7 @@ static struct bpf_test tests[] = { | |||
6068 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | 6588 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), |
6069 | BPF_EXIT_INSN(), | 6589 | BPF_EXIT_INSN(), |
6070 | }, | 6590 | }, |
6071 | .fixup_map3 = { 3, 10 }, | 6591 | .fixup_map_hash_16b = { 3, 10 }, |
6072 | .result = ACCEPT, | 6592 | .result = ACCEPT, |
6073 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 6593 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
6074 | }, | 6594 | }, |
@@ -6089,7 +6609,7 @@ static struct bpf_test tests[] = { | |||
6089 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | 6609 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), |
6090 | BPF_EXIT_INSN(), | 6610 | BPF_EXIT_INSN(), |
6091 | }, | 6611 | }, |
6092 | .fixup_map3 = { 3, 10 }, | 6612 | .fixup_map_hash_16b = { 3, 10 }, |
6093 | .result = REJECT, | 6613 | .result = REJECT, |
6094 | .errstr = "invalid access to map value, value_size=16 off=12 size=8", | 6614 | .errstr = "invalid access to map value, value_size=16 off=12 size=8", |
6095 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 6615 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
@@ -6110,7 +6630,7 @@ static struct bpf_test tests[] = { | |||
6110 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | 6630 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), |
6111 | BPF_EXIT_INSN(), | 6631 | BPF_EXIT_INSN(), |
6112 | }, | 6632 | }, |
6113 | .fixup_map3 = { 3, 10 }, | 6633 | .fixup_map_hash_16b = { 3, 10 }, |
6114 | .result = REJECT, | 6634 | .result = REJECT, |
6115 | .errstr = "invalid access to map value, value_size=16 off=-4 size=8", | 6635 | .errstr = "invalid access to map value, value_size=16 off=-4 size=8", |
6116 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 6636 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
@@ -6133,7 +6653,7 @@ static struct bpf_test tests[] = { | |||
6133 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | 6653 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), |
6134 | BPF_EXIT_INSN(), | 6654 | BPF_EXIT_INSN(), |
6135 | }, | 6655 | }, |
6136 | .fixup_map3 = { 3, 11 }, | 6656 | .fixup_map_hash_16b = { 3, 11 }, |
6137 | .result = ACCEPT, | 6657 | .result = ACCEPT, |
6138 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 6658 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
6139 | }, | 6659 | }, |
@@ -6153,7 +6673,7 @@ static struct bpf_test tests[] = { | |||
6153 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | 6673 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), |
6154 | BPF_EXIT_INSN(), | 6674 | BPF_EXIT_INSN(), |
6155 | }, | 6675 | }, |
6156 | .fixup_map3 = { 3, 10 }, | 6676 | .fixup_map_hash_16b = { 3, 10 }, |
6157 | .result = REJECT, | 6677 | .result = REJECT, |
6158 | .errstr = "R2 unbounded memory access, make sure to bounds check any array access into a map", | 6678 | .errstr = "R2 unbounded memory access, make sure to bounds check any array access into a map", |
6159 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 6679 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
@@ -6176,7 +6696,7 @@ static struct bpf_test tests[] = { | |||
6176 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), | 6696 | BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), |
6177 | BPF_EXIT_INSN(), | 6697 | BPF_EXIT_INSN(), |
6178 | }, | 6698 | }, |
6179 | .fixup_map3 = { 3, 11 }, | 6699 | .fixup_map_hash_16b = { 3, 11 }, |
6180 | .result = REJECT, | 6700 | .result = REJECT, |
6181 | .errstr = "invalid access to map value, value_size=16 off=9 size=8", | 6701 | .errstr = "invalid access to map value, value_size=16 off=9 size=8", |
6182 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 6702 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
@@ -6198,7 +6718,7 @@ static struct bpf_test tests[] = { | |||
6198 | BPF_ST_MEM(BPF_DW, BPF_REG_3, 0, 42), | 6718 | BPF_ST_MEM(BPF_DW, BPF_REG_3, 0, 42), |
6199 | BPF_EXIT_INSN(), | 6719 | BPF_EXIT_INSN(), |
6200 | }, | 6720 | }, |
6201 | .fixup_map2 = { 3 }, | 6721 | .fixup_map_hash_48b = { 3 }, |
6202 | .errstr_unpriv = "R0 leaks addr", | 6722 | .errstr_unpriv = "R0 leaks addr", |
6203 | .result = ACCEPT, | 6723 | .result = ACCEPT, |
6204 | .result_unpriv = REJECT, | 6724 | .result_unpriv = REJECT, |
@@ -6219,7 +6739,7 @@ static struct bpf_test tests[] = { | |||
6219 | BPF_ST_MEM(BPF_DW, BPF_REG_3, 0, 42), | 6739 | BPF_ST_MEM(BPF_DW, BPF_REG_3, 0, 42), |
6220 | BPF_EXIT_INSN(), | 6740 | BPF_EXIT_INSN(), |
6221 | }, | 6741 | }, |
6222 | .fixup_map2 = { 3 }, | 6742 | .fixup_map_hash_48b = { 3 }, |
6223 | .errstr_unpriv = "R0 leaks addr", | 6743 | .errstr_unpriv = "R0 leaks addr", |
6224 | .result = ACCEPT, | 6744 | .result = ACCEPT, |
6225 | .result_unpriv = REJECT, | 6745 | .result_unpriv = REJECT, |
@@ -6236,7 +6756,7 @@ static struct bpf_test tests[] = { | |||
6236 | BPF_STX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, 0), | 6756 | BPF_STX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, 0), |
6237 | BPF_EXIT_INSN(), | 6757 | BPF_EXIT_INSN(), |
6238 | }, | 6758 | }, |
6239 | .fixup_map2 = { 3 }, | 6759 | .fixup_map_hash_48b = { 3 }, |
6240 | .errstr_unpriv = "R1 !read_ok", | 6760 | .errstr_unpriv = "R1 !read_ok", |
6241 | .errstr = "R1 !read_ok", | 6761 | .errstr = "R1 !read_ok", |
6242 | .result = REJECT, | 6762 | .result = REJECT, |
@@ -6270,7 +6790,7 @@ static struct bpf_test tests[] = { | |||
6270 | BPF_ST_MEM(BPF_DW, BPF_REG_7, -4, 24), | 6790 | BPF_ST_MEM(BPF_DW, BPF_REG_7, -4, 24), |
6271 | BPF_EXIT_INSN(), | 6791 | BPF_EXIT_INSN(), |
6272 | }, | 6792 | }, |
6273 | .fixup_map2 = { 3 }, | 6793 | .fixup_map_hash_48b = { 3 }, |
6274 | .errstr_unpriv = "R0 leaks addr", | 6794 | .errstr_unpriv = "R0 leaks addr", |
6275 | .result = ACCEPT, | 6795 | .result = ACCEPT, |
6276 | .result_unpriv = REJECT, | 6796 | .result_unpriv = REJECT, |
@@ -6298,7 +6818,7 @@ static struct bpf_test tests[] = { | |||
6298 | BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 4), | 6818 | BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 4), |
6299 | BPF_EXIT_INSN(), | 6819 | BPF_EXIT_INSN(), |
6300 | }, | 6820 | }, |
6301 | .fixup_map2 = { 3 }, | 6821 | .fixup_map_hash_48b = { 3 }, |
6302 | .errstr_unpriv = "R0 leaks addr", | 6822 | .errstr_unpriv = "R0 leaks addr", |
6303 | .result = ACCEPT, | 6823 | .result = ACCEPT, |
6304 | .result_unpriv = REJECT, | 6824 | .result_unpriv = REJECT, |
@@ -6317,7 +6837,7 @@ static struct bpf_test tests[] = { | |||
6317 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 22), | 6837 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 22), |
6318 | BPF_EXIT_INSN(), | 6838 | BPF_EXIT_INSN(), |
6319 | }, | 6839 | }, |
6320 | .fixup_map2 = { 3 }, | 6840 | .fixup_map_hash_48b = { 3 }, |
6321 | .errstr = "R0 bitwise operator &= on pointer", | 6841 | .errstr = "R0 bitwise operator &= on pointer", |
6322 | .result = REJECT, | 6842 | .result = REJECT, |
6323 | }, | 6843 | }, |
@@ -6334,7 +6854,7 @@ static struct bpf_test tests[] = { | |||
6334 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 22), | 6854 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 22), |
6335 | BPF_EXIT_INSN(), | 6855 | BPF_EXIT_INSN(), |
6336 | }, | 6856 | }, |
6337 | .fixup_map2 = { 3 }, | 6857 | .fixup_map_hash_48b = { 3 }, |
6338 | .errstr = "R0 32-bit pointer arithmetic prohibited", | 6858 | .errstr = "R0 32-bit pointer arithmetic prohibited", |
6339 | .result = REJECT, | 6859 | .result = REJECT, |
6340 | }, | 6860 | }, |
@@ -6351,7 +6871,7 @@ static struct bpf_test tests[] = { | |||
6351 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 22), | 6871 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 22), |
6352 | BPF_EXIT_INSN(), | 6872 | BPF_EXIT_INSN(), |
6353 | }, | 6873 | }, |
6354 | .fixup_map2 = { 3 }, | 6874 | .fixup_map_hash_48b = { 3 }, |
6355 | .errstr = "R0 pointer arithmetic with /= operator", | 6875 | .errstr = "R0 pointer arithmetic with /= operator", |
6356 | .result = REJECT, | 6876 | .result = REJECT, |
6357 | }, | 6877 | }, |
@@ -6368,7 +6888,7 @@ static struct bpf_test tests[] = { | |||
6368 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 22), | 6888 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 22), |
6369 | BPF_EXIT_INSN(), | 6889 | BPF_EXIT_INSN(), |
6370 | }, | 6890 | }, |
6371 | .fixup_map2 = { 3 }, | 6891 | .fixup_map_hash_48b = { 3 }, |
6372 | .errstr_unpriv = "R0 pointer arithmetic prohibited", | 6892 | .errstr_unpriv = "R0 pointer arithmetic prohibited", |
6373 | .errstr = "invalid mem access 'inv'", | 6893 | .errstr = "invalid mem access 'inv'", |
6374 | .result = REJECT, | 6894 | .result = REJECT, |
@@ -6392,7 +6912,7 @@ static struct bpf_test tests[] = { | |||
6392 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 22), | 6912 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 22), |
6393 | BPF_EXIT_INSN(), | 6913 | BPF_EXIT_INSN(), |
6394 | }, | 6914 | }, |
6395 | .fixup_map2 = { 3 }, | 6915 | .fixup_map_hash_48b = { 3 }, |
6396 | .errstr = "R0 invalid mem access 'inv'", | 6916 | .errstr = "R0 invalid mem access 'inv'", |
6397 | .result = REJECT, | 6917 | .result = REJECT, |
6398 | }, | 6918 | }, |
@@ -6415,7 +6935,7 @@ static struct bpf_test tests[] = { | |||
6415 | BPF_ST_MEM(BPF_DW, BPF_REG_3, 0, 42), | 6935 | BPF_ST_MEM(BPF_DW, BPF_REG_3, 0, 42), |
6416 | BPF_EXIT_INSN(), | 6936 | BPF_EXIT_INSN(), |
6417 | }, | 6937 | }, |
6418 | .fixup_map2 = { 3 }, | 6938 | .fixup_map_hash_48b = { 3 }, |
6419 | .errstr_unpriv = "R0 leaks addr", | 6939 | .errstr_unpriv = "R0 leaks addr", |
6420 | .result = ACCEPT, | 6940 | .result = ACCEPT, |
6421 | .result_unpriv = REJECT, | 6941 | .result_unpriv = REJECT, |
@@ -6661,7 +7181,7 @@ static struct bpf_test tests[] = { | |||
6661 | BPF_MOV64_IMM(BPF_REG_0, 0), | 7181 | BPF_MOV64_IMM(BPF_REG_0, 0), |
6662 | BPF_EXIT_INSN(), | 7182 | BPF_EXIT_INSN(), |
6663 | }, | 7183 | }, |
6664 | .fixup_map2 = { 3 }, | 7184 | .fixup_map_hash_48b = { 3 }, |
6665 | .result = ACCEPT, | 7185 | .result = ACCEPT, |
6666 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 7186 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
6667 | }, | 7187 | }, |
@@ -6687,7 +7207,7 @@ static struct bpf_test tests[] = { | |||
6687 | BPF_MOV64_IMM(BPF_REG_0, 0), | 7207 | BPF_MOV64_IMM(BPF_REG_0, 0), |
6688 | BPF_EXIT_INSN(), | 7208 | BPF_EXIT_INSN(), |
6689 | }, | 7209 | }, |
6690 | .fixup_map2 = { 3 }, | 7210 | .fixup_map_hash_48b = { 3 }, |
6691 | .errstr = "invalid access to map value, value_size=48 off=0 size=49", | 7211 | .errstr = "invalid access to map value, value_size=48 off=0 size=49", |
6692 | .result = REJECT, | 7212 | .result = REJECT, |
6693 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 7213 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
@@ -6715,7 +7235,7 @@ static struct bpf_test tests[] = { | |||
6715 | BPF_MOV64_IMM(BPF_REG_0, 0), | 7235 | BPF_MOV64_IMM(BPF_REG_0, 0), |
6716 | BPF_EXIT_INSN(), | 7236 | BPF_EXIT_INSN(), |
6717 | }, | 7237 | }, |
6718 | .fixup_map2 = { 3 }, | 7238 | .fixup_map_hash_48b = { 3 }, |
6719 | .result = ACCEPT, | 7239 | .result = ACCEPT, |
6720 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 7240 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
6721 | }, | 7241 | }, |
@@ -6742,7 +7262,7 @@ static struct bpf_test tests[] = { | |||
6742 | BPF_MOV64_IMM(BPF_REG_0, 0), | 7262 | BPF_MOV64_IMM(BPF_REG_0, 0), |
6743 | BPF_EXIT_INSN(), | 7263 | BPF_EXIT_INSN(), |
6744 | }, | 7264 | }, |
6745 | .fixup_map2 = { 3 }, | 7265 | .fixup_map_hash_48b = { 3 }, |
6746 | .errstr = "R1 min value is outside of the array range", | 7266 | .errstr = "R1 min value is outside of the array range", |
6747 | .result = REJECT, | 7267 | .result = REJECT, |
6748 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 7268 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
@@ -6814,7 +7334,7 @@ static struct bpf_test tests[] = { | |||
6814 | BPF_EMIT_CALL(BPF_FUNC_csum_diff), | 7334 | BPF_EMIT_CALL(BPF_FUNC_csum_diff), |
6815 | BPF_EXIT_INSN(), | 7335 | BPF_EXIT_INSN(), |
6816 | }, | 7336 | }, |
6817 | .fixup_map1 = { 3 }, | 7337 | .fixup_map_hash_8b = { 3 }, |
6818 | .result = ACCEPT, | 7338 | .result = ACCEPT, |
6819 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 7339 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
6820 | }, | 7340 | }, |
@@ -6839,7 +7359,7 @@ static struct bpf_test tests[] = { | |||
6839 | BPF_EMIT_CALL(BPF_FUNC_csum_diff), | 7359 | BPF_EMIT_CALL(BPF_FUNC_csum_diff), |
6840 | BPF_EXIT_INSN(), | 7360 | BPF_EXIT_INSN(), |
6841 | }, | 7361 | }, |
6842 | .fixup_map1 = { 3 }, | 7362 | .fixup_map_hash_8b = { 3 }, |
6843 | .result = ACCEPT, | 7363 | .result = ACCEPT, |
6844 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 7364 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
6845 | }, | 7365 | }, |
@@ -6862,7 +7382,7 @@ static struct bpf_test tests[] = { | |||
6862 | BPF_EMIT_CALL(BPF_FUNC_csum_diff), | 7382 | BPF_EMIT_CALL(BPF_FUNC_csum_diff), |
6863 | BPF_EXIT_INSN(), | 7383 | BPF_EXIT_INSN(), |
6864 | }, | 7384 | }, |
6865 | .fixup_map1 = { 3 }, | 7385 | .fixup_map_hash_8b = { 3 }, |
6866 | .result = ACCEPT, | 7386 | .result = ACCEPT, |
6867 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 7387 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
6868 | }, | 7388 | }, |
@@ -6943,7 +7463,7 @@ static struct bpf_test tests[] = { | |||
6943 | BPF_EMIT_CALL(BPF_FUNC_probe_read), | 7463 | BPF_EMIT_CALL(BPF_FUNC_probe_read), |
6944 | BPF_EXIT_INSN(), | 7464 | BPF_EXIT_INSN(), |
6945 | }, | 7465 | }, |
6946 | .fixup_map1 = { 3 }, | 7466 | .fixup_map_hash_8b = { 3 }, |
6947 | .result = ACCEPT, | 7467 | .result = ACCEPT, |
6948 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 7468 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
6949 | }, | 7469 | }, |
@@ -6964,7 +7484,7 @@ static struct bpf_test tests[] = { | |||
6964 | BPF_EMIT_CALL(BPF_FUNC_probe_read), | 7484 | BPF_EMIT_CALL(BPF_FUNC_probe_read), |
6965 | BPF_EXIT_INSN(), | 7485 | BPF_EXIT_INSN(), |
6966 | }, | 7486 | }, |
6967 | .fixup_map1 = { 3 }, | 7487 | .fixup_map_hash_8b = { 3 }, |
6968 | .result = ACCEPT, | 7488 | .result = ACCEPT, |
6969 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 7489 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
6970 | }, | 7490 | }, |
@@ -6984,7 +7504,7 @@ static struct bpf_test tests[] = { | |||
6984 | BPF_EMIT_CALL(BPF_FUNC_probe_read), | 7504 | BPF_EMIT_CALL(BPF_FUNC_probe_read), |
6985 | BPF_EXIT_INSN(), | 7505 | BPF_EXIT_INSN(), |
6986 | }, | 7506 | }, |
6987 | .fixup_map1 = { 3 }, | 7507 | .fixup_map_hash_8b = { 3 }, |
6988 | .result = ACCEPT, | 7508 | .result = ACCEPT, |
6989 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 7509 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
6990 | }, | 7510 | }, |
@@ -7059,7 +7579,7 @@ static struct bpf_test tests[] = { | |||
7059 | offsetof(struct test_val, foo)), | 7579 | offsetof(struct test_val, foo)), |
7060 | BPF_EXIT_INSN(), | 7580 | BPF_EXIT_INSN(), |
7061 | }, | 7581 | }, |
7062 | .fixup_map2 = { 3 }, | 7582 | .fixup_map_hash_48b = { 3 }, |
7063 | .errstr = "R0 max value is outside of the array range", | 7583 | .errstr = "R0 max value is outside of the array range", |
7064 | .result = REJECT, | 7584 | .result = REJECT, |
7065 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | 7585 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |
@@ -7089,7 +7609,7 @@ static struct bpf_test tests[] = { | |||
7089 | BPF_MOV64_REG(BPF_REG_0, 0), | 7609 | BPF_MOV64_REG(BPF_REG_0, 0), |
7090 | BPF_EXIT_INSN(), | 7610 | BPF_EXIT_INSN(), |
7091 | }, | 7611 | }, |
7092 | .fixup_map2 = { 3 }, | 7612 | .fixup_map_hash_48b = { 3 }, |
7093 | .errstr = "R0 max value is outside of the array range", | 7613 | .errstr = "R0 max value is outside of the array range", |
7094 | .result = REJECT, | 7614 | .result = REJECT, |
7095 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, | 7615 | .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, |
@@ -7137,7 +7657,7 @@ static struct bpf_test tests[] = { | |||
7137 | BPF_EXIT_INSN(), | 7657 | BPF_EXIT_INSN(), |
7138 | }, | 7658 | }, |
7139 | .fixup_map_in_map = { 3 }, | 7659 | .fixup_map_in_map = { 3 }, |
7140 | .errstr = "R1 pointer arithmetic on CONST_PTR_TO_MAP prohibited", | 7660 | .errstr = "R1 pointer arithmetic on map_ptr prohibited", |
7141 | .result = REJECT, | 7661 | .result = REJECT, |
7142 | }, | 7662 | }, |
7143 | { | 7663 | { |
@@ -7442,7 +7962,7 @@ static struct bpf_test tests[] = { | |||
7442 | BPF_MOV64_IMM(BPF_REG_0, 0), | 7962 | BPF_MOV64_IMM(BPF_REG_0, 0), |
7443 | BPF_EXIT_INSN(), | 7963 | BPF_EXIT_INSN(), |
7444 | }, | 7964 | }, |
7445 | .fixup_map1 = { 3 }, | 7965 | .fixup_map_hash_8b = { 3 }, |
7446 | .errstr = "unbounded min value", | 7966 | .errstr = "unbounded min value", |
7447 | .result = REJECT, | 7967 | .result = REJECT, |
7448 | }, | 7968 | }, |
@@ -7466,7 +7986,7 @@ static struct bpf_test tests[] = { | |||
7466 | BPF_MOV64_IMM(BPF_REG_0, 0), | 7986 | BPF_MOV64_IMM(BPF_REG_0, 0), |
7467 | BPF_EXIT_INSN(), | 7987 | BPF_EXIT_INSN(), |
7468 | }, | 7988 | }, |
7469 | .fixup_map1 = { 3 }, | 7989 | .fixup_map_hash_8b = { 3 }, |
7470 | .errstr = "unbounded min value", | 7990 | .errstr = "unbounded min value", |
7471 | .result = REJECT, | 7991 | .result = REJECT, |
7472 | }, | 7992 | }, |
@@ -7492,7 +8012,7 @@ static struct bpf_test tests[] = { | |||
7492 | BPF_MOV64_IMM(BPF_REG_0, 0), | 8012 | BPF_MOV64_IMM(BPF_REG_0, 0), |
7493 | BPF_EXIT_INSN(), | 8013 | BPF_EXIT_INSN(), |
7494 | }, | 8014 | }, |
7495 | .fixup_map1 = { 3 }, | 8015 | .fixup_map_hash_8b = { 3 }, |
7496 | .errstr = "unbounded min value", | 8016 | .errstr = "unbounded min value", |
7497 | .result = REJECT, | 8017 | .result = REJECT, |
7498 | }, | 8018 | }, |
@@ -7517,7 +8037,7 @@ static struct bpf_test tests[] = { | |||
7517 | BPF_MOV64_IMM(BPF_REG_0, 0), | 8037 | BPF_MOV64_IMM(BPF_REG_0, 0), |
7518 | BPF_EXIT_INSN(), | 8038 | BPF_EXIT_INSN(), |
7519 | }, | 8039 | }, |
7520 | .fixup_map1 = { 3 }, | 8040 | .fixup_map_hash_8b = { 3 }, |
7521 | .errstr = "unbounded min value", | 8041 | .errstr = "unbounded min value", |
7522 | .result = REJECT, | 8042 | .result = REJECT, |
7523 | }, | 8043 | }, |
@@ -7541,7 +8061,7 @@ static struct bpf_test tests[] = { | |||
7541 | BPF_MOV64_IMM(BPF_REG_0, 0), | 8061 | BPF_MOV64_IMM(BPF_REG_0, 0), |
7542 | BPF_EXIT_INSN(), | 8062 | BPF_EXIT_INSN(), |
7543 | }, | 8063 | }, |
7544 | .fixup_map1 = { 3 }, | 8064 | .fixup_map_hash_8b = { 3 }, |
7545 | .result = ACCEPT, | 8065 | .result = ACCEPT, |
7546 | }, | 8066 | }, |
7547 | { | 8067 | { |
@@ -7565,7 +8085,7 @@ static struct bpf_test tests[] = { | |||
7565 | BPF_MOV64_IMM(BPF_REG_0, 0), | 8085 | BPF_MOV64_IMM(BPF_REG_0, 0), |
7566 | BPF_EXIT_INSN(), | 8086 | BPF_EXIT_INSN(), |
7567 | }, | 8087 | }, |
7568 | .fixup_map1 = { 3 }, | 8088 | .fixup_map_hash_8b = { 3 }, |
7569 | .errstr = "unbounded min value", | 8089 | .errstr = "unbounded min value", |
7570 | .result = REJECT, | 8090 | .result = REJECT, |
7571 | }, | 8091 | }, |
@@ -7611,7 +8131,7 @@ static struct bpf_test tests[] = { | |||
7611 | BPF_MOV64_IMM(BPF_REG_0, 0), | 8131 | BPF_MOV64_IMM(BPF_REG_0, 0), |
7612 | BPF_EXIT_INSN(), | 8132 | BPF_EXIT_INSN(), |
7613 | }, | 8133 | }, |
7614 | .fixup_map1 = { 3 }, | 8134 | .fixup_map_hash_8b = { 3 }, |
7615 | .result = ACCEPT, | 8135 | .result = ACCEPT, |
7616 | }, | 8136 | }, |
7617 | { | 8137 | { |
@@ -7636,7 +8156,7 @@ static struct bpf_test tests[] = { | |||
7636 | BPF_MOV64_IMM(BPF_REG_0, 0), | 8156 | BPF_MOV64_IMM(BPF_REG_0, 0), |
7637 | BPF_EXIT_INSN(), | 8157 | BPF_EXIT_INSN(), |
7638 | }, | 8158 | }, |
7639 | .fixup_map1 = { 3 }, | 8159 | .fixup_map_hash_8b = { 3 }, |
7640 | .errstr = "unbounded min value", | 8160 | .errstr = "unbounded min value", |
7641 | .result = REJECT, | 8161 | .result = REJECT, |
7642 | }, | 8162 | }, |
@@ -7662,7 +8182,7 @@ static struct bpf_test tests[] = { | |||
7662 | BPF_MOV64_IMM(BPF_REG_0, 0), | 8182 | BPF_MOV64_IMM(BPF_REG_0, 0), |
7663 | BPF_EXIT_INSN(), | 8183 | BPF_EXIT_INSN(), |
7664 | }, | 8184 | }, |
7665 | .fixup_map1 = { 3 }, | 8185 | .fixup_map_hash_8b = { 3 }, |
7666 | .result = ACCEPT, | 8186 | .result = ACCEPT, |
7667 | }, | 8187 | }, |
7668 | { | 8188 | { |
@@ -7687,7 +8207,7 @@ static struct bpf_test tests[] = { | |||
7687 | BPF_MOV64_IMM(BPF_REG_0, 0), | 8207 | BPF_MOV64_IMM(BPF_REG_0, 0), |
7688 | BPF_EXIT_INSN(), | 8208 | BPF_EXIT_INSN(), |
7689 | }, | 8209 | }, |
7690 | .fixup_map1 = { 3 }, | 8210 | .fixup_map_hash_8b = { 3 }, |
7691 | .errstr = "unbounded min value", | 8211 | .errstr = "unbounded min value", |
7692 | .result = REJECT, | 8212 | .result = REJECT, |
7693 | }, | 8213 | }, |
@@ -7714,7 +8234,7 @@ static struct bpf_test tests[] = { | |||
7714 | BPF_MOV64_IMM(BPF_REG_0, 0), | 8234 | BPF_MOV64_IMM(BPF_REG_0, 0), |
7715 | BPF_EXIT_INSN(), | 8235 | BPF_EXIT_INSN(), |
7716 | }, | 8236 | }, |
7717 | .fixup_map1 = { 3 }, | 8237 | .fixup_map_hash_8b = { 3 }, |
7718 | .errstr = "unbounded min value", | 8238 | .errstr = "unbounded min value", |
7719 | .result = REJECT, | 8239 | .result = REJECT, |
7720 | }, | 8240 | }, |
@@ -7740,7 +8260,7 @@ static struct bpf_test tests[] = { | |||
7740 | BPF_MOV64_IMM(BPF_REG_0, 0), | 8260 | BPF_MOV64_IMM(BPF_REG_0, 0), |
7741 | BPF_EXIT_INSN(), | 8261 | BPF_EXIT_INSN(), |
7742 | }, | 8262 | }, |
7743 | .fixup_map1 = { 3 }, | 8263 | .fixup_map_hash_8b = { 3 }, |
7744 | .errstr = "unbounded min value", | 8264 | .errstr = "unbounded min value", |
7745 | .result = REJECT, | 8265 | .result = REJECT, |
7746 | }, | 8266 | }, |
@@ -7769,7 +8289,7 @@ static struct bpf_test tests[] = { | |||
7769 | BPF_MOV64_IMM(BPF_REG_0, 0), | 8289 | BPF_MOV64_IMM(BPF_REG_0, 0), |
7770 | BPF_EXIT_INSN(), | 8290 | BPF_EXIT_INSN(), |
7771 | }, | 8291 | }, |
7772 | .fixup_map1 = { 3 }, | 8292 | .fixup_map_hash_8b = { 3 }, |
7773 | .errstr = "unbounded min value", | 8293 | .errstr = "unbounded min value", |
7774 | .result = REJECT, | 8294 | .result = REJECT, |
7775 | }, | 8295 | }, |
@@ -7799,7 +8319,7 @@ static struct bpf_test tests[] = { | |||
7799 | BPF_JMP_REG(BPF_JGT, BPF_REG_1, BPF_REG_2, -3), | 8319 | BPF_JMP_REG(BPF_JGT, BPF_REG_1, BPF_REG_2, -3), |
7800 | BPF_JMP_IMM(BPF_JA, 0, 0, -7), | 8320 | BPF_JMP_IMM(BPF_JA, 0, 0, -7), |
7801 | }, | 8321 | }, |
7802 | .fixup_map1 = { 4 }, | 8322 | .fixup_map_hash_8b = { 4 }, |
7803 | .errstr = "R0 invalid mem access 'inv'", | 8323 | .errstr = "R0 invalid mem access 'inv'", |
7804 | .result = REJECT, | 8324 | .result = REJECT, |
7805 | }, | 8325 | }, |
@@ -7827,7 +8347,7 @@ static struct bpf_test tests[] = { | |||
7827 | BPF_MOV64_IMM(BPF_REG_0, 0), | 8347 | BPF_MOV64_IMM(BPF_REG_0, 0), |
7828 | BPF_EXIT_INSN(), | 8348 | BPF_EXIT_INSN(), |
7829 | }, | 8349 | }, |
7830 | .fixup_map1 = { 3 }, | 8350 | .fixup_map_hash_8b = { 3 }, |
7831 | .errstr = "unbounded min value", | 8351 | .errstr = "unbounded min value", |
7832 | .result = REJECT, | 8352 | .result = REJECT, |
7833 | .result_unpriv = REJECT, | 8353 | .result_unpriv = REJECT, |
@@ -7854,7 +8374,7 @@ static struct bpf_test tests[] = { | |||
7854 | BPF_MOV64_IMM(BPF_REG_0, 0), | 8374 | BPF_MOV64_IMM(BPF_REG_0, 0), |
7855 | BPF_EXIT_INSN(), | 8375 | BPF_EXIT_INSN(), |
7856 | }, | 8376 | }, |
7857 | .fixup_map1 = { 3 }, | 8377 | .fixup_map_hash_8b = { 3 }, |
7858 | .errstr = "R0 max value is outside of the array range", | 8378 | .errstr = "R0 max value is outside of the array range", |
7859 | .result = REJECT, | 8379 | .result = REJECT, |
7860 | }, | 8380 | }, |
@@ -7879,7 +8399,7 @@ static struct bpf_test tests[] = { | |||
7879 | BPF_MOV64_IMM(BPF_REG_0, 0), | 8399 | BPF_MOV64_IMM(BPF_REG_0, 0), |
7880 | BPF_EXIT_INSN(), | 8400 | BPF_EXIT_INSN(), |
7881 | }, | 8401 | }, |
7882 | .fixup_map1 = { 3 }, | 8402 | .fixup_map_hash_8b = { 3 }, |
7883 | .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", | 8403 | .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", |
7884 | .result = REJECT, | 8404 | .result = REJECT, |
7885 | }, | 8405 | }, |
@@ -7905,7 +8425,7 @@ static struct bpf_test tests[] = { | |||
7905 | BPF_MOV64_IMM(BPF_REG_0, 0), | 8425 | BPF_MOV64_IMM(BPF_REG_0, 0), |
7906 | BPF_EXIT_INSN(), | 8426 | BPF_EXIT_INSN(), |
7907 | }, | 8427 | }, |
7908 | .fixup_map1 = { 3 }, | 8428 | .fixup_map_hash_8b = { 3 }, |
7909 | .result = ACCEPT | 8429 | .result = ACCEPT |
7910 | }, | 8430 | }, |
7911 | { | 8431 | { |
@@ -7930,7 +8450,7 @@ static struct bpf_test tests[] = { | |||
7930 | BPF_MOV64_IMM(BPF_REG_0, 0), | 8450 | BPF_MOV64_IMM(BPF_REG_0, 0), |
7931 | BPF_EXIT_INSN(), | 8451 | BPF_EXIT_INSN(), |
7932 | }, | 8452 | }, |
7933 | .fixup_map1 = { 3 }, | 8453 | .fixup_map_hash_8b = { 3 }, |
7934 | .errstr = "map_value pointer and 4294967295", | 8454 | .errstr = "map_value pointer and 4294967295", |
7935 | .result = REJECT | 8455 | .result = REJECT |
7936 | }, | 8456 | }, |
@@ -7956,7 +8476,7 @@ static struct bpf_test tests[] = { | |||
7956 | BPF_MOV64_IMM(BPF_REG_0, 0), | 8476 | BPF_MOV64_IMM(BPF_REG_0, 0), |
7957 | BPF_EXIT_INSN(), | 8477 | BPF_EXIT_INSN(), |
7958 | }, | 8478 | }, |
7959 | .fixup_map1 = { 3 }, | 8479 | .fixup_map_hash_8b = { 3 }, |
7960 | .errstr = "R0 min value is outside of the array range", | 8480 | .errstr = "R0 min value is outside of the array range", |
7961 | .result = REJECT | 8481 | .result = REJECT |
7962 | }, | 8482 | }, |
@@ -7980,7 +8500,7 @@ static struct bpf_test tests[] = { | |||
7980 | BPF_MOV64_IMM(BPF_REG_0, 0), | 8500 | BPF_MOV64_IMM(BPF_REG_0, 0), |
7981 | BPF_EXIT_INSN(), | 8501 | BPF_EXIT_INSN(), |
7982 | }, | 8502 | }, |
7983 | .fixup_map1 = { 4 }, | 8503 | .fixup_map_hash_8b = { 4 }, |
7984 | .errstr = "value_size=8 off=1073741825", | 8504 | .errstr = "value_size=8 off=1073741825", |
7985 | .result = REJECT, | 8505 | .result = REJECT, |
7986 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 8506 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
@@ -8005,7 +8525,7 @@ static struct bpf_test tests[] = { | |||
8005 | BPF_MOV64_IMM(BPF_REG_0, 0), | 8525 | BPF_MOV64_IMM(BPF_REG_0, 0), |
8006 | BPF_EXIT_INSN(), | 8526 | BPF_EXIT_INSN(), |
8007 | }, | 8527 | }, |
8008 | .fixup_map1 = { 4 }, | 8528 | .fixup_map_hash_8b = { 4 }, |
8009 | .errstr = "value 1073741823", | 8529 | .errstr = "value 1073741823", |
8010 | .result = REJECT, | 8530 | .result = REJECT, |
8011 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 8531 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
@@ -8041,7 +8561,7 @@ static struct bpf_test tests[] = { | |||
8041 | BPF_MOV64_IMM(BPF_REG_0, 0), | 8561 | BPF_MOV64_IMM(BPF_REG_0, 0), |
8042 | BPF_EXIT_INSN(), | 8562 | BPF_EXIT_INSN(), |
8043 | }, | 8563 | }, |
8044 | .fixup_map1 = { 3 }, | 8564 | .fixup_map_hash_8b = { 3 }, |
8045 | .result = ACCEPT | 8565 | .result = ACCEPT |
8046 | }, | 8566 | }, |
8047 | { | 8567 | { |
@@ -8080,7 +8600,7 @@ static struct bpf_test tests[] = { | |||
8080 | BPF_MOV64_IMM(BPF_REG_0, 0), | 8600 | BPF_MOV64_IMM(BPF_REG_0, 0), |
8081 | BPF_EXIT_INSN(), | 8601 | BPF_EXIT_INSN(), |
8082 | }, | 8602 | }, |
8083 | .fixup_map1 = { 3 }, | 8603 | .fixup_map_hash_8b = { 3 }, |
8084 | /* not actually fully unbounded, but the bound is very high */ | 8604 | /* not actually fully unbounded, but the bound is very high */ |
8085 | .errstr = "R0 unbounded memory access", | 8605 | .errstr = "R0 unbounded memory access", |
8086 | .result = REJECT | 8606 | .result = REJECT |
@@ -8123,7 +8643,7 @@ static struct bpf_test tests[] = { | |||
8123 | BPF_MOV64_IMM(BPF_REG_0, 0), | 8643 | BPF_MOV64_IMM(BPF_REG_0, 0), |
8124 | BPF_EXIT_INSN(), | 8644 | BPF_EXIT_INSN(), |
8125 | }, | 8645 | }, |
8126 | .fixup_map1 = { 3 }, | 8646 | .fixup_map_hash_8b = { 3 }, |
8127 | /* not actually fully unbounded, but the bound is very high */ | 8647 | /* not actually fully unbounded, but the bound is very high */ |
8128 | .errstr = "R0 unbounded memory access", | 8648 | .errstr = "R0 unbounded memory access", |
8129 | .result = REJECT | 8649 | .result = REJECT |
@@ -8152,7 +8672,7 @@ static struct bpf_test tests[] = { | |||
8152 | BPF_MOV64_IMM(BPF_REG_0, 0), | 8672 | BPF_MOV64_IMM(BPF_REG_0, 0), |
8153 | BPF_EXIT_INSN(), | 8673 | BPF_EXIT_INSN(), |
8154 | }, | 8674 | }, |
8155 | .fixup_map1 = { 3 }, | 8675 | .fixup_map_hash_8b = { 3 }, |
8156 | .result = ACCEPT | 8676 | .result = ACCEPT |
8157 | }, | 8677 | }, |
8158 | { | 8678 | { |
@@ -8179,7 +8699,7 @@ static struct bpf_test tests[] = { | |||
8179 | BPF_MOV64_IMM(BPF_REG_0, 0), | 8699 | BPF_MOV64_IMM(BPF_REG_0, 0), |
8180 | BPF_EXIT_INSN(), | 8700 | BPF_EXIT_INSN(), |
8181 | }, | 8701 | }, |
8182 | .fixup_map1 = { 3 }, | 8702 | .fixup_map_hash_8b = { 3 }, |
8183 | .errstr = "R0 max value is outside of the array range", | 8703 | .errstr = "R0 max value is outside of the array range", |
8184 | .result = REJECT | 8704 | .result = REJECT |
8185 | }, | 8705 | }, |
@@ -8209,7 +8729,7 @@ static struct bpf_test tests[] = { | |||
8209 | BPF_MOV64_IMM(BPF_REG_0, 0), | 8729 | BPF_MOV64_IMM(BPF_REG_0, 0), |
8210 | BPF_EXIT_INSN(), | 8730 | BPF_EXIT_INSN(), |
8211 | }, | 8731 | }, |
8212 | .fixup_map1 = { 3 }, | 8732 | .fixup_map_hash_8b = { 3 }, |
8213 | .errstr = "R0 unbounded memory access", | 8733 | .errstr = "R0 unbounded memory access", |
8214 | .result = REJECT | 8734 | .result = REJECT |
8215 | }, | 8735 | }, |
@@ -8229,7 +8749,7 @@ static struct bpf_test tests[] = { | |||
8229 | BPF_JMP_A(0), | 8749 | BPF_JMP_A(0), |
8230 | BPF_EXIT_INSN(), | 8750 | BPF_EXIT_INSN(), |
8231 | }, | 8751 | }, |
8232 | .fixup_map1 = { 3 }, | 8752 | .fixup_map_hash_8b = { 3 }, |
8233 | .errstr = "map_value pointer and 2147483646", | 8753 | .errstr = "map_value pointer and 2147483646", |
8234 | .result = REJECT | 8754 | .result = REJECT |
8235 | }, | 8755 | }, |
@@ -8251,7 +8771,7 @@ static struct bpf_test tests[] = { | |||
8251 | BPF_JMP_A(0), | 8771 | BPF_JMP_A(0), |
8252 | BPF_EXIT_INSN(), | 8772 | BPF_EXIT_INSN(), |
8253 | }, | 8773 | }, |
8254 | .fixup_map1 = { 3 }, | 8774 | .fixup_map_hash_8b = { 3 }, |
8255 | .errstr = "pointer offset 1073741822", | 8775 | .errstr = "pointer offset 1073741822", |
8256 | .result = REJECT | 8776 | .result = REJECT |
8257 | }, | 8777 | }, |
@@ -8272,7 +8792,7 @@ static struct bpf_test tests[] = { | |||
8272 | BPF_JMP_A(0), | 8792 | BPF_JMP_A(0), |
8273 | BPF_EXIT_INSN(), | 8793 | BPF_EXIT_INSN(), |
8274 | }, | 8794 | }, |
8275 | .fixup_map1 = { 3 }, | 8795 | .fixup_map_hash_8b = { 3 }, |
8276 | .errstr = "pointer offset -1073741822", | 8796 | .errstr = "pointer offset -1073741822", |
8277 | .result = REJECT | 8797 | .result = REJECT |
8278 | }, | 8798 | }, |
@@ -8294,7 +8814,7 @@ static struct bpf_test tests[] = { | |||
8294 | BPF_JMP_A(0), | 8814 | BPF_JMP_A(0), |
8295 | BPF_EXIT_INSN(), | 8815 | BPF_EXIT_INSN(), |
8296 | }, | 8816 | }, |
8297 | .fixup_map1 = { 3 }, | 8817 | .fixup_map_hash_8b = { 3 }, |
8298 | .errstr = "map_value pointer and 1000000000000", | 8818 | .errstr = "map_value pointer and 1000000000000", |
8299 | .result = REJECT | 8819 | .result = REJECT |
8300 | }, | 8820 | }, |
@@ -8314,7 +8834,7 @@ static struct bpf_test tests[] = { | |||
8314 | BPF_JMP_A(0), | 8834 | BPF_JMP_A(0), |
8315 | BPF_EXIT_INSN(), | 8835 | BPF_EXIT_INSN(), |
8316 | }, | 8836 | }, |
8317 | .fixup_map1 = { 3 }, | 8837 | .fixup_map_hash_8b = { 3 }, |
8318 | .result = ACCEPT, | 8838 | .result = ACCEPT, |
8319 | .retval = POINTER_VALUE, | 8839 | .retval = POINTER_VALUE, |
8320 | .result_unpriv = REJECT, | 8840 | .result_unpriv = REJECT, |
@@ -8335,7 +8855,7 @@ static struct bpf_test tests[] = { | |||
8335 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0), | 8855 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0), |
8336 | BPF_EXIT_INSN(), | 8856 | BPF_EXIT_INSN(), |
8337 | }, | 8857 | }, |
8338 | .fixup_map1 = { 3 }, | 8858 | .fixup_map_hash_8b = { 3 }, |
8339 | .result = ACCEPT, | 8859 | .result = ACCEPT, |
8340 | .retval = POINTER_VALUE, | 8860 | .retval = POINTER_VALUE, |
8341 | .result_unpriv = REJECT, | 8861 | .result_unpriv = REJECT, |
@@ -8403,7 +8923,7 @@ static struct bpf_test tests[] = { | |||
8403 | BPF_MOV64_IMM(BPF_REG_0, 0), | 8923 | BPF_MOV64_IMM(BPF_REG_0, 0), |
8404 | BPF_EXIT_INSN(), | 8924 | BPF_EXIT_INSN(), |
8405 | }, | 8925 | }, |
8406 | .fixup_map1 = { 5 }, | 8926 | .fixup_map_hash_8b = { 5 }, |
8407 | .errstr = "variable stack read R2", | 8927 | .errstr = "variable stack read R2", |
8408 | .result = REJECT, | 8928 | .result = REJECT, |
8409 | .prog_type = BPF_PROG_TYPE_LWT_IN, | 8929 | .prog_type = BPF_PROG_TYPE_LWT_IN, |
@@ -8484,7 +9004,7 @@ static struct bpf_test tests[] = { | |||
8484 | offsetof(struct test_val, foo)), | 9004 | offsetof(struct test_val, foo)), |
8485 | BPF_EXIT_INSN(), | 9005 | BPF_EXIT_INSN(), |
8486 | }, | 9006 | }, |
8487 | .fixup_map2 = { 3 }, | 9007 | .fixup_map_hash_48b = { 3 }, |
8488 | .errstr_unpriv = "R0 leaks addr", | 9008 | .errstr_unpriv = "R0 leaks addr", |
8489 | .errstr = "R0 unbounded memory access", | 9009 | .errstr = "R0 unbounded memory access", |
8490 | .result_unpriv = REJECT, | 9010 | .result_unpriv = REJECT, |
@@ -8811,7 +9331,7 @@ static struct bpf_test tests[] = { | |||
8811 | BPF_MOV64_IMM(BPF_REG_0, 0), | 9331 | BPF_MOV64_IMM(BPF_REG_0, 0), |
8812 | BPF_EXIT_INSN(), | 9332 | BPF_EXIT_INSN(), |
8813 | }, | 9333 | }, |
8814 | .errstr = "R3 pointer arithmetic on PTR_TO_PACKET_END", | 9334 | .errstr = "R3 pointer arithmetic on pkt_end", |
8815 | .result = REJECT, | 9335 | .result = REJECT, |
8816 | .prog_type = BPF_PROG_TYPE_XDP, | 9336 | .prog_type = BPF_PROG_TYPE_XDP, |
8817 | }, | 9337 | }, |
@@ -8830,7 +9350,7 @@ static struct bpf_test tests[] = { | |||
8830 | BPF_MOV64_IMM(BPF_REG_0, 0), | 9350 | BPF_MOV64_IMM(BPF_REG_0, 0), |
8831 | BPF_EXIT_INSN(), | 9351 | BPF_EXIT_INSN(), |
8832 | }, | 9352 | }, |
8833 | .errstr = "R3 pointer arithmetic on PTR_TO_PACKET_END", | 9353 | .errstr = "R3 pointer arithmetic on pkt_end", |
8834 | .result = REJECT, | 9354 | .result = REJECT, |
8835 | .prog_type = BPF_PROG_TYPE_XDP, | 9355 | .prog_type = BPF_PROG_TYPE_XDP, |
8836 | }, | 9356 | }, |
@@ -10018,7 +10538,7 @@ static struct bpf_test tests[] = { | |||
10018 | BPF_EXIT_INSN(), | 10538 | BPF_EXIT_INSN(), |
10019 | }, | 10539 | }, |
10020 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 10540 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
10021 | .fixup_map1 = { 16 }, | 10541 | .fixup_map_hash_8b = { 16 }, |
10022 | .result = REJECT, | 10542 | .result = REJECT, |
10023 | .errstr = "R0 min value is outside of the array range", | 10543 | .errstr = "R0 min value is outside of the array range", |
10024 | }, | 10544 | }, |
@@ -10969,7 +11489,7 @@ static struct bpf_test tests[] = { | |||
10969 | BPF_EXIT_INSN(), /* return 0 */ | 11489 | BPF_EXIT_INSN(), /* return 0 */ |
10970 | }, | 11490 | }, |
10971 | .prog_type = BPF_PROG_TYPE_XDP, | 11491 | .prog_type = BPF_PROG_TYPE_XDP, |
10972 | .fixup_map1 = { 23 }, | 11492 | .fixup_map_hash_8b = { 23 }, |
10973 | .result = ACCEPT, | 11493 | .result = ACCEPT, |
10974 | }, | 11494 | }, |
10975 | { | 11495 | { |
@@ -11024,7 +11544,7 @@ static struct bpf_test tests[] = { | |||
11024 | BPF_EXIT_INSN(), /* return 1 */ | 11544 | BPF_EXIT_INSN(), /* return 1 */ |
11025 | }, | 11545 | }, |
11026 | .prog_type = BPF_PROG_TYPE_XDP, | 11546 | .prog_type = BPF_PROG_TYPE_XDP, |
11027 | .fixup_map1 = { 23 }, | 11547 | .fixup_map_hash_8b = { 23 }, |
11028 | .result = ACCEPT, | 11548 | .result = ACCEPT, |
11029 | }, | 11549 | }, |
11030 | { | 11550 | { |
@@ -11079,7 +11599,7 @@ static struct bpf_test tests[] = { | |||
11079 | BPF_EXIT_INSN(), /* return 1 */ | 11599 | BPF_EXIT_INSN(), /* return 1 */ |
11080 | }, | 11600 | }, |
11081 | .prog_type = BPF_PROG_TYPE_XDP, | 11601 | .prog_type = BPF_PROG_TYPE_XDP, |
11082 | .fixup_map1 = { 23 }, | 11602 | .fixup_map_hash_8b = { 23 }, |
11083 | .result = REJECT, | 11603 | .result = REJECT, |
11084 | .errstr = "invalid read from stack off -16+0 size 8", | 11604 | .errstr = "invalid read from stack off -16+0 size 8", |
11085 | }, | 11605 | }, |
@@ -11151,7 +11671,7 @@ static struct bpf_test tests[] = { | |||
11151 | BPF_EXIT_INSN(), | 11671 | BPF_EXIT_INSN(), |
11152 | }, | 11672 | }, |
11153 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 11673 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
11154 | .fixup_map1 = { 12, 22 }, | 11674 | .fixup_map_hash_8b = { 12, 22 }, |
11155 | .result = REJECT, | 11675 | .result = REJECT, |
11156 | .errstr = "invalid access to map value, value_size=8 off=2 size=8", | 11676 | .errstr = "invalid access to map value, value_size=8 off=2 size=8", |
11157 | }, | 11677 | }, |
@@ -11223,7 +11743,7 @@ static struct bpf_test tests[] = { | |||
11223 | BPF_EXIT_INSN(), | 11743 | BPF_EXIT_INSN(), |
11224 | }, | 11744 | }, |
11225 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 11745 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
11226 | .fixup_map1 = { 12, 22 }, | 11746 | .fixup_map_hash_8b = { 12, 22 }, |
11227 | .result = ACCEPT, | 11747 | .result = ACCEPT, |
11228 | }, | 11748 | }, |
11229 | { | 11749 | { |
@@ -11294,7 +11814,7 @@ static struct bpf_test tests[] = { | |||
11294 | BPF_JMP_IMM(BPF_JA, 0, 0, -8), | 11814 | BPF_JMP_IMM(BPF_JA, 0, 0, -8), |
11295 | }, | 11815 | }, |
11296 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 11816 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
11297 | .fixup_map1 = { 12, 22 }, | 11817 | .fixup_map_hash_8b = { 12, 22 }, |
11298 | .result = REJECT, | 11818 | .result = REJECT, |
11299 | .errstr = "invalid access to map value, value_size=8 off=2 size=8", | 11819 | .errstr = "invalid access to map value, value_size=8 off=2 size=8", |
11300 | }, | 11820 | }, |
@@ -11366,7 +11886,7 @@ static struct bpf_test tests[] = { | |||
11366 | BPF_EXIT_INSN(), | 11886 | BPF_EXIT_INSN(), |
11367 | }, | 11887 | }, |
11368 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 11888 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
11369 | .fixup_map1 = { 12, 22 }, | 11889 | .fixup_map_hash_8b = { 12, 22 }, |
11370 | .result = ACCEPT, | 11890 | .result = ACCEPT, |
11371 | }, | 11891 | }, |
11372 | { | 11892 | { |
@@ -11437,7 +11957,7 @@ static struct bpf_test tests[] = { | |||
11437 | BPF_EXIT_INSN(), | 11957 | BPF_EXIT_INSN(), |
11438 | }, | 11958 | }, |
11439 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 11959 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
11440 | .fixup_map1 = { 12, 22 }, | 11960 | .fixup_map_hash_8b = { 12, 22 }, |
11441 | .result = REJECT, | 11961 | .result = REJECT, |
11442 | .errstr = "R0 invalid mem access 'inv'", | 11962 | .errstr = "R0 invalid mem access 'inv'", |
11443 | }, | 11963 | }, |
@@ -11782,7 +12302,7 @@ static struct bpf_test tests[] = { | |||
11782 | BPF_STX_MEM(BPF_DW, BPF_REG_6, BPF_REG_0, 0), | 12302 | BPF_STX_MEM(BPF_DW, BPF_REG_6, BPF_REG_0, 0), |
11783 | BPF_EXIT_INSN(), | 12303 | BPF_EXIT_INSN(), |
11784 | }, | 12304 | }, |
11785 | .fixup_map1 = { 13 }, | 12305 | .fixup_map_hash_8b = { 13 }, |
11786 | .result = ACCEPT, | 12306 | .result = ACCEPT, |
11787 | .prog_type = BPF_PROG_TYPE_XDP, | 12307 | .prog_type = BPF_PROG_TYPE_XDP, |
11788 | }, | 12308 | }, |
@@ -11809,7 +12329,7 @@ static struct bpf_test tests[] = { | |||
11809 | BPF_FUNC_map_lookup_elem), | 12329 | BPF_FUNC_map_lookup_elem), |
11810 | BPF_EXIT_INSN(), | 12330 | BPF_EXIT_INSN(), |
11811 | }, | 12331 | }, |
11812 | .fixup_map2 = { 6 }, | 12332 | .fixup_map_hash_48b = { 6 }, |
11813 | .errstr = "invalid indirect read from stack off -8+0 size 8", | 12333 | .errstr = "invalid indirect read from stack off -8+0 size 8", |
11814 | .result = REJECT, | 12334 | .result = REJECT, |
11815 | .prog_type = BPF_PROG_TYPE_XDP, | 12335 | .prog_type = BPF_PROG_TYPE_XDP, |
@@ -11841,8 +12361,8 @@ static struct bpf_test tests[] = { | |||
11841 | BPF_EXIT_INSN(), | 12361 | BPF_EXIT_INSN(), |
11842 | }, | 12362 | }, |
11843 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 12363 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
11844 | .fixup_map2 = { 13 }, | 12364 | .fixup_map_hash_48b = { 13 }, |
11845 | .fixup_map4 = { 16 }, | 12365 | .fixup_map_array_48b = { 16 }, |
11846 | .result = ACCEPT, | 12366 | .result = ACCEPT, |
11847 | .retval = 1, | 12367 | .retval = 1, |
11848 | }, | 12368 | }, |
@@ -11874,7 +12394,7 @@ static struct bpf_test tests[] = { | |||
11874 | }, | 12394 | }, |
11875 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 12395 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
11876 | .fixup_map_in_map = { 16 }, | 12396 | .fixup_map_in_map = { 16 }, |
11877 | .fixup_map4 = { 13 }, | 12397 | .fixup_map_array_48b = { 13 }, |
11878 | .result = REJECT, | 12398 | .result = REJECT, |
11879 | .errstr = "R0 invalid mem access 'map_ptr'", | 12399 | .errstr = "R0 invalid mem access 'map_ptr'", |
11880 | }, | 12400 | }, |
@@ -11942,7 +12462,7 @@ static struct bpf_test tests[] = { | |||
11942 | BPF_ST_MEM(BPF_DW, BPF_REG_6, 0, 0xdead), | 12462 | BPF_ST_MEM(BPF_DW, BPF_REG_6, 0, 0xdead), |
11943 | BPF_EXIT_INSN(), | 12463 | BPF_EXIT_INSN(), |
11944 | }, | 12464 | }, |
11945 | .fixup_map1 = { 3 }, | 12465 | .fixup_map_hash_8b = { 3 }, |
11946 | .errstr = "R6 invalid mem access 'inv'", | 12466 | .errstr = "R6 invalid mem access 'inv'", |
11947 | .result = REJECT, | 12467 | .result = REJECT, |
11948 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 12468 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
@@ -11966,7 +12486,7 @@ static struct bpf_test tests[] = { | |||
11966 | BPF_LDX_MEM(BPF_DW, BPF_REG_5, BPF_REG_10, -16), | 12486 | BPF_LDX_MEM(BPF_DW, BPF_REG_5, BPF_REG_10, -16), |
11967 | BPF_EXIT_INSN(), | 12487 | BPF_EXIT_INSN(), |
11968 | }, | 12488 | }, |
11969 | .fixup_map1 = { 3 }, | 12489 | .fixup_map_hash_8b = { 3 }, |
11970 | .errstr = "invalid read from stack off -16+0 size 8", | 12490 | .errstr = "invalid read from stack off -16+0 size 8", |
11971 | .result = REJECT, | 12491 | .result = REJECT, |
11972 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 12492 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
@@ -12088,7 +12608,7 @@ static struct bpf_test tests[] = { | |||
12088 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_0, 3), | 12608 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_0, 3), |
12089 | BPF_EXIT_INSN(), | 12609 | BPF_EXIT_INSN(), |
12090 | }, | 12610 | }, |
12091 | .fixup_map1 = { 3 }, | 12611 | .fixup_map_hash_8b = { 3 }, |
12092 | .result = REJECT, | 12612 | .result = REJECT, |
12093 | .errstr = "misaligned value access off", | 12613 | .errstr = "misaligned value access off", |
12094 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 12614 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
@@ -12114,7 +12634,7 @@ static struct bpf_test tests[] = { | |||
12114 | BPF_EXIT_INSN(), | 12634 | BPF_EXIT_INSN(), |
12115 | }, | 12635 | }, |
12116 | .result = REJECT, | 12636 | .result = REJECT, |
12117 | .errstr = "BPF_XADD stores into R2 packet", | 12637 | .errstr = "BPF_XADD stores into R2 pkt is not allowed", |
12118 | .prog_type = BPF_PROG_TYPE_XDP, | 12638 | .prog_type = BPF_PROG_TYPE_XDP, |
12119 | }, | 12639 | }, |
12120 | { | 12640 | { |
@@ -12198,7 +12718,7 @@ static struct bpf_test tests[] = { | |||
12198 | BPF_EMIT_CALL(BPF_FUNC_get_stack), | 12718 | BPF_EMIT_CALL(BPF_FUNC_get_stack), |
12199 | BPF_EXIT_INSN(), | 12719 | BPF_EXIT_INSN(), |
12200 | }, | 12720 | }, |
12201 | .fixup_map2 = { 4 }, | 12721 | .fixup_map_hash_48b = { 4 }, |
12202 | .result = ACCEPT, | 12722 | .result = ACCEPT, |
12203 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | 12723 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, |
12204 | }, | 12724 | }, |
@@ -12442,6 +12962,214 @@ static struct bpf_test tests[] = { | |||
12442 | .result = ACCEPT, | 12962 | .result = ACCEPT, |
12443 | }, | 12963 | }, |
12444 | { | 12964 | { |
12965 | "reference tracking: leak potential reference", | ||
12966 | .insns = { | ||
12967 | BPF_SK_LOOKUP, | ||
12968 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_0), /* leak reference */ | ||
12969 | BPF_EXIT_INSN(), | ||
12970 | }, | ||
12971 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
12972 | .errstr = "Unreleased reference", | ||
12973 | .result = REJECT, | ||
12974 | }, | ||
12975 | { | ||
12976 | "reference tracking: leak potential reference on stack", | ||
12977 | .insns = { | ||
12978 | BPF_SK_LOOKUP, | ||
12979 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_10), | ||
12980 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, -8), | ||
12981 | BPF_STX_MEM(BPF_DW, BPF_REG_4, BPF_REG_0, 0), | ||
12982 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
12983 | BPF_EXIT_INSN(), | ||
12984 | }, | ||
12985 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
12986 | .errstr = "Unreleased reference", | ||
12987 | .result = REJECT, | ||
12988 | }, | ||
12989 | { | ||
12990 | "reference tracking: leak potential reference on stack 2", | ||
12991 | .insns = { | ||
12992 | BPF_SK_LOOKUP, | ||
12993 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_10), | ||
12994 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, -8), | ||
12995 | BPF_STX_MEM(BPF_DW, BPF_REG_4, BPF_REG_0, 0), | ||
12996 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
12997 | BPF_ST_MEM(BPF_DW, BPF_REG_4, 0, 0), | ||
12998 | BPF_EXIT_INSN(), | ||
12999 | }, | ||
13000 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
13001 | .errstr = "Unreleased reference", | ||
13002 | .result = REJECT, | ||
13003 | }, | ||
13004 | { | ||
13005 | "reference tracking: zero potential reference", | ||
13006 | .insns = { | ||
13007 | BPF_SK_LOOKUP, | ||
13008 | BPF_MOV64_IMM(BPF_REG_0, 0), /* leak reference */ | ||
13009 | BPF_EXIT_INSN(), | ||
13010 | }, | ||
13011 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
13012 | .errstr = "Unreleased reference", | ||
13013 | .result = REJECT, | ||
13014 | }, | ||
13015 | { | ||
13016 | "reference tracking: copy and zero potential references", | ||
13017 | .insns = { | ||
13018 | BPF_SK_LOOKUP, | ||
13019 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_0), | ||
13020 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
13021 | BPF_MOV64_IMM(BPF_REG_7, 0), /* leak reference */ | ||
13022 | BPF_EXIT_INSN(), | ||
13023 | }, | ||
13024 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
13025 | .errstr = "Unreleased reference", | ||
13026 | .result = REJECT, | ||
13027 | }, | ||
13028 | { | ||
13029 | "reference tracking: release reference without check", | ||
13030 | .insns = { | ||
13031 | BPF_SK_LOOKUP, | ||
13032 | /* reference in r0 may be NULL */ | ||
13033 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
13034 | BPF_MOV64_IMM(BPF_REG_2, 0), | ||
13035 | BPF_EMIT_CALL(BPF_FUNC_sk_release), | ||
13036 | BPF_EXIT_INSN(), | ||
13037 | }, | ||
13038 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
13039 | .errstr = "type=sock_or_null expected=sock", | ||
13040 | .result = REJECT, | ||
13041 | }, | ||
13042 | { | ||
13043 | "reference tracking: release reference", | ||
13044 | .insns = { | ||
13045 | BPF_SK_LOOKUP, | ||
13046 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
13047 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1), | ||
13048 | BPF_EMIT_CALL(BPF_FUNC_sk_release), | ||
13049 | BPF_EXIT_INSN(), | ||
13050 | }, | ||
13051 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
13052 | .result = ACCEPT, | ||
13053 | }, | ||
13054 | { | ||
13055 | "reference tracking: release reference 2", | ||
13056 | .insns = { | ||
13057 | BPF_SK_LOOKUP, | ||
13058 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
13059 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), | ||
13060 | BPF_EXIT_INSN(), | ||
13061 | BPF_EMIT_CALL(BPF_FUNC_sk_release), | ||
13062 | BPF_EXIT_INSN(), | ||
13063 | }, | ||
13064 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
13065 | .result = ACCEPT, | ||
13066 | }, | ||
13067 | { | ||
13068 | "reference tracking: release reference twice", | ||
13069 | .insns = { | ||
13070 | BPF_SK_LOOKUP, | ||
13071 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
13072 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_0), | ||
13073 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1), | ||
13074 | BPF_EMIT_CALL(BPF_FUNC_sk_release), | ||
13075 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), | ||
13076 | BPF_EMIT_CALL(BPF_FUNC_sk_release), | ||
13077 | BPF_EXIT_INSN(), | ||
13078 | }, | ||
13079 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
13080 | .errstr = "type=inv expected=sock", | ||
13081 | .result = REJECT, | ||
13082 | }, | ||
13083 | { | ||
13084 | "reference tracking: release reference twice inside branch", | ||
13085 | .insns = { | ||
13086 | BPF_SK_LOOKUP, | ||
13087 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
13088 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_0), | ||
13089 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3), /* goto end */ | ||
13090 | BPF_EMIT_CALL(BPF_FUNC_sk_release), | ||
13091 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), | ||
13092 | BPF_EMIT_CALL(BPF_FUNC_sk_release), | ||
13093 | BPF_EXIT_INSN(), | ||
13094 | }, | ||
13095 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
13096 | .errstr = "type=inv expected=sock", | ||
13097 | .result = REJECT, | ||
13098 | }, | ||
13099 | { | ||
13100 | "reference tracking: alloc, check, free in one subbranch", | ||
13101 | .insns = { | ||
13102 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
13103 | offsetof(struct __sk_buff, data)), | ||
13104 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
13105 | offsetof(struct __sk_buff, data_end)), | ||
13106 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), | ||
13107 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 16), | ||
13108 | /* if (offsetof(skb, mark) > data_len) exit; */ | ||
13109 | BPF_JMP_REG(BPF_JLE, BPF_REG_0, BPF_REG_3, 1), | ||
13110 | BPF_EXIT_INSN(), | ||
13111 | BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_2, | ||
13112 | offsetof(struct __sk_buff, mark)), | ||
13113 | BPF_SK_LOOKUP, | ||
13114 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_6, 0, 1), /* mark == 0? */ | ||
13115 | /* Leak reference in R0 */ | ||
13116 | BPF_EXIT_INSN(), | ||
13117 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), /* sk NULL? */ | ||
13118 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
13119 | BPF_EMIT_CALL(BPF_FUNC_sk_release), | ||
13120 | BPF_EXIT_INSN(), | ||
13121 | }, | ||
13122 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
13123 | .errstr = "Unreleased reference", | ||
13124 | .result = REJECT, | ||
13125 | }, | ||
13126 | { | ||
13127 | "reference tracking: alloc, check, free in both subbranches", | ||
13128 | .insns = { | ||
13129 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
13130 | offsetof(struct __sk_buff, data)), | ||
13131 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
13132 | offsetof(struct __sk_buff, data_end)), | ||
13133 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), | ||
13134 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 16), | ||
13135 | /* if (offsetof(skb, mark) > data_len) exit; */ | ||
13136 | BPF_JMP_REG(BPF_JLE, BPF_REG_0, BPF_REG_3, 1), | ||
13137 | BPF_EXIT_INSN(), | ||
13138 | BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_2, | ||
13139 | offsetof(struct __sk_buff, mark)), | ||
13140 | BPF_SK_LOOKUP, | ||
13141 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_6, 0, 4), /* mark == 0? */ | ||
13142 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), /* sk NULL? */ | ||
13143 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
13144 | BPF_EMIT_CALL(BPF_FUNC_sk_release), | ||
13145 | BPF_EXIT_INSN(), | ||
13146 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), /* sk NULL? */ | ||
13147 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
13148 | BPF_EMIT_CALL(BPF_FUNC_sk_release), | ||
13149 | BPF_EXIT_INSN(), | ||
13150 | }, | ||
13151 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
13152 | .result = ACCEPT, | ||
13153 | }, | ||
13154 | { | ||
13155 | "reference tracking in call: free reference in subprog", | ||
13156 | .insns = { | ||
13157 | BPF_SK_LOOKUP, | ||
13158 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), /* unchecked reference */ | ||
13159 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2), | ||
13160 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
13161 | BPF_EXIT_INSN(), | ||
13162 | |||
13163 | /* subprog 1 */ | ||
13164 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_1), | ||
13165 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_2, 0, 1), | ||
13166 | BPF_EMIT_CALL(BPF_FUNC_sk_release), | ||
13167 | BPF_EXIT_INSN(), | ||
13168 | }, | ||
13169 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
13170 | .result = ACCEPT, | ||
13171 | }, | ||
13172 | { | ||
12445 | "pass modified ctx pointer to helper, 1", | 13173 | "pass modified ctx pointer to helper, 1", |
12446 | .insns = { | 13174 | .insns = { |
12447 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -612), | 13175 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -612), |
@@ -12511,6 +13239,407 @@ static struct bpf_test tests[] = { | |||
12511 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | 13239 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, |
12512 | .result = ACCEPT, | 13240 | .result = ACCEPT, |
12513 | }, | 13241 | }, |
13242 | { | ||
13243 | "reference tracking in call: free reference in subprog and outside", | ||
13244 | .insns = { | ||
13245 | BPF_SK_LOOKUP, | ||
13246 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), /* unchecked reference */ | ||
13247 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_0), | ||
13248 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 3), | ||
13249 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), | ||
13250 | BPF_EMIT_CALL(BPF_FUNC_sk_release), | ||
13251 | BPF_EXIT_INSN(), | ||
13252 | |||
13253 | /* subprog 1 */ | ||
13254 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_1), | ||
13255 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_2, 0, 1), | ||
13256 | BPF_EMIT_CALL(BPF_FUNC_sk_release), | ||
13257 | BPF_EXIT_INSN(), | ||
13258 | }, | ||
13259 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
13260 | .errstr = "type=inv expected=sock", | ||
13261 | .result = REJECT, | ||
13262 | }, | ||
13263 | { | ||
13264 | "reference tracking in call: alloc & leak reference in subprog", | ||
13265 | .insns = { | ||
13266 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_10), | ||
13267 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, -8), | ||
13268 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 3), | ||
13269 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
13270 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
13271 | BPF_EXIT_INSN(), | ||
13272 | |||
13273 | /* subprog 1 */ | ||
13274 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_4), | ||
13275 | BPF_SK_LOOKUP, | ||
13276 | /* spill unchecked sk_ptr into stack of caller */ | ||
13277 | BPF_STX_MEM(BPF_DW, BPF_REG_6, BPF_REG_0, 0), | ||
13278 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
13279 | BPF_EXIT_INSN(), | ||
13280 | }, | ||
13281 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
13282 | .errstr = "Unreleased reference", | ||
13283 | .result = REJECT, | ||
13284 | }, | ||
13285 | { | ||
13286 | "reference tracking in call: alloc in subprog, release outside", | ||
13287 | .insns = { | ||
13288 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_10), | ||
13289 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 4), | ||
13290 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
13291 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1), | ||
13292 | BPF_EMIT_CALL(BPF_FUNC_sk_release), | ||
13293 | BPF_EXIT_INSN(), | ||
13294 | |||
13295 | /* subprog 1 */ | ||
13296 | BPF_SK_LOOKUP, | ||
13297 | BPF_EXIT_INSN(), /* return sk */ | ||
13298 | }, | ||
13299 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
13300 | .retval = POINTER_VALUE, | ||
13301 | .result = ACCEPT, | ||
13302 | }, | ||
13303 | { | ||
13304 | "reference tracking in call: sk_ptr leak into caller stack", | ||
13305 | .insns = { | ||
13306 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_10), | ||
13307 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, -8), | ||
13308 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2), | ||
13309 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
13310 | BPF_EXIT_INSN(), | ||
13311 | |||
13312 | /* subprog 1 */ | ||
13313 | BPF_MOV64_REG(BPF_REG_5, BPF_REG_10), | ||
13314 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, -8), | ||
13315 | BPF_STX_MEM(BPF_DW, BPF_REG_5, BPF_REG_4, 0), | ||
13316 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 5), | ||
13317 | /* spill unchecked sk_ptr into stack of caller */ | ||
13318 | BPF_MOV64_REG(BPF_REG_5, BPF_REG_10), | ||
13319 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, -8), | ||
13320 | BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_5, 0), | ||
13321 | BPF_STX_MEM(BPF_DW, BPF_REG_4, BPF_REG_0, 0), | ||
13322 | BPF_EXIT_INSN(), | ||
13323 | |||
13324 | /* subprog 2 */ | ||
13325 | BPF_SK_LOOKUP, | ||
13326 | BPF_EXIT_INSN(), | ||
13327 | }, | ||
13328 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
13329 | .errstr = "Unreleased reference", | ||
13330 | .result = REJECT, | ||
13331 | }, | ||
13332 | { | ||
13333 | "reference tracking in call: sk_ptr spill into caller stack", | ||
13334 | .insns = { | ||
13335 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_10), | ||
13336 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, -8), | ||
13337 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2), | ||
13338 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
13339 | BPF_EXIT_INSN(), | ||
13340 | |||
13341 | /* subprog 1 */ | ||
13342 | BPF_MOV64_REG(BPF_REG_5, BPF_REG_10), | ||
13343 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, -8), | ||
13344 | BPF_STX_MEM(BPF_DW, BPF_REG_5, BPF_REG_4, 0), | ||
13345 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 8), | ||
13346 | /* spill unchecked sk_ptr into stack of caller */ | ||
13347 | BPF_MOV64_REG(BPF_REG_5, BPF_REG_10), | ||
13348 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, -8), | ||
13349 | BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_5, 0), | ||
13350 | BPF_STX_MEM(BPF_DW, BPF_REG_4, BPF_REG_0, 0), | ||
13351 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), | ||
13352 | /* now the sk_ptr is verified, free the reference */ | ||
13353 | BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_4, 0), | ||
13354 | BPF_EMIT_CALL(BPF_FUNC_sk_release), | ||
13355 | BPF_EXIT_INSN(), | ||
13356 | |||
13357 | /* subprog 2 */ | ||
13358 | BPF_SK_LOOKUP, | ||
13359 | BPF_EXIT_INSN(), | ||
13360 | }, | ||
13361 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
13362 | .result = ACCEPT, | ||
13363 | }, | ||
13364 | { | ||
13365 | "reference tracking: allow LD_ABS", | ||
13366 | .insns = { | ||
13367 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | ||
13368 | BPF_SK_LOOKUP, | ||
13369 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
13370 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1), | ||
13371 | BPF_EMIT_CALL(BPF_FUNC_sk_release), | ||
13372 | BPF_LD_ABS(BPF_B, 0), | ||
13373 | BPF_LD_ABS(BPF_H, 0), | ||
13374 | BPF_LD_ABS(BPF_W, 0), | ||
13375 | BPF_EXIT_INSN(), | ||
13376 | }, | ||
13377 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
13378 | .result = ACCEPT, | ||
13379 | }, | ||
13380 | { | ||
13381 | "reference tracking: forbid LD_ABS while holding reference", | ||
13382 | .insns = { | ||
13383 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | ||
13384 | BPF_SK_LOOKUP, | ||
13385 | BPF_LD_ABS(BPF_B, 0), | ||
13386 | BPF_LD_ABS(BPF_H, 0), | ||
13387 | BPF_LD_ABS(BPF_W, 0), | ||
13388 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
13389 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1), | ||
13390 | BPF_EMIT_CALL(BPF_FUNC_sk_release), | ||
13391 | BPF_EXIT_INSN(), | ||
13392 | }, | ||
13393 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
13394 | .errstr = "BPF_LD_[ABS|IND] cannot be mixed with socket references", | ||
13395 | .result = REJECT, | ||
13396 | }, | ||
13397 | { | ||
13398 | "reference tracking: allow LD_IND", | ||
13399 | .insns = { | ||
13400 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | ||
13401 | BPF_SK_LOOKUP, | ||
13402 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
13403 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1), | ||
13404 | BPF_EMIT_CALL(BPF_FUNC_sk_release), | ||
13405 | BPF_MOV64_IMM(BPF_REG_7, 1), | ||
13406 | BPF_LD_IND(BPF_W, BPF_REG_7, -0x200000), | ||
13407 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_7), | ||
13408 | BPF_EXIT_INSN(), | ||
13409 | }, | ||
13410 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
13411 | .result = ACCEPT, | ||
13412 | .retval = 1, | ||
13413 | }, | ||
13414 | { | ||
13415 | "reference tracking: forbid LD_IND while holding reference", | ||
13416 | .insns = { | ||
13417 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | ||
13418 | BPF_SK_LOOKUP, | ||
13419 | BPF_MOV64_REG(BPF_REG_4, BPF_REG_0), | ||
13420 | BPF_MOV64_IMM(BPF_REG_7, 1), | ||
13421 | BPF_LD_IND(BPF_W, BPF_REG_7, -0x200000), | ||
13422 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_7), | ||
13423 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_4), | ||
13424 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 1), | ||
13425 | BPF_EMIT_CALL(BPF_FUNC_sk_release), | ||
13426 | BPF_EXIT_INSN(), | ||
13427 | }, | ||
13428 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
13429 | .errstr = "BPF_LD_[ABS|IND] cannot be mixed with socket references", | ||
13430 | .result = REJECT, | ||
13431 | }, | ||
13432 | { | ||
13433 | "reference tracking: check reference or tail call", | ||
13434 | .insns = { | ||
13435 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_1), | ||
13436 | BPF_SK_LOOKUP, | ||
13437 | /* if (sk) bpf_sk_release() */ | ||
13438 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
13439 | BPF_JMP_IMM(BPF_JNE, BPF_REG_1, 0, 7), | ||
13440 | /* bpf_tail_call() */ | ||
13441 | BPF_MOV64_IMM(BPF_REG_3, 2), | ||
13442 | BPF_LD_MAP_FD(BPF_REG_2, 0), | ||
13443 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), | ||
13444 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
13445 | BPF_FUNC_tail_call), | ||
13446 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
13447 | BPF_EXIT_INSN(), | ||
13448 | BPF_EMIT_CALL(BPF_FUNC_sk_release), | ||
13449 | BPF_EXIT_INSN(), | ||
13450 | }, | ||
13451 | .fixup_prog1 = { 17 }, | ||
13452 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
13453 | .result = ACCEPT, | ||
13454 | }, | ||
13455 | { | ||
13456 | "reference tracking: release reference then tail call", | ||
13457 | .insns = { | ||
13458 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_1), | ||
13459 | BPF_SK_LOOKUP, | ||
13460 | /* if (sk) bpf_sk_release() */ | ||
13461 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
13462 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 1), | ||
13463 | BPF_EMIT_CALL(BPF_FUNC_sk_release), | ||
13464 | /* bpf_tail_call() */ | ||
13465 | BPF_MOV64_IMM(BPF_REG_3, 2), | ||
13466 | BPF_LD_MAP_FD(BPF_REG_2, 0), | ||
13467 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), | ||
13468 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
13469 | BPF_FUNC_tail_call), | ||
13470 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
13471 | BPF_EXIT_INSN(), | ||
13472 | }, | ||
13473 | .fixup_prog1 = { 18 }, | ||
13474 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
13475 | .result = ACCEPT, | ||
13476 | }, | ||
13477 | { | ||
13478 | "reference tracking: leak possible reference over tail call", | ||
13479 | .insns = { | ||
13480 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_1), | ||
13481 | /* Look up socket and store in REG_6 */ | ||
13482 | BPF_SK_LOOKUP, | ||
13483 | /* bpf_tail_call() */ | ||
13484 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_0), | ||
13485 | BPF_MOV64_IMM(BPF_REG_3, 2), | ||
13486 | BPF_LD_MAP_FD(BPF_REG_2, 0), | ||
13487 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), | ||
13488 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
13489 | BPF_FUNC_tail_call), | ||
13490 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
13491 | /* if (sk) bpf_sk_release() */ | ||
13492 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), | ||
13493 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 1), | ||
13494 | BPF_EMIT_CALL(BPF_FUNC_sk_release), | ||
13495 | BPF_EXIT_INSN(), | ||
13496 | }, | ||
13497 | .fixup_prog1 = { 16 }, | ||
13498 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
13499 | .errstr = "tail_call would lead to reference leak", | ||
13500 | .result = REJECT, | ||
13501 | }, | ||
13502 | { | ||
13503 | "reference tracking: leak checked reference over tail call", | ||
13504 | .insns = { | ||
13505 | BPF_MOV64_REG(BPF_REG_7, BPF_REG_1), | ||
13506 | /* Look up socket and store in REG_6 */ | ||
13507 | BPF_SK_LOOKUP, | ||
13508 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_0), | ||
13509 | /* if (!sk) goto end */ | ||
13510 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 7), | ||
13511 | /* bpf_tail_call() */ | ||
13512 | BPF_MOV64_IMM(BPF_REG_3, 0), | ||
13513 | BPF_LD_MAP_FD(BPF_REG_2, 0), | ||
13514 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_7), | ||
13515 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
13516 | BPF_FUNC_tail_call), | ||
13517 | BPF_MOV64_IMM(BPF_REG_0, 0), | ||
13518 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), | ||
13519 | BPF_EMIT_CALL(BPF_FUNC_sk_release), | ||
13520 | BPF_EXIT_INSN(), | ||
13521 | }, | ||
13522 | .fixup_prog1 = { 17 }, | ||
13523 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
13524 | .errstr = "tail_call would lead to reference leak", | ||
13525 | .result = REJECT, | ||
13526 | }, | ||
13527 | { | ||
13528 | "reference tracking: mangle and release sock_or_null", | ||
13529 | .insns = { | ||
13530 | BPF_SK_LOOKUP, | ||
13531 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
13532 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 5), | ||
13533 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1), | ||
13534 | BPF_EMIT_CALL(BPF_FUNC_sk_release), | ||
13535 | BPF_EXIT_INSN(), | ||
13536 | }, | ||
13537 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
13538 | .errstr = "R1 pointer arithmetic on sock_or_null prohibited", | ||
13539 | .result = REJECT, | ||
13540 | }, | ||
13541 | { | ||
13542 | "reference tracking: mangle and release sock", | ||
13543 | .insns = { | ||
13544 | BPF_SK_LOOKUP, | ||
13545 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
13546 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), | ||
13547 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 5), | ||
13548 | BPF_EMIT_CALL(BPF_FUNC_sk_release), | ||
13549 | BPF_EXIT_INSN(), | ||
13550 | }, | ||
13551 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
13552 | .errstr = "R1 pointer arithmetic on sock prohibited", | ||
13553 | .result = REJECT, | ||
13554 | }, | ||
13555 | { | ||
13556 | "reference tracking: access member", | ||
13557 | .insns = { | ||
13558 | BPF_SK_LOOKUP, | ||
13559 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_0), | ||
13560 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3), | ||
13561 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_0, 4), | ||
13562 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), | ||
13563 | BPF_EMIT_CALL(BPF_FUNC_sk_release), | ||
13564 | BPF_EXIT_INSN(), | ||
13565 | }, | ||
13566 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
13567 | .result = ACCEPT, | ||
13568 | }, | ||
13569 | { | ||
13570 | "reference tracking: write to member", | ||
13571 | .insns = { | ||
13572 | BPF_SK_LOOKUP, | ||
13573 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_0), | ||
13574 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5), | ||
13575 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), | ||
13576 | BPF_LD_IMM64(BPF_REG_2, 42), | ||
13577 | BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_2, | ||
13578 | offsetof(struct bpf_sock, mark)), | ||
13579 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), | ||
13580 | BPF_EMIT_CALL(BPF_FUNC_sk_release), | ||
13581 | BPF_LD_IMM64(BPF_REG_0, 0), | ||
13582 | BPF_EXIT_INSN(), | ||
13583 | }, | ||
13584 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
13585 | .errstr = "cannot write into socket", | ||
13586 | .result = REJECT, | ||
13587 | }, | ||
13588 | { | ||
13589 | "reference tracking: invalid 64-bit access of member", | ||
13590 | .insns = { | ||
13591 | BPF_SK_LOOKUP, | ||
13592 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_0), | ||
13593 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3), | ||
13594 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_0, 0), | ||
13595 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), | ||
13596 | BPF_EMIT_CALL(BPF_FUNC_sk_release), | ||
13597 | BPF_EXIT_INSN(), | ||
13598 | }, | ||
13599 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
13600 | .errstr = "invalid bpf_sock access off=0 size=8", | ||
13601 | .result = REJECT, | ||
13602 | }, | ||
13603 | { | ||
13604 | "reference tracking: access after release", | ||
13605 | .insns = { | ||
13606 | BPF_SK_LOOKUP, | ||
13607 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
13608 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), | ||
13609 | BPF_EMIT_CALL(BPF_FUNC_sk_release), | ||
13610 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0), | ||
13611 | BPF_EXIT_INSN(), | ||
13612 | }, | ||
13613 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
13614 | .errstr = "!read_ok", | ||
13615 | .result = REJECT, | ||
13616 | }, | ||
13617 | { | ||
13618 | "reference tracking: direct access for lookup", | ||
13619 | .insns = { | ||
13620 | /* Check that the packet is at least 64B long */ | ||
13621 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, | ||
13622 | offsetof(struct __sk_buff, data)), | ||
13623 | BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, | ||
13624 | offsetof(struct __sk_buff, data_end)), | ||
13625 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), | ||
13626 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 64), | ||
13627 | BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 9), | ||
13628 | /* sk = sk_lookup_tcp(ctx, skb->data, ...) */ | ||
13629 | BPF_MOV64_IMM(BPF_REG_3, sizeof(struct bpf_sock_tuple)), | ||
13630 | BPF_MOV64_IMM(BPF_REG_4, 0), | ||
13631 | BPF_MOV64_IMM(BPF_REG_5, 0), | ||
13632 | BPF_EMIT_CALL(BPF_FUNC_sk_lookup_tcp), | ||
13633 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_0), | ||
13634 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3), | ||
13635 | BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_0, 4), | ||
13636 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), | ||
13637 | BPF_EMIT_CALL(BPF_FUNC_sk_release), | ||
13638 | BPF_EXIT_INSN(), | ||
13639 | }, | ||
13640 | .prog_type = BPF_PROG_TYPE_SCHED_CLS, | ||
13641 | .result = ACCEPT, | ||
13642 | }, | ||
12514 | }; | 13643 | }; |
12515 | 13644 | ||
12516 | static int probe_filter_length(const struct bpf_insn *fp) | 13645 | static int probe_filter_length(const struct bpf_insn *fp) |
@@ -12536,18 +13665,18 @@ static int create_map(uint32_t type, uint32_t size_key, | |||
12536 | return fd; | 13665 | return fd; |
12537 | } | 13666 | } |
12538 | 13667 | ||
12539 | static int create_prog_dummy1(void) | 13668 | static int create_prog_dummy1(enum bpf_map_type prog_type) |
12540 | { | 13669 | { |
12541 | struct bpf_insn prog[] = { | 13670 | struct bpf_insn prog[] = { |
12542 | BPF_MOV64_IMM(BPF_REG_0, 42), | 13671 | BPF_MOV64_IMM(BPF_REG_0, 42), |
12543 | BPF_EXIT_INSN(), | 13672 | BPF_EXIT_INSN(), |
12544 | }; | 13673 | }; |
12545 | 13674 | ||
12546 | return bpf_load_program(BPF_PROG_TYPE_SOCKET_FILTER, prog, | 13675 | return bpf_load_program(prog_type, prog, |
12547 | ARRAY_SIZE(prog), "GPL", 0, NULL, 0); | 13676 | ARRAY_SIZE(prog), "GPL", 0, NULL, 0); |
12548 | } | 13677 | } |
12549 | 13678 | ||
12550 | static int create_prog_dummy2(int mfd, int idx) | 13679 | static int create_prog_dummy2(enum bpf_map_type prog_type, int mfd, int idx) |
12551 | { | 13680 | { |
12552 | struct bpf_insn prog[] = { | 13681 | struct bpf_insn prog[] = { |
12553 | BPF_MOV64_IMM(BPF_REG_3, idx), | 13682 | BPF_MOV64_IMM(BPF_REG_3, idx), |
@@ -12558,11 +13687,12 @@ static int create_prog_dummy2(int mfd, int idx) | |||
12558 | BPF_EXIT_INSN(), | 13687 | BPF_EXIT_INSN(), |
12559 | }; | 13688 | }; |
12560 | 13689 | ||
12561 | return bpf_load_program(BPF_PROG_TYPE_SOCKET_FILTER, prog, | 13690 | return bpf_load_program(prog_type, prog, |
12562 | ARRAY_SIZE(prog), "GPL", 0, NULL, 0); | 13691 | ARRAY_SIZE(prog), "GPL", 0, NULL, 0); |
12563 | } | 13692 | } |
12564 | 13693 | ||
12565 | static int create_prog_array(uint32_t max_elem, int p1key) | 13694 | static int create_prog_array(enum bpf_map_type prog_type, uint32_t max_elem, |
13695 | int p1key) | ||
12566 | { | 13696 | { |
12567 | int p2key = 1; | 13697 | int p2key = 1; |
12568 | int mfd, p1fd, p2fd; | 13698 | int mfd, p1fd, p2fd; |
@@ -12574,8 +13704,8 @@ static int create_prog_array(uint32_t max_elem, int p1key) | |||
12574 | return -1; | 13704 | return -1; |
12575 | } | 13705 | } |
12576 | 13706 | ||
12577 | p1fd = create_prog_dummy1(); | 13707 | p1fd = create_prog_dummy1(prog_type); |
12578 | p2fd = create_prog_dummy2(mfd, p2key); | 13708 | p2fd = create_prog_dummy2(prog_type, mfd, p2key); |
12579 | if (p1fd < 0 || p2fd < 0) | 13709 | if (p1fd < 0 || p2fd < 0) |
12580 | goto out; | 13710 | goto out; |
12581 | if (bpf_map_update_elem(mfd, &p1key, &p1fd, BPF_ANY) < 0) | 13711 | if (bpf_map_update_elem(mfd, &p1key, &p1fd, BPF_ANY) < 0) |
@@ -12615,32 +13745,39 @@ static int create_map_in_map(void) | |||
12615 | return outer_map_fd; | 13745 | return outer_map_fd; |
12616 | } | 13746 | } |
12617 | 13747 | ||
12618 | static int create_cgroup_storage(void) | 13748 | static int create_cgroup_storage(bool percpu) |
12619 | { | 13749 | { |
13750 | enum bpf_map_type type = percpu ? BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE : | ||
13751 | BPF_MAP_TYPE_CGROUP_STORAGE; | ||
12620 | int fd; | 13752 | int fd; |
12621 | 13753 | ||
12622 | fd = bpf_create_map(BPF_MAP_TYPE_CGROUP_STORAGE, | 13754 | fd = bpf_create_map(type, sizeof(struct bpf_cgroup_storage_key), |
12623 | sizeof(struct bpf_cgroup_storage_key), | ||
12624 | TEST_DATA_LEN, 0, 0); | 13755 | TEST_DATA_LEN, 0, 0); |
12625 | if (fd < 0) | 13756 | if (fd < 0) |
12626 | printf("Failed to create array '%s'!\n", strerror(errno)); | 13757 | printf("Failed to create cgroup storage '%s'!\n", |
13758 | strerror(errno)); | ||
12627 | 13759 | ||
12628 | return fd; | 13760 | return fd; |
12629 | } | 13761 | } |
12630 | 13762 | ||
12631 | static char bpf_vlog[UINT_MAX >> 8]; | 13763 | static char bpf_vlog[UINT_MAX >> 8]; |
12632 | 13764 | ||
12633 | static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog, | 13765 | static void do_test_fixup(struct bpf_test *test, enum bpf_map_type prog_type, |
12634 | int *map_fds) | 13766 | struct bpf_insn *prog, int *map_fds) |
12635 | { | 13767 | { |
12636 | int *fixup_map1 = test->fixup_map1; | 13768 | int *fixup_map_hash_8b = test->fixup_map_hash_8b; |
12637 | int *fixup_map2 = test->fixup_map2; | 13769 | int *fixup_map_hash_48b = test->fixup_map_hash_48b; |
12638 | int *fixup_map3 = test->fixup_map3; | 13770 | int *fixup_map_hash_16b = test->fixup_map_hash_16b; |
12639 | int *fixup_map4 = test->fixup_map4; | 13771 | int *fixup_map_array_48b = test->fixup_map_array_48b; |
13772 | int *fixup_map_sockmap = test->fixup_map_sockmap; | ||
13773 | int *fixup_map_sockhash = test->fixup_map_sockhash; | ||
13774 | int *fixup_map_xskmap = test->fixup_map_xskmap; | ||
13775 | int *fixup_map_stacktrace = test->fixup_map_stacktrace; | ||
12640 | int *fixup_prog1 = test->fixup_prog1; | 13776 | int *fixup_prog1 = test->fixup_prog1; |
12641 | int *fixup_prog2 = test->fixup_prog2; | 13777 | int *fixup_prog2 = test->fixup_prog2; |
12642 | int *fixup_map_in_map = test->fixup_map_in_map; | 13778 | int *fixup_map_in_map = test->fixup_map_in_map; |
12643 | int *fixup_cgroup_storage = test->fixup_cgroup_storage; | 13779 | int *fixup_cgroup_storage = test->fixup_cgroup_storage; |
13780 | int *fixup_percpu_cgroup_storage = test->fixup_percpu_cgroup_storage; | ||
12644 | 13781 | ||
12645 | if (test->fill_helper) | 13782 | if (test->fill_helper) |
12646 | test->fill_helper(test); | 13783 | test->fill_helper(test); |
@@ -12649,44 +13786,44 @@ static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog, | |||
12649 | * for verifier and not do a runtime lookup, so the only thing | 13786 | * for verifier and not do a runtime lookup, so the only thing |
12650 | * that really matters is value size in this case. | 13787 | * that really matters is value size in this case. |
12651 | */ | 13788 | */ |
12652 | if (*fixup_map1) { | 13789 | if (*fixup_map_hash_8b) { |
12653 | map_fds[0] = create_map(BPF_MAP_TYPE_HASH, sizeof(long long), | 13790 | map_fds[0] = create_map(BPF_MAP_TYPE_HASH, sizeof(long long), |
12654 | sizeof(long long), 1); | 13791 | sizeof(long long), 1); |
12655 | do { | 13792 | do { |
12656 | prog[*fixup_map1].imm = map_fds[0]; | 13793 | prog[*fixup_map_hash_8b].imm = map_fds[0]; |
12657 | fixup_map1++; | 13794 | fixup_map_hash_8b++; |
12658 | } while (*fixup_map1); | 13795 | } while (*fixup_map_hash_8b); |
12659 | } | 13796 | } |
12660 | 13797 | ||
12661 | if (*fixup_map2) { | 13798 | if (*fixup_map_hash_48b) { |
12662 | map_fds[1] = create_map(BPF_MAP_TYPE_HASH, sizeof(long long), | 13799 | map_fds[1] = create_map(BPF_MAP_TYPE_HASH, sizeof(long long), |
12663 | sizeof(struct test_val), 1); | 13800 | sizeof(struct test_val), 1); |
12664 | do { | 13801 | do { |
12665 | prog[*fixup_map2].imm = map_fds[1]; | 13802 | prog[*fixup_map_hash_48b].imm = map_fds[1]; |
12666 | fixup_map2++; | 13803 | fixup_map_hash_48b++; |
12667 | } while (*fixup_map2); | 13804 | } while (*fixup_map_hash_48b); |
12668 | } | 13805 | } |
12669 | 13806 | ||
12670 | if (*fixup_map3) { | 13807 | if (*fixup_map_hash_16b) { |
12671 | map_fds[2] = create_map(BPF_MAP_TYPE_HASH, sizeof(long long), | 13808 | map_fds[2] = create_map(BPF_MAP_TYPE_HASH, sizeof(long long), |
12672 | sizeof(struct other_val), 1); | 13809 | sizeof(struct other_val), 1); |
12673 | do { | 13810 | do { |
12674 | prog[*fixup_map3].imm = map_fds[2]; | 13811 | prog[*fixup_map_hash_16b].imm = map_fds[2]; |
12675 | fixup_map3++; | 13812 | fixup_map_hash_16b++; |
12676 | } while (*fixup_map3); | 13813 | } while (*fixup_map_hash_16b); |
12677 | } | 13814 | } |
12678 | 13815 | ||
12679 | if (*fixup_map4) { | 13816 | if (*fixup_map_array_48b) { |
12680 | map_fds[3] = create_map(BPF_MAP_TYPE_ARRAY, sizeof(int), | 13817 | map_fds[3] = create_map(BPF_MAP_TYPE_ARRAY, sizeof(int), |
12681 | sizeof(struct test_val), 1); | 13818 | sizeof(struct test_val), 1); |
12682 | do { | 13819 | do { |
12683 | prog[*fixup_map4].imm = map_fds[3]; | 13820 | prog[*fixup_map_array_48b].imm = map_fds[3]; |
12684 | fixup_map4++; | 13821 | fixup_map_array_48b++; |
12685 | } while (*fixup_map4); | 13822 | } while (*fixup_map_array_48b); |
12686 | } | 13823 | } |
12687 | 13824 | ||
12688 | if (*fixup_prog1) { | 13825 | if (*fixup_prog1) { |
12689 | map_fds[4] = create_prog_array(4, 0); | 13826 | map_fds[4] = create_prog_array(prog_type, 4, 0); |
12690 | do { | 13827 | do { |
12691 | prog[*fixup_prog1].imm = map_fds[4]; | 13828 | prog[*fixup_prog1].imm = map_fds[4]; |
12692 | fixup_prog1++; | 13829 | fixup_prog1++; |
@@ -12694,7 +13831,7 @@ static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog, | |||
12694 | } | 13831 | } |
12695 | 13832 | ||
12696 | if (*fixup_prog2) { | 13833 | if (*fixup_prog2) { |
12697 | map_fds[5] = create_prog_array(8, 7); | 13834 | map_fds[5] = create_prog_array(prog_type, 8, 7); |
12698 | do { | 13835 | do { |
12699 | prog[*fixup_prog2].imm = map_fds[5]; | 13836 | prog[*fixup_prog2].imm = map_fds[5]; |
12700 | fixup_prog2++; | 13837 | fixup_prog2++; |
@@ -12710,12 +13847,52 @@ static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog, | |||
12710 | } | 13847 | } |
12711 | 13848 | ||
12712 | if (*fixup_cgroup_storage) { | 13849 | if (*fixup_cgroup_storage) { |
12713 | map_fds[7] = create_cgroup_storage(); | 13850 | map_fds[7] = create_cgroup_storage(false); |
12714 | do { | 13851 | do { |
12715 | prog[*fixup_cgroup_storage].imm = map_fds[7]; | 13852 | prog[*fixup_cgroup_storage].imm = map_fds[7]; |
12716 | fixup_cgroup_storage++; | 13853 | fixup_cgroup_storage++; |
12717 | } while (*fixup_cgroup_storage); | 13854 | } while (*fixup_cgroup_storage); |
12718 | } | 13855 | } |
13856 | |||
13857 | if (*fixup_percpu_cgroup_storage) { | ||
13858 | map_fds[8] = create_cgroup_storage(true); | ||
13859 | do { | ||
13860 | prog[*fixup_percpu_cgroup_storage].imm = map_fds[8]; | ||
13861 | fixup_percpu_cgroup_storage++; | ||
13862 | } while (*fixup_percpu_cgroup_storage); | ||
13863 | } | ||
13864 | if (*fixup_map_sockmap) { | ||
13865 | map_fds[9] = create_map(BPF_MAP_TYPE_SOCKMAP, sizeof(int), | ||
13866 | sizeof(int), 1); | ||
13867 | do { | ||
13868 | prog[*fixup_map_sockmap].imm = map_fds[9]; | ||
13869 | fixup_map_sockmap++; | ||
13870 | } while (*fixup_map_sockmap); | ||
13871 | } | ||
13872 | if (*fixup_map_sockhash) { | ||
13873 | map_fds[10] = create_map(BPF_MAP_TYPE_SOCKHASH, sizeof(int), | ||
13874 | sizeof(int), 1); | ||
13875 | do { | ||
13876 | prog[*fixup_map_sockhash].imm = map_fds[10]; | ||
13877 | fixup_map_sockhash++; | ||
13878 | } while (*fixup_map_sockhash); | ||
13879 | } | ||
13880 | if (*fixup_map_xskmap) { | ||
13881 | map_fds[11] = create_map(BPF_MAP_TYPE_XSKMAP, sizeof(int), | ||
13882 | sizeof(int), 1); | ||
13883 | do { | ||
13884 | prog[*fixup_map_xskmap].imm = map_fds[11]; | ||
13885 | fixup_map_xskmap++; | ||
13886 | } while (*fixup_map_xskmap); | ||
13887 | } | ||
13888 | if (*fixup_map_stacktrace) { | ||
13889 | map_fds[12] = create_map(BPF_MAP_TYPE_STACK_TRACE, sizeof(u32), | ||
13890 | sizeof(u64), 1); | ||
13891 | do { | ||
13892 | prog[*fixup_map_stacktrace].imm = map_fds[12]; | ||
13893 | fixup_map_stacktrace++; | ||
13894 | } while (fixup_map_stacktrace); | ||
13895 | } | ||
12719 | } | 13896 | } |
12720 | 13897 | ||
12721 | static void do_test_single(struct bpf_test *test, bool unpriv, | 13898 | static void do_test_single(struct bpf_test *test, bool unpriv, |
@@ -12732,11 +13909,13 @@ static void do_test_single(struct bpf_test *test, bool unpriv, | |||
12732 | for (i = 0; i < MAX_NR_MAPS; i++) | 13909 | for (i = 0; i < MAX_NR_MAPS; i++) |
12733 | map_fds[i] = -1; | 13910 | map_fds[i] = -1; |
12734 | 13911 | ||
12735 | do_test_fixup(test, prog, map_fds); | 13912 | if (!prog_type) |
13913 | prog_type = BPF_PROG_TYPE_SOCKET_FILTER; | ||
13914 | do_test_fixup(test, prog_type, prog, map_fds); | ||
12736 | prog_len = probe_filter_length(prog); | 13915 | prog_len = probe_filter_length(prog); |
12737 | 13916 | ||
12738 | fd_prog = bpf_verify_program(prog_type ? : BPF_PROG_TYPE_SOCKET_FILTER, | 13917 | fd_prog = bpf_verify_program(prog_type, prog, prog_len, |
12739 | prog, prog_len, test->flags & F_LOAD_WITH_STRICT_ALIGNMENT, | 13918 | test->flags & F_LOAD_WITH_STRICT_ALIGNMENT, |
12740 | "GPL", 0, bpf_vlog, sizeof(bpf_vlog), 1); | 13919 | "GPL", 0, bpf_vlog, sizeof(bpf_vlog), 1); |
12741 | 13920 | ||
12742 | expected_ret = unpriv && test->result_unpriv != UNDEF ? | 13921 | expected_ret = unpriv && test->result_unpriv != UNDEF ? |
diff --git a/tools/testing/selftests/bpf/test_xdp_vlan.c b/tools/testing/selftests/bpf/test_xdp_vlan.c new file mode 100644 index 000000000000..365a7d2d9f5c --- /dev/null +++ b/tools/testing/selftests/bpf/test_xdp_vlan.c | |||
@@ -0,0 +1,292 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 | ||
2 | * Copyright(c) 2018 Jesper Dangaard Brouer. | ||
3 | * | ||
4 | * XDP/TC VLAN manipulation example | ||
5 | * | ||
6 | * GOTCHA: Remember to disable NIC hardware offloading of VLANs, | ||
7 | * else the VLAN tags are NOT inlined in the packet payload: | ||
8 | * | ||
9 | * # ethtool -K ixgbe2 rxvlan off | ||
10 | * | ||
11 | * Verify setting: | ||
12 | * # ethtool -k ixgbe2 | grep rx-vlan-offload | ||
13 | * rx-vlan-offload: off | ||
14 | * | ||
15 | */ | ||
16 | #include <stddef.h> | ||
17 | #include <stdbool.h> | ||
18 | #include <string.h> | ||
19 | #include <linux/bpf.h> | ||
20 | #include <linux/if_ether.h> | ||
21 | #include <linux/if_vlan.h> | ||
22 | #include <linux/in.h> | ||
23 | #include <linux/pkt_cls.h> | ||
24 | |||
25 | #include "bpf_helpers.h" | ||
26 | #include "bpf_endian.h" | ||
27 | |||
28 | /* linux/if_vlan.h have not exposed this as UAPI, thus mirror some here | ||
29 | * | ||
30 | * struct vlan_hdr - vlan header | ||
31 | * @h_vlan_TCI: priority and VLAN ID | ||
32 | * @h_vlan_encapsulated_proto: packet type ID or len | ||
33 | */ | ||
34 | struct _vlan_hdr { | ||
35 | __be16 h_vlan_TCI; | ||
36 | __be16 h_vlan_encapsulated_proto; | ||
37 | }; | ||
38 | #define VLAN_PRIO_MASK 0xe000 /* Priority Code Point */ | ||
39 | #define VLAN_PRIO_SHIFT 13 | ||
40 | #define VLAN_CFI_MASK 0x1000 /* Canonical Format Indicator */ | ||
41 | #define VLAN_TAG_PRESENT VLAN_CFI_MASK | ||
42 | #define VLAN_VID_MASK 0x0fff /* VLAN Identifier */ | ||
43 | #define VLAN_N_VID 4096 | ||
44 | |||
45 | struct parse_pkt { | ||
46 | __u16 l3_proto; | ||
47 | __u16 l3_offset; | ||
48 | __u16 vlan_outer; | ||
49 | __u16 vlan_inner; | ||
50 | __u8 vlan_outer_offset; | ||
51 | __u8 vlan_inner_offset; | ||
52 | }; | ||
53 | |||
54 | char _license[] SEC("license") = "GPL"; | ||
55 | |||
56 | static __always_inline | ||
57 | bool parse_eth_frame(struct ethhdr *eth, void *data_end, struct parse_pkt *pkt) | ||
58 | { | ||
59 | __u16 eth_type; | ||
60 | __u8 offset; | ||
61 | |||
62 | offset = sizeof(*eth); | ||
63 | /* Make sure packet is large enough for parsing eth + 2 VLAN headers */ | ||
64 | if ((void *)eth + offset + (2*sizeof(struct _vlan_hdr)) > data_end) | ||
65 | return false; | ||
66 | |||
67 | eth_type = eth->h_proto; | ||
68 | |||
69 | /* Handle outer VLAN tag */ | ||
70 | if (eth_type == bpf_htons(ETH_P_8021Q) | ||
71 | || eth_type == bpf_htons(ETH_P_8021AD)) { | ||
72 | struct _vlan_hdr *vlan_hdr; | ||
73 | |||
74 | vlan_hdr = (void *)eth + offset; | ||
75 | pkt->vlan_outer_offset = offset; | ||
76 | pkt->vlan_outer = bpf_ntohs(vlan_hdr->h_vlan_TCI) | ||
77 | & VLAN_VID_MASK; | ||
78 | eth_type = vlan_hdr->h_vlan_encapsulated_proto; | ||
79 | offset += sizeof(*vlan_hdr); | ||
80 | } | ||
81 | |||
82 | /* Handle inner (double) VLAN tag */ | ||
83 | if (eth_type == bpf_htons(ETH_P_8021Q) | ||
84 | || eth_type == bpf_htons(ETH_P_8021AD)) { | ||
85 | struct _vlan_hdr *vlan_hdr; | ||
86 | |||
87 | vlan_hdr = (void *)eth + offset; | ||
88 | pkt->vlan_inner_offset = offset; | ||
89 | pkt->vlan_inner = bpf_ntohs(vlan_hdr->h_vlan_TCI) | ||
90 | & VLAN_VID_MASK; | ||
91 | eth_type = vlan_hdr->h_vlan_encapsulated_proto; | ||
92 | offset += sizeof(*vlan_hdr); | ||
93 | } | ||
94 | |||
95 | pkt->l3_proto = bpf_ntohs(eth_type); /* Convert to host-byte-order */ | ||
96 | pkt->l3_offset = offset; | ||
97 | |||
98 | return true; | ||
99 | } | ||
100 | |||
101 | /* Hint, VLANs are choosen to hit network-byte-order issues */ | ||
102 | #define TESTVLAN 4011 /* 0xFAB */ | ||
103 | // #define TO_VLAN 4000 /* 0xFA0 (hint 0xOA0 = 160) */ | ||
104 | |||
105 | SEC("xdp_drop_vlan_4011") | ||
106 | int xdp_prognum0(struct xdp_md *ctx) | ||
107 | { | ||
108 | void *data_end = (void *)(long)ctx->data_end; | ||
109 | void *data = (void *)(long)ctx->data; | ||
110 | struct parse_pkt pkt = { 0 }; | ||
111 | |||
112 | if (!parse_eth_frame(data, data_end, &pkt)) | ||
113 | return XDP_ABORTED; | ||
114 | |||
115 | /* Drop specific VLAN ID example */ | ||
116 | if (pkt.vlan_outer == TESTVLAN) | ||
117 | return XDP_ABORTED; | ||
118 | /* | ||
119 | * Using XDP_ABORTED makes it possible to record this event, | ||
120 | * via tracepoint xdp:xdp_exception like: | ||
121 | * # perf record -a -e xdp:xdp_exception | ||
122 | * # perf script | ||
123 | */ | ||
124 | return XDP_PASS; | ||
125 | } | ||
126 | /* | ||
127 | Commands to setup VLAN on Linux to test packets gets dropped: | ||
128 | |||
129 | export ROOTDEV=ixgbe2 | ||
130 | export VLANID=4011 | ||
131 | ip link add link $ROOTDEV name $ROOTDEV.$VLANID type vlan id $VLANID | ||
132 | ip link set dev $ROOTDEV.$VLANID up | ||
133 | |||
134 | ip link set dev $ROOTDEV mtu 1508 | ||
135 | ip addr add 100.64.40.11/24 dev $ROOTDEV.$VLANID | ||
136 | |||
137 | Load prog with ip tool: | ||
138 | |||
139 | ip link set $ROOTDEV xdp off | ||
140 | ip link set $ROOTDEV xdp object xdp_vlan01_kern.o section xdp_drop_vlan_4011 | ||
141 | |||
142 | */ | ||
143 | |||
144 | /* Changing VLAN to zero, have same practical effect as removing the VLAN. */ | ||
145 | #define TO_VLAN 0 | ||
146 | |||
147 | SEC("xdp_vlan_change") | ||
148 | int xdp_prognum1(struct xdp_md *ctx) | ||
149 | { | ||
150 | void *data_end = (void *)(long)ctx->data_end; | ||
151 | void *data = (void *)(long)ctx->data; | ||
152 | struct parse_pkt pkt = { 0 }; | ||
153 | |||
154 | if (!parse_eth_frame(data, data_end, &pkt)) | ||
155 | return XDP_ABORTED; | ||
156 | |||
157 | /* Change specific VLAN ID */ | ||
158 | if (pkt.vlan_outer == TESTVLAN) { | ||
159 | struct _vlan_hdr *vlan_hdr = data + pkt.vlan_outer_offset; | ||
160 | |||
161 | /* Modifying VLAN, preserve top 4 bits */ | ||
162 | vlan_hdr->h_vlan_TCI = | ||
163 | bpf_htons((bpf_ntohs(vlan_hdr->h_vlan_TCI) & 0xf000) | ||
164 | | TO_VLAN); | ||
165 | } | ||
166 | |||
167 | return XDP_PASS; | ||
168 | } | ||
169 | |||
170 | /* | ||
171 | * Show XDP+TC can cooperate, on creating a VLAN rewriter. | ||
172 | * 1. Create a XDP prog that can "pop"/remove a VLAN header. | ||
173 | * 2. Create a TC-bpf prog that egress can add a VLAN header. | ||
174 | */ | ||
175 | |||
176 | #ifndef ETH_ALEN /* Ethernet MAC address length */ | ||
177 | #define ETH_ALEN 6 /* bytes */ | ||
178 | #endif | ||
179 | #define VLAN_HDR_SZ 4 /* bytes */ | ||
180 | |||
181 | SEC("xdp_vlan_remove_outer") | ||
182 | int xdp_prognum2(struct xdp_md *ctx) | ||
183 | { | ||
184 | void *data_end = (void *)(long)ctx->data_end; | ||
185 | void *data = (void *)(long)ctx->data; | ||
186 | struct parse_pkt pkt = { 0 }; | ||
187 | char *dest; | ||
188 | |||
189 | if (!parse_eth_frame(data, data_end, &pkt)) | ||
190 | return XDP_ABORTED; | ||
191 | |||
192 | /* Skip packet if no outer VLAN was detected */ | ||
193 | if (pkt.vlan_outer_offset == 0) | ||
194 | return XDP_PASS; | ||
195 | |||
196 | /* Moving Ethernet header, dest overlap with src, memmove handle this */ | ||
197 | dest = data; | ||
198 | dest+= VLAN_HDR_SZ; | ||
199 | /* | ||
200 | * Notice: Taking over vlan_hdr->h_vlan_encapsulated_proto, by | ||
201 | * only moving two MAC addrs (12 bytes), not overwriting last 2 bytes | ||
202 | */ | ||
203 | __builtin_memmove(dest, data, ETH_ALEN * 2); | ||
204 | /* Note: LLVM built-in memmove inlining require size to be constant */ | ||
205 | |||
206 | /* Move start of packet header seen by Linux kernel stack */ | ||
207 | bpf_xdp_adjust_head(ctx, VLAN_HDR_SZ); | ||
208 | |||
209 | return XDP_PASS; | ||
210 | } | ||
211 | |||
212 | static __always_inline | ||
213 | void shift_mac_4bytes_16bit(void *data) | ||
214 | { | ||
215 | __u16 *p = data; | ||
216 | |||
217 | p[7] = p[5]; /* delete p[7] was vlan_hdr->h_vlan_TCI */ | ||
218 | p[6] = p[4]; /* delete p[6] was ethhdr->h_proto */ | ||
219 | p[5] = p[3]; | ||
220 | p[4] = p[2]; | ||
221 | p[3] = p[1]; | ||
222 | p[2] = p[0]; | ||
223 | } | ||
224 | |||
225 | static __always_inline | ||
226 | void shift_mac_4bytes_32bit(void *data) | ||
227 | { | ||
228 | __u32 *p = data; | ||
229 | |||
230 | /* Assuming VLAN hdr present. The 4 bytes in p[3] that gets | ||
231 | * overwritten, is ethhdr->h_proto and vlan_hdr->h_vlan_TCI. | ||
232 | * The vlan_hdr->h_vlan_encapsulated_proto take over role as | ||
233 | * ethhdr->h_proto. | ||
234 | */ | ||
235 | p[3] = p[2]; | ||
236 | p[2] = p[1]; | ||
237 | p[1] = p[0]; | ||
238 | } | ||
239 | |||
240 | SEC("xdp_vlan_remove_outer2") | ||
241 | int xdp_prognum3(struct xdp_md *ctx) | ||
242 | { | ||
243 | void *data_end = (void *)(long)ctx->data_end; | ||
244 | void *data = (void *)(long)ctx->data; | ||
245 | struct ethhdr *orig_eth = data; | ||
246 | struct parse_pkt pkt = { 0 }; | ||
247 | |||
248 | if (!parse_eth_frame(orig_eth, data_end, &pkt)) | ||
249 | return XDP_ABORTED; | ||
250 | |||
251 | /* Skip packet if no outer VLAN was detected */ | ||
252 | if (pkt.vlan_outer_offset == 0) | ||
253 | return XDP_PASS; | ||
254 | |||
255 | /* Simply shift down MAC addrs 4 bytes, overwrite h_proto + TCI */ | ||
256 | shift_mac_4bytes_32bit(data); | ||
257 | |||
258 | /* Move start of packet header seen by Linux kernel stack */ | ||
259 | bpf_xdp_adjust_head(ctx, VLAN_HDR_SZ); | ||
260 | |||
261 | return XDP_PASS; | ||
262 | } | ||
263 | |||
264 | /*===================================== | ||
265 | * BELOW: TC-hook based ebpf programs | ||
266 | * ==================================== | ||
267 | * The TC-clsact eBPF programs (currently) need to be attach via TC commands | ||
268 | */ | ||
269 | |||
270 | SEC("tc_vlan_push") | ||
271 | int _tc_progA(struct __sk_buff *ctx) | ||
272 | { | ||
273 | bpf_skb_vlan_push(ctx, bpf_htons(ETH_P_8021Q), TESTVLAN); | ||
274 | |||
275 | return TC_ACT_OK; | ||
276 | } | ||
277 | /* | ||
278 | Commands to setup TC to use above bpf prog: | ||
279 | |||
280 | export ROOTDEV=ixgbe2 | ||
281 | export FILE=xdp_vlan01_kern.o | ||
282 | |||
283 | # Re-attach clsact to clear/flush existing role | ||
284 | tc qdisc del dev $ROOTDEV clsact 2> /dev/null ;\ | ||
285 | tc qdisc add dev $ROOTDEV clsact | ||
286 | |||
287 | # Attach BPF prog EGRESS | ||
288 | tc filter add dev $ROOTDEV egress \ | ||
289 | prio 1 handle 1 bpf da obj $FILE sec tc_vlan_push | ||
290 | |||
291 | tc filter show dev $ROOTDEV egress | ||
292 | */ | ||
diff --git a/tools/testing/selftests/bpf/test_xdp_vlan.sh b/tools/testing/selftests/bpf/test_xdp_vlan.sh new file mode 100755 index 000000000000..51a3a31d1aac --- /dev/null +++ b/tools/testing/selftests/bpf/test_xdp_vlan.sh | |||
@@ -0,0 +1,195 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | TESTNAME=xdp_vlan | ||
4 | |||
5 | usage() { | ||
6 | echo "Testing XDP + TC eBPF VLAN manipulations: $TESTNAME" | ||
7 | echo "" | ||
8 | echo "Usage: $0 [-vfh]" | ||
9 | echo " -v | --verbose : Verbose" | ||
10 | echo " --flush : Flush before starting (e.g. after --interactive)" | ||
11 | echo " --interactive : Keep netns setup running after test-run" | ||
12 | echo "" | ||
13 | } | ||
14 | |||
15 | cleanup() | ||
16 | { | ||
17 | local status=$? | ||
18 | |||
19 | if [ "$status" = "0" ]; then | ||
20 | echo "selftests: $TESTNAME [PASS]"; | ||
21 | else | ||
22 | echo "selftests: $TESTNAME [FAILED]"; | ||
23 | fi | ||
24 | |||
25 | if [ -n "$INTERACTIVE" ]; then | ||
26 | echo "Namespace setup still active explore with:" | ||
27 | echo " ip netns exec ns1 bash" | ||
28 | echo " ip netns exec ns2 bash" | ||
29 | exit $status | ||
30 | fi | ||
31 | |||
32 | set +e | ||
33 | ip link del veth1 2> /dev/null | ||
34 | ip netns del ns1 2> /dev/null | ||
35 | ip netns del ns2 2> /dev/null | ||
36 | } | ||
37 | |||
38 | # Using external program "getopt" to get --long-options | ||
39 | OPTIONS=$(getopt -o hvfi: \ | ||
40 | --long verbose,flush,help,interactive,debug -- "$@") | ||
41 | if (( $? != 0 )); then | ||
42 | usage | ||
43 | echo "selftests: $TESTNAME [FAILED] Error calling getopt, unknown option?" | ||
44 | exit 2 | ||
45 | fi | ||
46 | eval set -- "$OPTIONS" | ||
47 | |||
48 | ## --- Parse command line arguments / parameters --- | ||
49 | while true; do | ||
50 | case "$1" in | ||
51 | -v | --verbose) | ||
52 | export VERBOSE=yes | ||
53 | shift | ||
54 | ;; | ||
55 | -i | --interactive | --debug ) | ||
56 | INTERACTIVE=yes | ||
57 | shift | ||
58 | ;; | ||
59 | -f | --flush ) | ||
60 | cleanup | ||
61 | shift | ||
62 | ;; | ||
63 | -- ) | ||
64 | shift | ||
65 | break | ||
66 | ;; | ||
67 | -h | --help ) | ||
68 | usage; | ||
69 | echo "selftests: $TESTNAME [SKIP] usage help info requested" | ||
70 | exit 0 | ||
71 | ;; | ||
72 | * ) | ||
73 | shift | ||
74 | break | ||
75 | ;; | ||
76 | esac | ||
77 | done | ||
78 | |||
79 | if [ "$EUID" -ne 0 ]; then | ||
80 | echo "selftests: $TESTNAME [FAILED] need root privileges" | ||
81 | exit 1 | ||
82 | fi | ||
83 | |||
84 | ip link set dev lo xdp off 2>/dev/null > /dev/null | ||
85 | if [ $? -ne 0 ];then | ||
86 | echo "selftests: $TESTNAME [SKIP] need ip xdp support" | ||
87 | exit 0 | ||
88 | fi | ||
89 | |||
90 | # Interactive mode likely require us to cleanup netns | ||
91 | if [ -n "$INTERACTIVE" ]; then | ||
92 | ip link del veth1 2> /dev/null | ||
93 | ip netns del ns1 2> /dev/null | ||
94 | ip netns del ns2 2> /dev/null | ||
95 | fi | ||
96 | |||
97 | # Exit on failure | ||
98 | set -e | ||
99 | |||
100 | # Some shell-tools dependencies | ||
101 | which ip > /dev/null | ||
102 | which tc > /dev/null | ||
103 | which ethtool > /dev/null | ||
104 | |||
105 | # Make rest of shell verbose, showing comments as doc/info | ||
106 | if [ -n "$VERBOSE" ]; then | ||
107 | set -v | ||
108 | fi | ||
109 | |||
110 | # Create two namespaces | ||
111 | ip netns add ns1 | ||
112 | ip netns add ns2 | ||
113 | |||
114 | # Run cleanup if failing or on kill | ||
115 | trap cleanup 0 2 3 6 9 | ||
116 | |||
117 | # Create veth pair | ||
118 | ip link add veth1 type veth peer name veth2 | ||
119 | |||
120 | # Move veth1 and veth2 into the respective namespaces | ||
121 | ip link set veth1 netns ns1 | ||
122 | ip link set veth2 netns ns2 | ||
123 | |||
124 | # NOTICE: XDP require VLAN header inside packet payload | ||
125 | # - Thus, disable VLAN offloading driver features | ||
126 | # - For veth REMEMBER TX side VLAN-offload | ||
127 | # | ||
128 | # Disable rx-vlan-offload (mostly needed on ns1) | ||
129 | ip netns exec ns1 ethtool -K veth1 rxvlan off | ||
130 | ip netns exec ns2 ethtool -K veth2 rxvlan off | ||
131 | # | ||
132 | # Disable tx-vlan-offload (mostly needed on ns2) | ||
133 | ip netns exec ns2 ethtool -K veth2 txvlan off | ||
134 | ip netns exec ns1 ethtool -K veth1 txvlan off | ||
135 | |||
136 | export IPADDR1=100.64.41.1 | ||
137 | export IPADDR2=100.64.41.2 | ||
138 | |||
139 | # In ns1/veth1 add IP-addr on plain net_device | ||
140 | ip netns exec ns1 ip addr add ${IPADDR1}/24 dev veth1 | ||
141 | ip netns exec ns1 ip link set veth1 up | ||
142 | |||
143 | # In ns2/veth2 create VLAN device | ||
144 | export VLAN=4011 | ||
145 | export DEVNS2=veth2 | ||
146 | ip netns exec ns2 ip link add link $DEVNS2 name $DEVNS2.$VLAN type vlan id $VLAN | ||
147 | ip netns exec ns2 ip addr add ${IPADDR2}/24 dev $DEVNS2.$VLAN | ||
148 | ip netns exec ns2 ip link set $DEVNS2 up | ||
149 | ip netns exec ns2 ip link set $DEVNS2.$VLAN up | ||
150 | |||
151 | # Bringup lo in netns (to avoids confusing people using --interactive) | ||
152 | ip netns exec ns1 ip link set lo up | ||
153 | ip netns exec ns2 ip link set lo up | ||
154 | |||
155 | # At this point, the hosts cannot reach each-other, | ||
156 | # because ns2 are using VLAN tags on the packets. | ||
157 | |||
158 | ip netns exec ns2 sh -c 'ping -W 1 -c 1 100.64.41.1 || echo "Okay ping fails"' | ||
159 | |||
160 | |||
161 | # Now we can use the test_xdp_vlan.c program to pop/push these VLAN tags | ||
162 | # ---------------------------------------------------------------------- | ||
163 | # In ns1: ingress use XDP to remove VLAN tags | ||
164 | export DEVNS1=veth1 | ||
165 | export FILE=test_xdp_vlan.o | ||
166 | |||
167 | # First test: Remove VLAN by setting VLAN ID 0, using "xdp_vlan_change" | ||
168 | export XDP_PROG=xdp_vlan_change | ||
169 | ip netns exec ns1 ip link set $DEVNS1 xdp object $FILE section $XDP_PROG | ||
170 | |||
171 | # In ns1: egress use TC to add back VLAN tag 4011 | ||
172 | # (del cmd) | ||
173 | # tc qdisc del dev $DEVNS1 clsact 2> /dev/null | ||
174 | # | ||
175 | ip netns exec ns1 tc qdisc add dev $DEVNS1 clsact | ||
176 | ip netns exec ns1 tc filter add dev $DEVNS1 egress \ | ||
177 | prio 1 handle 1 bpf da obj $FILE sec tc_vlan_push | ||
178 | |||
179 | # Now the namespaces can reach each-other, test with ping: | ||
180 | ip netns exec ns2 ping -W 2 -c 3 $IPADDR1 | ||
181 | ip netns exec ns1 ping -W 2 -c 3 $IPADDR2 | ||
182 | |||
183 | # Second test: Replace xdp prog, that fully remove vlan header | ||
184 | # | ||
185 | # Catch kernel bug for generic-XDP, that does didn't allow us to | ||
186 | # remove a VLAN header, because skb->protocol still contain VLAN | ||
187 | # ETH_P_8021Q indication, and this cause overwriting of our changes. | ||
188 | # | ||
189 | export XDP_PROG=xdp_vlan_remove_outer2 | ||
190 | ip netns exec ns1 ip link set $DEVNS1 xdp off | ||
191 | ip netns exec ns1 ip link set $DEVNS1 xdp object $FILE section $XDP_PROG | ||
192 | |||
193 | # Now the namespaces should still be able reach each-other, test with ping: | ||
194 | ip netns exec ns2 ping -W 2 -c 3 $IPADDR1 | ||
195 | ip netns exec ns1 ping -W 2 -c 3 $IPADDR2 | ||
diff --git a/tools/testing/selftests/bpf/trace_helpers.c b/tools/testing/selftests/bpf/trace_helpers.c index cabe2a3a3b30..4cdb63bf0521 100644 --- a/tools/testing/selftests/bpf/trace_helpers.c +++ b/tools/testing/selftests/bpf/trace_helpers.c | |||
@@ -41,6 +41,7 @@ int load_kallsyms(void) | |||
41 | syms[i].name = strdup(func); | 41 | syms[i].name = strdup(func); |
42 | i++; | 42 | i++; |
43 | } | 43 | } |
44 | fclose(f); | ||
44 | sym_cnt = i; | 45 | sym_cnt = i; |
45 | qsort(syms, sym_cnt, sizeof(struct ksym), ksym_cmp); | 46 | qsort(syms, sym_cnt, sizeof(struct ksym), ksym_cmp); |
46 | return 0; | 47 | return 0; |
@@ -124,10 +125,11 @@ struct perf_event_sample { | |||
124 | char data[]; | 125 | char data[]; |
125 | }; | 126 | }; |
126 | 127 | ||
127 | static enum bpf_perf_event_ret bpf_perf_event_print(void *event, void *priv) | 128 | static enum bpf_perf_event_ret |
129 | bpf_perf_event_print(struct perf_event_header *hdr, void *private_data) | ||
128 | { | 130 | { |
129 | struct perf_event_sample *e = event; | 131 | struct perf_event_sample *e = (struct perf_event_sample *)hdr; |
130 | perf_event_print_fn fn = priv; | 132 | perf_event_print_fn fn = private_data; |
131 | int ret; | 133 | int ret; |
132 | 134 | ||
133 | if (e->header.type == PERF_RECORD_SAMPLE) { | 135 | if (e->header.type == PERF_RECORD_SAMPLE) { |
diff --git a/tools/testing/selftests/bpf/with_addr.sh b/tools/testing/selftests/bpf/with_addr.sh new file mode 100755 index 000000000000..ffcd3953f94c --- /dev/null +++ b/tools/testing/selftests/bpf/with_addr.sh | |||
@@ -0,0 +1,54 @@ | |||
1 | #!/bin/bash | ||
2 | # SPDX-License-Identifier: GPL-2.0 | ||
3 | # | ||
4 | # add private ipv4 and ipv6 addresses to loopback | ||
5 | |||
6 | readonly V6_INNER='100::a/128' | ||
7 | readonly V4_INNER='192.168.0.1/32' | ||
8 | |||
9 | if getopts ":s" opt; then | ||
10 | readonly SIT_DEV_NAME='sixtofourtest0' | ||
11 | readonly V6_SIT='2::/64' | ||
12 | readonly V4_SIT='172.17.0.1/32' | ||
13 | shift | ||
14 | fi | ||
15 | |||
16 | fail() { | ||
17 | echo "error: $*" 1>&2 | ||
18 | exit 1 | ||
19 | } | ||
20 | |||
21 | setup() { | ||
22 | ip -6 addr add "${V6_INNER}" dev lo || fail 'failed to setup v6 address' | ||
23 | ip -4 addr add "${V4_INNER}" dev lo || fail 'failed to setup v4 address' | ||
24 | |||
25 | if [[ -n "${V6_SIT}" ]]; then | ||
26 | ip link add "${SIT_DEV_NAME}" type sit remote any local any \ | ||
27 | || fail 'failed to add sit' | ||
28 | ip link set dev "${SIT_DEV_NAME}" up \ | ||
29 | || fail 'failed to bring sit device up' | ||
30 | ip -6 addr add "${V6_SIT}" dev "${SIT_DEV_NAME}" \ | ||
31 | || fail 'failed to setup v6 SIT address' | ||
32 | ip -4 addr add "${V4_SIT}" dev "${SIT_DEV_NAME}" \ | ||
33 | || fail 'failed to setup v4 SIT address' | ||
34 | fi | ||
35 | |||
36 | sleep 2 # avoid race causing bind to fail | ||
37 | } | ||
38 | |||
39 | cleanup() { | ||
40 | if [[ -n "${V6_SIT}" ]]; then | ||
41 | ip -4 addr del "${V4_SIT}" dev "${SIT_DEV_NAME}" | ||
42 | ip -6 addr del "${V6_SIT}" dev "${SIT_DEV_NAME}" | ||
43 | ip link del "${SIT_DEV_NAME}" | ||
44 | fi | ||
45 | |||
46 | ip -4 addr del "${V4_INNER}" dev lo | ||
47 | ip -6 addr del "${V6_INNER}" dev lo | ||
48 | } | ||
49 | |||
50 | trap cleanup EXIT | ||
51 | |||
52 | setup | ||
53 | "$@" | ||
54 | exit "$?" | ||
diff --git a/tools/testing/selftests/bpf/with_tunnels.sh b/tools/testing/selftests/bpf/with_tunnels.sh new file mode 100755 index 000000000000..e24949ed3a20 --- /dev/null +++ b/tools/testing/selftests/bpf/with_tunnels.sh | |||
@@ -0,0 +1,36 @@ | |||
1 | #!/bin/bash | ||
2 | # SPDX-License-Identifier: GPL-2.0 | ||
3 | # | ||
4 | # setup tunnels for flow dissection test | ||
5 | |||
6 | readonly SUFFIX="test_$(mktemp -u XXXX)" | ||
7 | CONFIG="remote 127.0.0.2 local 127.0.0.1 dev lo" | ||
8 | |||
9 | setup() { | ||
10 | ip link add "ipip_${SUFFIX}" type ipip ${CONFIG} | ||
11 | ip link add "gre_${SUFFIX}" type gre ${CONFIG} | ||
12 | ip link add "sit_${SUFFIX}" type sit ${CONFIG} | ||
13 | |||
14 | echo "tunnels before test:" | ||
15 | ip tunnel show | ||
16 | |||
17 | ip link set "ipip_${SUFFIX}" up | ||
18 | ip link set "gre_${SUFFIX}" up | ||
19 | ip link set "sit_${SUFFIX}" up | ||
20 | } | ||
21 | |||
22 | |||
23 | cleanup() { | ||
24 | ip tunnel del "ipip_${SUFFIX}" | ||
25 | ip tunnel del "gre_${SUFFIX}" | ||
26 | ip tunnel del "sit_${SUFFIX}" | ||
27 | |||
28 | echo "tunnels after test:" | ||
29 | ip tunnel show | ||
30 | } | ||
31 | |||
32 | trap cleanup EXIT | ||
33 | |||
34 | setup | ||
35 | "$@" | ||
36 | exit "$?" | ||
diff --git a/tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh b/tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh new file mode 100755 index 000000000000..0150bb2741eb --- /dev/null +++ b/tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh | |||
@@ -0,0 +1,347 @@ | |||
1 | #!/bin/bash | ||
2 | # SPDX-License-Identifier: GPL-2.0 | ||
3 | # | ||
4 | # A test for switch behavior under MC overload. An issue in Spectrum chips | ||
5 | # causes throughput of UC traffic to drop severely when a switch is under heavy | ||
6 | # MC load. This issue can be overcome by putting the switch to MC-aware mode. | ||
7 | # This test verifies that UC performance stays intact even as the switch is | ||
8 | # under MC flood, and therefore that the MC-aware mode is enabled and correctly | ||
9 | # configured. | ||
10 | # | ||
11 | # Because mlxsw throttles CPU port, the traffic can't actually reach userspace | ||
12 | # at full speed. That makes it impossible to use iperf3 to simply measure the | ||
13 | # throughput, because many packets (that reach $h3) don't get to the kernel at | ||
14 | # all even in UDP mode (the situation is even worse in TCP mode, where one can't | ||
15 | # hope to see more than a couple Mbps). | ||
16 | # | ||
17 | # So instead we send traffic with mausezahn and use RX ethtool counters at $h3. | ||
18 | # Multicast traffic is untagged, unicast traffic is tagged with PCP 1. Therefore | ||
19 | # each gets a different priority and we can use per-prio ethtool counters to | ||
20 | # measure the throughput. In order to avoid prioritizing unicast traffic, prio | ||
21 | # qdisc is installed on $swp3 and maps all priorities to the same band #7 (and | ||
22 | # thus TC 0). | ||
23 | # | ||
24 | # Mausezahn can't actually saturate the links unless it's using large frames. | ||
25 | # Thus we set MTU to 10K on all involved interfaces. Then both unicast and | ||
26 | # multicast traffic uses 8K frames. | ||
27 | # | ||
28 | # +-----------------------+ +----------------------------------+ | ||
29 | # | H1 | | H2 | | ||
30 | # | | | unicast --> + $h2.111 | | ||
31 | # | | | traffic | 192.0.2.129/28 | | ||
32 | # | multicast | | | e-qos-map 0:1 | | ||
33 | # | traffic | | | | | ||
34 | # | $h1 + <----- | | + $h2 | | ||
35 | # +-----|-----------------+ +--------------|-------------------+ | ||
36 | # | | | ||
37 | # +-----|-------------------------------------------------|-------------------+ | ||
38 | # | + $swp1 + $swp2 | | ||
39 | # | | >1Gbps | >1Gbps | | ||
40 | # | +---|----------------+ +----------|----------------+ | | ||
41 | # | | + $swp1.1 | | + $swp2.111 | | | ||
42 | # | | BR1 | SW | BR111 | | | ||
43 | # | | + $swp3.1 | | + $swp3.111 | | | ||
44 | # | +---|----------------+ +----------|----------------+ | | ||
45 | # | \_________________________________________________/ | | ||
46 | # | | | | ||
47 | # | + $swp3 | | ||
48 | # | | 1Gbps bottleneck | | ||
49 | # | | prio qdisc: {0..7} -> 7 | | ||
50 | # +------------------------------------|--------------------------------------+ | ||
51 | # | | ||
52 | # +--|-----------------+ | ||
53 | # | + $h3 H3 | | ||
54 | # | | | | ||
55 | # | + $h3.111 | | ||
56 | # | 192.0.2.130/28 | | ||
57 | # +--------------------+ | ||
58 | |||
59 | ALL_TESTS=" | ||
60 | ping_ipv4 | ||
61 | test_mc_aware | ||
62 | " | ||
63 | |||
64 | lib_dir=$(dirname $0)/../../../net/forwarding | ||
65 | |||
66 | NUM_NETIFS=6 | ||
67 | source $lib_dir/lib.sh | ||
68 | |||
69 | h1_create() | ||
70 | { | ||
71 | simple_if_init $h1 | ||
72 | mtu_set $h1 10000 | ||
73 | } | ||
74 | |||
75 | h1_destroy() | ||
76 | { | ||
77 | mtu_restore $h1 | ||
78 | simple_if_fini $h1 | ||
79 | } | ||
80 | |||
81 | h2_create() | ||
82 | { | ||
83 | simple_if_init $h2 | ||
84 | mtu_set $h2 10000 | ||
85 | |||
86 | vlan_create $h2 111 v$h2 192.0.2.129/28 | ||
87 | ip link set dev $h2.111 type vlan egress-qos-map 0:1 | ||
88 | } | ||
89 | |||
90 | h2_destroy() | ||
91 | { | ||
92 | vlan_destroy $h2 111 | ||
93 | |||
94 | mtu_restore $h2 | ||
95 | simple_if_fini $h2 | ||
96 | } | ||
97 | |||
98 | h3_create() | ||
99 | { | ||
100 | simple_if_init $h3 | ||
101 | mtu_set $h3 10000 | ||
102 | |||
103 | vlan_create $h3 111 v$h3 192.0.2.130/28 | ||
104 | } | ||
105 | |||
106 | h3_destroy() | ||
107 | { | ||
108 | vlan_destroy $h3 111 | ||
109 | |||
110 | mtu_restore $h3 | ||
111 | simple_if_fini $h3 | ||
112 | } | ||
113 | |||
114 | switch_create() | ||
115 | { | ||
116 | ip link set dev $swp1 up | ||
117 | mtu_set $swp1 10000 | ||
118 | |||
119 | ip link set dev $swp2 up | ||
120 | mtu_set $swp2 10000 | ||
121 | |||
122 | ip link set dev $swp3 up | ||
123 | mtu_set $swp3 10000 | ||
124 | |||
125 | vlan_create $swp2 111 | ||
126 | vlan_create $swp3 111 | ||
127 | |||
128 | ethtool -s $swp3 speed 1000 autoneg off | ||
129 | tc qdisc replace dev $swp3 root handle 3: \ | ||
130 | prio bands 8 priomap 7 7 7 7 7 7 7 7 | ||
131 | |||
132 | ip link add name br1 type bridge vlan_filtering 0 | ||
133 | ip link set dev br1 up | ||
134 | ip link set dev $swp1 master br1 | ||
135 | ip link set dev $swp3 master br1 | ||
136 | |||
137 | ip link add name br111 type bridge vlan_filtering 0 | ||
138 | ip link set dev br111 up | ||
139 | ip link set dev $swp2.111 master br111 | ||
140 | ip link set dev $swp3.111 master br111 | ||
141 | } | ||
142 | |||
143 | switch_destroy() | ||
144 | { | ||
145 | ip link del dev br111 | ||
146 | ip link del dev br1 | ||
147 | |||
148 | tc qdisc del dev $swp3 root handle 3: | ||
149 | ethtool -s $swp3 autoneg on | ||
150 | |||
151 | vlan_destroy $swp3 111 | ||
152 | vlan_destroy $swp2 111 | ||
153 | |||
154 | mtu_restore $swp3 | ||
155 | ip link set dev $swp3 down | ||
156 | |||
157 | mtu_restore $swp2 | ||
158 | ip link set dev $swp2 down | ||
159 | |||
160 | mtu_restore $swp1 | ||
161 | ip link set dev $swp1 down | ||
162 | } | ||
163 | |||
164 | setup_prepare() | ||
165 | { | ||
166 | h1=${NETIFS[p1]} | ||
167 | swp1=${NETIFS[p2]} | ||
168 | |||
169 | swp2=${NETIFS[p3]} | ||
170 | h2=${NETIFS[p4]} | ||
171 | |||
172 | swp3=${NETIFS[p5]} | ||
173 | h3=${NETIFS[p6]} | ||
174 | |||
175 | h3mac=$(mac_get $h3) | ||
176 | |||
177 | vrf_prepare | ||
178 | |||
179 | h1_create | ||
180 | h2_create | ||
181 | h3_create | ||
182 | switch_create | ||
183 | } | ||
184 | |||
185 | cleanup() | ||
186 | { | ||
187 | pre_cleanup | ||
188 | |||
189 | switch_destroy | ||
190 | h3_destroy | ||
191 | h2_destroy | ||
192 | h1_destroy | ||
193 | |||
194 | vrf_cleanup | ||
195 | } | ||
196 | |||
197 | ping_ipv4() | ||
198 | { | ||
199 | ping_test $h2 192.0.2.130 | ||
200 | } | ||
201 | |||
202 | humanize() | ||
203 | { | ||
204 | local speed=$1; shift | ||
205 | |||
206 | for unit in bps Kbps Mbps Gbps; do | ||
207 | if (($(echo "$speed < 1024" | bc))); then | ||
208 | break | ||
209 | fi | ||
210 | |||
211 | speed=$(echo "scale=1; $speed / 1024" | bc) | ||
212 | done | ||
213 | |||
214 | echo "$speed${unit}" | ||
215 | } | ||
216 | |||
217 | rate() | ||
218 | { | ||
219 | local t0=$1; shift | ||
220 | local t1=$1; shift | ||
221 | local interval=$1; shift | ||
222 | |||
223 | echo $((8 * (t1 - t0) / interval)) | ||
224 | } | ||
225 | |||
226 | check_rate() | ||
227 | { | ||
228 | local rate=$1; shift | ||
229 | local min=$1; shift | ||
230 | local what=$1; shift | ||
231 | |||
232 | if ((rate > min)); then | ||
233 | return 0 | ||
234 | fi | ||
235 | |||
236 | echo "$what $(humanize $ir) < $(humanize $min_ingress)" > /dev/stderr | ||
237 | return 1 | ||
238 | } | ||
239 | |||
240 | measure_uc_rate() | ||
241 | { | ||
242 | local what=$1; shift | ||
243 | |||
244 | local interval=10 | ||
245 | local i | ||
246 | local ret=0 | ||
247 | |||
248 | # Dips in performance might cause momentary ingress rate to drop below | ||
249 | # 1Gbps. That wouldn't saturate egress and MC would thus get through, | ||
250 | # seemingly winning bandwidth on account of UC. Demand at least 2Gbps | ||
251 | # average ingress rate to somewhat mitigate this. | ||
252 | local min_ingress=2147483648 | ||
253 | |||
254 | mausezahn $h2.111 -p 8000 -A 192.0.2.129 -B 192.0.2.130 -c 0 \ | ||
255 | -a own -b $h3mac -t udp -q & | ||
256 | sleep 1 | ||
257 | |||
258 | for i in {5..0}; do | ||
259 | local t0=$(ethtool_stats_get $h3 rx_octets_prio_1) | ||
260 | local u0=$(ethtool_stats_get $swp2 rx_octets_prio_1) | ||
261 | sleep $interval | ||
262 | local t1=$(ethtool_stats_get $h3 rx_octets_prio_1) | ||
263 | local u1=$(ethtool_stats_get $swp2 rx_octets_prio_1) | ||
264 | |||
265 | local ir=$(rate $u0 $u1 $interval) | ||
266 | local er=$(rate $t0 $t1 $interval) | ||
267 | |||
268 | if check_rate $ir $min_ingress "$what ingress rate"; then | ||
269 | break | ||
270 | fi | ||
271 | |||
272 | # Fail the test if we can't get the throughput. | ||
273 | if ((i == 0)); then | ||
274 | ret=1 | ||
275 | fi | ||
276 | done | ||
277 | |||
278 | # Suppress noise from killing mausezahn. | ||
279 | { kill %% && wait; } 2>/dev/null | ||
280 | |||
281 | echo $ir $er | ||
282 | exit $ret | ||
283 | } | ||
284 | |||
285 | test_mc_aware() | ||
286 | { | ||
287 | RET=0 | ||
288 | |||
289 | local -a uc_rate | ||
290 | uc_rate=($(measure_uc_rate "UC-only")) | ||
291 | check_err $? "Could not get high enough UC-only ingress rate" | ||
292 | local ucth1=${uc_rate[1]} | ||
293 | |||
294 | mausezahn $h1 -p 8000 -c 0 -a own -b bc -t udp -q & | ||
295 | |||
296 | local d0=$(date +%s) | ||
297 | local t0=$(ethtool_stats_get $h3 rx_octets_prio_0) | ||
298 | local u0=$(ethtool_stats_get $swp1 rx_octets_prio_0) | ||
299 | |||
300 | local -a uc_rate_2 | ||
301 | uc_rate_2=($(measure_uc_rate "UC+MC")) | ||
302 | check_err $? "Could not get high enough UC+MC ingress rate" | ||
303 | local ucth2=${uc_rate_2[1]} | ||
304 | |||
305 | local d1=$(date +%s) | ||
306 | local t1=$(ethtool_stats_get $h3 rx_octets_prio_0) | ||
307 | local u1=$(ethtool_stats_get $swp1 rx_octets_prio_0) | ||
308 | |||
309 | local deg=$(bc <<< " | ||
310 | scale=2 | ||
311 | ret = 100 * ($ucth1 - $ucth2) / $ucth1 | ||
312 | if (ret > 0) { ret } else { 0 } | ||
313 | ") | ||
314 | check_err $(bc <<< "$deg > 10") | ||
315 | |||
316 | local interval=$((d1 - d0)) | ||
317 | local mc_ir=$(rate $u0 $u1 $interval) | ||
318 | local mc_er=$(rate $t0 $t1 $interval) | ||
319 | |||
320 | # Suppress noise from killing mausezahn. | ||
321 | { kill %% && wait; } 2>/dev/null | ||
322 | |||
323 | log_test "UC performace under MC overload" | ||
324 | |||
325 | echo "UC-only throughput $(humanize $ucth1)" | ||
326 | echo "UC+MC throughput $(humanize $ucth2)" | ||
327 | echo "Degradation $deg %" | ||
328 | echo | ||
329 | echo "Full report:" | ||
330 | echo " UC only:" | ||
331 | echo " ingress UC throughput $(humanize ${uc_rate[0]})" | ||
332 | echo " egress UC throughput $(humanize ${uc_rate[1]})" | ||
333 | echo " UC+MC:" | ||
334 | echo " ingress UC throughput $(humanize ${uc_rate_2[0]})" | ||
335 | echo " egress UC throughput $(humanize ${uc_rate_2[1]})" | ||
336 | echo " ingress MC throughput $(humanize $mc_ir)" | ||
337 | echo " egress MC throughput $(humanize $mc_er)" | ||
338 | } | ||
339 | |||
340 | trap cleanup EXIT | ||
341 | |||
342 | setup_prepare | ||
343 | setup_wait | ||
344 | |||
345 | tests_run | ||
346 | |||
347 | exit $EXIT_STATUS | ||
diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore index 5c34752e1cff..6210ba41c29e 100644 --- a/tools/testing/selftests/kvm/.gitignore +++ b/tools/testing/selftests/kvm/.gitignore | |||
@@ -1,6 +1,8 @@ | |||
1 | cr4_cpuid_sync_test | 1 | /x86_64/cr4_cpuid_sync_test |
2 | platform_info_test | 2 | /x86_64/evmcs_test |
3 | set_sregs_test | 3 | /x86_64/platform_info_test |
4 | sync_regs_test | 4 | /x86_64/set_sregs_test |
5 | vmx_tsc_adjust_test | 5 | /x86_64/sync_regs_test |
6 | state_test | 6 | /x86_64/vmx_tsc_adjust_test |
7 | /x86_64/state_test | ||
8 | /dirty_log_test | ||
diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index ec32dad3c3f0..01a219229238 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile | |||
@@ -1,26 +1,30 @@ | |||
1 | all: | 1 | all: |
2 | 2 | ||
3 | top_srcdir = ../../../../ | 3 | top_srcdir = ../../../.. |
4 | UNAME_M := $(shell uname -m) | 4 | UNAME_M := $(shell uname -m) |
5 | 5 | ||
6 | LIBKVM = lib/assert.c lib/elf.c lib/io.c lib/kvm_util.c lib/sparsebit.c | 6 | LIBKVM = lib/assert.c lib/elf.c lib/io.c lib/kvm_util.c lib/ucall.c lib/sparsebit.c |
7 | LIBKVM_x86_64 = lib/x86.c lib/vmx.c | 7 | LIBKVM_x86_64 = lib/x86_64/processor.c lib/x86_64/vmx.c |
8 | 8 | LIBKVM_aarch64 = lib/aarch64/processor.c | |
9 | TEST_GEN_PROGS_x86_64 = platform_info_test | 9 | |
10 | TEST_GEN_PROGS_x86_64 += set_sregs_test | 10 | TEST_GEN_PROGS_x86_64 = x86_64/platform_info_test |
11 | TEST_GEN_PROGS_x86_64 += sync_regs_test | 11 | TEST_GEN_PROGS_x86_64 += x86_64/set_sregs_test |
12 | TEST_GEN_PROGS_x86_64 += vmx_tsc_adjust_test | 12 | TEST_GEN_PROGS_x86_64 += x86_64/sync_regs_test |
13 | TEST_GEN_PROGS_x86_64 += cr4_cpuid_sync_test | 13 | TEST_GEN_PROGS_x86_64 += x86_64/vmx_tsc_adjust_test |
14 | TEST_GEN_PROGS_x86_64 += state_test | 14 | TEST_GEN_PROGS_x86_64 += x86_64/cr4_cpuid_sync_test |
15 | TEST_GEN_PROGS_x86_64 += x86_64/state_test | ||
16 | TEST_GEN_PROGS_x86_64 += x86_64/evmcs_test | ||
15 | TEST_GEN_PROGS_x86_64 += dirty_log_test | 17 | TEST_GEN_PROGS_x86_64 += dirty_log_test |
16 | 18 | ||
19 | TEST_GEN_PROGS_aarch64 += dirty_log_test | ||
20 | |||
17 | TEST_GEN_PROGS += $(TEST_GEN_PROGS_$(UNAME_M)) | 21 | TEST_GEN_PROGS += $(TEST_GEN_PROGS_$(UNAME_M)) |
18 | LIBKVM += $(LIBKVM_$(UNAME_M)) | 22 | LIBKVM += $(LIBKVM_$(UNAME_M)) |
19 | 23 | ||
20 | INSTALL_HDR_PATH = $(top_srcdir)/usr | 24 | INSTALL_HDR_PATH = $(top_srcdir)/usr |
21 | LINUX_HDR_PATH = $(INSTALL_HDR_PATH)/include/ | 25 | LINUX_HDR_PATH = $(INSTALL_HDR_PATH)/include/ |
22 | LINUX_TOOL_INCLUDE = $(top_srcdir)tools/include | 26 | LINUX_TOOL_INCLUDE = $(top_srcdir)/tools/include |
23 | CFLAGS += -O2 -g -std=gnu99 -I$(LINUX_TOOL_INCLUDE) -I$(LINUX_HDR_PATH) -Iinclude -I$(<D) -I.. | 27 | CFLAGS += -O2 -g -std=gnu99 -I$(LINUX_TOOL_INCLUDE) -I$(LINUX_HDR_PATH) -Iinclude -I$(<D) -Iinclude/$(UNAME_M) -I.. |
24 | LDFLAGS += -pthread | 28 | LDFLAGS += -pthread |
25 | 29 | ||
26 | # After inclusion, $(OUTPUT) is defined and | 30 | # After inclusion, $(OUTPUT) is defined and |
@@ -29,7 +33,7 @@ include ../lib.mk | |||
29 | 33 | ||
30 | STATIC_LIBS := $(OUTPUT)/libkvm.a | 34 | STATIC_LIBS := $(OUTPUT)/libkvm.a |
31 | LIBKVM_OBJ := $(patsubst %.c, $(OUTPUT)/%.o, $(LIBKVM)) | 35 | LIBKVM_OBJ := $(patsubst %.c, $(OUTPUT)/%.o, $(LIBKVM)) |
32 | EXTRA_CLEAN += $(LIBKVM_OBJ) $(STATIC_LIBS) | 36 | EXTRA_CLEAN += $(LIBKVM_OBJ) $(STATIC_LIBS) cscope.* |
33 | 37 | ||
34 | x := $(shell mkdir -p $(sort $(dir $(LIBKVM_OBJ)))) | 38 | x := $(shell mkdir -p $(sort $(dir $(LIBKVM_OBJ)))) |
35 | $(LIBKVM_OBJ): $(OUTPUT)/%.o: %.c | 39 | $(LIBKVM_OBJ): $(OUTPUT)/%.o: %.c |
@@ -41,3 +45,12 @@ $(OUTPUT)/libkvm.a: $(LIBKVM_OBJ) | |||
41 | all: $(STATIC_LIBS) | 45 | all: $(STATIC_LIBS) |
42 | $(TEST_GEN_PROGS): $(STATIC_LIBS) | 46 | $(TEST_GEN_PROGS): $(STATIC_LIBS) |
43 | $(STATIC_LIBS):| khdr | 47 | $(STATIC_LIBS):| khdr |
48 | |||
49 | cscope: include_paths = $(LINUX_TOOL_INCLUDE) $(LINUX_HDR_PATH) include lib .. | ||
50 | cscope: | ||
51 | $(RM) cscope.* | ||
52 | (find $(include_paths) -name '*.h' \ | ||
53 | -exec realpath --relative-base=$(PWD) {} \;; \ | ||
54 | find . -name '*.c' \ | ||
55 | -exec realpath --relative-base=$(PWD) {} \;) | sort -u > cscope.files | ||
56 | cscope -b | ||
diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c index 0c2cdc105f96..d59820cc2d39 100644 --- a/tools/testing/selftests/kvm/dirty_log_test.c +++ b/tools/testing/selftests/kvm/dirty_log_test.c | |||
@@ -5,6 +5,8 @@ | |||
5 | * Copyright (C) 2018, Red Hat, Inc. | 5 | * Copyright (C) 2018, Red Hat, Inc. |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #define _GNU_SOURCE /* for program_invocation_name */ | ||
9 | |||
8 | #include <stdio.h> | 10 | #include <stdio.h> |
9 | #include <stdlib.h> | 11 | #include <stdlib.h> |
10 | #include <unistd.h> | 12 | #include <unistd.h> |
@@ -15,76 +17,78 @@ | |||
15 | 17 | ||
16 | #include "test_util.h" | 18 | #include "test_util.h" |
17 | #include "kvm_util.h" | 19 | #include "kvm_util.h" |
20 | #include "processor.h" | ||
21 | |||
22 | #define DEBUG printf | ||
18 | 23 | ||
19 | #define DEBUG printf | 24 | #define VCPU_ID 1 |
20 | 25 | ||
21 | #define VCPU_ID 1 | ||
22 | /* The memory slot index to track dirty pages */ | 26 | /* The memory slot index to track dirty pages */ |
23 | #define TEST_MEM_SLOT_INDEX 1 | 27 | #define TEST_MEM_SLOT_INDEX 1 |
24 | /* | 28 | |
25 | * GPA offset of the testing memory slot. Must be bigger than the | 29 | /* Default guest test memory offset, 1G */ |
26 | * default vm mem slot, which is DEFAULT_GUEST_PHY_PAGES. | 30 | #define DEFAULT_GUEST_TEST_MEM 0x40000000 |
27 | */ | 31 | |
28 | #define TEST_MEM_OFFSET (1ULL << 30) /* 1G */ | ||
29 | /* Size of the testing memory slot */ | ||
30 | #define TEST_MEM_PAGES (1ULL << 18) /* 1G for 4K pages */ | ||
31 | /* How many pages to dirty for each guest loop */ | 32 | /* How many pages to dirty for each guest loop */ |
32 | #define TEST_PAGES_PER_LOOP 1024 | 33 | #define TEST_PAGES_PER_LOOP 1024 |
34 | |||
33 | /* How many host loops to run (one KVM_GET_DIRTY_LOG for each loop) */ | 35 | /* How many host loops to run (one KVM_GET_DIRTY_LOG for each loop) */ |
34 | #define TEST_HOST_LOOP_N 32 | 36 | #define TEST_HOST_LOOP_N 32 |
37 | |||
35 | /* Interval for each host loop (ms) */ | 38 | /* Interval for each host loop (ms) */ |
36 | #define TEST_HOST_LOOP_INTERVAL 10 | 39 | #define TEST_HOST_LOOP_INTERVAL 10 |
40 | |||
41 | /* | ||
42 | * Guest/Host shared variables. Ensure addr_gva2hva() and/or | ||
43 | * sync_global_to/from_guest() are used when accessing from | ||
44 | * the host. READ/WRITE_ONCE() should also be used with anything | ||
45 | * that may change. | ||
46 | */ | ||
47 | static uint64_t host_page_size; | ||
48 | static uint64_t guest_page_size; | ||
49 | static uint64_t guest_num_pages; | ||
50 | static uint64_t random_array[TEST_PAGES_PER_LOOP]; | ||
51 | static uint64_t iteration; | ||
37 | 52 | ||
38 | /* | 53 | /* |
39 | * Guest variables. We use these variables to share data between host | 54 | * GPA offset of the testing memory slot. Must be bigger than |
40 | * and guest. There are two copies of the variables, one in host memory | 55 | * DEFAULT_GUEST_PHY_PAGES. |
41 | * (which is unused) and one in guest memory. When the host wants to | ||
42 | * access these variables, it needs to call addr_gva2hva() to access the | ||
43 | * guest copy. | ||
44 | */ | 56 | */ |
45 | uint64_t guest_random_array[TEST_PAGES_PER_LOOP]; | 57 | static uint64_t guest_test_mem = DEFAULT_GUEST_TEST_MEM; |
46 | uint64_t guest_iteration; | ||
47 | uint64_t guest_page_size; | ||
48 | 58 | ||
49 | /* | 59 | /* |
50 | * Writes to the first byte of a random page within the testing memory | 60 | * Continuously write to the first 8 bytes of a random pages within |
51 | * region continuously. | 61 | * the testing memory region. |
52 | */ | 62 | */ |
53 | void guest_code(void) | 63 | static void guest_code(void) |
54 | { | 64 | { |
55 | int i = 0; | 65 | int i; |
56 | uint64_t volatile *array = guest_random_array; | ||
57 | uint64_t volatile *guest_addr; | ||
58 | 66 | ||
59 | while (true) { | 67 | while (true) { |
60 | for (i = 0; i < TEST_PAGES_PER_LOOP; i++) { | 68 | for (i = 0; i < TEST_PAGES_PER_LOOP; i++) { |
61 | /* | 69 | uint64_t addr = guest_test_mem; |
62 | * Write to the first 8 bytes of a random page | 70 | addr += (READ_ONCE(random_array[i]) % guest_num_pages) |
63 | * on the testing memory region. | 71 | * guest_page_size; |
64 | */ | 72 | addr &= ~(host_page_size - 1); |
65 | guest_addr = (uint64_t *) | 73 | *(uint64_t *)addr = READ_ONCE(iteration); |
66 | (TEST_MEM_OFFSET + | ||
67 | (array[i] % TEST_MEM_PAGES) * guest_page_size); | ||
68 | *guest_addr = guest_iteration; | ||
69 | } | 74 | } |
75 | |||
70 | /* Tell the host that we need more random numbers */ | 76 | /* Tell the host that we need more random numbers */ |
71 | GUEST_SYNC(1); | 77 | GUEST_SYNC(1); |
72 | } | 78 | } |
73 | } | 79 | } |
74 | 80 | ||
75 | /* | 81 | /* Host variables */ |
76 | * Host variables. These variables should only be used by the host | 82 | static bool host_quit; |
77 | * rather than the guest. | ||
78 | */ | ||
79 | bool host_quit; | ||
80 | 83 | ||
81 | /* Points to the test VM memory region on which we track dirty logs */ | 84 | /* Points to the test VM memory region on which we track dirty logs */ |
82 | void *host_test_mem; | 85 | static void *host_test_mem; |
86 | static uint64_t host_num_pages; | ||
83 | 87 | ||
84 | /* For statistics only */ | 88 | /* For statistics only */ |
85 | uint64_t host_dirty_count; | 89 | static uint64_t host_dirty_count; |
86 | uint64_t host_clear_count; | 90 | static uint64_t host_clear_count; |
87 | uint64_t host_track_next_count; | 91 | static uint64_t host_track_next_count; |
88 | 92 | ||
89 | /* | 93 | /* |
90 | * We use this bitmap to track some pages that should have its dirty | 94 | * We use this bitmap to track some pages that should have its dirty |
@@ -93,40 +97,34 @@ uint64_t host_track_next_count; | |||
93 | * page bit is cleared in the latest bitmap, then the system must | 97 | * page bit is cleared in the latest bitmap, then the system must |
94 | * report that write in the next get dirty log call. | 98 | * report that write in the next get dirty log call. |
95 | */ | 99 | */ |
96 | unsigned long *host_bmap_track; | 100 | static unsigned long *host_bmap_track; |
97 | 101 | ||
98 | void generate_random_array(uint64_t *guest_array, uint64_t size) | 102 | static void generate_random_array(uint64_t *guest_array, uint64_t size) |
99 | { | 103 | { |
100 | uint64_t i; | 104 | uint64_t i; |
101 | 105 | ||
102 | for (i = 0; i < size; i++) { | 106 | for (i = 0; i < size; i++) |
103 | guest_array[i] = random(); | 107 | guest_array[i] = random(); |
104 | } | ||
105 | } | 108 | } |
106 | 109 | ||
107 | void *vcpu_worker(void *data) | 110 | static void *vcpu_worker(void *data) |
108 | { | 111 | { |
109 | int ret; | 112 | int ret; |
110 | uint64_t loops, *guest_array, pages_count = 0; | ||
111 | struct kvm_vm *vm = data; | 113 | struct kvm_vm *vm = data; |
114 | uint64_t *guest_array; | ||
115 | uint64_t pages_count = 0; | ||
112 | struct kvm_run *run; | 116 | struct kvm_run *run; |
113 | struct guest_args args; | 117 | struct ucall uc; |
114 | 118 | ||
115 | run = vcpu_state(vm, VCPU_ID); | 119 | run = vcpu_state(vm, VCPU_ID); |
116 | 120 | ||
117 | /* Retrieve the guest random array pointer and cache it */ | 121 | guest_array = addr_gva2hva(vm, (vm_vaddr_t)random_array); |
118 | guest_array = addr_gva2hva(vm, (vm_vaddr_t)guest_random_array); | ||
119 | |||
120 | DEBUG("VCPU starts\n"); | ||
121 | |||
122 | generate_random_array(guest_array, TEST_PAGES_PER_LOOP); | 122 | generate_random_array(guest_array, TEST_PAGES_PER_LOOP); |
123 | 123 | ||
124 | while (!READ_ONCE(host_quit)) { | 124 | while (!READ_ONCE(host_quit)) { |
125 | /* Let the guest to dirty these random pages */ | 125 | /* Let the guest dirty the random pages */ |
126 | ret = _vcpu_run(vm, VCPU_ID); | 126 | ret = _vcpu_run(vm, VCPU_ID); |
127 | guest_args_read(vm, VCPU_ID, &args); | 127 | if (get_ucall(vm, VCPU_ID, &uc) == UCALL_SYNC) { |
128 | if (run->exit_reason == KVM_EXIT_IO && | ||
129 | args.port == GUEST_PORT_SYNC) { | ||
130 | pages_count += TEST_PAGES_PER_LOOP; | 128 | pages_count += TEST_PAGES_PER_LOOP; |
131 | generate_random_array(guest_array, TEST_PAGES_PER_LOOP); | 129 | generate_random_array(guest_array, TEST_PAGES_PER_LOOP); |
132 | } else { | 130 | } else { |
@@ -137,18 +135,20 @@ void *vcpu_worker(void *data) | |||
137 | } | 135 | } |
138 | } | 136 | } |
139 | 137 | ||
140 | DEBUG("VCPU exits, dirtied %"PRIu64" pages\n", pages_count); | 138 | DEBUG("Dirtied %"PRIu64" pages\n", pages_count); |
141 | 139 | ||
142 | return NULL; | 140 | return NULL; |
143 | } | 141 | } |
144 | 142 | ||
145 | void vm_dirty_log_verify(unsigned long *bmap, uint64_t iteration) | 143 | static void vm_dirty_log_verify(unsigned long *bmap) |
146 | { | 144 | { |
147 | uint64_t page; | 145 | uint64_t page; |
148 | uint64_t volatile *value_ptr; | 146 | uint64_t *value_ptr; |
147 | uint64_t step = host_page_size >= guest_page_size ? 1 : | ||
148 | guest_page_size / host_page_size; | ||
149 | 149 | ||
150 | for (page = 0; page < TEST_MEM_PAGES; page++) { | 150 | for (page = 0; page < host_num_pages; page += step) { |
151 | value_ptr = host_test_mem + page * getpagesize(); | 151 | value_ptr = host_test_mem + page * host_page_size; |
152 | 152 | ||
153 | /* If this is a special page that we were tracking... */ | 153 | /* If this is a special page that we were tracking... */ |
154 | if (test_and_clear_bit(page, host_bmap_track)) { | 154 | if (test_and_clear_bit(page, host_bmap_track)) { |
@@ -208,88 +208,117 @@ void vm_dirty_log_verify(unsigned long *bmap, uint64_t iteration) | |||
208 | } | 208 | } |
209 | } | 209 | } |
210 | 210 | ||
211 | void help(char *name) | 211 | static struct kvm_vm *create_vm(enum vm_guest_mode mode, uint32_t vcpuid, |
212 | uint64_t extra_mem_pages, void *guest_code) | ||
212 | { | 213 | { |
213 | puts(""); | 214 | struct kvm_vm *vm; |
214 | printf("usage: %s [-i iterations] [-I interval] [-h]\n", name); | 215 | uint64_t extra_pg_pages = extra_mem_pages / 512 * 2; |
215 | puts(""); | 216 | |
216 | printf(" -i: specify iteration counts (default: %"PRIu64")\n", | 217 | vm = vm_create(mode, DEFAULT_GUEST_PHY_PAGES + extra_pg_pages, O_RDWR); |
217 | TEST_HOST_LOOP_N); | 218 | kvm_vm_elf_load(vm, program_invocation_name, 0, 0); |
218 | printf(" -I: specify interval in ms (default: %"PRIu64" ms)\n", | 219 | #ifdef __x86_64__ |
219 | TEST_HOST_LOOP_INTERVAL); | 220 | vm_create_irqchip(vm); |
220 | puts(""); | 221 | #endif |
221 | exit(0); | 222 | vm_vcpu_add_default(vm, vcpuid, guest_code); |
223 | return vm; | ||
222 | } | 224 | } |
223 | 225 | ||
224 | int main(int argc, char *argv[]) | 226 | static void run_test(enum vm_guest_mode mode, unsigned long iterations, |
227 | unsigned long interval, bool top_offset) | ||
225 | { | 228 | { |
229 | unsigned int guest_pa_bits, guest_page_shift; | ||
226 | pthread_t vcpu_thread; | 230 | pthread_t vcpu_thread; |
227 | struct kvm_vm *vm; | 231 | struct kvm_vm *vm; |
228 | uint64_t volatile *psize, *iteration; | 232 | uint64_t max_gfn; |
229 | unsigned long *bmap, iterations = TEST_HOST_LOOP_N, | 233 | unsigned long *bmap; |
230 | interval = TEST_HOST_LOOP_INTERVAL; | 234 | |
231 | int opt; | 235 | switch (mode) { |
232 | 236 | case VM_MODE_P52V48_4K: | |
233 | while ((opt = getopt(argc, argv, "hi:I:")) != -1) { | 237 | guest_pa_bits = 52; |
234 | switch (opt) { | 238 | guest_page_shift = 12; |
235 | case 'i': | 239 | break; |
236 | iterations = strtol(optarg, NULL, 10); | 240 | case VM_MODE_P52V48_64K: |
237 | break; | 241 | guest_pa_bits = 52; |
238 | case 'I': | 242 | guest_page_shift = 16; |
239 | interval = strtol(optarg, NULL, 10); | 243 | break; |
240 | break; | 244 | case VM_MODE_P40V48_4K: |
241 | case 'h': | 245 | guest_pa_bits = 40; |
242 | default: | 246 | guest_page_shift = 12; |
243 | help(argv[0]); | 247 | break; |
244 | break; | 248 | case VM_MODE_P40V48_64K: |
245 | } | 249 | guest_pa_bits = 40; |
250 | guest_page_shift = 16; | ||
251 | break; | ||
252 | default: | ||
253 | TEST_ASSERT(false, "Unknown guest mode, mode: 0x%x", mode); | ||
246 | } | 254 | } |
247 | 255 | ||
248 | TEST_ASSERT(iterations > 2, "Iteration must be bigger than zero\n"); | 256 | DEBUG("Testing guest mode: %s\n", vm_guest_mode_string(mode)); |
249 | TEST_ASSERT(interval > 0, "Interval must be bigger than zero"); | ||
250 | 257 | ||
251 | DEBUG("Test iterations: %"PRIu64", interval: %"PRIu64" (ms)\n", | 258 | max_gfn = (1ul << (guest_pa_bits - guest_page_shift)) - 1; |
252 | iterations, interval); | 259 | guest_page_size = (1ul << guest_page_shift); |
260 | /* 1G of guest page sized pages */ | ||
261 | guest_num_pages = (1ul << (30 - guest_page_shift)); | ||
262 | host_page_size = getpagesize(); | ||
263 | host_num_pages = (guest_num_pages * guest_page_size) / host_page_size + | ||
264 | !!((guest_num_pages * guest_page_size) % host_page_size); | ||
253 | 265 | ||
254 | srandom(time(0)); | 266 | if (top_offset) { |
267 | guest_test_mem = (max_gfn - guest_num_pages) * guest_page_size; | ||
268 | guest_test_mem &= ~(host_page_size - 1); | ||
269 | } | ||
255 | 270 | ||
256 | bmap = bitmap_alloc(TEST_MEM_PAGES); | 271 | DEBUG("guest test mem offset: 0x%lx\n", guest_test_mem); |
257 | host_bmap_track = bitmap_alloc(TEST_MEM_PAGES); | ||
258 | 272 | ||
259 | vm = vm_create_default(VCPU_ID, TEST_MEM_PAGES, guest_code); | 273 | bmap = bitmap_alloc(host_num_pages); |
274 | host_bmap_track = bitmap_alloc(host_num_pages); | ||
275 | |||
276 | vm = create_vm(mode, VCPU_ID, guest_num_pages, guest_code); | ||
260 | 277 | ||
261 | /* Add an extra memory slot for testing dirty logging */ | 278 | /* Add an extra memory slot for testing dirty logging */ |
262 | vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, | 279 | vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, |
263 | TEST_MEM_OFFSET, | 280 | guest_test_mem, |
264 | TEST_MEM_SLOT_INDEX, | 281 | TEST_MEM_SLOT_INDEX, |
265 | TEST_MEM_PAGES, | 282 | guest_num_pages, |
266 | KVM_MEM_LOG_DIRTY_PAGES); | 283 | KVM_MEM_LOG_DIRTY_PAGES); |
267 | /* Cache the HVA pointer of the region */ | ||
268 | host_test_mem = addr_gpa2hva(vm, (vm_paddr_t)TEST_MEM_OFFSET); | ||
269 | 284 | ||
270 | /* Do 1:1 mapping for the dirty track memory slot */ | 285 | /* Do 1:1 mapping for the dirty track memory slot */ |
271 | virt_map(vm, TEST_MEM_OFFSET, TEST_MEM_OFFSET, | 286 | virt_map(vm, guest_test_mem, guest_test_mem, |
272 | TEST_MEM_PAGES * getpagesize(), 0); | 287 | guest_num_pages * guest_page_size, 0); |
288 | |||
289 | /* Cache the HVA pointer of the region */ | ||
290 | host_test_mem = addr_gpa2hva(vm, (vm_paddr_t)guest_test_mem); | ||
273 | 291 | ||
292 | #ifdef __x86_64__ | ||
274 | vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); | 293 | vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); |
294 | #endif | ||
295 | #ifdef __aarch64__ | ||
296 | ucall_init(vm, UCALL_MMIO, NULL); | ||
297 | #endif | ||
275 | 298 | ||
276 | /* Tell the guest about the page size on the system */ | 299 | /* Export the shared variables to the guest */ |
277 | psize = addr_gva2hva(vm, (vm_vaddr_t)&guest_page_size); | 300 | sync_global_to_guest(vm, host_page_size); |
278 | *psize = getpagesize(); | 301 | sync_global_to_guest(vm, guest_page_size); |
302 | sync_global_to_guest(vm, guest_test_mem); | ||
303 | sync_global_to_guest(vm, guest_num_pages); | ||
279 | 304 | ||
280 | /* Start the iterations */ | 305 | /* Start the iterations */ |
281 | iteration = addr_gva2hva(vm, (vm_vaddr_t)&guest_iteration); | 306 | iteration = 1; |
282 | *iteration = 1; | 307 | sync_global_to_guest(vm, iteration); |
308 | host_quit = false; | ||
309 | host_dirty_count = 0; | ||
310 | host_clear_count = 0; | ||
311 | host_track_next_count = 0; | ||
283 | 312 | ||
284 | /* Start dirtying pages */ | ||
285 | pthread_create(&vcpu_thread, NULL, vcpu_worker, vm); | 313 | pthread_create(&vcpu_thread, NULL, vcpu_worker, vm); |
286 | 314 | ||
287 | while (*iteration < iterations) { | 315 | while (iteration < iterations) { |
288 | /* Give the vcpu thread some time to dirty some pages */ | 316 | /* Give the vcpu thread some time to dirty some pages */ |
289 | usleep(interval * 1000); | 317 | usleep(interval * 1000); |
290 | kvm_vm_get_dirty_log(vm, TEST_MEM_SLOT_INDEX, bmap); | 318 | kvm_vm_get_dirty_log(vm, TEST_MEM_SLOT_INDEX, bmap); |
291 | vm_dirty_log_verify(bmap, *iteration); | 319 | vm_dirty_log_verify(bmap); |
292 | (*iteration)++; | 320 | iteration++; |
321 | sync_global_to_guest(vm, iteration); | ||
293 | } | 322 | } |
294 | 323 | ||
295 | /* Tell the vcpu thread to quit */ | 324 | /* Tell the vcpu thread to quit */ |
@@ -302,7 +331,118 @@ int main(int argc, char *argv[]) | |||
302 | 331 | ||
303 | free(bmap); | 332 | free(bmap); |
304 | free(host_bmap_track); | 333 | free(host_bmap_track); |
334 | ucall_uninit(vm); | ||
305 | kvm_vm_free(vm); | 335 | kvm_vm_free(vm); |
336 | } | ||
337 | |||
338 | static struct vm_guest_modes { | ||
339 | enum vm_guest_mode mode; | ||
340 | bool supported; | ||
341 | bool enabled; | ||
342 | } vm_guest_modes[NUM_VM_MODES] = { | ||
343 | #if defined(__x86_64__) | ||
344 | { VM_MODE_P52V48_4K, 1, 1, }, | ||
345 | { VM_MODE_P52V48_64K, 0, 0, }, | ||
346 | { VM_MODE_P40V48_4K, 0, 0, }, | ||
347 | { VM_MODE_P40V48_64K, 0, 0, }, | ||
348 | #elif defined(__aarch64__) | ||
349 | { VM_MODE_P52V48_4K, 0, 0, }, | ||
350 | { VM_MODE_P52V48_64K, 0, 0, }, | ||
351 | { VM_MODE_P40V48_4K, 1, 1, }, | ||
352 | { VM_MODE_P40V48_64K, 1, 1, }, | ||
353 | #endif | ||
354 | }; | ||
355 | |||
356 | static void help(char *name) | ||
357 | { | ||
358 | int i; | ||
359 | |||
360 | puts(""); | ||
361 | printf("usage: %s [-h] [-i iterations] [-I interval] " | ||
362 | "[-o offset] [-t] [-m mode]\n", name); | ||
363 | puts(""); | ||
364 | printf(" -i: specify iteration counts (default: %"PRIu64")\n", | ||
365 | TEST_HOST_LOOP_N); | ||
366 | printf(" -I: specify interval in ms (default: %"PRIu64" ms)\n", | ||
367 | TEST_HOST_LOOP_INTERVAL); | ||
368 | printf(" -o: guest test memory offset (default: 0x%lx)\n", | ||
369 | DEFAULT_GUEST_TEST_MEM); | ||
370 | printf(" -t: map guest test memory at the top of the allowed " | ||
371 | "physical address range\n"); | ||
372 | printf(" -m: specify the guest mode ID to test " | ||
373 | "(default: test all supported modes)\n" | ||
374 | " This option may be used multiple times.\n" | ||
375 | " Guest mode IDs:\n"); | ||
376 | for (i = 0; i < NUM_VM_MODES; ++i) { | ||
377 | printf(" %d: %s%s\n", | ||
378 | vm_guest_modes[i].mode, | ||
379 | vm_guest_mode_string(vm_guest_modes[i].mode), | ||
380 | vm_guest_modes[i].supported ? " (supported)" : ""); | ||
381 | } | ||
382 | puts(""); | ||
383 | exit(0); | ||
384 | } | ||
385 | |||
386 | int main(int argc, char *argv[]) | ||
387 | { | ||
388 | unsigned long iterations = TEST_HOST_LOOP_N; | ||
389 | unsigned long interval = TEST_HOST_LOOP_INTERVAL; | ||
390 | bool mode_selected = false; | ||
391 | bool top_offset = false; | ||
392 | unsigned int mode; | ||
393 | int opt, i; | ||
394 | |||
395 | while ((opt = getopt(argc, argv, "hi:I:o:tm:")) != -1) { | ||
396 | switch (opt) { | ||
397 | case 'i': | ||
398 | iterations = strtol(optarg, NULL, 10); | ||
399 | break; | ||
400 | case 'I': | ||
401 | interval = strtol(optarg, NULL, 10); | ||
402 | break; | ||
403 | case 'o': | ||
404 | guest_test_mem = strtoull(optarg, NULL, 0); | ||
405 | break; | ||
406 | case 't': | ||
407 | top_offset = true; | ||
408 | break; | ||
409 | case 'm': | ||
410 | if (!mode_selected) { | ||
411 | for (i = 0; i < NUM_VM_MODES; ++i) | ||
412 | vm_guest_modes[i].enabled = 0; | ||
413 | mode_selected = true; | ||
414 | } | ||
415 | mode = strtoul(optarg, NULL, 10); | ||
416 | TEST_ASSERT(mode < NUM_VM_MODES, | ||
417 | "Guest mode ID %d too big", mode); | ||
418 | vm_guest_modes[mode].enabled = 1; | ||
419 | break; | ||
420 | case 'h': | ||
421 | default: | ||
422 | help(argv[0]); | ||
423 | break; | ||
424 | } | ||
425 | } | ||
426 | |||
427 | TEST_ASSERT(iterations > 2, "Iterations must be greater than two"); | ||
428 | TEST_ASSERT(interval > 0, "Interval must be greater than zero"); | ||
429 | TEST_ASSERT(!top_offset || guest_test_mem == DEFAULT_GUEST_TEST_MEM, | ||
430 | "Cannot use both -o [offset] and -t at the same time"); | ||
431 | |||
432 | DEBUG("Test iterations: %"PRIu64", interval: %"PRIu64" (ms)\n", | ||
433 | iterations, interval); | ||
434 | |||
435 | srandom(time(0)); | ||
436 | |||
437 | for (i = 0; i < NUM_VM_MODES; ++i) { | ||
438 | if (!vm_guest_modes[i].enabled) | ||
439 | continue; | ||
440 | TEST_ASSERT(vm_guest_modes[i].supported, | ||
441 | "Guest mode ID %d (%s) not supported.", | ||
442 | vm_guest_modes[i].mode, | ||
443 | vm_guest_mode_string(vm_guest_modes[i].mode)); | ||
444 | run_test(vm_guest_modes[i].mode, iterations, interval, top_offset); | ||
445 | } | ||
306 | 446 | ||
307 | return 0; | 447 | return 0; |
308 | } | 448 | } |
diff --git a/tools/testing/selftests/kvm/include/aarch64/processor.h b/tools/testing/selftests/kvm/include/aarch64/processor.h new file mode 100644 index 000000000000..9ef2ab1a0c08 --- /dev/null +++ b/tools/testing/selftests/kvm/include/aarch64/processor.h | |||
@@ -0,0 +1,55 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | /* | ||
3 | * AArch64 processor specific defines | ||
4 | * | ||
5 | * Copyright (C) 2018, Red Hat, Inc. | ||
6 | */ | ||
7 | #ifndef SELFTEST_KVM_PROCESSOR_H | ||
8 | #define SELFTEST_KVM_PROCESSOR_H | ||
9 | |||
10 | #include "kvm_util.h" | ||
11 | |||
12 | |||
13 | #define ARM64_CORE_REG(x) (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \ | ||
14 | KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(x)) | ||
15 | |||
16 | #define CPACR_EL1 3, 0, 1, 0, 2 | ||
17 | #define TCR_EL1 3, 0, 2, 0, 2 | ||
18 | #define MAIR_EL1 3, 0, 10, 2, 0 | ||
19 | #define TTBR0_EL1 3, 0, 2, 0, 0 | ||
20 | #define SCTLR_EL1 3, 0, 1, 0, 0 | ||
21 | |||
22 | /* | ||
23 | * Default MAIR | ||
24 | * index attribute | ||
25 | * DEVICE_nGnRnE 0 0000:0000 | ||
26 | * DEVICE_nGnRE 1 0000:0100 | ||
27 | * DEVICE_GRE 2 0000:1100 | ||
28 | * NORMAL_NC 3 0100:0100 | ||
29 | * NORMAL 4 1111:1111 | ||
30 | * NORMAL_WT 5 1011:1011 | ||
31 | */ | ||
32 | #define DEFAULT_MAIR_EL1 ((0x00ul << (0 * 8)) | \ | ||
33 | (0x04ul << (1 * 8)) | \ | ||
34 | (0x0cul << (2 * 8)) | \ | ||
35 | (0x44ul << (3 * 8)) | \ | ||
36 | (0xfful << (4 * 8)) | \ | ||
37 | (0xbbul << (5 * 8))) | ||
38 | |||
39 | static inline void get_reg(struct kvm_vm *vm, uint32_t vcpuid, uint64_t id, uint64_t *addr) | ||
40 | { | ||
41 | struct kvm_one_reg reg; | ||
42 | reg.id = id; | ||
43 | reg.addr = (uint64_t)addr; | ||
44 | vcpu_ioctl(vm, vcpuid, KVM_GET_ONE_REG, ®); | ||
45 | } | ||
46 | |||
47 | static inline void set_reg(struct kvm_vm *vm, uint32_t vcpuid, uint64_t id, uint64_t val) | ||
48 | { | ||
49 | struct kvm_one_reg reg; | ||
50 | reg.id = id; | ||
51 | reg.addr = (uint64_t)&val; | ||
52 | vcpu_ioctl(vm, vcpuid, KVM_SET_ONE_REG, ®); | ||
53 | } | ||
54 | |||
55 | #endif /* SELFTEST_KVM_PROCESSOR_H */ | ||
diff --git a/tools/testing/selftests/kvm/include/evmcs.h b/tools/testing/selftests/kvm/include/evmcs.h new file mode 100644 index 000000000000..4059014d93ea --- /dev/null +++ b/tools/testing/selftests/kvm/include/evmcs.h | |||
@@ -0,0 +1,1098 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | /* | ||
3 | * tools/testing/selftests/kvm/include/vmx.h | ||
4 | * | ||
5 | * Copyright (C) 2018, Red Hat, Inc. | ||
6 | * | ||
7 | */ | ||
8 | |||
9 | #ifndef SELFTEST_KVM_EVMCS_H | ||
10 | #define SELFTEST_KVM_EVMCS_H | ||
11 | |||
12 | #include <stdint.h> | ||
13 | #include "vmx.h" | ||
14 | |||
15 | #define u16 uint16_t | ||
16 | #define u32 uint32_t | ||
17 | #define u64 uint64_t | ||
18 | |||
19 | extern bool enable_evmcs; | ||
20 | |||
21 | struct hv_vp_assist_page { | ||
22 | __u32 apic_assist; | ||
23 | __u32 reserved; | ||
24 | __u64 vtl_control[2]; | ||
25 | __u64 nested_enlightenments_control[2]; | ||
26 | __u32 enlighten_vmentry; | ||
27 | __u64 current_nested_vmcs; | ||
28 | }; | ||
29 | |||
30 | struct hv_enlightened_vmcs { | ||
31 | u32 revision_id; | ||
32 | u32 abort; | ||
33 | |||
34 | u16 host_es_selector; | ||
35 | u16 host_cs_selector; | ||
36 | u16 host_ss_selector; | ||
37 | u16 host_ds_selector; | ||
38 | u16 host_fs_selector; | ||
39 | u16 host_gs_selector; | ||
40 | u16 host_tr_selector; | ||
41 | |||
42 | u64 host_ia32_pat; | ||
43 | u64 host_ia32_efer; | ||
44 | |||
45 | u64 host_cr0; | ||
46 | u64 host_cr3; | ||
47 | u64 host_cr4; | ||
48 | |||
49 | u64 host_ia32_sysenter_esp; | ||
50 | u64 host_ia32_sysenter_eip; | ||
51 | u64 host_rip; | ||
52 | u32 host_ia32_sysenter_cs; | ||
53 | |||
54 | u32 pin_based_vm_exec_control; | ||
55 | u32 vm_exit_controls; | ||
56 | u32 secondary_vm_exec_control; | ||
57 | |||
58 | u64 io_bitmap_a; | ||
59 | u64 io_bitmap_b; | ||
60 | u64 msr_bitmap; | ||
61 | |||
62 | u16 guest_es_selector; | ||
63 | u16 guest_cs_selector; | ||
64 | u16 guest_ss_selector; | ||
65 | u16 guest_ds_selector; | ||
66 | u16 guest_fs_selector; | ||
67 | u16 guest_gs_selector; | ||
68 | u16 guest_ldtr_selector; | ||
69 | u16 guest_tr_selector; | ||
70 | |||
71 | u32 guest_es_limit; | ||
72 | u32 guest_cs_limit; | ||
73 | u32 guest_ss_limit; | ||
74 | u32 guest_ds_limit; | ||
75 | u32 guest_fs_limit; | ||
76 | u32 guest_gs_limit; | ||
77 | u32 guest_ldtr_limit; | ||
78 | u32 guest_tr_limit; | ||
79 | u32 guest_gdtr_limit; | ||
80 | u32 guest_idtr_limit; | ||
81 | |||
82 | u32 guest_es_ar_bytes; | ||
83 | u32 guest_cs_ar_bytes; | ||
84 | u32 guest_ss_ar_bytes; | ||
85 | u32 guest_ds_ar_bytes; | ||
86 | u32 guest_fs_ar_bytes; | ||
87 | u32 guest_gs_ar_bytes; | ||
88 | u32 guest_ldtr_ar_bytes; | ||
89 | u32 guest_tr_ar_bytes; | ||
90 | |||
91 | u64 guest_es_base; | ||
92 | u64 guest_cs_base; | ||
93 | u64 guest_ss_base; | ||
94 | u64 guest_ds_base; | ||
95 | u64 guest_fs_base; | ||
96 | u64 guest_gs_base; | ||
97 | u64 guest_ldtr_base; | ||
98 | u64 guest_tr_base; | ||
99 | u64 guest_gdtr_base; | ||
100 | u64 guest_idtr_base; | ||
101 | |||
102 | u64 padding64_1[3]; | ||
103 | |||
104 | u64 vm_exit_msr_store_addr; | ||
105 | u64 vm_exit_msr_load_addr; | ||
106 | u64 vm_entry_msr_load_addr; | ||
107 | |||
108 | u64 cr3_target_value0; | ||
109 | u64 cr3_target_value1; | ||
110 | u64 cr3_target_value2; | ||
111 | u64 cr3_target_value3; | ||
112 | |||
113 | u32 page_fault_error_code_mask; | ||
114 | u32 page_fault_error_code_match; | ||
115 | |||
116 | u32 cr3_target_count; | ||
117 | u32 vm_exit_msr_store_count; | ||
118 | u32 vm_exit_msr_load_count; | ||
119 | u32 vm_entry_msr_load_count; | ||
120 | |||
121 | u64 tsc_offset; | ||
122 | u64 virtual_apic_page_addr; | ||
123 | u64 vmcs_link_pointer; | ||
124 | |||
125 | u64 guest_ia32_debugctl; | ||
126 | u64 guest_ia32_pat; | ||
127 | u64 guest_ia32_efer; | ||
128 | |||
129 | u64 guest_pdptr0; | ||
130 | u64 guest_pdptr1; | ||
131 | u64 guest_pdptr2; | ||
132 | u64 guest_pdptr3; | ||
133 | |||
134 | u64 guest_pending_dbg_exceptions; | ||
135 | u64 guest_sysenter_esp; | ||
136 | u64 guest_sysenter_eip; | ||
137 | |||
138 | u32 guest_activity_state; | ||
139 | u32 guest_sysenter_cs; | ||
140 | |||
141 | u64 cr0_guest_host_mask; | ||
142 | u64 cr4_guest_host_mask; | ||
143 | u64 cr0_read_shadow; | ||
144 | u64 cr4_read_shadow; | ||
145 | u64 guest_cr0; | ||
146 | u64 guest_cr3; | ||
147 | u64 guest_cr4; | ||
148 | u64 guest_dr7; | ||
149 | |||
150 | u64 host_fs_base; | ||
151 | u64 host_gs_base; | ||
152 | u64 host_tr_base; | ||
153 | u64 host_gdtr_base; | ||
154 | u64 host_idtr_base; | ||
155 | u64 host_rsp; | ||
156 | |||
157 | u64 ept_pointer; | ||
158 | |||
159 | u16 virtual_processor_id; | ||
160 | u16 padding16[3]; | ||
161 | |||
162 | u64 padding64_2[5]; | ||
163 | u64 guest_physical_address; | ||
164 | |||
165 | u32 vm_instruction_error; | ||
166 | u32 vm_exit_reason; | ||
167 | u32 vm_exit_intr_info; | ||
168 | u32 vm_exit_intr_error_code; | ||
169 | u32 idt_vectoring_info_field; | ||
170 | u32 idt_vectoring_error_code; | ||
171 | u32 vm_exit_instruction_len; | ||
172 | u32 vmx_instruction_info; | ||
173 | |||
174 | u64 exit_qualification; | ||
175 | u64 exit_io_instruction_ecx; | ||
176 | u64 exit_io_instruction_esi; | ||
177 | u64 exit_io_instruction_edi; | ||
178 | u64 exit_io_instruction_eip; | ||
179 | |||
180 | u64 guest_linear_address; | ||
181 | u64 guest_rsp; | ||
182 | u64 guest_rflags; | ||
183 | |||
184 | u32 guest_interruptibility_info; | ||
185 | u32 cpu_based_vm_exec_control; | ||
186 | u32 exception_bitmap; | ||
187 | u32 vm_entry_controls; | ||
188 | u32 vm_entry_intr_info_field; | ||
189 | u32 vm_entry_exception_error_code; | ||
190 | u32 vm_entry_instruction_len; | ||
191 | u32 tpr_threshold; | ||
192 | |||
193 | u64 guest_rip; | ||
194 | |||
195 | u32 hv_clean_fields; | ||
196 | u32 hv_padding_32; | ||
197 | u32 hv_synthetic_controls; | ||
198 | struct { | ||
199 | u32 nested_flush_hypercall:1; | ||
200 | u32 msr_bitmap:1; | ||
201 | u32 reserved:30; | ||
202 | } hv_enlightenments_control; | ||
203 | u32 hv_vp_id; | ||
204 | |||
205 | u64 hv_vm_id; | ||
206 | u64 partition_assist_page; | ||
207 | u64 padding64_4[4]; | ||
208 | u64 guest_bndcfgs; | ||
209 | u64 padding64_5[7]; | ||
210 | u64 xss_exit_bitmap; | ||
211 | u64 padding64_6[7]; | ||
212 | }; | ||
213 | |||
214 | #define HV_X64_MSR_VP_ASSIST_PAGE 0x40000073 | ||
215 | #define HV_X64_MSR_VP_ASSIST_PAGE_ENABLE 0x00000001 | ||
216 | #define HV_X64_MSR_VP_ASSIST_PAGE_ADDRESS_SHIFT 12 | ||
217 | #define HV_X64_MSR_VP_ASSIST_PAGE_ADDRESS_MASK \ | ||
218 | (~((1ull << HV_X64_MSR_VP_ASSIST_PAGE_ADDRESS_SHIFT) - 1)) | ||
219 | |||
220 | struct hv_enlightened_vmcs *current_evmcs; | ||
221 | struct hv_vp_assist_page *current_vp_assist; | ||
222 | |||
223 | static inline int enable_vp_assist(uint64_t vp_assist_pa, void *vp_assist) | ||
224 | { | ||
225 | u64 val = (vp_assist_pa & HV_X64_MSR_VP_ASSIST_PAGE_ADDRESS_MASK) | | ||
226 | HV_X64_MSR_VP_ASSIST_PAGE_ENABLE; | ||
227 | |||
228 | wrmsr(HV_X64_MSR_VP_ASSIST_PAGE, val); | ||
229 | |||
230 | current_vp_assist = vp_assist; | ||
231 | |||
232 | enable_evmcs = true; | ||
233 | |||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static inline int evmcs_vmptrld(uint64_t vmcs_pa, void *vmcs) | ||
238 | { | ||
239 | current_vp_assist->current_nested_vmcs = vmcs_pa; | ||
240 | current_vp_assist->enlighten_vmentry = 1; | ||
241 | |||
242 | current_evmcs = vmcs; | ||
243 | |||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | static inline int evmcs_vmptrst(uint64_t *value) | ||
248 | { | ||
249 | *value = current_vp_assist->current_nested_vmcs & | ||
250 | ~HV_X64_MSR_VP_ASSIST_PAGE_ENABLE; | ||
251 | |||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | static inline int evmcs_vmread(uint64_t encoding, uint64_t *value) | ||
256 | { | ||
257 | switch (encoding) { | ||
258 | case GUEST_RIP: | ||
259 | *value = current_evmcs->guest_rip; | ||
260 | break; | ||
261 | case GUEST_RSP: | ||
262 | *value = current_evmcs->guest_rsp; | ||
263 | break; | ||
264 | case GUEST_RFLAGS: | ||
265 | *value = current_evmcs->guest_rflags; | ||
266 | break; | ||
267 | case HOST_IA32_PAT: | ||
268 | *value = current_evmcs->host_ia32_pat; | ||
269 | break; | ||
270 | case HOST_IA32_EFER: | ||
271 | *value = current_evmcs->host_ia32_efer; | ||
272 | break; | ||
273 | case HOST_CR0: | ||
274 | *value = current_evmcs->host_cr0; | ||
275 | break; | ||
276 | case HOST_CR3: | ||
277 | *value = current_evmcs->host_cr3; | ||
278 | break; | ||
279 | case HOST_CR4: | ||
280 | *value = current_evmcs->host_cr4; | ||
281 | break; | ||
282 | case HOST_IA32_SYSENTER_ESP: | ||
283 | *value = current_evmcs->host_ia32_sysenter_esp; | ||
284 | break; | ||
285 | case HOST_IA32_SYSENTER_EIP: | ||
286 | *value = current_evmcs->host_ia32_sysenter_eip; | ||
287 | break; | ||
288 | case HOST_RIP: | ||
289 | *value = current_evmcs->host_rip; | ||
290 | break; | ||
291 | case IO_BITMAP_A: | ||
292 | *value = current_evmcs->io_bitmap_a; | ||
293 | break; | ||
294 | case IO_BITMAP_B: | ||
295 | *value = current_evmcs->io_bitmap_b; | ||
296 | break; | ||
297 | case MSR_BITMAP: | ||
298 | *value = current_evmcs->msr_bitmap; | ||
299 | break; | ||
300 | case GUEST_ES_BASE: | ||
301 | *value = current_evmcs->guest_es_base; | ||
302 | break; | ||
303 | case GUEST_CS_BASE: | ||
304 | *value = current_evmcs->guest_cs_base; | ||
305 | break; | ||
306 | case GUEST_SS_BASE: | ||
307 | *value = current_evmcs->guest_ss_base; | ||
308 | break; | ||
309 | case GUEST_DS_BASE: | ||
310 | *value = current_evmcs->guest_ds_base; | ||
311 | break; | ||
312 | case GUEST_FS_BASE: | ||
313 | *value = current_evmcs->guest_fs_base; | ||
314 | break; | ||
315 | case GUEST_GS_BASE: | ||
316 | *value = current_evmcs->guest_gs_base; | ||
317 | break; | ||
318 | case GUEST_LDTR_BASE: | ||
319 | *value = current_evmcs->guest_ldtr_base; | ||
320 | break; | ||
321 | case GUEST_TR_BASE: | ||
322 | *value = current_evmcs->guest_tr_base; | ||
323 | break; | ||
324 | case GUEST_GDTR_BASE: | ||
325 | *value = current_evmcs->guest_gdtr_base; | ||
326 | break; | ||
327 | case GUEST_IDTR_BASE: | ||
328 | *value = current_evmcs->guest_idtr_base; | ||
329 | break; | ||
330 | case TSC_OFFSET: | ||
331 | *value = current_evmcs->tsc_offset; | ||
332 | break; | ||
333 | case VIRTUAL_APIC_PAGE_ADDR: | ||
334 | *value = current_evmcs->virtual_apic_page_addr; | ||
335 | break; | ||
336 | case VMCS_LINK_POINTER: | ||
337 | *value = current_evmcs->vmcs_link_pointer; | ||
338 | break; | ||
339 | case GUEST_IA32_DEBUGCTL: | ||
340 | *value = current_evmcs->guest_ia32_debugctl; | ||
341 | break; | ||
342 | case GUEST_IA32_PAT: | ||
343 | *value = current_evmcs->guest_ia32_pat; | ||
344 | break; | ||
345 | case GUEST_IA32_EFER: | ||
346 | *value = current_evmcs->guest_ia32_efer; | ||
347 | break; | ||
348 | case GUEST_PDPTR0: | ||
349 | *value = current_evmcs->guest_pdptr0; | ||
350 | break; | ||
351 | case GUEST_PDPTR1: | ||
352 | *value = current_evmcs->guest_pdptr1; | ||
353 | break; | ||
354 | case GUEST_PDPTR2: | ||
355 | *value = current_evmcs->guest_pdptr2; | ||
356 | break; | ||
357 | case GUEST_PDPTR3: | ||
358 | *value = current_evmcs->guest_pdptr3; | ||
359 | break; | ||
360 | case GUEST_PENDING_DBG_EXCEPTIONS: | ||
361 | *value = current_evmcs->guest_pending_dbg_exceptions; | ||
362 | break; | ||
363 | case GUEST_SYSENTER_ESP: | ||
364 | *value = current_evmcs->guest_sysenter_esp; | ||
365 | break; | ||
366 | case GUEST_SYSENTER_EIP: | ||
367 | *value = current_evmcs->guest_sysenter_eip; | ||
368 | break; | ||
369 | case CR0_GUEST_HOST_MASK: | ||
370 | *value = current_evmcs->cr0_guest_host_mask; | ||
371 | break; | ||
372 | case CR4_GUEST_HOST_MASK: | ||
373 | *value = current_evmcs->cr4_guest_host_mask; | ||
374 | break; | ||
375 | case CR0_READ_SHADOW: | ||
376 | *value = current_evmcs->cr0_read_shadow; | ||
377 | break; | ||
378 | case CR4_READ_SHADOW: | ||
379 | *value = current_evmcs->cr4_read_shadow; | ||
380 | break; | ||
381 | case GUEST_CR0: | ||
382 | *value = current_evmcs->guest_cr0; | ||
383 | break; | ||
384 | case GUEST_CR3: | ||
385 | *value = current_evmcs->guest_cr3; | ||
386 | break; | ||
387 | case GUEST_CR4: | ||
388 | *value = current_evmcs->guest_cr4; | ||
389 | break; | ||
390 | case GUEST_DR7: | ||
391 | *value = current_evmcs->guest_dr7; | ||
392 | break; | ||
393 | case HOST_FS_BASE: | ||
394 | *value = current_evmcs->host_fs_base; | ||
395 | break; | ||
396 | case HOST_GS_BASE: | ||
397 | *value = current_evmcs->host_gs_base; | ||
398 | break; | ||
399 | case HOST_TR_BASE: | ||
400 | *value = current_evmcs->host_tr_base; | ||
401 | break; | ||
402 | case HOST_GDTR_BASE: | ||
403 | *value = current_evmcs->host_gdtr_base; | ||
404 | break; | ||
405 | case HOST_IDTR_BASE: | ||
406 | *value = current_evmcs->host_idtr_base; | ||
407 | break; | ||
408 | case HOST_RSP: | ||
409 | *value = current_evmcs->host_rsp; | ||
410 | break; | ||
411 | case EPT_POINTER: | ||
412 | *value = current_evmcs->ept_pointer; | ||
413 | break; | ||
414 | case GUEST_BNDCFGS: | ||
415 | *value = current_evmcs->guest_bndcfgs; | ||
416 | break; | ||
417 | case XSS_EXIT_BITMAP: | ||
418 | *value = current_evmcs->xss_exit_bitmap; | ||
419 | break; | ||
420 | case GUEST_PHYSICAL_ADDRESS: | ||
421 | *value = current_evmcs->guest_physical_address; | ||
422 | break; | ||
423 | case EXIT_QUALIFICATION: | ||
424 | *value = current_evmcs->exit_qualification; | ||
425 | break; | ||
426 | case GUEST_LINEAR_ADDRESS: | ||
427 | *value = current_evmcs->guest_linear_address; | ||
428 | break; | ||
429 | case VM_EXIT_MSR_STORE_ADDR: | ||
430 | *value = current_evmcs->vm_exit_msr_store_addr; | ||
431 | break; | ||
432 | case VM_EXIT_MSR_LOAD_ADDR: | ||
433 | *value = current_evmcs->vm_exit_msr_load_addr; | ||
434 | break; | ||
435 | case VM_ENTRY_MSR_LOAD_ADDR: | ||
436 | *value = current_evmcs->vm_entry_msr_load_addr; | ||
437 | break; | ||
438 | case CR3_TARGET_VALUE0: | ||
439 | *value = current_evmcs->cr3_target_value0; | ||
440 | break; | ||
441 | case CR3_TARGET_VALUE1: | ||
442 | *value = current_evmcs->cr3_target_value1; | ||
443 | break; | ||
444 | case CR3_TARGET_VALUE2: | ||
445 | *value = current_evmcs->cr3_target_value2; | ||
446 | break; | ||
447 | case CR3_TARGET_VALUE3: | ||
448 | *value = current_evmcs->cr3_target_value3; | ||
449 | break; | ||
450 | case TPR_THRESHOLD: | ||
451 | *value = current_evmcs->tpr_threshold; | ||
452 | break; | ||
453 | case GUEST_INTERRUPTIBILITY_INFO: | ||
454 | *value = current_evmcs->guest_interruptibility_info; | ||
455 | break; | ||
456 | case CPU_BASED_VM_EXEC_CONTROL: | ||
457 | *value = current_evmcs->cpu_based_vm_exec_control; | ||
458 | break; | ||
459 | case EXCEPTION_BITMAP: | ||
460 | *value = current_evmcs->exception_bitmap; | ||
461 | break; | ||
462 | case VM_ENTRY_CONTROLS: | ||
463 | *value = current_evmcs->vm_entry_controls; | ||
464 | break; | ||
465 | case VM_ENTRY_INTR_INFO_FIELD: | ||
466 | *value = current_evmcs->vm_entry_intr_info_field; | ||
467 | break; | ||
468 | case VM_ENTRY_EXCEPTION_ERROR_CODE: | ||
469 | *value = current_evmcs->vm_entry_exception_error_code; | ||
470 | break; | ||
471 | case VM_ENTRY_INSTRUCTION_LEN: | ||
472 | *value = current_evmcs->vm_entry_instruction_len; | ||
473 | break; | ||
474 | case HOST_IA32_SYSENTER_CS: | ||
475 | *value = current_evmcs->host_ia32_sysenter_cs; | ||
476 | break; | ||
477 | case PIN_BASED_VM_EXEC_CONTROL: | ||
478 | *value = current_evmcs->pin_based_vm_exec_control; | ||
479 | break; | ||
480 | case VM_EXIT_CONTROLS: | ||
481 | *value = current_evmcs->vm_exit_controls; | ||
482 | break; | ||
483 | case SECONDARY_VM_EXEC_CONTROL: | ||
484 | *value = current_evmcs->secondary_vm_exec_control; | ||
485 | break; | ||
486 | case GUEST_ES_LIMIT: | ||
487 | *value = current_evmcs->guest_es_limit; | ||
488 | break; | ||
489 | case GUEST_CS_LIMIT: | ||
490 | *value = current_evmcs->guest_cs_limit; | ||
491 | break; | ||
492 | case GUEST_SS_LIMIT: | ||
493 | *value = current_evmcs->guest_ss_limit; | ||
494 | break; | ||
495 | case GUEST_DS_LIMIT: | ||
496 | *value = current_evmcs->guest_ds_limit; | ||
497 | break; | ||
498 | case GUEST_FS_LIMIT: | ||
499 | *value = current_evmcs->guest_fs_limit; | ||
500 | break; | ||
501 | case GUEST_GS_LIMIT: | ||
502 | *value = current_evmcs->guest_gs_limit; | ||
503 | break; | ||
504 | case GUEST_LDTR_LIMIT: | ||
505 | *value = current_evmcs->guest_ldtr_limit; | ||
506 | break; | ||
507 | case GUEST_TR_LIMIT: | ||
508 | *value = current_evmcs->guest_tr_limit; | ||
509 | break; | ||
510 | case GUEST_GDTR_LIMIT: | ||
511 | *value = current_evmcs->guest_gdtr_limit; | ||
512 | break; | ||
513 | case GUEST_IDTR_LIMIT: | ||
514 | *value = current_evmcs->guest_idtr_limit; | ||
515 | break; | ||
516 | case GUEST_ES_AR_BYTES: | ||
517 | *value = current_evmcs->guest_es_ar_bytes; | ||
518 | break; | ||
519 | case GUEST_CS_AR_BYTES: | ||
520 | *value = current_evmcs->guest_cs_ar_bytes; | ||
521 | break; | ||
522 | case GUEST_SS_AR_BYTES: | ||
523 | *value = current_evmcs->guest_ss_ar_bytes; | ||
524 | break; | ||
525 | case GUEST_DS_AR_BYTES: | ||
526 | *value = current_evmcs->guest_ds_ar_bytes; | ||
527 | break; | ||
528 | case GUEST_FS_AR_BYTES: | ||
529 | *value = current_evmcs->guest_fs_ar_bytes; | ||
530 | break; | ||
531 | case GUEST_GS_AR_BYTES: | ||
532 | *value = current_evmcs->guest_gs_ar_bytes; | ||
533 | break; | ||
534 | case GUEST_LDTR_AR_BYTES: | ||
535 | *value = current_evmcs->guest_ldtr_ar_bytes; | ||
536 | break; | ||
537 | case GUEST_TR_AR_BYTES: | ||
538 | *value = current_evmcs->guest_tr_ar_bytes; | ||
539 | break; | ||
540 | case GUEST_ACTIVITY_STATE: | ||
541 | *value = current_evmcs->guest_activity_state; | ||
542 | break; | ||
543 | case GUEST_SYSENTER_CS: | ||
544 | *value = current_evmcs->guest_sysenter_cs; | ||
545 | break; | ||
546 | case VM_INSTRUCTION_ERROR: | ||
547 | *value = current_evmcs->vm_instruction_error; | ||
548 | break; | ||
549 | case VM_EXIT_REASON: | ||
550 | *value = current_evmcs->vm_exit_reason; | ||
551 | break; | ||
552 | case VM_EXIT_INTR_INFO: | ||
553 | *value = current_evmcs->vm_exit_intr_info; | ||
554 | break; | ||
555 | case VM_EXIT_INTR_ERROR_CODE: | ||
556 | *value = current_evmcs->vm_exit_intr_error_code; | ||
557 | break; | ||
558 | case IDT_VECTORING_INFO_FIELD: | ||
559 | *value = current_evmcs->idt_vectoring_info_field; | ||
560 | break; | ||
561 | case IDT_VECTORING_ERROR_CODE: | ||
562 | *value = current_evmcs->idt_vectoring_error_code; | ||
563 | break; | ||
564 | case VM_EXIT_INSTRUCTION_LEN: | ||
565 | *value = current_evmcs->vm_exit_instruction_len; | ||
566 | break; | ||
567 | case VMX_INSTRUCTION_INFO: | ||
568 | *value = current_evmcs->vmx_instruction_info; | ||
569 | break; | ||
570 | case PAGE_FAULT_ERROR_CODE_MASK: | ||
571 | *value = current_evmcs->page_fault_error_code_mask; | ||
572 | break; | ||
573 | case PAGE_FAULT_ERROR_CODE_MATCH: | ||
574 | *value = current_evmcs->page_fault_error_code_match; | ||
575 | break; | ||
576 | case CR3_TARGET_COUNT: | ||
577 | *value = current_evmcs->cr3_target_count; | ||
578 | break; | ||
579 | case VM_EXIT_MSR_STORE_COUNT: | ||
580 | *value = current_evmcs->vm_exit_msr_store_count; | ||
581 | break; | ||
582 | case VM_EXIT_MSR_LOAD_COUNT: | ||
583 | *value = current_evmcs->vm_exit_msr_load_count; | ||
584 | break; | ||
585 | case VM_ENTRY_MSR_LOAD_COUNT: | ||
586 | *value = current_evmcs->vm_entry_msr_load_count; | ||
587 | break; | ||
588 | case HOST_ES_SELECTOR: | ||
589 | *value = current_evmcs->host_es_selector; | ||
590 | break; | ||
591 | case HOST_CS_SELECTOR: | ||
592 | *value = current_evmcs->host_cs_selector; | ||
593 | break; | ||
594 | case HOST_SS_SELECTOR: | ||
595 | *value = current_evmcs->host_ss_selector; | ||
596 | break; | ||
597 | case HOST_DS_SELECTOR: | ||
598 | *value = current_evmcs->host_ds_selector; | ||
599 | break; | ||
600 | case HOST_FS_SELECTOR: | ||
601 | *value = current_evmcs->host_fs_selector; | ||
602 | break; | ||
603 | case HOST_GS_SELECTOR: | ||
604 | *value = current_evmcs->host_gs_selector; | ||
605 | break; | ||
606 | case HOST_TR_SELECTOR: | ||
607 | *value = current_evmcs->host_tr_selector; | ||
608 | break; | ||
609 | case GUEST_ES_SELECTOR: | ||
610 | *value = current_evmcs->guest_es_selector; | ||
611 | break; | ||
612 | case GUEST_CS_SELECTOR: | ||
613 | *value = current_evmcs->guest_cs_selector; | ||
614 | break; | ||
615 | case GUEST_SS_SELECTOR: | ||
616 | *value = current_evmcs->guest_ss_selector; | ||
617 | break; | ||
618 | case GUEST_DS_SELECTOR: | ||
619 | *value = current_evmcs->guest_ds_selector; | ||
620 | break; | ||
621 | case GUEST_FS_SELECTOR: | ||
622 | *value = current_evmcs->guest_fs_selector; | ||
623 | break; | ||
624 | case GUEST_GS_SELECTOR: | ||
625 | *value = current_evmcs->guest_gs_selector; | ||
626 | break; | ||
627 | case GUEST_LDTR_SELECTOR: | ||
628 | *value = current_evmcs->guest_ldtr_selector; | ||
629 | break; | ||
630 | case GUEST_TR_SELECTOR: | ||
631 | *value = current_evmcs->guest_tr_selector; | ||
632 | break; | ||
633 | case VIRTUAL_PROCESSOR_ID: | ||
634 | *value = current_evmcs->virtual_processor_id; | ||
635 | break; | ||
636 | default: return 1; | ||
637 | } | ||
638 | |||
639 | return 0; | ||
640 | } | ||
641 | |||
642 | static inline int evmcs_vmwrite(uint64_t encoding, uint64_t value) | ||
643 | { | ||
644 | switch (encoding) { | ||
645 | case GUEST_RIP: | ||
646 | current_evmcs->guest_rip = value; | ||
647 | break; | ||
648 | case GUEST_RSP: | ||
649 | current_evmcs->guest_rsp = value; | ||
650 | break; | ||
651 | case GUEST_RFLAGS: | ||
652 | current_evmcs->guest_rflags = value; | ||
653 | break; | ||
654 | case HOST_IA32_PAT: | ||
655 | current_evmcs->host_ia32_pat = value; | ||
656 | break; | ||
657 | case HOST_IA32_EFER: | ||
658 | current_evmcs->host_ia32_efer = value; | ||
659 | break; | ||
660 | case HOST_CR0: | ||
661 | current_evmcs->host_cr0 = value; | ||
662 | break; | ||
663 | case HOST_CR3: | ||
664 | current_evmcs->host_cr3 = value; | ||
665 | break; | ||
666 | case HOST_CR4: | ||
667 | current_evmcs->host_cr4 = value; | ||
668 | break; | ||
669 | case HOST_IA32_SYSENTER_ESP: | ||
670 | current_evmcs->host_ia32_sysenter_esp = value; | ||
671 | break; | ||
672 | case HOST_IA32_SYSENTER_EIP: | ||
673 | current_evmcs->host_ia32_sysenter_eip = value; | ||
674 | break; | ||
675 | case HOST_RIP: | ||
676 | current_evmcs->host_rip = value; | ||
677 | break; | ||
678 | case IO_BITMAP_A: | ||
679 | current_evmcs->io_bitmap_a = value; | ||
680 | break; | ||
681 | case IO_BITMAP_B: | ||
682 | current_evmcs->io_bitmap_b = value; | ||
683 | break; | ||
684 | case MSR_BITMAP: | ||
685 | current_evmcs->msr_bitmap = value; | ||
686 | break; | ||
687 | case GUEST_ES_BASE: | ||
688 | current_evmcs->guest_es_base = value; | ||
689 | break; | ||
690 | case GUEST_CS_BASE: | ||
691 | current_evmcs->guest_cs_base = value; | ||
692 | break; | ||
693 | case GUEST_SS_BASE: | ||
694 | current_evmcs->guest_ss_base = value; | ||
695 | break; | ||
696 | case GUEST_DS_BASE: | ||
697 | current_evmcs->guest_ds_base = value; | ||
698 | break; | ||
699 | case GUEST_FS_BASE: | ||
700 | current_evmcs->guest_fs_base = value; | ||
701 | break; | ||
702 | case GUEST_GS_BASE: | ||
703 | current_evmcs->guest_gs_base = value; | ||
704 | break; | ||
705 | case GUEST_LDTR_BASE: | ||
706 | current_evmcs->guest_ldtr_base = value; | ||
707 | break; | ||
708 | case GUEST_TR_BASE: | ||
709 | current_evmcs->guest_tr_base = value; | ||
710 | break; | ||
711 | case GUEST_GDTR_BASE: | ||
712 | current_evmcs->guest_gdtr_base = value; | ||
713 | break; | ||
714 | case GUEST_IDTR_BASE: | ||
715 | current_evmcs->guest_idtr_base = value; | ||
716 | break; | ||
717 | case TSC_OFFSET: | ||
718 | current_evmcs->tsc_offset = value; | ||
719 | break; | ||
720 | case VIRTUAL_APIC_PAGE_ADDR: | ||
721 | current_evmcs->virtual_apic_page_addr = value; | ||
722 | break; | ||
723 | case VMCS_LINK_POINTER: | ||
724 | current_evmcs->vmcs_link_pointer = value; | ||
725 | break; | ||
726 | case GUEST_IA32_DEBUGCTL: | ||
727 | current_evmcs->guest_ia32_debugctl = value; | ||
728 | break; | ||
729 | case GUEST_IA32_PAT: | ||
730 | current_evmcs->guest_ia32_pat = value; | ||
731 | break; | ||
732 | case GUEST_IA32_EFER: | ||
733 | current_evmcs->guest_ia32_efer = value; | ||
734 | break; | ||
735 | case GUEST_PDPTR0: | ||
736 | current_evmcs->guest_pdptr0 = value; | ||
737 | break; | ||
738 | case GUEST_PDPTR1: | ||
739 | current_evmcs->guest_pdptr1 = value; | ||
740 | break; | ||
741 | case GUEST_PDPTR2: | ||
742 | current_evmcs->guest_pdptr2 = value; | ||
743 | break; | ||
744 | case GUEST_PDPTR3: | ||
745 | current_evmcs->guest_pdptr3 = value; | ||
746 | break; | ||
747 | case GUEST_PENDING_DBG_EXCEPTIONS: | ||
748 | current_evmcs->guest_pending_dbg_exceptions = value; | ||
749 | break; | ||
750 | case GUEST_SYSENTER_ESP: | ||
751 | current_evmcs->guest_sysenter_esp = value; | ||
752 | break; | ||
753 | case GUEST_SYSENTER_EIP: | ||
754 | current_evmcs->guest_sysenter_eip = value; | ||
755 | break; | ||
756 | case CR0_GUEST_HOST_MASK: | ||
757 | current_evmcs->cr0_guest_host_mask = value; | ||
758 | break; | ||
759 | case CR4_GUEST_HOST_MASK: | ||
760 | current_evmcs->cr4_guest_host_mask = value; | ||
761 | break; | ||
762 | case CR0_READ_SHADOW: | ||
763 | current_evmcs->cr0_read_shadow = value; | ||
764 | break; | ||
765 | case CR4_READ_SHADOW: | ||
766 | current_evmcs->cr4_read_shadow = value; | ||
767 | break; | ||
768 | case GUEST_CR0: | ||
769 | current_evmcs->guest_cr0 = value; | ||
770 | break; | ||
771 | case GUEST_CR3: | ||
772 | current_evmcs->guest_cr3 = value; | ||
773 | break; | ||
774 | case GUEST_CR4: | ||
775 | current_evmcs->guest_cr4 = value; | ||
776 | break; | ||
777 | case GUEST_DR7: | ||
778 | current_evmcs->guest_dr7 = value; | ||
779 | break; | ||
780 | case HOST_FS_BASE: | ||
781 | current_evmcs->host_fs_base = value; | ||
782 | break; | ||
783 | case HOST_GS_BASE: | ||
784 | current_evmcs->host_gs_base = value; | ||
785 | break; | ||
786 | case HOST_TR_BASE: | ||
787 | current_evmcs->host_tr_base = value; | ||
788 | break; | ||
789 | case HOST_GDTR_BASE: | ||
790 | current_evmcs->host_gdtr_base = value; | ||
791 | break; | ||
792 | case HOST_IDTR_BASE: | ||
793 | current_evmcs->host_idtr_base = value; | ||
794 | break; | ||
795 | case HOST_RSP: | ||
796 | current_evmcs->host_rsp = value; | ||
797 | break; | ||
798 | case EPT_POINTER: | ||
799 | current_evmcs->ept_pointer = value; | ||
800 | break; | ||
801 | case GUEST_BNDCFGS: | ||
802 | current_evmcs->guest_bndcfgs = value; | ||
803 | break; | ||
804 | case XSS_EXIT_BITMAP: | ||
805 | current_evmcs->xss_exit_bitmap = value; | ||
806 | break; | ||
807 | case GUEST_PHYSICAL_ADDRESS: | ||
808 | current_evmcs->guest_physical_address = value; | ||
809 | break; | ||
810 | case EXIT_QUALIFICATION: | ||
811 | current_evmcs->exit_qualification = value; | ||
812 | break; | ||
813 | case GUEST_LINEAR_ADDRESS: | ||
814 | current_evmcs->guest_linear_address = value; | ||
815 | break; | ||
816 | case VM_EXIT_MSR_STORE_ADDR: | ||
817 | current_evmcs->vm_exit_msr_store_addr = value; | ||
818 | break; | ||
819 | case VM_EXIT_MSR_LOAD_ADDR: | ||
820 | current_evmcs->vm_exit_msr_load_addr = value; | ||
821 | break; | ||
822 | case VM_ENTRY_MSR_LOAD_ADDR: | ||
823 | current_evmcs->vm_entry_msr_load_addr = value; | ||
824 | break; | ||
825 | case CR3_TARGET_VALUE0: | ||
826 | current_evmcs->cr3_target_value0 = value; | ||
827 | break; | ||
828 | case CR3_TARGET_VALUE1: | ||
829 | current_evmcs->cr3_target_value1 = value; | ||
830 | break; | ||
831 | case CR3_TARGET_VALUE2: | ||
832 | current_evmcs->cr3_target_value2 = value; | ||
833 | break; | ||
834 | case CR3_TARGET_VALUE3: | ||
835 | current_evmcs->cr3_target_value3 = value; | ||
836 | break; | ||
837 | case TPR_THRESHOLD: | ||
838 | current_evmcs->tpr_threshold = value; | ||
839 | break; | ||
840 | case GUEST_INTERRUPTIBILITY_INFO: | ||
841 | current_evmcs->guest_interruptibility_info = value; | ||
842 | break; | ||
843 | case CPU_BASED_VM_EXEC_CONTROL: | ||
844 | current_evmcs->cpu_based_vm_exec_control = value; | ||
845 | break; | ||
846 | case EXCEPTION_BITMAP: | ||
847 | current_evmcs->exception_bitmap = value; | ||
848 | break; | ||
849 | case VM_ENTRY_CONTROLS: | ||
850 | current_evmcs->vm_entry_controls = value; | ||
851 | break; | ||
852 | case VM_ENTRY_INTR_INFO_FIELD: | ||
853 | current_evmcs->vm_entry_intr_info_field = value; | ||
854 | break; | ||
855 | case VM_ENTRY_EXCEPTION_ERROR_CODE: | ||
856 | current_evmcs->vm_entry_exception_error_code = value; | ||
857 | break; | ||
858 | case VM_ENTRY_INSTRUCTION_LEN: | ||
859 | current_evmcs->vm_entry_instruction_len = value; | ||
860 | break; | ||
861 | case HOST_IA32_SYSENTER_CS: | ||
862 | current_evmcs->host_ia32_sysenter_cs = value; | ||
863 | break; | ||
864 | case PIN_BASED_VM_EXEC_CONTROL: | ||
865 | current_evmcs->pin_based_vm_exec_control = value; | ||
866 | break; | ||
867 | case VM_EXIT_CONTROLS: | ||
868 | current_evmcs->vm_exit_controls = value; | ||
869 | break; | ||
870 | case SECONDARY_VM_EXEC_CONTROL: | ||
871 | current_evmcs->secondary_vm_exec_control = value; | ||
872 | break; | ||
873 | case GUEST_ES_LIMIT: | ||
874 | current_evmcs->guest_es_limit = value; | ||
875 | break; | ||
876 | case GUEST_CS_LIMIT: | ||
877 | current_evmcs->guest_cs_limit = value; | ||
878 | break; | ||
879 | case GUEST_SS_LIMIT: | ||
880 | current_evmcs->guest_ss_limit = value; | ||
881 | break; | ||
882 | case GUEST_DS_LIMIT: | ||
883 | current_evmcs->guest_ds_limit = value; | ||
884 | break; | ||
885 | case GUEST_FS_LIMIT: | ||
886 | current_evmcs->guest_fs_limit = value; | ||
887 | break; | ||
888 | case GUEST_GS_LIMIT: | ||
889 | current_evmcs->guest_gs_limit = value; | ||
890 | break; | ||
891 | case GUEST_LDTR_LIMIT: | ||
892 | current_evmcs->guest_ldtr_limit = value; | ||
893 | break; | ||
894 | case GUEST_TR_LIMIT: | ||
895 | current_evmcs->guest_tr_limit = value; | ||
896 | break; | ||
897 | case GUEST_GDTR_LIMIT: | ||
898 | current_evmcs->guest_gdtr_limit = value; | ||
899 | break; | ||
900 | case GUEST_IDTR_LIMIT: | ||
901 | current_evmcs->guest_idtr_limit = value; | ||
902 | break; | ||
903 | case GUEST_ES_AR_BYTES: | ||
904 | current_evmcs->guest_es_ar_bytes = value; | ||
905 | break; | ||
906 | case GUEST_CS_AR_BYTES: | ||
907 | current_evmcs->guest_cs_ar_bytes = value; | ||
908 | break; | ||
909 | case GUEST_SS_AR_BYTES: | ||
910 | current_evmcs->guest_ss_ar_bytes = value; | ||
911 | break; | ||
912 | case GUEST_DS_AR_BYTES: | ||
913 | current_evmcs->guest_ds_ar_bytes = value; | ||
914 | break; | ||
915 | case GUEST_FS_AR_BYTES: | ||
916 | current_evmcs->guest_fs_ar_bytes = value; | ||
917 | break; | ||
918 | case GUEST_GS_AR_BYTES: | ||
919 | current_evmcs->guest_gs_ar_bytes = value; | ||
920 | break; | ||
921 | case GUEST_LDTR_AR_BYTES: | ||
922 | current_evmcs->guest_ldtr_ar_bytes = value; | ||
923 | break; | ||
924 | case GUEST_TR_AR_BYTES: | ||
925 | current_evmcs->guest_tr_ar_bytes = value; | ||
926 | break; | ||
927 | case GUEST_ACTIVITY_STATE: | ||
928 | current_evmcs->guest_activity_state = value; | ||
929 | break; | ||
930 | case GUEST_SYSENTER_CS: | ||
931 | current_evmcs->guest_sysenter_cs = value; | ||
932 | break; | ||
933 | case VM_INSTRUCTION_ERROR: | ||
934 | current_evmcs->vm_instruction_error = value; | ||
935 | break; | ||
936 | case VM_EXIT_REASON: | ||
937 | current_evmcs->vm_exit_reason = value; | ||
938 | break; | ||
939 | case VM_EXIT_INTR_INFO: | ||
940 | current_evmcs->vm_exit_intr_info = value; | ||
941 | break; | ||
942 | case VM_EXIT_INTR_ERROR_CODE: | ||
943 | current_evmcs->vm_exit_intr_error_code = value; | ||
944 | break; | ||
945 | case IDT_VECTORING_INFO_FIELD: | ||
946 | current_evmcs->idt_vectoring_info_field = value; | ||
947 | break; | ||
948 | case IDT_VECTORING_ERROR_CODE: | ||
949 | current_evmcs->idt_vectoring_error_code = value; | ||
950 | break; | ||
951 | case VM_EXIT_INSTRUCTION_LEN: | ||
952 | current_evmcs->vm_exit_instruction_len = value; | ||
953 | break; | ||
954 | case VMX_INSTRUCTION_INFO: | ||
955 | current_evmcs->vmx_instruction_info = value; | ||
956 | break; | ||
957 | case PAGE_FAULT_ERROR_CODE_MASK: | ||
958 | current_evmcs->page_fault_error_code_mask = value; | ||
959 | break; | ||
960 | case PAGE_FAULT_ERROR_CODE_MATCH: | ||
961 | current_evmcs->page_fault_error_code_match = value; | ||
962 | break; | ||
963 | case CR3_TARGET_COUNT: | ||
964 | current_evmcs->cr3_target_count = value; | ||
965 | break; | ||
966 | case VM_EXIT_MSR_STORE_COUNT: | ||
967 | current_evmcs->vm_exit_msr_store_count = value; | ||
968 | break; | ||
969 | case VM_EXIT_MSR_LOAD_COUNT: | ||
970 | current_evmcs->vm_exit_msr_load_count = value; | ||
971 | break; | ||
972 | case VM_ENTRY_MSR_LOAD_COUNT: | ||
973 | current_evmcs->vm_entry_msr_load_count = value; | ||
974 | break; | ||
975 | case HOST_ES_SELECTOR: | ||
976 | current_evmcs->host_es_selector = value; | ||
977 | break; | ||
978 | case HOST_CS_SELECTOR: | ||
979 | current_evmcs->host_cs_selector = value; | ||
980 | break; | ||
981 | case HOST_SS_SELECTOR: | ||
982 | current_evmcs->host_ss_selector = value; | ||
983 | break; | ||
984 | case HOST_DS_SELECTOR: | ||
985 | current_evmcs->host_ds_selector = value; | ||
986 | break; | ||
987 | case HOST_FS_SELECTOR: | ||
988 | current_evmcs->host_fs_selector = value; | ||
989 | break; | ||
990 | case HOST_GS_SELECTOR: | ||
991 | current_evmcs->host_gs_selector = value; | ||
992 | break; | ||
993 | case HOST_TR_SELECTOR: | ||
994 | current_evmcs->host_tr_selector = value; | ||
995 | break; | ||
996 | case GUEST_ES_SELECTOR: | ||
997 | current_evmcs->guest_es_selector = value; | ||
998 | break; | ||
999 | case GUEST_CS_SELECTOR: | ||
1000 | current_evmcs->guest_cs_selector = value; | ||
1001 | break; | ||
1002 | case GUEST_SS_SELECTOR: | ||
1003 | current_evmcs->guest_ss_selector = value; | ||
1004 | break; | ||
1005 | case GUEST_DS_SELECTOR: | ||
1006 | current_evmcs->guest_ds_selector = value; | ||
1007 | break; | ||
1008 | case GUEST_FS_SELECTOR: | ||
1009 | current_evmcs->guest_fs_selector = value; | ||
1010 | break; | ||
1011 | case GUEST_GS_SELECTOR: | ||
1012 | current_evmcs->guest_gs_selector = value; | ||
1013 | break; | ||
1014 | case GUEST_LDTR_SELECTOR: | ||
1015 | current_evmcs->guest_ldtr_selector = value; | ||
1016 | break; | ||
1017 | case GUEST_TR_SELECTOR: | ||
1018 | current_evmcs->guest_tr_selector = value; | ||
1019 | break; | ||
1020 | case VIRTUAL_PROCESSOR_ID: | ||
1021 | current_evmcs->virtual_processor_id = value; | ||
1022 | break; | ||
1023 | default: return 1; | ||
1024 | } | ||
1025 | |||
1026 | return 0; | ||
1027 | } | ||
1028 | |||
1029 | static inline int evmcs_vmlaunch(void) | ||
1030 | { | ||
1031 | int ret; | ||
1032 | |||
1033 | current_evmcs->hv_clean_fields = 0; | ||
1034 | |||
1035 | __asm__ __volatile__("push %%rbp;" | ||
1036 | "push %%rcx;" | ||
1037 | "push %%rdx;" | ||
1038 | "push %%rsi;" | ||
1039 | "push %%rdi;" | ||
1040 | "push $0;" | ||
1041 | "mov %%rsp, (%[host_rsp]);" | ||
1042 | "lea 1f(%%rip), %%rax;" | ||
1043 | "mov %%rax, (%[host_rip]);" | ||
1044 | "vmlaunch;" | ||
1045 | "incq (%%rsp);" | ||
1046 | "1: pop %%rax;" | ||
1047 | "pop %%rdi;" | ||
1048 | "pop %%rsi;" | ||
1049 | "pop %%rdx;" | ||
1050 | "pop %%rcx;" | ||
1051 | "pop %%rbp;" | ||
1052 | : [ret]"=&a"(ret) | ||
1053 | : [host_rsp]"r" | ||
1054 | ((uint64_t)¤t_evmcs->host_rsp), | ||
1055 | [host_rip]"r" | ||
1056 | ((uint64_t)¤t_evmcs->host_rip) | ||
1057 | : "memory", "cc", "rbx", "r8", "r9", "r10", | ||
1058 | "r11", "r12", "r13", "r14", "r15"); | ||
1059 | return ret; | ||
1060 | } | ||
1061 | |||
1062 | /* | ||
1063 | * No guest state (e.g. GPRs) is established by this vmresume. | ||
1064 | */ | ||
1065 | static inline int evmcs_vmresume(void) | ||
1066 | { | ||
1067 | int ret; | ||
1068 | |||
1069 | current_evmcs->hv_clean_fields = 0; | ||
1070 | |||
1071 | __asm__ __volatile__("push %%rbp;" | ||
1072 | "push %%rcx;" | ||
1073 | "push %%rdx;" | ||
1074 | "push %%rsi;" | ||
1075 | "push %%rdi;" | ||
1076 | "push $0;" | ||
1077 | "mov %%rsp, (%[host_rsp]);" | ||
1078 | "lea 1f(%%rip), %%rax;" | ||
1079 | "mov %%rax, (%[host_rip]);" | ||
1080 | "vmresume;" | ||
1081 | "incq (%%rsp);" | ||
1082 | "1: pop %%rax;" | ||
1083 | "pop %%rdi;" | ||
1084 | "pop %%rsi;" | ||
1085 | "pop %%rdx;" | ||
1086 | "pop %%rcx;" | ||
1087 | "pop %%rbp;" | ||
1088 | : [ret]"=&a"(ret) | ||
1089 | : [host_rsp]"r" | ||
1090 | ((uint64_t)¤t_evmcs->host_rsp), | ||
1091 | [host_rip]"r" | ||
1092 | ((uint64_t)¤t_evmcs->host_rip) | ||
1093 | : "memory", "cc", "rbx", "r8", "r9", "r10", | ||
1094 | "r11", "r12", "r13", "r14", "r15"); | ||
1095 | return ret; | ||
1096 | } | ||
1097 | |||
1098 | #endif /* !SELFTEST_KVM_EVMCS_H */ | ||
diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h index 3acf9a91704c..a4e59e3b4826 100644 --- a/tools/testing/selftests/kvm/include/kvm_util.h +++ b/tools/testing/selftests/kvm/include/kvm_util.h | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | */ | 8 | */ |
9 | #ifndef SELFTEST_KVM_UTIL_H | 9 | #ifndef SELFTEST_KVM_UTIL_H |
10 | #define SELFTEST_KVM_UTIL_H 1 | 10 | #define SELFTEST_KVM_UTIL_H |
11 | 11 | ||
12 | #include "test_util.h" | 12 | #include "test_util.h" |
13 | 13 | ||
@@ -17,12 +17,6 @@ | |||
17 | 17 | ||
18 | #include "sparsebit.h" | 18 | #include "sparsebit.h" |
19 | 19 | ||
20 | /* | ||
21 | * Memslots can't cover the gfn starting at this gpa otherwise vCPUs can't be | ||
22 | * created. Only applies to VMs using EPT. | ||
23 | */ | ||
24 | #define KVM_DEFAULT_IDENTITY_MAP_ADDRESS 0xfffbc000ul | ||
25 | |||
26 | 20 | ||
27 | /* Callers of kvm_util only have an incomplete/opaque description of the | 21 | /* Callers of kvm_util only have an incomplete/opaque description of the |
28 | * structure kvm_util is using to maintain the state of a VM. | 22 | * structure kvm_util is using to maintain the state of a VM. |
@@ -33,16 +27,23 @@ typedef uint64_t vm_paddr_t; /* Virtual Machine (Guest) physical address */ | |||
33 | typedef uint64_t vm_vaddr_t; /* Virtual Machine (Guest) virtual address */ | 27 | typedef uint64_t vm_vaddr_t; /* Virtual Machine (Guest) virtual address */ |
34 | 28 | ||
35 | /* Minimum allocated guest virtual and physical addresses */ | 29 | /* Minimum allocated guest virtual and physical addresses */ |
36 | #define KVM_UTIL_MIN_VADDR 0x2000 | 30 | #define KVM_UTIL_MIN_VADDR 0x2000 |
37 | 31 | ||
38 | #define DEFAULT_GUEST_PHY_PAGES 512 | 32 | #define DEFAULT_GUEST_PHY_PAGES 512 |
39 | #define DEFAULT_GUEST_STACK_VADDR_MIN 0xab6000 | 33 | #define DEFAULT_GUEST_STACK_VADDR_MIN 0xab6000 |
40 | #define DEFAULT_STACK_PGS 5 | 34 | #define DEFAULT_STACK_PGS 5 |
41 | 35 | ||
42 | enum vm_guest_mode { | 36 | enum vm_guest_mode { |
43 | VM_MODE_FLAT48PG, | 37 | VM_MODE_P52V48_4K, |
38 | VM_MODE_P52V48_64K, | ||
39 | VM_MODE_P40V48_4K, | ||
40 | VM_MODE_P40V48_64K, | ||
41 | NUM_VM_MODES, | ||
44 | }; | 42 | }; |
45 | 43 | ||
44 | #define vm_guest_mode_string(m) vm_guest_mode_string[m] | ||
45 | extern const char * const vm_guest_mode_string[]; | ||
46 | |||
46 | enum vm_mem_backing_src_type { | 47 | enum vm_mem_backing_src_type { |
47 | VM_MEM_SRC_ANONYMOUS, | 48 | VM_MEM_SRC_ANONYMOUS, |
48 | VM_MEM_SRC_ANONYMOUS_THP, | 49 | VM_MEM_SRC_ANONYMOUS_THP, |
@@ -58,15 +59,15 @@ void kvm_vm_restart(struct kvm_vm *vmp, int perm); | |||
58 | void kvm_vm_release(struct kvm_vm *vmp); | 59 | void kvm_vm_release(struct kvm_vm *vmp); |
59 | void kvm_vm_get_dirty_log(struct kvm_vm *vm, int slot, void *log); | 60 | void kvm_vm_get_dirty_log(struct kvm_vm *vm, int slot, void *log); |
60 | 61 | ||
61 | int kvm_memcmp_hva_gva(void *hva, | 62 | int kvm_memcmp_hva_gva(void *hva, struct kvm_vm *vm, const vm_vaddr_t gva, |
62 | struct kvm_vm *vm, const vm_vaddr_t gva, size_t len); | 63 | size_t len); |
63 | 64 | ||
64 | void kvm_vm_elf_load(struct kvm_vm *vm, const char *filename, | 65 | void kvm_vm_elf_load(struct kvm_vm *vm, const char *filename, |
65 | uint32_t data_memslot, uint32_t pgd_memslot); | 66 | uint32_t data_memslot, uint32_t pgd_memslot); |
66 | 67 | ||
67 | void vm_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent); | 68 | void vm_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent); |
68 | void vcpu_dump(FILE *stream, struct kvm_vm *vm, | 69 | void vcpu_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, |
69 | uint32_t vcpuid, uint8_t indent); | 70 | uint8_t indent); |
70 | 71 | ||
71 | void vm_create_irqchip(struct kvm_vm *vm); | 72 | void vm_create_irqchip(struct kvm_vm *vm); |
72 | 73 | ||
@@ -75,13 +76,14 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm, | |||
75 | uint64_t guest_paddr, uint32_t slot, uint64_t npages, | 76 | uint64_t guest_paddr, uint32_t slot, uint64_t npages, |
76 | uint32_t flags); | 77 | uint32_t flags); |
77 | 78 | ||
78 | void vcpu_ioctl(struct kvm_vm *vm, | 79 | void vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, unsigned long ioctl, |
79 | uint32_t vcpuid, unsigned long ioctl, void *arg); | 80 | void *arg); |
80 | void vm_ioctl(struct kvm_vm *vm, unsigned long ioctl, void *arg); | 81 | void vm_ioctl(struct kvm_vm *vm, unsigned long ioctl, void *arg); |
81 | void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags); | 82 | void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags); |
82 | void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid, int pgd_memslot, int gdt_memslot); | 83 | void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid, int pgd_memslot, |
84 | int gdt_memslot); | ||
83 | vm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min, | 85 | vm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min, |
84 | uint32_t data_memslot, uint32_t pgd_memslot); | 86 | uint32_t data_memslot, uint32_t pgd_memslot); |
85 | void virt_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, | 87 | void virt_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, |
86 | size_t size, uint32_t pgd_memslot); | 88 | size_t size, uint32_t pgd_memslot); |
87 | void *addr_gpa2hva(struct kvm_vm *vm, vm_paddr_t gpa); | 89 | void *addr_gpa2hva(struct kvm_vm *vm, vm_paddr_t gpa); |
@@ -93,56 +95,35 @@ struct kvm_run *vcpu_state(struct kvm_vm *vm, uint32_t vcpuid); | |||
93 | void vcpu_run(struct kvm_vm *vm, uint32_t vcpuid); | 95 | void vcpu_run(struct kvm_vm *vm, uint32_t vcpuid); |
94 | int _vcpu_run(struct kvm_vm *vm, uint32_t vcpuid); | 96 | int _vcpu_run(struct kvm_vm *vm, uint32_t vcpuid); |
95 | void vcpu_set_mp_state(struct kvm_vm *vm, uint32_t vcpuid, | 97 | void vcpu_set_mp_state(struct kvm_vm *vm, uint32_t vcpuid, |
96 | struct kvm_mp_state *mp_state); | 98 | struct kvm_mp_state *mp_state); |
97 | void vcpu_regs_get(struct kvm_vm *vm, | 99 | void vcpu_regs_get(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_regs *regs); |
98 | uint32_t vcpuid, struct kvm_regs *regs); | 100 | void vcpu_regs_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_regs *regs); |
99 | void vcpu_regs_set(struct kvm_vm *vm, | ||
100 | uint32_t vcpuid, struct kvm_regs *regs); | ||
101 | void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...); | 101 | void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...); |
102 | void vcpu_sregs_get(struct kvm_vm *vm, | 102 | void vcpu_sregs_get(struct kvm_vm *vm, uint32_t vcpuid, |
103 | uint32_t vcpuid, struct kvm_sregs *sregs); | 103 | struct kvm_sregs *sregs); |
104 | void vcpu_sregs_set(struct kvm_vm *vm, | 104 | void vcpu_sregs_set(struct kvm_vm *vm, uint32_t vcpuid, |
105 | uint32_t vcpuid, struct kvm_sregs *sregs); | 105 | struct kvm_sregs *sregs); |
106 | int _vcpu_sregs_set(struct kvm_vm *vm, | 106 | int _vcpu_sregs_set(struct kvm_vm *vm, uint32_t vcpuid, |
107 | uint32_t vcpuid, struct kvm_sregs *sregs); | 107 | struct kvm_sregs *sregs); |
108 | void vcpu_events_get(struct kvm_vm *vm, uint32_t vcpuid, | 108 | void vcpu_events_get(struct kvm_vm *vm, uint32_t vcpuid, |
109 | struct kvm_vcpu_events *events); | 109 | struct kvm_vcpu_events *events); |
110 | void vcpu_events_set(struct kvm_vm *vm, uint32_t vcpuid, | 110 | void vcpu_events_set(struct kvm_vm *vm, uint32_t vcpuid, |
111 | struct kvm_vcpu_events *events); | 111 | struct kvm_vcpu_events *events); |
112 | uint64_t vcpu_get_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index); | ||
113 | void vcpu_set_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index, | ||
114 | uint64_t msr_value); | ||
115 | 112 | ||
116 | const char *exit_reason_str(unsigned int exit_reason); | 113 | const char *exit_reason_str(unsigned int exit_reason); |
117 | 114 | ||
118 | void virt_pgd_alloc(struct kvm_vm *vm, uint32_t pgd_memslot); | 115 | void virt_pgd_alloc(struct kvm_vm *vm, uint32_t pgd_memslot); |
119 | void virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, | 116 | void virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, |
120 | uint32_t pgd_memslot); | 117 | uint32_t pgd_memslot); |
121 | vm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm, | 118 | vm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm, vm_paddr_t paddr_min, |
122 | vm_paddr_t paddr_min, uint32_t memslot); | 119 | uint32_t memslot); |
123 | 120 | vm_paddr_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t num, | |
124 | struct kvm_cpuid2 *kvm_get_supported_cpuid(void); | 121 | vm_paddr_t paddr_min, uint32_t memslot); |
125 | void vcpu_set_cpuid( | ||
126 | struct kvm_vm *vm, uint32_t vcpuid, struct kvm_cpuid2 *cpuid); | ||
127 | |||
128 | struct kvm_cpuid_entry2 * | ||
129 | kvm_get_supported_cpuid_index(uint32_t function, uint32_t index); | ||
130 | |||
131 | static inline struct kvm_cpuid_entry2 * | ||
132 | kvm_get_supported_cpuid_entry(uint32_t function) | ||
133 | { | ||
134 | return kvm_get_supported_cpuid_index(function, 0); | ||
135 | } | ||
136 | 122 | ||
137 | struct kvm_vm *vm_create_default(uint32_t vcpuid, uint64_t extra_mem_size, | 123 | struct kvm_vm *vm_create_default(uint32_t vcpuid, uint64_t extra_mem_size, |
138 | void *guest_code); | 124 | void *guest_code); |
139 | void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code); | 125 | void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code); |
140 | 126 | ||
141 | typedef void (*vmx_guest_code_t)(vm_vaddr_t vmxon_vaddr, | ||
142 | vm_paddr_t vmxon_paddr, | ||
143 | vm_vaddr_t vmcs_vaddr, | ||
144 | vm_paddr_t vmcs_paddr); | ||
145 | |||
146 | struct kvm_userspace_memory_region * | 127 | struct kvm_userspace_memory_region * |
147 | kvm_userspace_memory_region_find(struct kvm_vm *vm, uint64_t start, | 128 | kvm_userspace_memory_region_find(struct kvm_vm *vm, uint64_t start, |
148 | uint64_t end); | 129 | uint64_t end); |
@@ -152,43 +133,49 @@ allocate_kvm_dirty_log(struct kvm_userspace_memory_region *region); | |||
152 | 133 | ||
153 | int vm_create_device(struct kvm_vm *vm, struct kvm_create_device *cd); | 134 | int vm_create_device(struct kvm_vm *vm, struct kvm_create_device *cd); |
154 | 135 | ||
155 | #define GUEST_PORT_SYNC 0x1000 | 136 | #define sync_global_to_guest(vm, g) ({ \ |
156 | #define GUEST_PORT_ABORT 0x1001 | 137 | typeof(g) *_p = addr_gva2hva(vm, (vm_vaddr_t)&(g)); \ |
157 | #define GUEST_PORT_DONE 0x1002 | 138 | memcpy(_p, &(g), sizeof(g)); \ |
158 | 139 | }) | |
159 | static inline void __exit_to_l0(uint16_t port, uint64_t arg0, uint64_t arg1) | 140 | |
160 | { | 141 | #define sync_global_from_guest(vm, g) ({ \ |
161 | __asm__ __volatile__("in %[port], %%al" | 142 | typeof(g) *_p = addr_gva2hva(vm, (vm_vaddr_t)&(g)); \ |
162 | : | 143 | memcpy(&(g), _p, sizeof(g)); \ |
163 | : [port]"d"(port), "D"(arg0), "S"(arg1) | 144 | }) |
164 | : "rax"); | 145 | |
165 | } | 146 | /* ucall implementation types */ |
166 | 147 | typedef enum { | |
167 | /* | 148 | UCALL_PIO, |
168 | * Allows to pass three arguments to the host: port is 16bit wide, | 149 | UCALL_MMIO, |
169 | * arg0 & arg1 are 64bit wide | 150 | } ucall_type_t; |
170 | */ | 151 | |
171 | #define GUEST_SYNC_ARGS(_port, _arg0, _arg1) \ | 152 | /* Common ucalls */ |
172 | __exit_to_l0(_port, (uint64_t) (_arg0), (uint64_t) (_arg1)) | 153 | enum { |
173 | 154 | UCALL_NONE, | |
174 | #define GUEST_ASSERT(_condition) do { \ | 155 | UCALL_SYNC, |
175 | if (!(_condition)) \ | 156 | UCALL_ABORT, |
176 | GUEST_SYNC_ARGS(GUEST_PORT_ABORT, \ | 157 | UCALL_DONE, |
177 | "Failed guest assert: " \ | 158 | }; |
178 | #_condition, __LINE__); \ | ||
179 | } while (0) | ||
180 | |||
181 | #define GUEST_SYNC(stage) GUEST_SYNC_ARGS(GUEST_PORT_SYNC, "hello", stage) | ||
182 | 159 | ||
183 | #define GUEST_DONE() GUEST_SYNC_ARGS(GUEST_PORT_DONE, 0, 0) | 160 | #define UCALL_MAX_ARGS 6 |
184 | 161 | ||
185 | struct guest_args { | 162 | struct ucall { |
186 | uint64_t arg0; | 163 | uint64_t cmd; |
187 | uint64_t arg1; | 164 | uint64_t args[UCALL_MAX_ARGS]; |
188 | uint16_t port; | 165 | }; |
189 | } __attribute__ ((packed)); | ||
190 | 166 | ||
191 | void guest_args_read(struct kvm_vm *vm, uint32_t vcpu_id, | 167 | void ucall_init(struct kvm_vm *vm, ucall_type_t type, void *arg); |
192 | struct guest_args *args); | 168 | void ucall_uninit(struct kvm_vm *vm); |
169 | void ucall(uint64_t cmd, int nargs, ...); | ||
170 | uint64_t get_ucall(struct kvm_vm *vm, uint32_t vcpu_id, struct ucall *uc); | ||
171 | |||
172 | #define GUEST_SYNC(stage) ucall(UCALL_SYNC, 2, "hello", stage) | ||
173 | #define GUEST_DONE() ucall(UCALL_DONE, 0) | ||
174 | #define GUEST_ASSERT(_condition) do { \ | ||
175 | if (!(_condition)) \ | ||
176 | ucall(UCALL_ABORT, 2, \ | ||
177 | "Failed guest assert: " \ | ||
178 | #_condition, __LINE__); \ | ||
179 | } while (0) | ||
193 | 180 | ||
194 | #endif /* SELFTEST_KVM_UTIL_H */ | 181 | #endif /* SELFTEST_KVM_UTIL_H */ |
diff --git a/tools/testing/selftests/kvm/include/sparsebit.h b/tools/testing/selftests/kvm/include/sparsebit.h index 54cfeb6568d3..31e030915c1f 100644 --- a/tools/testing/selftests/kvm/include/sparsebit.h +++ b/tools/testing/selftests/kvm/include/sparsebit.h | |||
@@ -15,8 +15,8 @@ | |||
15 | * even in the case where most bits are set. | 15 | * even in the case where most bits are set. |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #ifndef _TEST_SPARSEBIT_H_ | 18 | #ifndef SELFTEST_KVM_SPARSEBIT_H |
19 | #define _TEST_SPARSEBIT_H_ | 19 | #define SELFTEST_KVM_SPARSEBIT_H |
20 | 20 | ||
21 | #include <stdbool.h> | 21 | #include <stdbool.h> |
22 | #include <stdint.h> | 22 | #include <stdint.h> |
@@ -72,4 +72,4 @@ void sparsebit_validate_internal(struct sparsebit *sbit); | |||
72 | } | 72 | } |
73 | #endif | 73 | #endif |
74 | 74 | ||
75 | #endif /* _TEST_SPARSEBIT_H_ */ | 75 | #endif /* SELFTEST_KVM_SPARSEBIT_H */ |
diff --git a/tools/testing/selftests/kvm/include/test_util.h b/tools/testing/selftests/kvm/include/test_util.h index 73c3933436ec..c7dafe8bd02c 100644 --- a/tools/testing/selftests/kvm/include/test_util.h +++ b/tools/testing/selftests/kvm/include/test_util.h | |||
@@ -7,8 +7,8 @@ | |||
7 | * | 7 | * |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #ifndef TEST_UTIL_H | 10 | #ifndef SELFTEST_KVM_TEST_UTIL_H |
11 | #define TEST_UTIL_H 1 | 11 | #define SELFTEST_KVM_TEST_UTIL_H |
12 | 12 | ||
13 | #include <stdlib.h> | 13 | #include <stdlib.h> |
14 | #include <stdarg.h> | 14 | #include <stdarg.h> |
@@ -41,4 +41,4 @@ void test_assert(bool exp, const char *exp_str, | |||
41 | #a, #b, #a, (unsigned long) __a, #b, (unsigned long) __b); \ | 41 | #a, #b, #a, (unsigned long) __a, #b, (unsigned long) __b); \ |
42 | } while (0) | 42 | } while (0) |
43 | 43 | ||
44 | #endif /* TEST_UTIL_H */ | 44 | #endif /* SELFTEST_KVM_TEST_UTIL_H */ |
diff --git a/tools/testing/selftests/kvm/include/x86.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index 42c3596815b8..e2884c2b81ff 100644 --- a/tools/testing/selftests/kvm/include/x86.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * tools/testing/selftests/kvm/include/x86.h | 2 | * tools/testing/selftests/kvm/include/x86_64/processor.h |
3 | * | 3 | * |
4 | * Copyright (C) 2018, Google LLC. | 4 | * Copyright (C) 2018, Google LLC. |
5 | * | 5 | * |
@@ -7,8 +7,8 @@ | |||
7 | * | 7 | * |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #ifndef SELFTEST_KVM_X86_H | 10 | #ifndef SELFTEST_KVM_PROCESSOR_H |
11 | #define SELFTEST_KVM_X86_H | 11 | #define SELFTEST_KVM_PROCESSOR_H |
12 | 12 | ||
13 | #include <assert.h> | 13 | #include <assert.h> |
14 | #include <stdint.h> | 14 | #include <stdint.h> |
@@ -305,7 +305,25 @@ static inline unsigned long get_xmm(int n) | |||
305 | 305 | ||
306 | struct kvm_x86_state; | 306 | struct kvm_x86_state; |
307 | struct kvm_x86_state *vcpu_save_state(struct kvm_vm *vm, uint32_t vcpuid); | 307 | struct kvm_x86_state *vcpu_save_state(struct kvm_vm *vm, uint32_t vcpuid); |
308 | void vcpu_load_state(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_x86_state *state); | 308 | void vcpu_load_state(struct kvm_vm *vm, uint32_t vcpuid, |
309 | struct kvm_x86_state *state); | ||
310 | |||
311 | struct kvm_cpuid2 *kvm_get_supported_cpuid(void); | ||
312 | void vcpu_set_cpuid(struct kvm_vm *vm, uint32_t vcpuid, | ||
313 | struct kvm_cpuid2 *cpuid); | ||
314 | |||
315 | struct kvm_cpuid_entry2 * | ||
316 | kvm_get_supported_cpuid_index(uint32_t function, uint32_t index); | ||
317 | |||
318 | static inline struct kvm_cpuid_entry2 * | ||
319 | kvm_get_supported_cpuid_entry(uint32_t function) | ||
320 | { | ||
321 | return kvm_get_supported_cpuid_index(function, 0); | ||
322 | } | ||
323 | |||
324 | uint64_t vcpu_get_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index); | ||
325 | void vcpu_set_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index, | ||
326 | uint64_t msr_value); | ||
309 | 327 | ||
310 | /* | 328 | /* |
311 | * Basic CPU control in CR0 | 329 | * Basic CPU control in CR0 |
@@ -1044,4 +1062,4 @@ void vcpu_load_state(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_x86_state *s | |||
1044 | #define MSR_VM_IGNNE 0xc0010115 | 1062 | #define MSR_VM_IGNNE 0xc0010115 |
1045 | #define MSR_VM_HSAVE_PA 0xc0010117 | 1063 | #define MSR_VM_HSAVE_PA 0xc0010117 |
1046 | 1064 | ||
1047 | #endif /* !SELFTEST_KVM_X86_H */ | 1065 | #endif /* SELFTEST_KVM_PROCESSOR_H */ |
diff --git a/tools/testing/selftests/kvm/include/vmx.h b/tools/testing/selftests/kvm/include/x86_64/vmx.h index b9ffe1024d3a..c9bd935b939c 100644 --- a/tools/testing/selftests/kvm/include/vmx.h +++ b/tools/testing/selftests/kvm/include/x86_64/vmx.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * tools/testing/selftests/kvm/include/vmx.h | 2 | * tools/testing/selftests/kvm/include/x86_64/vmx.h |
3 | * | 3 | * |
4 | * Copyright (C) 2018, Google LLC. | 4 | * Copyright (C) 2018, Google LLC. |
5 | * | 5 | * |
@@ -11,7 +11,7 @@ | |||
11 | #define SELFTEST_KVM_VMX_H | 11 | #define SELFTEST_KVM_VMX_H |
12 | 12 | ||
13 | #include <stdint.h> | 13 | #include <stdint.h> |
14 | #include "x86.h" | 14 | #include "processor.h" |
15 | 15 | ||
16 | #define CPUID_VMX_BIT 5 | 16 | #define CPUID_VMX_BIT 5 |
17 | 17 | ||
@@ -339,6 +339,8 @@ struct vmx_msr_entry { | |||
339 | uint64_t value; | 339 | uint64_t value; |
340 | } __attribute__ ((aligned(16))); | 340 | } __attribute__ ((aligned(16))); |
341 | 341 | ||
342 | #include "evmcs.h" | ||
343 | |||
342 | static inline int vmxon(uint64_t phys) | 344 | static inline int vmxon(uint64_t phys) |
343 | { | 345 | { |
344 | uint8_t ret; | 346 | uint8_t ret; |
@@ -372,6 +374,9 @@ static inline int vmptrld(uint64_t vmcs_pa) | |||
372 | { | 374 | { |
373 | uint8_t ret; | 375 | uint8_t ret; |
374 | 376 | ||
377 | if (enable_evmcs) | ||
378 | return -1; | ||
379 | |||
375 | __asm__ __volatile__ ("vmptrld %[pa]; setna %[ret]" | 380 | __asm__ __volatile__ ("vmptrld %[pa]; setna %[ret]" |
376 | : [ret]"=rm"(ret) | 381 | : [ret]"=rm"(ret) |
377 | : [pa]"m"(vmcs_pa) | 382 | : [pa]"m"(vmcs_pa) |
@@ -385,6 +390,9 @@ static inline int vmptrst(uint64_t *value) | |||
385 | uint64_t tmp; | 390 | uint64_t tmp; |
386 | uint8_t ret; | 391 | uint8_t ret; |
387 | 392 | ||
393 | if (enable_evmcs) | ||
394 | return evmcs_vmptrst(value); | ||
395 | |||
388 | __asm__ __volatile__("vmptrst %[value]; setna %[ret]" | 396 | __asm__ __volatile__("vmptrst %[value]; setna %[ret]" |
389 | : [value]"=m"(tmp), [ret]"=rm"(ret) | 397 | : [value]"=m"(tmp), [ret]"=rm"(ret) |
390 | : : "cc", "memory"); | 398 | : : "cc", "memory"); |
@@ -411,6 +419,9 @@ static inline int vmlaunch(void) | |||
411 | { | 419 | { |
412 | int ret; | 420 | int ret; |
413 | 421 | ||
422 | if (enable_evmcs) | ||
423 | return evmcs_vmlaunch(); | ||
424 | |||
414 | __asm__ __volatile__("push %%rbp;" | 425 | __asm__ __volatile__("push %%rbp;" |
415 | "push %%rcx;" | 426 | "push %%rcx;" |
416 | "push %%rdx;" | 427 | "push %%rdx;" |
@@ -443,6 +454,9 @@ static inline int vmresume(void) | |||
443 | { | 454 | { |
444 | int ret; | 455 | int ret; |
445 | 456 | ||
457 | if (enable_evmcs) | ||
458 | return evmcs_vmresume(); | ||
459 | |||
446 | __asm__ __volatile__("push %%rbp;" | 460 | __asm__ __volatile__("push %%rbp;" |
447 | "push %%rcx;" | 461 | "push %%rcx;" |
448 | "push %%rdx;" | 462 | "push %%rdx;" |
@@ -482,6 +496,9 @@ static inline int vmread(uint64_t encoding, uint64_t *value) | |||
482 | uint64_t tmp; | 496 | uint64_t tmp; |
483 | uint8_t ret; | 497 | uint8_t ret; |
484 | 498 | ||
499 | if (enable_evmcs) | ||
500 | return evmcs_vmread(encoding, value); | ||
501 | |||
485 | __asm__ __volatile__("vmread %[encoding], %[value]; setna %[ret]" | 502 | __asm__ __volatile__("vmread %[encoding], %[value]; setna %[ret]" |
486 | : [value]"=rm"(tmp), [ret]"=rm"(ret) | 503 | : [value]"=rm"(tmp), [ret]"=rm"(ret) |
487 | : [encoding]"r"(encoding) | 504 | : [encoding]"r"(encoding) |
@@ -506,6 +523,9 @@ static inline int vmwrite(uint64_t encoding, uint64_t value) | |||
506 | { | 523 | { |
507 | uint8_t ret; | 524 | uint8_t ret; |
508 | 525 | ||
526 | if (enable_evmcs) | ||
527 | return evmcs_vmwrite(encoding, value); | ||
528 | |||
509 | __asm__ __volatile__ ("vmwrite %[value], %[encoding]; setna %[ret]" | 529 | __asm__ __volatile__ ("vmwrite %[value], %[encoding]; setna %[ret]" |
510 | : [ret]"=rm"(ret) | 530 | : [ret]"=rm"(ret) |
511 | : [value]"rm"(value), [encoding]"r"(encoding) | 531 | : [value]"rm"(value), [encoding]"r"(encoding) |
@@ -543,10 +563,19 @@ struct vmx_pages { | |||
543 | void *vmwrite_hva; | 563 | void *vmwrite_hva; |
544 | uint64_t vmwrite_gpa; | 564 | uint64_t vmwrite_gpa; |
545 | void *vmwrite; | 565 | void *vmwrite; |
566 | |||
567 | void *vp_assist_hva; | ||
568 | uint64_t vp_assist_gpa; | ||
569 | void *vp_assist; | ||
570 | |||
571 | void *enlightened_vmcs_hva; | ||
572 | uint64_t enlightened_vmcs_gpa; | ||
573 | void *enlightened_vmcs; | ||
546 | }; | 574 | }; |
547 | 575 | ||
548 | struct vmx_pages *vcpu_alloc_vmx(struct kvm_vm *vm, vm_vaddr_t *p_vmx_gva); | 576 | struct vmx_pages *vcpu_alloc_vmx(struct kvm_vm *vm, vm_vaddr_t *p_vmx_gva); |
549 | bool prepare_for_vmx_operation(struct vmx_pages *vmx); | 577 | bool prepare_for_vmx_operation(struct vmx_pages *vmx); |
550 | void prepare_vmcs(struct vmx_pages *vmx, void *guest_rip, void *guest_rsp); | 578 | void prepare_vmcs(struct vmx_pages *vmx, void *guest_rip, void *guest_rsp); |
579 | bool load_vmcs(struct vmx_pages *vmx); | ||
551 | 580 | ||
552 | #endif /* !SELFTEST_KVM_VMX_H */ | 581 | #endif /* SELFTEST_KVM_VMX_H */ |
diff --git a/tools/testing/selftests/kvm/lib/aarch64/processor.c b/tools/testing/selftests/kvm/lib/aarch64/processor.c new file mode 100644 index 000000000000..b6022e2f116e --- /dev/null +++ b/tools/testing/selftests/kvm/lib/aarch64/processor.c | |||
@@ -0,0 +1,311 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * AArch64 code | ||
4 | * | ||
5 | * Copyright (C) 2018, Red Hat, Inc. | ||
6 | */ | ||
7 | |||
8 | #define _GNU_SOURCE /* for program_invocation_name */ | ||
9 | |||
10 | #include "kvm_util.h" | ||
11 | #include "../kvm_util_internal.h" | ||
12 | #include "processor.h" | ||
13 | |||
14 | #define KVM_GUEST_PAGE_TABLE_MIN_PADDR 0x180000 | ||
15 | #define DEFAULT_ARM64_GUEST_STACK_VADDR_MIN 0xac0000 | ||
16 | |||
17 | static uint64_t page_align(struct kvm_vm *vm, uint64_t v) | ||
18 | { | ||
19 | return (v + vm->page_size) & ~(vm->page_size - 1); | ||
20 | } | ||
21 | |||
22 | static uint64_t pgd_index(struct kvm_vm *vm, vm_vaddr_t gva) | ||
23 | { | ||
24 | unsigned int shift = (vm->pgtable_levels - 1) * (vm->page_shift - 3) + vm->page_shift; | ||
25 | uint64_t mask = (1UL << (vm->va_bits - shift)) - 1; | ||
26 | |||
27 | return (gva >> shift) & mask; | ||
28 | } | ||
29 | |||
30 | static uint64_t pud_index(struct kvm_vm *vm, vm_vaddr_t gva) | ||
31 | { | ||
32 | unsigned int shift = 2 * (vm->page_shift - 3) + vm->page_shift; | ||
33 | uint64_t mask = (1UL << (vm->page_shift - 3)) - 1; | ||
34 | |||
35 | TEST_ASSERT(vm->pgtable_levels == 4, | ||
36 | "Mode %d does not have 4 page table levels", vm->mode); | ||
37 | |||
38 | return (gva >> shift) & mask; | ||
39 | } | ||
40 | |||
41 | static uint64_t pmd_index(struct kvm_vm *vm, vm_vaddr_t gva) | ||
42 | { | ||
43 | unsigned int shift = (vm->page_shift - 3) + vm->page_shift; | ||
44 | uint64_t mask = (1UL << (vm->page_shift - 3)) - 1; | ||
45 | |||
46 | TEST_ASSERT(vm->pgtable_levels >= 3, | ||
47 | "Mode %d does not have >= 3 page table levels", vm->mode); | ||
48 | |||
49 | return (gva >> shift) & mask; | ||
50 | } | ||
51 | |||
52 | static uint64_t pte_index(struct kvm_vm *vm, vm_vaddr_t gva) | ||
53 | { | ||
54 | uint64_t mask = (1UL << (vm->page_shift - 3)) - 1; | ||
55 | return (gva >> vm->page_shift) & mask; | ||
56 | } | ||
57 | |||
58 | static uint64_t pte_addr(struct kvm_vm *vm, uint64_t entry) | ||
59 | { | ||
60 | uint64_t mask = ((1UL << (vm->va_bits - vm->page_shift)) - 1) << vm->page_shift; | ||
61 | return entry & mask; | ||
62 | } | ||
63 | |||
64 | static uint64_t ptrs_per_pgd(struct kvm_vm *vm) | ||
65 | { | ||
66 | unsigned int shift = (vm->pgtable_levels - 1) * (vm->page_shift - 3) + vm->page_shift; | ||
67 | return 1 << (vm->va_bits - shift); | ||
68 | } | ||
69 | |||
70 | static uint64_t ptrs_per_pte(struct kvm_vm *vm) | ||
71 | { | ||
72 | return 1 << (vm->page_shift - 3); | ||
73 | } | ||
74 | |||
75 | void virt_pgd_alloc(struct kvm_vm *vm, uint32_t pgd_memslot) | ||
76 | { | ||
77 | int rc; | ||
78 | |||
79 | if (!vm->pgd_created) { | ||
80 | vm_paddr_t paddr = vm_phy_pages_alloc(vm, | ||
81 | page_align(vm, ptrs_per_pgd(vm) * 8) / vm->page_size, | ||
82 | KVM_GUEST_PAGE_TABLE_MIN_PADDR, pgd_memslot); | ||
83 | vm->pgd = paddr; | ||
84 | vm->pgd_created = true; | ||
85 | } | ||
86 | } | ||
87 | |||
88 | void _virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, | ||
89 | uint32_t pgd_memslot, uint64_t flags) | ||
90 | { | ||
91 | uint8_t attr_idx = flags & 7; | ||
92 | uint64_t *ptep; | ||
93 | |||
94 | TEST_ASSERT((vaddr % vm->page_size) == 0, | ||
95 | "Virtual address not on page boundary,\n" | ||
96 | " vaddr: 0x%lx vm->page_size: 0x%x", vaddr, vm->page_size); | ||
97 | TEST_ASSERT(sparsebit_is_set(vm->vpages_valid, | ||
98 | (vaddr >> vm->page_shift)), | ||
99 | "Invalid virtual address, vaddr: 0x%lx", vaddr); | ||
100 | TEST_ASSERT((paddr % vm->page_size) == 0, | ||
101 | "Physical address not on page boundary,\n" | ||
102 | " paddr: 0x%lx vm->page_size: 0x%x", paddr, vm->page_size); | ||
103 | TEST_ASSERT((paddr >> vm->page_shift) <= vm->max_gfn, | ||
104 | "Physical address beyond beyond maximum supported,\n" | ||
105 | " paddr: 0x%lx vm->max_gfn: 0x%lx vm->page_size: 0x%x", | ||
106 | paddr, vm->max_gfn, vm->page_size); | ||
107 | |||
108 | ptep = addr_gpa2hva(vm, vm->pgd) + pgd_index(vm, vaddr) * 8; | ||
109 | if (!*ptep) { | ||
110 | *ptep = vm_phy_page_alloc(vm, KVM_GUEST_PAGE_TABLE_MIN_PADDR, pgd_memslot); | ||
111 | *ptep |= 3; | ||
112 | } | ||
113 | |||
114 | switch (vm->pgtable_levels) { | ||
115 | case 4: | ||
116 | ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pud_index(vm, vaddr) * 8; | ||
117 | if (!*ptep) { | ||
118 | *ptep = vm_phy_page_alloc(vm, KVM_GUEST_PAGE_TABLE_MIN_PADDR, pgd_memslot); | ||
119 | *ptep |= 3; | ||
120 | } | ||
121 | /* fall through */ | ||
122 | case 3: | ||
123 | ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pmd_index(vm, vaddr) * 8; | ||
124 | if (!*ptep) { | ||
125 | *ptep = vm_phy_page_alloc(vm, KVM_GUEST_PAGE_TABLE_MIN_PADDR, pgd_memslot); | ||
126 | *ptep |= 3; | ||
127 | } | ||
128 | /* fall through */ | ||
129 | case 2: | ||
130 | ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pte_index(vm, vaddr) * 8; | ||
131 | break; | ||
132 | default: | ||
133 | TEST_ASSERT(false, "Page table levels must be 2, 3, or 4"); | ||
134 | } | ||
135 | |||
136 | *ptep = paddr | 3; | ||
137 | *ptep |= (attr_idx << 2) | (1 << 10) /* Access Flag */; | ||
138 | } | ||
139 | |||
140 | void virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, | ||
141 | uint32_t pgd_memslot) | ||
142 | { | ||
143 | uint64_t attr_idx = 4; /* NORMAL (See DEFAULT_MAIR_EL1) */ | ||
144 | |||
145 | _virt_pg_map(vm, vaddr, paddr, pgd_memslot, attr_idx); | ||
146 | } | ||
147 | |||
148 | vm_paddr_t addr_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva) | ||
149 | { | ||
150 | uint64_t *ptep; | ||
151 | |||
152 | if (!vm->pgd_created) | ||
153 | goto unmapped_gva; | ||
154 | |||
155 | ptep = addr_gpa2hva(vm, vm->pgd) + pgd_index(vm, gva) * 8; | ||
156 | if (!ptep) | ||
157 | goto unmapped_gva; | ||
158 | |||
159 | switch (vm->pgtable_levels) { | ||
160 | case 4: | ||
161 | ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pud_index(vm, gva) * 8; | ||
162 | if (!ptep) | ||
163 | goto unmapped_gva; | ||
164 | /* fall through */ | ||
165 | case 3: | ||
166 | ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pmd_index(vm, gva) * 8; | ||
167 | if (!ptep) | ||
168 | goto unmapped_gva; | ||
169 | /* fall through */ | ||
170 | case 2: | ||
171 | ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pte_index(vm, gva) * 8; | ||
172 | if (!ptep) | ||
173 | goto unmapped_gva; | ||
174 | break; | ||
175 | default: | ||
176 | TEST_ASSERT(false, "Page table levels must be 2, 3, or 4"); | ||
177 | } | ||
178 | |||
179 | return pte_addr(vm, *ptep) + (gva & (vm->page_size - 1)); | ||
180 | |||
181 | unmapped_gva: | ||
182 | TEST_ASSERT(false, "No mapping for vm virtual address, " | ||
183 | "gva: 0x%lx", gva); | ||
184 | } | ||
185 | |||
186 | static void pte_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent, uint64_t page, int level) | ||
187 | { | ||
188 | #ifdef DEBUG_VM | ||
189 | static const char * const type[] = { "", "pud", "pmd", "pte" }; | ||
190 | uint64_t pte, *ptep; | ||
191 | |||
192 | if (level == 4) | ||
193 | return; | ||
194 | |||
195 | for (pte = page; pte < page + ptrs_per_pte(vm) * 8; pte += 8) { | ||
196 | ptep = addr_gpa2hva(vm, pte); | ||
197 | if (!*ptep) | ||
198 | continue; | ||
199 | printf("%*s%s: %lx: %lx at %p\n", indent, "", type[level], pte, *ptep, ptep); | ||
200 | pte_dump(stream, vm, indent + 1, pte_addr(vm, *ptep), level + 1); | ||
201 | } | ||
202 | #endif | ||
203 | } | ||
204 | |||
205 | void virt_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent) | ||
206 | { | ||
207 | int level = 4 - (vm->pgtable_levels - 1); | ||
208 | uint64_t pgd, *ptep; | ||
209 | |||
210 | if (!vm->pgd_created) | ||
211 | return; | ||
212 | |||
213 | for (pgd = vm->pgd; pgd < vm->pgd + ptrs_per_pgd(vm) * 8; pgd += 8) { | ||
214 | ptep = addr_gpa2hva(vm, pgd); | ||
215 | if (!*ptep) | ||
216 | continue; | ||
217 | printf("%*spgd: %lx: %lx at %p\n", indent, "", pgd, *ptep, ptep); | ||
218 | pte_dump(stream, vm, indent + 1, pte_addr(vm, *ptep), level); | ||
219 | } | ||
220 | } | ||
221 | |||
222 | struct kvm_vm *vm_create_default(uint32_t vcpuid, uint64_t extra_mem_pages, | ||
223 | void *guest_code) | ||
224 | { | ||
225 | uint64_t ptrs_per_4k_pte = 512; | ||
226 | uint64_t extra_pg_pages = (extra_mem_pages / ptrs_per_4k_pte) * 2; | ||
227 | struct kvm_vm *vm; | ||
228 | |||
229 | vm = vm_create(VM_MODE_P52V48_4K, DEFAULT_GUEST_PHY_PAGES + extra_pg_pages, O_RDWR); | ||
230 | |||
231 | kvm_vm_elf_load(vm, program_invocation_name, 0, 0); | ||
232 | vm_vcpu_add_default(vm, vcpuid, guest_code); | ||
233 | |||
234 | return vm; | ||
235 | } | ||
236 | |||
237 | void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code) | ||
238 | { | ||
239 | size_t stack_size = vm->page_size == 4096 ? | ||
240 | DEFAULT_STACK_PGS * vm->page_size : | ||
241 | vm->page_size; | ||
242 | uint64_t stack_vaddr = vm_vaddr_alloc(vm, stack_size, | ||
243 | DEFAULT_ARM64_GUEST_STACK_VADDR_MIN, 0, 0); | ||
244 | |||
245 | vm_vcpu_add(vm, vcpuid, 0, 0); | ||
246 | |||
247 | set_reg(vm, vcpuid, ARM64_CORE_REG(sp_el1), stack_vaddr + stack_size); | ||
248 | set_reg(vm, vcpuid, ARM64_CORE_REG(regs.pc), (uint64_t)guest_code); | ||
249 | } | ||
250 | |||
251 | void vcpu_setup(struct kvm_vm *vm, int vcpuid, int pgd_memslot, int gdt_memslot) | ||
252 | { | ||
253 | struct kvm_vcpu_init init; | ||
254 | uint64_t sctlr_el1, tcr_el1; | ||
255 | |||
256 | memset(&init, 0, sizeof(init)); | ||
257 | init.target = KVM_ARM_TARGET_GENERIC_V8; | ||
258 | vcpu_ioctl(vm, vcpuid, KVM_ARM_VCPU_INIT, &init); | ||
259 | |||
260 | /* | ||
261 | * Enable FP/ASIMD to avoid trapping when accessing Q0-Q15 | ||
262 | * registers, which the variable argument list macros do. | ||
263 | */ | ||
264 | set_reg(vm, vcpuid, ARM64_SYS_REG(CPACR_EL1), 3 << 20); | ||
265 | |||
266 | get_reg(vm, vcpuid, ARM64_SYS_REG(SCTLR_EL1), &sctlr_el1); | ||
267 | get_reg(vm, vcpuid, ARM64_SYS_REG(TCR_EL1), &tcr_el1); | ||
268 | |||
269 | switch (vm->mode) { | ||
270 | case VM_MODE_P52V48_4K: | ||
271 | tcr_el1 |= 0ul << 14; /* TG0 = 4KB */ | ||
272 | tcr_el1 |= 6ul << 32; /* IPS = 52 bits */ | ||
273 | break; | ||
274 | case VM_MODE_P52V48_64K: | ||
275 | tcr_el1 |= 1ul << 14; /* TG0 = 64KB */ | ||
276 | tcr_el1 |= 6ul << 32; /* IPS = 52 bits */ | ||
277 | break; | ||
278 | case VM_MODE_P40V48_4K: | ||
279 | tcr_el1 |= 0ul << 14; /* TG0 = 4KB */ | ||
280 | tcr_el1 |= 2ul << 32; /* IPS = 40 bits */ | ||
281 | break; | ||
282 | case VM_MODE_P40V48_64K: | ||
283 | tcr_el1 |= 1ul << 14; /* TG0 = 64KB */ | ||
284 | tcr_el1 |= 2ul << 32; /* IPS = 40 bits */ | ||
285 | break; | ||
286 | default: | ||
287 | TEST_ASSERT(false, "Unknown guest mode, mode: 0x%x", vm->mode); | ||
288 | } | ||
289 | |||
290 | sctlr_el1 |= (1 << 0) | (1 << 2) | (1 << 12) /* M | C | I */; | ||
291 | /* TCR_EL1 |= IRGN0:WBWA | ORGN0:WBWA | SH0:Inner-Shareable */; | ||
292 | tcr_el1 |= (1 << 8) | (1 << 10) | (3 << 12); | ||
293 | tcr_el1 |= (64 - vm->va_bits) /* T0SZ */; | ||
294 | |||
295 | set_reg(vm, vcpuid, ARM64_SYS_REG(SCTLR_EL1), sctlr_el1); | ||
296 | set_reg(vm, vcpuid, ARM64_SYS_REG(TCR_EL1), tcr_el1); | ||
297 | set_reg(vm, vcpuid, ARM64_SYS_REG(MAIR_EL1), DEFAULT_MAIR_EL1); | ||
298 | set_reg(vm, vcpuid, ARM64_SYS_REG(TTBR0_EL1), vm->pgd); | ||
299 | } | ||
300 | |||
301 | void vcpu_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, uint8_t indent) | ||
302 | { | ||
303 | uint64_t pstate, pc; | ||
304 | |||
305 | get_reg(vm, vcpuid, ARM64_CORE_REG(regs.pstate), &pstate); | ||
306 | get_reg(vm, vcpuid, ARM64_CORE_REG(regs.pc), &pc); | ||
307 | |||
308 | fprintf(stream, "%*spstate: 0x%.16llx pc: 0x%.16llx\n", | ||
309 | indent, "", pstate, pc); | ||
310 | |||
311 | } | ||
diff --git a/tools/testing/selftests/kvm/lib/assert.c b/tools/testing/selftests/kvm/lib/assert.c index cd01144d27c8..6398efe67885 100644 --- a/tools/testing/selftests/kvm/lib/assert.c +++ b/tools/testing/selftests/kvm/lib/assert.c | |||
@@ -13,7 +13,7 @@ | |||
13 | #include <execinfo.h> | 13 | #include <execinfo.h> |
14 | #include <sys/syscall.h> | 14 | #include <sys/syscall.h> |
15 | 15 | ||
16 | #include "../../kselftest.h" | 16 | #include "kselftest.h" |
17 | 17 | ||
18 | /* Dumps the current stack trace to stderr. */ | 18 | /* Dumps the current stack trace to stderr. */ |
19 | static void __attribute__((noinline)) test_dump_stack(void); | 19 | static void __attribute__((noinline)) test_dump_stack(void); |
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 6fd8c089cafc..8c06da4f03db 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c | |||
@@ -16,10 +16,8 @@ | |||
16 | #include <sys/stat.h> | 16 | #include <sys/stat.h> |
17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
18 | 18 | ||
19 | #define KVM_DEV_PATH "/dev/kvm" | ||
20 | |||
21 | #define KVM_UTIL_PGS_PER_HUGEPG 512 | 19 | #define KVM_UTIL_PGS_PER_HUGEPG 512 |
22 | #define KVM_UTIL_MIN_PADDR 0x2000 | 20 | #define KVM_UTIL_MIN_PFN 2 |
23 | 21 | ||
24 | /* Aligns x up to the next multiple of size. Size must be a power of 2. */ | 22 | /* Aligns x up to the next multiple of size. Size must be a power of 2. */ |
25 | static void *align(void *x, size_t size) | 23 | static void *align(void *x, size_t size) |
@@ -30,7 +28,8 @@ static void *align(void *x, size_t size) | |||
30 | return (void *) (((size_t) x + mask) & ~mask); | 28 | return (void *) (((size_t) x + mask) & ~mask); |
31 | } | 29 | } |
32 | 30 | ||
33 | /* Capability | 31 | /* |
32 | * Capability | ||
34 | * | 33 | * |
35 | * Input Args: | 34 | * Input Args: |
36 | * cap - Capability | 35 | * cap - Capability |
@@ -92,16 +91,23 @@ static void vm_open(struct kvm_vm *vm, int perm) | |||
92 | if (vm->kvm_fd < 0) | 91 | if (vm->kvm_fd < 0) |
93 | exit(KSFT_SKIP); | 92 | exit(KSFT_SKIP); |
94 | 93 | ||
95 | /* Create VM. */ | ||
96 | vm->fd = ioctl(vm->kvm_fd, KVM_CREATE_VM, NULL); | 94 | vm->fd = ioctl(vm->kvm_fd, KVM_CREATE_VM, NULL); |
97 | TEST_ASSERT(vm->fd >= 0, "KVM_CREATE_VM ioctl failed, " | 95 | TEST_ASSERT(vm->fd >= 0, "KVM_CREATE_VM ioctl failed, " |
98 | "rc: %i errno: %i", vm->fd, errno); | 96 | "rc: %i errno: %i", vm->fd, errno); |
99 | } | 97 | } |
100 | 98 | ||
101 | /* VM Create | 99 | const char * const vm_guest_mode_string[] = { |
100 | "PA-bits:52, VA-bits:48, 4K pages", | ||
101 | "PA-bits:52, VA-bits:48, 64K pages", | ||
102 | "PA-bits:40, VA-bits:48, 4K pages", | ||
103 | "PA-bits:40, VA-bits:48, 64K pages", | ||
104 | }; | ||
105 | |||
106 | /* | ||
107 | * VM Create | ||
102 | * | 108 | * |
103 | * Input Args: | 109 | * Input Args: |
104 | * mode - VM Mode (e.g. VM_MODE_FLAT48PG) | 110 | * mode - VM Mode (e.g. VM_MODE_P52V48_4K) |
105 | * phy_pages - Physical memory pages | 111 | * phy_pages - Physical memory pages |
106 | * perm - permission | 112 | * perm - permission |
107 | * | 113 | * |
@@ -110,7 +116,7 @@ static void vm_open(struct kvm_vm *vm, int perm) | |||
110 | * Return: | 116 | * Return: |
111 | * Pointer to opaque structure that describes the created VM. | 117 | * Pointer to opaque structure that describes the created VM. |
112 | * | 118 | * |
113 | * Creates a VM with the mode specified by mode (e.g. VM_MODE_FLAT48PG). | 119 | * Creates a VM with the mode specified by mode (e.g. VM_MODE_P52V48_4K). |
114 | * When phy_pages is non-zero, a memory region of phy_pages physical pages | 120 | * When phy_pages is non-zero, a memory region of phy_pages physical pages |
115 | * is created and mapped starting at guest physical address 0. The file | 121 | * is created and mapped starting at guest physical address 0. The file |
116 | * descriptor to control the created VM is created with the permissions | 122 | * descriptor to control the created VM is created with the permissions |
@@ -121,7 +127,6 @@ struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm) | |||
121 | struct kvm_vm *vm; | 127 | struct kvm_vm *vm; |
122 | int kvm_fd; | 128 | int kvm_fd; |
123 | 129 | ||
124 | /* Allocate memory. */ | ||
125 | vm = calloc(1, sizeof(*vm)); | 130 | vm = calloc(1, sizeof(*vm)); |
126 | TEST_ASSERT(vm != NULL, "Insufficent Memory"); | 131 | TEST_ASSERT(vm != NULL, "Insufficent Memory"); |
127 | 132 | ||
@@ -130,26 +135,48 @@ struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm) | |||
130 | 135 | ||
131 | /* Setup mode specific traits. */ | 136 | /* Setup mode specific traits. */ |
132 | switch (vm->mode) { | 137 | switch (vm->mode) { |
133 | case VM_MODE_FLAT48PG: | 138 | case VM_MODE_P52V48_4K: |
139 | vm->pgtable_levels = 4; | ||
134 | vm->page_size = 0x1000; | 140 | vm->page_size = 0x1000; |
135 | vm->page_shift = 12; | 141 | vm->page_shift = 12; |
136 | 142 | vm->va_bits = 48; | |
137 | /* Limit to 48-bit canonical virtual addresses. */ | 143 | break; |
138 | vm->vpages_valid = sparsebit_alloc(); | 144 | case VM_MODE_P52V48_64K: |
139 | sparsebit_set_num(vm->vpages_valid, | 145 | vm->pgtable_levels = 3; |
140 | 0, (1ULL << (48 - 1)) >> vm->page_shift); | 146 | vm->pa_bits = 52; |
141 | sparsebit_set_num(vm->vpages_valid, | 147 | vm->page_size = 0x10000; |
142 | (~((1ULL << (48 - 1)) - 1)) >> vm->page_shift, | 148 | vm->page_shift = 16; |
143 | (1ULL << (48 - 1)) >> vm->page_shift); | 149 | vm->va_bits = 48; |
144 | 150 | break; | |
145 | /* Limit physical addresses to 52-bits. */ | 151 | case VM_MODE_P40V48_4K: |
146 | vm->max_gfn = ((1ULL << 52) >> vm->page_shift) - 1; | 152 | vm->pgtable_levels = 4; |
153 | vm->pa_bits = 40; | ||
154 | vm->va_bits = 48; | ||
155 | vm->page_size = 0x1000; | ||
156 | vm->page_shift = 12; | ||
157 | break; | ||
158 | case VM_MODE_P40V48_64K: | ||
159 | vm->pgtable_levels = 3; | ||
160 | vm->pa_bits = 40; | ||
161 | vm->va_bits = 48; | ||
162 | vm->page_size = 0x10000; | ||
163 | vm->page_shift = 16; | ||
147 | break; | 164 | break; |
148 | |||
149 | default: | 165 | default: |
150 | TEST_ASSERT(false, "Unknown guest mode, mode: 0x%x", mode); | 166 | TEST_ASSERT(false, "Unknown guest mode, mode: 0x%x", mode); |
151 | } | 167 | } |
152 | 168 | ||
169 | /* Limit to VA-bit canonical virtual addresses. */ | ||
170 | vm->vpages_valid = sparsebit_alloc(); | ||
171 | sparsebit_set_num(vm->vpages_valid, | ||
172 | 0, (1ULL << (vm->va_bits - 1)) >> vm->page_shift); | ||
173 | sparsebit_set_num(vm->vpages_valid, | ||
174 | (~((1ULL << (vm->va_bits - 1)) - 1)) >> vm->page_shift, | ||
175 | (1ULL << (vm->va_bits - 1)) >> vm->page_shift); | ||
176 | |||
177 | /* Limit physical addresses to PA-bits. */ | ||
178 | vm->max_gfn = ((1ULL << vm->pa_bits) >> vm->page_shift) - 1; | ||
179 | |||
153 | /* Allocate and setup memory for guest. */ | 180 | /* Allocate and setup memory for guest. */ |
154 | vm->vpages_mapped = sparsebit_alloc(); | 181 | vm->vpages_mapped = sparsebit_alloc(); |
155 | if (phy_pages != 0) | 182 | if (phy_pages != 0) |
@@ -159,7 +186,8 @@ struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm) | |||
159 | return vm; | 186 | return vm; |
160 | } | 187 | } |
161 | 188 | ||
162 | /* VM Restart | 189 | /* |
190 | * VM Restart | ||
163 | * | 191 | * |
164 | * Input Args: | 192 | * Input Args: |
165 | * vm - VM that has been released before | 193 | * vm - VM that has been released before |
@@ -186,7 +214,8 @@ void kvm_vm_restart(struct kvm_vm *vmp, int perm) | |||
186 | " rc: %i errno: %i\n" | 214 | " rc: %i errno: %i\n" |
187 | " slot: %u flags: 0x%x\n" | 215 | " slot: %u flags: 0x%x\n" |
188 | " guest_phys_addr: 0x%lx size: 0x%lx", | 216 | " guest_phys_addr: 0x%lx size: 0x%lx", |
189 | ret, errno, region->region.slot, region->region.flags, | 217 | ret, errno, region->region.slot, |
218 | region->region.flags, | ||
190 | region->region.guest_phys_addr, | 219 | region->region.guest_phys_addr, |
191 | region->region.memory_size); | 220 | region->region.memory_size); |
192 | } | 221 | } |
@@ -202,7 +231,8 @@ void kvm_vm_get_dirty_log(struct kvm_vm *vm, int slot, void *log) | |||
202 | strerror(-ret)); | 231 | strerror(-ret)); |
203 | } | 232 | } |
204 | 233 | ||
205 | /* Userspace Memory Region Find | 234 | /* |
235 | * Userspace Memory Region Find | ||
206 | * | 236 | * |
207 | * Input Args: | 237 | * Input Args: |
208 | * vm - Virtual Machine | 238 | * vm - Virtual Machine |
@@ -220,8 +250,8 @@ void kvm_vm_get_dirty_log(struct kvm_vm *vm, int slot, void *log) | |||
220 | * of the regions is returned. Null is returned only when no overlapping | 250 | * of the regions is returned. Null is returned only when no overlapping |
221 | * region exists. | 251 | * region exists. |
222 | */ | 252 | */ |
223 | static struct userspace_mem_region *userspace_mem_region_find( | 253 | static struct userspace_mem_region * |
224 | struct kvm_vm *vm, uint64_t start, uint64_t end) | 254 | userspace_mem_region_find(struct kvm_vm *vm, uint64_t start, uint64_t end) |
225 | { | 255 | { |
226 | struct userspace_mem_region *region; | 256 | struct userspace_mem_region *region; |
227 | 257 | ||
@@ -237,7 +267,8 @@ static struct userspace_mem_region *userspace_mem_region_find( | |||
237 | return NULL; | 267 | return NULL; |
238 | } | 268 | } |
239 | 269 | ||
240 | /* KVM Userspace Memory Region Find | 270 | /* |
271 | * KVM Userspace Memory Region Find | ||
241 | * | 272 | * |
242 | * Input Args: | 273 | * Input Args: |
243 | * vm - Virtual Machine | 274 | * vm - Virtual Machine |
@@ -265,7 +296,8 @@ kvm_userspace_memory_region_find(struct kvm_vm *vm, uint64_t start, | |||
265 | return ®ion->region; | 296 | return ®ion->region; |
266 | } | 297 | } |
267 | 298 | ||
268 | /* VCPU Find | 299 | /* |
300 | * VCPU Find | ||
269 | * | 301 | * |
270 | * Input Args: | 302 | * Input Args: |
271 | * vm - Virtual Machine | 303 | * vm - Virtual Machine |
@@ -280,8 +312,7 @@ kvm_userspace_memory_region_find(struct kvm_vm *vm, uint64_t start, | |||
280 | * returns a pointer to it. Returns NULL if the VM doesn't contain a VCPU | 312 | * returns a pointer to it. Returns NULL if the VM doesn't contain a VCPU |
281 | * for the specified vcpuid. | 313 | * for the specified vcpuid. |
282 | */ | 314 | */ |
283 | struct vcpu *vcpu_find(struct kvm_vm *vm, | 315 | struct vcpu *vcpu_find(struct kvm_vm *vm, uint32_t vcpuid) |
284 | uint32_t vcpuid) | ||
285 | { | 316 | { |
286 | struct vcpu *vcpup; | 317 | struct vcpu *vcpup; |
287 | 318 | ||
@@ -293,7 +324,8 @@ struct vcpu *vcpu_find(struct kvm_vm *vm, | |||
293 | return NULL; | 324 | return NULL; |
294 | } | 325 | } |
295 | 326 | ||
296 | /* VM VCPU Remove | 327 | /* |
328 | * VM VCPU Remove | ||
297 | * | 329 | * |
298 | * Input Args: | 330 | * Input Args: |
299 | * vm - Virtual Machine | 331 | * vm - Virtual Machine |
@@ -330,11 +362,9 @@ void kvm_vm_release(struct kvm_vm *vmp) | |||
330 | { | 362 | { |
331 | int ret; | 363 | int ret; |
332 | 364 | ||
333 | /* Free VCPUs. */ | ||
334 | while (vmp->vcpu_head) | 365 | while (vmp->vcpu_head) |
335 | vm_vcpu_rm(vmp, vmp->vcpu_head->id); | 366 | vm_vcpu_rm(vmp, vmp->vcpu_head->id); |
336 | 367 | ||
337 | /* Close file descriptor for the VM. */ | ||
338 | ret = close(vmp->fd); | 368 | ret = close(vmp->fd); |
339 | TEST_ASSERT(ret == 0, "Close of vm fd failed,\n" | 369 | TEST_ASSERT(ret == 0, "Close of vm fd failed,\n" |
340 | " vmp->fd: %i rc: %i errno: %i", vmp->fd, ret, errno); | 370 | " vmp->fd: %i rc: %i errno: %i", vmp->fd, ret, errno); |
@@ -344,7 +374,8 @@ void kvm_vm_release(struct kvm_vm *vmp) | |||
344 | " vmp->kvm_fd: %i rc: %i errno: %i", vmp->kvm_fd, ret, errno); | 374 | " vmp->kvm_fd: %i rc: %i errno: %i", vmp->kvm_fd, ret, errno); |
345 | } | 375 | } |
346 | 376 | ||
347 | /* Destroys and frees the VM pointed to by vmp. | 377 | /* |
378 | * Destroys and frees the VM pointed to by vmp. | ||
348 | */ | 379 | */ |
349 | void kvm_vm_free(struct kvm_vm *vmp) | 380 | void kvm_vm_free(struct kvm_vm *vmp) |
350 | { | 381 | { |
@@ -383,7 +414,8 @@ void kvm_vm_free(struct kvm_vm *vmp) | |||
383 | free(vmp); | 414 | free(vmp); |
384 | } | 415 | } |
385 | 416 | ||
386 | /* Memory Compare, host virtual to guest virtual | 417 | /* |
418 | * Memory Compare, host virtual to guest virtual | ||
387 | * | 419 | * |
388 | * Input Args: | 420 | * Input Args: |
389 | * hva - Starting host virtual address | 421 | * hva - Starting host virtual address |
@@ -405,23 +437,25 @@ void kvm_vm_free(struct kvm_vm *vmp) | |||
405 | * a length of len, to the guest bytes starting at the guest virtual | 437 | * a length of len, to the guest bytes starting at the guest virtual |
406 | * address given by gva. | 438 | * address given by gva. |
407 | */ | 439 | */ |
408 | int kvm_memcmp_hva_gva(void *hva, | 440 | int kvm_memcmp_hva_gva(void *hva, struct kvm_vm *vm, vm_vaddr_t gva, size_t len) |
409 | struct kvm_vm *vm, vm_vaddr_t gva, size_t len) | ||
410 | { | 441 | { |
411 | size_t amt; | 442 | size_t amt; |
412 | 443 | ||
413 | /* Compare a batch of bytes until either a match is found | 444 | /* |
445 | * Compare a batch of bytes until either a match is found | ||
414 | * or all the bytes have been compared. | 446 | * or all the bytes have been compared. |
415 | */ | 447 | */ |
416 | for (uintptr_t offset = 0; offset < len; offset += amt) { | 448 | for (uintptr_t offset = 0; offset < len; offset += amt) { |
417 | uintptr_t ptr1 = (uintptr_t)hva + offset; | 449 | uintptr_t ptr1 = (uintptr_t)hva + offset; |
418 | 450 | ||
419 | /* Determine host address for guest virtual address | 451 | /* |
452 | * Determine host address for guest virtual address | ||
420 | * at offset. | 453 | * at offset. |
421 | */ | 454 | */ |
422 | uintptr_t ptr2 = (uintptr_t)addr_gva2hva(vm, gva + offset); | 455 | uintptr_t ptr2 = (uintptr_t)addr_gva2hva(vm, gva + offset); |
423 | 456 | ||
424 | /* Determine amount to compare on this pass. | 457 | /* |
458 | * Determine amount to compare on this pass. | ||
425 | * Don't allow the comparsion to cross a page boundary. | 459 | * Don't allow the comparsion to cross a page boundary. |
426 | */ | 460 | */ |
427 | amt = len - offset; | 461 | amt = len - offset; |
@@ -433,7 +467,8 @@ int kvm_memcmp_hva_gva(void *hva, | |||
433 | assert((ptr1 >> vm->page_shift) == ((ptr1 + amt - 1) >> vm->page_shift)); | 467 | assert((ptr1 >> vm->page_shift) == ((ptr1 + amt - 1) >> vm->page_shift)); |
434 | assert((ptr2 >> vm->page_shift) == ((ptr2 + amt - 1) >> vm->page_shift)); | 468 | assert((ptr2 >> vm->page_shift) == ((ptr2 + amt - 1) >> vm->page_shift)); |
435 | 469 | ||
436 | /* Perform the comparison. If there is a difference | 470 | /* |
471 | * Perform the comparison. If there is a difference | ||
437 | * return that result to the caller, otherwise need | 472 | * return that result to the caller, otherwise need |
438 | * to continue on looking for a mismatch. | 473 | * to continue on looking for a mismatch. |
439 | */ | 474 | */ |
@@ -442,109 +477,15 @@ int kvm_memcmp_hva_gva(void *hva, | |||
442 | return ret; | 477 | return ret; |
443 | } | 478 | } |
444 | 479 | ||
445 | /* No mismatch found. Let the caller know the two memory | 480 | /* |
481 | * No mismatch found. Let the caller know the two memory | ||
446 | * areas are equal. | 482 | * areas are equal. |
447 | */ | 483 | */ |
448 | return 0; | 484 | return 0; |
449 | } | 485 | } |
450 | 486 | ||
451 | /* Allocate an instance of struct kvm_cpuid2 | 487 | /* |
452 | * | 488 | * VM Userspace Memory Region Add |
453 | * Input Args: None | ||
454 | * | ||
455 | * Output Args: None | ||
456 | * | ||
457 | * Return: A pointer to the allocated struct. The caller is responsible | ||
458 | * for freeing this struct. | ||
459 | * | ||
460 | * Since kvm_cpuid2 uses a 0-length array to allow a the size of the | ||
461 | * array to be decided at allocation time, allocation is slightly | ||
462 | * complicated. This function uses a reasonable default length for | ||
463 | * the array and performs the appropriate allocation. | ||
464 | */ | ||
465 | static struct kvm_cpuid2 *allocate_kvm_cpuid2(void) | ||
466 | { | ||
467 | struct kvm_cpuid2 *cpuid; | ||
468 | int nent = 100; | ||
469 | size_t size; | ||
470 | |||
471 | size = sizeof(*cpuid); | ||
472 | size += nent * sizeof(struct kvm_cpuid_entry2); | ||
473 | cpuid = malloc(size); | ||
474 | if (!cpuid) { | ||
475 | perror("malloc"); | ||
476 | abort(); | ||
477 | } | ||
478 | |||
479 | cpuid->nent = nent; | ||
480 | |||
481 | return cpuid; | ||
482 | } | ||
483 | |||
484 | /* KVM Supported CPUID Get | ||
485 | * | ||
486 | * Input Args: None | ||
487 | * | ||
488 | * Output Args: | ||
489 | * | ||
490 | * Return: The supported KVM CPUID | ||
491 | * | ||
492 | * Get the guest CPUID supported by KVM. | ||
493 | */ | ||
494 | struct kvm_cpuid2 *kvm_get_supported_cpuid(void) | ||
495 | { | ||
496 | static struct kvm_cpuid2 *cpuid; | ||
497 | int ret; | ||
498 | int kvm_fd; | ||
499 | |||
500 | if (cpuid) | ||
501 | return cpuid; | ||
502 | |||
503 | cpuid = allocate_kvm_cpuid2(); | ||
504 | kvm_fd = open(KVM_DEV_PATH, O_RDONLY); | ||
505 | if (kvm_fd < 0) | ||
506 | exit(KSFT_SKIP); | ||
507 | |||
508 | ret = ioctl(kvm_fd, KVM_GET_SUPPORTED_CPUID, cpuid); | ||
509 | TEST_ASSERT(ret == 0, "KVM_GET_SUPPORTED_CPUID failed %d %d\n", | ||
510 | ret, errno); | ||
511 | |||
512 | close(kvm_fd); | ||
513 | return cpuid; | ||
514 | } | ||
515 | |||
516 | /* Locate a cpuid entry. | ||
517 | * | ||
518 | * Input Args: | ||
519 | * cpuid: The cpuid. | ||
520 | * function: The function of the cpuid entry to find. | ||
521 | * | ||
522 | * Output Args: None | ||
523 | * | ||
524 | * Return: A pointer to the cpuid entry. Never returns NULL. | ||
525 | */ | ||
526 | struct kvm_cpuid_entry2 * | ||
527 | kvm_get_supported_cpuid_index(uint32_t function, uint32_t index) | ||
528 | { | ||
529 | struct kvm_cpuid2 *cpuid; | ||
530 | struct kvm_cpuid_entry2 *entry = NULL; | ||
531 | int i; | ||
532 | |||
533 | cpuid = kvm_get_supported_cpuid(); | ||
534 | for (i = 0; i < cpuid->nent; i++) { | ||
535 | if (cpuid->entries[i].function == function && | ||
536 | cpuid->entries[i].index == index) { | ||
537 | entry = &cpuid->entries[i]; | ||
538 | break; | ||
539 | } | ||
540 | } | ||
541 | |||
542 | TEST_ASSERT(entry, "Guest CPUID entry not found: (EAX=%x, ECX=%x).", | ||
543 | function, index); | ||
544 | return entry; | ||
545 | } | ||
546 | |||
547 | /* VM Userspace Memory Region Add | ||
548 | * | 489 | * |
549 | * Input Args: | 490 | * Input Args: |
550 | * vm - Virtual Machine | 491 | * vm - Virtual Machine |
@@ -586,7 +527,8 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm, | |||
586 | " vm->max_gfn: 0x%lx vm->page_size: 0x%x", | 527 | " vm->max_gfn: 0x%lx vm->page_size: 0x%x", |
587 | guest_paddr, npages, vm->max_gfn, vm->page_size); | 528 | guest_paddr, npages, vm->max_gfn, vm->page_size); |
588 | 529 | ||
589 | /* Confirm a mem region with an overlapping address doesn't | 530 | /* |
531 | * Confirm a mem region with an overlapping address doesn't | ||
590 | * already exist. | 532 | * already exist. |
591 | */ | 533 | */ |
592 | region = (struct userspace_mem_region *) userspace_mem_region_find( | 534 | region = (struct userspace_mem_region *) userspace_mem_region_find( |
@@ -677,7 +619,8 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm, | |||
677 | vm->userspace_mem_region_head = region; | 619 | vm->userspace_mem_region_head = region; |
678 | } | 620 | } |
679 | 621 | ||
680 | /* Memslot to region | 622 | /* |
623 | * Memslot to region | ||
681 | * | 624 | * |
682 | * Input Args: | 625 | * Input Args: |
683 | * vm - Virtual Machine | 626 | * vm - Virtual Machine |
@@ -691,8 +634,8 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm, | |||
691 | * on error (e.g. currently no memory region using memslot as a KVM | 634 | * on error (e.g. currently no memory region using memslot as a KVM |
692 | * memory slot ID). | 635 | * memory slot ID). |
693 | */ | 636 | */ |
694 | static struct userspace_mem_region *memslot2region(struct kvm_vm *vm, | 637 | static struct userspace_mem_region * |
695 | uint32_t memslot) | 638 | memslot2region(struct kvm_vm *vm, uint32_t memslot) |
696 | { | 639 | { |
697 | struct userspace_mem_region *region; | 640 | struct userspace_mem_region *region; |
698 | 641 | ||
@@ -712,7 +655,8 @@ static struct userspace_mem_region *memslot2region(struct kvm_vm *vm, | |||
712 | return region; | 655 | return region; |
713 | } | 656 | } |
714 | 657 | ||
715 | /* VM Memory Region Flags Set | 658 | /* |
659 | * VM Memory Region Flags Set | ||
716 | * | 660 | * |
717 | * Input Args: | 661 | * Input Args: |
718 | * vm - Virtual Machine | 662 | * vm - Virtual Machine |
@@ -730,7 +674,6 @@ void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags) | |||
730 | int ret; | 674 | int ret; |
731 | struct userspace_mem_region *region; | 675 | struct userspace_mem_region *region; |
732 | 676 | ||
733 | /* Locate memory region. */ | ||
734 | region = memslot2region(vm, slot); | 677 | region = memslot2region(vm, slot); |
735 | 678 | ||
736 | region->region.flags = flags; | 679 | region->region.flags = flags; |
@@ -742,7 +685,8 @@ void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags) | |||
742 | ret, errno, slot, flags); | 685 | ret, errno, slot, flags); |
743 | } | 686 | } |
744 | 687 | ||
745 | /* VCPU mmap Size | 688 | /* |
689 | * VCPU mmap Size | ||
746 | * | 690 | * |
747 | * Input Args: None | 691 | * Input Args: None |
748 | * | 692 | * |
@@ -772,7 +716,8 @@ static int vcpu_mmap_sz(void) | |||
772 | return ret; | 716 | return ret; |
773 | } | 717 | } |
774 | 718 | ||
775 | /* VM VCPU Add | 719 | /* |
720 | * VM VCPU Add | ||
776 | * | 721 | * |
777 | * Input Args: | 722 | * Input Args: |
778 | * vm - Virtual Machine | 723 | * vm - Virtual Machine |
@@ -785,7 +730,8 @@ static int vcpu_mmap_sz(void) | |||
785 | * Creates and adds to the VM specified by vm and virtual CPU with | 730 | * Creates and adds to the VM specified by vm and virtual CPU with |
786 | * the ID given by vcpuid. | 731 | * the ID given by vcpuid. |
787 | */ | 732 | */ |
788 | void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid, int pgd_memslot, int gdt_memslot) | 733 | void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid, int pgd_memslot, |
734 | int gdt_memslot) | ||
789 | { | 735 | { |
790 | struct vcpu *vcpu; | 736 | struct vcpu *vcpu; |
791 | 737 | ||
@@ -823,7 +769,8 @@ void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid, int pgd_memslot, int gdt_me | |||
823 | vcpu_setup(vm, vcpuid, pgd_memslot, gdt_memslot); | 769 | vcpu_setup(vm, vcpuid, pgd_memslot, gdt_memslot); |
824 | } | 770 | } |
825 | 771 | ||
826 | /* VM Virtual Address Unused Gap | 772 | /* |
773 | * VM Virtual Address Unused Gap | ||
827 | * | 774 | * |
828 | * Input Args: | 775 | * Input Args: |
829 | * vm - Virtual Machine | 776 | * vm - Virtual Machine |
@@ -843,14 +790,14 @@ void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid, int pgd_memslot, int gdt_me | |||
843 | * sz unallocated bytes >= vaddr_min is available. | 790 | * sz unallocated bytes >= vaddr_min is available. |
844 | */ | 791 | */ |
845 | static vm_vaddr_t vm_vaddr_unused_gap(struct kvm_vm *vm, size_t sz, | 792 | static vm_vaddr_t vm_vaddr_unused_gap(struct kvm_vm *vm, size_t sz, |
846 | vm_vaddr_t vaddr_min) | 793 | vm_vaddr_t vaddr_min) |
847 | { | 794 | { |
848 | uint64_t pages = (sz + vm->page_size - 1) >> vm->page_shift; | 795 | uint64_t pages = (sz + vm->page_size - 1) >> vm->page_shift; |
849 | 796 | ||
850 | /* Determine lowest permitted virtual page index. */ | 797 | /* Determine lowest permitted virtual page index. */ |
851 | uint64_t pgidx_start = (vaddr_min + vm->page_size - 1) >> vm->page_shift; | 798 | uint64_t pgidx_start = (vaddr_min + vm->page_size - 1) >> vm->page_shift; |
852 | if ((pgidx_start * vm->page_size) < vaddr_min) | 799 | if ((pgidx_start * vm->page_size) < vaddr_min) |
853 | goto no_va_found; | 800 | goto no_va_found; |
854 | 801 | ||
855 | /* Loop over section with enough valid virtual page indexes. */ | 802 | /* Loop over section with enough valid virtual page indexes. */ |
856 | if (!sparsebit_is_set_num(vm->vpages_valid, | 803 | if (!sparsebit_is_set_num(vm->vpages_valid, |
@@ -909,7 +856,8 @@ va_found: | |||
909 | return pgidx_start * vm->page_size; | 856 | return pgidx_start * vm->page_size; |
910 | } | 857 | } |
911 | 858 | ||
912 | /* VM Virtual Address Allocate | 859 | /* |
860 | * VM Virtual Address Allocate | ||
913 | * | 861 | * |
914 | * Input Args: | 862 | * Input Args: |
915 | * vm - Virtual Machine | 863 | * vm - Virtual Machine |
@@ -930,13 +878,14 @@ va_found: | |||
930 | * a page. | 878 | * a page. |
931 | */ | 879 | */ |
932 | vm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min, | 880 | vm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min, |
933 | uint32_t data_memslot, uint32_t pgd_memslot) | 881 | uint32_t data_memslot, uint32_t pgd_memslot) |
934 | { | 882 | { |
935 | uint64_t pages = (sz >> vm->page_shift) + ((sz % vm->page_size) != 0); | 883 | uint64_t pages = (sz >> vm->page_shift) + ((sz % vm->page_size) != 0); |
936 | 884 | ||
937 | virt_pgd_alloc(vm, pgd_memslot); | 885 | virt_pgd_alloc(vm, pgd_memslot); |
938 | 886 | ||
939 | /* Find an unused range of virtual page addresses of at least | 887 | /* |
888 | * Find an unused range of virtual page addresses of at least | ||
940 | * pages in length. | 889 | * pages in length. |
941 | */ | 890 | */ |
942 | vm_vaddr_t vaddr_start = vm_vaddr_unused_gap(vm, sz, vaddr_min); | 891 | vm_vaddr_t vaddr_start = vm_vaddr_unused_gap(vm, sz, vaddr_min); |
@@ -946,7 +895,8 @@ vm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min, | |||
946 | pages--, vaddr += vm->page_size) { | 895 | pages--, vaddr += vm->page_size) { |
947 | vm_paddr_t paddr; | 896 | vm_paddr_t paddr; |
948 | 897 | ||
949 | paddr = vm_phy_page_alloc(vm, KVM_UTIL_MIN_PADDR, data_memslot); | 898 | paddr = vm_phy_page_alloc(vm, |
899 | KVM_UTIL_MIN_PFN * vm->page_size, data_memslot); | ||
950 | 900 | ||
951 | virt_pg_map(vm, vaddr, paddr, pgd_memslot); | 901 | virt_pg_map(vm, vaddr, paddr, pgd_memslot); |
952 | 902 | ||
@@ -990,7 +940,8 @@ void virt_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, | |||
990 | } | 940 | } |
991 | } | 941 | } |
992 | 942 | ||
993 | /* Address VM Physical to Host Virtual | 943 | /* |
944 | * Address VM Physical to Host Virtual | ||
994 | * | 945 | * |
995 | * Input Args: | 946 | * Input Args: |
996 | * vm - Virtual Machine | 947 | * vm - Virtual Machine |
@@ -1022,7 +973,8 @@ void *addr_gpa2hva(struct kvm_vm *vm, vm_paddr_t gpa) | |||
1022 | return NULL; | 973 | return NULL; |
1023 | } | 974 | } |
1024 | 975 | ||
1025 | /* Address Host Virtual to VM Physical | 976 | /* |
977 | * Address Host Virtual to VM Physical | ||
1026 | * | 978 | * |
1027 | * Input Args: | 979 | * Input Args: |
1028 | * vm - Virtual Machine | 980 | * vm - Virtual Machine |
@@ -1056,7 +1008,8 @@ vm_paddr_t addr_hva2gpa(struct kvm_vm *vm, void *hva) | |||
1056 | return -1; | 1008 | return -1; |
1057 | } | 1009 | } |
1058 | 1010 | ||
1059 | /* VM Create IRQ Chip | 1011 | /* |
1012 | * VM Create IRQ Chip | ||
1060 | * | 1013 | * |
1061 | * Input Args: | 1014 | * Input Args: |
1062 | * vm - Virtual Machine | 1015 | * vm - Virtual Machine |
@@ -1078,7 +1031,8 @@ void vm_create_irqchip(struct kvm_vm *vm) | |||
1078 | vm->has_irqchip = true; | 1031 | vm->has_irqchip = true; |
1079 | } | 1032 | } |
1080 | 1033 | ||
1081 | /* VM VCPU State | 1034 | /* |
1035 | * VM VCPU State | ||
1082 | * | 1036 | * |
1083 | * Input Args: | 1037 | * Input Args: |
1084 | * vm - Virtual Machine | 1038 | * vm - Virtual Machine |
@@ -1100,7 +1054,8 @@ struct kvm_run *vcpu_state(struct kvm_vm *vm, uint32_t vcpuid) | |||
1100 | return vcpu->state; | 1054 | return vcpu->state; |
1101 | } | 1055 | } |
1102 | 1056 | ||
1103 | /* VM VCPU Run | 1057 | /* |
1058 | * VM VCPU Run | ||
1104 | * | 1059 | * |
1105 | * Input Args: | 1060 | * Input Args: |
1106 | * vm - Virtual Machine | 1061 | * vm - Virtual Machine |
@@ -1126,13 +1081,14 @@ int _vcpu_run(struct kvm_vm *vm, uint32_t vcpuid) | |||
1126 | int rc; | 1081 | int rc; |
1127 | 1082 | ||
1128 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | 1083 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); |
1129 | do { | 1084 | do { |
1130 | rc = ioctl(vcpu->fd, KVM_RUN, NULL); | 1085 | rc = ioctl(vcpu->fd, KVM_RUN, NULL); |
1131 | } while (rc == -1 && errno == EINTR); | 1086 | } while (rc == -1 && errno == EINTR); |
1132 | return rc; | 1087 | return rc; |
1133 | } | 1088 | } |
1134 | 1089 | ||
1135 | /* VM VCPU Set MP State | 1090 | /* |
1091 | * VM VCPU Set MP State | ||
1136 | * | 1092 | * |
1137 | * Input Args: | 1093 | * Input Args: |
1138 | * vm - Virtual Machine | 1094 | * vm - Virtual Machine |
@@ -1147,7 +1103,7 @@ int _vcpu_run(struct kvm_vm *vm, uint32_t vcpuid) | |||
1147 | * by mp_state. | 1103 | * by mp_state. |
1148 | */ | 1104 | */ |
1149 | void vcpu_set_mp_state(struct kvm_vm *vm, uint32_t vcpuid, | 1105 | void vcpu_set_mp_state(struct kvm_vm *vm, uint32_t vcpuid, |
1150 | struct kvm_mp_state *mp_state) | 1106 | struct kvm_mp_state *mp_state) |
1151 | { | 1107 | { |
1152 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | 1108 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); |
1153 | int ret; | 1109 | int ret; |
@@ -1159,7 +1115,8 @@ void vcpu_set_mp_state(struct kvm_vm *vm, uint32_t vcpuid, | |||
1159 | "rc: %i errno: %i", ret, errno); | 1115 | "rc: %i errno: %i", ret, errno); |
1160 | } | 1116 | } |
1161 | 1117 | ||
1162 | /* VM VCPU Regs Get | 1118 | /* |
1119 | * VM VCPU Regs Get | ||
1163 | * | 1120 | * |
1164 | * Input Args: | 1121 | * Input Args: |
1165 | * vm - Virtual Machine | 1122 | * vm - Virtual Machine |
@@ -1173,21 +1130,20 @@ void vcpu_set_mp_state(struct kvm_vm *vm, uint32_t vcpuid, | |||
1173 | * Obtains the current register state for the VCPU specified by vcpuid | 1130 | * Obtains the current register state for the VCPU specified by vcpuid |
1174 | * and stores it at the location given by regs. | 1131 | * and stores it at the location given by regs. |
1175 | */ | 1132 | */ |
1176 | void vcpu_regs_get(struct kvm_vm *vm, | 1133 | void vcpu_regs_get(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_regs *regs) |
1177 | uint32_t vcpuid, struct kvm_regs *regs) | ||
1178 | { | 1134 | { |
1179 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | 1135 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); |
1180 | int ret; | 1136 | int ret; |
1181 | 1137 | ||
1182 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | 1138 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); |
1183 | 1139 | ||
1184 | /* Get the regs. */ | ||
1185 | ret = ioctl(vcpu->fd, KVM_GET_REGS, regs); | 1140 | ret = ioctl(vcpu->fd, KVM_GET_REGS, regs); |
1186 | TEST_ASSERT(ret == 0, "KVM_GET_REGS failed, rc: %i errno: %i", | 1141 | TEST_ASSERT(ret == 0, "KVM_GET_REGS failed, rc: %i errno: %i", |
1187 | ret, errno); | 1142 | ret, errno); |
1188 | } | 1143 | } |
1189 | 1144 | ||
1190 | /* VM VCPU Regs Set | 1145 | /* |
1146 | * VM VCPU Regs Set | ||
1191 | * | 1147 | * |
1192 | * Input Args: | 1148 | * Input Args: |
1193 | * vm - Virtual Machine | 1149 | * vm - Virtual Machine |
@@ -1201,165 +1157,46 @@ void vcpu_regs_get(struct kvm_vm *vm, | |||
1201 | * Sets the regs of the VCPU specified by vcpuid to the values | 1157 | * Sets the regs of the VCPU specified by vcpuid to the values |
1202 | * given by regs. | 1158 | * given by regs. |
1203 | */ | 1159 | */ |
1204 | void vcpu_regs_set(struct kvm_vm *vm, | 1160 | void vcpu_regs_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_regs *regs) |
1205 | uint32_t vcpuid, struct kvm_regs *regs) | ||
1206 | { | 1161 | { |
1207 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | 1162 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); |
1208 | int ret; | 1163 | int ret; |
1209 | 1164 | ||
1210 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | 1165 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); |
1211 | 1166 | ||
1212 | /* Set the regs. */ | ||
1213 | ret = ioctl(vcpu->fd, KVM_SET_REGS, regs); | 1167 | ret = ioctl(vcpu->fd, KVM_SET_REGS, regs); |
1214 | TEST_ASSERT(ret == 0, "KVM_SET_REGS failed, rc: %i errno: %i", | 1168 | TEST_ASSERT(ret == 0, "KVM_SET_REGS failed, rc: %i errno: %i", |
1215 | ret, errno); | 1169 | ret, errno); |
1216 | } | 1170 | } |
1217 | 1171 | ||
1218 | void vcpu_events_get(struct kvm_vm *vm, uint32_t vcpuid, | 1172 | void vcpu_events_get(struct kvm_vm *vm, uint32_t vcpuid, |
1219 | struct kvm_vcpu_events *events) | 1173 | struct kvm_vcpu_events *events) |
1220 | { | 1174 | { |
1221 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | 1175 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); |
1222 | int ret; | 1176 | int ret; |
1223 | 1177 | ||
1224 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | 1178 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); |
1225 | 1179 | ||
1226 | /* Get the regs. */ | ||
1227 | ret = ioctl(vcpu->fd, KVM_GET_VCPU_EVENTS, events); | 1180 | ret = ioctl(vcpu->fd, KVM_GET_VCPU_EVENTS, events); |
1228 | TEST_ASSERT(ret == 0, "KVM_GET_VCPU_EVENTS, failed, rc: %i errno: %i", | 1181 | TEST_ASSERT(ret == 0, "KVM_GET_VCPU_EVENTS, failed, rc: %i errno: %i", |
1229 | ret, errno); | 1182 | ret, errno); |
1230 | } | 1183 | } |
1231 | 1184 | ||
1232 | void vcpu_events_set(struct kvm_vm *vm, uint32_t vcpuid, | 1185 | void vcpu_events_set(struct kvm_vm *vm, uint32_t vcpuid, |
1233 | struct kvm_vcpu_events *events) | 1186 | struct kvm_vcpu_events *events) |
1234 | { | 1187 | { |
1235 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | 1188 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); |
1236 | int ret; | 1189 | int ret; |
1237 | 1190 | ||
1238 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | 1191 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); |
1239 | 1192 | ||
1240 | /* Set the regs. */ | ||
1241 | ret = ioctl(vcpu->fd, KVM_SET_VCPU_EVENTS, events); | 1193 | ret = ioctl(vcpu->fd, KVM_SET_VCPU_EVENTS, events); |
1242 | TEST_ASSERT(ret == 0, "KVM_SET_VCPU_EVENTS, failed, rc: %i errno: %i", | 1194 | TEST_ASSERT(ret == 0, "KVM_SET_VCPU_EVENTS, failed, rc: %i errno: %i", |
1243 | ret, errno); | 1195 | ret, errno); |
1244 | } | 1196 | } |
1245 | 1197 | ||
1246 | /* VCPU Get MSR | 1198 | /* |
1247 | * | 1199 | * VM VCPU System Regs Get |
1248 | * Input Args: | ||
1249 | * vm - Virtual Machine | ||
1250 | * vcpuid - VCPU ID | ||
1251 | * msr_index - Index of MSR | ||
1252 | * | ||
1253 | * Output Args: None | ||
1254 | * | ||
1255 | * Return: On success, value of the MSR. On failure a TEST_ASSERT is produced. | ||
1256 | * | ||
1257 | * Get value of MSR for VCPU. | ||
1258 | */ | ||
1259 | uint64_t vcpu_get_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index) | ||
1260 | { | ||
1261 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | ||
1262 | struct { | ||
1263 | struct kvm_msrs header; | ||
1264 | struct kvm_msr_entry entry; | ||
1265 | } buffer = {}; | ||
1266 | int r; | ||
1267 | |||
1268 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | ||
1269 | buffer.header.nmsrs = 1; | ||
1270 | buffer.entry.index = msr_index; | ||
1271 | r = ioctl(vcpu->fd, KVM_GET_MSRS, &buffer.header); | ||
1272 | TEST_ASSERT(r == 1, "KVM_GET_MSRS IOCTL failed,\n" | ||
1273 | " rc: %i errno: %i", r, errno); | ||
1274 | |||
1275 | return buffer.entry.data; | ||
1276 | } | ||
1277 | |||
1278 | /* VCPU Set MSR | ||
1279 | * | ||
1280 | * Input Args: | ||
1281 | * vm - Virtual Machine | ||
1282 | * vcpuid - VCPU ID | ||
1283 | * msr_index - Index of MSR | ||
1284 | * msr_value - New value of MSR | ||
1285 | * | ||
1286 | * Output Args: None | ||
1287 | * | ||
1288 | * Return: On success, nothing. On failure a TEST_ASSERT is produced. | ||
1289 | * | ||
1290 | * Set value of MSR for VCPU. | ||
1291 | */ | ||
1292 | void vcpu_set_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index, | ||
1293 | uint64_t msr_value) | ||
1294 | { | ||
1295 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | ||
1296 | struct { | ||
1297 | struct kvm_msrs header; | ||
1298 | struct kvm_msr_entry entry; | ||
1299 | } buffer = {}; | ||
1300 | int r; | ||
1301 | |||
1302 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | ||
1303 | memset(&buffer, 0, sizeof(buffer)); | ||
1304 | buffer.header.nmsrs = 1; | ||
1305 | buffer.entry.index = msr_index; | ||
1306 | buffer.entry.data = msr_value; | ||
1307 | r = ioctl(vcpu->fd, KVM_SET_MSRS, &buffer.header); | ||
1308 | TEST_ASSERT(r == 1, "KVM_SET_MSRS IOCTL failed,\n" | ||
1309 | " rc: %i errno: %i", r, errno); | ||
1310 | } | ||
1311 | |||
1312 | /* VM VCPU Args Set | ||
1313 | * | ||
1314 | * Input Args: | ||
1315 | * vm - Virtual Machine | ||
1316 | * vcpuid - VCPU ID | ||
1317 | * num - number of arguments | ||
1318 | * ... - arguments, each of type uint64_t | ||
1319 | * | ||
1320 | * Output Args: None | ||
1321 | * | ||
1322 | * Return: None | ||
1323 | * | ||
1324 | * Sets the first num function input arguments to the values | ||
1325 | * given as variable args. Each of the variable args is expected to | ||
1326 | * be of type uint64_t. | ||
1327 | */ | ||
1328 | void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...) | ||
1329 | { | ||
1330 | va_list ap; | ||
1331 | struct kvm_regs regs; | ||
1332 | |||
1333 | TEST_ASSERT(num >= 1 && num <= 6, "Unsupported number of args,\n" | ||
1334 | " num: %u\n", | ||
1335 | num); | ||
1336 | |||
1337 | va_start(ap, num); | ||
1338 | vcpu_regs_get(vm, vcpuid, ®s); | ||
1339 | |||
1340 | if (num >= 1) | ||
1341 | regs.rdi = va_arg(ap, uint64_t); | ||
1342 | |||
1343 | if (num >= 2) | ||
1344 | regs.rsi = va_arg(ap, uint64_t); | ||
1345 | |||
1346 | if (num >= 3) | ||
1347 | regs.rdx = va_arg(ap, uint64_t); | ||
1348 | |||
1349 | if (num >= 4) | ||
1350 | regs.rcx = va_arg(ap, uint64_t); | ||
1351 | |||
1352 | if (num >= 5) | ||
1353 | regs.r8 = va_arg(ap, uint64_t); | ||
1354 | |||
1355 | if (num >= 6) | ||
1356 | regs.r9 = va_arg(ap, uint64_t); | ||
1357 | |||
1358 | vcpu_regs_set(vm, vcpuid, ®s); | ||
1359 | va_end(ap); | ||
1360 | } | ||
1361 | |||
1362 | /* VM VCPU System Regs Get | ||
1363 | * | 1200 | * |
1364 | * Input Args: | 1201 | * Input Args: |
1365 | * vm - Virtual Machine | 1202 | * vm - Virtual Machine |
@@ -1373,22 +1210,20 @@ void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...) | |||
1373 | * Obtains the current system register state for the VCPU specified by | 1210 | * Obtains the current system register state for the VCPU specified by |
1374 | * vcpuid and stores it at the location given by sregs. | 1211 | * vcpuid and stores it at the location given by sregs. |
1375 | */ | 1212 | */ |
1376 | void vcpu_sregs_get(struct kvm_vm *vm, | 1213 | void vcpu_sregs_get(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_sregs *sregs) |
1377 | uint32_t vcpuid, struct kvm_sregs *sregs) | ||
1378 | { | 1214 | { |
1379 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | 1215 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); |
1380 | int ret; | 1216 | int ret; |
1381 | 1217 | ||
1382 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | 1218 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); |
1383 | 1219 | ||
1384 | /* Get the regs. */ | ||
1385 | /* Get the regs. */ | ||
1386 | ret = ioctl(vcpu->fd, KVM_GET_SREGS, sregs); | 1220 | ret = ioctl(vcpu->fd, KVM_GET_SREGS, sregs); |
1387 | TEST_ASSERT(ret == 0, "KVM_GET_SREGS failed, rc: %i errno: %i", | 1221 | TEST_ASSERT(ret == 0, "KVM_GET_SREGS failed, rc: %i errno: %i", |
1388 | ret, errno); | 1222 | ret, errno); |
1389 | } | 1223 | } |
1390 | 1224 | ||
1391 | /* VM VCPU System Regs Set | 1225 | /* |
1226 | * VM VCPU System Regs Set | ||
1392 | * | 1227 | * |
1393 | * Input Args: | 1228 | * Input Args: |
1394 | * vm - Virtual Machine | 1229 | * vm - Virtual Machine |
@@ -1402,27 +1237,25 @@ void vcpu_sregs_get(struct kvm_vm *vm, | |||
1402 | * Sets the system regs of the VCPU specified by vcpuid to the values | 1237 | * Sets the system regs of the VCPU specified by vcpuid to the values |
1403 | * given by sregs. | 1238 | * given by sregs. |
1404 | */ | 1239 | */ |
1405 | void vcpu_sregs_set(struct kvm_vm *vm, | 1240 | void vcpu_sregs_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_sregs *sregs) |
1406 | uint32_t vcpuid, struct kvm_sregs *sregs) | ||
1407 | { | 1241 | { |
1408 | int ret = _vcpu_sregs_set(vm, vcpuid, sregs); | 1242 | int ret = _vcpu_sregs_set(vm, vcpuid, sregs); |
1409 | TEST_ASSERT(ret == 0, "KVM_RUN IOCTL failed, " | 1243 | TEST_ASSERT(ret == 0, "KVM_RUN IOCTL failed, " |
1410 | "rc: %i errno: %i", ret, errno); | 1244 | "rc: %i errno: %i", ret, errno); |
1411 | } | 1245 | } |
1412 | 1246 | ||
1413 | int _vcpu_sregs_set(struct kvm_vm *vm, | 1247 | int _vcpu_sregs_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_sregs *sregs) |
1414 | uint32_t vcpuid, struct kvm_sregs *sregs) | ||
1415 | { | 1248 | { |
1416 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | 1249 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); |
1417 | int ret; | 1250 | int ret; |
1418 | 1251 | ||
1419 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | 1252 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); |
1420 | 1253 | ||
1421 | /* Get the regs. */ | ||
1422 | return ioctl(vcpu->fd, KVM_SET_SREGS, sregs); | 1254 | return ioctl(vcpu->fd, KVM_SET_SREGS, sregs); |
1423 | } | 1255 | } |
1424 | 1256 | ||
1425 | /* VCPU Ioctl | 1257 | /* |
1258 | * VCPU Ioctl | ||
1426 | * | 1259 | * |
1427 | * Input Args: | 1260 | * Input Args: |
1428 | * vm - Virtual Machine | 1261 | * vm - Virtual Machine |
@@ -1434,8 +1267,8 @@ int _vcpu_sregs_set(struct kvm_vm *vm, | |||
1434 | * | 1267 | * |
1435 | * Issues an arbitrary ioctl on a VCPU fd. | 1268 | * Issues an arbitrary ioctl on a VCPU fd. |
1436 | */ | 1269 | */ |
1437 | void vcpu_ioctl(struct kvm_vm *vm, | 1270 | void vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, |
1438 | uint32_t vcpuid, unsigned long cmd, void *arg) | 1271 | unsigned long cmd, void *arg) |
1439 | { | 1272 | { |
1440 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | 1273 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); |
1441 | int ret; | 1274 | int ret; |
@@ -1447,7 +1280,8 @@ void vcpu_ioctl(struct kvm_vm *vm, | |||
1447 | cmd, ret, errno, strerror(errno)); | 1280 | cmd, ret, errno, strerror(errno)); |
1448 | } | 1281 | } |
1449 | 1282 | ||
1450 | /* VM Ioctl | 1283 | /* |
1284 | * VM Ioctl | ||
1451 | * | 1285 | * |
1452 | * Input Args: | 1286 | * Input Args: |
1453 | * vm - Virtual Machine | 1287 | * vm - Virtual Machine |
@@ -1467,7 +1301,8 @@ void vm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg) | |||
1467 | cmd, ret, errno, strerror(errno)); | 1301 | cmd, ret, errno, strerror(errno)); |
1468 | } | 1302 | } |
1469 | 1303 | ||
1470 | /* VM Dump | 1304 | /* |
1305 | * VM Dump | ||
1471 | * | 1306 | * |
1472 | * Input Args: | 1307 | * Input Args: |
1473 | * vm - Virtual Machine | 1308 | * vm - Virtual Machine |
@@ -1514,38 +1349,6 @@ void vm_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent) | |||
1514 | vcpu_dump(stream, vm, vcpu->id, indent + 2); | 1349 | vcpu_dump(stream, vm, vcpu->id, indent + 2); |
1515 | } | 1350 | } |
1516 | 1351 | ||
1517 | /* VM VCPU Dump | ||
1518 | * | ||
1519 | * Input Args: | ||
1520 | * vm - Virtual Machine | ||
1521 | * vcpuid - VCPU ID | ||
1522 | * indent - Left margin indent amount | ||
1523 | * | ||
1524 | * Output Args: | ||
1525 | * stream - Output FILE stream | ||
1526 | * | ||
1527 | * Return: None | ||
1528 | * | ||
1529 | * Dumps the current state of the VCPU specified by vcpuid, within the VM | ||
1530 | * given by vm, to the FILE stream given by stream. | ||
1531 | */ | ||
1532 | void vcpu_dump(FILE *stream, struct kvm_vm *vm, | ||
1533 | uint32_t vcpuid, uint8_t indent) | ||
1534 | { | ||
1535 | struct kvm_regs regs; | ||
1536 | struct kvm_sregs sregs; | ||
1537 | |||
1538 | fprintf(stream, "%*scpuid: %u\n", indent, "", vcpuid); | ||
1539 | |||
1540 | fprintf(stream, "%*sregs:\n", indent + 2, ""); | ||
1541 | vcpu_regs_get(vm, vcpuid, ®s); | ||
1542 | regs_dump(stream, ®s, indent + 4); | ||
1543 | |||
1544 | fprintf(stream, "%*ssregs:\n", indent + 2, ""); | ||
1545 | vcpu_sregs_get(vm, vcpuid, &sregs); | ||
1546 | sregs_dump(stream, &sregs, indent + 4); | ||
1547 | } | ||
1548 | |||
1549 | /* Known KVM exit reasons */ | 1352 | /* Known KVM exit reasons */ |
1550 | static struct exit_reason { | 1353 | static struct exit_reason { |
1551 | unsigned int reason; | 1354 | unsigned int reason; |
@@ -1576,7 +1379,8 @@ static struct exit_reason { | |||
1576 | #endif | 1379 | #endif |
1577 | }; | 1380 | }; |
1578 | 1381 | ||
1579 | /* Exit Reason String | 1382 | /* |
1383 | * Exit Reason String | ||
1580 | * | 1384 | * |
1581 | * Input Args: | 1385 | * Input Args: |
1582 | * exit_reason - Exit reason | 1386 | * exit_reason - Exit reason |
@@ -1602,10 +1406,12 @@ const char *exit_reason_str(unsigned int exit_reason) | |||
1602 | return "Unknown"; | 1406 | return "Unknown"; |
1603 | } | 1407 | } |
1604 | 1408 | ||
1605 | /* Physical Page Allocate | 1409 | /* |
1410 | * Physical Contiguous Page Allocator | ||
1606 | * | 1411 | * |
1607 | * Input Args: | 1412 | * Input Args: |
1608 | * vm - Virtual Machine | 1413 | * vm - Virtual Machine |
1414 | * num - number of pages | ||
1609 | * paddr_min - Physical address minimum | 1415 | * paddr_min - Physical address minimum |
1610 | * memslot - Memory region to allocate page from | 1416 | * memslot - Memory region to allocate page from |
1611 | * | 1417 | * |
@@ -1614,47 +1420,59 @@ const char *exit_reason_str(unsigned int exit_reason) | |||
1614 | * Return: | 1420 | * Return: |
1615 | * Starting physical address | 1421 | * Starting physical address |
1616 | * | 1422 | * |
1617 | * Within the VM specified by vm, locates an available physical page | 1423 | * Within the VM specified by vm, locates a range of available physical |
1618 | * at or above paddr_min. If found, the page is marked as in use | 1424 | * pages at or above paddr_min. If found, the pages are marked as in use |
1619 | * and its address is returned. A TEST_ASSERT failure occurs if no | 1425 | * and thier base address is returned. A TEST_ASSERT failure occurs if |
1620 | * page is available at or above paddr_min. | 1426 | * not enough pages are available at or above paddr_min. |
1621 | */ | 1427 | */ |
1622 | vm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm, | 1428 | vm_paddr_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t num, |
1623 | vm_paddr_t paddr_min, uint32_t memslot) | 1429 | vm_paddr_t paddr_min, uint32_t memslot) |
1624 | { | 1430 | { |
1625 | struct userspace_mem_region *region; | 1431 | struct userspace_mem_region *region; |
1626 | sparsebit_idx_t pg; | 1432 | sparsebit_idx_t pg, base; |
1433 | |||
1434 | TEST_ASSERT(num > 0, "Must allocate at least one page"); | ||
1627 | 1435 | ||
1628 | TEST_ASSERT((paddr_min % vm->page_size) == 0, "Min physical address " | 1436 | TEST_ASSERT((paddr_min % vm->page_size) == 0, "Min physical address " |
1629 | "not divisible by page size.\n" | 1437 | "not divisible by page size.\n" |
1630 | " paddr_min: 0x%lx page_size: 0x%x", | 1438 | " paddr_min: 0x%lx page_size: 0x%x", |
1631 | paddr_min, vm->page_size); | 1439 | paddr_min, vm->page_size); |
1632 | 1440 | ||
1633 | /* Locate memory region. */ | ||
1634 | region = memslot2region(vm, memslot); | 1441 | region = memslot2region(vm, memslot); |
1442 | base = pg = paddr_min >> vm->page_shift; | ||
1635 | 1443 | ||
1636 | /* Locate next available physical page at or above paddr_min. */ | 1444 | do { |
1637 | pg = paddr_min >> vm->page_shift; | 1445 | for (; pg < base + num; ++pg) { |
1638 | 1446 | if (!sparsebit_is_set(region->unused_phy_pages, pg)) { | |
1639 | if (!sparsebit_is_set(region->unused_phy_pages, pg)) { | 1447 | base = pg = sparsebit_next_set(region->unused_phy_pages, pg); |
1640 | pg = sparsebit_next_set(region->unused_phy_pages, pg); | 1448 | break; |
1641 | if (pg == 0) { | 1449 | } |
1642 | fprintf(stderr, "No guest physical page available, " | ||
1643 | "paddr_min: 0x%lx page_size: 0x%x memslot: %u", | ||
1644 | paddr_min, vm->page_size, memslot); | ||
1645 | fputs("---- vm dump ----\n", stderr); | ||
1646 | vm_dump(stderr, vm, 2); | ||
1647 | abort(); | ||
1648 | } | 1450 | } |
1451 | } while (pg && pg != base + num); | ||
1452 | |||
1453 | if (pg == 0) { | ||
1454 | fprintf(stderr, "No guest physical page available, " | ||
1455 | "paddr_min: 0x%lx page_size: 0x%x memslot: %u\n", | ||
1456 | paddr_min, vm->page_size, memslot); | ||
1457 | fputs("---- vm dump ----\n", stderr); | ||
1458 | vm_dump(stderr, vm, 2); | ||
1459 | abort(); | ||
1649 | } | 1460 | } |
1650 | 1461 | ||
1651 | /* Specify page as in use and return its address. */ | 1462 | for (pg = base; pg < base + num; ++pg) |
1652 | sparsebit_clear(region->unused_phy_pages, pg); | 1463 | sparsebit_clear(region->unused_phy_pages, pg); |
1464 | |||
1465 | return base * vm->page_size; | ||
1466 | } | ||
1653 | 1467 | ||
1654 | return pg * vm->page_size; | 1468 | vm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm, vm_paddr_t paddr_min, |
1469 | uint32_t memslot) | ||
1470 | { | ||
1471 | return vm_phy_pages_alloc(vm, 1, paddr_min, memslot); | ||
1655 | } | 1472 | } |
1656 | 1473 | ||
1657 | /* Address Guest Virtual to Host Virtual | 1474 | /* |
1475 | * Address Guest Virtual to Host Virtual | ||
1658 | * | 1476 | * |
1659 | * Input Args: | 1477 | * Input Args: |
1660 | * vm - Virtual Machine | 1478 | * vm - Virtual Machine |
@@ -1669,17 +1487,3 @@ void *addr_gva2hva(struct kvm_vm *vm, vm_vaddr_t gva) | |||
1669 | { | 1487 | { |
1670 | return addr_gpa2hva(vm, addr_gva2gpa(vm, gva)); | 1488 | return addr_gpa2hva(vm, addr_gva2gpa(vm, gva)); |
1671 | } | 1489 | } |
1672 | |||
1673 | void guest_args_read(struct kvm_vm *vm, uint32_t vcpu_id, | ||
1674 | struct guest_args *args) | ||
1675 | { | ||
1676 | struct kvm_run *run = vcpu_state(vm, vcpu_id); | ||
1677 | struct kvm_regs regs; | ||
1678 | |||
1679 | memset(®s, 0, sizeof(regs)); | ||
1680 | vcpu_regs_get(vm, vcpu_id, ®s); | ||
1681 | |||
1682 | args->port = run->io.port; | ||
1683 | args->arg0 = regs.rdi; | ||
1684 | args->arg1 = regs.rsi; | ||
1685 | } | ||
diff --git a/tools/testing/selftests/kvm/lib/kvm_util_internal.h b/tools/testing/selftests/kvm/lib/kvm_util_internal.h index 542ed606b338..52701db0f253 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util_internal.h +++ b/tools/testing/selftests/kvm/lib/kvm_util_internal.h | |||
@@ -1,28 +1,29 @@ | |||
1 | /* | 1 | /* |
2 | * tools/testing/selftests/kvm/lib/kvm_util.c | 2 | * tools/testing/selftests/kvm/lib/kvm_util_internal.h |
3 | * | 3 | * |
4 | * Copyright (C) 2018, Google LLC. | 4 | * Copyright (C) 2018, Google LLC. |
5 | * | 5 | * |
6 | * This work is licensed under the terms of the GNU GPL, version 2. | 6 | * This work is licensed under the terms of the GNU GPL, version 2. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #ifndef KVM_UTIL_INTERNAL_H | 9 | #ifndef SELFTEST_KVM_UTIL_INTERNAL_H |
10 | #define KVM_UTIL_INTERNAL_H 1 | 10 | #define SELFTEST_KVM_UTIL_INTERNAL_H |
11 | 11 | ||
12 | #include "sparsebit.h" | 12 | #include "sparsebit.h" |
13 | 13 | ||
14 | #define KVM_DEV_PATH "/dev/kvm" | ||
15 | |||
14 | #ifndef BITS_PER_BYTE | 16 | #ifndef BITS_PER_BYTE |
15 | #define BITS_PER_BYTE 8 | 17 | #define BITS_PER_BYTE 8 |
16 | #endif | 18 | #endif |
17 | 19 | ||
18 | #ifndef BITS_PER_LONG | 20 | #ifndef BITS_PER_LONG |
19 | #define BITS_PER_LONG (BITS_PER_BYTE * sizeof(long)) | 21 | #define BITS_PER_LONG (BITS_PER_BYTE * sizeof(long)) |
20 | #endif | 22 | #endif |
21 | 23 | ||
22 | #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) | 24 | #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) |
23 | #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_LONG) | 25 | #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_LONG) |
24 | 26 | ||
25 | /* Concrete definition of struct kvm_vm. */ | ||
26 | struct userspace_mem_region { | 27 | struct userspace_mem_region { |
27 | struct userspace_mem_region *next, *prev; | 28 | struct userspace_mem_region *next, *prev; |
28 | struct kvm_userspace_memory_region region; | 29 | struct kvm_userspace_memory_region region; |
@@ -45,14 +46,16 @@ struct kvm_vm { | |||
45 | int mode; | 46 | int mode; |
46 | int kvm_fd; | 47 | int kvm_fd; |
47 | int fd; | 48 | int fd; |
49 | unsigned int pgtable_levels; | ||
48 | unsigned int page_size; | 50 | unsigned int page_size; |
49 | unsigned int page_shift; | 51 | unsigned int page_shift; |
52 | unsigned int pa_bits; | ||
53 | unsigned int va_bits; | ||
50 | uint64_t max_gfn; | 54 | uint64_t max_gfn; |
51 | struct vcpu *vcpu_head; | 55 | struct vcpu *vcpu_head; |
52 | struct userspace_mem_region *userspace_mem_region_head; | 56 | struct userspace_mem_region *userspace_mem_region_head; |
53 | struct sparsebit *vpages_valid; | 57 | struct sparsebit *vpages_valid; |
54 | struct sparsebit *vpages_mapped; | 58 | struct sparsebit *vpages_mapped; |
55 | |||
56 | bool has_irqchip; | 59 | bool has_irqchip; |
57 | bool pgd_created; | 60 | bool pgd_created; |
58 | vm_paddr_t pgd; | 61 | vm_paddr_t pgd; |
@@ -60,13 +63,11 @@ struct kvm_vm { | |||
60 | vm_vaddr_t tss; | 63 | vm_vaddr_t tss; |
61 | }; | 64 | }; |
62 | 65 | ||
63 | struct vcpu *vcpu_find(struct kvm_vm *vm, | 66 | struct vcpu *vcpu_find(struct kvm_vm *vm, uint32_t vcpuid); |
64 | uint32_t vcpuid); | 67 | void vcpu_setup(struct kvm_vm *vm, int vcpuid, int pgd_memslot, |
65 | void vcpu_setup(struct kvm_vm *vm, int vcpuid, int pgd_memslot, int gdt_memslot); | 68 | int gdt_memslot); |
66 | void virt_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent); | 69 | void virt_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent); |
67 | void regs_dump(FILE *stream, struct kvm_regs *regs, | 70 | void regs_dump(FILE *stream, struct kvm_regs *regs, uint8_t indent); |
68 | uint8_t indent); | 71 | void sregs_dump(FILE *stream, struct kvm_sregs *sregs, uint8_t indent); |
69 | void sregs_dump(FILE *stream, struct kvm_sregs *sregs, | ||
70 | uint8_t indent); | ||
71 | 72 | ||
72 | #endif | 73 | #endif /* SELFTEST_KVM_UTIL_INTERNAL_H */ |
diff --git a/tools/testing/selftests/kvm/lib/ucall.c b/tools/testing/selftests/kvm/lib/ucall.c new file mode 100644 index 000000000000..4777f9bb5194 --- /dev/null +++ b/tools/testing/selftests/kvm/lib/ucall.c | |||
@@ -0,0 +1,144 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * ucall support. A ucall is a "hypercall to userspace". | ||
4 | * | ||
5 | * Copyright (C) 2018, Red Hat, Inc. | ||
6 | */ | ||
7 | #include "kvm_util.h" | ||
8 | #include "kvm_util_internal.h" | ||
9 | |||
10 | #define UCALL_PIO_PORT ((uint16_t)0x1000) | ||
11 | |||
12 | static ucall_type_t ucall_type; | ||
13 | static vm_vaddr_t *ucall_exit_mmio_addr; | ||
14 | |||
15 | static bool ucall_mmio_init(struct kvm_vm *vm, vm_paddr_t gpa) | ||
16 | { | ||
17 | if (kvm_userspace_memory_region_find(vm, gpa, gpa + 1)) | ||
18 | return false; | ||
19 | |||
20 | virt_pg_map(vm, gpa, gpa, 0); | ||
21 | |||
22 | ucall_exit_mmio_addr = (vm_vaddr_t *)gpa; | ||
23 | sync_global_to_guest(vm, ucall_exit_mmio_addr); | ||
24 | |||
25 | return true; | ||
26 | } | ||
27 | |||
28 | void ucall_init(struct kvm_vm *vm, ucall_type_t type, void *arg) | ||
29 | { | ||
30 | ucall_type = type; | ||
31 | sync_global_to_guest(vm, ucall_type); | ||
32 | |||
33 | if (type == UCALL_PIO) | ||
34 | return; | ||
35 | |||
36 | if (type == UCALL_MMIO) { | ||
37 | vm_paddr_t gpa, start, end, step; | ||
38 | bool ret; | ||
39 | |||
40 | if (arg) { | ||
41 | gpa = (vm_paddr_t)arg; | ||
42 | ret = ucall_mmio_init(vm, gpa); | ||
43 | TEST_ASSERT(ret, "Can't set ucall mmio address to %lx", gpa); | ||
44 | return; | ||
45 | } | ||
46 | |||
47 | /* | ||
48 | * Find an address within the allowed virtual address space, | ||
49 | * that does _not_ have a KVM memory region associated with it. | ||
50 | * Identity mapping an address like this allows the guest to | ||
51 | * access it, but as KVM doesn't know what to do with it, it | ||
52 | * will assume it's something userspace handles and exit with | ||
53 | * KVM_EXIT_MMIO. Well, at least that's how it works for AArch64. | ||
54 | * Here we start with a guess that the addresses around two | ||
55 | * thirds of the VA space are unmapped and then work both down | ||
56 | * and up from there in 1/6 VA space sized steps. | ||
57 | */ | ||
58 | start = 1ul << (vm->va_bits * 2 / 3); | ||
59 | end = 1ul << vm->va_bits; | ||
60 | step = 1ul << (vm->va_bits / 6); | ||
61 | for (gpa = start; gpa >= 0; gpa -= step) { | ||
62 | if (ucall_mmio_init(vm, gpa & ~(vm->page_size - 1))) | ||
63 | return; | ||
64 | } | ||
65 | for (gpa = start + step; gpa < end; gpa += step) { | ||
66 | if (ucall_mmio_init(vm, gpa & ~(vm->page_size - 1))) | ||
67 | return; | ||
68 | } | ||
69 | TEST_ASSERT(false, "Can't find a ucall mmio address"); | ||
70 | } | ||
71 | } | ||
72 | |||
73 | void ucall_uninit(struct kvm_vm *vm) | ||
74 | { | ||
75 | ucall_type = 0; | ||
76 | sync_global_to_guest(vm, ucall_type); | ||
77 | ucall_exit_mmio_addr = 0; | ||
78 | sync_global_to_guest(vm, ucall_exit_mmio_addr); | ||
79 | } | ||
80 | |||
81 | static void ucall_pio_exit(struct ucall *uc) | ||
82 | { | ||
83 | #ifdef __x86_64__ | ||
84 | asm volatile("in %[port], %%al" | ||
85 | : : [port] "d" (UCALL_PIO_PORT), "D" (uc) : "rax"); | ||
86 | #endif | ||
87 | } | ||
88 | |||
89 | static void ucall_mmio_exit(struct ucall *uc) | ||
90 | { | ||
91 | *ucall_exit_mmio_addr = (vm_vaddr_t)uc; | ||
92 | } | ||
93 | |||
94 | void ucall(uint64_t cmd, int nargs, ...) | ||
95 | { | ||
96 | struct ucall uc = { | ||
97 | .cmd = cmd, | ||
98 | }; | ||
99 | va_list va; | ||
100 | int i; | ||
101 | |||
102 | nargs = nargs <= UCALL_MAX_ARGS ? nargs : UCALL_MAX_ARGS; | ||
103 | |||
104 | va_start(va, nargs); | ||
105 | for (i = 0; i < nargs; ++i) | ||
106 | uc.args[i] = va_arg(va, uint64_t); | ||
107 | va_end(va); | ||
108 | |||
109 | switch (ucall_type) { | ||
110 | case UCALL_PIO: | ||
111 | ucall_pio_exit(&uc); | ||
112 | break; | ||
113 | case UCALL_MMIO: | ||
114 | ucall_mmio_exit(&uc); | ||
115 | break; | ||
116 | }; | ||
117 | } | ||
118 | |||
119 | uint64_t get_ucall(struct kvm_vm *vm, uint32_t vcpu_id, struct ucall *uc) | ||
120 | { | ||
121 | struct kvm_run *run = vcpu_state(vm, vcpu_id); | ||
122 | |||
123 | memset(uc, 0, sizeof(*uc)); | ||
124 | |||
125 | #ifdef __x86_64__ | ||
126 | if (ucall_type == UCALL_PIO && run->exit_reason == KVM_EXIT_IO && | ||
127 | run->io.port == UCALL_PIO_PORT) { | ||
128 | struct kvm_regs regs; | ||
129 | vcpu_regs_get(vm, vcpu_id, ®s); | ||
130 | memcpy(uc, addr_gva2hva(vm, (vm_vaddr_t)regs.rdi), sizeof(*uc)); | ||
131 | return uc->cmd; | ||
132 | } | ||
133 | #endif | ||
134 | if (ucall_type == UCALL_MMIO && run->exit_reason == KVM_EXIT_MMIO && | ||
135 | run->mmio.phys_addr == (uint64_t)ucall_exit_mmio_addr) { | ||
136 | vm_vaddr_t gva; | ||
137 | TEST_ASSERT(run->mmio.is_write && run->mmio.len == 8, | ||
138 | "Unexpected ucall exit mmio address access"); | ||
139 | gva = *(vm_vaddr_t *)run->mmio.data; | ||
140 | memcpy(uc, addr_gva2hva(vm, gva), sizeof(*uc)); | ||
141 | } | ||
142 | |||
143 | return uc->cmd; | ||
144 | } | ||
diff --git a/tools/testing/selftests/kvm/lib/x86.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index a3122f1949a8..f28127f4a3af 100644 --- a/tools/testing/selftests/kvm/lib/x86.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * tools/testing/selftests/kvm/lib/x86.c | 2 | * tools/testing/selftests/kvm/lib/x86_64/processor.c |
3 | * | 3 | * |
4 | * Copyright (C) 2018, Google LLC. | 4 | * Copyright (C) 2018, Google LLC. |
5 | * | 5 | * |
@@ -10,8 +10,8 @@ | |||
10 | 10 | ||
11 | #include "test_util.h" | 11 | #include "test_util.h" |
12 | #include "kvm_util.h" | 12 | #include "kvm_util.h" |
13 | #include "kvm_util_internal.h" | 13 | #include "../kvm_util_internal.h" |
14 | #include "x86.h" | 14 | #include "processor.h" |
15 | 15 | ||
16 | /* Minimum physical address used for virtual translation tables. */ | 16 | /* Minimum physical address used for virtual translation tables. */ |
17 | #define KVM_GUEST_PAGE_TABLE_MIN_PADDR 0x180000 | 17 | #define KVM_GUEST_PAGE_TABLE_MIN_PADDR 0x180000 |
@@ -231,7 +231,7 @@ void virt_pgd_alloc(struct kvm_vm *vm, uint32_t pgd_memslot) | |||
231 | { | 231 | { |
232 | int rc; | 232 | int rc; |
233 | 233 | ||
234 | TEST_ASSERT(vm->mode == VM_MODE_FLAT48PG, "Attempt to use " | 234 | TEST_ASSERT(vm->mode == VM_MODE_P52V48_4K, "Attempt to use " |
235 | "unknown or unsupported guest mode, mode: 0x%x", vm->mode); | 235 | "unknown or unsupported guest mode, mode: 0x%x", vm->mode); |
236 | 236 | ||
237 | /* If needed, create page map l4 table. */ | 237 | /* If needed, create page map l4 table. */ |
@@ -264,7 +264,7 @@ void virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, | |||
264 | uint16_t index[4]; | 264 | uint16_t index[4]; |
265 | struct pageMapL4Entry *pml4e; | 265 | struct pageMapL4Entry *pml4e; |
266 | 266 | ||
267 | TEST_ASSERT(vm->mode == VM_MODE_FLAT48PG, "Attempt to use " | 267 | TEST_ASSERT(vm->mode == VM_MODE_P52V48_4K, "Attempt to use " |
268 | "unknown or unsupported guest mode, mode: 0x%x", vm->mode); | 268 | "unknown or unsupported guest mode, mode: 0x%x", vm->mode); |
269 | 269 | ||
270 | TEST_ASSERT((vaddr % vm->page_size) == 0, | 270 | TEST_ASSERT((vaddr % vm->page_size) == 0, |
@@ -551,7 +551,7 @@ vm_paddr_t addr_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva) | |||
551 | struct pageTableEntry *pte; | 551 | struct pageTableEntry *pte; |
552 | void *hva; | 552 | void *hva; |
553 | 553 | ||
554 | TEST_ASSERT(vm->mode == VM_MODE_FLAT48PG, "Attempt to use " | 554 | TEST_ASSERT(vm->mode == VM_MODE_P52V48_4K, "Attempt to use " |
555 | "unknown or unsupported guest mode, mode: 0x%x", vm->mode); | 555 | "unknown or unsupported guest mode, mode: 0x%x", vm->mode); |
556 | 556 | ||
557 | index[0] = (gva >> 12) & 0x1ffu; | 557 | index[0] = (gva >> 12) & 0x1ffu; |
@@ -624,9 +624,9 @@ void vcpu_setup(struct kvm_vm *vm, int vcpuid, int pgd_memslot, int gdt_memslot) | |||
624 | kvm_setup_gdt(vm, &sregs.gdt, gdt_memslot, pgd_memslot); | 624 | kvm_setup_gdt(vm, &sregs.gdt, gdt_memslot, pgd_memslot); |
625 | 625 | ||
626 | switch (vm->mode) { | 626 | switch (vm->mode) { |
627 | case VM_MODE_FLAT48PG: | 627 | case VM_MODE_P52V48_4K: |
628 | sregs.cr0 = X86_CR0_PE | X86_CR0_NE | X86_CR0_PG; | 628 | sregs.cr0 = X86_CR0_PE | X86_CR0_NE | X86_CR0_PG; |
629 | sregs.cr4 |= X86_CR4_PAE; | 629 | sregs.cr4 |= X86_CR4_PAE | X86_CR4_OSFXSR; |
630 | sregs.efer |= (EFER_LME | EFER_LMA | EFER_NX); | 630 | sregs.efer |= (EFER_LME | EFER_LMA | EFER_NX); |
631 | 631 | ||
632 | kvm_seg_set_unusable(&sregs.ldt); | 632 | kvm_seg_set_unusable(&sregs.ldt); |
@@ -672,6 +672,102 @@ void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code) | |||
672 | vcpu_set_mp_state(vm, vcpuid, &mp_state); | 672 | vcpu_set_mp_state(vm, vcpuid, &mp_state); |
673 | } | 673 | } |
674 | 674 | ||
675 | /* Allocate an instance of struct kvm_cpuid2 | ||
676 | * | ||
677 | * Input Args: None | ||
678 | * | ||
679 | * Output Args: None | ||
680 | * | ||
681 | * Return: A pointer to the allocated struct. The caller is responsible | ||
682 | * for freeing this struct. | ||
683 | * | ||
684 | * Since kvm_cpuid2 uses a 0-length array to allow a the size of the | ||
685 | * array to be decided at allocation time, allocation is slightly | ||
686 | * complicated. This function uses a reasonable default length for | ||
687 | * the array and performs the appropriate allocation. | ||
688 | */ | ||
689 | static struct kvm_cpuid2 *allocate_kvm_cpuid2(void) | ||
690 | { | ||
691 | struct kvm_cpuid2 *cpuid; | ||
692 | int nent = 100; | ||
693 | size_t size; | ||
694 | |||
695 | size = sizeof(*cpuid); | ||
696 | size += nent * sizeof(struct kvm_cpuid_entry2); | ||
697 | cpuid = malloc(size); | ||
698 | if (!cpuid) { | ||
699 | perror("malloc"); | ||
700 | abort(); | ||
701 | } | ||
702 | |||
703 | cpuid->nent = nent; | ||
704 | |||
705 | return cpuid; | ||
706 | } | ||
707 | |||
708 | /* KVM Supported CPUID Get | ||
709 | * | ||
710 | * Input Args: None | ||
711 | * | ||
712 | * Output Args: | ||
713 | * | ||
714 | * Return: The supported KVM CPUID | ||
715 | * | ||
716 | * Get the guest CPUID supported by KVM. | ||
717 | */ | ||
718 | struct kvm_cpuid2 *kvm_get_supported_cpuid(void) | ||
719 | { | ||
720 | static struct kvm_cpuid2 *cpuid; | ||
721 | int ret; | ||
722 | int kvm_fd; | ||
723 | |||
724 | if (cpuid) | ||
725 | return cpuid; | ||
726 | |||
727 | cpuid = allocate_kvm_cpuid2(); | ||
728 | kvm_fd = open(KVM_DEV_PATH, O_RDONLY); | ||
729 | if (kvm_fd < 0) | ||
730 | exit(KSFT_SKIP); | ||
731 | |||
732 | ret = ioctl(kvm_fd, KVM_GET_SUPPORTED_CPUID, cpuid); | ||
733 | TEST_ASSERT(ret == 0, "KVM_GET_SUPPORTED_CPUID failed %d %d\n", | ||
734 | ret, errno); | ||
735 | |||
736 | close(kvm_fd); | ||
737 | return cpuid; | ||
738 | } | ||
739 | |||
740 | /* Locate a cpuid entry. | ||
741 | * | ||
742 | * Input Args: | ||
743 | * cpuid: The cpuid. | ||
744 | * function: The function of the cpuid entry to find. | ||
745 | * | ||
746 | * Output Args: None | ||
747 | * | ||
748 | * Return: A pointer to the cpuid entry. Never returns NULL. | ||
749 | */ | ||
750 | struct kvm_cpuid_entry2 * | ||
751 | kvm_get_supported_cpuid_index(uint32_t function, uint32_t index) | ||
752 | { | ||
753 | struct kvm_cpuid2 *cpuid; | ||
754 | struct kvm_cpuid_entry2 *entry = NULL; | ||
755 | int i; | ||
756 | |||
757 | cpuid = kvm_get_supported_cpuid(); | ||
758 | for (i = 0; i < cpuid->nent; i++) { | ||
759 | if (cpuid->entries[i].function == function && | ||
760 | cpuid->entries[i].index == index) { | ||
761 | entry = &cpuid->entries[i]; | ||
762 | break; | ||
763 | } | ||
764 | } | ||
765 | |||
766 | TEST_ASSERT(entry, "Guest CPUID entry not found: (EAX=%x, ECX=%x).", | ||
767 | function, index); | ||
768 | return entry; | ||
769 | } | ||
770 | |||
675 | /* VM VCPU CPUID Set | 771 | /* VM VCPU CPUID Set |
676 | * | 772 | * |
677 | * Input Args: | 773 | * Input Args: |
@@ -698,6 +794,7 @@ void vcpu_set_cpuid(struct kvm_vm *vm, | |||
698 | rc, errno); | 794 | rc, errno); |
699 | 795 | ||
700 | } | 796 | } |
797 | |||
701 | /* Create a VM with reasonable defaults | 798 | /* Create a VM with reasonable defaults |
702 | * | 799 | * |
703 | * Input Args: | 800 | * Input Args: |
@@ -726,7 +823,7 @@ struct kvm_vm *vm_create_default(uint32_t vcpuid, uint64_t extra_mem_pages, | |||
726 | uint64_t extra_pg_pages = extra_mem_pages / 512 * 2; | 823 | uint64_t extra_pg_pages = extra_mem_pages / 512 * 2; |
727 | 824 | ||
728 | /* Create VM */ | 825 | /* Create VM */ |
729 | vm = vm_create(VM_MODE_FLAT48PG, | 826 | vm = vm_create(VM_MODE_P52V48_4K, |
730 | DEFAULT_GUEST_PHY_PAGES + extra_pg_pages, | 827 | DEFAULT_GUEST_PHY_PAGES + extra_pg_pages, |
731 | O_RDWR); | 828 | O_RDWR); |
732 | 829 | ||
@@ -742,6 +839,154 @@ struct kvm_vm *vm_create_default(uint32_t vcpuid, uint64_t extra_mem_pages, | |||
742 | return vm; | 839 | return vm; |
743 | } | 840 | } |
744 | 841 | ||
842 | /* VCPU Get MSR | ||
843 | * | ||
844 | * Input Args: | ||
845 | * vm - Virtual Machine | ||
846 | * vcpuid - VCPU ID | ||
847 | * msr_index - Index of MSR | ||
848 | * | ||
849 | * Output Args: None | ||
850 | * | ||
851 | * Return: On success, value of the MSR. On failure a TEST_ASSERT is produced. | ||
852 | * | ||
853 | * Get value of MSR for VCPU. | ||
854 | */ | ||
855 | uint64_t vcpu_get_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index) | ||
856 | { | ||
857 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | ||
858 | struct { | ||
859 | struct kvm_msrs header; | ||
860 | struct kvm_msr_entry entry; | ||
861 | } buffer = {}; | ||
862 | int r; | ||
863 | |||
864 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | ||
865 | buffer.header.nmsrs = 1; | ||
866 | buffer.entry.index = msr_index; | ||
867 | r = ioctl(vcpu->fd, KVM_GET_MSRS, &buffer.header); | ||
868 | TEST_ASSERT(r == 1, "KVM_GET_MSRS IOCTL failed,\n" | ||
869 | " rc: %i errno: %i", r, errno); | ||
870 | |||
871 | return buffer.entry.data; | ||
872 | } | ||
873 | |||
874 | /* VCPU Set MSR | ||
875 | * | ||
876 | * Input Args: | ||
877 | * vm - Virtual Machine | ||
878 | * vcpuid - VCPU ID | ||
879 | * msr_index - Index of MSR | ||
880 | * msr_value - New value of MSR | ||
881 | * | ||
882 | * Output Args: None | ||
883 | * | ||
884 | * Return: On success, nothing. On failure a TEST_ASSERT is produced. | ||
885 | * | ||
886 | * Set value of MSR for VCPU. | ||
887 | */ | ||
888 | void vcpu_set_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index, | ||
889 | uint64_t msr_value) | ||
890 | { | ||
891 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | ||
892 | struct { | ||
893 | struct kvm_msrs header; | ||
894 | struct kvm_msr_entry entry; | ||
895 | } buffer = {}; | ||
896 | int r; | ||
897 | |||
898 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | ||
899 | memset(&buffer, 0, sizeof(buffer)); | ||
900 | buffer.header.nmsrs = 1; | ||
901 | buffer.entry.index = msr_index; | ||
902 | buffer.entry.data = msr_value; | ||
903 | r = ioctl(vcpu->fd, KVM_SET_MSRS, &buffer.header); | ||
904 | TEST_ASSERT(r == 1, "KVM_SET_MSRS IOCTL failed,\n" | ||
905 | " rc: %i errno: %i", r, errno); | ||
906 | } | ||
907 | |||
908 | /* VM VCPU Args Set | ||
909 | * | ||
910 | * Input Args: | ||
911 | * vm - Virtual Machine | ||
912 | * vcpuid - VCPU ID | ||
913 | * num - number of arguments | ||
914 | * ... - arguments, each of type uint64_t | ||
915 | * | ||
916 | * Output Args: None | ||
917 | * | ||
918 | * Return: None | ||
919 | * | ||
920 | * Sets the first num function input arguments to the values | ||
921 | * given as variable args. Each of the variable args is expected to | ||
922 | * be of type uint64_t. | ||
923 | */ | ||
924 | void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...) | ||
925 | { | ||
926 | va_list ap; | ||
927 | struct kvm_regs regs; | ||
928 | |||
929 | TEST_ASSERT(num >= 1 && num <= 6, "Unsupported number of args,\n" | ||
930 | " num: %u\n", | ||
931 | num); | ||
932 | |||
933 | va_start(ap, num); | ||
934 | vcpu_regs_get(vm, vcpuid, ®s); | ||
935 | |||
936 | if (num >= 1) | ||
937 | regs.rdi = va_arg(ap, uint64_t); | ||
938 | |||
939 | if (num >= 2) | ||
940 | regs.rsi = va_arg(ap, uint64_t); | ||
941 | |||
942 | if (num >= 3) | ||
943 | regs.rdx = va_arg(ap, uint64_t); | ||
944 | |||
945 | if (num >= 4) | ||
946 | regs.rcx = va_arg(ap, uint64_t); | ||
947 | |||
948 | if (num >= 5) | ||
949 | regs.r8 = va_arg(ap, uint64_t); | ||
950 | |||
951 | if (num >= 6) | ||
952 | regs.r9 = va_arg(ap, uint64_t); | ||
953 | |||
954 | vcpu_regs_set(vm, vcpuid, ®s); | ||
955 | va_end(ap); | ||
956 | } | ||
957 | |||
958 | /* | ||
959 | * VM VCPU Dump | ||
960 | * | ||
961 | * Input Args: | ||
962 | * vm - Virtual Machine | ||
963 | * vcpuid - VCPU ID | ||
964 | * indent - Left margin indent amount | ||
965 | * | ||
966 | * Output Args: | ||
967 | * stream - Output FILE stream | ||
968 | * | ||
969 | * Return: None | ||
970 | * | ||
971 | * Dumps the current state of the VCPU specified by vcpuid, within the VM | ||
972 | * given by vm, to the FILE stream given by stream. | ||
973 | */ | ||
974 | void vcpu_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, uint8_t indent) | ||
975 | { | ||
976 | struct kvm_regs regs; | ||
977 | struct kvm_sregs sregs; | ||
978 | |||
979 | fprintf(stream, "%*scpuid: %u\n", indent, "", vcpuid); | ||
980 | |||
981 | fprintf(stream, "%*sregs:\n", indent + 2, ""); | ||
982 | vcpu_regs_get(vm, vcpuid, ®s); | ||
983 | regs_dump(stream, ®s, indent + 4); | ||
984 | |||
985 | fprintf(stream, "%*ssregs:\n", indent + 2, ""); | ||
986 | vcpu_sregs_get(vm, vcpuid, &sregs); | ||
987 | sregs_dump(stream, &sregs, indent + 4); | ||
988 | } | ||
989 | |||
745 | struct kvm_x86_state { | 990 | struct kvm_x86_state { |
746 | struct kvm_vcpu_events events; | 991 | struct kvm_vcpu_events events; |
747 | struct kvm_mp_state mp_state; | 992 | struct kvm_mp_state mp_state; |
diff --git a/tools/testing/selftests/kvm/lib/vmx.c b/tools/testing/selftests/kvm/lib/x86_64/vmx.c index b987c3c970eb..771ba6bf751c 100644 --- a/tools/testing/selftests/kvm/lib/vmx.c +++ b/tools/testing/selftests/kvm/lib/x86_64/vmx.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * tools/testing/selftests/kvm/lib/x86.c | 2 | * tools/testing/selftests/kvm/lib/x86_64/vmx.c |
3 | * | 3 | * |
4 | * Copyright (C) 2018, Google LLC. | 4 | * Copyright (C) 2018, Google LLC. |
5 | * | 5 | * |
@@ -10,9 +10,11 @@ | |||
10 | 10 | ||
11 | #include "test_util.h" | 11 | #include "test_util.h" |
12 | #include "kvm_util.h" | 12 | #include "kvm_util.h" |
13 | #include "x86.h" | 13 | #include "processor.h" |
14 | #include "vmx.h" | 14 | #include "vmx.h" |
15 | 15 | ||
16 | bool enable_evmcs; | ||
17 | |||
16 | /* Allocate memory regions for nested VMX tests. | 18 | /* Allocate memory regions for nested VMX tests. |
17 | * | 19 | * |
18 | * Input Args: | 20 | * Input Args: |
@@ -62,6 +64,20 @@ vcpu_alloc_vmx(struct kvm_vm *vm, vm_vaddr_t *p_vmx_gva) | |||
62 | vmx->vmwrite_gpa = addr_gva2gpa(vm, (uintptr_t)vmx->vmwrite); | 64 | vmx->vmwrite_gpa = addr_gva2gpa(vm, (uintptr_t)vmx->vmwrite); |
63 | memset(vmx->vmwrite_hva, 0, getpagesize()); | 65 | memset(vmx->vmwrite_hva, 0, getpagesize()); |
64 | 66 | ||
67 | /* Setup of a region of guest memory for the VP Assist page. */ | ||
68 | vmx->vp_assist = (void *)vm_vaddr_alloc(vm, getpagesize(), | ||
69 | 0x10000, 0, 0); | ||
70 | vmx->vp_assist_hva = addr_gva2hva(vm, (uintptr_t)vmx->vp_assist); | ||
71 | vmx->vp_assist_gpa = addr_gva2gpa(vm, (uintptr_t)vmx->vp_assist); | ||
72 | |||
73 | /* Setup of a region of guest memory for the enlightened VMCS. */ | ||
74 | vmx->enlightened_vmcs = (void *)vm_vaddr_alloc(vm, getpagesize(), | ||
75 | 0x10000, 0, 0); | ||
76 | vmx->enlightened_vmcs_hva = | ||
77 | addr_gva2hva(vm, (uintptr_t)vmx->enlightened_vmcs); | ||
78 | vmx->enlightened_vmcs_gpa = | ||
79 | addr_gva2gpa(vm, (uintptr_t)vmx->enlightened_vmcs); | ||
80 | |||
65 | *p_vmx_gva = vmx_gva; | 81 | *p_vmx_gva = vmx_gva; |
66 | return vmx; | 82 | return vmx; |
67 | } | 83 | } |
@@ -107,18 +123,31 @@ bool prepare_for_vmx_operation(struct vmx_pages *vmx) | |||
107 | if (vmxon(vmx->vmxon_gpa)) | 123 | if (vmxon(vmx->vmxon_gpa)) |
108 | return false; | 124 | return false; |
109 | 125 | ||
110 | /* Load a VMCS. */ | 126 | return true; |
111 | *(uint32_t *)(vmx->vmcs) = vmcs_revision(); | 127 | } |
112 | if (vmclear(vmx->vmcs_gpa)) | ||
113 | return false; | ||
114 | |||
115 | if (vmptrld(vmx->vmcs_gpa)) | ||
116 | return false; | ||
117 | 128 | ||
118 | /* Setup shadow VMCS, do not load it yet. */ | 129 | bool load_vmcs(struct vmx_pages *vmx) |
119 | *(uint32_t *)(vmx->shadow_vmcs) = vmcs_revision() | 0x80000000ul; | 130 | { |
120 | if (vmclear(vmx->shadow_vmcs_gpa)) | 131 | if (!enable_evmcs) { |
121 | return false; | 132 | /* Load a VMCS. */ |
133 | *(uint32_t *)(vmx->vmcs) = vmcs_revision(); | ||
134 | if (vmclear(vmx->vmcs_gpa)) | ||
135 | return false; | ||
136 | |||
137 | if (vmptrld(vmx->vmcs_gpa)) | ||
138 | return false; | ||
139 | |||
140 | /* Setup shadow VMCS, do not load it yet. */ | ||
141 | *(uint32_t *)(vmx->shadow_vmcs) = | ||
142 | vmcs_revision() | 0x80000000ul; | ||
143 | if (vmclear(vmx->shadow_vmcs_gpa)) | ||
144 | return false; | ||
145 | } else { | ||
146 | if (evmcs_vmptrld(vmx->enlightened_vmcs_gpa, | ||
147 | vmx->enlightened_vmcs)) | ||
148 | return false; | ||
149 | current_evmcs->revision_id = vmcs_revision(); | ||
150 | } | ||
122 | 151 | ||
123 | return true; | 152 | return true; |
124 | } | 153 | } |
diff --git a/tools/testing/selftests/kvm/cr4_cpuid_sync_test.c b/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c index 11ec358bf969..d503a51fad30 100644 --- a/tools/testing/selftests/kvm/cr4_cpuid_sync_test.c +++ b/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c | |||
@@ -17,7 +17,7 @@ | |||
17 | #include "test_util.h" | 17 | #include "test_util.h" |
18 | 18 | ||
19 | #include "kvm_util.h" | 19 | #include "kvm_util.h" |
20 | #include "x86.h" | 20 | #include "processor.h" |
21 | 21 | ||
22 | #define X86_FEATURE_XSAVE (1<<26) | 22 | #define X86_FEATURE_XSAVE (1<<26) |
23 | #define X86_FEATURE_OSXSAVE (1<<27) | 23 | #define X86_FEATURE_OSXSAVE (1<<27) |
@@ -67,6 +67,7 @@ int main(int argc, char *argv[]) | |||
67 | struct kvm_vm *vm; | 67 | struct kvm_vm *vm; |
68 | struct kvm_sregs sregs; | 68 | struct kvm_sregs sregs; |
69 | struct kvm_cpuid_entry2 *entry; | 69 | struct kvm_cpuid_entry2 *entry; |
70 | struct ucall uc; | ||
70 | int rc; | 71 | int rc; |
71 | 72 | ||
72 | entry = kvm_get_supported_cpuid_entry(1); | 73 | entry = kvm_get_supported_cpuid_entry(1); |
@@ -87,21 +88,20 @@ int main(int argc, char *argv[]) | |||
87 | rc = _vcpu_run(vm, VCPU_ID); | 88 | rc = _vcpu_run(vm, VCPU_ID); |
88 | 89 | ||
89 | if (run->exit_reason == KVM_EXIT_IO) { | 90 | if (run->exit_reason == KVM_EXIT_IO) { |
90 | switch (run->io.port) { | 91 | switch (get_ucall(vm, VCPU_ID, &uc)) { |
91 | case GUEST_PORT_SYNC: | 92 | case UCALL_SYNC: |
92 | /* emulate hypervisor clearing CR4.OSXSAVE */ | 93 | /* emulate hypervisor clearing CR4.OSXSAVE */ |
93 | vcpu_sregs_get(vm, VCPU_ID, &sregs); | 94 | vcpu_sregs_get(vm, VCPU_ID, &sregs); |
94 | sregs.cr4 &= ~X86_CR4_OSXSAVE; | 95 | sregs.cr4 &= ~X86_CR4_OSXSAVE; |
95 | vcpu_sregs_set(vm, VCPU_ID, &sregs); | 96 | vcpu_sregs_set(vm, VCPU_ID, &sregs); |
96 | break; | 97 | break; |
97 | case GUEST_PORT_ABORT: | 98 | case UCALL_ABORT: |
98 | TEST_ASSERT(false, "Guest CR4 bit (OSXSAVE) unsynchronized with CPUID bit."); | 99 | TEST_ASSERT(false, "Guest CR4 bit (OSXSAVE) unsynchronized with CPUID bit."); |
99 | break; | 100 | break; |
100 | case GUEST_PORT_DONE: | 101 | case UCALL_DONE: |
101 | goto done; | 102 | goto done; |
102 | default: | 103 | default: |
103 | TEST_ASSERT(false, "Unknown port 0x%x.", | 104 | TEST_ASSERT(false, "Unknown ucall 0x%x.", uc.cmd); |
104 | run->io.port); | ||
105 | } | 105 | } |
106 | } | 106 | } |
107 | } | 107 | } |
diff --git a/tools/testing/selftests/kvm/x86_64/evmcs_test.c b/tools/testing/selftests/kvm/x86_64/evmcs_test.c new file mode 100644 index 000000000000..92c2cfd1b182 --- /dev/null +++ b/tools/testing/selftests/kvm/x86_64/evmcs_test.c | |||
@@ -0,0 +1,160 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * Copyright (C) 2018, Red Hat, Inc. | ||
4 | * | ||
5 | * Tests for Enlightened VMCS, including nested guest state. | ||
6 | */ | ||
7 | #define _GNU_SOURCE /* for program_invocation_short_name */ | ||
8 | #include <fcntl.h> | ||
9 | #include <stdio.h> | ||
10 | #include <stdlib.h> | ||
11 | #include <string.h> | ||
12 | #include <sys/ioctl.h> | ||
13 | |||
14 | #include "test_util.h" | ||
15 | |||
16 | #include "kvm_util.h" | ||
17 | |||
18 | #include "vmx.h" | ||
19 | |||
20 | #define VCPU_ID 5 | ||
21 | |||
22 | static bool have_nested_state; | ||
23 | |||
24 | void l2_guest_code(void) | ||
25 | { | ||
26 | GUEST_SYNC(6); | ||
27 | |||
28 | GUEST_SYNC(7); | ||
29 | |||
30 | /* Done, exit to L1 and never come back. */ | ||
31 | vmcall(); | ||
32 | } | ||
33 | |||
34 | void l1_guest_code(struct vmx_pages *vmx_pages) | ||
35 | { | ||
36 | #define L2_GUEST_STACK_SIZE 64 | ||
37 | unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE]; | ||
38 | |||
39 | enable_vp_assist(vmx_pages->vp_assist_gpa, vmx_pages->vp_assist); | ||
40 | |||
41 | GUEST_ASSERT(vmx_pages->vmcs_gpa); | ||
42 | GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); | ||
43 | GUEST_SYNC(3); | ||
44 | GUEST_ASSERT(load_vmcs(vmx_pages)); | ||
45 | GUEST_ASSERT(vmptrstz() == vmx_pages->enlightened_vmcs_gpa); | ||
46 | |||
47 | GUEST_SYNC(4); | ||
48 | GUEST_ASSERT(vmptrstz() == vmx_pages->enlightened_vmcs_gpa); | ||
49 | |||
50 | prepare_vmcs(vmx_pages, l2_guest_code, | ||
51 | &l2_guest_stack[L2_GUEST_STACK_SIZE]); | ||
52 | |||
53 | GUEST_SYNC(5); | ||
54 | GUEST_ASSERT(vmptrstz() == vmx_pages->enlightened_vmcs_gpa); | ||
55 | GUEST_ASSERT(!vmlaunch()); | ||
56 | GUEST_ASSERT(vmptrstz() == vmx_pages->enlightened_vmcs_gpa); | ||
57 | GUEST_SYNC(8); | ||
58 | GUEST_ASSERT(!vmresume()); | ||
59 | GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL); | ||
60 | GUEST_SYNC(9); | ||
61 | } | ||
62 | |||
63 | void guest_code(struct vmx_pages *vmx_pages) | ||
64 | { | ||
65 | GUEST_SYNC(1); | ||
66 | GUEST_SYNC(2); | ||
67 | |||
68 | if (vmx_pages) | ||
69 | l1_guest_code(vmx_pages); | ||
70 | |||
71 | GUEST_DONE(); | ||
72 | } | ||
73 | |||
74 | int main(int argc, char *argv[]) | ||
75 | { | ||
76 | struct vmx_pages *vmx_pages = NULL; | ||
77 | vm_vaddr_t vmx_pages_gva = 0; | ||
78 | |||
79 | struct kvm_regs regs1, regs2; | ||
80 | struct kvm_vm *vm; | ||
81 | struct kvm_run *run; | ||
82 | struct kvm_x86_state *state; | ||
83 | struct ucall uc; | ||
84 | int stage; | ||
85 | uint16_t evmcs_ver; | ||
86 | struct kvm_enable_cap enable_evmcs_cap = { | ||
87 | .cap = KVM_CAP_HYPERV_ENLIGHTENED_VMCS, | ||
88 | .args[0] = (unsigned long)&evmcs_ver | ||
89 | }; | ||
90 | |||
91 | struct kvm_cpuid_entry2 *entry = kvm_get_supported_cpuid_entry(1); | ||
92 | |||
93 | /* Create VM */ | ||
94 | vm = vm_create_default(VCPU_ID, 0, guest_code); | ||
95 | |||
96 | vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); | ||
97 | |||
98 | if (!kvm_check_cap(KVM_CAP_NESTED_STATE) || | ||
99 | !kvm_check_cap(KVM_CAP_HYPERV_ENLIGHTENED_VMCS)) { | ||
100 | printf("capabilities not available, skipping test\n"); | ||
101 | exit(KSFT_SKIP); | ||
102 | } | ||
103 | |||
104 | vcpu_ioctl(vm, VCPU_ID, KVM_ENABLE_CAP, &enable_evmcs_cap); | ||
105 | |||
106 | run = vcpu_state(vm, VCPU_ID); | ||
107 | |||
108 | vcpu_regs_get(vm, VCPU_ID, ®s1); | ||
109 | |||
110 | vmx_pages = vcpu_alloc_vmx(vm, &vmx_pages_gva); | ||
111 | vcpu_args_set(vm, VCPU_ID, 1, vmx_pages_gva); | ||
112 | |||
113 | for (stage = 1;; stage++) { | ||
114 | _vcpu_run(vm, VCPU_ID); | ||
115 | TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, | ||
116 | "Unexpected exit reason: %u (%s),\n", | ||
117 | run->exit_reason, | ||
118 | exit_reason_str(run->exit_reason)); | ||
119 | |||
120 | memset(®s1, 0, sizeof(regs1)); | ||
121 | vcpu_regs_get(vm, VCPU_ID, ®s1); | ||
122 | switch (get_ucall(vm, VCPU_ID, &uc)) { | ||
123 | case UCALL_ABORT: | ||
124 | TEST_ASSERT(false, "%s at %s:%d", (const char *)uc.args[0], | ||
125 | __FILE__, uc.args[1]); | ||
126 | /* NOT REACHED */ | ||
127 | case UCALL_SYNC: | ||
128 | break; | ||
129 | case UCALL_DONE: | ||
130 | goto done; | ||
131 | default: | ||
132 | TEST_ASSERT(false, "Unknown ucall 0x%x.", uc.cmd); | ||
133 | } | ||
134 | |||
135 | /* UCALL_SYNC is handled here. */ | ||
136 | TEST_ASSERT(!strcmp((const char *)uc.args[0], "hello") && | ||
137 | uc.args[1] == stage, "Unexpected register values vmexit #%lx, got %lx", | ||
138 | stage, (ulong)uc.args[1]); | ||
139 | |||
140 | state = vcpu_save_state(vm, VCPU_ID); | ||
141 | kvm_vm_release(vm); | ||
142 | |||
143 | /* Restore state in a new VM. */ | ||
144 | kvm_vm_restart(vm, O_RDWR); | ||
145 | vm_vcpu_add(vm, VCPU_ID, 0, 0); | ||
146 | vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); | ||
147 | vcpu_load_state(vm, VCPU_ID, state); | ||
148 | run = vcpu_state(vm, VCPU_ID); | ||
149 | free(state); | ||
150 | |||
151 | memset(®s2, 0, sizeof(regs2)); | ||
152 | vcpu_regs_get(vm, VCPU_ID, ®s2); | ||
153 | TEST_ASSERT(!memcmp(®s1, ®s2, sizeof(regs2)), | ||
154 | "Unexpected register values after vcpu_load_state; rdi: %lx rsi: %lx", | ||
155 | (ulong) regs2.rdi, (ulong) regs2.rsi); | ||
156 | } | ||
157 | |||
158 | done: | ||
159 | kvm_vm_free(vm); | ||
160 | } | ||
diff --git a/tools/testing/selftests/kvm/platform_info_test.c b/tools/testing/selftests/kvm/x86_64/platform_info_test.c index 3764e7121265..eb3e7a838cb4 100644 --- a/tools/testing/selftests/kvm/platform_info_test.c +++ b/tools/testing/selftests/kvm/x86_64/platform_info_test.c | |||
@@ -19,7 +19,7 @@ | |||
19 | 19 | ||
20 | #include "test_util.h" | 20 | #include "test_util.h" |
21 | #include "kvm_util.h" | 21 | #include "kvm_util.h" |
22 | #include "x86.h" | 22 | #include "processor.h" |
23 | 23 | ||
24 | #define VCPU_ID 0 | 24 | #define VCPU_ID 0 |
25 | #define MSR_PLATFORM_INFO_MAX_TURBO_RATIO 0xff00 | 25 | #define MSR_PLATFORM_INFO_MAX_TURBO_RATIO 0xff00 |
@@ -48,7 +48,7 @@ static void set_msr_platform_info_enabled(struct kvm_vm *vm, bool enable) | |||
48 | static void test_msr_platform_info_enabled(struct kvm_vm *vm) | 48 | static void test_msr_platform_info_enabled(struct kvm_vm *vm) |
49 | { | 49 | { |
50 | struct kvm_run *run = vcpu_state(vm, VCPU_ID); | 50 | struct kvm_run *run = vcpu_state(vm, VCPU_ID); |
51 | struct guest_args args; | 51 | struct ucall uc; |
52 | 52 | ||
53 | set_msr_platform_info_enabled(vm, true); | 53 | set_msr_platform_info_enabled(vm, true); |
54 | vcpu_run(vm, VCPU_ID); | 54 | vcpu_run(vm, VCPU_ID); |
@@ -56,11 +56,11 @@ static void test_msr_platform_info_enabled(struct kvm_vm *vm) | |||
56 | "Exit_reason other than KVM_EXIT_IO: %u (%s),\n", | 56 | "Exit_reason other than KVM_EXIT_IO: %u (%s),\n", |
57 | run->exit_reason, | 57 | run->exit_reason, |
58 | exit_reason_str(run->exit_reason)); | 58 | exit_reason_str(run->exit_reason)); |
59 | guest_args_read(vm, VCPU_ID, &args); | 59 | get_ucall(vm, VCPU_ID, &uc); |
60 | TEST_ASSERT(args.port == GUEST_PORT_SYNC, | 60 | TEST_ASSERT(uc.cmd == UCALL_SYNC, |
61 | "Received IO from port other than PORT_HOST_SYNC: %u\n", | 61 | "Received ucall other than UCALL_SYNC: %u\n", |
62 | run->io.port); | 62 | ucall); |
63 | TEST_ASSERT((args.arg1 & MSR_PLATFORM_INFO_MAX_TURBO_RATIO) == | 63 | TEST_ASSERT((uc.args[1] & MSR_PLATFORM_INFO_MAX_TURBO_RATIO) == |
64 | MSR_PLATFORM_INFO_MAX_TURBO_RATIO, | 64 | MSR_PLATFORM_INFO_MAX_TURBO_RATIO, |
65 | "Expected MSR_PLATFORM_INFO to have max turbo ratio mask: %i.", | 65 | "Expected MSR_PLATFORM_INFO to have max turbo ratio mask: %i.", |
66 | MSR_PLATFORM_INFO_MAX_TURBO_RATIO); | 66 | MSR_PLATFORM_INFO_MAX_TURBO_RATIO); |
diff --git a/tools/testing/selftests/kvm/set_sregs_test.c b/tools/testing/selftests/kvm/x86_64/set_sregs_test.c index 881419d5746e..35640e8e95bc 100644 --- a/tools/testing/selftests/kvm/set_sregs_test.c +++ b/tools/testing/selftests/kvm/x86_64/set_sregs_test.c | |||
@@ -22,7 +22,7 @@ | |||
22 | #include "test_util.h" | 22 | #include "test_util.h" |
23 | 23 | ||
24 | #include "kvm_util.h" | 24 | #include "kvm_util.h" |
25 | #include "x86.h" | 25 | #include "processor.h" |
26 | 26 | ||
27 | #define VCPU_ID 5 | 27 | #define VCPU_ID 5 |
28 | 28 | ||
diff --git a/tools/testing/selftests/kvm/state_test.c b/tools/testing/selftests/kvm/x86_64/state_test.c index 900e3e9dfb9f..03da41f0f736 100644 --- a/tools/testing/selftests/kvm/state_test.c +++ b/tools/testing/selftests/kvm/x86_64/state_test.c | |||
@@ -17,7 +17,7 @@ | |||
17 | #include "test_util.h" | 17 | #include "test_util.h" |
18 | 18 | ||
19 | #include "kvm_util.h" | 19 | #include "kvm_util.h" |
20 | #include "x86.h" | 20 | #include "processor.h" |
21 | #include "vmx.h" | 21 | #include "vmx.h" |
22 | 22 | ||
23 | #define VCPU_ID 5 | 23 | #define VCPU_ID 5 |
@@ -26,20 +26,20 @@ static bool have_nested_state; | |||
26 | 26 | ||
27 | void l2_guest_code(void) | 27 | void l2_guest_code(void) |
28 | { | 28 | { |
29 | GUEST_SYNC(5); | 29 | GUEST_SYNC(6); |
30 | 30 | ||
31 | /* Exit to L1 */ | 31 | /* Exit to L1 */ |
32 | vmcall(); | 32 | vmcall(); |
33 | 33 | ||
34 | /* L1 has now set up a shadow VMCS for us. */ | 34 | /* L1 has now set up a shadow VMCS for us. */ |
35 | GUEST_ASSERT(vmreadz(GUEST_RIP) == 0xc0ffee); | 35 | GUEST_ASSERT(vmreadz(GUEST_RIP) == 0xc0ffee); |
36 | GUEST_SYNC(9); | 36 | GUEST_SYNC(10); |
37 | GUEST_ASSERT(vmreadz(GUEST_RIP) == 0xc0ffee); | 37 | GUEST_ASSERT(vmreadz(GUEST_RIP) == 0xc0ffee); |
38 | GUEST_ASSERT(!vmwrite(GUEST_RIP, 0xc0fffee)); | 38 | GUEST_ASSERT(!vmwrite(GUEST_RIP, 0xc0fffee)); |
39 | GUEST_SYNC(10); | 39 | GUEST_SYNC(11); |
40 | GUEST_ASSERT(vmreadz(GUEST_RIP) == 0xc0fffee); | 40 | GUEST_ASSERT(vmreadz(GUEST_RIP) == 0xc0fffee); |
41 | GUEST_ASSERT(!vmwrite(GUEST_RIP, 0xc0ffffee)); | 41 | GUEST_ASSERT(!vmwrite(GUEST_RIP, 0xc0ffffee)); |
42 | GUEST_SYNC(11); | 42 | GUEST_SYNC(12); |
43 | 43 | ||
44 | /* Done, exit to L1 and never come back. */ | 44 | /* Done, exit to L1 and never come back. */ |
45 | vmcall(); | 45 | vmcall(); |
@@ -52,15 +52,17 @@ void l1_guest_code(struct vmx_pages *vmx_pages) | |||
52 | 52 | ||
53 | GUEST_ASSERT(vmx_pages->vmcs_gpa); | 53 | GUEST_ASSERT(vmx_pages->vmcs_gpa); |
54 | GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); | 54 | GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); |
55 | GUEST_SYNC(3); | ||
56 | GUEST_ASSERT(load_vmcs(vmx_pages)); | ||
55 | GUEST_ASSERT(vmptrstz() == vmx_pages->vmcs_gpa); | 57 | GUEST_ASSERT(vmptrstz() == vmx_pages->vmcs_gpa); |
56 | 58 | ||
57 | GUEST_SYNC(3); | 59 | GUEST_SYNC(4); |
58 | GUEST_ASSERT(vmptrstz() == vmx_pages->vmcs_gpa); | 60 | GUEST_ASSERT(vmptrstz() == vmx_pages->vmcs_gpa); |
59 | 61 | ||
60 | prepare_vmcs(vmx_pages, l2_guest_code, | 62 | prepare_vmcs(vmx_pages, l2_guest_code, |
61 | &l2_guest_stack[L2_GUEST_STACK_SIZE]); | 63 | &l2_guest_stack[L2_GUEST_STACK_SIZE]); |
62 | 64 | ||
63 | GUEST_SYNC(4); | 65 | GUEST_SYNC(5); |
64 | GUEST_ASSERT(vmptrstz() == vmx_pages->vmcs_gpa); | 66 | GUEST_ASSERT(vmptrstz() == vmx_pages->vmcs_gpa); |
65 | GUEST_ASSERT(!vmlaunch()); | 67 | GUEST_ASSERT(!vmlaunch()); |
66 | GUEST_ASSERT(vmptrstz() == vmx_pages->vmcs_gpa); | 68 | GUEST_ASSERT(vmptrstz() == vmx_pages->vmcs_gpa); |
@@ -72,7 +74,7 @@ void l1_guest_code(struct vmx_pages *vmx_pages) | |||
72 | GUEST_ASSERT(!vmresume()); | 74 | GUEST_ASSERT(!vmresume()); |
73 | GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL); | 75 | GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL); |
74 | 76 | ||
75 | GUEST_SYNC(6); | 77 | GUEST_SYNC(7); |
76 | GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL); | 78 | GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL); |
77 | 79 | ||
78 | GUEST_ASSERT(!vmresume()); | 80 | GUEST_ASSERT(!vmresume()); |
@@ -85,12 +87,12 @@ void l1_guest_code(struct vmx_pages *vmx_pages) | |||
85 | 87 | ||
86 | GUEST_ASSERT(!vmptrld(vmx_pages->shadow_vmcs_gpa)); | 88 | GUEST_ASSERT(!vmptrld(vmx_pages->shadow_vmcs_gpa)); |
87 | GUEST_ASSERT(vmlaunch()); | 89 | GUEST_ASSERT(vmlaunch()); |
88 | GUEST_SYNC(7); | 90 | GUEST_SYNC(8); |
89 | GUEST_ASSERT(vmlaunch()); | 91 | GUEST_ASSERT(vmlaunch()); |
90 | GUEST_ASSERT(vmresume()); | 92 | GUEST_ASSERT(vmresume()); |
91 | 93 | ||
92 | vmwrite(GUEST_RIP, 0xc0ffee); | 94 | vmwrite(GUEST_RIP, 0xc0ffee); |
93 | GUEST_SYNC(8); | 95 | GUEST_SYNC(9); |
94 | GUEST_ASSERT(vmreadz(GUEST_RIP) == 0xc0ffee); | 96 | GUEST_ASSERT(vmreadz(GUEST_RIP) == 0xc0ffee); |
95 | 97 | ||
96 | GUEST_ASSERT(!vmptrld(vmx_pages->vmcs_gpa)); | 98 | GUEST_ASSERT(!vmptrld(vmx_pages->vmcs_gpa)); |
@@ -101,7 +103,7 @@ void l1_guest_code(struct vmx_pages *vmx_pages) | |||
101 | GUEST_ASSERT(vmreadz(GUEST_RIP) == 0xc0ffffee); | 103 | GUEST_ASSERT(vmreadz(GUEST_RIP) == 0xc0ffffee); |
102 | GUEST_ASSERT(vmlaunch()); | 104 | GUEST_ASSERT(vmlaunch()); |
103 | GUEST_ASSERT(vmresume()); | 105 | GUEST_ASSERT(vmresume()); |
104 | GUEST_SYNC(12); | 106 | GUEST_SYNC(13); |
105 | GUEST_ASSERT(vmreadz(GUEST_RIP) == 0xc0ffffee); | 107 | GUEST_ASSERT(vmreadz(GUEST_RIP) == 0xc0ffffee); |
106 | GUEST_ASSERT(vmlaunch()); | 108 | GUEST_ASSERT(vmlaunch()); |
107 | GUEST_ASSERT(vmresume()); | 109 | GUEST_ASSERT(vmresume()); |
@@ -127,6 +129,7 @@ int main(int argc, char *argv[]) | |||
127 | struct kvm_vm *vm; | 129 | struct kvm_vm *vm; |
128 | struct kvm_run *run; | 130 | struct kvm_run *run; |
129 | struct kvm_x86_state *state; | 131 | struct kvm_x86_state *state; |
132 | struct ucall uc; | ||
130 | int stage; | 133 | int stage; |
131 | 134 | ||
132 | struct kvm_cpuid_entry2 *entry = kvm_get_supported_cpuid_entry(1); | 135 | struct kvm_cpuid_entry2 *entry = kvm_get_supported_cpuid_entry(1); |
@@ -155,23 +158,23 @@ int main(int argc, char *argv[]) | |||
155 | 158 | ||
156 | memset(®s1, 0, sizeof(regs1)); | 159 | memset(®s1, 0, sizeof(regs1)); |
157 | vcpu_regs_get(vm, VCPU_ID, ®s1); | 160 | vcpu_regs_get(vm, VCPU_ID, ®s1); |
158 | switch (run->io.port) { | 161 | switch (get_ucall(vm, VCPU_ID, &uc)) { |
159 | case GUEST_PORT_ABORT: | 162 | case UCALL_ABORT: |
160 | TEST_ASSERT(false, "%s at %s:%d", (const char *) regs1.rdi, | 163 | TEST_ASSERT(false, "%s at %s:%d", (const char *)uc.args[0], |
161 | __FILE__, regs1.rsi); | 164 | __FILE__, uc.args[1]); |
162 | /* NOT REACHED */ | 165 | /* NOT REACHED */ |
163 | case GUEST_PORT_SYNC: | 166 | case UCALL_SYNC: |
164 | break; | 167 | break; |
165 | case GUEST_PORT_DONE: | 168 | case UCALL_DONE: |
166 | goto done; | 169 | goto done; |
167 | default: | 170 | default: |
168 | TEST_ASSERT(false, "Unknown port 0x%x.", run->io.port); | 171 | TEST_ASSERT(false, "Unknown ucall 0x%x.", uc.cmd); |
169 | } | 172 | } |
170 | 173 | ||
171 | /* PORT_SYNC is handled here. */ | 174 | /* UCALL_SYNC is handled here. */ |
172 | TEST_ASSERT(!strcmp((const char *)regs1.rdi, "hello") && | 175 | TEST_ASSERT(!strcmp((const char *)uc.args[0], "hello") && |
173 | regs1.rsi == stage, "Unexpected register values vmexit #%lx, got %lx", | 176 | uc.args[1] == stage, "Unexpected register values vmexit #%lx, got %lx", |
174 | stage, (ulong) regs1.rsi); | 177 | stage, (ulong)uc.args[1]); |
175 | 178 | ||
176 | state = vcpu_save_state(vm, VCPU_ID); | 179 | state = vcpu_save_state(vm, VCPU_ID); |
177 | kvm_vm_release(vm); | 180 | kvm_vm_release(vm); |
diff --git a/tools/testing/selftests/kvm/sync_regs_test.c b/tools/testing/selftests/kvm/x86_64/sync_regs_test.c index 213343e5dff9..c8478ce9ea77 100644 --- a/tools/testing/selftests/kvm/sync_regs_test.c +++ b/tools/testing/selftests/kvm/x86_64/sync_regs_test.c | |||
@@ -19,7 +19,7 @@ | |||
19 | 19 | ||
20 | #include "test_util.h" | 20 | #include "test_util.h" |
21 | #include "kvm_util.h" | 21 | #include "kvm_util.h" |
22 | #include "x86.h" | 22 | #include "processor.h" |
23 | 23 | ||
24 | #define VCPU_ID 5 | 24 | #define VCPU_ID 5 |
25 | 25 | ||
diff --git a/tools/testing/selftests/kvm/vmx_tsc_adjust_test.c b/tools/testing/selftests/kvm/x86_64/vmx_tsc_adjust_test.c index 49bcc68b0235..18fa64db0d7a 100644 --- a/tools/testing/selftests/kvm/vmx_tsc_adjust_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_tsc_adjust_test.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * gtests/tests/vmx_tsc_adjust_test.c | 2 | * vmx_tsc_adjust_test |
3 | * | 3 | * |
4 | * Copyright (C) 2018, Google LLC. | 4 | * Copyright (C) 2018, Google LLC. |
5 | * | 5 | * |
@@ -22,13 +22,13 @@ | |||
22 | 22 | ||
23 | #include "test_util.h" | 23 | #include "test_util.h" |
24 | #include "kvm_util.h" | 24 | #include "kvm_util.h" |
25 | #include "x86.h" | 25 | #include "processor.h" |
26 | #include "vmx.h" | 26 | #include "vmx.h" |
27 | 27 | ||
28 | #include <string.h> | 28 | #include <string.h> |
29 | #include <sys/ioctl.h> | 29 | #include <sys/ioctl.h> |
30 | 30 | ||
31 | #include "../kselftest.h" | 31 | #include "kselftest.h" |
32 | 32 | ||
33 | #ifndef MSR_IA32_TSC_ADJUST | 33 | #ifndef MSR_IA32_TSC_ADJUST |
34 | #define MSR_IA32_TSC_ADJUST 0x3b | 34 | #define MSR_IA32_TSC_ADJUST 0x3b |
@@ -94,6 +94,7 @@ static void l1_guest_code(struct vmx_pages *vmx_pages) | |||
94 | check_ia32_tsc_adjust(-1 * TSC_ADJUST_VALUE); | 94 | check_ia32_tsc_adjust(-1 * TSC_ADJUST_VALUE); |
95 | 95 | ||
96 | GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); | 96 | GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); |
97 | GUEST_ASSERT(load_vmcs(vmx_pages)); | ||
97 | 98 | ||
98 | /* Prepare the VMCS for L2 execution. */ | 99 | /* Prepare the VMCS for L2 execution. */ |
99 | prepare_vmcs(vmx_pages, l2_guest_code, | 100 | prepare_vmcs(vmx_pages, l2_guest_code, |
@@ -146,26 +147,25 @@ int main(int argc, char *argv[]) | |||
146 | 147 | ||
147 | for (;;) { | 148 | for (;;) { |
148 | volatile struct kvm_run *run = vcpu_state(vm, VCPU_ID); | 149 | volatile struct kvm_run *run = vcpu_state(vm, VCPU_ID); |
149 | struct guest_args args; | 150 | struct ucall uc; |
150 | 151 | ||
151 | vcpu_run(vm, VCPU_ID); | 152 | vcpu_run(vm, VCPU_ID); |
152 | guest_args_read(vm, VCPU_ID, &args); | ||
153 | TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, | 153 | TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, |
154 | "Got exit_reason other than KVM_EXIT_IO: %u (%s)\n", | 154 | "Got exit_reason other than KVM_EXIT_IO: %u (%s)\n", |
155 | run->exit_reason, | 155 | run->exit_reason, |
156 | exit_reason_str(run->exit_reason)); | 156 | exit_reason_str(run->exit_reason)); |
157 | 157 | ||
158 | switch (args.port) { | 158 | switch (get_ucall(vm, VCPU_ID, &uc)) { |
159 | case GUEST_PORT_ABORT: | 159 | case UCALL_ABORT: |
160 | TEST_ASSERT(false, "%s", (const char *) args.arg0); | 160 | TEST_ASSERT(false, "%s", (const char *)uc.args[0]); |
161 | /* NOT REACHED */ | 161 | /* NOT REACHED */ |
162 | case GUEST_PORT_SYNC: | 162 | case UCALL_SYNC: |
163 | report(args.arg1); | 163 | report(uc.args[1]); |
164 | break; | 164 | break; |
165 | case GUEST_PORT_DONE: | 165 | case UCALL_DONE: |
166 | goto done; | 166 | goto done; |
167 | default: | 167 | default: |
168 | TEST_ASSERT(false, "Unknown port 0x%x.", args.port); | 168 | TEST_ASSERT(false, "Unknown ucall 0x%x.", uc.cmd); |
169 | } | 169 | } |
170 | } | 170 | } |
171 | 171 | ||
diff --git a/tools/testing/selftests/net/.gitignore b/tools/testing/selftests/net/.gitignore index 78b24cf76f40..8cf22b3c2563 100644 --- a/tools/testing/selftests/net/.gitignore +++ b/tools/testing/selftests/net/.gitignore | |||
@@ -14,3 +14,4 @@ udpgso_bench_rx | |||
14 | udpgso_bench_tx | 14 | udpgso_bench_tx |
15 | tcp_inq | 15 | tcp_inq |
16 | tls | 16 | tls |
17 | ip_defrag | ||
diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile index 919aa2ac00af..256d82d5fa87 100644 --- a/tools/testing/selftests/net/Makefile +++ b/tools/testing/selftests/net/Makefile | |||
@@ -5,13 +5,13 @@ CFLAGS = -Wall -Wl,--no-as-needed -O2 -g | |||
5 | CFLAGS += -I../../../../usr/include/ | 5 | CFLAGS += -I../../../../usr/include/ |
6 | 6 | ||
7 | TEST_PROGS := run_netsocktests run_afpackettests test_bpf.sh netdevice.sh rtnetlink.sh | 7 | TEST_PROGS := run_netsocktests run_afpackettests test_bpf.sh netdevice.sh rtnetlink.sh |
8 | TEST_PROGS += fib_tests.sh fib-onlink-tests.sh pmtu.sh udpgso.sh | 8 | TEST_PROGS += fib_tests.sh fib-onlink-tests.sh pmtu.sh udpgso.sh ip_defrag.sh |
9 | TEST_PROGS += udpgso_bench.sh fib_rule_tests.sh msg_zerocopy.sh psock_snd.sh | 9 | TEST_PROGS += udpgso_bench.sh fib_rule_tests.sh msg_zerocopy.sh psock_snd.sh |
10 | TEST_PROGS_EXTENDED := in_netns.sh | 10 | TEST_PROGS_EXTENDED := in_netns.sh |
11 | TEST_GEN_FILES = socket | 11 | TEST_GEN_FILES = socket |
12 | TEST_GEN_FILES += psock_fanout psock_tpacket msg_zerocopy | 12 | TEST_GEN_FILES += psock_fanout psock_tpacket msg_zerocopy |
13 | TEST_GEN_FILES += tcp_mmap tcp_inq psock_snd | 13 | TEST_GEN_FILES += tcp_mmap tcp_inq psock_snd |
14 | TEST_GEN_FILES += udpgso udpgso_bench_tx udpgso_bench_rx | 14 | TEST_GEN_FILES += udpgso udpgso_bench_tx udpgso_bench_rx ip_defrag |
15 | TEST_GEN_PROGS = reuseport_bpf reuseport_bpf_cpu reuseport_bpf_numa | 15 | TEST_GEN_PROGS = reuseport_bpf reuseport_bpf_cpu reuseport_bpf_numa |
16 | TEST_GEN_PROGS += reuseport_dualstack reuseaddr_conflict tls | 16 | TEST_GEN_PROGS += reuseport_dualstack reuseaddr_conflict tls |
17 | 17 | ||
diff --git a/tools/testing/selftests/net/fib-onlink-tests.sh b/tools/testing/selftests/net/fib-onlink-tests.sh index 3991ad1a368d..864f865eee55 100755 --- a/tools/testing/selftests/net/fib-onlink-tests.sh +++ b/tools/testing/selftests/net/fib-onlink-tests.sh | |||
@@ -167,8 +167,8 @@ setup() | |||
167 | # add vrf table | 167 | # add vrf table |
168 | ip li add ${VRF} type vrf table ${VRF_TABLE} | 168 | ip li add ${VRF} type vrf table ${VRF_TABLE} |
169 | ip li set ${VRF} up | 169 | ip li set ${VRF} up |
170 | ip ro add table ${VRF_TABLE} unreachable default | 170 | ip ro add table ${VRF_TABLE} unreachable default metric 8192 |
171 | ip -6 ro add table ${VRF_TABLE} unreachable default | 171 | ip -6 ro add table ${VRF_TABLE} unreachable default metric 8192 |
172 | 172 | ||
173 | # create test interfaces | 173 | # create test interfaces |
174 | ip li add ${NETIFS[p1]} type veth peer name ${NETIFS[p2]} | 174 | ip li add ${NETIFS[p1]} type veth peer name ${NETIFS[p2]} |
@@ -185,20 +185,20 @@ setup() | |||
185 | for n in 1 3 5 7; do | 185 | for n in 1 3 5 7; do |
186 | ip li set ${NETIFS[p${n}]} up | 186 | ip li set ${NETIFS[p${n}]} up |
187 | ip addr add ${V4ADDRS[p${n}]}/24 dev ${NETIFS[p${n}]} | 187 | ip addr add ${V4ADDRS[p${n}]}/24 dev ${NETIFS[p${n}]} |
188 | ip addr add ${V6ADDRS[p${n}]}/64 dev ${NETIFS[p${n}]} | 188 | ip addr add ${V6ADDRS[p${n}]}/64 dev ${NETIFS[p${n}]} nodad |
189 | done | 189 | done |
190 | 190 | ||
191 | # move peer interfaces to namespace and add addresses | 191 | # move peer interfaces to namespace and add addresses |
192 | for n in 2 4 6 8; do | 192 | for n in 2 4 6 8; do |
193 | ip li set ${NETIFS[p${n}]} netns ${PEER_NS} up | 193 | ip li set ${NETIFS[p${n}]} netns ${PEER_NS} up |
194 | ip -netns ${PEER_NS} addr add ${V4ADDRS[p${n}]}/24 dev ${NETIFS[p${n}]} | 194 | ip -netns ${PEER_NS} addr add ${V4ADDRS[p${n}]}/24 dev ${NETIFS[p${n}]} |
195 | ip -netns ${PEER_NS} addr add ${V6ADDRS[p${n}]}/64 dev ${NETIFS[p${n}]} | 195 | ip -netns ${PEER_NS} addr add ${V6ADDRS[p${n}]}/64 dev ${NETIFS[p${n}]} nodad |
196 | done | 196 | done |
197 | 197 | ||
198 | set +e | 198 | ip -6 ro add default via ${V6ADDRS[p3]/::[0-9]/::64} |
199 | ip -6 ro add table ${VRF_TABLE} default via ${V6ADDRS[p7]/::[0-9]/::64} | ||
199 | 200 | ||
200 | # let DAD complete - assume default of 1 probe | 201 | set +e |
201 | sleep 1 | ||
202 | } | 202 | } |
203 | 203 | ||
204 | cleanup() | 204 | cleanup() |
diff --git a/tools/testing/selftests/net/fib_tests.sh b/tools/testing/selftests/net/fib_tests.sh index 0f45633bd634..802b4af18729 100755 --- a/tools/testing/selftests/net/fib_tests.sh +++ b/tools/testing/selftests/net/fib_tests.sh | |||
@@ -9,11 +9,11 @@ ret=0 | |||
9 | ksft_skip=4 | 9 | ksft_skip=4 |
10 | 10 | ||
11 | # all tests in this script. Can be overridden with -t option | 11 | # all tests in this script. Can be overridden with -t option |
12 | TESTS="unregister down carrier nexthop ipv6_rt ipv4_rt ipv6_addr_metric ipv4_addr_metric" | 12 | TESTS="unregister down carrier nexthop ipv6_rt ipv4_rt ipv6_addr_metric ipv4_addr_metric ipv6_route_metrics ipv4_route_metrics" |
13 | VERBOSE=0 | 13 | VERBOSE=0 |
14 | PAUSE_ON_FAIL=no | 14 | PAUSE_ON_FAIL=no |
15 | PAUSE=no | 15 | PAUSE=no |
16 | IP="ip -netns testns" | 16 | IP="ip -netns ns1" |
17 | 17 | ||
18 | log_test() | 18 | log_test() |
19 | { | 19 | { |
@@ -47,8 +47,10 @@ log_test() | |||
47 | setup() | 47 | setup() |
48 | { | 48 | { |
49 | set -e | 49 | set -e |
50 | ip netns add testns | 50 | ip netns add ns1 |
51 | $IP link set dev lo up | 51 | $IP link set dev lo up |
52 | ip netns exec ns1 sysctl -qw net.ipv4.ip_forward=1 | ||
53 | ip netns exec ns1 sysctl -qw net.ipv6.conf.all.forwarding=1 | ||
52 | 54 | ||
53 | $IP link add dummy0 type dummy | 55 | $IP link add dummy0 type dummy |
54 | $IP link set dev dummy0 up | 56 | $IP link set dev dummy0 up |
@@ -61,7 +63,8 @@ setup() | |||
61 | cleanup() | 63 | cleanup() |
62 | { | 64 | { |
63 | $IP link del dev dummy0 &> /dev/null | 65 | $IP link del dev dummy0 &> /dev/null |
64 | ip netns del testns | 66 | ip netns del ns1 |
67 | ip netns del ns2 &> /dev/null | ||
65 | } | 68 | } |
66 | 69 | ||
67 | get_linklocal() | 70 | get_linklocal() |
@@ -639,11 +642,14 @@ add_initial_route6() | |||
639 | 642 | ||
640 | check_route6() | 643 | check_route6() |
641 | { | 644 | { |
642 | local pfx="2001:db8:104::/64" | 645 | local pfx |
643 | local expected="$1" | 646 | local expected="$1" |
644 | local out | 647 | local out |
645 | local rc=0 | 648 | local rc=0 |
646 | 649 | ||
650 | set -- $expected | ||
651 | pfx=$1 | ||
652 | |||
647 | out=$($IP -6 ro ls match ${pfx} | sed -e 's/ pref medium//') | 653 | out=$($IP -6 ro ls match ${pfx} | sed -e 's/ pref medium//') |
648 | [ "${out}" = "${expected}" ] && return 0 | 654 | [ "${out}" = "${expected}" ] && return 0 |
649 | 655 | ||
@@ -690,28 +696,33 @@ route_setup() | |||
690 | [ "${VERBOSE}" = "1" ] && set -x | 696 | [ "${VERBOSE}" = "1" ] && set -x |
691 | set -e | 697 | set -e |
692 | 698 | ||
693 | $IP li add red up type vrf table 101 | 699 | ip netns add ns2 |
700 | ip -netns ns2 link set dev lo up | ||
701 | ip netns exec ns2 sysctl -qw net.ipv4.ip_forward=1 | ||
702 | ip netns exec ns2 sysctl -qw net.ipv6.conf.all.forwarding=1 | ||
703 | |||
694 | $IP li add veth1 type veth peer name veth2 | 704 | $IP li add veth1 type veth peer name veth2 |
695 | $IP li add veth3 type veth peer name veth4 | 705 | $IP li add veth3 type veth peer name veth4 |
696 | 706 | ||
697 | $IP li set veth1 up | 707 | $IP li set veth1 up |
698 | $IP li set veth3 up | 708 | $IP li set veth3 up |
699 | $IP li set veth2 vrf red up | 709 | $IP li set veth2 netns ns2 up |
700 | $IP li set veth4 vrf red up | 710 | $IP li set veth4 netns ns2 up |
701 | $IP li add dummy1 type dummy | 711 | ip -netns ns2 li add dummy1 type dummy |
702 | $IP li set dummy1 vrf red up | 712 | ip -netns ns2 li set dummy1 up |
703 | |||
704 | $IP -6 addr add 2001:db8:101::1/64 dev veth1 | ||
705 | $IP -6 addr add 2001:db8:101::2/64 dev veth2 | ||
706 | $IP -6 addr add 2001:db8:103::1/64 dev veth3 | ||
707 | $IP -6 addr add 2001:db8:103::2/64 dev veth4 | ||
708 | $IP -6 addr add 2001:db8:104::1/64 dev dummy1 | ||
709 | 713 | ||
714 | $IP -6 addr add 2001:db8:101::1/64 dev veth1 nodad | ||
715 | $IP -6 addr add 2001:db8:103::1/64 dev veth3 nodad | ||
710 | $IP addr add 172.16.101.1/24 dev veth1 | 716 | $IP addr add 172.16.101.1/24 dev veth1 |
711 | $IP addr add 172.16.101.2/24 dev veth2 | ||
712 | $IP addr add 172.16.103.1/24 dev veth3 | 717 | $IP addr add 172.16.103.1/24 dev veth3 |
713 | $IP addr add 172.16.103.2/24 dev veth4 | 718 | |
714 | $IP addr add 172.16.104.1/24 dev dummy1 | 719 | ip -netns ns2 -6 addr add 2001:db8:101::2/64 dev veth2 nodad |
720 | ip -netns ns2 -6 addr add 2001:db8:103::2/64 dev veth4 nodad | ||
721 | ip -netns ns2 -6 addr add 2001:db8:104::1/64 dev dummy1 nodad | ||
722 | |||
723 | ip -netns ns2 addr add 172.16.101.2/24 dev veth2 | ||
724 | ip -netns ns2 addr add 172.16.103.2/24 dev veth4 | ||
725 | ip -netns ns2 addr add 172.16.104.1/24 dev dummy1 | ||
715 | 726 | ||
716 | set +ex | 727 | set +ex |
717 | } | 728 | } |
@@ -944,7 +955,7 @@ ipv6_addr_metric_test() | |||
944 | log_test $rc 0 "Modify metric of address" | 955 | log_test $rc 0 "Modify metric of address" |
945 | 956 | ||
946 | # verify prefix route removed on down | 957 | # verify prefix route removed on down |
947 | run_cmd "ip netns exec testns sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1" | 958 | run_cmd "ip netns exec ns1 sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1" |
948 | run_cmd "$IP li set dev dummy2 down" | 959 | run_cmd "$IP li set dev dummy2 down" |
949 | rc=$? | 960 | rc=$? |
950 | if [ $rc -eq 0 ]; then | 961 | if [ $rc -eq 0 ]; then |
@@ -967,6 +978,77 @@ ipv6_addr_metric_test() | |||
967 | cleanup | 978 | cleanup |
968 | } | 979 | } |
969 | 980 | ||
981 | ipv6_route_metrics_test() | ||
982 | { | ||
983 | local rc | ||
984 | |||
985 | echo | ||
986 | echo "IPv6 routes with metrics" | ||
987 | |||
988 | route_setup | ||
989 | |||
990 | # | ||
991 | # single path with metrics | ||
992 | # | ||
993 | run_cmd "$IP -6 ro add 2001:db8:111::/64 via 2001:db8:101::2 mtu 1400" | ||
994 | rc=$? | ||
995 | if [ $rc -eq 0 ]; then | ||
996 | check_route6 "2001:db8:111::/64 via 2001:db8:101::2 dev veth1 metric 1024 mtu 1400" | ||
997 | rc=$? | ||
998 | fi | ||
999 | log_test $rc 0 "Single path route with mtu metric" | ||
1000 | |||
1001 | |||
1002 | # | ||
1003 | # multipath via separate routes with metrics | ||
1004 | # | ||
1005 | run_cmd "$IP -6 ro add 2001:db8:112::/64 via 2001:db8:101::2 mtu 1400" | ||
1006 | run_cmd "$IP -6 ro append 2001:db8:112::/64 via 2001:db8:103::2" | ||
1007 | rc=$? | ||
1008 | if [ $rc -eq 0 ]; then | ||
1009 | check_route6 "2001:db8:112::/64 metric 1024 mtu 1400 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1" | ||
1010 | rc=$? | ||
1011 | fi | ||
1012 | log_test $rc 0 "Multipath route via 2 single routes with mtu metric on first" | ||
1013 | |||
1014 | # second route is coalesced to first to make a multipath route. | ||
1015 | # MTU of the second path is hidden from display! | ||
1016 | run_cmd "$IP -6 ro add 2001:db8:113::/64 via 2001:db8:101::2" | ||
1017 | run_cmd "$IP -6 ro append 2001:db8:113::/64 via 2001:db8:103::2 mtu 1400" | ||
1018 | rc=$? | ||
1019 | if [ $rc -eq 0 ]; then | ||
1020 | check_route6 "2001:db8:113::/64 metric 1024 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1" | ||
1021 | rc=$? | ||
1022 | fi | ||
1023 | log_test $rc 0 "Multipath route via 2 single routes with mtu metric on 2nd" | ||
1024 | |||
1025 | run_cmd "$IP -6 ro del 2001:db8:113::/64 via 2001:db8:101::2" | ||
1026 | if [ $? -eq 0 ]; then | ||
1027 | check_route6 "2001:db8:113::/64 via 2001:db8:103::2 dev veth3 metric 1024 mtu 1400" | ||
1028 | log_test $? 0 " MTU of second leg" | ||
1029 | fi | ||
1030 | |||
1031 | # | ||
1032 | # multipath with metrics | ||
1033 | # | ||
1034 | run_cmd "$IP -6 ro add 2001:db8:115::/64 mtu 1400 nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2" | ||
1035 | rc=$? | ||
1036 | if [ $rc -eq 0 ]; then | ||
1037 | check_route6 "2001:db8:115::/64 metric 1024 mtu 1400 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1" | ||
1038 | rc=$? | ||
1039 | fi | ||
1040 | log_test $rc 0 "Multipath route with mtu metric" | ||
1041 | |||
1042 | $IP -6 ro add 2001:db8:104::/64 via 2001:db8:101::2 mtu 1300 | ||
1043 | run_cmd "ip netns exec ns1 ping6 -w1 -c1 -s 1500 2001:db8:104::1" | ||
1044 | log_test $? 0 "Using route with mtu metric" | ||
1045 | |||
1046 | run_cmd "$IP -6 ro add 2001:db8:114::/64 via 2001:db8:101::2 congctl lock foo" | ||
1047 | log_test $? 2 "Invalid metric (fails metric_convert)" | ||
1048 | |||
1049 | route_cleanup | ||
1050 | } | ||
1051 | |||
970 | # add route for a prefix, flushing any existing routes first | 1052 | # add route for a prefix, flushing any existing routes first |
971 | # expected to be the first step of a test | 1053 | # expected to be the first step of a test |
972 | add_route() | 1054 | add_route() |
@@ -1005,11 +1087,15 @@ add_initial_route() | |||
1005 | 1087 | ||
1006 | check_route() | 1088 | check_route() |
1007 | { | 1089 | { |
1008 | local pfx="172.16.104.0/24" | 1090 | local pfx |
1009 | local expected="$1" | 1091 | local expected="$1" |
1010 | local out | 1092 | local out |
1011 | local rc=0 | 1093 | local rc=0 |
1012 | 1094 | ||
1095 | set -- $expected | ||
1096 | pfx=$1 | ||
1097 | [ "${pfx}" = "unreachable" ] && pfx=$2 | ||
1098 | |||
1013 | out=$($IP ro ls match ${pfx}) | 1099 | out=$($IP ro ls match ${pfx}) |
1014 | [ "${out}" = "${expected}" ] && return 0 | 1100 | [ "${out}" = "${expected}" ] && return 0 |
1015 | 1101 | ||
@@ -1319,6 +1405,43 @@ ipv4_addr_metric_test() | |||
1319 | cleanup | 1405 | cleanup |
1320 | } | 1406 | } |
1321 | 1407 | ||
1408 | ipv4_route_metrics_test() | ||
1409 | { | ||
1410 | local rc | ||
1411 | |||
1412 | echo | ||
1413 | echo "IPv4 route add / append tests" | ||
1414 | |||
1415 | route_setup | ||
1416 | |||
1417 | run_cmd "$IP ro add 172.16.111.0/24 via 172.16.101.2 mtu 1400" | ||
1418 | rc=$? | ||
1419 | if [ $rc -eq 0 ]; then | ||
1420 | check_route "172.16.111.0/24 via 172.16.101.2 dev veth1 mtu 1400" | ||
1421 | rc=$? | ||
1422 | fi | ||
1423 | log_test $rc 0 "Single path route with mtu metric" | ||
1424 | |||
1425 | |||
1426 | run_cmd "$IP ro add 172.16.112.0/24 mtu 1400 nexthop via 172.16.101.2 nexthop via 172.16.103.2" | ||
1427 | rc=$? | ||
1428 | if [ $rc -eq 0 ]; then | ||
1429 | check_route "172.16.112.0/24 mtu 1400 nexthop via 172.16.101.2 dev veth1 weight 1 nexthop via 172.16.103.2 dev veth3 weight 1" | ||
1430 | rc=$? | ||
1431 | fi | ||
1432 | log_test $rc 0 "Multipath route with mtu metric" | ||
1433 | |||
1434 | $IP ro add 172.16.104.0/24 via 172.16.101.2 mtu 1300 | ||
1435 | run_cmd "ip netns exec ns1 ping -w1 -c1 -s 1500 172.16.104.1" | ||
1436 | log_test $? 0 "Using route with mtu metric" | ||
1437 | |||
1438 | run_cmd "$IP ro add 172.16.111.0/24 via 172.16.101.2 congctl lock foo" | ||
1439 | log_test $? 2 "Invalid metric (fails metric_convert)" | ||
1440 | |||
1441 | route_cleanup | ||
1442 | } | ||
1443 | |||
1444 | |||
1322 | ################################################################################ | 1445 | ################################################################################ |
1323 | # usage | 1446 | # usage |
1324 | 1447 | ||
@@ -1385,6 +1508,8 @@ do | |||
1385 | ipv4_route_test|ipv4_rt) ipv4_route_test;; | 1508 | ipv4_route_test|ipv4_rt) ipv4_route_test;; |
1386 | ipv6_addr_metric) ipv6_addr_metric_test;; | 1509 | ipv6_addr_metric) ipv6_addr_metric_test;; |
1387 | ipv4_addr_metric) ipv4_addr_metric_test;; | 1510 | ipv4_addr_metric) ipv4_addr_metric_test;; |
1511 | ipv6_route_metrics) ipv6_route_metrics_test;; | ||
1512 | ipv4_route_metrics) ipv4_route_metrics_test;; | ||
1388 | 1513 | ||
1389 | help) echo "Test names: $TESTS"; exit 0;; | 1514 | help) echo "Test names: $TESTS"; exit 0;; |
1390 | esac | 1515 | esac |
diff --git a/tools/testing/selftests/net/forwarding/bridge_sticky_fdb.sh b/tools/testing/selftests/net/forwarding/bridge_sticky_fdb.sh new file mode 100755 index 000000000000..1f8ef0eff862 --- /dev/null +++ b/tools/testing/selftests/net/forwarding/bridge_sticky_fdb.sh | |||
@@ -0,0 +1,69 @@ | |||
1 | #!/bin/bash | ||
2 | # SPDX-License-Identifier: GPL-2.0 | ||
3 | |||
4 | ALL_TESTS="sticky" | ||
5 | NUM_NETIFS=4 | ||
6 | TEST_MAC=de:ad:be:ef:13:37 | ||
7 | source lib.sh | ||
8 | |||
9 | switch_create() | ||
10 | { | ||
11 | ip link add dev br0 type bridge | ||
12 | |||
13 | ip link set dev $swp1 master br0 | ||
14 | ip link set dev $swp2 master br0 | ||
15 | |||
16 | ip link set dev br0 up | ||
17 | ip link set dev $h1 up | ||
18 | ip link set dev $swp1 up | ||
19 | ip link set dev $h2 up | ||
20 | ip link set dev $swp2 up | ||
21 | } | ||
22 | |||
23 | switch_destroy() | ||
24 | { | ||
25 | ip link set dev $swp2 down | ||
26 | ip link set dev $h2 down | ||
27 | ip link set dev $swp1 down | ||
28 | ip link set dev $h1 down | ||
29 | |||
30 | ip link del dev br0 | ||
31 | } | ||
32 | |||
33 | setup_prepare() | ||
34 | { | ||
35 | h1=${NETIFS[p1]} | ||
36 | swp1=${NETIFS[p2]} | ||
37 | h2=${NETIFS[p3]} | ||
38 | swp2=${NETIFS[p4]} | ||
39 | |||
40 | switch_create | ||
41 | } | ||
42 | |||
43 | cleanup() | ||
44 | { | ||
45 | pre_cleanup | ||
46 | switch_destroy | ||
47 | } | ||
48 | |||
49 | sticky() | ||
50 | { | ||
51 | bridge fdb add $TEST_MAC dev $swp1 master static sticky | ||
52 | check_err $? "Could not add fdb entry" | ||
53 | bridge fdb del $TEST_MAC dev $swp1 vlan 1 master static sticky | ||
54 | $MZ $h2 -c 1 -a $TEST_MAC -t arp "request" -q | ||
55 | bridge -j fdb show br br0 brport $swp1\ | ||
56 | | jq -e ".[] | select(.mac == \"$TEST_MAC\")" &> /dev/null | ||
57 | check_err $? "Did not find FDB record when should" | ||
58 | |||
59 | log_test "Sticky fdb entry" | ||
60 | } | ||
61 | |||
62 | trap cleanup EXIT | ||
63 | |||
64 | setup_prepare | ||
65 | setup_wait | ||
66 | |||
67 | tests_run | ||
68 | |||
69 | exit $EXIT_STATUS | ||
diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index ca53b539aa2d..85d253546684 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh | |||
@@ -251,7 +251,7 @@ lldpad_app_wait_set() | |||
251 | { | 251 | { |
252 | local dev=$1; shift | 252 | local dev=$1; shift |
253 | 253 | ||
254 | while lldptool -t -i $dev -V APP -c app | grep -q pending; do | 254 | while lldptool -t -i $dev -V APP -c app | grep -Eq "pending|unknown"; do |
255 | echo "$dev: waiting for lldpad to push pending APP updates" | 255 | echo "$dev: waiting for lldpad to push pending APP updates" |
256 | sleep 5 | 256 | sleep 5 |
257 | done | 257 | done |
@@ -494,6 +494,14 @@ tc_rule_stats_get() | |||
494 | | jq '.[1].options.actions[].stats.packets' | 494 | | jq '.[1].options.actions[].stats.packets' |
495 | } | 495 | } |
496 | 496 | ||
497 | ethtool_stats_get() | ||
498 | { | ||
499 | local dev=$1; shift | ||
500 | local stat=$1; shift | ||
501 | |||
502 | ethtool -S $dev | grep "^ *$stat:" | head -n 1 | cut -d: -f2 | ||
503 | } | ||
504 | |||
497 | mac_get() | 505 | mac_get() |
498 | { | 506 | { |
499 | local if_name=$1 | 507 | local if_name=$1 |
@@ -541,6 +549,23 @@ forwarding_restore() | |||
541 | sysctl_restore net.ipv4.conf.all.forwarding | 549 | sysctl_restore net.ipv4.conf.all.forwarding |
542 | } | 550 | } |
543 | 551 | ||
552 | declare -A MTU_ORIG | ||
553 | mtu_set() | ||
554 | { | ||
555 | local dev=$1; shift | ||
556 | local mtu=$1; shift | ||
557 | |||
558 | MTU_ORIG["$dev"]=$(ip -j link show dev $dev | jq -e '.[].mtu') | ||
559 | ip link set dev $dev mtu $mtu | ||
560 | } | ||
561 | |||
562 | mtu_restore() | ||
563 | { | ||
564 | local dev=$1; shift | ||
565 | |||
566 | ip link set dev $dev mtu ${MTU_ORIG["$dev"]} | ||
567 | } | ||
568 | |||
544 | tc_offload_check() | 569 | tc_offload_check() |
545 | { | 570 | { |
546 | local num_netifs=${1:-$NUM_NETIFS} | 571 | local num_netifs=${1:-$NUM_NETIFS} |
diff --git a/tools/testing/selftests/net/ip_defrag.c b/tools/testing/selftests/net/ip_defrag.c new file mode 100644 index 000000000000..61ae2782388e --- /dev/null +++ b/tools/testing/selftests/net/ip_defrag.c | |||
@@ -0,0 +1,393 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | |||
3 | #define _GNU_SOURCE | ||
4 | |||
5 | #include <arpa/inet.h> | ||
6 | #include <errno.h> | ||
7 | #include <error.h> | ||
8 | #include <linux/in.h> | ||
9 | #include <netinet/ip.h> | ||
10 | #include <netinet/ip6.h> | ||
11 | #include <netinet/udp.h> | ||
12 | #include <stdbool.h> | ||
13 | #include <stdio.h> | ||
14 | #include <stdlib.h> | ||
15 | #include <string.h> | ||
16 | #include <time.h> | ||
17 | #include <unistd.h> | ||
18 | |||
19 | static bool cfg_do_ipv4; | ||
20 | static bool cfg_do_ipv6; | ||
21 | static bool cfg_verbose; | ||
22 | static bool cfg_overlap; | ||
23 | static unsigned short cfg_port = 9000; | ||
24 | |||
25 | const struct in_addr addr4 = { .s_addr = __constant_htonl(INADDR_LOOPBACK + 2) }; | ||
26 | const struct in6_addr addr6 = IN6ADDR_LOOPBACK_INIT; | ||
27 | |||
28 | #define IP4_HLEN (sizeof(struct iphdr)) | ||
29 | #define IP6_HLEN (sizeof(struct ip6_hdr)) | ||
30 | #define UDP_HLEN (sizeof(struct udphdr)) | ||
31 | |||
32 | /* IPv6 fragment header lenth. */ | ||
33 | #define FRAG_HLEN 8 | ||
34 | |||
35 | static int payload_len; | ||
36 | static int max_frag_len; | ||
37 | |||
38 | #define MSG_LEN_MAX 60000 /* Max UDP payload length. */ | ||
39 | |||
40 | #define IP4_MF (1u << 13) /* IPv4 MF flag. */ | ||
41 | #define IP6_MF (1) /* IPv6 MF flag. */ | ||
42 | |||
43 | #define CSUM_MANGLED_0 (0xffff) | ||
44 | |||
45 | static uint8_t udp_payload[MSG_LEN_MAX]; | ||
46 | static uint8_t ip_frame[IP_MAXPACKET]; | ||
47 | static uint32_t ip_id = 0xabcd; | ||
48 | static int msg_counter; | ||
49 | static int frag_counter; | ||
50 | static unsigned int seed; | ||
51 | |||
52 | /* Receive a UDP packet. Validate it matches udp_payload. */ | ||
53 | static void recv_validate_udp(int fd_udp) | ||
54 | { | ||
55 | ssize_t ret; | ||
56 | static uint8_t recv_buff[MSG_LEN_MAX]; | ||
57 | |||
58 | ret = recv(fd_udp, recv_buff, payload_len, 0); | ||
59 | msg_counter++; | ||
60 | |||
61 | if (cfg_overlap) { | ||
62 | if (ret != -1) | ||
63 | error(1, 0, "recv: expected timeout; got %d", | ||
64 | (int)ret); | ||
65 | if (errno != ETIMEDOUT && errno != EAGAIN) | ||
66 | error(1, errno, "recv: expected timeout: %d", | ||
67 | errno); | ||
68 | return; /* OK */ | ||
69 | } | ||
70 | |||
71 | if (ret == -1) | ||
72 | error(1, errno, "recv: payload_len = %d max_frag_len = %d", | ||
73 | payload_len, max_frag_len); | ||
74 | if (ret != payload_len) | ||
75 | error(1, 0, "recv: wrong size: %d vs %d", (int)ret, payload_len); | ||
76 | if (memcmp(udp_payload, recv_buff, payload_len)) | ||
77 | error(1, 0, "recv: wrong data"); | ||
78 | } | ||
79 | |||
80 | static uint32_t raw_checksum(uint8_t *buf, int len, uint32_t sum) | ||
81 | { | ||
82 | int i; | ||
83 | |||
84 | for (i = 0; i < (len & ~1U); i += 2) { | ||
85 | sum += (u_int16_t)ntohs(*((u_int16_t *)(buf + i))); | ||
86 | if (sum > 0xffff) | ||
87 | sum -= 0xffff; | ||
88 | } | ||
89 | |||
90 | if (i < len) { | ||
91 | sum += buf[i] << 8; | ||
92 | if (sum > 0xffff) | ||
93 | sum -= 0xffff; | ||
94 | } | ||
95 | |||
96 | return sum; | ||
97 | } | ||
98 | |||
99 | static uint16_t udp_checksum(struct ip *iphdr, struct udphdr *udphdr) | ||
100 | { | ||
101 | uint32_t sum = 0; | ||
102 | uint16_t res; | ||
103 | |||
104 | sum = raw_checksum((uint8_t *)&iphdr->ip_src, 2 * sizeof(iphdr->ip_src), | ||
105 | IPPROTO_UDP + (uint32_t)(UDP_HLEN + payload_len)); | ||
106 | sum = raw_checksum((uint8_t *)udphdr, UDP_HLEN, sum); | ||
107 | sum = raw_checksum((uint8_t *)udp_payload, payload_len, sum); | ||
108 | res = 0xffff & ~sum; | ||
109 | if (res) | ||
110 | return htons(res); | ||
111 | else | ||
112 | return CSUM_MANGLED_0; | ||
113 | } | ||
114 | |||
115 | static uint16_t udp6_checksum(struct ip6_hdr *iphdr, struct udphdr *udphdr) | ||
116 | { | ||
117 | uint32_t sum = 0; | ||
118 | uint16_t res; | ||
119 | |||
120 | sum = raw_checksum((uint8_t *)&iphdr->ip6_src, 2 * sizeof(iphdr->ip6_src), | ||
121 | IPPROTO_UDP); | ||
122 | sum = raw_checksum((uint8_t *)&udphdr->len, sizeof(udphdr->len), sum); | ||
123 | sum = raw_checksum((uint8_t *)udphdr, UDP_HLEN, sum); | ||
124 | sum = raw_checksum((uint8_t *)udp_payload, payload_len, sum); | ||
125 | res = 0xffff & ~sum; | ||
126 | if (res) | ||
127 | return htons(res); | ||
128 | else | ||
129 | return CSUM_MANGLED_0; | ||
130 | } | ||
131 | |||
132 | static void send_fragment(int fd_raw, struct sockaddr *addr, socklen_t alen, | ||
133 | int offset, bool ipv6) | ||
134 | { | ||
135 | int frag_len; | ||
136 | int res; | ||
137 | int payload_offset = offset > 0 ? offset - UDP_HLEN : 0; | ||
138 | uint8_t *frag_start = ipv6 ? ip_frame + IP6_HLEN + FRAG_HLEN : | ||
139 | ip_frame + IP4_HLEN; | ||
140 | |||
141 | if (offset == 0) { | ||
142 | struct udphdr udphdr; | ||
143 | udphdr.source = htons(cfg_port + 1); | ||
144 | udphdr.dest = htons(cfg_port); | ||
145 | udphdr.len = htons(UDP_HLEN + payload_len); | ||
146 | udphdr.check = 0; | ||
147 | if (ipv6) | ||
148 | udphdr.check = udp6_checksum((struct ip6_hdr *)ip_frame, &udphdr); | ||
149 | else | ||
150 | udphdr.check = udp_checksum((struct ip *)ip_frame, &udphdr); | ||
151 | memcpy(frag_start, &udphdr, UDP_HLEN); | ||
152 | } | ||
153 | |||
154 | if (ipv6) { | ||
155 | struct ip6_hdr *ip6hdr = (struct ip6_hdr *)ip_frame; | ||
156 | struct ip6_frag *fraghdr = (struct ip6_frag *)(ip_frame + IP6_HLEN); | ||
157 | if (payload_len - payload_offset <= max_frag_len && offset > 0) { | ||
158 | /* This is the last fragment. */ | ||
159 | frag_len = FRAG_HLEN + payload_len - payload_offset; | ||
160 | fraghdr->ip6f_offlg = htons(offset); | ||
161 | } else { | ||
162 | frag_len = FRAG_HLEN + max_frag_len; | ||
163 | fraghdr->ip6f_offlg = htons(offset | IP6_MF); | ||
164 | } | ||
165 | ip6hdr->ip6_plen = htons(frag_len); | ||
166 | if (offset == 0) | ||
167 | memcpy(frag_start + UDP_HLEN, udp_payload, | ||
168 | frag_len - FRAG_HLEN - UDP_HLEN); | ||
169 | else | ||
170 | memcpy(frag_start, udp_payload + payload_offset, | ||
171 | frag_len - FRAG_HLEN); | ||
172 | frag_len += IP6_HLEN; | ||
173 | } else { | ||
174 | struct ip *iphdr = (struct ip *)ip_frame; | ||
175 | if (payload_len - payload_offset <= max_frag_len && offset > 0) { | ||
176 | /* This is the last fragment. */ | ||
177 | frag_len = IP4_HLEN + payload_len - payload_offset; | ||
178 | iphdr->ip_off = htons(offset / 8); | ||
179 | } else { | ||
180 | frag_len = IP4_HLEN + max_frag_len; | ||
181 | iphdr->ip_off = htons(offset / 8 | IP4_MF); | ||
182 | } | ||
183 | iphdr->ip_len = htons(frag_len); | ||
184 | if (offset == 0) | ||
185 | memcpy(frag_start + UDP_HLEN, udp_payload, | ||
186 | frag_len - IP4_HLEN - UDP_HLEN); | ||
187 | else | ||
188 | memcpy(frag_start, udp_payload + payload_offset, | ||
189 | frag_len - IP4_HLEN); | ||
190 | } | ||
191 | |||
192 | res = sendto(fd_raw, ip_frame, frag_len, 0, addr, alen); | ||
193 | if (res < 0) | ||
194 | error(1, errno, "send_fragment"); | ||
195 | if (res != frag_len) | ||
196 | error(1, 0, "send_fragment: %d vs %d", res, frag_len); | ||
197 | |||
198 | frag_counter++; | ||
199 | } | ||
200 | |||
201 | static void send_udp_frags(int fd_raw, struct sockaddr *addr, | ||
202 | socklen_t alen, bool ipv6) | ||
203 | { | ||
204 | struct ip *iphdr = (struct ip *)ip_frame; | ||
205 | struct ip6_hdr *ip6hdr = (struct ip6_hdr *)ip_frame; | ||
206 | int res; | ||
207 | int offset; | ||
208 | int frag_len; | ||
209 | |||
210 | /* Send the UDP datagram using raw IP fragments: the 0th fragment | ||
211 | * has the UDP header; other fragments are pieces of udp_payload | ||
212 | * split in chunks of frag_len size. | ||
213 | * | ||
214 | * Odd fragments (1st, 3rd, 5th, etc.) are sent out first, then | ||
215 | * even fragments (0th, 2nd, etc.) are sent out. | ||
216 | */ | ||
217 | if (ipv6) { | ||
218 | struct ip6_frag *fraghdr = (struct ip6_frag *)(ip_frame + IP6_HLEN); | ||
219 | ((struct sockaddr_in6 *)addr)->sin6_port = 0; | ||
220 | memset(ip6hdr, 0, sizeof(*ip6hdr)); | ||
221 | ip6hdr->ip6_flow = htonl(6<<28); /* Version. */ | ||
222 | ip6hdr->ip6_nxt = IPPROTO_FRAGMENT; | ||
223 | ip6hdr->ip6_hops = 255; | ||
224 | ip6hdr->ip6_src = addr6; | ||
225 | ip6hdr->ip6_dst = addr6; | ||
226 | fraghdr->ip6f_nxt = IPPROTO_UDP; | ||
227 | fraghdr->ip6f_reserved = 0; | ||
228 | fraghdr->ip6f_ident = htonl(ip_id++); | ||
229 | } else { | ||
230 | memset(iphdr, 0, sizeof(*iphdr)); | ||
231 | iphdr->ip_hl = 5; | ||
232 | iphdr->ip_v = 4; | ||
233 | iphdr->ip_tos = 0; | ||
234 | iphdr->ip_id = htons(ip_id++); | ||
235 | iphdr->ip_ttl = 0x40; | ||
236 | iphdr->ip_p = IPPROTO_UDP; | ||
237 | iphdr->ip_src.s_addr = htonl(INADDR_LOOPBACK); | ||
238 | iphdr->ip_dst = addr4; | ||
239 | iphdr->ip_sum = 0; | ||
240 | } | ||
241 | |||
242 | /* Odd fragments. */ | ||
243 | offset = max_frag_len; | ||
244 | while (offset < (UDP_HLEN + payload_len)) { | ||
245 | send_fragment(fd_raw, addr, alen, offset, ipv6); | ||
246 | offset += 2 * max_frag_len; | ||
247 | } | ||
248 | |||
249 | if (cfg_overlap) { | ||
250 | /* Send an extra random fragment. */ | ||
251 | offset = rand() % (UDP_HLEN + payload_len - 1); | ||
252 | /* sendto() returns EINVAL if offset + frag_len is too small. */ | ||
253 | if (ipv6) { | ||
254 | struct ip6_frag *fraghdr = (struct ip6_frag *)(ip_frame + IP6_HLEN); | ||
255 | frag_len = max_frag_len + rand() % 256; | ||
256 | /* In IPv6 if !!(frag_len % 8), the fragment is dropped. */ | ||
257 | frag_len &= ~0x7; | ||
258 | fraghdr->ip6f_offlg = htons(offset / 8 | IP6_MF); | ||
259 | ip6hdr->ip6_plen = htons(frag_len); | ||
260 | frag_len += IP6_HLEN; | ||
261 | } else { | ||
262 | frag_len = IP4_HLEN + UDP_HLEN + rand() % 256; | ||
263 | iphdr->ip_off = htons(offset / 8 | IP4_MF); | ||
264 | iphdr->ip_len = htons(frag_len); | ||
265 | } | ||
266 | res = sendto(fd_raw, ip_frame, frag_len, 0, addr, alen); | ||
267 | if (res < 0) | ||
268 | error(1, errno, "sendto overlap"); | ||
269 | if (res != frag_len) | ||
270 | error(1, 0, "sendto overlap: %d vs %d", (int)res, frag_len); | ||
271 | frag_counter++; | ||
272 | } | ||
273 | |||
274 | /* Event fragments. */ | ||
275 | offset = 0; | ||
276 | while (offset < (UDP_HLEN + payload_len)) { | ||
277 | send_fragment(fd_raw, addr, alen, offset, ipv6); | ||
278 | offset += 2 * max_frag_len; | ||
279 | } | ||
280 | } | ||
281 | |||
282 | static void run_test(struct sockaddr *addr, socklen_t alen, bool ipv6) | ||
283 | { | ||
284 | int fd_tx_raw, fd_rx_udp; | ||
285 | struct timeval tv = { .tv_sec = 0, .tv_usec = 10 * 1000 }; | ||
286 | int idx; | ||
287 | int min_frag_len = ipv6 ? 1280 : 8; | ||
288 | |||
289 | /* Initialize the payload. */ | ||
290 | for (idx = 0; idx < MSG_LEN_MAX; ++idx) | ||
291 | udp_payload[idx] = idx % 256; | ||
292 | |||
293 | /* Open sockets. */ | ||
294 | fd_tx_raw = socket(addr->sa_family, SOCK_RAW, IPPROTO_RAW); | ||
295 | if (fd_tx_raw == -1) | ||
296 | error(1, errno, "socket tx_raw"); | ||
297 | |||
298 | fd_rx_udp = socket(addr->sa_family, SOCK_DGRAM, 0); | ||
299 | if (fd_rx_udp == -1) | ||
300 | error(1, errno, "socket rx_udp"); | ||
301 | if (bind(fd_rx_udp, addr, alen)) | ||
302 | error(1, errno, "bind"); | ||
303 | /* Fail fast. */ | ||
304 | if (setsockopt(fd_rx_udp, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv))) | ||
305 | error(1, errno, "setsockopt rcv timeout"); | ||
306 | |||
307 | for (payload_len = min_frag_len; payload_len < MSG_LEN_MAX; | ||
308 | payload_len += (rand() % 4096)) { | ||
309 | if (cfg_verbose) | ||
310 | printf("payload_len: %d\n", payload_len); | ||
311 | max_frag_len = min_frag_len; | ||
312 | do { | ||
313 | send_udp_frags(fd_tx_raw, addr, alen, ipv6); | ||
314 | recv_validate_udp(fd_rx_udp); | ||
315 | max_frag_len += 8 * (rand() % 8); | ||
316 | } while (max_frag_len < (1500 - FRAG_HLEN) && max_frag_len <= payload_len); | ||
317 | } | ||
318 | |||
319 | /* Cleanup. */ | ||
320 | if (close(fd_tx_raw)) | ||
321 | error(1, errno, "close tx_raw"); | ||
322 | if (close(fd_rx_udp)) | ||
323 | error(1, errno, "close rx_udp"); | ||
324 | |||
325 | if (cfg_verbose) | ||
326 | printf("processed %d messages, %d fragments\n", | ||
327 | msg_counter, frag_counter); | ||
328 | |||
329 | fprintf(stderr, "PASS\n"); | ||
330 | } | ||
331 | |||
332 | |||
333 | static void run_test_v4(void) | ||
334 | { | ||
335 | struct sockaddr_in addr = {0}; | ||
336 | |||
337 | addr.sin_family = AF_INET; | ||
338 | addr.sin_port = htons(cfg_port); | ||
339 | addr.sin_addr = addr4; | ||
340 | |||
341 | run_test((void *)&addr, sizeof(addr), false /* !ipv6 */); | ||
342 | } | ||
343 | |||
344 | static void run_test_v6(void) | ||
345 | { | ||
346 | struct sockaddr_in6 addr = {0}; | ||
347 | |||
348 | addr.sin6_family = AF_INET6; | ||
349 | addr.sin6_port = htons(cfg_port); | ||
350 | addr.sin6_addr = addr6; | ||
351 | |||
352 | run_test((void *)&addr, sizeof(addr), true /* ipv6 */); | ||
353 | } | ||
354 | |||
355 | static void parse_opts(int argc, char **argv) | ||
356 | { | ||
357 | int c; | ||
358 | |||
359 | while ((c = getopt(argc, argv, "46ov")) != -1) { | ||
360 | switch (c) { | ||
361 | case '4': | ||
362 | cfg_do_ipv4 = true; | ||
363 | break; | ||
364 | case '6': | ||
365 | cfg_do_ipv6 = true; | ||
366 | break; | ||
367 | case 'o': | ||
368 | cfg_overlap = true; | ||
369 | break; | ||
370 | case 'v': | ||
371 | cfg_verbose = true; | ||
372 | break; | ||
373 | default: | ||
374 | error(1, 0, "%s: parse error", argv[0]); | ||
375 | } | ||
376 | } | ||
377 | } | ||
378 | |||
379 | int main(int argc, char **argv) | ||
380 | { | ||
381 | parse_opts(argc, argv); | ||
382 | seed = time(NULL); | ||
383 | srand(seed); | ||
384 | /* Print the seed to track/reproduce potential failures. */ | ||
385 | printf("seed = %d\n", seed); | ||
386 | |||
387 | if (cfg_do_ipv4) | ||
388 | run_test_v4(); | ||
389 | if (cfg_do_ipv6) | ||
390 | run_test_v6(); | ||
391 | |||
392 | return 0; | ||
393 | } | ||
diff --git a/tools/testing/selftests/net/ip_defrag.sh b/tools/testing/selftests/net/ip_defrag.sh new file mode 100755 index 000000000000..f34672796044 --- /dev/null +++ b/tools/testing/selftests/net/ip_defrag.sh | |||
@@ -0,0 +1,39 @@ | |||
1 | #!/bin/sh | ||
2 | # SPDX-License-Identifier: GPL-2.0 | ||
3 | # | ||
4 | # Run a couple of IP defragmentation tests. | ||
5 | |||
6 | set +x | ||
7 | set -e | ||
8 | |||
9 | readonly NETNS="ns-$(mktemp -u XXXXXX)" | ||
10 | |||
11 | setup() { | ||
12 | ip netns add "${NETNS}" | ||
13 | ip -netns "${NETNS}" link set lo up | ||
14 | ip netns exec "${NETNS}" sysctl -w net.ipv4.ipfrag_high_thresh=9000000 >/dev/null 2>&1 | ||
15 | ip netns exec "${NETNS}" sysctl -w net.ipv4.ipfrag_low_thresh=7000000 >/dev/null 2>&1 | ||
16 | ip netns exec "${NETNS}" sysctl -w net.ipv6.ip6frag_high_thresh=9000000 >/dev/null 2>&1 | ||
17 | ip netns exec "${NETNS}" sysctl -w net.ipv6.ip6frag_low_thresh=7000000 >/dev/null 2>&1 | ||
18 | } | ||
19 | |||
20 | cleanup() { | ||
21 | ip netns del "${NETNS}" | ||
22 | } | ||
23 | |||
24 | trap cleanup EXIT | ||
25 | setup | ||
26 | |||
27 | echo "ipv4 defrag" | ||
28 | ip netns exec "${NETNS}" ./ip_defrag -4 | ||
29 | |||
30 | |||
31 | echo "ipv4 defrag with overlaps" | ||
32 | ip netns exec "${NETNS}" ./ip_defrag -4o | ||
33 | |||
34 | echo "ipv6 defrag" | ||
35 | ip netns exec "${NETNS}" ./ip_defrag -6 | ||
36 | |||
37 | echo "ipv6 defrag with overlaps" | ||
38 | ip netns exec "${NETNS}" ./ip_defrag -6o | ||
39 | |||
diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh index 0ab9423d009f..a369d616b390 100755 --- a/tools/testing/selftests/net/pmtu.sh +++ b/tools/testing/selftests/net/pmtu.sh | |||
@@ -6,6 +6,26 @@ | |||
6 | # | 6 | # |
7 | # Tests currently implemented: | 7 | # Tests currently implemented: |
8 | # | 8 | # |
9 | # - pmtu_ipv4 | ||
10 | # Set up two namespaces, A and B, with two paths between them over routers | ||
11 | # R1 and R2 (also implemented with namespaces), with different MTUs: | ||
12 | # | ||
13 | # segment a_r1 segment b_r1 a_r1: 2000 | ||
14 | # .--------------R1--------------. a_r2: 1500 | ||
15 | # A B a_r3: 2000 | ||
16 | # '--------------R2--------------' a_r4: 1400 | ||
17 | # segment a_r2 segment b_r2 | ||
18 | # | ||
19 | # Check that PMTU exceptions with the correct PMTU are created. Then | ||
20 | # decrease and increase the MTU of the local link for one of the paths, | ||
21 | # A to R1, checking that route exception PMTU changes accordingly over | ||
22 | # this path. Also check that locked exceptions are created when an ICMP | ||
23 | # message advertising a PMTU smaller than net.ipv4.route.min_pmtu is | ||
24 | # received | ||
25 | # | ||
26 | # - pmtu_ipv6 | ||
27 | # Same as pmtu_ipv4, except for locked PMTU tests, using IPv6 | ||
28 | # | ||
9 | # - pmtu_vti4_exception | 29 | # - pmtu_vti4_exception |
10 | # Set up vti tunnel on top of veth, with xfrm states and policies, in two | 30 | # Set up vti tunnel on top of veth, with xfrm states and policies, in two |
11 | # namespaces with matching endpoints. Check that route exception is not | 31 | # namespaces with matching endpoints. Check that route exception is not |
@@ -50,6 +70,8 @@ ksft_skip=4 | |||
50 | which ping6 > /dev/null 2>&1 && ping6=$(which ping6) || ping6=$(which ping) | 70 | which ping6 > /dev/null 2>&1 && ping6=$(which ping6) || ping6=$(which ping) |
51 | 71 | ||
52 | tests=" | 72 | tests=" |
73 | pmtu_ipv4_exception ipv4: PMTU exceptions | ||
74 | pmtu_ipv6_exception ipv6: PMTU exceptions | ||
53 | pmtu_vti6_exception vti6: PMTU exceptions | 75 | pmtu_vti6_exception vti6: PMTU exceptions |
54 | pmtu_vti4_exception vti4: PMTU exceptions | 76 | pmtu_vti4_exception vti4: PMTU exceptions |
55 | pmtu_vti4_default_mtu vti4: default MTU assignment | 77 | pmtu_vti4_default_mtu vti4: default MTU assignment |
@@ -60,8 +82,45 @@ tests=" | |||
60 | 82 | ||
61 | NS_A="ns-$(mktemp -u XXXXXX)" | 83 | NS_A="ns-$(mktemp -u XXXXXX)" |
62 | NS_B="ns-$(mktemp -u XXXXXX)" | 84 | NS_B="ns-$(mktemp -u XXXXXX)" |
85 | NS_R1="ns-$(mktemp -u XXXXXX)" | ||
86 | NS_R2="ns-$(mktemp -u XXXXXX)" | ||
63 | ns_a="ip netns exec ${NS_A}" | 87 | ns_a="ip netns exec ${NS_A}" |
64 | ns_b="ip netns exec ${NS_B}" | 88 | ns_b="ip netns exec ${NS_B}" |
89 | ns_r1="ip netns exec ${NS_R1}" | ||
90 | ns_r2="ip netns exec ${NS_R2}" | ||
91 | |||
92 | # Addressing and routing for tests with routers: four network segments, with | ||
93 | # index SEGMENT between 1 and 4, a common prefix (PREFIX4 or PREFIX6) and an | ||
94 | # identifier ID, which is 1 for hosts (A and B), 2 for routers (R1 and R2). | ||
95 | # Addresses are: | ||
96 | # - IPv4: PREFIX4.SEGMENT.ID (/24) | ||
97 | # - IPv6: PREFIX6:SEGMENT::ID (/64) | ||
98 | prefix4="192.168" | ||
99 | prefix6="fd00" | ||
100 | a_r1=1 | ||
101 | a_r2=2 | ||
102 | b_r1=3 | ||
103 | b_r2=4 | ||
104 | # ns peer segment | ||
105 | routing_addrs=" | ||
106 | A R1 ${a_r1} | ||
107 | A R2 ${a_r2} | ||
108 | B R1 ${b_r1} | ||
109 | B R2 ${b_r2} | ||
110 | " | ||
111 | # Traffic from A to B goes through R1 by default, and through R2, if destined to | ||
112 | # B's address on the b_r2 segment. | ||
113 | # Traffic from B to A goes through R1. | ||
114 | # ns destination gateway | ||
115 | routes=" | ||
116 | A default ${prefix4}.${a_r1}.2 | ||
117 | A ${prefix4}.${b_r2}.1 ${prefix4}.${a_r2}.2 | ||
118 | B default ${prefix4}.${b_r1}.2 | ||
119 | |||
120 | A default ${prefix6}:${a_r1}::2 | ||
121 | A ${prefix6}:${b_r2}::1 ${prefix6}:${a_r2}::2 | ||
122 | B default ${prefix6}:${b_r1}::2 | ||
123 | " | ||
65 | 124 | ||
66 | veth4_a_addr="192.168.1.1" | 125 | veth4_a_addr="192.168.1.1" |
67 | veth4_b_addr="192.168.1.2" | 126 | veth4_b_addr="192.168.1.2" |
@@ -83,6 +142,7 @@ dummy6_mask="64" | |||
83 | 142 | ||
84 | cleanup_done=1 | 143 | cleanup_done=1 |
85 | err_buf= | 144 | err_buf= |
145 | tcpdump_pids= | ||
86 | 146 | ||
87 | err() { | 147 | err() { |
88 | err_buf="${err_buf}${1} | 148 | err_buf="${err_buf}${1} |
@@ -94,9 +154,15 @@ err_flush() { | |||
94 | err_buf= | 154 | err_buf= |
95 | } | 155 | } |
96 | 156 | ||
157 | # Find the auto-generated name for this namespace | ||
158 | nsname() { | ||
159 | eval echo \$NS_$1 | ||
160 | } | ||
161 | |||
97 | setup_namespaces() { | 162 | setup_namespaces() { |
98 | ip netns add ${NS_A} || return 1 | 163 | for n in ${NS_A} ${NS_B} ${NS_R1} ${NS_R2}; do |
99 | ip netns add ${NS_B} | 164 | ip netns add ${n} || return 1 |
165 | done | ||
100 | } | 166 | } |
101 | 167 | ||
102 | setup_veth() { | 168 | setup_veth() { |
@@ -167,6 +233,49 @@ setup_xfrm6() { | |||
167 | setup_xfrm 6 ${veth6_a_addr} ${veth6_b_addr} | 233 | setup_xfrm 6 ${veth6_a_addr} ${veth6_b_addr} |
168 | } | 234 | } |
169 | 235 | ||
236 | setup_routing() { | ||
237 | for i in ${NS_R1} ${NS_R2}; do | ||
238 | ip netns exec ${i} sysctl -q net/ipv4/ip_forward=1 | ||
239 | ip netns exec ${i} sysctl -q net/ipv6/conf/all/forwarding=1 | ||
240 | done | ||
241 | |||
242 | for i in ${routing_addrs}; do | ||
243 | [ "${ns}" = "" ] && ns="${i}" && continue | ||
244 | [ "${peer}" = "" ] && peer="${i}" && continue | ||
245 | [ "${segment}" = "" ] && segment="${i}" | ||
246 | |||
247 | ns_name="$(nsname ${ns})" | ||
248 | peer_name="$(nsname ${peer})" | ||
249 | if="veth_${ns}-${peer}" | ||
250 | ifpeer="veth_${peer}-${ns}" | ||
251 | |||
252 | # Create veth links | ||
253 | ip link add ${if} up netns ${ns_name} type veth peer name ${ifpeer} netns ${peer_name} || return 1 | ||
254 | ip -n ${peer_name} link set dev ${ifpeer} up | ||
255 | |||
256 | # Add addresses | ||
257 | ip -n ${ns_name} addr add ${prefix4}.${segment}.1/24 dev ${if} | ||
258 | ip -n ${ns_name} addr add ${prefix6}:${segment}::1/64 dev ${if} | ||
259 | |||
260 | ip -n ${peer_name} addr add ${prefix4}.${segment}.2/24 dev ${ifpeer} | ||
261 | ip -n ${peer_name} addr add ${prefix6}:${segment}::2/64 dev ${ifpeer} | ||
262 | |||
263 | ns=""; peer=""; segment="" | ||
264 | done | ||
265 | |||
266 | for i in ${routes}; do | ||
267 | [ "${ns}" = "" ] && ns="${i}" && continue | ||
268 | [ "${addr}" = "" ] && addr="${i}" && continue | ||
269 | [ "${gw}" = "" ] && gw="${i}" | ||
270 | |||
271 | ns_name="$(nsname ${ns})" | ||
272 | |||
273 | ip -n ${ns_name} route add ${addr} via ${gw} | ||
274 | |||
275 | ns=""; addr=""; gw="" | ||
276 | done | ||
277 | } | ||
278 | |||
170 | setup() { | 279 | setup() { |
171 | [ "$(id -u)" -ne 0 ] && echo " need to run as root" && return $ksft_skip | 280 | [ "$(id -u)" -ne 0 ] && echo " need to run as root" && return $ksft_skip |
172 | 281 | ||
@@ -176,10 +285,28 @@ setup() { | |||
176 | done | 285 | done |
177 | } | 286 | } |
178 | 287 | ||
288 | trace() { | ||
289 | [ $tracing -eq 0 ] && return | ||
290 | |||
291 | for arg do | ||
292 | [ "${ns_cmd}" = "" ] && ns_cmd="${arg}" && continue | ||
293 | ${ns_cmd} tcpdump -s 0 -i "${arg}" -w "${name}_${arg}.pcap" 2> /dev/null & | ||
294 | tcpdump_pids="${tcpdump_pids} $!" | ||
295 | ns_cmd= | ||
296 | done | ||
297 | sleep 1 | ||
298 | } | ||
299 | |||
179 | cleanup() { | 300 | cleanup() { |
301 | for pid in ${tcpdump_pids}; do | ||
302 | kill ${pid} | ||
303 | done | ||
304 | tcpdump_pids= | ||
305 | |||
180 | [ ${cleanup_done} -eq 1 ] && return | 306 | [ ${cleanup_done} -eq 1 ] && return |
181 | ip netns del ${NS_A} 2> /dev/null | 307 | for n in ${NS_A} ${NS_B} ${NS_R1} ${NS_R2}; do |
182 | ip netns del ${NS_B} 2> /dev/null | 308 | ip netns del ${n} 2> /dev/null |
309 | done | ||
183 | cleanup_done=1 | 310 | cleanup_done=1 |
184 | } | 311 | } |
185 | 312 | ||
@@ -196,7 +323,9 @@ mtu_parse() { | |||
196 | 323 | ||
197 | next=0 | 324 | next=0 |
198 | for i in ${input}; do | 325 | for i in ${input}; do |
326 | [ ${next} -eq 1 -a "${i}" = "lock" ] && next=2 && continue | ||
199 | [ ${next} -eq 1 ] && echo "${i}" && return | 327 | [ ${next} -eq 1 ] && echo "${i}" && return |
328 | [ ${next} -eq 2 ] && echo "lock ${i}" && return | ||
200 | [ "${i}" = "mtu" ] && next=1 | 329 | [ "${i}" = "mtu" ] && next=1 |
201 | done | 330 | done |
202 | } | 331 | } |
@@ -229,8 +358,117 @@ route_get_dst_pmtu_from_exception() { | |||
229 | mtu_parse "$(route_get_dst_exception "${ns_cmd}" ${dst})" | 358 | mtu_parse "$(route_get_dst_exception "${ns_cmd}" ${dst})" |
230 | } | 359 | } |
231 | 360 | ||
361 | check_pmtu_value() { | ||
362 | expected="${1}" | ||
363 | value="${2}" | ||
364 | event="${3}" | ||
365 | |||
366 | [ "${expected}" = "any" ] && [ -n "${value}" ] && return 0 | ||
367 | [ "${value}" = "${expected}" ] && return 0 | ||
368 | [ -z "${value}" ] && err " PMTU exception wasn't created after ${event}" && return 1 | ||
369 | [ -z "${expected}" ] && err " PMTU exception shouldn't exist after ${event}" && return 1 | ||
370 | err " found PMTU exception with incorrect MTU ${value}, expected ${expected}, after ${event}" | ||
371 | return 1 | ||
372 | } | ||
373 | |||
374 | test_pmtu_ipvX() { | ||
375 | family=${1} | ||
376 | |||
377 | setup namespaces routing || return 2 | ||
378 | trace "${ns_a}" veth_A-R1 "${ns_r1}" veth_R1-A \ | ||
379 | "${ns_r1}" veth_R1-B "${ns_b}" veth_B-R1 \ | ||
380 | "${ns_a}" veth_A-R2 "${ns_r2}" veth_R2-A \ | ||
381 | "${ns_r2}" veth_R2-B "${ns_b}" veth_B-R2 | ||
382 | |||
383 | if [ ${family} -eq 4 ]; then | ||
384 | ping=ping | ||
385 | dst1="${prefix4}.${b_r1}.1" | ||
386 | dst2="${prefix4}.${b_r2}.1" | ||
387 | else | ||
388 | ping=${ping6} | ||
389 | dst1="${prefix6}:${b_r1}::1" | ||
390 | dst2="${prefix6}:${b_r2}::1" | ||
391 | fi | ||
392 | |||
393 | # Set up initial MTU values | ||
394 | mtu "${ns_a}" veth_A-R1 2000 | ||
395 | mtu "${ns_r1}" veth_R1-A 2000 | ||
396 | mtu "${ns_r1}" veth_R1-B 1400 | ||
397 | mtu "${ns_b}" veth_B-R1 1400 | ||
398 | |||
399 | mtu "${ns_a}" veth_A-R2 2000 | ||
400 | mtu "${ns_r2}" veth_R2-A 2000 | ||
401 | mtu "${ns_r2}" veth_R2-B 1500 | ||
402 | mtu "${ns_b}" veth_B-R2 1500 | ||
403 | |||
404 | # Create route exceptions | ||
405 | ${ns_a} ${ping} -q -M want -i 0.1 -w 2 -s 1800 ${dst1} > /dev/null | ||
406 | ${ns_a} ${ping} -q -M want -i 0.1 -w 2 -s 1800 ${dst2} > /dev/null | ||
407 | |||
408 | # Check that exceptions have been created with the correct PMTU | ||
409 | pmtu_1="$(route_get_dst_pmtu_from_exception "${ns_a}" ${dst1})" | ||
410 | check_pmtu_value "1400" "${pmtu_1}" "exceeding MTU" || return 1 | ||
411 | pmtu_2="$(route_get_dst_pmtu_from_exception "${ns_a}" ${dst2})" | ||
412 | check_pmtu_value "1500" "${pmtu_2}" "exceeding MTU" || return 1 | ||
413 | |||
414 | # Decrease local MTU below PMTU, check for PMTU decrease in route exception | ||
415 | mtu "${ns_a}" veth_A-R1 1300 | ||
416 | mtu "${ns_r1}" veth_R1-A 1300 | ||
417 | pmtu_1="$(route_get_dst_pmtu_from_exception "${ns_a}" ${dst1})" | ||
418 | check_pmtu_value "1300" "${pmtu_1}" "decreasing local MTU" || return 1 | ||
419 | # Second exception shouldn't be modified | ||
420 | pmtu_2="$(route_get_dst_pmtu_from_exception "${ns_a}" ${dst2})" | ||
421 | check_pmtu_value "1500" "${pmtu_2}" "changing local MTU on a link not on this path" || return 1 | ||
422 | |||
423 | # Increase MTU, check for PMTU increase in route exception | ||
424 | mtu "${ns_a}" veth_A-R1 1700 | ||
425 | mtu "${ns_r1}" veth_R1-A 1700 | ||
426 | pmtu_1="$(route_get_dst_pmtu_from_exception "${ns_a}" ${dst1})" | ||
427 | check_pmtu_value "1700" "${pmtu_1}" "increasing local MTU" || return 1 | ||
428 | # Second exception shouldn't be modified | ||
429 | pmtu_2="$(route_get_dst_pmtu_from_exception "${ns_a}" ${dst2})" | ||
430 | check_pmtu_value "1500" "${pmtu_2}" "changing local MTU on a link not on this path" || return 1 | ||
431 | |||
432 | # Skip PMTU locking tests for IPv6 | ||
433 | [ $family -eq 6 ] && return 0 | ||
434 | |||
435 | # Decrease remote MTU on path via R2, get new exception | ||
436 | mtu "${ns_r2}" veth_R2-B 400 | ||
437 | mtu "${ns_b}" veth_B-R2 400 | ||
438 | ${ns_a} ${ping} -q -M want -i 0.1 -w 2 -s 1400 ${dst2} > /dev/null | ||
439 | pmtu_2="$(route_get_dst_pmtu_from_exception "${ns_a}" ${dst2})" | ||
440 | check_pmtu_value "lock 552" "${pmtu_2}" "exceeding MTU, with MTU < min_pmtu" || return 1 | ||
441 | |||
442 | # Decrease local MTU below PMTU | ||
443 | mtu "${ns_a}" veth_A-R2 500 | ||
444 | mtu "${ns_r2}" veth_R2-A 500 | ||
445 | pmtu_2="$(route_get_dst_pmtu_from_exception "${ns_a}" ${dst2})" | ||
446 | check_pmtu_value "500" "${pmtu_2}" "decreasing local MTU" || return 1 | ||
447 | |||
448 | # Increase local MTU | ||
449 | mtu "${ns_a}" veth_A-R2 1500 | ||
450 | mtu "${ns_r2}" veth_R2-A 1500 | ||
451 | pmtu_2="$(route_get_dst_pmtu_from_exception "${ns_a}" ${dst2})" | ||
452 | check_pmtu_value "1500" "${pmtu_2}" "increasing local MTU" || return 1 | ||
453 | |||
454 | # Get new exception | ||
455 | ${ns_a} ${ping} -q -M want -i 0.1 -w 2 -s 1400 ${dst2} > /dev/null | ||
456 | pmtu_2="$(route_get_dst_pmtu_from_exception "${ns_a}" ${dst2})" | ||
457 | check_pmtu_value "lock 552" "${pmtu_2}" "exceeding MTU, with MTU < min_pmtu" || return 1 | ||
458 | } | ||
459 | |||
460 | test_pmtu_ipv4_exception() { | ||
461 | test_pmtu_ipvX 4 | ||
462 | } | ||
463 | |||
464 | test_pmtu_ipv6_exception() { | ||
465 | test_pmtu_ipvX 6 | ||
466 | } | ||
467 | |||
232 | test_pmtu_vti4_exception() { | 468 | test_pmtu_vti4_exception() { |
233 | setup namespaces veth vti4 xfrm4 || return 2 | 469 | setup namespaces veth vti4 xfrm4 || return 2 |
470 | trace "${ns_a}" veth_a "${ns_b}" veth_b \ | ||
471 | "${ns_a}" vti4_a "${ns_b}" vti4_b | ||
234 | 472 | ||
235 | veth_mtu=1500 | 473 | veth_mtu=1500 |
236 | vti_mtu=$((veth_mtu - 20)) | 474 | vti_mtu=$((veth_mtu - 20)) |
@@ -248,28 +486,19 @@ test_pmtu_vti4_exception() { | |||
248 | # exception is created | 486 | # exception is created |
249 | ${ns_a} ping -q -M want -i 0.1 -w 2 -s ${ping_payload} ${vti4_b_addr} > /dev/null | 487 | ${ns_a} ping -q -M want -i 0.1 -w 2 -s ${ping_payload} ${vti4_b_addr} > /dev/null |
250 | pmtu="$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti4_b_addr})" | 488 | pmtu="$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti4_b_addr})" |
251 | if [ "${pmtu}" != "" ]; then | 489 | check_pmtu_value "" "${pmtu}" "sending packet smaller than PMTU (IP payload length ${esp_payload_rfc4106})" || return 1 |
252 | err " unexpected exception created with PMTU ${pmtu} for IP payload length ${esp_payload_rfc4106}" | ||
253 | return 1 | ||
254 | fi | ||
255 | 490 | ||
256 | # Now exceed link layer MTU by one byte, check that exception is created | 491 | # Now exceed link layer MTU by one byte, check that exception is created |
492 | # with the right PMTU value | ||
257 | ${ns_a} ping -q -M want -i 0.1 -w 2 -s $((ping_payload + 1)) ${vti4_b_addr} > /dev/null | 493 | ${ns_a} ping -q -M want -i 0.1 -w 2 -s $((ping_payload + 1)) ${vti4_b_addr} > /dev/null |
258 | pmtu="$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti4_b_addr})" | 494 | pmtu="$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti4_b_addr})" |
259 | if [ "${pmtu}" = "" ]; then | 495 | check_pmtu_value "${esp_payload_rfc4106}" "${pmtu}" "exceeding PMTU (IP payload length $((esp_payload_rfc4106 + 1)))" |
260 | err " exception not created for IP payload length $((esp_payload_rfc4106 + 1))" | ||
261 | return 1 | ||
262 | fi | ||
263 | |||
264 | # ...with the right PMTU value | ||
265 | if [ ${pmtu} -ne ${esp_payload_rfc4106} ]; then | ||
266 | err " wrong PMTU ${pmtu} in exception, expected: ${esp_payload_rfc4106}" | ||
267 | return 1 | ||
268 | fi | ||
269 | } | 496 | } |
270 | 497 | ||
271 | test_pmtu_vti6_exception() { | 498 | test_pmtu_vti6_exception() { |
272 | setup namespaces veth vti6 xfrm6 || return 2 | 499 | setup namespaces veth vti6 xfrm6 || return 2 |
500 | trace "${ns_a}" veth_a "${ns_b}" veth_b \ | ||
501 | "${ns_a}" vti6_a "${ns_b}" vti6_b | ||
273 | fail=0 | 502 | fail=0 |
274 | 503 | ||
275 | # Create route exception by exceeding link layer MTU | 504 | # Create route exception by exceeding link layer MTU |
@@ -280,25 +509,18 @@ test_pmtu_vti6_exception() { | |||
280 | ${ns_a} ${ping6} -q -i 0.1 -w 2 -s 60000 ${vti6_b_addr} > /dev/null | 509 | ${ns_a} ${ping6} -q -i 0.1 -w 2 -s 60000 ${vti6_b_addr} > /dev/null |
281 | 510 | ||
282 | # Check that exception was created | 511 | # Check that exception was created |
283 | if [ "$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})" = "" ]; then | 512 | pmtu="$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})" |
284 | err " tunnel exceeding link layer MTU didn't create route exception" | 513 | check_pmtu_value any "${pmtu}" "creating tunnel exceeding link layer MTU" || return 1 |
285 | return 1 | ||
286 | fi | ||
287 | 514 | ||
288 | # Decrease tunnel MTU, check for PMTU decrease in route exception | 515 | # Decrease tunnel MTU, check for PMTU decrease in route exception |
289 | mtu "${ns_a}" vti6_a 3000 | 516 | mtu "${ns_a}" vti6_a 3000 |
290 | 517 | pmtu="$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})" | |
291 | if [ "$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})" -ne 3000 ]; then | 518 | check_pmtu_value "3000" "${pmtu}" "decreasing tunnel MTU" || fail=1 |
292 | err " decreasing tunnel MTU didn't decrease route exception PMTU" | ||
293 | fail=1 | ||
294 | fi | ||
295 | 519 | ||
296 | # Increase tunnel MTU, check for PMTU increase in route exception | 520 | # Increase tunnel MTU, check for PMTU increase in route exception |
297 | mtu "${ns_a}" vti6_a 9000 | 521 | mtu "${ns_a}" vti6_a 9000 |
298 | if [ "$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})" -ne 9000 ]; then | 522 | pmtu="$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})" |
299 | err " increasing tunnel MTU didn't increase route exception PMTU" | 523 | check_pmtu_value "9000" "${pmtu}" "increasing tunnel MTU" || fail=1 |
300 | fail=1 | ||
301 | fi | ||
302 | 524 | ||
303 | return ${fail} | 525 | return ${fail} |
304 | } | 526 | } |
@@ -445,15 +667,56 @@ test_pmtu_vti6_link_change_mtu() { | |||
445 | return ${fail} | 667 | return ${fail} |
446 | } | 668 | } |
447 | 669 | ||
448 | trap cleanup EXIT | 670 | usage() { |
671 | echo | ||
672 | echo "$0 [OPTIONS] [TEST]..." | ||
673 | echo "If no TEST argument is given, all tests will be run." | ||
674 | echo | ||
675 | echo "Options" | ||
676 | echo " --trace: capture traffic to TEST_INTERFACE.pcap" | ||
677 | echo | ||
678 | echo "Available tests${tests}" | ||
679 | exit 1 | ||
680 | } | ||
449 | 681 | ||
450 | exitcode=0 | 682 | exitcode=0 |
451 | desc=0 | 683 | desc=0 |
452 | IFS=" | 684 | IFS=" |
453 | " | 685 | " |
686 | |||
687 | tracing=0 | ||
688 | for arg do | ||
689 | if [ "${arg}" != "${arg#--*}" ]; then | ||
690 | opt="${arg#--}" | ||
691 | if [ "${opt}" = "trace" ]; then | ||
692 | if which tcpdump > /dev/null 2>&1; then | ||
693 | tracing=1 | ||
694 | else | ||
695 | echo "=== tcpdump not available, tracing disabled" | ||
696 | fi | ||
697 | else | ||
698 | usage | ||
699 | fi | ||
700 | else | ||
701 | # Check first that all requested tests are available before | ||
702 | # running any | ||
703 | command -v > /dev/null "test_${arg}" || { echo "=== Test ${arg} not found"; usage; } | ||
704 | fi | ||
705 | done | ||
706 | |||
707 | trap cleanup EXIT | ||
708 | |||
454 | for t in ${tests}; do | 709 | for t in ${tests}; do |
455 | [ $desc -eq 0 ] && name="${t}" && desc=1 && continue || desc=0 | 710 | [ $desc -eq 0 ] && name="${t}" && desc=1 && continue || desc=0 |
456 | 711 | ||
712 | run_this=1 | ||
713 | for arg do | ||
714 | [ "${arg}" != "${arg#--*}" ] && continue | ||
715 | [ "${arg}" = "${name}" ] && run_this=1 && break | ||
716 | run_this=0 | ||
717 | done | ||
718 | [ $run_this -eq 0 ] && continue | ||
719 | |||
457 | ( | 720 | ( |
458 | unset IFS | 721 | unset IFS |
459 | eval test_${name} | 722 | eval test_${name} |
diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c index 8fdfeafaf8c0..fac68d710f35 100644 --- a/tools/testing/selftests/net/tls.c +++ b/tools/testing/selftests/net/tls.c | |||
@@ -121,11 +121,11 @@ TEST_F(tls, send_then_sendfile) | |||
121 | buf = (char *)malloc(st.st_size); | 121 | buf = (char *)malloc(st.st_size); |
122 | 122 | ||
123 | EXPECT_EQ(send(self->fd, test_str, to_send, 0), to_send); | 123 | EXPECT_EQ(send(self->fd, test_str, to_send, 0), to_send); |
124 | EXPECT_EQ(recv(self->cfd, recv_buf, to_send, 0), to_send); | 124 | EXPECT_EQ(recv(self->cfd, recv_buf, to_send, MSG_WAITALL), to_send); |
125 | EXPECT_EQ(memcmp(test_str, recv_buf, to_send), 0); | 125 | EXPECT_EQ(memcmp(test_str, recv_buf, to_send), 0); |
126 | 126 | ||
127 | EXPECT_GE(sendfile(self->fd, filefd, 0, st.st_size), 0); | 127 | EXPECT_GE(sendfile(self->fd, filefd, 0, st.st_size), 0); |
128 | EXPECT_EQ(recv(self->cfd, buf, st.st_size, 0), st.st_size); | 128 | EXPECT_EQ(recv(self->cfd, buf, st.st_size, MSG_WAITALL), st.st_size); |
129 | } | 129 | } |
130 | 130 | ||
131 | TEST_F(tls, recv_max) | 131 | TEST_F(tls, recv_max) |
@@ -160,7 +160,7 @@ TEST_F(tls, msg_more) | |||
160 | EXPECT_EQ(send(self->fd, test_str, send_len, MSG_MORE), send_len); | 160 | EXPECT_EQ(send(self->fd, test_str, send_len, MSG_MORE), send_len); |
161 | EXPECT_EQ(recv(self->cfd, buf, send_len, MSG_DONTWAIT), -1); | 161 | EXPECT_EQ(recv(self->cfd, buf, send_len, MSG_DONTWAIT), -1); |
162 | EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len); | 162 | EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len); |
163 | EXPECT_EQ(recv(self->cfd, buf, send_len * 2, MSG_DONTWAIT), | 163 | EXPECT_EQ(recv(self->cfd, buf, send_len * 2, MSG_WAITALL), |
164 | send_len * 2); | 164 | send_len * 2); |
165 | EXPECT_EQ(memcmp(buf, test_str, send_len), 0); | 165 | EXPECT_EQ(memcmp(buf, test_str, send_len), 0); |
166 | } | 166 | } |
@@ -180,7 +180,7 @@ TEST_F(tls, sendmsg_single) | |||
180 | msg.msg_iov = &vec; | 180 | msg.msg_iov = &vec; |
181 | msg.msg_iovlen = 1; | 181 | msg.msg_iovlen = 1; |
182 | EXPECT_EQ(sendmsg(self->fd, &msg, 0), send_len); | 182 | EXPECT_EQ(sendmsg(self->fd, &msg, 0), send_len); |
183 | EXPECT_EQ(recv(self->cfd, buf, send_len, 0), send_len); | 183 | EXPECT_EQ(recv(self->cfd, buf, send_len, MSG_WAITALL), send_len); |
184 | EXPECT_EQ(memcmp(buf, test_str, send_len), 0); | 184 | EXPECT_EQ(memcmp(buf, test_str, send_len), 0); |
185 | } | 185 | } |
186 | 186 | ||
@@ -288,7 +288,7 @@ TEST_F(tls, splice_from_pipe) | |||
288 | ASSERT_GE(pipe(p), 0); | 288 | ASSERT_GE(pipe(p), 0); |
289 | EXPECT_GE(write(p[1], mem_send, send_len), 0); | 289 | EXPECT_GE(write(p[1], mem_send, send_len), 0); |
290 | EXPECT_GE(splice(p[0], NULL, self->fd, NULL, send_len, 0), 0); | 290 | EXPECT_GE(splice(p[0], NULL, self->fd, NULL, send_len, 0), 0); |
291 | EXPECT_GE(recv(self->cfd, mem_recv, send_len, 0), 0); | 291 | EXPECT_EQ(recv(self->cfd, mem_recv, send_len, MSG_WAITALL), send_len); |
292 | EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0); | 292 | EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0); |
293 | } | 293 | } |
294 | 294 | ||
@@ -306,7 +306,7 @@ TEST_F(tls, splice_from_pipe2) | |||
306 | EXPECT_GE(splice(p[0], NULL, self->fd, NULL, 8000, 0), 0); | 306 | EXPECT_GE(splice(p[0], NULL, self->fd, NULL, 8000, 0), 0); |
307 | EXPECT_GE(write(p2[1], mem_send + 8000, 8000), 0); | 307 | EXPECT_GE(write(p2[1], mem_send + 8000, 8000), 0); |
308 | EXPECT_GE(splice(p2[0], NULL, self->fd, NULL, 8000, 0), 0); | 308 | EXPECT_GE(splice(p2[0], NULL, self->fd, NULL, 8000, 0), 0); |
309 | EXPECT_GE(recv(self->cfd, mem_recv, send_len, 0), 0); | 309 | EXPECT_EQ(recv(self->cfd, mem_recv, send_len, MSG_WAITALL), send_len); |
310 | EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0); | 310 | EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0); |
311 | } | 311 | } |
312 | 312 | ||
@@ -322,13 +322,13 @@ TEST_F(tls, send_and_splice) | |||
322 | 322 | ||
323 | ASSERT_GE(pipe(p), 0); | 323 | ASSERT_GE(pipe(p), 0); |
324 | EXPECT_EQ(send(self->fd, test_str, send_len2, 0), send_len2); | 324 | EXPECT_EQ(send(self->fd, test_str, send_len2, 0), send_len2); |
325 | EXPECT_NE(recv(self->cfd, buf, send_len2, 0), -1); | 325 | EXPECT_EQ(recv(self->cfd, buf, send_len2, MSG_WAITALL), send_len2); |
326 | EXPECT_EQ(memcmp(test_str, buf, send_len2), 0); | 326 | EXPECT_EQ(memcmp(test_str, buf, send_len2), 0); |
327 | 327 | ||
328 | EXPECT_GE(write(p[1], mem_send, send_len), send_len); | 328 | EXPECT_GE(write(p[1], mem_send, send_len), send_len); |
329 | EXPECT_GE(splice(p[0], NULL, self->fd, NULL, send_len, 0), send_len); | 329 | EXPECT_GE(splice(p[0], NULL, self->fd, NULL, send_len, 0), send_len); |
330 | 330 | ||
331 | EXPECT_GE(recv(self->cfd, mem_recv, send_len, 0), 0); | 331 | EXPECT_EQ(recv(self->cfd, mem_recv, send_len, MSG_WAITALL), send_len); |
332 | EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0); | 332 | EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0); |
333 | } | 333 | } |
334 | 334 | ||
@@ -436,7 +436,7 @@ TEST_F(tls, multiple_send_single_recv) | |||
436 | EXPECT_GE(send(self->fd, send_mem, send_len, 0), 0); | 436 | EXPECT_GE(send(self->fd, send_mem, send_len, 0), 0); |
437 | EXPECT_GE(send(self->fd, send_mem, send_len, 0), 0); | 437 | EXPECT_GE(send(self->fd, send_mem, send_len, 0), 0); |
438 | memset(recv_mem, 0, total_len); | 438 | memset(recv_mem, 0, total_len); |
439 | EXPECT_EQ(recv(self->cfd, recv_mem, total_len, 0), total_len); | 439 | EXPECT_EQ(recv(self->cfd, recv_mem, total_len, MSG_WAITALL), total_len); |
440 | 440 | ||
441 | EXPECT_EQ(memcmp(send_mem, recv_mem, send_len), 0); | 441 | EXPECT_EQ(memcmp(send_mem, recv_mem, send_len), 0); |
442 | EXPECT_EQ(memcmp(send_mem, recv_mem + send_len, send_len), 0); | 442 | EXPECT_EQ(memcmp(send_mem, recv_mem + send_len, send_len), 0); |
@@ -516,17 +516,17 @@ TEST_F(tls, recv_peek_multiple_records) | |||
516 | len = strlen(test_str_second) + 1; | 516 | len = strlen(test_str_second) + 1; |
517 | EXPECT_EQ(send(self->fd, test_str_second, len, 0), len); | 517 | EXPECT_EQ(send(self->fd, test_str_second, len, 0), len); |
518 | 518 | ||
519 | len = sizeof(buf); | 519 | len = strlen(test_str_first); |
520 | memset(buf, 0, len); | 520 | memset(buf, 0, len); |
521 | EXPECT_NE(recv(self->cfd, buf, len, MSG_PEEK), -1); | 521 | EXPECT_EQ(recv(self->cfd, buf, len, MSG_PEEK | MSG_WAITALL), len); |
522 | 522 | ||
523 | /* MSG_PEEK can only peek into the current record. */ | 523 | /* MSG_PEEK can only peek into the current record. */ |
524 | len = strlen(test_str_first) + 1; | 524 | len = strlen(test_str_first); |
525 | EXPECT_EQ(memcmp(test_str_first, buf, len), 0); | 525 | EXPECT_EQ(memcmp(test_str_first, buf, len), 0); |
526 | 526 | ||
527 | len = sizeof(buf); | 527 | len = strlen(test_str) + 1; |
528 | memset(buf, 0, len); | 528 | memset(buf, 0, len); |
529 | EXPECT_NE(recv(self->cfd, buf, len, 0), -1); | 529 | EXPECT_EQ(recv(self->cfd, buf, len, MSG_WAITALL), len); |
530 | 530 | ||
531 | /* Non-MSG_PEEK will advance strparser (and therefore record) | 531 | /* Non-MSG_PEEK will advance strparser (and therefore record) |
532 | * however. | 532 | * however. |
@@ -543,6 +543,28 @@ TEST_F(tls, recv_peek_multiple_records) | |||
543 | len = strlen(test_str_second) + 1; | 543 | len = strlen(test_str_second) + 1; |
544 | EXPECT_EQ(send(self->fd, test_str_second, len, 0), len); | 544 | EXPECT_EQ(send(self->fd, test_str_second, len, 0), len); |
545 | 545 | ||
546 | len = strlen(test_str) + 1; | ||
547 | memset(buf, 0, len); | ||
548 | EXPECT_EQ(recv(self->cfd, buf, len, MSG_PEEK | MSG_WAITALL), len); | ||
549 | |||
550 | len = strlen(test_str) + 1; | ||
551 | EXPECT_EQ(memcmp(test_str, buf, len), 0); | ||
552 | } | ||
553 | |||
554 | TEST_F(tls, recv_peek_large_buf_mult_recs) | ||
555 | { | ||
556 | char const *test_str = "test_read_peek_mult_recs"; | ||
557 | char const *test_str_first = "test_read_peek"; | ||
558 | char const *test_str_second = "_mult_recs"; | ||
559 | int len; | ||
560 | char buf[64]; | ||
561 | |||
562 | len = strlen(test_str_first); | ||
563 | EXPECT_EQ(send(self->fd, test_str_first, len, 0), len); | ||
564 | |||
565 | len = strlen(test_str_second) + 1; | ||
566 | EXPECT_EQ(send(self->fd, test_str_second, len, 0), len); | ||
567 | |||
546 | len = sizeof(buf); | 568 | len = sizeof(buf); |
547 | memset(buf, 0, len); | 569 | memset(buf, 0, len); |
548 | EXPECT_NE(recv(self->cfd, buf, len, MSG_PEEK), -1); | 570 | EXPECT_NE(recv(self->cfd, buf, len, MSG_PEEK), -1); |
@@ -551,6 +573,7 @@ TEST_F(tls, recv_peek_multiple_records) | |||
551 | EXPECT_EQ(memcmp(test_str, buf, len), 0); | 573 | EXPECT_EQ(memcmp(test_str, buf, len), 0); |
552 | } | 574 | } |
553 | 575 | ||
576 | |||
554 | TEST_F(tls, pollin) | 577 | TEST_F(tls, pollin) |
555 | { | 578 | { |
556 | char const *test_str = "test_poll"; | 579 | char const *test_str = "test_poll"; |
@@ -564,7 +587,7 @@ TEST_F(tls, pollin) | |||
564 | 587 | ||
565 | EXPECT_EQ(poll(&fd, 1, 20), 1); | 588 | EXPECT_EQ(poll(&fd, 1, 20), 1); |
566 | EXPECT_EQ(fd.revents & POLLIN, 1); | 589 | EXPECT_EQ(fd.revents & POLLIN, 1); |
567 | EXPECT_EQ(recv(self->cfd, buf, send_len, 0), send_len); | 590 | EXPECT_EQ(recv(self->cfd, buf, send_len, MSG_WAITALL), send_len); |
568 | /* Test timing out */ | 591 | /* Test timing out */ |
569 | EXPECT_EQ(poll(&fd, 1, 20), 0); | 592 | EXPECT_EQ(poll(&fd, 1, 20), 0); |
570 | } | 593 | } |
@@ -582,7 +605,7 @@ TEST_F(tls, poll_wait) | |||
582 | /* Set timeout to inf. secs */ | 605 | /* Set timeout to inf. secs */ |
583 | EXPECT_EQ(poll(&fd, 1, -1), 1); | 606 | EXPECT_EQ(poll(&fd, 1, -1), 1); |
584 | EXPECT_EQ(fd.revents & POLLIN, 1); | 607 | EXPECT_EQ(fd.revents & POLLIN, 1); |
585 | EXPECT_EQ(recv(self->cfd, recv_mem, send_len, 0), send_len); | 608 | EXPECT_EQ(recv(self->cfd, recv_mem, send_len, MSG_WAITALL), send_len); |
586 | } | 609 | } |
587 | 610 | ||
588 | TEST_F(tls, blocking) | 611 | TEST_F(tls, blocking) |
@@ -728,7 +751,7 @@ TEST_F(tls, control_msg) | |||
728 | EXPECT_EQ(recv(self->cfd, buf, send_len, 0), -1); | 751 | EXPECT_EQ(recv(self->cfd, buf, send_len, 0), -1); |
729 | 752 | ||
730 | vec.iov_base = buf; | 753 | vec.iov_base = buf; |
731 | EXPECT_EQ(recvmsg(self->cfd, &msg, 0), send_len); | 754 | EXPECT_EQ(recvmsg(self->cfd, &msg, MSG_WAITALL), send_len); |
732 | cmsg = CMSG_FIRSTHDR(&msg); | 755 | cmsg = CMSG_FIRSTHDR(&msg); |
733 | EXPECT_NE(cmsg, NULL); | 756 | EXPECT_NE(cmsg, NULL); |
734 | EXPECT_EQ(cmsg->cmsg_level, SOL_TLS); | 757 | EXPECT_EQ(cmsg->cmsg_level, SOL_TLS); |
diff --git a/tools/testing/selftests/powerpc/Makefile b/tools/testing/selftests/powerpc/Makefile index 201b598558b9..b3ad909aefbc 100644 --- a/tools/testing/selftests/powerpc/Makefile +++ b/tools/testing/selftests/powerpc/Makefile | |||
@@ -28,7 +28,8 @@ SUB_DIRS = alignment \ | |||
28 | tm \ | 28 | tm \ |
29 | vphn \ | 29 | vphn \ |
30 | math \ | 30 | math \ |
31 | ptrace | 31 | ptrace \ |
32 | security | ||
32 | 33 | ||
33 | endif | 34 | endif |
34 | 35 | ||
diff --git a/tools/testing/selftests/powerpc/include/reg.h b/tools/testing/selftests/powerpc/include/reg.h index 7f348c059bc2..52b4710469d2 100644 --- a/tools/testing/selftests/powerpc/include/reg.h +++ b/tools/testing/selftests/powerpc/include/reg.h | |||
@@ -17,6 +17,7 @@ | |||
17 | : "memory") | 17 | : "memory") |
18 | 18 | ||
19 | #define mb() asm volatile("sync" : : : "memory"); | 19 | #define mb() asm volatile("sync" : : : "memory"); |
20 | #define barrier() asm volatile("" : : : "memory"); | ||
20 | 21 | ||
21 | #define SPRN_MMCR2 769 | 22 | #define SPRN_MMCR2 769 |
22 | #define SPRN_MMCRA 770 | 23 | #define SPRN_MMCRA 770 |
diff --git a/tools/testing/selftests/powerpc/include/utils.h b/tools/testing/selftests/powerpc/include/utils.h index c58c370828b4..49621822d7c3 100644 --- a/tools/testing/selftests/powerpc/include/utils.h +++ b/tools/testing/selftests/powerpc/include/utils.h | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <stdint.h> | 11 | #include <stdint.h> |
12 | #include <stdbool.h> | 12 | #include <stdbool.h> |
13 | #include <linux/auxvec.h> | 13 | #include <linux/auxvec.h> |
14 | #include <linux/perf_event.h> | ||
14 | #include "reg.h" | 15 | #include "reg.h" |
15 | 16 | ||
16 | /* Avoid headaches with PRI?64 - just use %ll? always */ | 17 | /* Avoid headaches with PRI?64 - just use %ll? always */ |
@@ -31,6 +32,15 @@ void *get_auxv_entry(int type); | |||
31 | 32 | ||
32 | int pick_online_cpu(void); | 33 | int pick_online_cpu(void); |
33 | 34 | ||
35 | int read_debugfs_file(char *debugfs_file, int *result); | ||
36 | int write_debugfs_file(char *debugfs_file, int result); | ||
37 | void set_dscr(unsigned long val); | ||
38 | int perf_event_open_counter(unsigned int type, | ||
39 | unsigned long config, int group_fd); | ||
40 | int perf_event_enable(int fd); | ||
41 | int perf_event_disable(int fd); | ||
42 | int perf_event_reset(int fd); | ||
43 | |||
34 | static inline bool have_hwcap(unsigned long ftr) | 44 | static inline bool have_hwcap(unsigned long ftr) |
35 | { | 45 | { |
36 | return ((unsigned long)get_auxv_entry(AT_HWCAP) & ftr) == ftr; | 46 | return ((unsigned long)get_auxv_entry(AT_HWCAP) & ftr) == ftr; |
@@ -80,4 +90,12 @@ do { \ | |||
80 | #define PPC_FEATURE2_ARCH_3_00 0x00800000 | 90 | #define PPC_FEATURE2_ARCH_3_00 0x00800000 |
81 | #endif | 91 | #endif |
82 | 92 | ||
93 | #if defined(__powerpc64__) | ||
94 | #define UCONTEXT_NIA(UC) (UC)->uc_mcontext.gp_regs[PT_NIP] | ||
95 | #elif defined(__powerpc__) | ||
96 | #define UCONTEXT_NIA(UC) (UC)->uc_mcontext.uc_regs->gregs[PT_NIP] | ||
97 | #else | ||
98 | #error implement UCONTEXT_NIA | ||
99 | #endif | ||
100 | |||
83 | #endif /* _SELFTESTS_POWERPC_UTILS_H */ | 101 | #endif /* _SELFTESTS_POWERPC_UTILS_H */ |
diff --git a/tools/testing/selftests/powerpc/mm/.gitignore b/tools/testing/selftests/powerpc/mm/.gitignore index 7d7c42ed6de9..ba919308fe30 100644 --- a/tools/testing/selftests/powerpc/mm/.gitignore +++ b/tools/testing/selftests/powerpc/mm/.gitignore | |||
@@ -2,4 +2,5 @@ hugetlb_vs_thp_test | |||
2 | subpage_prot | 2 | subpage_prot |
3 | tempfile | 3 | tempfile |
4 | prot_sao | 4 | prot_sao |
5 | segv_errors \ No newline at end of file | 5 | segv_errors |
6 | wild_bctr \ No newline at end of file | ||
diff --git a/tools/testing/selftests/powerpc/mm/Makefile b/tools/testing/selftests/powerpc/mm/Makefile index 33ced6e0ad25..43d68420e363 100644 --- a/tools/testing/selftests/powerpc/mm/Makefile +++ b/tools/testing/selftests/powerpc/mm/Makefile | |||
@@ -2,7 +2,7 @@ | |||
2 | noarg: | 2 | noarg: |
3 | $(MAKE) -C ../ | 3 | $(MAKE) -C ../ |
4 | 4 | ||
5 | TEST_GEN_PROGS := hugetlb_vs_thp_test subpage_prot prot_sao segv_errors | 5 | TEST_GEN_PROGS := hugetlb_vs_thp_test subpage_prot prot_sao segv_errors wild_bctr |
6 | TEST_GEN_FILES := tempfile | 6 | TEST_GEN_FILES := tempfile |
7 | 7 | ||
8 | top_srcdir = ../../../../.. | 8 | top_srcdir = ../../../../.. |
@@ -12,6 +12,8 @@ $(TEST_GEN_PROGS): ../harness.c | |||
12 | 12 | ||
13 | $(OUTPUT)/prot_sao: ../utils.c | 13 | $(OUTPUT)/prot_sao: ../utils.c |
14 | 14 | ||
15 | $(OUTPUT)/wild_bctr: CFLAGS += -m64 | ||
16 | |||
15 | $(OUTPUT)/tempfile: | 17 | $(OUTPUT)/tempfile: |
16 | dd if=/dev/zero of=$@ bs=64k count=1 | 18 | dd if=/dev/zero of=$@ bs=64k count=1 |
17 | 19 | ||
diff --git a/tools/testing/selftests/powerpc/mm/wild_bctr.c b/tools/testing/selftests/powerpc/mm/wild_bctr.c new file mode 100644 index 000000000000..1b0e9e9a2ddc --- /dev/null +++ b/tools/testing/selftests/powerpc/mm/wild_bctr.c | |||
@@ -0,0 +1,155 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0+ | ||
2 | /* | ||
3 | * Copyright 2018, Michael Ellerman, IBM Corp. | ||
4 | * | ||
5 | * Test that an out-of-bounds branch to counter behaves as expected. | ||
6 | */ | ||
7 | |||
8 | #include <setjmp.h> | ||
9 | #include <stdio.h> | ||
10 | #include <stdlib.h> | ||
11 | #include <string.h> | ||
12 | #include <sys/mman.h> | ||
13 | #include <sys/types.h> | ||
14 | #include <sys/wait.h> | ||
15 | #include <ucontext.h> | ||
16 | #include <unistd.h> | ||
17 | |||
18 | #include "utils.h" | ||
19 | |||
20 | |||
21 | #define BAD_NIP 0x788c545a18000000ull | ||
22 | |||
23 | static struct pt_regs signal_regs; | ||
24 | static jmp_buf setjmp_env; | ||
25 | |||
26 | static void save_regs(ucontext_t *ctxt) | ||
27 | { | ||
28 | struct pt_regs *regs = ctxt->uc_mcontext.regs; | ||
29 | |||
30 | memcpy(&signal_regs, regs, sizeof(signal_regs)); | ||
31 | } | ||
32 | |||
33 | static void segv_handler(int signum, siginfo_t *info, void *ctxt_v) | ||
34 | { | ||
35 | save_regs(ctxt_v); | ||
36 | longjmp(setjmp_env, 1); | ||
37 | } | ||
38 | |||
39 | static void usr2_handler(int signum, siginfo_t *info, void *ctxt_v) | ||
40 | { | ||
41 | save_regs(ctxt_v); | ||
42 | } | ||
43 | |||
44 | static int ok(void) | ||
45 | { | ||
46 | printf("Everything is OK in here.\n"); | ||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | #define REG_POISON 0x5a5aUL | ||
51 | #define POISONED_REG(n) ((REG_POISON << 48) | ((n) << 32) | (REG_POISON << 16) | (n)) | ||
52 | |||
53 | static inline void poison_regs(void) | ||
54 | { | ||
55 | #define POISON_REG(n) \ | ||
56 | "lis " __stringify(n) "," __stringify(REG_POISON) ";" \ | ||
57 | "addi " __stringify(n) "," __stringify(n) "," __stringify(n) ";" \ | ||
58 | "sldi " __stringify(n) "," __stringify(n) ", 32 ;" \ | ||
59 | "oris " __stringify(n) "," __stringify(n) "," __stringify(REG_POISON) ";" \ | ||
60 | "addi " __stringify(n) "," __stringify(n) "," __stringify(n) ";" | ||
61 | |||
62 | asm (POISON_REG(15) | ||
63 | POISON_REG(16) | ||
64 | POISON_REG(17) | ||
65 | POISON_REG(18) | ||
66 | POISON_REG(19) | ||
67 | POISON_REG(20) | ||
68 | POISON_REG(21) | ||
69 | POISON_REG(22) | ||
70 | POISON_REG(23) | ||
71 | POISON_REG(24) | ||
72 | POISON_REG(25) | ||
73 | POISON_REG(26) | ||
74 | POISON_REG(27) | ||
75 | POISON_REG(28) | ||
76 | POISON_REG(29) | ||
77 | : // inputs | ||
78 | : // outputs | ||
79 | : "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", | ||
80 | "26", "27", "28", "29" | ||
81 | ); | ||
82 | #undef POISON_REG | ||
83 | } | ||
84 | |||
85 | static int check_regs(void) | ||
86 | { | ||
87 | unsigned long i; | ||
88 | |||
89 | for (i = 15; i <= 29; i++) | ||
90 | FAIL_IF(signal_regs.gpr[i] != POISONED_REG(i)); | ||
91 | |||
92 | printf("Regs OK\n"); | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static void dump_regs(void) | ||
97 | { | ||
98 | for (int i = 0; i < 32; i += 4) { | ||
99 | printf("r%02d 0x%016lx r%02d 0x%016lx " \ | ||
100 | "r%02d 0x%016lx r%02d 0x%016lx\n", | ||
101 | i, signal_regs.gpr[i], | ||
102 | i+1, signal_regs.gpr[i+1], | ||
103 | i+2, signal_regs.gpr[i+2], | ||
104 | i+3, signal_regs.gpr[i+3]); | ||
105 | } | ||
106 | } | ||
107 | |||
108 | int test_wild_bctr(void) | ||
109 | { | ||
110 | int (*func_ptr)(void); | ||
111 | struct sigaction segv = { | ||
112 | .sa_sigaction = segv_handler, | ||
113 | .sa_flags = SA_SIGINFO | ||
114 | }; | ||
115 | struct sigaction usr2 = { | ||
116 | .sa_sigaction = usr2_handler, | ||
117 | .sa_flags = SA_SIGINFO | ||
118 | }; | ||
119 | |||
120 | FAIL_IF(sigaction(SIGSEGV, &segv, NULL)); | ||
121 | FAIL_IF(sigaction(SIGUSR2, &usr2, NULL)); | ||
122 | |||
123 | bzero(&signal_regs, sizeof(signal_regs)); | ||
124 | |||
125 | if (setjmp(setjmp_env) == 0) { | ||
126 | func_ptr = ok; | ||
127 | func_ptr(); | ||
128 | |||
129 | kill(getpid(), SIGUSR2); | ||
130 | printf("Regs before:\n"); | ||
131 | dump_regs(); | ||
132 | bzero(&signal_regs, sizeof(signal_regs)); | ||
133 | |||
134 | poison_regs(); | ||
135 | |||
136 | func_ptr = (int (*)(void))BAD_NIP; | ||
137 | func_ptr(); | ||
138 | |||
139 | FAIL_IF(1); /* we didn't segv? */ | ||
140 | } | ||
141 | |||
142 | FAIL_IF(signal_regs.nip != BAD_NIP); | ||
143 | |||
144 | printf("All good - took SEGV as expected branching to 0x%llx\n", BAD_NIP); | ||
145 | |||
146 | dump_regs(); | ||
147 | FAIL_IF(check_regs()); | ||
148 | |||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | int main(void) | ||
153 | { | ||
154 | return test_harness(test_wild_bctr, "wild_bctr"); | ||
155 | } | ||
diff --git a/tools/testing/selftests/powerpc/primitives/load_unaligned_zeropad.c b/tools/testing/selftests/powerpc/primitives/load_unaligned_zeropad.c index ed3239bbfae2..ee1e9ca22f0d 100644 --- a/tools/testing/selftests/powerpc/primitives/load_unaligned_zeropad.c +++ b/tools/testing/selftests/powerpc/primitives/load_unaligned_zeropad.c | |||
@@ -65,14 +65,6 @@ static int unprotect_region(void) | |||
65 | extern char __start___ex_table[]; | 65 | extern char __start___ex_table[]; |
66 | extern char __stop___ex_table[]; | 66 | extern char __stop___ex_table[]; |
67 | 67 | ||
68 | #if defined(__powerpc64__) | ||
69 | #define UCONTEXT_NIA(UC) (UC)->uc_mcontext.gp_regs[PT_NIP] | ||
70 | #elif defined(__powerpc__) | ||
71 | #define UCONTEXT_NIA(UC) (UC)->uc_mcontext.uc_regs->gregs[PT_NIP] | ||
72 | #else | ||
73 | #error implement UCONTEXT_NIA | ||
74 | #endif | ||
75 | |||
76 | struct extbl_entry { | 68 | struct extbl_entry { |
77 | int insn; | 69 | int insn; |
78 | int fixup; | 70 | int fixup; |
diff --git a/tools/testing/selftests/powerpc/ptrace/Makefile b/tools/testing/selftests/powerpc/ptrace/Makefile index 923d531265f8..9b35ca8e8f13 100644 --- a/tools/testing/selftests/powerpc/ptrace/Makefile +++ b/tools/testing/selftests/powerpc/ptrace/Makefile | |||
@@ -2,7 +2,7 @@ | |||
2 | TEST_PROGS := ptrace-gpr ptrace-tm-gpr ptrace-tm-spd-gpr \ | 2 | TEST_PROGS := ptrace-gpr ptrace-tm-gpr ptrace-tm-spd-gpr \ |
3 | ptrace-tar ptrace-tm-tar ptrace-tm-spd-tar ptrace-vsx ptrace-tm-vsx \ | 3 | ptrace-tar ptrace-tm-tar ptrace-tm-spd-tar ptrace-vsx ptrace-tm-vsx \ |
4 | ptrace-tm-spd-vsx ptrace-tm-spr ptrace-hwbreak ptrace-pkey core-pkey \ | 4 | ptrace-tm-spd-vsx ptrace-tm-spr ptrace-hwbreak ptrace-pkey core-pkey \ |
5 | perf-hwbreak | 5 | perf-hwbreak ptrace-syscall |
6 | 6 | ||
7 | top_srcdir = ../../../../.. | 7 | top_srcdir = ../../../../.. |
8 | include ../../lib.mk | 8 | include ../../lib.mk |
diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-syscall.c b/tools/testing/selftests/powerpc/ptrace/ptrace-syscall.c new file mode 100644 index 000000000000..3353210dcdbd --- /dev/null +++ b/tools/testing/selftests/powerpc/ptrace/ptrace-syscall.c | |||
@@ -0,0 +1,228 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * A ptrace test for testing PTRACE_SYSEMU, PTRACE_SETREGS and | ||
4 | * PTRACE_GETREG. This test basically create a child process that executes | ||
5 | * syscalls and the parent process check if it is being traced appropriated. | ||
6 | * | ||
7 | * This test is heavily based on tools/testing/selftests/x86/ptrace_syscall.c | ||
8 | * test, and it was adapted to run on Powerpc by | ||
9 | * Breno Leitao <leitao@debian.org> | ||
10 | */ | ||
11 | #define _GNU_SOURCE | ||
12 | |||
13 | #include <sys/ptrace.h> | ||
14 | #include <sys/types.h> | ||
15 | #include <sys/wait.h> | ||
16 | #include <sys/syscall.h> | ||
17 | #include <sys/user.h> | ||
18 | #include <unistd.h> | ||
19 | #include <errno.h> | ||
20 | #include <stddef.h> | ||
21 | #include <stdio.h> | ||
22 | #include <err.h> | ||
23 | #include <string.h> | ||
24 | #include <sys/auxv.h> | ||
25 | #include "utils.h" | ||
26 | |||
27 | /* Bitness-agnostic defines for user_regs_struct fields. */ | ||
28 | #define user_syscall_nr gpr[0] | ||
29 | #define user_arg0 gpr[3] | ||
30 | #define user_arg1 gpr[4] | ||
31 | #define user_arg2 gpr[5] | ||
32 | #define user_arg3 gpr[6] | ||
33 | #define user_arg4 gpr[7] | ||
34 | #define user_arg5 gpr[8] | ||
35 | #define user_ip nip | ||
36 | |||
37 | #define PTRACE_SYSEMU 0x1d | ||
38 | |||
39 | static int nerrs; | ||
40 | |||
41 | static void wait_trap(pid_t chld) | ||
42 | { | ||
43 | siginfo_t si; | ||
44 | |||
45 | if (waitid(P_PID, chld, &si, WEXITED|WSTOPPED) != 0) | ||
46 | err(1, "waitid"); | ||
47 | if (si.si_pid != chld) | ||
48 | errx(1, "got unexpected pid in event\n"); | ||
49 | if (si.si_code != CLD_TRAPPED) | ||
50 | errx(1, "got unexpected event type %d\n", si.si_code); | ||
51 | } | ||
52 | |||
53 | static void test_ptrace_syscall_restart(void) | ||
54 | { | ||
55 | int status; | ||
56 | struct pt_regs regs; | ||
57 | pid_t chld; | ||
58 | |||
59 | printf("[RUN]\tptrace-induced syscall restart\n"); | ||
60 | |||
61 | chld = fork(); | ||
62 | if (chld < 0) | ||
63 | err(1, "fork"); | ||
64 | |||
65 | /* | ||
66 | * Child process is running 4 syscalls after ptrace. | ||
67 | * | ||
68 | * 1) getpid() | ||
69 | * 2) gettid() | ||
70 | * 3) tgkill() -> Send SIGSTOP | ||
71 | * 4) gettid() -> Where the tests will happen essentially | ||
72 | */ | ||
73 | if (chld == 0) { | ||
74 | if (ptrace(PTRACE_TRACEME, 0, 0, 0) != 0) | ||
75 | err(1, "PTRACE_TRACEME"); | ||
76 | |||
77 | pid_t pid = getpid(), tid = syscall(SYS_gettid); | ||
78 | |||
79 | printf("\tChild will make one syscall\n"); | ||
80 | syscall(SYS_tgkill, pid, tid, SIGSTOP); | ||
81 | |||
82 | syscall(SYS_gettid, 10, 11, 12, 13, 14, 15); | ||
83 | _exit(0); | ||
84 | } | ||
85 | /* Parent process below */ | ||
86 | |||
87 | /* Wait for SIGSTOP sent by tgkill above. */ | ||
88 | if (waitpid(chld, &status, 0) != chld || !WIFSTOPPED(status)) | ||
89 | err(1, "waitpid"); | ||
90 | |||
91 | printf("[RUN]\tSYSEMU\n"); | ||
92 | if (ptrace(PTRACE_SYSEMU, chld, 0, 0) != 0) | ||
93 | err(1, "PTRACE_SYSEMU"); | ||
94 | wait_trap(chld); | ||
95 | |||
96 | if (ptrace(PTRACE_GETREGS, chld, 0, ®s) != 0) | ||
97 | err(1, "PTRACE_GETREGS"); | ||
98 | |||
99 | /* | ||
100 | * Ptrace trapped prior to executing the syscall, thus r3 still has | ||
101 | * the syscall number instead of the sys_gettid() result | ||
102 | */ | ||
103 | if (regs.user_syscall_nr != SYS_gettid || | ||
104 | regs.user_arg0 != 10 || regs.user_arg1 != 11 || | ||
105 | regs.user_arg2 != 12 || regs.user_arg3 != 13 || | ||
106 | regs.user_arg4 != 14 || regs.user_arg5 != 15) { | ||
107 | printf("[FAIL]\tInitial args are wrong (nr=%lu, args=%lu %lu %lu %lu %lu %lu)\n", | ||
108 | (unsigned long)regs.user_syscall_nr, | ||
109 | (unsigned long)regs.user_arg0, | ||
110 | (unsigned long)regs.user_arg1, | ||
111 | (unsigned long)regs.user_arg2, | ||
112 | (unsigned long)regs.user_arg3, | ||
113 | (unsigned long)regs.user_arg4, | ||
114 | (unsigned long)regs.user_arg5); | ||
115 | nerrs++; | ||
116 | } else { | ||
117 | printf("[OK]\tInitial nr and args are correct\n"); } | ||
118 | |||
119 | printf("[RUN]\tRestart the syscall (ip = 0x%lx)\n", | ||
120 | (unsigned long)regs.user_ip); | ||
121 | |||
122 | /* | ||
123 | * Rewind to retry the same syscall again. This will basically test | ||
124 | * the rewind process together with PTRACE_SETREGS and PTRACE_GETREGS. | ||
125 | */ | ||
126 | regs.user_ip -= 4; | ||
127 | if (ptrace(PTRACE_SETREGS, chld, 0, ®s) != 0) | ||
128 | err(1, "PTRACE_SETREGS"); | ||
129 | |||
130 | if (ptrace(PTRACE_SYSEMU, chld, 0, 0) != 0) | ||
131 | err(1, "PTRACE_SYSEMU"); | ||
132 | wait_trap(chld); | ||
133 | |||
134 | if (ptrace(PTRACE_GETREGS, chld, 0, ®s) != 0) | ||
135 | err(1, "PTRACE_GETREGS"); | ||
136 | |||
137 | if (regs.user_syscall_nr != SYS_gettid || | ||
138 | regs.user_arg0 != 10 || regs.user_arg1 != 11 || | ||
139 | regs.user_arg2 != 12 || regs.user_arg3 != 13 || | ||
140 | regs.user_arg4 != 14 || regs.user_arg5 != 15) { | ||
141 | printf("[FAIL]\tRestart nr or args are wrong (nr=%lu, args=%lu %lu %lu %lu %lu %lu)\n", | ||
142 | (unsigned long)regs.user_syscall_nr, | ||
143 | (unsigned long)regs.user_arg0, | ||
144 | (unsigned long)regs.user_arg1, | ||
145 | (unsigned long)regs.user_arg2, | ||
146 | (unsigned long)regs.user_arg3, | ||
147 | (unsigned long)regs.user_arg4, | ||
148 | (unsigned long)regs.user_arg5); | ||
149 | nerrs++; | ||
150 | } else { | ||
151 | printf("[OK]\tRestarted nr and args are correct\n"); | ||
152 | } | ||
153 | |||
154 | printf("[RUN]\tChange nr and args and restart the syscall (ip = 0x%lx)\n", | ||
155 | (unsigned long)regs.user_ip); | ||
156 | |||
157 | /* | ||
158 | * Inject a new syscall (getpid) in the same place the previous | ||
159 | * syscall (gettid), rewind and re-execute. | ||
160 | */ | ||
161 | regs.user_syscall_nr = SYS_getpid; | ||
162 | regs.user_arg0 = 20; | ||
163 | regs.user_arg1 = 21; | ||
164 | regs.user_arg2 = 22; | ||
165 | regs.user_arg3 = 23; | ||
166 | regs.user_arg4 = 24; | ||
167 | regs.user_arg5 = 25; | ||
168 | regs.user_ip -= 4; | ||
169 | |||
170 | if (ptrace(PTRACE_SETREGS, chld, 0, ®s) != 0) | ||
171 | err(1, "PTRACE_SETREGS"); | ||
172 | |||
173 | if (ptrace(PTRACE_SYSEMU, chld, 0, 0) != 0) | ||
174 | err(1, "PTRACE_SYSEMU"); | ||
175 | wait_trap(chld); | ||
176 | |||
177 | if (ptrace(PTRACE_GETREGS, chld, 0, ®s) != 0) | ||
178 | err(1, "PTRACE_GETREGS"); | ||
179 | |||
180 | /* Check that ptrace stopped at the new syscall that was | ||
181 | * injected, and guarantee that it haven't executed, i.e, user_args | ||
182 | * contain the arguments and not the syscall return value, for | ||
183 | * instance. | ||
184 | */ | ||
185 | if (regs.user_syscall_nr != SYS_getpid | ||
186 | || regs.user_arg0 != 20 || regs.user_arg1 != 21 | ||
187 | || regs.user_arg2 != 22 || regs.user_arg3 != 23 | ||
188 | || regs.user_arg4 != 24 || regs.user_arg5 != 25) { | ||
189 | |||
190 | printf("[FAIL]\tRestart nr or args are wrong (nr=%lu, args=%lu %lu %lu %lu %lu %lu)\n", | ||
191 | (unsigned long)regs.user_syscall_nr, | ||
192 | (unsigned long)regs.user_arg0, | ||
193 | (unsigned long)regs.user_arg1, | ||
194 | (unsigned long)regs.user_arg2, | ||
195 | (unsigned long)regs.user_arg3, | ||
196 | (unsigned long)regs.user_arg4, | ||
197 | (unsigned long)regs.user_arg5); | ||
198 | nerrs++; | ||
199 | } else { | ||
200 | printf("[OK]\tReplacement nr and args are correct\n"); | ||
201 | } | ||
202 | |||
203 | if (ptrace(PTRACE_CONT, chld, 0, 0) != 0) | ||
204 | err(1, "PTRACE_CONT"); | ||
205 | |||
206 | if (waitpid(chld, &status, 0) != chld) | ||
207 | err(1, "waitpid"); | ||
208 | |||
209 | /* Guarantee that the process executed properly, returning 0 */ | ||
210 | if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { | ||
211 | printf("[FAIL]\tChild failed\n"); | ||
212 | nerrs++; | ||
213 | } else { | ||
214 | printf("[OK]\tChild exited cleanly\n"); | ||
215 | } | ||
216 | } | ||
217 | |||
218 | int ptrace_syscall(void) | ||
219 | { | ||
220 | test_ptrace_syscall_restart(); | ||
221 | |||
222 | return nerrs; | ||
223 | } | ||
224 | |||
225 | int main(void) | ||
226 | { | ||
227 | return test_harness(ptrace_syscall, "ptrace_syscall"); | ||
228 | } | ||
diff --git a/tools/testing/selftests/powerpc/security/Makefile b/tools/testing/selftests/powerpc/security/Makefile new file mode 100644 index 000000000000..44690f1bb26a --- /dev/null +++ b/tools/testing/selftests/powerpc/security/Makefile | |||
@@ -0,0 +1,9 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0+ | ||
2 | |||
3 | TEST_GEN_PROGS := rfi_flush | ||
4 | |||
5 | CFLAGS += -I../../../../../usr/include | ||
6 | |||
7 | include ../../lib.mk | ||
8 | |||
9 | $(TEST_GEN_PROGS): ../harness.c ../utils.c | ||
diff --git a/tools/testing/selftests/powerpc/security/rfi_flush.c b/tools/testing/selftests/powerpc/security/rfi_flush.c new file mode 100644 index 000000000000..564ed45bbf73 --- /dev/null +++ b/tools/testing/selftests/powerpc/security/rfi_flush.c | |||
@@ -0,0 +1,132 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0+ | ||
2 | |||
3 | /* | ||
4 | * Copyright 2018 IBM Corporation. | ||
5 | */ | ||
6 | |||
7 | #define __SANE_USERSPACE_TYPES__ | ||
8 | |||
9 | #include <sys/types.h> | ||
10 | #include <stdint.h> | ||
11 | #include <malloc.h> | ||
12 | #include <unistd.h> | ||
13 | #include <stdlib.h> | ||
14 | #include <string.h> | ||
15 | #include <stdio.h> | ||
16 | #include "utils.h" | ||
17 | |||
18 | #define CACHELINE_SIZE 128 | ||
19 | |||
20 | struct perf_event_read { | ||
21 | __u64 nr; | ||
22 | __u64 l1d_misses; | ||
23 | }; | ||
24 | |||
25 | static inline __u64 load(void *addr) | ||
26 | { | ||
27 | __u64 tmp; | ||
28 | |||
29 | asm volatile("ld %0,0(%1)" : "=r"(tmp) : "b"(addr)); | ||
30 | |||
31 | return tmp; | ||
32 | } | ||
33 | |||
34 | static void syscall_loop(char *p, unsigned long iterations, | ||
35 | unsigned long zero_size) | ||
36 | { | ||
37 | for (unsigned long i = 0; i < iterations; i++) { | ||
38 | for (unsigned long j = 0; j < zero_size; j += CACHELINE_SIZE) | ||
39 | load(p + j); | ||
40 | getppid(); | ||
41 | } | ||
42 | } | ||
43 | |||
44 | int rfi_flush_test(void) | ||
45 | { | ||
46 | char *p; | ||
47 | int repetitions = 10; | ||
48 | int fd, passes = 0, iter, rc = 0; | ||
49 | struct perf_event_read v; | ||
50 | __u64 l1d_misses_total = 0; | ||
51 | unsigned long iterations = 100000, zero_size = 24 * 1024; | ||
52 | int rfi_flush_org, rfi_flush; | ||
53 | |||
54 | SKIP_IF(geteuid() != 0); | ||
55 | |||
56 | if (read_debugfs_file("powerpc/rfi_flush", &rfi_flush_org)) { | ||
57 | perror("Unable to read powerpc/rfi_flush debugfs file"); | ||
58 | SKIP_IF(1); | ||
59 | } | ||
60 | |||
61 | rfi_flush = rfi_flush_org; | ||
62 | |||
63 | fd = perf_event_open_counter(PERF_TYPE_RAW, /* L1d miss */ 0x400f0, -1); | ||
64 | FAIL_IF(fd < 0); | ||
65 | |||
66 | p = (char *)memalign(zero_size, CACHELINE_SIZE); | ||
67 | |||
68 | FAIL_IF(perf_event_enable(fd)); | ||
69 | |||
70 | set_dscr(1); | ||
71 | |||
72 | iter = repetitions; | ||
73 | |||
74 | again: | ||
75 | FAIL_IF(perf_event_reset(fd)); | ||
76 | |||
77 | syscall_loop(p, iterations, zero_size); | ||
78 | |||
79 | FAIL_IF(read(fd, &v, sizeof(v)) != sizeof(v)); | ||
80 | |||
81 | /* Expect at least zero_size/CACHELINE_SIZE misses per iteration */ | ||
82 | if (v.l1d_misses >= (iterations * zero_size / CACHELINE_SIZE) && rfi_flush) | ||
83 | passes++; | ||
84 | else if (v.l1d_misses < iterations && !rfi_flush) | ||
85 | passes++; | ||
86 | |||
87 | l1d_misses_total += v.l1d_misses; | ||
88 | |||
89 | while (--iter) | ||
90 | goto again; | ||
91 | |||
92 | if (passes < repetitions) { | ||
93 | printf("FAIL (L1D misses with rfi_flush=%d: %llu %c %lu) [%d/%d failures]\n", | ||
94 | rfi_flush, l1d_misses_total, rfi_flush ? '<' : '>', | ||
95 | rfi_flush ? (repetitions * iterations * zero_size / CACHELINE_SIZE) : iterations, | ||
96 | repetitions - passes, repetitions); | ||
97 | rc = 1; | ||
98 | } else | ||
99 | printf("PASS (L1D misses with rfi_flush=%d: %llu %c %lu) [%d/%d pass]\n", | ||
100 | rfi_flush, l1d_misses_total, rfi_flush ? '>' : '<', | ||
101 | rfi_flush ? (repetitions * iterations * zero_size / CACHELINE_SIZE) : iterations, | ||
102 | passes, repetitions); | ||
103 | |||
104 | if (rfi_flush == rfi_flush_org) { | ||
105 | rfi_flush = !rfi_flush_org; | ||
106 | if (write_debugfs_file("powerpc/rfi_flush", rfi_flush) < 0) { | ||
107 | perror("error writing to powerpc/rfi_flush debugfs file"); | ||
108 | return 1; | ||
109 | } | ||
110 | iter = repetitions; | ||
111 | l1d_misses_total = 0; | ||
112 | passes = 0; | ||
113 | goto again; | ||
114 | } | ||
115 | |||
116 | perf_event_disable(fd); | ||
117 | close(fd); | ||
118 | |||
119 | set_dscr(0); | ||
120 | |||
121 | if (write_debugfs_file("powerpc/rfi_flush", rfi_flush_org) < 0) { | ||
122 | perror("unable to restore original value of powerpc/rfi_flush debugfs file"); | ||
123 | return 1; | ||
124 | } | ||
125 | |||
126 | return rc; | ||
127 | } | ||
128 | |||
129 | int main(int argc, char *argv[]) | ||
130 | { | ||
131 | return test_harness(rfi_flush_test, "rfi_flush_test"); | ||
132 | } | ||
diff --git a/tools/testing/selftests/powerpc/tm/tm-tmspr.c b/tools/testing/selftests/powerpc/tm/tm-tmspr.c index 2bda81c7bf23..df1d7d4b1c89 100644 --- a/tools/testing/selftests/powerpc/tm/tm-tmspr.c +++ b/tools/testing/selftests/powerpc/tm/tm-tmspr.c | |||
@@ -98,7 +98,7 @@ void texasr(void *in) | |||
98 | 98 | ||
99 | int test_tmspr() | 99 | int test_tmspr() |
100 | { | 100 | { |
101 | pthread_t thread; | 101 | pthread_t *thread; |
102 | int thread_num; | 102 | int thread_num; |
103 | unsigned long i; | 103 | unsigned long i; |
104 | 104 | ||
@@ -107,21 +107,28 @@ int test_tmspr() | |||
107 | /* To cause some context switching */ | 107 | /* To cause some context switching */ |
108 | thread_num = 10 * sysconf(_SC_NPROCESSORS_ONLN); | 108 | thread_num = 10 * sysconf(_SC_NPROCESSORS_ONLN); |
109 | 109 | ||
110 | thread = malloc(thread_num * sizeof(pthread_t)); | ||
111 | if (thread == NULL) | ||
112 | return EXIT_FAILURE; | ||
113 | |||
110 | /* Test TFIAR and TFHAR */ | 114 | /* Test TFIAR and TFHAR */ |
111 | for (i = 0 ; i < thread_num ; i += 2){ | 115 | for (i = 0; i < thread_num; i += 2) { |
112 | if (pthread_create(&thread, NULL, (void*)tfiar_tfhar, (void *)i)) | 116 | if (pthread_create(&thread[i], NULL, (void *)tfiar_tfhar, |
117 | (void *)i)) | ||
113 | return EXIT_FAILURE; | 118 | return EXIT_FAILURE; |
114 | } | 119 | } |
115 | if (pthread_join(thread, NULL) != 0) | ||
116 | return EXIT_FAILURE; | ||
117 | |||
118 | /* Test TEXASR */ | 120 | /* Test TEXASR */ |
119 | for (i = 0 ; i < thread_num ; i++){ | 121 | for (i = 1; i < thread_num; i += 2) { |
120 | if (pthread_create(&thread, NULL, (void*)texasr, (void *)i)) | 122 | if (pthread_create(&thread[i], NULL, (void *)texasr, (void *)i)) |
121 | return EXIT_FAILURE; | 123 | return EXIT_FAILURE; |
122 | } | 124 | } |
123 | if (pthread_join(thread, NULL) != 0) | 125 | |
124 | return EXIT_FAILURE; | 126 | for (i = 0; i < thread_num; i++) { |
127 | if (pthread_join(thread[i], NULL) != 0) | ||
128 | return EXIT_FAILURE; | ||
129 | } | ||
130 | |||
131 | free(thread); | ||
125 | 132 | ||
126 | if (passed) | 133 | if (passed) |
127 | return 0; | 134 | return 0; |
diff --git a/tools/testing/selftests/powerpc/tm/tm-unavailable.c b/tools/testing/selftests/powerpc/tm/tm-unavailable.c index 156c8e750259..09894f4ff62e 100644 --- a/tools/testing/selftests/powerpc/tm/tm-unavailable.c +++ b/tools/testing/selftests/powerpc/tm/tm-unavailable.c | |||
@@ -236,7 +236,8 @@ void *tm_una_ping(void *input) | |||
236 | } | 236 | } |
237 | 237 | ||
238 | /* Check if we were not expecting a failure and a it occurred. */ | 238 | /* Check if we were not expecting a failure and a it occurred. */ |
239 | if (!expecting_failure() && is_failure(cr_)) { | 239 | if (!expecting_failure() && is_failure(cr_) && |
240 | !failure_is_reschedule()) { | ||
240 | printf("\n\tUnexpected transaction failure 0x%02lx\n\t", | 241 | printf("\n\tUnexpected transaction failure 0x%02lx\n\t", |
241 | failure_code()); | 242 | failure_code()); |
242 | return (void *) -1; | 243 | return (void *) -1; |
@@ -244,9 +245,11 @@ void *tm_una_ping(void *input) | |||
244 | 245 | ||
245 | /* | 246 | /* |
246 | * Check if TM failed due to the cause we were expecting. 0xda is a | 247 | * Check if TM failed due to the cause we were expecting. 0xda is a |
247 | * TM_CAUSE_FAC_UNAV cause, otherwise it's an unexpected cause. | 248 | * TM_CAUSE_FAC_UNAV cause, otherwise it's an unexpected cause, unless |
249 | * it was caused by a reschedule. | ||
248 | */ | 250 | */ |
249 | if (is_failure(cr_) && !failure_is_unavailable()) { | 251 | if (is_failure(cr_) && !failure_is_unavailable() && |
252 | !failure_is_reschedule()) { | ||
250 | printf("\n\tUnexpected failure cause 0x%02lx\n\t", | 253 | printf("\n\tUnexpected failure cause 0x%02lx\n\t", |
251 | failure_code()); | 254 | failure_code()); |
252 | return (void *) -1; | 255 | return (void *) -1; |
diff --git a/tools/testing/selftests/powerpc/tm/tm.h b/tools/testing/selftests/powerpc/tm/tm.h index df4204247d45..5518b1d4ef8b 100644 --- a/tools/testing/selftests/powerpc/tm/tm.h +++ b/tools/testing/selftests/powerpc/tm/tm.h | |||
@@ -52,6 +52,15 @@ static inline bool failure_is_unavailable(void) | |||
52 | return (failure_code() & TM_CAUSE_FAC_UNAV) == TM_CAUSE_FAC_UNAV; | 52 | return (failure_code() & TM_CAUSE_FAC_UNAV) == TM_CAUSE_FAC_UNAV; |
53 | } | 53 | } |
54 | 54 | ||
55 | static inline bool failure_is_reschedule(void) | ||
56 | { | ||
57 | if ((failure_code() & TM_CAUSE_RESCHED) == TM_CAUSE_RESCHED || | ||
58 | (failure_code() & TM_CAUSE_KVM_RESCHED) == TM_CAUSE_KVM_RESCHED) | ||
59 | return true; | ||
60 | |||
61 | return false; | ||
62 | } | ||
63 | |||
55 | static inline bool failure_is_nesting(void) | 64 | static inline bool failure_is_nesting(void) |
56 | { | 65 | { |
57 | return (__builtin_get_texasru() & 0x400000); | 66 | return (__builtin_get_texasru() & 0x400000); |
diff --git a/tools/testing/selftests/powerpc/utils.c b/tools/testing/selftests/powerpc/utils.c index aa8fc1e6365b..43c342845be0 100644 --- a/tools/testing/selftests/powerpc/utils.c +++ b/tools/testing/selftests/powerpc/utils.c | |||
@@ -10,16 +10,22 @@ | |||
10 | #include <fcntl.h> | 10 | #include <fcntl.h> |
11 | #include <link.h> | 11 | #include <link.h> |
12 | #include <sched.h> | 12 | #include <sched.h> |
13 | #include <signal.h> | ||
13 | #include <stdio.h> | 14 | #include <stdio.h> |
15 | #include <stdlib.h> | ||
14 | #include <string.h> | 16 | #include <string.h> |
17 | #include <sys/ioctl.h> | ||
15 | #include <sys/stat.h> | 18 | #include <sys/stat.h> |
16 | #include <sys/types.h> | 19 | #include <sys/types.h> |
17 | #include <sys/utsname.h> | 20 | #include <sys/utsname.h> |
18 | #include <unistd.h> | 21 | #include <unistd.h> |
22 | #include <asm/unistd.h> | ||
23 | #include <linux/limits.h> | ||
19 | 24 | ||
20 | #include "utils.h" | 25 | #include "utils.h" |
21 | 26 | ||
22 | static char auxv[4096]; | 27 | static char auxv[4096]; |
28 | extern unsigned int dscr_insn[]; | ||
23 | 29 | ||
24 | int read_auxv(char *buf, ssize_t buf_size) | 30 | int read_auxv(char *buf, ssize_t buf_size) |
25 | { | 31 | { |
@@ -121,3 +127,149 @@ bool is_ppc64le(void) | |||
121 | 127 | ||
122 | return strcmp(uts.machine, "ppc64le") == 0; | 128 | return strcmp(uts.machine, "ppc64le") == 0; |
123 | } | 129 | } |
130 | |||
131 | int read_debugfs_file(char *debugfs_file, int *result) | ||
132 | { | ||
133 | int rc = -1, fd; | ||
134 | char path[PATH_MAX]; | ||
135 | char value[16]; | ||
136 | |||
137 | strcpy(path, "/sys/kernel/debug/"); | ||
138 | strncat(path, debugfs_file, PATH_MAX - strlen(path) - 1); | ||
139 | |||
140 | if ((fd = open(path, O_RDONLY)) < 0) | ||
141 | return rc; | ||
142 | |||
143 | if ((rc = read(fd, value, sizeof(value))) < 0) | ||
144 | return rc; | ||
145 | |||
146 | value[15] = 0; | ||
147 | *result = atoi(value); | ||
148 | close(fd); | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | int write_debugfs_file(char *debugfs_file, int result) | ||
154 | { | ||
155 | int rc = -1, fd; | ||
156 | char path[PATH_MAX]; | ||
157 | char value[16]; | ||
158 | |||
159 | strcpy(path, "/sys/kernel/debug/"); | ||
160 | strncat(path, debugfs_file, PATH_MAX - strlen(path) - 1); | ||
161 | |||
162 | if ((fd = open(path, O_WRONLY)) < 0) | ||
163 | return rc; | ||
164 | |||
165 | snprintf(value, 16, "%d", result); | ||
166 | |||
167 | if ((rc = write(fd, value, strlen(value))) < 0) | ||
168 | return rc; | ||
169 | |||
170 | close(fd); | ||
171 | |||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid, | ||
176 | int cpu, int group_fd, unsigned long flags) | ||
177 | { | ||
178 | return syscall(__NR_perf_event_open, hw_event, pid, cpu, | ||
179 | group_fd, flags); | ||
180 | } | ||
181 | |||
182 | static void perf_event_attr_init(struct perf_event_attr *event_attr, | ||
183 | unsigned int type, | ||
184 | unsigned long config) | ||
185 | { | ||
186 | memset(event_attr, 0, sizeof(*event_attr)); | ||
187 | |||
188 | event_attr->type = type; | ||
189 | event_attr->size = sizeof(struct perf_event_attr); | ||
190 | event_attr->config = config; | ||
191 | event_attr->read_format = PERF_FORMAT_GROUP; | ||
192 | event_attr->disabled = 1; | ||
193 | event_attr->exclude_kernel = 1; | ||
194 | event_attr->exclude_hv = 1; | ||
195 | event_attr->exclude_guest = 1; | ||
196 | } | ||
197 | |||
198 | int perf_event_open_counter(unsigned int type, | ||
199 | unsigned long config, int group_fd) | ||
200 | { | ||
201 | int fd; | ||
202 | struct perf_event_attr event_attr; | ||
203 | |||
204 | perf_event_attr_init(&event_attr, type, config); | ||
205 | |||
206 | fd = perf_event_open(&event_attr, 0, -1, group_fd, 0); | ||
207 | |||
208 | if (fd < 0) | ||
209 | perror("perf_event_open() failed"); | ||
210 | |||
211 | return fd; | ||
212 | } | ||
213 | |||
214 | int perf_event_enable(int fd) | ||
215 | { | ||
216 | if (ioctl(fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) == -1) { | ||
217 | perror("error while enabling perf events"); | ||
218 | return -1; | ||
219 | } | ||
220 | |||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | int perf_event_disable(int fd) | ||
225 | { | ||
226 | if (ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) == -1) { | ||
227 | perror("error disabling perf events"); | ||
228 | return -1; | ||
229 | } | ||
230 | |||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | int perf_event_reset(int fd) | ||
235 | { | ||
236 | if (ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP) == -1) { | ||
237 | perror("error resetting perf events"); | ||
238 | return -1; | ||
239 | } | ||
240 | |||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | static void sigill_handler(int signr, siginfo_t *info, void *unused) | ||
245 | { | ||
246 | static int warned = 0; | ||
247 | ucontext_t *ctx = (ucontext_t *)unused; | ||
248 | unsigned long *pc = &UCONTEXT_NIA(ctx); | ||
249 | |||
250 | if (*pc == (unsigned long)&dscr_insn) { | ||
251 | if (!warned++) | ||
252 | printf("WARNING: Skipping over dscr setup. Consider running 'ppc64_cpu --dscr=1' manually.\n"); | ||
253 | *pc += 4; | ||
254 | } else { | ||
255 | printf("SIGILL at %p\n", pc); | ||
256 | abort(); | ||
257 | } | ||
258 | } | ||
259 | |||
260 | void set_dscr(unsigned long val) | ||
261 | { | ||
262 | static int init = 0; | ||
263 | struct sigaction sa; | ||
264 | |||
265 | if (!init) { | ||
266 | memset(&sa, 0, sizeof(sa)); | ||
267 | sa.sa_sigaction = sigill_handler; | ||
268 | sa.sa_flags = SA_SIGINFO; | ||
269 | if (sigaction(SIGILL, &sa, NULL)) | ||
270 | perror("sigill_handler"); | ||
271 | init = 1; | ||
272 | } | ||
273 | |||
274 | asm volatile("dscr_insn: mtspr %1,%0" : : "r" (val), "i" (SPRN_DSCR)); | ||
275 | } | ||
diff --git a/tools/testing/selftests/tc-testing/README b/tools/testing/selftests/tc-testing/README index 49a6f8c3fdae..f9281e8aa313 100644 --- a/tools/testing/selftests/tc-testing/README +++ b/tools/testing/selftests/tc-testing/README | |||
@@ -232,6 +232,8 @@ directory: | |||
232 | and the other is a test whether the command leaked memory or not. | 232 | and the other is a test whether the command leaked memory or not. |
233 | (This one is a preliminary version, it may not work quite right yet, | 233 | (This one is a preliminary version, it may not work quite right yet, |
234 | but the overall template is there and it should only need tweaks.) | 234 | but the overall template is there and it should only need tweaks.) |
235 | - buildebpfPlugin.py: | ||
236 | builds all programs in $EBPFDIR. | ||
235 | 237 | ||
236 | 238 | ||
237 | ACKNOWLEDGEMENTS | 239 | ACKNOWLEDGEMENTS |
diff --git a/tools/testing/selftests/tc-testing/bpf/Makefile b/tools/testing/selftests/tc-testing/bpf/Makefile new file mode 100644 index 000000000000..dc92eb271d9a --- /dev/null +++ b/tools/testing/selftests/tc-testing/bpf/Makefile | |||
@@ -0,0 +1,29 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 | ||
2 | |||
3 | APIDIR := ../../../../include/uapi | ||
4 | TEST_GEN_FILES = action.o | ||
5 | |||
6 | top_srcdir = ../../../../.. | ||
7 | include ../../lib.mk | ||
8 | |||
9 | CLANG ?= clang | ||
10 | LLC ?= llc | ||
11 | PROBE := $(shell $(LLC) -march=bpf -mcpu=probe -filetype=null /dev/null 2>&1) | ||
12 | |||
13 | ifeq ($(PROBE),) | ||
14 | CPU ?= probe | ||
15 | else | ||
16 | CPU ?= generic | ||
17 | endif | ||
18 | |||
19 | CLANG_SYS_INCLUDES := $(shell $(CLANG) -v -E - </dev/null 2>&1 \ | ||
20 | | sed -n '/<...> search starts here:/,/End of search list./{ s| \(/.*\)|-idirafter \1|p }') | ||
21 | |||
22 | CLANG_FLAGS = -I. -I$(APIDIR) \ | ||
23 | $(CLANG_SYS_INCLUDES) \ | ||
24 | -Wno-compare-distinct-pointer-types | ||
25 | |||
26 | $(OUTPUT)/%.o: %.c | ||
27 | $(CLANG) $(CLANG_FLAGS) \ | ||
28 | -O2 -target bpf -emit-llvm -c $< -o - | \ | ||
29 | $(LLC) -march=bpf -mcpu=$(CPU) $(LLC_FLAGS) -filetype=obj -o $@ | ||
diff --git a/tools/testing/selftests/tc-testing/bpf/action.c b/tools/testing/selftests/tc-testing/bpf/action.c new file mode 100644 index 000000000000..c32b99b80e19 --- /dev/null +++ b/tools/testing/selftests/tc-testing/bpf/action.c | |||
@@ -0,0 +1,23 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 | ||
2 | * Copyright (c) 2018 Davide Caratti, Red Hat inc. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of version 2 of the GNU General Public | ||
6 | * License as published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/bpf.h> | ||
10 | #include <linux/pkt_cls.h> | ||
11 | |||
12 | __attribute__((section("action-ok"),used)) int action_ok(struct __sk_buff *s) | ||
13 | { | ||
14 | return TC_ACT_OK; | ||
15 | } | ||
16 | |||
17 | __attribute__((section("action-ko"),used)) int action_ko(struct __sk_buff *s) | ||
18 | { | ||
19 | s->data = 0x0; | ||
20 | return TC_ACT_OK; | ||
21 | } | ||
22 | |||
23 | char _license[] __attribute__((section("license"),used)) = "GPL"; | ||
diff --git a/tools/testing/selftests/tc-testing/plugin-lib/buildebpfPlugin.py b/tools/testing/selftests/tc-testing/plugin-lib/buildebpfPlugin.py new file mode 100644 index 000000000000..9f0ba10c44b4 --- /dev/null +++ b/tools/testing/selftests/tc-testing/plugin-lib/buildebpfPlugin.py | |||
@@ -0,0 +1,66 @@ | |||
1 | ''' | ||
2 | build ebpf program | ||
3 | ''' | ||
4 | |||
5 | import os | ||
6 | import signal | ||
7 | from string import Template | ||
8 | import subprocess | ||
9 | import time | ||
10 | from TdcPlugin import TdcPlugin | ||
11 | from tdc_config import * | ||
12 | |||
13 | class SubPlugin(TdcPlugin): | ||
14 | def __init__(self): | ||
15 | self.sub_class = 'buildebpf/SubPlugin' | ||
16 | self.tap = '' | ||
17 | super().__init__() | ||
18 | |||
19 | def pre_suite(self, testcount, testidlist): | ||
20 | super().pre_suite(testcount, testidlist) | ||
21 | |||
22 | if self.args.buildebpf: | ||
23 | self._ebpf_makeall() | ||
24 | |||
25 | def post_suite(self, index): | ||
26 | super().post_suite(index) | ||
27 | |||
28 | self._ebpf_makeclean() | ||
29 | |||
30 | def add_args(self, parser): | ||
31 | super().add_args(parser) | ||
32 | |||
33 | self.argparser_group = self.argparser.add_argument_group( | ||
34 | 'buildebpf', | ||
35 | 'options for buildebpfPlugin') | ||
36 | self.argparser_group.add_argument( | ||
37 | '-B', '--buildebpf', action='store_true', | ||
38 | help='build eBPF programs') | ||
39 | |||
40 | return self.argparser | ||
41 | |||
42 | def _ebpf_makeall(self): | ||
43 | if self.args.buildebpf: | ||
44 | self._make('all') | ||
45 | |||
46 | def _ebpf_makeclean(self): | ||
47 | if self.args.buildebpf: | ||
48 | self._make('clean') | ||
49 | |||
50 | def _make(self, target): | ||
51 | command = 'make -C {} {}'.format(self.args.NAMES['EBPFDIR'], target) | ||
52 | proc = subprocess.Popen(command, | ||
53 | shell=True, | ||
54 | stdout=subprocess.PIPE, | ||
55 | stderr=subprocess.PIPE, | ||
56 | env=ENVIR) | ||
57 | (rawout, serr) = proc.communicate() | ||
58 | |||
59 | if proc.returncode != 0 and len(serr) > 0: | ||
60 | foutput = serr.decode("utf-8") | ||
61 | else: | ||
62 | foutput = rawout.decode("utf-8") | ||
63 | |||
64 | proc.stdout.close() | ||
65 | proc.stderr.close() | ||
66 | return proc, foutput | ||
diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/bpf.json b/tools/testing/selftests/tc-testing/tc-tests/actions/bpf.json index 6f289a49e5ec..5970cee6d05f 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/bpf.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/bpf.json | |||
@@ -55,7 +55,6 @@ | |||
55 | "bpf" | 55 | "bpf" |
56 | ], | 56 | ], |
57 | "setup": [ | 57 | "setup": [ |
58 | "printf '#include <linux/bpf.h>\nchar l[] __attribute__((section(\"license\"),used))=\"GPL\"; __attribute__((section(\"action\"),used)) int m(struct __sk_buff *s) { return 2; }' | clang -O2 -x c -c - -target bpf -o _b.o", | ||
59 | [ | 58 | [ |
60 | "$TC action flush action bpf", | 59 | "$TC action flush action bpf", |
61 | 0, | 60 | 0, |
@@ -63,14 +62,13 @@ | |||
63 | 255 | 62 | 255 |
64 | ] | 63 | ] |
65 | ], | 64 | ], |
66 | "cmdUnderTest": "$TC action add action bpf object-file _b.o index 667", | 65 | "cmdUnderTest": "$TC action add action bpf object-file $EBPFDIR/action.o section action-ok index 667", |
67 | "expExitCode": "0", | 66 | "expExitCode": "0", |
68 | "verifyCmd": "$TC action get action bpf index 667", | 67 | "verifyCmd": "$TC action get action bpf index 667", |
69 | "matchPattern": "action order [0-9]*: bpf _b.o:\\[action\\] id [0-9]* tag 3b185187f1855c4c( jited)? default-action pipe.*index 667 ref", | 68 | "matchPattern": "action order [0-9]*: bpf action.o:\\[action-ok\\] id [0-9]* tag [0-9a-f]{16}( jited)? default-action pipe.*index 667 ref", |
70 | "matchCount": "1", | 69 | "matchCount": "1", |
71 | "teardown": [ | 70 | "teardown": [ |
72 | "$TC action flush action bpf", | 71 | "$TC action flush action bpf" |
73 | "rm -f _b.o" | ||
74 | ] | 72 | ] |
75 | }, | 73 | }, |
76 | { | 74 | { |
@@ -81,7 +79,6 @@ | |||
81 | "bpf" | 79 | "bpf" |
82 | ], | 80 | ], |
83 | "setup": [ | 81 | "setup": [ |
84 | "printf '#include <linux/bpf.h>\nchar l[] __attribute__((section(\"license\"),used))=\"GPL\"; __attribute__((section(\"action\"),used)) int m(struct __sk_buff *s) { s->data = 0x0; return 2; }' | clang -O2 -x c -c - -target bpf -o _c.o", | ||
85 | [ | 82 | [ |
86 | "$TC action flush action bpf", | 83 | "$TC action flush action bpf", |
87 | 0, | 84 | 0, |
@@ -89,10 +86,10 @@ | |||
89 | 255 | 86 | 255 |
90 | ] | 87 | ] |
91 | ], | 88 | ], |
92 | "cmdUnderTest": "$TC action add action bpf object-file _c.o index 667", | 89 | "cmdUnderTest": "$TC action add action bpf object-file $EBPFDIR/action.o section action-ko index 667", |
93 | "expExitCode": "255", | 90 | "expExitCode": "255", |
94 | "verifyCmd": "$TC action get action bpf index 667", | 91 | "verifyCmd": "$TC action get action bpf index 667", |
95 | "matchPattern": "action order [0-9]*: bpf _c.o:\\[action\\] id [0-9].*index 667 ref", | 92 | "matchPattern": "action order [0-9]*: bpf action.o:\\[action-ko\\] id [0-9].*index 667 ref", |
96 | "matchCount": "0", | 93 | "matchCount": "0", |
97 | "teardown": [ | 94 | "teardown": [ |
98 | [ | 95 | [ |
@@ -100,8 +97,7 @@ | |||
100 | 0, | 97 | 0, |
101 | 1, | 98 | 1, |
102 | 255 | 99 | 255 |
103 | ], | 100 | ] |
104 | "rm -f _c.o" | ||
105 | ] | 101 | ] |
106 | }, | 102 | }, |
107 | { | 103 | { |
diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/gact.json b/tools/testing/selftests/tc-testing/tc-tests/actions/gact.json index 68c91023cdb9..89189a03ce3d 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/gact.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/gact.json | |||
@@ -536,5 +536,29 @@ | |||
536 | "matchPattern": "^[ \t]+index [0-9]+ ref", | 536 | "matchPattern": "^[ \t]+index [0-9]+ ref", |
537 | "matchCount": "0", | 537 | "matchCount": "0", |
538 | "teardown": [] | 538 | "teardown": [] |
539 | }, | ||
540 | { | ||
541 | "id": "8e47", | ||
542 | "name": "Add gact action with random determ goto chain control action", | ||
543 | "category": [ | ||
544 | "actions", | ||
545 | "gact" | ||
546 | ], | ||
547 | "setup": [ | ||
548 | [ | ||
549 | "$TC actions flush action gact", | ||
550 | 0, | ||
551 | 1, | ||
552 | 255 | ||
553 | ] | ||
554 | ], | ||
555 | "cmdUnderTest": "$TC actions add action pass random determ goto chain 1 2 index 90", | ||
556 | "expExitCode": "255", | ||
557 | "verifyCmd": "$TC actions list action gact", | ||
558 | "matchPattern": "action order [0-9]*: gact action pass random type determ goto chain 1 val 2.*index 90 ref", | ||
559 | "matchCount": "0", | ||
560 | "teardown": [ | ||
561 | "$TC actions flush action gact" | ||
562 | ] | ||
539 | } | 563 | } |
540 | ] | 564 | ] |
diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/police.json b/tools/testing/selftests/tc-testing/tc-tests/actions/police.json index 30f9b54bd666..4086a50a670e 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/police.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/police.json | |||
@@ -715,5 +715,29 @@ | |||
715 | "teardown": [ | 715 | "teardown": [ |
716 | "$TC actions flush action police" | 716 | "$TC actions flush action police" |
717 | ] | 717 | ] |
718 | }, | ||
719 | { | ||
720 | "id": "b48b", | ||
721 | "name": "Add police action with exceed goto chain control action", | ||
722 | "category": [ | ||
723 | "actions", | ||
724 | "police" | ||
725 | ], | ||
726 | "setup": [ | ||
727 | [ | ||
728 | "$TC actions flush action police", | ||
729 | 0, | ||
730 | 1, | ||
731 | 255 | ||
732 | ] | ||
733 | ], | ||
734 | "cmdUnderTest": "$TC actions add action police rate 1mbit burst 1k conform-exceed pass / goto chain 42", | ||
735 | "expExitCode": "255", | ||
736 | "verifyCmd": "$TC actions ls action police", | ||
737 | "matchPattern": "action order [0-9]*: police 0x1 rate 1Mbit burst 1Kb mtu 2Kb action pass/goto chain 42", | ||
738 | "matchCount": "0", | ||
739 | "teardown": [ | ||
740 | "$TC actions flush action police" | ||
741 | ] | ||
718 | } | 742 | } |
719 | ] | 743 | ] |
diff --git a/tools/testing/selftests/tc-testing/tdc_config.py b/tools/testing/selftests/tc-testing/tdc_config.py index a023d0d62b25..d651bc1501bd 100644 --- a/tools/testing/selftests/tc-testing/tdc_config.py +++ b/tools/testing/selftests/tc-testing/tdc_config.py | |||
@@ -16,7 +16,9 @@ NAMES = { | |||
16 | 'DEV2': '', | 16 | 'DEV2': '', |
17 | 'BATCH_FILE': './batch.txt', | 17 | 'BATCH_FILE': './batch.txt', |
18 | # Name of the namespace to use | 18 | # Name of the namespace to use |
19 | 'NS': 'tcut' | 19 | 'NS': 'tcut', |
20 | # Directory containing eBPF test programs | ||
21 | 'EBPFDIR': './bpf' | ||
20 | } | 22 | } |
21 | 23 | ||
22 | 24 | ||
diff --git a/tools/testing/selftests/vm/.gitignore b/tools/testing/selftests/vm/.gitignore index af5ff83f6d7f..31b3c98b6d34 100644 --- a/tools/testing/selftests/vm/.gitignore +++ b/tools/testing/selftests/vm/.gitignore | |||
@@ -13,3 +13,4 @@ mlock-random-test | |||
13 | virtual_address_range | 13 | virtual_address_range |
14 | gup_benchmark | 14 | gup_benchmark |
15 | va_128TBswitch | 15 | va_128TBswitch |
16 | map_fixed_noreplace | ||
diff --git a/tools/testing/selftests/vm/Makefile b/tools/testing/selftests/vm/Makefile index e94b7b14bcb2..6e67e726e5a5 100644 --- a/tools/testing/selftests/vm/Makefile +++ b/tools/testing/selftests/vm/Makefile | |||
@@ -12,6 +12,7 @@ TEST_GEN_FILES += gup_benchmark | |||
12 | TEST_GEN_FILES += hugepage-mmap | 12 | TEST_GEN_FILES += hugepage-mmap |
13 | TEST_GEN_FILES += hugepage-shm | 13 | TEST_GEN_FILES += hugepage-shm |
14 | TEST_GEN_FILES += map_hugetlb | 14 | TEST_GEN_FILES += map_hugetlb |
15 | TEST_GEN_FILES += map_fixed_noreplace | ||
15 | TEST_GEN_FILES += map_populate | 16 | TEST_GEN_FILES += map_populate |
16 | TEST_GEN_FILES += mlock-random-test | 17 | TEST_GEN_FILES += mlock-random-test |
17 | TEST_GEN_FILES += mlock2-tests | 18 | TEST_GEN_FILES += mlock2-tests |
diff --git a/tools/testing/selftests/vm/gup_benchmark.c b/tools/testing/selftests/vm/gup_benchmark.c index 36df55132036..880b96fc80d4 100644 --- a/tools/testing/selftests/vm/gup_benchmark.c +++ b/tools/testing/selftests/vm/gup_benchmark.c | |||
@@ -15,9 +15,12 @@ | |||
15 | #define PAGE_SIZE sysconf(_SC_PAGESIZE) | 15 | #define PAGE_SIZE sysconf(_SC_PAGESIZE) |
16 | 16 | ||
17 | #define GUP_FAST_BENCHMARK _IOWR('g', 1, struct gup_benchmark) | 17 | #define GUP_FAST_BENCHMARK _IOWR('g', 1, struct gup_benchmark) |
18 | #define GUP_LONGTERM_BENCHMARK _IOWR('g', 2, struct gup_benchmark) | ||
19 | #define GUP_BENCHMARK _IOWR('g', 3, struct gup_benchmark) | ||
18 | 20 | ||
19 | struct gup_benchmark { | 21 | struct gup_benchmark { |
20 | __u64 delta_usec; | 22 | __u64 get_delta_usec; |
23 | __u64 put_delta_usec; | ||
21 | __u64 addr; | 24 | __u64 addr; |
22 | __u64 size; | 25 | __u64 size; |
23 | __u32 nr_pages_per_call; | 26 | __u32 nr_pages_per_call; |
@@ -28,10 +31,12 @@ int main(int argc, char **argv) | |||
28 | { | 31 | { |
29 | struct gup_benchmark gup; | 32 | struct gup_benchmark gup; |
30 | unsigned long size = 128 * MB; | 33 | unsigned long size = 128 * MB; |
31 | int i, fd, opt, nr_pages = 1, thp = -1, repeats = 1, write = 0; | 34 | int i, fd, filed, opt, nr_pages = 1, thp = -1, repeats = 1, write = 0; |
35 | int cmd = GUP_FAST_BENCHMARK, flags = MAP_PRIVATE; | ||
36 | char *file = "/dev/zero"; | ||
32 | char *p; | 37 | char *p; |
33 | 38 | ||
34 | while ((opt = getopt(argc, argv, "m:r:n:tT")) != -1) { | 39 | while ((opt = getopt(argc, argv, "m:r:n:f:tTLUSH")) != -1) { |
35 | switch (opt) { | 40 | switch (opt) { |
36 | case 'm': | 41 | case 'm': |
37 | size = atoi(optarg) * MB; | 42 | size = atoi(optarg) * MB; |
@@ -48,13 +53,36 @@ int main(int argc, char **argv) | |||
48 | case 'T': | 53 | case 'T': |
49 | thp = 0; | 54 | thp = 0; |
50 | break; | 55 | break; |
56 | case 'L': | ||
57 | cmd = GUP_LONGTERM_BENCHMARK; | ||
58 | break; | ||
59 | case 'U': | ||
60 | cmd = GUP_BENCHMARK; | ||
61 | break; | ||
51 | case 'w': | 62 | case 'w': |
52 | write = 1; | 63 | write = 1; |
64 | break; | ||
65 | case 'f': | ||
66 | file = optarg; | ||
67 | break; | ||
68 | case 'S': | ||
69 | flags &= ~MAP_PRIVATE; | ||
70 | flags |= MAP_SHARED; | ||
71 | break; | ||
72 | case 'H': | ||
73 | flags |= MAP_HUGETLB; | ||
74 | break; | ||
53 | default: | 75 | default: |
54 | return -1; | 76 | return -1; |
55 | } | 77 | } |
56 | } | 78 | } |
57 | 79 | ||
80 | filed = open(file, O_RDWR|O_CREAT); | ||
81 | if (filed < 0) { | ||
82 | perror("open"); | ||
83 | exit(filed); | ||
84 | } | ||
85 | |||
58 | gup.nr_pages_per_call = nr_pages; | 86 | gup.nr_pages_per_call = nr_pages; |
59 | gup.flags = write; | 87 | gup.flags = write; |
60 | 88 | ||
@@ -62,8 +90,7 @@ int main(int argc, char **argv) | |||
62 | if (fd == -1) | 90 | if (fd == -1) |
63 | perror("open"), exit(1); | 91 | perror("open"), exit(1); |
64 | 92 | ||
65 | p = mmap(NULL, size, PROT_READ | PROT_WRITE, | 93 | p = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, filed, 0); |
66 | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); | ||
67 | if (p == MAP_FAILED) | 94 | if (p == MAP_FAILED) |
68 | perror("mmap"), exit(1); | 95 | perror("mmap"), exit(1); |
69 | gup.addr = (unsigned long)p; | 96 | gup.addr = (unsigned long)p; |
@@ -78,10 +105,11 @@ int main(int argc, char **argv) | |||
78 | 105 | ||
79 | for (i = 0; i < repeats; i++) { | 106 | for (i = 0; i < repeats; i++) { |
80 | gup.size = size; | 107 | gup.size = size; |
81 | if (ioctl(fd, GUP_FAST_BENCHMARK, &gup)) | 108 | if (ioctl(fd, cmd, &gup)) |
82 | perror("ioctl"), exit(1); | 109 | perror("ioctl"), exit(1); |
83 | 110 | ||
84 | printf("Time: %lld us", gup.delta_usec); | 111 | printf("Time: get:%lld put:%lld us", gup.get_delta_usec, |
112 | gup.put_delta_usec); | ||
85 | if (gup.size != size) | 113 | if (gup.size != size) |
86 | printf(", truncated (size: %lld)", gup.size); | 114 | printf(", truncated (size: %lld)", gup.size); |
87 | printf("\n"); | 115 | printf("\n"); |
diff --git a/tools/testing/selftests/vm/map_fixed_noreplace.c b/tools/testing/selftests/vm/map_fixed_noreplace.c new file mode 100644 index 000000000000..d91bde511268 --- /dev/null +++ b/tools/testing/selftests/vm/map_fixed_noreplace.c | |||
@@ -0,0 +1,206 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | |||
3 | /* | ||
4 | * Test that MAP_FIXED_NOREPLACE works. | ||
5 | * | ||
6 | * Copyright 2018, Jann Horn <jannh@google.com> | ||
7 | * Copyright 2018, Michael Ellerman, IBM Corporation. | ||
8 | */ | ||
9 | |||
10 | #include <sys/mman.h> | ||
11 | #include <errno.h> | ||
12 | #include <stdio.h> | ||
13 | #include <stdlib.h> | ||
14 | #include <unistd.h> | ||
15 | |||
16 | #ifndef MAP_FIXED_NOREPLACE | ||
17 | #define MAP_FIXED_NOREPLACE 0x100000 | ||
18 | #endif | ||
19 | |||
20 | #define BASE_ADDRESS (256ul * 1024 * 1024) | ||
21 | |||
22 | |||
23 | static void dump_maps(void) | ||
24 | { | ||
25 | char cmd[32]; | ||
26 | |||
27 | snprintf(cmd, sizeof(cmd), "cat /proc/%d/maps", getpid()); | ||
28 | system(cmd); | ||
29 | } | ||
30 | |||
31 | int main(void) | ||
32 | { | ||
33 | unsigned long flags, addr, size, page_size; | ||
34 | char *p; | ||
35 | |||
36 | page_size = sysconf(_SC_PAGE_SIZE); | ||
37 | |||
38 | flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE; | ||
39 | |||
40 | // Check we can map all the areas we need below | ||
41 | errno = 0; | ||
42 | addr = BASE_ADDRESS; | ||
43 | size = 5 * page_size; | ||
44 | p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0); | ||
45 | |||
46 | printf("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p); | ||
47 | |||
48 | if (p == MAP_FAILED) { | ||
49 | dump_maps(); | ||
50 | printf("Error: couldn't map the space we need for the test\n"); | ||
51 | return 1; | ||
52 | } | ||
53 | |||
54 | errno = 0; | ||
55 | if (munmap((void *)addr, 5 * page_size) != 0) { | ||
56 | dump_maps(); | ||
57 | printf("Error: munmap failed!?\n"); | ||
58 | return 1; | ||
59 | } | ||
60 | printf("unmap() successful\n"); | ||
61 | |||
62 | errno = 0; | ||
63 | addr = BASE_ADDRESS + page_size; | ||
64 | size = 3 * page_size; | ||
65 | p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0); | ||
66 | printf("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p); | ||
67 | |||
68 | if (p == MAP_FAILED) { | ||
69 | dump_maps(); | ||
70 | printf("Error: first mmap() failed unexpectedly\n"); | ||
71 | return 1; | ||
72 | } | ||
73 | |||
74 | /* | ||
75 | * Exact same mapping again: | ||
76 | * base | free | new | ||
77 | * +1 | mapped | new | ||
78 | * +2 | mapped | new | ||
79 | * +3 | mapped | new | ||
80 | * +4 | free | new | ||
81 | */ | ||
82 | errno = 0; | ||
83 | addr = BASE_ADDRESS; | ||
84 | size = 5 * page_size; | ||
85 | p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0); | ||
86 | printf("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p); | ||
87 | |||
88 | if (p != MAP_FAILED) { | ||
89 | dump_maps(); | ||
90 | printf("Error:1: mmap() succeeded when it shouldn't have\n"); | ||
91 | return 1; | ||
92 | } | ||
93 | |||
94 | /* | ||
95 | * Second mapping contained within first: | ||
96 | * | ||
97 | * base | free | | ||
98 | * +1 | mapped | | ||
99 | * +2 | mapped | new | ||
100 | * +3 | mapped | | ||
101 | * +4 | free | | ||
102 | */ | ||
103 | errno = 0; | ||
104 | addr = BASE_ADDRESS + (2 * page_size); | ||
105 | size = page_size; | ||
106 | p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0); | ||
107 | printf("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p); | ||
108 | |||
109 | if (p != MAP_FAILED) { | ||
110 | dump_maps(); | ||
111 | printf("Error:2: mmap() succeeded when it shouldn't have\n"); | ||
112 | return 1; | ||
113 | } | ||
114 | |||
115 | /* | ||
116 | * Overlap end of existing mapping: | ||
117 | * base | free | | ||
118 | * +1 | mapped | | ||
119 | * +2 | mapped | | ||
120 | * +3 | mapped | new | ||
121 | * +4 | free | new | ||
122 | */ | ||
123 | errno = 0; | ||
124 | addr = BASE_ADDRESS + (3 * page_size); | ||
125 | size = 2 * page_size; | ||
126 | p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0); | ||
127 | printf("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p); | ||
128 | |||
129 | if (p != MAP_FAILED) { | ||
130 | dump_maps(); | ||
131 | printf("Error:3: mmap() succeeded when it shouldn't have\n"); | ||
132 | return 1; | ||
133 | } | ||
134 | |||
135 | /* | ||
136 | * Overlap start of existing mapping: | ||
137 | * base | free | new | ||
138 | * +1 | mapped | new | ||
139 | * +2 | mapped | | ||
140 | * +3 | mapped | | ||
141 | * +4 | free | | ||
142 | */ | ||
143 | errno = 0; | ||
144 | addr = BASE_ADDRESS; | ||
145 | size = 2 * page_size; | ||
146 | p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0); | ||
147 | printf("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p); | ||
148 | |||
149 | if (p != MAP_FAILED) { | ||
150 | dump_maps(); | ||
151 | printf("Error:4: mmap() succeeded when it shouldn't have\n"); | ||
152 | return 1; | ||
153 | } | ||
154 | |||
155 | /* | ||
156 | * Adjacent to start of existing mapping: | ||
157 | * base | free | new | ||
158 | * +1 | mapped | | ||
159 | * +2 | mapped | | ||
160 | * +3 | mapped | | ||
161 | * +4 | free | | ||
162 | */ | ||
163 | errno = 0; | ||
164 | addr = BASE_ADDRESS; | ||
165 | size = page_size; | ||
166 | p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0); | ||
167 | printf("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p); | ||
168 | |||
169 | if (p == MAP_FAILED) { | ||
170 | dump_maps(); | ||
171 | printf("Error:5: mmap() failed when it shouldn't have\n"); | ||
172 | return 1; | ||
173 | } | ||
174 | |||
175 | /* | ||
176 | * Adjacent to end of existing mapping: | ||
177 | * base | free | | ||
178 | * +1 | mapped | | ||
179 | * +2 | mapped | | ||
180 | * +3 | mapped | | ||
181 | * +4 | free | new | ||
182 | */ | ||
183 | errno = 0; | ||
184 | addr = BASE_ADDRESS + (4 * page_size); | ||
185 | size = page_size; | ||
186 | p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0); | ||
187 | printf("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p); | ||
188 | |||
189 | if (p == MAP_FAILED) { | ||
190 | dump_maps(); | ||
191 | printf("Error:6: mmap() failed when it shouldn't have\n"); | ||
192 | return 1; | ||
193 | } | ||
194 | |||
195 | addr = BASE_ADDRESS; | ||
196 | size = 5 * page_size; | ||
197 | if (munmap((void *)addr, size) != 0) { | ||
198 | dump_maps(); | ||
199 | printf("Error: munmap failed!?\n"); | ||
200 | return 1; | ||
201 | } | ||
202 | printf("unmap() successful\n"); | ||
203 | |||
204 | printf("OK\n"); | ||
205 | return 0; | ||
206 | } | ||
diff --git a/tools/testing/selftests/vm/userfaultfd.c b/tools/testing/selftests/vm/userfaultfd.c index 7b8171e3128a..5d1db824f73a 100644 --- a/tools/testing/selftests/vm/userfaultfd.c +++ b/tools/testing/selftests/vm/userfaultfd.c | |||
@@ -34,18 +34,6 @@ | |||
34 | * per-CPU threads 1 by triggering userfaults inside | 34 | * per-CPU threads 1 by triggering userfaults inside |
35 | * pthread_mutex_lock will also verify the atomicity of the memory | 35 | * pthread_mutex_lock will also verify the atomicity of the memory |
36 | * transfer (UFFDIO_COPY). | 36 | * transfer (UFFDIO_COPY). |
37 | * | ||
38 | * The program takes two parameters: the amounts of physical memory in | ||
39 | * megabytes (MiB) of the area and the number of bounces to execute. | ||
40 | * | ||
41 | * # 100MiB 99999 bounces | ||
42 | * ./userfaultfd 100 99999 | ||
43 | * | ||
44 | * # 1GiB 99 bounces | ||
45 | * ./userfaultfd 1000 99 | ||
46 | * | ||
47 | * # 10MiB-~6GiB 999 bounces, continue forever unless an error triggers | ||
48 | * while ./userfaultfd $[RANDOM % 6000 + 10] 999; do true; done | ||
49 | */ | 37 | */ |
50 | 38 | ||
51 | #define _GNU_SOURCE | 39 | #define _GNU_SOURCE |
@@ -115,6 +103,30 @@ pthread_attr_t attr; | |||
115 | ~(unsigned long)(sizeof(unsigned long long) \ | 103 | ~(unsigned long)(sizeof(unsigned long long) \ |
116 | - 1))) | 104 | - 1))) |
117 | 105 | ||
106 | const char *examples = | ||
107 | "# Run anonymous memory test on 100MiB region with 99999 bounces:\n" | ||
108 | "./userfaultfd anon 100 99999\n\n" | ||
109 | "# Run share memory test on 1GiB region with 99 bounces:\n" | ||
110 | "./userfaultfd shmem 1000 99\n\n" | ||
111 | "# Run hugetlb memory test on 256MiB region with 50 bounces (using /dev/hugepages/hugefile):\n" | ||
112 | "./userfaultfd hugetlb 256 50 /dev/hugepages/hugefile\n\n" | ||
113 | "# Run the same hugetlb test but using shmem:\n" | ||
114 | "./userfaultfd hugetlb_shared 256 50 /dev/hugepages/hugefile\n\n" | ||
115 | "# 10MiB-~6GiB 999 bounces anonymous test, " | ||
116 | "continue forever unless an error triggers\n" | ||
117 | "while ./userfaultfd anon $[RANDOM % 6000 + 10] 999; do true; done\n\n"; | ||
118 | |||
119 | static void usage(void) | ||
120 | { | ||
121 | fprintf(stderr, "\nUsage: ./userfaultfd <test type> <MiB> <bounces> " | ||
122 | "[hugetlbfs_file]\n\n"); | ||
123 | fprintf(stderr, "Supported <test type>: anon, hugetlb, " | ||
124 | "hugetlb_shared, shmem\n\n"); | ||
125 | fprintf(stderr, "Examples:\n\n"); | ||
126 | fprintf(stderr, examples); | ||
127 | exit(1); | ||
128 | } | ||
129 | |||
118 | static int anon_release_pages(char *rel_area) | 130 | static int anon_release_pages(char *rel_area) |
119 | { | 131 | { |
120 | int ret = 0; | 132 | int ret = 0; |
@@ -439,6 +451,43 @@ static int copy_page(int ufd, unsigned long offset) | |||
439 | return __copy_page(ufd, offset, false); | 451 | return __copy_page(ufd, offset, false); |
440 | } | 452 | } |
441 | 453 | ||
454 | static int uffd_read_msg(int ufd, struct uffd_msg *msg) | ||
455 | { | ||
456 | int ret = read(uffd, msg, sizeof(*msg)); | ||
457 | |||
458 | if (ret != sizeof(*msg)) { | ||
459 | if (ret < 0) { | ||
460 | if (errno == EAGAIN) | ||
461 | return 1; | ||
462 | else | ||
463 | perror("blocking read error"), exit(1); | ||
464 | } else { | ||
465 | fprintf(stderr, "short read\n"), exit(1); | ||
466 | } | ||
467 | } | ||
468 | |||
469 | return 0; | ||
470 | } | ||
471 | |||
472 | /* Return 1 if page fault handled by us; otherwise 0 */ | ||
473 | static int uffd_handle_page_fault(struct uffd_msg *msg) | ||
474 | { | ||
475 | unsigned long offset; | ||
476 | |||
477 | if (msg->event != UFFD_EVENT_PAGEFAULT) | ||
478 | fprintf(stderr, "unexpected msg event %u\n", | ||
479 | msg->event), exit(1); | ||
480 | |||
481 | if (bounces & BOUNCE_VERIFY && | ||
482 | msg->arg.pagefault.flags & UFFD_PAGEFAULT_FLAG_WRITE) | ||
483 | fprintf(stderr, "unexpected write fault\n"), exit(1); | ||
484 | |||
485 | offset = (char *)(unsigned long)msg->arg.pagefault.address - area_dst; | ||
486 | offset &= ~(page_size-1); | ||
487 | |||
488 | return copy_page(uffd, offset); | ||
489 | } | ||
490 | |||
442 | static void *uffd_poll_thread(void *arg) | 491 | static void *uffd_poll_thread(void *arg) |
443 | { | 492 | { |
444 | unsigned long cpu = (unsigned long) arg; | 493 | unsigned long cpu = (unsigned long) arg; |
@@ -446,7 +495,6 @@ static void *uffd_poll_thread(void *arg) | |||
446 | struct uffd_msg msg; | 495 | struct uffd_msg msg; |
447 | struct uffdio_register uffd_reg; | 496 | struct uffdio_register uffd_reg; |
448 | int ret; | 497 | int ret; |
449 | unsigned long offset; | ||
450 | char tmp_chr; | 498 | char tmp_chr; |
451 | unsigned long userfaults = 0; | 499 | unsigned long userfaults = 0; |
452 | 500 | ||
@@ -470,25 +518,15 @@ static void *uffd_poll_thread(void *arg) | |||
470 | if (!(pollfd[0].revents & POLLIN)) | 518 | if (!(pollfd[0].revents & POLLIN)) |
471 | fprintf(stderr, "pollfd[0].revents %d\n", | 519 | fprintf(stderr, "pollfd[0].revents %d\n", |
472 | pollfd[0].revents), exit(1); | 520 | pollfd[0].revents), exit(1); |
473 | ret = read(uffd, &msg, sizeof(msg)); | 521 | if (uffd_read_msg(uffd, &msg)) |
474 | if (ret < 0) { | 522 | continue; |
475 | if (errno == EAGAIN) | ||
476 | continue; | ||
477 | perror("nonblocking read error"), exit(1); | ||
478 | } | ||
479 | switch (msg.event) { | 523 | switch (msg.event) { |
480 | default: | 524 | default: |
481 | fprintf(stderr, "unexpected msg event %u\n", | 525 | fprintf(stderr, "unexpected msg event %u\n", |
482 | msg.event), exit(1); | 526 | msg.event), exit(1); |
483 | break; | 527 | break; |
484 | case UFFD_EVENT_PAGEFAULT: | 528 | case UFFD_EVENT_PAGEFAULT: |
485 | if (msg.arg.pagefault.flags & UFFD_PAGEFAULT_FLAG_WRITE) | 529 | userfaults += uffd_handle_page_fault(&msg); |
486 | fprintf(stderr, "unexpected write fault\n"), exit(1); | ||
487 | offset = (char *)(unsigned long)msg.arg.pagefault.address - | ||
488 | area_dst; | ||
489 | offset &= ~(page_size-1); | ||
490 | if (copy_page(uffd, offset)) | ||
491 | userfaults++; | ||
492 | break; | 530 | break; |
493 | case UFFD_EVENT_FORK: | 531 | case UFFD_EVENT_FORK: |
494 | close(uffd); | 532 | close(uffd); |
@@ -516,8 +554,6 @@ static void *uffd_read_thread(void *arg) | |||
516 | { | 554 | { |
517 | unsigned long *this_cpu_userfaults; | 555 | unsigned long *this_cpu_userfaults; |
518 | struct uffd_msg msg; | 556 | struct uffd_msg msg; |
519 | unsigned long offset; | ||
520 | int ret; | ||
521 | 557 | ||
522 | this_cpu_userfaults = (unsigned long *) arg; | 558 | this_cpu_userfaults = (unsigned long *) arg; |
523 | *this_cpu_userfaults = 0; | 559 | *this_cpu_userfaults = 0; |
@@ -526,24 +562,9 @@ static void *uffd_read_thread(void *arg) | |||
526 | /* from here cancellation is ok */ | 562 | /* from here cancellation is ok */ |
527 | 563 | ||
528 | for (;;) { | 564 | for (;;) { |
529 | ret = read(uffd, &msg, sizeof(msg)); | 565 | if (uffd_read_msg(uffd, &msg)) |
530 | if (ret != sizeof(msg)) { | 566 | continue; |
531 | if (ret < 0) | 567 | (*this_cpu_userfaults) += uffd_handle_page_fault(&msg); |
532 | perror("blocking read error"), exit(1); | ||
533 | else | ||
534 | fprintf(stderr, "short read\n"), exit(1); | ||
535 | } | ||
536 | if (msg.event != UFFD_EVENT_PAGEFAULT) | ||
537 | fprintf(stderr, "unexpected msg event %u\n", | ||
538 | msg.event), exit(1); | ||
539 | if (bounces & BOUNCE_VERIFY && | ||
540 | msg.arg.pagefault.flags & UFFD_PAGEFAULT_FLAG_WRITE) | ||
541 | fprintf(stderr, "unexpected write fault\n"), exit(1); | ||
542 | offset = (char *)(unsigned long)msg.arg.pagefault.address - | ||
543 | area_dst; | ||
544 | offset &= ~(page_size-1); | ||
545 | if (copy_page(uffd, offset)) | ||
546 | (*this_cpu_userfaults)++; | ||
547 | } | 568 | } |
548 | return (void *)NULL; | 569 | return (void *)NULL; |
549 | } | 570 | } |
@@ -605,6 +626,12 @@ static int stress(unsigned long *userfaults) | |||
605 | if (uffd_test_ops->release_pages(area_src)) | 626 | if (uffd_test_ops->release_pages(area_src)) |
606 | return 1; | 627 | return 1; |
607 | 628 | ||
629 | |||
630 | finished = 1; | ||
631 | for (cpu = 0; cpu < nr_cpus; cpu++) | ||
632 | if (pthread_join(locking_threads[cpu], NULL)) | ||
633 | return 1; | ||
634 | |||
608 | for (cpu = 0; cpu < nr_cpus; cpu++) { | 635 | for (cpu = 0; cpu < nr_cpus; cpu++) { |
609 | char c; | 636 | char c; |
610 | if (bounces & BOUNCE_POLL) { | 637 | if (bounces & BOUNCE_POLL) { |
@@ -622,11 +649,6 @@ static int stress(unsigned long *userfaults) | |||
622 | } | 649 | } |
623 | } | 650 | } |
624 | 651 | ||
625 | finished = 1; | ||
626 | for (cpu = 0; cpu < nr_cpus; cpu++) | ||
627 | if (pthread_join(locking_threads[cpu], NULL)) | ||
628 | return 1; | ||
629 | |||
630 | return 0; | 652 | return 0; |
631 | } | 653 | } |
632 | 654 | ||
@@ -1272,8 +1294,7 @@ static void sigalrm(int sig) | |||
1272 | int main(int argc, char **argv) | 1294 | int main(int argc, char **argv) |
1273 | { | 1295 | { |
1274 | if (argc < 4) | 1296 | if (argc < 4) |
1275 | fprintf(stderr, "Usage: <test type> <MiB> <bounces> [hugetlbfs_file]\n"), | 1297 | usage(); |
1276 | exit(1); | ||
1277 | 1298 | ||
1278 | if (signal(SIGALRM, sigalrm) == SIG_ERR) | 1299 | if (signal(SIGALRM, sigalrm) == SIG_ERR) |
1279 | fprintf(stderr, "failed to arm SIGALRM"), exit(1); | 1300 | fprintf(stderr, "failed to arm SIGALRM"), exit(1); |
@@ -1286,20 +1307,19 @@ int main(int argc, char **argv) | |||
1286 | nr_cpus; | 1307 | nr_cpus; |
1287 | if (!nr_pages_per_cpu) { | 1308 | if (!nr_pages_per_cpu) { |
1288 | fprintf(stderr, "invalid MiB\n"); | 1309 | fprintf(stderr, "invalid MiB\n"); |
1289 | fprintf(stderr, "Usage: <MiB> <bounces>\n"), exit(1); | 1310 | usage(); |
1290 | } | 1311 | } |
1291 | 1312 | ||
1292 | bounces = atoi(argv[3]); | 1313 | bounces = atoi(argv[3]); |
1293 | if (bounces <= 0) { | 1314 | if (bounces <= 0) { |
1294 | fprintf(stderr, "invalid bounces\n"); | 1315 | fprintf(stderr, "invalid bounces\n"); |
1295 | fprintf(stderr, "Usage: <MiB> <bounces>\n"), exit(1); | 1316 | usage(); |
1296 | } | 1317 | } |
1297 | nr_pages = nr_pages_per_cpu * nr_cpus; | 1318 | nr_pages = nr_pages_per_cpu * nr_cpus; |
1298 | 1319 | ||
1299 | if (test_type == TEST_HUGETLB) { | 1320 | if (test_type == TEST_HUGETLB) { |
1300 | if (argc < 5) | 1321 | if (argc < 5) |
1301 | fprintf(stderr, "Usage: hugetlb <MiB> <bounces> <hugetlbfs_file>\n"), | 1322 | usage(); |
1302 | exit(1); | ||
1303 | huge_fd = open(argv[4], O_CREAT | O_RDWR, 0755); | 1323 | huge_fd = open(argv[4], O_CREAT | O_RDWR, 0755); |
1304 | if (huge_fd < 0) { | 1324 | if (huge_fd < 0) { |
1305 | fprintf(stderr, "Open of %s failed", argv[3]); | 1325 | fprintf(stderr, "Open of %s failed", argv[3]); |
diff --git a/tools/usb/usbip/libsrc/usbip_host_common.c b/tools/usb/usbip/libsrc/usbip_host_common.c index dc93fadbee96..d79c7581b175 100644 --- a/tools/usb/usbip/libsrc/usbip_host_common.c +++ b/tools/usb/usbip/libsrc/usbip_host_common.c | |||
@@ -43,7 +43,7 @@ static int32_t read_attr_usbip_status(struct usbip_usb_device *udev) | |||
43 | int size; | 43 | int size; |
44 | int fd; | 44 | int fd; |
45 | int length; | 45 | int length; |
46 | char status; | 46 | char status[2] = { 0 }; |
47 | int value = 0; | 47 | int value = 0; |
48 | 48 | ||
49 | size = snprintf(status_attr_path, sizeof(status_attr_path), | 49 | size = snprintf(status_attr_path, sizeof(status_attr_path), |
@@ -61,14 +61,14 @@ static int32_t read_attr_usbip_status(struct usbip_usb_device *udev) | |||
61 | return -1; | 61 | return -1; |
62 | } | 62 | } |
63 | 63 | ||
64 | length = read(fd, &status, 1); | 64 | length = read(fd, status, 1); |
65 | if (length < 0) { | 65 | if (length < 0) { |
66 | err("error reading attribute %s", status_attr_path); | 66 | err("error reading attribute %s", status_attr_path); |
67 | close(fd); | 67 | close(fd); |
68 | return -1; | 68 | return -1; |
69 | } | 69 | } |
70 | 70 | ||
71 | value = atoi(&status); | 71 | value = atoi(status); |
72 | 72 | ||
73 | return value; | 73 | return value; |
74 | } | 74 | } |
diff --git a/tools/usb/usbip/libsrc/vhci_driver.c b/tools/usb/usbip/libsrc/vhci_driver.c index 4204359c9fee..8159fd98680b 100644 --- a/tools/usb/usbip/libsrc/vhci_driver.c +++ b/tools/usb/usbip/libsrc/vhci_driver.c | |||
@@ -150,7 +150,7 @@ static int get_nports(struct udev_device *hc_device) | |||
150 | 150 | ||
151 | static int vhci_hcd_filter(const struct dirent *dirent) | 151 | static int vhci_hcd_filter(const struct dirent *dirent) |
152 | { | 152 | { |
153 | return strcmp(dirent->d_name, "vhci_hcd") >= 0; | 153 | return !strncmp(dirent->d_name, "vhci_hcd.", 9); |
154 | } | 154 | } |
155 | 155 | ||
156 | static int get_ncontrollers(void) | 156 | static int get_ncontrollers(void) |