History

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

Daniel Borkmann says: ==================== pull-request: bpf-next 2022-09-05 The following pull-request contains BPF updates for your *net-next* tree. We've added 106 non-merge commits during the last 18 day(s) which contain a total of 159 files changed, 5225 insertions(+), 1358 deletions(-). There are two small merge conflicts, resolve them as follows: 1) tools/testing/selftests/bpf/DENYLIST.s390x Commit 27e23836ce22 ("selftests/bpf: Add lru_bug to s390x deny list") in bpf tree was needed to get BPF CI green on s390x, but it conflicted with newly added tests on bpf-next. Resolve by adding both hunks, result: [...] lru_bug # prog 'printk': failed to auto-attach: -524 setget_sockopt # attach unexpected error: -524 (trampoline) cb_refs # expected error message unexpected error: -524 (trampoline) cgroup_hierarchical_stats # JIT does not support calling kernel function (kfunc) htab_update # failed to attach: ERROR: strerror_r(-524)=22 (trampoline) [...] 2) net/core/filter.c Commit 1227c1771dd2 ("net: Fix data-races around sysctl_[rw]mem_(max|default).") from net tree conflicts with commit 29003875bd5b ("bpf: Change bpf_setsockopt(SOL_SOCKET) to reuse sk_setsockopt()") from bpf-next tree. Take the code as it is from bpf-next tree, result: [...] if (getopt) { if (optname == SO_BINDTODEVICE) return -EINVAL; return sk_getsockopt(sk, SOL_SOCKET, optname, KERNEL_SOCKPTR(optval), KERNEL_SOCKPTR(optlen)); } return sk_setsockopt(sk, SOL_SOCKET, optname, KERNEL_SOCKPTR(optval), *optlen); [...] The main changes are: 1) Add any-context BPF specific memory allocator which is useful in particular for BPF tracing with bonus of performance equal to full prealloc, from Alexei Starovoitov. 2) Big batch to remove duplicated code from bpf_{get,set}sockopt() helpers as an effort to reuse the existing core socket code as much as possible, from Martin KaFai Lau. 3) Extend BPF flow dissector for BPF programs to just augment the in-kernel dissector with custom logic. In other words, allow for partial replacement, from Shmulik Ladkani. 4) Add a new cgroup iterator to BPF with different traversal options, from Hao Luo. 5) Support for BPF to collect hierarchical cgroup statistics efficiently through BPF integration with the rstat framework, from Yosry Ahmed. 6) Support bpf_{g,s}et_retval() under more BPF cgroup hooks, from Stanislav Fomichev. 7) BPF hash table and local storages fixes under fully preemptible kernel, from Hou Tao. 8) Add various improvements to BPF selftests and libbpf for compilation with gcc BPF backend, from James Hilliard. 9) Fix verifier helper permissions and reference state management for synchronous callbacks, from Kumar Kartikeya Dwivedi. 10) Add support for BPF selftest's xskxceiver to also be used against real devices that support MAC loopback, from Maciej Fijalkowski. 11) Various fixes to the bpf-helpers(7) man page generation script, from Quentin Monnet. 12) Document BPF verifier's tnum_in(tnum_range(), ...) gotchas, from Shung-Hsi Yu. 13) Various minor misc improvements all over the place. * https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next: (106 commits) bpf: Optimize rcu_barrier usage between hash map and bpf_mem_alloc. bpf: Remove usage of kmem_cache from bpf_mem_cache. bpf: Remove prealloc-only restriction for sleepable bpf programs. bpf: Prepare bpf_mem_alloc to be used by sleepable bpf programs. bpf: Remove tracing program restriction on map types bpf: Convert percpu hash map to per-cpu bpf_mem_alloc. bpf: Add percpu allocation support to bpf_mem_alloc. bpf: Batch call_rcu callbacks instead of SLAB_TYPESAFE_BY_RCU. bpf: Adjust low/high watermarks in bpf_mem_cache bpf: Optimize call_rcu in non-preallocated hash map. bpf: Optimize element count in non-preallocated hash map. bpf: Relax the requirement to use preallocated hash maps in tracing progs. samples/bpf: Reduce syscall overhead in map_perf_test. selftests/bpf: Improve test coverage of test_maps bpf: Convert hash map to bpf_mem_alloc. bpf: Introduce any context BPF specific memory allocator. selftest/bpf: Add test for bpf_getsockopt() bpf: Change bpf_getsockopt(SOL_IPV6) to reuse do_ipv6_getsockopt() bpf: Change bpf_getsockopt(SOL_IP) to reuse do_ip_getsockopt() bpf: Change bpf_getsockopt(SOL_TCP) to reuse do_tcp_getsockopt() ... ====================

Paolo Abeni committed 4 years ago

Commit 2786bcf2 parents 03fdb11 274052a159 files · +5225 −1358Browse files

Unified · Split

159 files
  1. arch/mips/net/bpf_jit_comp32.c +9 −1
  2. arch/mips/net/bpf_jit_comp64.c +9 −1
  3. include/linux/bpf-cgroup.h +17 −0
  4. include/linux/bpf.h +22 −0
  5. include/linux/bpf_mem_alloc.h +28 −0
  6. include/linux/bpf_verifier.h +11 −0
  7. include/linux/filter.h +1 −2
  8. include/linux/igmp.h +2 −2
  9. include/linux/mroute.h +3 −3
  10. include/linux/mroute6.h +2 −2
  11. include/linux/skbuff.h +2 −2
  12. include/linux/sockptr.h +5 −0
  13. include/linux/tnum.h +18 −2
  14. include/net/ip.h +4 −0
  15. include/net/ipv6.h +5 −1
  16. include/net/ipv6_stubs.h +4 −0
  17. include/net/sock.h +9 −0
  18. include/net/tcp.h +4 −0
  19. include/uapi/linux/bpf.h +69 −14
  20. kernel/bpf/Makefile +4 −1
  21. kernel/bpf/bpf_iter.c +5 −0
  22. kernel/bpf/bpf_local_storage.c +2 −2
  23. kernel/bpf/bpf_lsm.c +14 −9
  24. kernel/bpf/bpf_task_storage.c +4 −4
  25. kernel/bpf/cgroup.c +134 −23
  26. kernel/bpf/cgroup_iter.c +282 −0
  27. kernel/bpf/hashtab.c +123 −45
  28. kernel/bpf/helpers.c +9 −39
  29. kernel/bpf/memalloc.c +634 −0
  30. kernel/bpf/syscall.c +10 −5
  31. kernel/bpf/trampoline.c +4 −4
  32. kernel/bpf/verifier.c +33 −61
  33. kernel/cgroup/rstat.c +48 −0
  34. net/core/filter.c +262 −373
  35. net/core/flow_dissector.c +10 −6
  36. net/core/sock.c +94 −40
  37. net/ipv4/igmp.c +13 −9
  38. net/ipv4/ip_sockglue.c +62 −52
  39. net/ipv4/ipmr.c +5 −4
  40. net/ipv4/tcp.c +59 −57
  41. net/ipv6/af_inet6.c +2 −0
  42. net/ipv6/ip6mr.c +5 −5
  43. net/ipv6/ipv6_sockglue.c +59 −54
  44. net/ipv6/mcast.c +4 −4
  45. samples/bpf/map_perf_test_kern.c +28 −16
  46. samples/bpf/map_perf_test_user.c +1 −1
  47. scripts/bpf_doc.py +71 −7
  48. tools/bpf/bpftool/btf_dumper.c +1 −1
  49. tools/bpf/bpftool/link.c +35 −0
  50. tools/include/uapi/linux/bpf.h +69 −14
  51. tools/lib/bpf/bpf_helpers.h +13 −6
  52. tools/lib/bpf/skel_internal.h +23 −0
  53. tools/testing/selftests/bpf/DENYLIST.s390x +4 −0
  54. tools/testing/selftests/bpf/Makefile +19 −18
  55. tools/testing/selftests/bpf/README.rst +4 −4
  56. tools/testing/selftests/bpf/cgroup_getset_retval_hooks.h +25 −0
  57. tools/testing/selftests/bpf/cgroup_helpers.c +161 −41
  58. tools/testing/selftests/bpf/cgroup_helpers.h +13 −6
  59. tools/testing/selftests/bpf/get_cgroup_id_user.c +1 −1
  60. tools/testing/selftests/bpf/map_tests/task_storage_map.c +122 −0
  61. tools/testing/selftests/bpf/prog_tests/bpf_obj_id.c +1 −1
  62. tools/testing/selftests/bpf/prog_tests/bpf_verif_scale.c +27 −27
  63. tools/testing/selftests/bpf/prog_tests/btf.c +2 −2
  64. tools/testing/selftests/bpf/prog_tests/btf_dump.c +5 −5
  65. tools/testing/selftests/bpf/prog_tests/btf_endian.c +1 −1
  66. tools/testing/selftests/bpf/prog_tests/cb_refs.c +48 −0
  67. tools/testing/selftests/bpf/prog_tests/cgroup_getset_retval.c +48 −0
  68. tools/testing/selftests/bpf/prog_tests/cgroup_hierarchical_stats.c +357 −0
  69. tools/testing/selftests/bpf/prog_tests/cgroup_iter.c +224 −0
  70. tools/testing/selftests/bpf/prog_tests/connect_force_port.c +1 −1
  71. tools/testing/selftests/bpf/prog_tests/core_reloc.c +37 −37
  72. tools/testing/selftests/bpf/prog_tests/fexit_bpf2bpf.c +22 −22
  73. tools/testing/selftests/bpf/prog_tests/flow_dissector.c +43 −1
  74. tools/testing/selftests/bpf/prog_tests/flow_dissector_load_bytes.c +1 −1
  75. tools/testing/selftests/bpf/prog_tests/get_stack_raw_tp.c +2 −2
  76. tools/testing/selftests/bpf/prog_tests/global_data.c +1 −1
  77. tools/testing/selftests/bpf/prog_tests/global_data_init.c +1 −1
  78. tools/testing/selftests/bpf/prog_tests/global_func_args.c +1 −1
  79. tools/testing/selftests/bpf/prog_tests/htab_update.c +126 −0
  80. tools/testing/selftests/bpf/prog_tests/kfree_skb.c +1 −1
  81. tools/testing/selftests/bpf/prog_tests/kfunc_call.c +1 −1
  82. tools/testing/selftests/bpf/prog_tests/l4lb_all.c +2 −2
  83. tools/testing/selftests/bpf/prog_tests/load_bytes_relative.c +2 −2
  84. tools/testing/selftests/bpf/prog_tests/map_lock.c +1 −1
  85. tools/testing/selftests/bpf/prog_tests/pinning.c +2 −2
  86. tools/testing/selftests/bpf/prog_tests/pkt_access.c +1 −1
  87. tools/testing/selftests/bpf/prog_tests/pkt_md_access.c +1 −1
  88. tools/testing/selftests/bpf/prog_tests/probe_user.c +1 −1
  89. tools/testing/selftests/bpf/prog_tests/queue_stack_map.c +2 −2
  90. tools/testing/selftests/bpf/prog_tests/rdonly_maps.c +1 −1
  91. tools/testing/selftests/bpf/prog_tests/reference_tracking.c +1 −1
  92. tools/testing/selftests/bpf/prog_tests/resolve_btfids.c +1 −1
  93. tools/testing/selftests/bpf/prog_tests/select_reuseport.c +2 −2
  94. tools/testing/selftests/bpf/prog_tests/setget_sockopt.c +125 −0
  95. tools/testing/selftests/bpf/prog_tests/sk_assign.c +1 −1
  96. tools/testing/selftests/bpf/prog_tests/skb_ctx.c +1 −1
  97. tools/testing/selftests/bpf/prog_tests/skb_helpers.c +1 −1
  98. tools/testing/selftests/bpf/prog_tests/sockopt_inherit.c +1 −1
  99. tools/testing/selftests/bpf/prog_tests/sockopt_multi.c +1 −1
  100. tools/testing/selftests/bpf/prog_tests/spinlock.c +1 −1
  101. tools/testing/selftests/bpf/prog_tests/stacktrace_map.c +1 −1
  102. tools/testing/selftests/bpf/prog_tests/stacktrace_map_raw_tp.c +1 −1
  103. tools/testing/selftests/bpf/prog_tests/tailcalls.c +18 −18
  104. tools/testing/selftests/bpf/prog_tests/task_fd_query_rawtp.c +1 −1
  105. tools/testing/selftests/bpf/prog_tests/task_fd_query_tp.c +1 −1
  106. tools/testing/selftests/bpf/prog_tests/tcp_estats.c +1 −1
  107. tools/testing/selftests/bpf/prog_tests/test_bprm_opts.c +1 −9
  108. tools/testing/selftests/bpf/prog_tests/test_global_funcs.c +17 −17
  109. tools/testing/selftests/bpf/prog_tests/test_local_storage.c +1 −9
  110. tools/testing/selftests/bpf/prog_tests/test_overhead.c +1 −1
  111. tools/testing/selftests/bpf/prog_tests/tp_attach_query.c +1 −1
  112. tools/testing/selftests/bpf/prog_tests/trampoline_count.c +1 −1
  113. tools/testing/selftests/bpf/prog_tests/xdp.c +1 −1
  114. tools/testing/selftests/bpf/prog_tests/xdp_adjust_frags.c +1 −1
  115. tools/testing/selftests/bpf/prog_tests/xdp_adjust_tail.c +5 −5
  116. tools/testing/selftests/bpf/prog_tests/xdp_attach.c +1 −1
  117. tools/testing/selftests/bpf/prog_tests/xdp_info.c +1 −1
  118. tools/testing/selftests/bpf/prog_tests/xdp_perf.c +1 −1
  119. tools/testing/selftests/bpf/prog_tests/xdp_synproxy.c +1 −1
  120. tools/testing/selftests/bpf/progs/bind4_prog.c +0 −2
  121. tools/testing/selftests/bpf/progs/bind6_prog.c +0 −2
  122. tools/testing/selftests/bpf/progs/bpf_flow.c +15 −0
  123. tools/testing/selftests/bpf/progs/bpf_iter.h +7 −0
  124. tools/testing/selftests/bpf/progs/bpf_tracing_net.h +31 −1
  125. tools/testing/selftests/bpf/progs/cb_refs.c +116 −0
  126. tools/testing/selftests/bpf/progs/cgroup_getset_retval_hooks.c +16 −0
  127. tools/testing/selftests/bpf/progs/cgroup_hierarchical_stats.c +226 −0
  128. tools/testing/selftests/bpf/progs/cgroup_iter.c +39 −0
  129. tools/testing/selftests/bpf/progs/connect4_prog.c +3 −2
  130. tools/testing/selftests/bpf/progs/fexit_bpf2bpf.c +4 −4
  131. tools/testing/selftests/bpf/progs/htab_update.c +29 −0
  132. tools/testing/selftests/bpf/progs/read_bpf_task_storage_busy.c +39 −0
  133. tools/testing/selftests/bpf/progs/setget_sockopt.c +395 −0
  134. tools/testing/selftests/bpf/progs/tailcall_bpf2bpf4.c +1 −1
  135. tools/testing/selftests/bpf/progs/test_tc_dtime.c +0 −1
  136. tools/testing/selftests/bpf/progs/test_tunnel_kern.c +16 −8
  137. tools/testing/selftests/bpf/progs/timer.c +0 −11
  138. tools/testing/selftests/bpf/task_local_storage_helpers.h +18 −0
  139. tools/testing/selftests/bpf/test_dev_cgroup.c +1 −1
  140. tools/testing/selftests/bpf/test_flow_dissector.sh +8 −0
  141. tools/testing/selftests/bpf/test_lirc_mode2_user.c +1 −1
  142. tools/testing/selftests/bpf/test_maps.c +29 −19
  143. tools/testing/selftests/bpf/test_offload.py +11 −11
  144. tools/testing/selftests/bpf/test_skb_cgroup_id.sh +1 −1
  145. tools/testing/selftests/bpf/test_sock_addr.c +8 −8
  146. tools/testing/selftests/bpf/test_sockmap.c +2 −2
  147. tools/testing/selftests/bpf/test_sysctl.c +3 −3
  148. tools/testing/selftests/bpf/test_tcp_check_syncookie.sh +1 −1
  149. tools/testing/selftests/bpf/test_tcpnotify_user.c +1 −1
  150. tools/testing/selftests/bpf/test_xdp_redirect.sh +4 −4
  151. tools/testing/selftests/bpf/test_xdp_redirect_multi.sh +1 −1
  152. tools/testing/selftests/bpf/test_xdp_veth.sh +4 −4
  153. tools/testing/selftests/bpf/test_xsk.sh +36 −16
  154. tools/testing/selftests/bpf/xdp_redirect_multi.c +1 −1
  155. tools/testing/selftests/bpf/xdp_synproxy.c +1 −1
  156. tools/testing/selftests/bpf/xdping.c +1 −1
  157. tools/testing/selftests/bpf/xsk.c +3 −3
  158. tools/testing/selftests/bpf/xskxceiver.c +296 −102
  159. tools/testing/selftests/bpf/xskxceiver.h +8 −3
arch/mips/net/bpf_jit_comp32.c+9−1
@@ -1376,12 +1376,20 @@ void build_prologue(struct jit_context *ctx) · 1375 unmodified lines
1376 const u8 *fp = bpf2mips32[BPF_REG_FP];1376 const u8 *fp = bpf2mips32[BPF_REG_FP];
1377 int stack, saved, locals, reserved;1377 int stack, saved, locals, reserved;
1378 1378
1379 /*
1380 * In the unlikely event that the TCC limit is raised to more
1381 * than 16 bits, it is clamped to the maximum value allowed for
1382 * the generated code (0xffff). It is better fail to compile
1383 * instead of degrading gracefully.
1384 */
1385 BUILD_BUG_ON(MAX_TAIL_CALL_CNT > 0xffff);
1386
1379 /*1387 /*
1380 * The first two instructions initialize TCC in the reserved (for us)1388 * The first two instructions initialize TCC in the reserved (for us)
1381 * 16-byte area in the parent's stack frame. On a tail call, the1389 * 16-byte area in the parent's stack frame. On a tail call, the
1382 * calling function jumps into the prologue after these instructions.1390 * calling function jumps into the prologue after these instructions.
1383 */1391 */
1384 emit(ctx, ori, MIPS_R_T9, MIPS_R_ZERO, min(MAX_TAIL_CALL_CNT, 0xffff));1392 emit(ctx, ori, MIPS_R_T9, MIPS_R_ZERO, MAX_TAIL_CALL_CNT);
1385 emit(ctx, sw, MIPS_R_T9, 0, MIPS_R_SP);1393 emit(ctx, sw, MIPS_R_T9, 0, MIPS_R_SP);
1386 1394
1387 /*1395 /*
arch/mips/net/bpf_jit_comp64.c+9−1
@@ -547,12 +547,20 @@ void build_prologue(struct jit_context *ctx) · 546 unmodified lines
547 u8 zx = bpf2mips64[JIT_REG_ZX];547 u8 zx = bpf2mips64[JIT_REG_ZX];
548 int stack, saved, locals, reserved;548 int stack, saved, locals, reserved;
549 549
550 /*
551 * In the unlikely event that the TCC limit is raised to more
552 * than 16 bits, it is clamped to the maximum value allowed for
553 * the generated code (0xffff). It is better fail to compile
554 * instead of degrading gracefully.
555 */
556 BUILD_BUG_ON(MAX_TAIL_CALL_CNT > 0xffff);
557
550 /*558 /*
551 * The first instruction initializes the tail call count register.559 * The first instruction initializes the tail call count register.
552 * On a tail call, the calling function jumps into the prologue560 * On a tail call, the calling function jumps into the prologue
553 * after this instruction.561 * after this instruction.
554 */562 */
555 emit(ctx, ori, tc, MIPS_R_ZERO, min(MAX_TAIL_CALL_CNT, 0xffff));563 emit(ctx, ori, tc, MIPS_R_ZERO, MAX_TAIL_CALL_CNT);
556 564
557 /* === Entry-point for tail calls === */565 /* === Entry-point for tail calls === */
558 566
include/linux/bpf-cgroup.h+17−0
@@ -414,6 +414,11 @@ int cgroup_bpf_prog_detach(const union bpf_attr *attr, · 413 unmodified lines
414int cgroup_bpf_link_attach(const union bpf_attr *attr, struct bpf_prog *prog);414int cgroup_bpf_link_attach(const union bpf_attr *attr, struct bpf_prog *prog);
415int cgroup_bpf_prog_query(const union bpf_attr *attr,415int cgroup_bpf_prog_query(const union bpf_attr *attr,
416 union bpf_attr __user *uattr);416 union bpf_attr __user *uattr);
417
418const struct bpf_func_proto *
419cgroup_common_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog);
420const struct bpf_func_proto *
421cgroup_current_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog);
417#else422#else
418 423
419static inline int cgroup_bpf_inherit(struct cgroup *cgrp) { return 0; }424static inline int cgroup_bpf_inherit(struct cgroup *cgrp) { return 0; }
@@ -444,6 +449,18 @@ static inline int cgroup_bpf_prog_query(const union bpf_attr *attr, · 24 unmodified lines
444 return -EINVAL;449 return -EINVAL;
445}450}
446 451
452static inline const struct bpf_func_proto *
453cgroup_common_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
454{
455 return NULL;
456}
457
458static inline const struct bpf_func_proto *
459cgroup_current_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
460{
461 return NULL;
462}
463
447static inline int bpf_cgroup_storage_assign(struct bpf_prog_aux *aux,464static inline int bpf_cgroup_storage_assign(struct bpf_prog_aux *aux,
448 struct bpf_map *map) { return 0; }465 struct bpf_map *map) { return 0; }
449static inline struct bpf_cgroup_storage *bpf_cgroup_storage_alloc(466static inline struct bpf_cgroup_storage *bpf_cgroup_storage_alloc(
include/linux/bpf.h+22−0
@@ -48,6 +48,7 @@ struct mem_cgroup; · 47 unmodified lines
48struct module;48struct module;
49struct bpf_func_state;49struct bpf_func_state;
50struct ftrace_ops;50struct ftrace_ops;
51struct cgroup;
51 52
52extern struct idr btf_idr;53extern struct idr btf_idr;
53extern spinlock_t btf_idr_lock;54extern spinlock_t btf_idr_lock;
@@ -1730,7 +1731,14 @@ int bpf_obj_get_user(const char __user *pathname, int flags); · 1676 unmodified lines
1730 int __init bpf_iter_ ## target(args) { return 0; }1731 int __init bpf_iter_ ## target(args) { return 0; }
1731 1732
1732struct bpf_iter_aux_info {1733struct bpf_iter_aux_info {
1734 /* for map_elem iter */
1733 struct bpf_map *map;1735 struct bpf_map *map;
1736
1737 /* for cgroup iter */
1738 struct {
1739 struct cgroup *start; /* starting cgroup */
1740 enum bpf_cgroup_iter_order order;
1741 } cgroup;
1734};1742};
1735 1743
1736typedef int (*bpf_iter_attach_target_t)(struct bpf_prog *prog,1744typedef int (*bpf_iter_attach_target_t)(struct bpf_prog *prog,
@@ -1966,6 +1974,15 @@ static inline bool unprivileged_ebpf_enabled(void) · 229 unmodified lines
1966 return !sysctl_unprivileged_bpf_disabled;1974 return !sysctl_unprivileged_bpf_disabled;
1967}1975}
1968 1976
1977/* Not all bpf prog type has the bpf_ctx.
1978 * For the bpf prog type that has initialized the bpf_ctx,
1979 * this function can be used to decide if a kernel function
1980 * is called by a bpf program.
1981 */
1982static inline bool has_current_bpf_ctx(void)
1983{
1984 return !!current->bpf_ctx;
1985}
1969#else /* !CONFIG_BPF_SYSCALL */1986#else /* !CONFIG_BPF_SYSCALL */
1970static inline struct bpf_prog *bpf_prog_get(u32 ufd)1987static inline struct bpf_prog *bpf_prog_get(u32 ufd)
1971{1988{
@@ -2175,6 +2192,10 @@ static inline bool unprivileged_ebpf_enabled(void) · 203 unmodified lines
2175 return false;2192 return false;
2176}2193}
2177 2194
2195static inline bool has_current_bpf_ctx(void)
2196{
2197 return false;
2198}
2178#endif /* CONFIG_BPF_SYSCALL */2199#endif /* CONFIG_BPF_SYSCALL */
2179 2200
2180void __bpf_free_used_btfs(struct bpf_prog_aux *aux,2201void __bpf_free_used_btfs(struct bpf_prog_aux *aux,
@@ -2362,6 +2383,7 @@ extern const struct bpf_func_proto bpf_sock_map_update_proto; · 181 unmodified lines
2362extern const struct bpf_func_proto bpf_sock_hash_update_proto;2383extern const struct bpf_func_proto bpf_sock_hash_update_proto;
2363extern const struct bpf_func_proto bpf_get_current_cgroup_id_proto;2384extern const struct bpf_func_proto bpf_get_current_cgroup_id_proto;
2364extern const struct bpf_func_proto bpf_get_current_ancestor_cgroup_id_proto;2385extern const struct bpf_func_proto bpf_get_current_ancestor_cgroup_id_proto;
2386extern const struct bpf_func_proto bpf_get_cgroup_classid_curr_proto;
2365extern const struct bpf_func_proto bpf_msg_redirect_hash_proto;2387extern const struct bpf_func_proto bpf_msg_redirect_hash_proto;
2366extern const struct bpf_func_proto bpf_msg_redirect_map_proto;2388extern const struct bpf_func_proto bpf_msg_redirect_map_proto;
2367extern const struct bpf_func_proto bpf_sk_redirect_hash_proto;2389extern const struct bpf_func_proto bpf_sk_redirect_hash_proto;
include/linux/bpf_mem_alloc.h+28−0
@@ -0,0 +1,28 @@
1/* SPDX-License-Identifier: GPL-2.0-only */
2/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
3#ifndef _BPF_MEM_ALLOC_H
4#define _BPF_MEM_ALLOC_H
5#include <linux/compiler_types.h>
6#include <linux/workqueue.h>
7
8struct bpf_mem_cache;
9struct bpf_mem_caches;
10
11struct bpf_mem_alloc {
12 struct bpf_mem_caches __percpu *caches;
13 struct bpf_mem_cache __percpu *cache;
14 struct work_struct work;
15};
16
17int bpf_mem_alloc_init(struct bpf_mem_alloc *ma, int size, bool percpu);
18void bpf_mem_alloc_destroy(struct bpf_mem_alloc *ma);
19
20/* kmalloc/kfree equivalent: */
21void *bpf_mem_alloc(struct bpf_mem_alloc *ma, size_t size);
22void bpf_mem_free(struct bpf_mem_alloc *ma, void *ptr);
23
24/* kmem_cache_alloc/free equivalent: */
25void *bpf_mem_cache_alloc(struct bpf_mem_alloc *ma);
26void bpf_mem_cache_free(struct bpf_mem_alloc *ma, void *ptr);
27
28#endif /* _BPF_MEM_ALLOC_H */
include/linux/bpf_verifier.h+11−0
@@ -212,6 +212,17 @@ struct bpf_reference_state { · 211 unmodified lines
212 * is used purely to inform the user of a reference leak.212 * is used purely to inform the user of a reference leak.
213 */213 */
214 int insn_idx;214 int insn_idx;
215 /* There can be a case like:
216 * main (frame 0)
217 * cb (frame 1)
218 * func (frame 3)
219 * cb (frame 4)
220 * Hence for frame 4, if callback_ref just stored boolean, it would be
221 * impossible to distinguish nested callback refs. Hence store the
222 * frameno and compare that to callback_ref in check_reference_leak when
223 * exiting a callback function.
224 */
225 int callback_ref;
215};226};
216 227
217/* state of the program:228/* state of the program:
include/linux/filter.h+1−2
@@ -900,8 +900,7 @@ int sk_reuseport_attach_filter(struct sock_fprog *fprog, struct sock *sk); · 899 unmodified lines
900int sk_reuseport_attach_bpf(u32 ufd, struct sock *sk);900int sk_reuseport_attach_bpf(u32 ufd, struct sock *sk);
901void sk_reuseport_prog_free(struct bpf_prog *prog);901void sk_reuseport_prog_free(struct bpf_prog *prog);
902int sk_detach_filter(struct sock *sk);902int sk_detach_filter(struct sock *sk);
903int sk_get_filter(struct sock *sk, struct sock_filter __user *filter,903int sk_get_filter(struct sock *sk, sockptr_t optval, unsigned int len);
904 unsigned int len);
905 904
906bool sk_filter_charge(struct sock *sk, struct sk_filter *fp);905bool sk_filter_charge(struct sock *sk, struct sk_filter *fp);
907void sk_filter_uncharge(struct sock *sk, struct sk_filter *fp);906void sk_filter_uncharge(struct sock *sk, struct sk_filter *fp);
include/linux/igmp.h+2−2
@@ -118,9 +118,9 @@ extern int ip_mc_source(int add, int omode, struct sock *sk, · 117 unmodified lines
118 struct ip_mreq_source *mreqs, int ifindex);118 struct ip_mreq_source *mreqs, int ifindex);
119extern int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf,int ifindex);119extern int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf,int ifindex);
120extern int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,120extern int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,
121 struct ip_msfilter __user *optval, int __user *optlen);121 sockptr_t optval, sockptr_t optlen);
122extern int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,122extern int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
123 struct sockaddr_storage __user *p);123 sockptr_t optval, size_t offset);
124extern int ip_mc_sf_allow(struct sock *sk, __be32 local, __be32 rmt,124extern int ip_mc_sf_allow(struct sock *sk, __be32 local, __be32 rmt,
125 int dif, int sdif);125 int dif, int sdif);
126extern void ip_mc_init_dev(struct in_device *);126extern void ip_mc_init_dev(struct in_device *);
include/linux/mroute.h+3−3
@@ -17,7 +17,7 @@ static inline int ip_mroute_opt(int opt) · 16 unmodified lines
17}17}
18 18
19int ip_mroute_setsockopt(struct sock *, int, sockptr_t, unsigned int);19int ip_mroute_setsockopt(struct sock *, int, sockptr_t, unsigned int);
20int ip_mroute_getsockopt(struct sock *, int, char __user *, int __user *);20int ip_mroute_getsockopt(struct sock *, int, sockptr_t, sockptr_t);
21int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg);21int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg);
22int ipmr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg);22int ipmr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg);
23int ip_mr_init(void);23int ip_mr_init(void);
@@ -29,8 +29,8 @@ static inline int ip_mroute_setsockopt(struct sock *sock, int optname, · 5 unmodified lines
29 return -ENOPROTOOPT;29 return -ENOPROTOOPT;
30}30}
31 31
32static inline int ip_mroute_getsockopt(struct sock *sock, int optname,32static inline int ip_mroute_getsockopt(struct sock *sk, int optname,
33 char __user *optval, int __user *optlen)33 sockptr_t optval, sockptr_t optlen)
34{34{
35 return -ENOPROTOOPT;35 return -ENOPROTOOPT;
36}36}
include/linux/mroute6.h+2−2
@@ -27,7 +27,7 @@ struct sock; · 26 unmodified lines
27 27
28#ifdef CONFIG_IPV6_MROUTE28#ifdef CONFIG_IPV6_MROUTE
29extern int ip6_mroute_setsockopt(struct sock *, int, sockptr_t, unsigned int);29extern int ip6_mroute_setsockopt(struct sock *, int, sockptr_t, unsigned int);
30extern int ip6_mroute_getsockopt(struct sock *, int, char __user *, int __user *);30extern int ip6_mroute_getsockopt(struct sock *, int, sockptr_t, sockptr_t);
31extern int ip6_mr_input(struct sk_buff *skb);31extern int ip6_mr_input(struct sk_buff *skb);
32extern int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg);32extern int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg);
33extern int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg);33extern int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg);
@@ -42,7 +42,7 @@ static inline int ip6_mroute_setsockopt(struct sock *sock, int optname, · 8 unmodified lines
42 42
43static inline43static inline
44int ip6_mroute_getsockopt(struct sock *sock,44int ip6_mroute_getsockopt(struct sock *sock,
45 int optname, char __user *optval, int __user *optlen)45 int optname, sockptr_t optval, sockptr_t optlen)
46{46{
47 return -ENOPROTOOPT;47 return -ENOPROTOOPT;
48}48}
include/linux/skbuff.h+2−2
@@ -1461,8 +1461,8 @@ void skb_flow_dissector_init(struct flow_dissector *flow_dissector, · 1460 unmodified lines
1461 unsigned int key_count);1461 unsigned int key_count);
1462 1462
1463struct bpf_flow_dissector;1463struct bpf_flow_dissector;
1464bool bpf_flow_dissect(struct bpf_prog *prog, struct bpf_flow_dissector *ctx,1464u32 bpf_flow_dissect(struct bpf_prog *prog, struct bpf_flow_dissector *ctx,
1465 __be16 proto, int nhoff, int hlen, unsigned int flags);1465 __be16 proto, int nhoff, int hlen, unsigned int flags);
1466 1466
1467bool __skb_flow_dissect(const struct net *net,1467bool __skb_flow_dissect(const struct net *net,
1468 const struct sk_buff *skb,1468 const struct sk_buff *skb,
include/linux/sockptr.h+5−0
@@ -64,6 +64,11 @@ static inline int copy_to_sockptr_offset(sockptr_t dst, size_t offset, · 63 unmodified lines
64 return 0;64 return 0;
65}65}
66 66
67static inline int copy_to_sockptr(sockptr_t dst, const void *src, size_t size)
68{
69 return copy_to_sockptr_offset(dst, 0, src, size);
70}
71
67static inline void *memdup_sockptr(sockptr_t src, size_t len)72static inline void *memdup_sockptr(sockptr_t src, size_t len)
68{73{
69 void *p = kmalloc_track_caller(len, GFP_USER | __GFP_NOWARN);74 void *p = kmalloc_track_caller(len, GFP_USER | __GFP_NOWARN);
include/linux/tnum.h+18−2
@@ -21,7 +21,12 @@ struct tnum { · 20 unmodified lines
21struct tnum tnum_const(u64 value);21struct tnum tnum_const(u64 value);
22/* A completely unknown value */22/* A completely unknown value */
23extern const struct tnum tnum_unknown;23extern const struct tnum tnum_unknown;
24/* A value that's unknown except that @min <= value <= @max */24/* An unknown value that is a superset of @min <= value <= @max.
25 *
26 * Could include values outside the range of [@min, @max].
27 * For example tnum_range(0, 2) is represented by {0, 1, 2, *3*},
28 * rather than the intended set of {0, 1, 2}.
29 */
25struct tnum tnum_range(u64 min, u64 max);30struct tnum tnum_range(u64 min, u64 max);
26 31
27/* Arithmetic and logical ops */32/* Arithmetic and logical ops */
@@ -73,7 +78,18 @@ static inline bool tnum_is_unknown(struct tnum a) · 45 unmodified lines
73 */78 */
74bool tnum_is_aligned(struct tnum a, u64 size);79bool tnum_is_aligned(struct tnum a, u64 size);
75 80
76/* Returns true if @b represents a subset of @a. */81/* Returns true if @b represents a subset of @a.
82 *
83 * Note that using tnum_range() as @a requires extra cautions as tnum_in() may
84 * return true unexpectedly due to tnum limited ability to represent tight
85 * range, e.g.
86 *
87 * tnum_in(tnum_range(0, 2), tnum_const(3)) == true
88 *
89 * As a rule of thumb, if @a is explicitly coded rather than coming from
90 * reg->var_off, it should be in form of tnum_const(), tnum_range(0, 2**n - 1),
91 * or tnum_range(2**n, 2**(n+1) - 1).
92 */
77bool tnum_in(struct tnum a, struct tnum b);93bool tnum_in(struct tnum a, struct tnum b);
78 94
79/* Formatting functions. These have snprintf-like semantics: they will write95/* Formatting functions. These have snprintf-like semantics: they will write
include/net/ip.h+4−0
@@ -743,8 +743,12 @@ void ip_cmsg_recv_offset(struct msghdr *msg, struct sock *sk, · 742 unmodified lines
743int ip_cmsg_send(struct sock *sk, struct msghdr *msg,743int ip_cmsg_send(struct sock *sk, struct msghdr *msg,
744 struct ipcm_cookie *ipc, bool allow_ipv6);744 struct ipcm_cookie *ipc, bool allow_ipv6);
745DECLARE_STATIC_KEY_FALSE(ip4_min_ttl);745DECLARE_STATIC_KEY_FALSE(ip4_min_ttl);
746int do_ip_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
747 unsigned int optlen);
746int ip_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,748int ip_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
747 unsigned int optlen);749 unsigned int optlen);
750int do_ip_getsockopt(struct sock *sk, int level, int optname,
751 sockptr_t optval, sockptr_t optlen);
748int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval,752int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
749 int __user *optlen);753 int __user *optlen);
750int ip_ra_control(struct sock *sk, unsigned char on,754int ip_ra_control(struct sock *sk, unsigned char on,
include/net/ipv6.h+5−1
@@ -1156,8 +1156,12 @@ struct in6_addr *fl6_update_dst(struct flowi6 *fl6, · 1155 unmodified lines
1156 */1156 */
1157DECLARE_STATIC_KEY_FALSE(ip6_min_hopcount);1157DECLARE_STATIC_KEY_FALSE(ip6_min_hopcount);
1158 1158
1159int do_ipv6_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
1160 unsigned int optlen);
1159int ipv6_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,1161int ipv6_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
1160 unsigned int optlen);1162 unsigned int optlen);
1163int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
1164 sockptr_t optval, sockptr_t optlen);
1161int ipv6_getsockopt(struct sock *sk, int level, int optname,1165int ipv6_getsockopt(struct sock *sk, int level, int optname,
1162 char __user *optval, int __user *optlen);1166 char __user *optval, int __user *optlen);
1163 1167
@@ -1207,7 +1211,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk, · 43 unmodified lines
1207int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf,1211int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf,
1208 struct sockaddr_storage *list);1212 struct sockaddr_storage *list);
1209int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,1213int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
1210 struct sockaddr_storage __user *p);1214 sockptr_t optval, size_t ss_offset);
1211 1215
1212#ifdef CONFIG_PROC_FS1216#ifdef CONFIG_PROC_FS
1213int ac6_proc_init(struct net *net);1217int ac6_proc_init(struct net *net);
include/net/ipv6_stubs.h+4−0
@@ -81,6 +81,10 @@ struct ipv6_bpf_stub { · 80 unmodified lines
81 const struct in6_addr *daddr, __be16 dport,81 const struct in6_addr *daddr, __be16 dport,
82 int dif, int sdif, struct udp_table *tbl,82 int dif, int sdif, struct udp_table *tbl,
83 struct sk_buff *skb);83 struct sk_buff *skb);
84 int (*ipv6_setsockopt)(struct sock *sk, int level, int optname,
85 sockptr_t optval, unsigned int optlen);
86 int (*ipv6_getsockopt)(struct sock *sk, int level, int optname,
87 sockptr_t optval, sockptr_t optlen);
84};88};
85extern const struct ipv6_bpf_stub *ipv6_bpf_stub __read_mostly;89extern const struct ipv6_bpf_stub *ipv6_bpf_stub __read_mostly;
86 90
include/net/sock.h+9−0
@@ -1788,6 +1788,11 @@ static inline void unlock_sock_fast(struct sock *sk, bool slow) · 1787 unmodified lines
1788 }1788 }
1789}1789}
1790 1790
1791void sockopt_lock_sock(struct sock *sk);
1792void sockopt_release_sock(struct sock *sk);
1793bool sockopt_ns_capable(struct user_namespace *ns, int cap);
1794bool sockopt_capable(int cap);
1795
1791/* Used by processes to "lock" a socket state, so that1796/* Used by processes to "lock" a socket state, so that
1792 * interrupts and bottom half handlers won't change it1797 * interrupts and bottom half handlers won't change it
1793 * from under us. It essentially blocks any incoming1798 * from under us. It essentially blocks any incoming
@@ -1862,9 +1867,13 @@ void sock_pfree(struct sk_buff *skb); · 68 unmodified lines
1862#define sock_edemux sock_efree1867#define sock_edemux sock_efree
1863#endif1868#endif
1864 1869
1870int sk_setsockopt(struct sock *sk, int level, int optname,
1871 sockptr_t optval, unsigned int optlen);
1865int sock_setsockopt(struct socket *sock, int level, int op,1872int sock_setsockopt(struct socket *sock, int level, int op,
1866 sockptr_t optval, unsigned int optlen);1873 sockptr_t optval, unsigned int optlen);
1867 1874
1875int sk_getsockopt(struct sock *sk, int level, int optname,
1876 sockptr_t optval, sockptr_t optlen);
1868int sock_getsockopt(struct socket *sock, int level, int op,1877int sock_getsockopt(struct socket *sock, int level, int op,
1869 char __user *optval, int __user *optlen);1878 char __user *optval, int __user *optlen);
1870int sock_gettstamp(struct socket *sock, void __user *userstamp,1879int sock_gettstamp(struct socket *sock, void __user *userstamp,
include/net/tcp.h+4−0
@@ -402,9 +402,13 @@ void tcp_init_sock(struct sock *sk); · 401 unmodified lines
402void tcp_init_transfer(struct sock *sk, int bpf_op, struct sk_buff *skb);402void tcp_init_transfer(struct sock *sk, int bpf_op, struct sk_buff *skb);
403__poll_t tcp_poll(struct file *file, struct socket *sock,403__poll_t tcp_poll(struct file *file, struct socket *sock,
404 struct poll_table_struct *wait);404 struct poll_table_struct *wait);
405int do_tcp_getsockopt(struct sock *sk, int level,
406 int optname, sockptr_t optval, sockptr_t optlen);
405int tcp_getsockopt(struct sock *sk, int level, int optname,407int tcp_getsockopt(struct sock *sk, int level, int optname,
406 char __user *optval, int __user *optlen);408 char __user *optval, int __user *optlen);
407bool tcp_bpf_bypass_getsockopt(int level, int optname);409bool tcp_bpf_bypass_getsockopt(int level, int optname);
410int do_tcp_setsockopt(struct sock *sk, int level, int optname,
411 sockptr_t optval, unsigned int optlen);
408int tcp_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,412int tcp_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
409 unsigned int optlen);413 unsigned int optlen);
410void tcp_set_keepalive(struct sock *sk, int val);414void tcp_set_keepalive(struct sock *sk, int val);
include/uapi/linux/bpf.h+69−14
@@ -87,10 +87,29 @@ struct bpf_cgroup_storage_key { · 86 unmodified lines
87 __u32 attach_type; /* program attach type (enum bpf_attach_type) */87 __u32 attach_type; /* program attach type (enum bpf_attach_type) */
88};88};
89 89
90enum bpf_cgroup_iter_order {
91 BPF_CGROUP_ITER_ORDER_UNSPEC = 0,
92 BPF_CGROUP_ITER_SELF_ONLY, /* process only a single object. */
93 BPF_CGROUP_ITER_DESCENDANTS_PRE, /* walk descendants in pre-order. */
94 BPF_CGROUP_ITER_DESCENDANTS_POST, /* walk descendants in post-order. */
95 BPF_CGROUP_ITER_ANCESTORS_UP, /* walk ancestors upward. */
96};
97
90union bpf_iter_link_info {98union bpf_iter_link_info {
91 struct {99 struct {
92 __u32 map_fd;100 __u32 map_fd;
93 } map;101 } map;
102 struct {
103 enum bpf_cgroup_iter_order order;
104
105 /* At most one of cgroup_fd and cgroup_id can be non-zero. If
106 * both are zero, the walk starts from the default cgroup v2
107 * root. For walking v1 hierarchy, one should always explicitly
108 * specify cgroup_fd.
109 */
110 __u32 cgroup_fd;
111 __u64 cgroup_id;
112 } cgroup;
94};113};
95 114
96/* BPF syscall commands, see bpf(2) man-page for more details. */115/* BPF syscall commands, see bpf(2) man-page for more details. */
@@ -4437,7 +4456,7 @@ union bpf_attr { · 4340 unmodified lines
4437 *4456 *
4438 * **-EEXIST** if the option already exists.4457 * **-EEXIST** if the option already exists.
4439 *4458 *
4440 * **-EFAULT** on failrue to parse the existing header options.4459 * **-EFAULT** on failure to parse the existing header options.
4441 *4460 *
4442 * **-EPERM** if the helper cannot be used under the current4461 * **-EPERM** if the helper cannot be used under the current
4443 * *skops*\ **->op**.4462 * *skops*\ **->op**.
@@ -4646,7 +4665,7 @@ union bpf_attr { · 202 unmodified lines
4646 * a *map* with *task* as the **key**. From this4665 * a *map* with *task* as the **key**. From this
4647 * perspective, the usage is not much different from4666 * perspective, the usage is not much different from
4648 * **bpf_map_lookup_elem**\ (*map*, **&**\ *task*) except this4667 * **bpf_map_lookup_elem**\ (*map*, **&**\ *task*) except this
4649 * helper enforces the key must be an task_struct and the map must also4668 * helper enforces the key must be a task_struct and the map must also
4650 * be a **BPF_MAP_TYPE_TASK_STORAGE**.4669 * be a **BPF_MAP_TYPE_TASK_STORAGE**.
4651 *4670 *
4652 * Underneath, the value is stored locally at *task* instead of4671 * Underneath, the value is stored locally at *task* instead of
@@ -4704,7 +4723,7 @@ union bpf_attr { · 51 unmodified lines
4704 *4723 *
4705 * long bpf_ima_inode_hash(struct inode *inode, void *dst, u32 size)4724 * long bpf_ima_inode_hash(struct inode *inode, void *dst, u32 size)
4706 * Description4725 * Description
4707 * Returns the stored IMA hash of the *inode* (if it's avaialable).4726 * Returns the stored IMA hash of the *inode* (if it's available).
4708 * If the hash is larger than *size*, then only *size*4727 * If the hash is larger than *size*, then only *size*
4709 * bytes will be copied to *dst*4728 * bytes will be copied to *dst*
4710 * Return4729 * Return
@@ -4728,12 +4747,12 @@ union bpf_attr { · 17 unmodified lines
4728 *4747 *
4729 * The argument *len_diff* can be used for querying with a planned4748 * The argument *len_diff* can be used for querying with a planned
4730 * size change. This allows to check MTU prior to changing packet4749 * size change. This allows to check MTU prior to changing packet
4731 * ctx. Providing an *len_diff* adjustment that is larger than the4750 * ctx. Providing a *len_diff* adjustment that is larger than the
4732 * actual packet size (resulting in negative packet size) will in4751 * actual packet size (resulting in negative packet size) will in
4733 * principle not exceed the MTU, why it is not considered a4752 * principle not exceed the MTU, which is why it is not considered
4734 * failure. Other BPF-helpers are needed for performing the4753 * a failure. Other BPF helpers are needed for performing the
4735 * planned size change, why the responsability for catch a negative4754 * planned size change; therefore the responsibility for catching
4736 * packet size belong in those helpers.4755 * a negative packet size belongs in those helpers.
4737 *4756 *
4738 * Specifying *ifindex* zero means the MTU check is performed4757 * Specifying *ifindex* zero means the MTU check is performed
4739 * against the current net device. This is practical if this isn't4758 * against the current net device. This is practical if this isn't
@@ -5085,17 +5104,29 @@ union bpf_attr { · 345 unmodified lines
5085 *5104 *
5086 * int bpf_get_retval(void)5105 * int bpf_get_retval(void)
5087 * Description5106 * Description
5088 * Get the syscall's return value that will be returned to userspace.5107 * Get the BPF program's return value that will be returned to the upper layers.
5089 *5108 *
5090 * This helper is currently supported by cgroup programs only.5109 * This helper is currently supported by cgroup programs and only by the hooks
5110 * where BPF program's return value is returned to the userspace via errno.
5091 * Return5111 * Return
5092 * The syscall's return value.5112 * The BPF program's return value.
5093 *5113 *
5094 * int bpf_set_retval(int retval)5114 * int bpf_set_retval(int retval)
5095 * Description5115 * Description
5096 * Set the syscall's return value that will be returned to userspace.5116 * Set the BPF program's return value that will be returned to the upper layers.
5117 *
5118 * This helper is currently supported by cgroup programs and only by the hooks
5119 * where BPF program's return value is returned to the userspace via errno.
5120 *
5121 * Note that there is the following corner case where the program exports an error
5122 * via bpf_set_retval but signals success via 'return 1':
5123 *
5124 * bpf_set_retval(-EPERM);
5125 * return 1;
5126 *
5127 * In this case, the BPF program's return value will use helper's -EPERM. This
5128 * still holds true for cgroup/bind{4,6} which supports extra 'return 3' success case.
5097 *5129 *
5098 * This helper is currently supported by cgroup programs only.
5099 * Return5130 * Return
5100 * 0 on success, or a negative error in case of failure.5131 * 0 on success, or a negative error in case of failure.
5101 *5132 *
@@ -5628,6 +5659,11 @@ enum { · 526 unmodified lines
5628 BPF_F_SEQ_NUMBER = (1ULL << 3),5659 BPF_F_SEQ_NUMBER = (1ULL << 3),
5629};5660};
5630 5661
5662/* BPF_FUNC_skb_get_tunnel_key flags. */
5663enum {
5664 BPF_F_TUNINFO_FLAGS = (1ULL << 4),
5665};
5666
5631/* BPF_FUNC_perf_event_output, BPF_FUNC_perf_event_read and5667/* BPF_FUNC_perf_event_output, BPF_FUNC_perf_event_read and
5632 * BPF_FUNC_perf_event_read_value flags.5668 * BPF_FUNC_perf_event_read_value flags.
5633 */5669 */
@@ -5817,7 +5853,10 @@ struct bpf_tunnel_key { · 183 unmodified lines
5817 };5853 };
5818 __u8 tunnel_tos;5854 __u8 tunnel_tos;
5819 __u8 tunnel_ttl;5855 __u8 tunnel_ttl;
5820 __u16 tunnel_ext; /* Padding, future use. */5856 union {
5857 __u16 tunnel_ext; /* compat */
5858 __be16 tunnel_flags;
5859 };
5821 __u32 tunnel_label;5860 __u32 tunnel_label;
5822 union {5861 union {
5823 __u32 local_ipv4;5862 __u32 local_ipv4;
@@ -5861,6 +5900,11 @@ enum bpf_ret_code { · 37 unmodified lines
5861 * represented by BPF_REDIRECT above).5900 * represented by BPF_REDIRECT above).
5862 */5901 */
5863 BPF_LWT_REROUTE = 128,5902 BPF_LWT_REROUTE = 128,
5903 /* BPF_FLOW_DISSECTOR_CONTINUE: used by BPF_PROG_TYPE_FLOW_DISSECTOR
5904 * to indicate that no custom dissection was performed, and
5905 * fallback to standard dissector is requested.
5906 */
5907 BPF_FLOW_DISSECTOR_CONTINUE = 129,
5864};5908};
5865 5909
5866struct bpf_sock {5910struct bpf_sock {
@@ -6159,11 +6203,22 @@ struct bpf_link_info { · 292 unmodified lines
6159 struct {6203 struct {
6160 __aligned_u64 target_name; /* in/out: target_name buffer ptr */6204 __aligned_u64 target_name; /* in/out: target_name buffer ptr */
6161 __u32 target_name_len; /* in/out: target_name buffer len */6205 __u32 target_name_len; /* in/out: target_name buffer len */
6206
6207 /* If the iter specific field is 32 bits, it can be put
6208 * in the first or second union. Otherwise it should be
6209 * put in the second union.
6210 */
6162 union {6211 union {
6163 struct {6212 struct {
6164 __u32 map_id;6213 __u32 map_id;
6165 } map;6214 } map;
6166 };6215 };
6216 union {
6217 struct {
6218 __u64 cgroup_id;
6219 __u32 order;
6220 } cgroup;
6221 };
6167 } iter;6222 } iter;
6168 struct {6223 struct {
6169 __u32 netns_ino;6224 __u32 netns_ino;
kernel/bpf/Makefile+4−1
@@ -13,7 +13,7 @@ obj-$(CONFIG_BPF_SYSCALL) += bpf_local_storage.o bpf_task_storage.o · 12 unmodified lines
13obj-${CONFIG_BPF_LSM} += bpf_inode_storage.o13obj-${CONFIG_BPF_LSM} += bpf_inode_storage.o
14obj-$(CONFIG_BPF_SYSCALL) += disasm.o14obj-$(CONFIG_BPF_SYSCALL) += disasm.o
15obj-$(CONFIG_BPF_JIT) += trampoline.o15obj-$(CONFIG_BPF_JIT) += trampoline.o
16obj-$(CONFIG_BPF_SYSCALL) += btf.o16obj-$(CONFIG_BPF_SYSCALL) += btf.o memalloc.o
17obj-$(CONFIG_BPF_JIT) += dispatcher.o17obj-$(CONFIG_BPF_JIT) += dispatcher.o
18ifeq ($(CONFIG_NET),y)18ifeq ($(CONFIG_NET),y)
19obj-$(CONFIG_BPF_SYSCALL) += devmap.o19obj-$(CONFIG_BPF_SYSCALL) += devmap.o
@@ -24,6 +24,9 @@ endif · 4 unmodified lines
24ifeq ($(CONFIG_PERF_EVENTS),y)24ifeq ($(CONFIG_PERF_EVENTS),y)
25obj-$(CONFIG_BPF_SYSCALL) += stackmap.o25obj-$(CONFIG_BPF_SYSCALL) += stackmap.o
26endif26endif
27ifeq ($(CONFIG_CGROUPS),y)
28obj-$(CONFIG_BPF_SYSCALL) += cgroup_iter.o
29endif
27obj-$(CONFIG_CGROUP_BPF) += cgroup.o30obj-$(CONFIG_CGROUP_BPF) += cgroup.o
28ifeq ($(CONFIG_INET),y)31ifeq ($(CONFIG_INET),y)
29obj-$(CONFIG_BPF_SYSCALL) += reuseport_array.o32obj-$(CONFIG_BPF_SYSCALL) += reuseport_array.o
kernel/bpf/bpf_iter.c+5−0
@@ -694,19 +694,24 @@ struct bpf_prog *bpf_iter_get_info(struct bpf_iter_meta *meta, bool in_stop) · 693 unmodified lines
694 694
695int bpf_iter_run_prog(struct bpf_prog *prog, void *ctx)695int bpf_iter_run_prog(struct bpf_prog *prog, void *ctx)
696{696{
697 struct bpf_run_ctx run_ctx, *old_run_ctx;
697 int ret;698 int ret;
698 699
699 if (prog->aux->sleepable) {700 if (prog->aux->sleepable) {
700 rcu_read_lock_trace();701 rcu_read_lock_trace();
701 migrate_disable();702 migrate_disable();
702 might_fault();703 might_fault();
704 old_run_ctx = bpf_set_run_ctx(&run_ctx);
703 ret = bpf_prog_run(prog, ctx);705 ret = bpf_prog_run(prog, ctx);
706 bpf_reset_run_ctx(old_run_ctx);
704 migrate_enable();707 migrate_enable();
705 rcu_read_unlock_trace();708 rcu_read_unlock_trace();
706 } else {709 } else {
707 rcu_read_lock();710 rcu_read_lock();
708 migrate_disable();711 migrate_disable();
712 old_run_ctx = bpf_set_run_ctx(&run_ctx);
709 ret = bpf_prog_run(prog, ctx);713 ret = bpf_prog_run(prog, ctx);
714 bpf_reset_run_ctx(old_run_ctx);
710 migrate_enable();715 migrate_enable();
711 rcu_read_unlock();716 rcu_read_unlock();
712 }717 }
kernel/bpf/bpf_local_storage.c+2−2
@@ -555,11 +555,11 @@ void bpf_local_storage_map_free(struct bpf_local_storage_map *smap, · 554 unmodified lines
555 struct bpf_local_storage_elem, map_node))) {555 struct bpf_local_storage_elem, map_node))) {
556 if (busy_counter) {556 if (busy_counter) {
557 migrate_disable();557 migrate_disable();
558 __this_cpu_inc(*busy_counter);558 this_cpu_inc(*busy_counter);
559 }559 }
560 bpf_selem_unlink(selem, false);560 bpf_selem_unlink(selem, false);
561 if (busy_counter) {561 if (busy_counter) {
562 __this_cpu_dec(*busy_counter);562 this_cpu_dec(*busy_counter);
563 migrate_enable();563 migrate_enable();
564 }564 }
565 cond_resched_rcu();565 cond_resched_rcu();
kernel/bpf/bpf_lsm.c+14−9
@@ -41,17 +41,21 @@ BTF_SET_END(bpf_lsm_hooks) · 40 unmodified lines
41 */41 */
42BTF_SET_START(bpf_lsm_current_hooks)42BTF_SET_START(bpf_lsm_current_hooks)
43/* operate on freshly allocated sk without any cgroup association */43/* operate on freshly allocated sk without any cgroup association */
44#ifdef CONFIG_SECURITY_NETWORK
44BTF_ID(func, bpf_lsm_sk_alloc_security)45BTF_ID(func, bpf_lsm_sk_alloc_security)
45BTF_ID(func, bpf_lsm_sk_free_security)46BTF_ID(func, bpf_lsm_sk_free_security)
47#endif
46BTF_SET_END(bpf_lsm_current_hooks)48BTF_SET_END(bpf_lsm_current_hooks)
47 49
48/* List of LSM hooks that trigger while the socket is properly locked.50/* List of LSM hooks that trigger while the socket is properly locked.
49 */51 */
50BTF_SET_START(bpf_lsm_locked_sockopt_hooks)52BTF_SET_START(bpf_lsm_locked_sockopt_hooks)
53#ifdef CONFIG_SECURITY_NETWORK
51BTF_ID(func, bpf_lsm_socket_sock_rcv_skb)54BTF_ID(func, bpf_lsm_socket_sock_rcv_skb)
52BTF_ID(func, bpf_lsm_sock_graft)55BTF_ID(func, bpf_lsm_sock_graft)
53BTF_ID(func, bpf_lsm_inet_csk_clone)56BTF_ID(func, bpf_lsm_inet_csk_clone)
54BTF_ID(func, bpf_lsm_inet_conn_established)57BTF_ID(func, bpf_lsm_inet_conn_established)
58#endif
55BTF_SET_END(bpf_lsm_locked_sockopt_hooks)59BTF_SET_END(bpf_lsm_locked_sockopt_hooks)
56 60
57/* List of LSM hooks that trigger while the socket is _not_ locked,61/* List of LSM hooks that trigger while the socket is _not_ locked,
@@ -59,8 +63,10 @@ BTF_SET_END(bpf_lsm_locked_sockopt_hooks) · 1 unmodified line
59 * in the early init phase.63 * in the early init phase.
60 */64 */
61BTF_SET_START(bpf_lsm_unlocked_sockopt_hooks)65BTF_SET_START(bpf_lsm_unlocked_sockopt_hooks)
66#ifdef CONFIG_SECURITY_NETWORK
62BTF_ID(func, bpf_lsm_socket_post_create)67BTF_ID(func, bpf_lsm_socket_post_create)
63BTF_ID(func, bpf_lsm_socket_socketpair)68BTF_ID(func, bpf_lsm_socket_socketpair)
69#endif
64BTF_SET_END(bpf_lsm_unlocked_sockopt_hooks)70BTF_SET_END(bpf_lsm_unlocked_sockopt_hooks)
65 71
66#ifdef CONFIG_CGROUP_BPF72#ifdef CONFIG_CGROUP_BPF
@@ -189,6 +195,14 @@ static const struct bpf_func_proto bpf_get_attach_cookie_proto = { · 122 unmodified lines
189static const struct bpf_func_proto *195static const struct bpf_func_proto *
190bpf_lsm_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)196bpf_lsm_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
191{197{
198 const struct bpf_func_proto *func_proto;
199
200 if (prog->expected_attach_type == BPF_LSM_CGROUP) {
201 func_proto = cgroup_common_func_proto(func_id, prog);
202 if (func_proto)
203 return func_proto;
204 }
205
192 switch (func_id) {206 switch (func_id) {
193 case BPF_FUNC_inode_storage_get:207 case BPF_FUNC_inode_storage_get:
194 return &bpf_inode_storage_get_proto;208 return &bpf_inode_storage_get_proto;
@@ -212,15 +226,6 @@ bpf_lsm_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) · 17 unmodified lines
212 return prog->aux->sleepable ? &bpf_ima_file_hash_proto : NULL;226 return prog->aux->sleepable ? &bpf_ima_file_hash_proto : NULL;
213 case BPF_FUNC_get_attach_cookie:227 case BPF_FUNC_get_attach_cookie:
214 return bpf_prog_has_trampoline(prog) ? &bpf_get_attach_cookie_proto : NULL;228 return bpf_prog_has_trampoline(prog) ? &bpf_get_attach_cookie_proto : NULL;
215 case BPF_FUNC_get_local_storage:
216 return prog->expected_attach_type == BPF_LSM_CGROUP ?
217 &bpf_get_local_storage_proto : NULL;
218 case BPF_FUNC_set_retval:
219 return prog->expected_attach_type == BPF_LSM_CGROUP ?
220 &bpf_set_retval_proto : NULL;
221 case BPF_FUNC_get_retval:
222 return prog->expected_attach_type == BPF_LSM_CGROUP ?
223 &bpf_get_retval_proto : NULL;
224#ifdef CONFIG_NET229#ifdef CONFIG_NET
225 case BPF_FUNC_setsockopt:230 case BPF_FUNC_setsockopt:
226 if (prog->expected_attach_type != BPF_LSM_CGROUP)231 if (prog->expected_attach_type != BPF_LSM_CGROUP)
kernel/bpf/bpf_task_storage.c+4−4
@@ -26,20 +26,20 @@ static DEFINE_PER_CPU(int, bpf_task_storage_busy); · 25 unmodified lines
26static void bpf_task_storage_lock(void)26static void bpf_task_storage_lock(void)
27{27{
28 migrate_disable();28 migrate_disable();
29 __this_cpu_inc(bpf_task_storage_busy);29 this_cpu_inc(bpf_task_storage_busy);
30}30}
31 31
32static void bpf_task_storage_unlock(void)32static void bpf_task_storage_unlock(void)
33{33{
34 __this_cpu_dec(bpf_task_storage_busy);34 this_cpu_dec(bpf_task_storage_busy);
35 migrate_enable();35 migrate_enable();
36}36}
37 37
38static bool bpf_task_storage_trylock(void)38static bool bpf_task_storage_trylock(void)
39{39{
40 migrate_disable();40 migrate_disable();
41 if (unlikely(__this_cpu_inc_return(bpf_task_storage_busy) != 1)) {41 if (unlikely(this_cpu_inc_return(bpf_task_storage_busy) != 1)) {
42 __this_cpu_dec(bpf_task_storage_busy);42 this_cpu_dec(bpf_task_storage_busy);
43 migrate_enable();43 migrate_enable();
44 return false;44 return false;
45 }45 }
kernel/bpf/cgroup.c+134−23
@@ -1529,6 +1529,37 @@ int __cgroup_bpf_check_dev_permission(short dev_type, u32 major, u32 minor, · 1528 unmodified lines
1529 return ret;1529 return ret;
1530}1530}
1531 1531
1532BPF_CALL_2(bpf_get_local_storage, struct bpf_map *, map, u64, flags)
1533{
1534 /* flags argument is not used now,
1535 * but provides an ability to extend the API.
1536 * verifier checks that its value is correct.
1537 */
1538 enum bpf_cgroup_storage_type stype = cgroup_storage_type(map);
1539 struct bpf_cgroup_storage *storage;
1540 struct bpf_cg_run_ctx *ctx;
1541 void *ptr;
1542
1543 /* get current cgroup storage from BPF run context */
1544 ctx = container_of(current->bpf_ctx, struct bpf_cg_run_ctx, run_ctx);
1545 storage = ctx->prog_item->cgroup_storage[stype];
1546
1547 if (stype == BPF_CGROUP_STORAGE_SHARED)
1548 ptr = &READ_ONCE(storage->buf)->data[0];
1549 else
1550 ptr = this_cpu_ptr(storage->percpu_buf);
1551
1552 return (unsigned long)ptr;
1553}
1554
1555const struct bpf_func_proto bpf_get_local_storage_proto = {
1556 .func = bpf_get_local_storage,
1557 .gpl_only = false,
1558 .ret_type = RET_PTR_TO_MAP_VALUE,
1559 .arg1_type = ARG_CONST_MAP_PTR,
1560 .arg2_type = ARG_ANYTHING,
1561};
1562
1532BPF_CALL_0(bpf_get_retval)1563BPF_CALL_0(bpf_get_retval)
1533{1564{
1534 struct bpf_cg_run_ctx *ctx =1565 struct bpf_cg_run_ctx *ctx =
@@ -1560,32 +1591,26 @@ const struct bpf_func_proto bpf_set_retval_proto = { · 25 unmodified lines
1560};1591};
1561 1592
1562static const struct bpf_func_proto *1593static const struct bpf_func_proto *
1563cgroup_base_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)1594cgroup_dev_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
1564{1595{
1596 const struct bpf_func_proto *func_proto;
1597
1598 func_proto = cgroup_common_func_proto(func_id, prog);
1599 if (func_proto)
1600 return func_proto;
1601
1602 func_proto = cgroup_current_func_proto(func_id, prog);
1603 if (func_proto)
1604 return func_proto;
1605
1565 switch (func_id) {1606 switch (func_id) {
1566 case BPF_FUNC_get_current_uid_gid:
1567 return &bpf_get_current_uid_gid_proto;
1568 case BPF_FUNC_get_local_storage:
1569 return &bpf_get_local_storage_proto;
1570 case BPF_FUNC_get_current_cgroup_id:
1571 return &bpf_get_current_cgroup_id_proto;
1572 case BPF_FUNC_perf_event_output:1607 case BPF_FUNC_perf_event_output:
1573 return &bpf_event_output_data_proto;1608 return &bpf_event_output_data_proto;
1574 case BPF_FUNC_get_retval:
1575 return &bpf_get_retval_proto;
1576 case BPF_FUNC_set_retval:
1577 return &bpf_set_retval_proto;
1578 default:1609 default:
1579 return bpf_base_func_proto(func_id);1610 return bpf_base_func_proto(func_id);
1580 }1611 }
1581}1612}
1582 1613
1583static const struct bpf_func_proto *
1584cgroup_dev_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
1585{
1586 return cgroup_base_func_proto(func_id, prog);
1587}
1588
1589static bool cgroup_dev_is_valid_access(int off, int size,1614static bool cgroup_dev_is_valid_access(int off, int size,
1590 enum bpf_access_type type,1615 enum bpf_access_type type,
1591 const struct bpf_prog *prog,1616 const struct bpf_prog *prog,
@@ -2098,11 +2123,17 @@ static const struct bpf_func_proto bpf_sysctl_set_new_value_proto = { · 506 unmodified lines
2098static const struct bpf_func_proto *2123static const struct bpf_func_proto *
2099sysctl_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)2124sysctl_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
2100{2125{
2126 const struct bpf_func_proto *func_proto;
2127
2128 func_proto = cgroup_common_func_proto(func_id, prog);
2129 if (func_proto)
2130 return func_proto;
2131
2132 func_proto = cgroup_current_func_proto(func_id, prog);
2133 if (func_proto)
2134 return func_proto;
2135
2101 switch (func_id) {2136 switch (func_id) {
2102 case BPF_FUNC_strtol:
2103 return &bpf_strtol_proto;
2104 case BPF_FUNC_strtoul:
2105 return &bpf_strtoul_proto;
2106 case BPF_FUNC_sysctl_get_name:2137 case BPF_FUNC_sysctl_get_name:
2107 return &bpf_sysctl_get_name_proto;2138 return &bpf_sysctl_get_name_proto;
2108 case BPF_FUNC_sysctl_get_current_value:2139 case BPF_FUNC_sysctl_get_current_value:
@@ -2113,8 +2144,10 @@ sysctl_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) · 4 unmodified lines
2113 return &bpf_sysctl_set_new_value_proto;2144 return &bpf_sysctl_set_new_value_proto;
2114 case BPF_FUNC_ktime_get_coarse_ns:2145 case BPF_FUNC_ktime_get_coarse_ns:
2115 return &bpf_ktime_get_coarse_ns_proto;2146 return &bpf_ktime_get_coarse_ns_proto;
2147 case BPF_FUNC_perf_event_output:
2148 return &bpf_event_output_data_proto;
2116 default:2149 default:
2117 return cgroup_base_func_proto(func_id, prog);2150 return bpf_base_func_proto(func_id);
2118 }2151 }
2119}2152}
2120 2153
@@ -2235,6 +2268,16 @@ static const struct bpf_func_proto bpf_get_netns_cookie_sockopt_proto = { · 114 unmodified lines
2235static const struct bpf_func_proto *2268static const struct bpf_func_proto *
2236cg_sockopt_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)2269cg_sockopt_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
2237{2270{
2271 const struct bpf_func_proto *func_proto;
2272
2273 func_proto = cgroup_common_func_proto(func_id, prog);
2274 if (func_proto)
2275 return func_proto;
2276
2277 func_proto = cgroup_current_func_proto(func_id, prog);
2278 if (func_proto)
2279 return func_proto;
2280
2238 switch (func_id) {2281 switch (func_id) {
2239#ifdef CONFIG_NET2282#ifdef CONFIG_NET
2240 case BPF_FUNC_get_netns_cookie:2283 case BPF_FUNC_get_netns_cookie:
@@ -2256,8 +2299,10 @@ cg_sockopt_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) · 15 unmodified lines
2256 case BPF_FUNC_tcp_sock:2299 case BPF_FUNC_tcp_sock:
2257 return &bpf_tcp_sock_proto;2300 return &bpf_tcp_sock_proto;
2258#endif2301#endif
2302 case BPF_FUNC_perf_event_output:
2303 return &bpf_event_output_data_proto;
2259 default:2304 default:
2260 return cgroup_base_func_proto(func_id, prog);2305 return bpf_base_func_proto(func_id);
2261 }2306 }
2262}2307}
2263 2308
@@ -2422,3 +2467,69 @@ const struct bpf_verifier_ops cg_sockopt_verifier_ops = { · 158 unmodified lines
2422 2467
2423const struct bpf_prog_ops cg_sockopt_prog_ops = {2468const struct bpf_prog_ops cg_sockopt_prog_ops = {
2424};2469};
2470
2471/* Common helpers for cgroup hooks. */
2472const struct bpf_func_proto *
2473cgroup_common_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
2474{
2475 switch (func_id) {
2476 case BPF_FUNC_get_local_storage:
2477 return &bpf_get_local_storage_proto;
2478 case BPF_FUNC_get_retval:
2479 switch (prog->expected_attach_type) {
2480 case BPF_CGROUP_INET_INGRESS:
2481 case BPF_CGROUP_INET_EGRESS:
2482 case BPF_CGROUP_SOCK_OPS:
2483 case BPF_CGROUP_UDP4_RECVMSG:
2484 case BPF_CGROUP_UDP6_RECVMSG:
2485 case BPF_CGROUP_INET4_GETPEERNAME:
2486 case BPF_CGROUP_INET6_GETPEERNAME:
2487 case BPF_CGROUP_INET4_GETSOCKNAME:
2488 case BPF_CGROUP_INET6_GETSOCKNAME:
2489 return NULL;
2490 default:
2491 return &bpf_get_retval_proto;
2492 }
2493 case BPF_FUNC_set_retval:
2494 switch (prog->expected_attach_type) {
2495 case BPF_CGROUP_INET_INGRESS:
2496 case BPF_CGROUP_INET_EGRESS:
2497 case BPF_CGROUP_SOCK_OPS:
2498 case BPF_CGROUP_UDP4_RECVMSG:
2499 case BPF_CGROUP_UDP6_RECVMSG:
2500 case BPF_CGROUP_INET4_GETPEERNAME:
2501 case BPF_CGROUP_INET6_GETPEERNAME:
2502 case BPF_CGROUP_INET4_GETSOCKNAME:
2503 case BPF_CGROUP_INET6_GETSOCKNAME:
2504 return NULL;
2505 default:
2506 return &bpf_set_retval_proto;
2507 }
2508 default:
2509 return NULL;
2510 }
2511}
2512
2513/* Common helpers for cgroup hooks with valid process context. */
2514const struct bpf_func_proto *
2515cgroup_current_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
2516{
2517 switch (func_id) {
2518 case BPF_FUNC_get_current_uid_gid:
2519 return &bpf_get_current_uid_gid_proto;
2520 case BPF_FUNC_get_current_pid_tgid:
2521 return &bpf_get_current_pid_tgid_proto;
2522 case BPF_FUNC_get_current_comm:
2523 return &bpf_get_current_comm_proto;
2524 case BPF_FUNC_get_current_cgroup_id:
2525 return &bpf_get_current_cgroup_id_proto;
2526 case BPF_FUNC_get_current_ancestor_cgroup_id:
2527 return &bpf_get_current_ancestor_cgroup_id_proto;
2528#ifdef CONFIG_CGROUP_NET_CLASSID
2529 case BPF_FUNC_get_cgroup_classid:
2530 return &bpf_get_cgroup_classid_curr_proto;
2531#endif
2532 default:
2533 return NULL;
2534 }
2535}
kernel/bpf/cgroup_iter.c+282−0
@@ -0,0 +1,282 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/* Copyright (c) 2022 Google */
3#include <linux/bpf.h>
4#include <linux/btf_ids.h>
5#include <linux/cgroup.h>
6#include <linux/kernel.h>
7#include <linux/seq_file.h>
8
9#include "../cgroup/cgroup-internal.h" /* cgroup_mutex and cgroup_is_dead */
10
11/* cgroup_iter provides four modes of traversal to the cgroup hierarchy.
12 *
13 * 1. Walk the descendants of a cgroup in pre-order.
14 * 2. Walk the descendants of a cgroup in post-order.
15 * 3. Walk the ancestors of a cgroup.
16 * 4. Show the given cgroup only.
17 *
18 * For walking descendants, cgroup_iter can walk in either pre-order or
19 * post-order. For walking ancestors, the iter walks up from a cgroup to
20 * the root.
21 *
22 * The iter program can terminate the walk early by returning 1. Walk
23 * continues if prog returns 0.
24 *
25 * The prog can check (seq->num == 0) to determine whether this is
26 * the first element. The prog may also be passed a NULL cgroup,
27 * which means the walk has completed and the prog has a chance to
28 * do post-processing, such as outputting an epilogue.
29 *
30 * Note: the iter_prog is called with cgroup_mutex held.
31 *
32 * Currently only one session is supported, which means, depending on the
33 * volume of data bpf program intends to send to user space, the number
34 * of cgroups that can be walked is limited. For example, given the current
35 * buffer size is 8 * PAGE_SIZE, if the program sends 64B data for each
36 * cgroup, assuming PAGE_SIZE is 4kb, the total number of cgroups that can
37 * be walked is 512. This is a limitation of cgroup_iter. If the output data
38 * is larger than the kernel buffer size, after all data in the kernel buffer
39 * is consumed by user space, the subsequent read() syscall will signal
40 * EOPNOTSUPP. In order to work around, the user may have to update their
41 * program to reduce the volume of data sent to output. For example, skip
42 * some uninteresting cgroups.
43 */
44
45struct bpf_iter__cgroup {
46 __bpf_md_ptr(struct bpf_iter_meta *, meta);
47 __bpf_md_ptr(struct cgroup *, cgroup);
48};
49
50struct cgroup_iter_priv {
51 struct cgroup_subsys_state *start_css;
52 bool visited_all;
53 bool terminate;
54 int order;
55};
56
57static void *cgroup_iter_seq_start(struct seq_file *seq, loff_t *pos)
58{
59 struct cgroup_iter_priv *p = seq->private;
60
61 mutex_lock(&cgroup_mutex);
62
63 /* cgroup_iter doesn't support read across multiple sessions. */
64 if (*pos > 0) {
65 if (p->visited_all)
66 return NULL;
67
68 /* Haven't visited all, but because cgroup_mutex has dropped,
69 * return -EOPNOTSUPP to indicate incomplete iteration.
70 */
71 return ERR_PTR(-EOPNOTSUPP);
72 }
73
74 ++*pos;
75 p->terminate = false;
76 p->visited_all = false;
77 if (p->order == BPF_CGROUP_ITER_DESCENDANTS_PRE)
78 return css_next_descendant_pre(NULL, p->start_css);
79 else if (p->order == BPF_CGROUP_ITER_DESCENDANTS_POST)
80 return css_next_descendant_post(NULL, p->start_css);
81 else /* BPF_CGROUP_ITER_SELF_ONLY and BPF_CGROUP_ITER_ANCESTORS_UP */
82 return p->start_css;
83}
84
85static int __cgroup_iter_seq_show(struct seq_file *seq,
86 struct cgroup_subsys_state *css, int in_stop);
87
88static void cgroup_iter_seq_stop(struct seq_file *seq, void *v)
89{
90 struct cgroup_iter_priv *p = seq->private;
91
92 mutex_unlock(&cgroup_mutex);
93
94 /* pass NULL to the prog for post-processing */
95 if (!v) {
96 __cgroup_iter_seq_show(seq, NULL, true);
97 p->visited_all = true;
98 }
99}
100
101static void *cgroup_iter_seq_next(struct seq_file *seq, void *v, loff_t *pos)
102{
103 struct cgroup_subsys_state *curr = (struct cgroup_subsys_state *)v;
104 struct cgroup_iter_priv *p = seq->private;
105
106 ++*pos;
107 if (p->terminate)
108 return NULL;
109
110 if (p->order == BPF_CGROUP_ITER_DESCENDANTS_PRE)
111 return css_next_descendant_pre(curr, p->start_css);
112 else if (p->order == BPF_CGROUP_ITER_DESCENDANTS_POST)
113 return css_next_descendant_post(curr, p->start_css);
114 else if (p->order == BPF_CGROUP_ITER_ANCESTORS_UP)
115 return curr->parent;
116 else /* BPF_CGROUP_ITER_SELF_ONLY */
117 return NULL;
118}
119
120static int __cgroup_iter_seq_show(struct seq_file *seq,
121 struct cgroup_subsys_state *css, int in_stop)
122{
123 struct cgroup_iter_priv *p = seq->private;
124 struct bpf_iter__cgroup ctx;
125 struct bpf_iter_meta meta;
126 struct bpf_prog *prog;
127 int ret = 0;
128
129 /* cgroup is dead, skip this element */
130 if (css && cgroup_is_dead(css->cgroup))
131 return 0;
132
133 ctx.meta = &meta;
134 ctx.cgroup = css ? css->cgroup : NULL;
135 meta.seq = seq;
136 prog = bpf_iter_get_info(&meta, in_stop);
137 if (prog)
138 ret = bpf_iter_run_prog(prog, &ctx);
139
140 /* if prog returns > 0, terminate after this element. */
141 if (ret != 0)
142 p->terminate = true;
143
144 return 0;
145}
146
147static int cgroup_iter_seq_show(struct seq_file *seq, void *v)
148{
149 return __cgroup_iter_seq_show(seq, (struct cgroup_subsys_state *)v,
150 false);
151}
152
153static const struct seq_operations cgroup_iter_seq_ops = {
154 .start = cgroup_iter_seq_start,
155 .next = cgroup_iter_seq_next,
156 .stop = cgroup_iter_seq_stop,
157 .show = cgroup_iter_seq_show,
158};
159
160BTF_ID_LIST_SINGLE(bpf_cgroup_btf_id, struct, cgroup)
161
162static int cgroup_iter_seq_init(void *priv, struct bpf_iter_aux_info *aux)
163{
164 struct cgroup_iter_priv *p = (struct cgroup_iter_priv *)priv;
165 struct cgroup *cgrp = aux->cgroup.start;
166
167 p->start_css = &cgrp->self;
168 p->terminate = false;
169 p->visited_all = false;
170 p->order = aux->cgroup.order;
171 return 0;
172}
173
174static const struct bpf_iter_seq_info cgroup_iter_seq_info = {
175 .seq_ops = &cgroup_iter_seq_ops,
176 .init_seq_private = cgroup_iter_seq_init,
177 .seq_priv_size = sizeof(struct cgroup_iter_priv),
178};
179
180static int bpf_iter_attach_cgroup(struct bpf_prog *prog,
181 union bpf_iter_link_info *linfo,
182 struct bpf_iter_aux_info *aux)
183{
184 int fd = linfo->cgroup.cgroup_fd;
185 u64 id = linfo->cgroup.cgroup_id;
186 int order = linfo->cgroup.order;
187 struct cgroup *cgrp;
188
189 if (order != BPF_CGROUP_ITER_DESCENDANTS_PRE &&
190 order != BPF_CGROUP_ITER_DESCENDANTS_POST &&
191 order != BPF_CGROUP_ITER_ANCESTORS_UP &&
192 order != BPF_CGROUP_ITER_SELF_ONLY)
193 return -EINVAL;
194
195 if (fd && id)
196 return -EINVAL;
197
198 if (fd)
199 cgrp = cgroup_get_from_fd(fd);
200 else if (id)
201 cgrp = cgroup_get_from_id(id);
202 else /* walk the entire hierarchy by default. */
203 cgrp = cgroup_get_from_path("/");
204
205 if (IS_ERR(cgrp))
206 return PTR_ERR(cgrp);
207
208 aux->cgroup.start = cgrp;
209 aux->cgroup.order = order;
210 return 0;
211}
212
213static void bpf_iter_detach_cgroup(struct bpf_iter_aux_info *aux)
214{
215 cgroup_put(aux->cgroup.start);
216}
217
218static void bpf_iter_cgroup_show_fdinfo(const struct bpf_iter_aux_info *aux,
219 struct seq_file *seq)
220{
221 char *buf;
222
223 buf = kzalloc(PATH_MAX, GFP_KERNEL);
224 if (!buf) {
225 seq_puts(seq, "cgroup_path:\t<unknown>\n");
226 goto show_order;
227 }
228
229 /* If cgroup_path_ns() fails, buf will be an empty string, cgroup_path
230 * will print nothing.
231 *
232 * Path is in the calling process's cgroup namespace.
233 */
234 cgroup_path_ns(aux->cgroup.start, buf, PATH_MAX,
235 current->nsproxy->cgroup_ns);
236 seq_printf(seq, "cgroup_path:\t%s\n", buf);
237 kfree(buf);
238
239show_order:
240 if (aux->cgroup.order == BPF_CGROUP_ITER_DESCENDANTS_PRE)
241 seq_puts(seq, "order: descendants_pre\n");
242 else if (aux->cgroup.order == BPF_CGROUP_ITER_DESCENDANTS_POST)
243 seq_puts(seq, "order: descendants_post\n");
244 else if (aux->cgroup.order == BPF_CGROUP_ITER_ANCESTORS_UP)
245 seq_puts(seq, "order: ancestors_up\n");
246 else /* BPF_CGROUP_ITER_SELF_ONLY */
247 seq_puts(seq, "order: self_only\n");
248}
249
250static int bpf_iter_cgroup_fill_link_info(const struct bpf_iter_aux_info *aux,
251 struct bpf_link_info *info)
252{
253 info->iter.cgroup.order = aux->cgroup.order;
254 info->iter.cgroup.cgroup_id = cgroup_id(aux->cgroup.start);
255 return 0;
256}
257
258DEFINE_BPF_ITER_FUNC(cgroup, struct bpf_iter_meta *meta,
259 struct cgroup *cgroup)
260
261static struct bpf_iter_reg bpf_cgroup_reg_info = {
262 .target = "cgroup",
263 .feature = BPF_ITER_RESCHED,
264 .attach_target = bpf_iter_attach_cgroup,
265 .detach_target = bpf_iter_detach_cgroup,
266 .show_fdinfo = bpf_iter_cgroup_show_fdinfo,
267 .fill_link_info = bpf_iter_cgroup_fill_link_info,
268 .ctx_arg_info_size = 1,
269 .ctx_arg_info = {
270 { offsetof(struct bpf_iter__cgroup, cgroup),
271 PTR_TO_BTF_ID_OR_NULL },
272 },
273 .seq_info = &cgroup_iter_seq_info,
274};
275
276static int __init bpf_cgroup_iter_init(void)
277{
278 bpf_cgroup_reg_info.ctx_arg_info[0].btf_id = bpf_cgroup_btf_id[0];
279 return bpf_iter_reg_target(&bpf_cgroup_reg_info);
280}
281
282late_initcall(bpf_cgroup_iter_init);
kernel/bpf/hashtab.c+123−45
@@ -14,6 +14,7 @@ · 13 unmodified lines
14#include "percpu_freelist.h"14#include "percpu_freelist.h"
15#include "bpf_lru_list.h"15#include "bpf_lru_list.h"
16#include "map_in_map.h"16#include "map_in_map.h"
17#include <linux/bpf_mem_alloc.h>
17 18
18#define HTAB_CREATE_FLAG_MASK \19#define HTAB_CREATE_FLAG_MASK \
19 (BPF_F_NO_PREALLOC | BPF_F_NO_COMMON_LRU | BPF_F_NUMA_NODE | \20 (BPF_F_NO_PREALLOC | BPF_F_NO_COMMON_LRU | BPF_F_NUMA_NODE | \
@@ -92,6 +93,8 @@ struct bucket { · 72 unmodified lines
92 93
93struct bpf_htab {94struct bpf_htab {
94 struct bpf_map map;95 struct bpf_map map;
96 struct bpf_mem_alloc ma;
97 struct bpf_mem_alloc pcpu_ma;
95 struct bucket *buckets;98 struct bucket *buckets;
96 void *elems;99 void *elems;
97 union {100 union {
@@ -99,7 +102,12 @@ struct bpf_htab { · 1 unmodified line
99 struct bpf_lru lru;102 struct bpf_lru lru;
100 };103 };
101 struct htab_elem *__percpu *extra_elems;104 struct htab_elem *__percpu *extra_elems;
102 atomic_t count; /* number of elements in this hashtable */105 /* number of elements in non-preallocated hashtable are kept
106 * in either pcount or count
107 */
108 struct percpu_counter pcount;
109 atomic_t count;
110 bool use_percpu_counter;
103 u32 n_buckets; /* number of hash buckets */111 u32 n_buckets; /* number of hash buckets */
104 u32 elem_size; /* size of each element in bytes */112 u32 elem_size; /* size of each element in bytes */
105 u32 hashrnd;113 u32 hashrnd;
@@ -114,14 +122,14 @@ struct htab_elem { · 8 unmodified lines
114 struct {122 struct {
115 void *padding;123 void *padding;
116 union {124 union {
117 struct bpf_htab *htab;
118 struct pcpu_freelist_node fnode;125 struct pcpu_freelist_node fnode;
119 struct htab_elem *batch_flink;126 struct htab_elem *batch_flink;
120 };127 };
121 };128 };
122 };129 };
123 union {130 union {
124 struct rcu_head rcu;131 /* pointer to per-cpu pointer */
132 void *ptr_to_pptr;
125 struct bpf_lru_node lru_node;133 struct bpf_lru_node lru_node;
126 };134 };
127 u32 hash;135 u32 hash;
@@ -162,17 +170,25 @@ static inline int htab_lock_bucket(const struct bpf_htab *htab, · 34 unmodified lines
162 unsigned long *pflags)170 unsigned long *pflags)
163{171{
164 unsigned long flags;172 unsigned long flags;
173 bool use_raw_lock;
165 174
166 hash = hash & HASHTAB_MAP_LOCK_MASK;175 hash = hash & HASHTAB_MAP_LOCK_MASK;
167 176
168 migrate_disable();177 use_raw_lock = htab_use_raw_lock(htab);
178 if (use_raw_lock)
179 preempt_disable();
180 else
181 migrate_disable();
169 if (unlikely(__this_cpu_inc_return(*(htab->map_locked[hash])) != 1)) {182 if (unlikely(__this_cpu_inc_return(*(htab->map_locked[hash])) != 1)) {
170 __this_cpu_dec(*(htab->map_locked[hash]));183 __this_cpu_dec(*(htab->map_locked[hash]));
171 migrate_enable();184 if (use_raw_lock)
185 preempt_enable();
186 else
187 migrate_enable();
172 return -EBUSY;188 return -EBUSY;
173 }189 }
174 190
175 if (htab_use_raw_lock(htab))191 if (use_raw_lock)
176 raw_spin_lock_irqsave(&b->raw_lock, flags);192 raw_spin_lock_irqsave(&b->raw_lock, flags);
177 else193 else
178 spin_lock_irqsave(&b->lock, flags);194 spin_lock_irqsave(&b->lock, flags);
@@ -185,13 +201,18 @@ static inline void htab_unlock_bucket(const struct bpf_htab *htab, · 6 unmodified lines
185 struct bucket *b, u32 hash,201 struct bucket *b, u32 hash,
186 unsigned long flags)202 unsigned long flags)
187{203{
204 bool use_raw_lock = htab_use_raw_lock(htab);
205
188 hash = hash & HASHTAB_MAP_LOCK_MASK;206 hash = hash & HASHTAB_MAP_LOCK_MASK;
189 if (htab_use_raw_lock(htab))207 if (use_raw_lock)
190 raw_spin_unlock_irqrestore(&b->raw_lock, flags);208 raw_spin_unlock_irqrestore(&b->raw_lock, flags);
191 else209 else
192 spin_unlock_irqrestore(&b->lock, flags);210 spin_unlock_irqrestore(&b->lock, flags);
193 __this_cpu_dec(*(htab->map_locked[hash]));211 __this_cpu_dec(*(htab->map_locked[hash]));
194 migrate_enable();212 if (use_raw_lock)
213 preempt_enable();
214 else
215 migrate_enable();
195}216}
196 217
197static bool htab_lru_map_delete_node(void *arg, struct bpf_lru_node *node);218static bool htab_lru_map_delete_node(void *arg, struct bpf_lru_node *node);
@@ -428,8 +449,6 @@ static int htab_map_alloc_check(union bpf_attr *attr) · 230 unmodified lines
428 bool zero_seed = (attr->map_flags & BPF_F_ZERO_SEED);449 bool zero_seed = (attr->map_flags & BPF_F_ZERO_SEED);
429 int numa_node = bpf_map_attr_numa_node(attr);450 int numa_node = bpf_map_attr_numa_node(attr);
430 451
431 BUILD_BUG_ON(offsetof(struct htab_elem, htab) !=
432 offsetof(struct htab_elem, hash_node.pprev));
433 BUILD_BUG_ON(offsetof(struct htab_elem, fnode.next) !=452 BUILD_BUG_ON(offsetof(struct htab_elem, fnode.next) !=
434 offsetof(struct htab_elem, hash_node.pprev));453 offsetof(struct htab_elem, hash_node.pprev));
435 454
@@ -550,6 +569,29 @@ static struct bpf_map *htab_map_alloc(union bpf_attr *attr) · 114 unmodified lines
550 569
551 htab_init_buckets(htab);570 htab_init_buckets(htab);
552 571
572/* compute_batch_value() computes batch value as num_online_cpus() * 2
573 * and __percpu_counter_compare() needs
574 * htab->max_entries - cur_number_of_elems to be more than batch * num_online_cpus()
575 * for percpu_counter to be faster than atomic_t. In practice the average bpf
576 * hash map size is 10k, which means that a system with 64 cpus will fill
577 * hashmap to 20% of 10k before percpu_counter becomes ineffective. Therefore
578 * define our own batch count as 32 then 10k hash map can be filled up to 80%:
579 * 10k - 8k > 32 _batch_ * 64 _cpus_
580 * and __percpu_counter_compare() will still be fast. At that point hash map
581 * collisions will dominate its performance anyway. Assume that hash map filled
582 * to 50+% isn't going to be O(1) and use the following formula to choose
583 * between percpu_counter and atomic_t.
584 */
585#define PERCPU_COUNTER_BATCH 32
586 if (attr->max_entries / 2 > num_online_cpus() * PERCPU_COUNTER_BATCH)
587 htab->use_percpu_counter = true;
588
589 if (htab->use_percpu_counter) {
590 err = percpu_counter_init(&htab->pcount, 0, GFP_KERNEL);
591 if (err)
592 goto free_map_locked;
593 }
594
553 if (prealloc) {595 if (prealloc) {
554 err = prealloc_init(htab);596 err = prealloc_init(htab);
555 if (err)597 if (err)
@@ -563,6 +605,16 @@ static struct bpf_map *htab_map_alloc(union bpf_attr *attr) · 7 unmodified lines
563 if (err)605 if (err)
564 goto free_prealloc;606 goto free_prealloc;
565 }607 }
608 } else {
609 err = bpf_mem_alloc_init(&htab->ma, htab->elem_size, false);
610 if (err)
611 goto free_map_locked;
612 if (percpu) {
613 err = bpf_mem_alloc_init(&htab->pcpu_ma,
614 round_up(htab->map.value_size, 8), true);
615 if (err)
616 goto free_map_locked;
617 }
566 }618 }
567 619
568 return &htab->map;620 return &htab->map;
@@ -573,6 +625,8 @@ free_map_locked: · 4 unmodified lines
573 for (i = 0; i < HASHTAB_MAP_LOCK_COUNT; i++)625 for (i = 0; i < HASHTAB_MAP_LOCK_COUNT; i++)
574 free_percpu(htab->map_locked[i]);626 free_percpu(htab->map_locked[i]);
575 bpf_map_area_free(htab->buckets);627 bpf_map_area_free(htab->buckets);
628 bpf_mem_alloc_destroy(&htab->pcpu_ma);
629 bpf_mem_alloc_destroy(&htab->ma);
576free_htab:630free_htab:
577 lockdep_unregister_key(&htab->lockdep_key);631 lockdep_unregister_key(&htab->lockdep_key);
578 bpf_map_area_free(htab);632 bpf_map_area_free(htab);
@@ -847,17 +901,9 @@ find_first_elem: · 268 unmodified lines
847static void htab_elem_free(struct bpf_htab *htab, struct htab_elem *l)901static void htab_elem_free(struct bpf_htab *htab, struct htab_elem *l)
848{902{
849 if (htab->map.map_type == BPF_MAP_TYPE_PERCPU_HASH)903 if (htab->map.map_type == BPF_MAP_TYPE_PERCPU_HASH)
850 free_percpu(htab_elem_get_ptr(l, htab->map.key_size));904 bpf_mem_cache_free(&htab->pcpu_ma, l->ptr_to_pptr);
851 check_and_free_fields(htab, l);905 check_and_free_fields(htab, l);
852 kfree(l);906 bpf_mem_cache_free(&htab->ma, l);
853}
854
855static void htab_elem_free_rcu(struct rcu_head *head)
856{
857 struct htab_elem *l = container_of(head, struct htab_elem, rcu);
858 struct bpf_htab *htab = l->htab;
859
860 htab_elem_free(htab, l);
861}907}
862 908
863static void htab_put_fd_value(struct bpf_htab *htab, struct htab_elem *l)909static void htab_put_fd_value(struct bpf_htab *htab, struct htab_elem *l)
@@ -871,6 +917,31 @@ static void htab_put_fd_value(struct bpf_htab *htab, struct htab_elem *l) · 7 unmodified lines
871 }917 }
872}918}
873 919
920static bool is_map_full(struct bpf_htab *htab)
921{
922 if (htab->use_percpu_counter)
923 return __percpu_counter_compare(&htab->pcount, htab->map.max_entries,
924 PERCPU_COUNTER_BATCH) >= 0;
925 return atomic_read(&htab->count) >= htab->map.max_entries;
926}
927
928static void inc_elem_count(struct bpf_htab *htab)
929{
930 if (htab->use_percpu_counter)
931 percpu_counter_add_batch(&htab->pcount, 1, PERCPU_COUNTER_BATCH);
932 else
933 atomic_inc(&htab->count);
934}
935
936static void dec_elem_count(struct bpf_htab *htab)
937{
938 if (htab->use_percpu_counter)
939 percpu_counter_add_batch(&htab->pcount, -1, PERCPU_COUNTER_BATCH);
940 else
941 atomic_dec(&htab->count);
942}
943
944
874static void free_htab_elem(struct bpf_htab *htab, struct htab_elem *l)945static void free_htab_elem(struct bpf_htab *htab, struct htab_elem *l)
875{946{
876 htab_put_fd_value(htab, l);947 htab_put_fd_value(htab, l);
@@ -879,9 +950,8 @@ static void free_htab_elem(struct bpf_htab *htab, struct htab_elem *l) · 2 unmodified lines
879 check_and_free_fields(htab, l);950 check_and_free_fields(htab, l);
880 __pcpu_freelist_push(&htab->freelist, &l->fnode);951 __pcpu_freelist_push(&htab->freelist, &l->fnode);
881 } else {952 } else {
882 atomic_dec(&htab->count);953 dec_elem_count(htab);
883 l->htab = htab;954 htab_elem_free(htab, l);
884 call_rcu(&l->rcu, htab_elem_free_rcu);
885 }955 }
886}956}
887 957
@@ -906,13 +976,12 @@ static void pcpu_copy_value(struct bpf_htab *htab, void __percpu *pptr, · 18 unmodified lines
906static void pcpu_init_value(struct bpf_htab *htab, void __percpu *pptr,976static void pcpu_init_value(struct bpf_htab *htab, void __percpu *pptr,
907 void *value, bool onallcpus)977 void *value, bool onallcpus)
908{978{
909 /* When using prealloc and not setting the initial value on all cpus,979 /* When not setting the initial value on all cpus, zero-fill element
910 * zero-fill element values for other cpus (just as what happens when980 * values for other cpus. Otherwise, bpf program has no way to ensure
911 * not using prealloc). Otherwise, bpf program has no way to ensure
912 * known initial values for cpus other than current one981 * known initial values for cpus other than current one
913 * (onallcpus=false always when coming from bpf prog).982 * (onallcpus=false always when coming from bpf prog).
914 */983 */
915 if (htab_is_prealloc(htab) && !onallcpus) {984 if (!onallcpus) {
916 u32 size = round_up(htab->map.value_size, 8);985 u32 size = round_up(htab->map.value_size, 8);
917 int current_cpu = raw_smp_processor_id();986 int current_cpu = raw_smp_processor_id();
918 int cpu;987 int cpu;
@@ -963,19 +1032,16 @@ static struct htab_elem *alloc_htab_elem(struct bpf_htab *htab, void *key, · 44 unmodified lines
963 l_new = container_of(l, struct htab_elem, fnode);1032 l_new = container_of(l, struct htab_elem, fnode);
964 }1033 }
965 } else {1034 } else {
966 if (atomic_inc_return(&htab->count) > htab->map.max_entries)1035 if (is_map_full(htab))
967 if (!old_elem) {1036 if (!old_elem)
968 /* when map is full and update() is replacing1037 /* when map is full and update() is replacing
969 * old element, it's ok to allocate, since1038 * old element, it's ok to allocate, since
970 * old element will be freed immediately.1039 * old element will be freed immediately.
971 * Otherwise return an error1040 * Otherwise return an error
972 */1041 */
973 l_new = ERR_PTR(-E2BIG);1042 return ERR_PTR(-E2BIG);
974 goto dec_count;1043 inc_elem_count(htab);
975 }1044 l_new = bpf_mem_cache_alloc(&htab->ma);
976 l_new = bpf_map_kmalloc_node(&htab->map, htab->elem_size,
977 GFP_NOWAIT | __GFP_NOWARN,
978 htab->map.numa_node);
979 if (!l_new) {1045 if (!l_new) {
980 l_new = ERR_PTR(-ENOMEM);1046 l_new = ERR_PTR(-ENOMEM);
981 goto dec_count;1047 goto dec_count;
@@ -986,18 +1052,18 @@ static struct htab_elem *alloc_htab_elem(struct bpf_htab *htab, void *key, · 4 unmodified lines
986 1052
987 memcpy(l_new->key, key, key_size);1053 memcpy(l_new->key, key, key_size);
988 if (percpu) {1054 if (percpu) {
989 size = round_up(size, 8);
990 if (prealloc) {1055 if (prealloc) {
991 pptr = htab_elem_get_ptr(l_new, key_size);1056 pptr = htab_elem_get_ptr(l_new, key_size);
992 } else {1057 } else {
993 /* alloc_percpu zero-fills */1058 /* alloc_percpu zero-fills */
994 pptr = bpf_map_alloc_percpu(&htab->map, size, 8,1059 pptr = bpf_mem_cache_alloc(&htab->pcpu_ma);
995 GFP_NOWAIT | __GFP_NOWARN);
996 if (!pptr) {1060 if (!pptr) {
997 kfree(l_new);1061 bpf_mem_cache_free(&htab->ma, l_new);
998 l_new = ERR_PTR(-ENOMEM);1062 l_new = ERR_PTR(-ENOMEM);
999 goto dec_count;1063 goto dec_count;
1000 }1064 }
1065 l_new->ptr_to_pptr = pptr;
1066 pptr = *(void **)pptr;
1001 }1067 }
1002 1068
1003 pcpu_init_value(htab, pptr, value, onallcpus);1069 pcpu_init_value(htab, pptr, value, onallcpus);
@@ -1016,7 +1082,7 @@ static struct htab_elem *alloc_htab_elem(struct bpf_htab *htab, void *key, · 12 unmodified lines
1016 l_new->hash = hash;1082 l_new->hash = hash;
1017 return l_new;1083 return l_new;
1018dec_count:1084dec_count:
1019 atomic_dec(&htab->count);1085 dec_elem_count(htab);
1020 return l_new;1086 return l_new;
1021}1087}
1022 1088
@@ -1416,6 +1482,10 @@ static void delete_all_elements(struct bpf_htab *htab) · 393 unmodified lines
1416{1482{
1417 int i;1483 int i;
1418 1484
1485 /* It's called from a worker thread, so disable migration here,
1486 * since bpf_mem_cache_free() relies on that.
1487 */
1488 migrate_disable();
1419 for (i = 0; i < htab->n_buckets; i++) {1489 for (i = 0; i < htab->n_buckets; i++) {
1420 struct hlist_nulls_head *head = select_bucket(htab, i);1490 struct hlist_nulls_head *head = select_bucket(htab, i);
1421 struct hlist_nulls_node *n;1491 struct hlist_nulls_node *n;
@@ -1426,6 +1496,7 @@ static void delete_all_elements(struct bpf_htab *htab) · 4 unmodified lines
1426 htab_elem_free(htab, l);1496 htab_elem_free(htab, l);
1427 }1497 }
1428 }1498 }
1499 migrate_enable();
1429}1500}
1430 1501
1431static void htab_free_malloced_timers(struct bpf_htab *htab)1502static void htab_free_malloced_timers(struct bpf_htab *htab)
@@ -1475,10 +1546,10 @@ static void htab_map_free(struct bpf_map *map) · 43 unmodified lines
1475 * There is no need to synchronize_rcu() here to protect map elements.1546 * There is no need to synchronize_rcu() here to protect map elements.
1476 */1547 */
1477 1548
1478 /* some of free_htab_elem() callbacks for elements of this map may1549 /* htab no longer uses call_rcu() directly. bpf_mem_alloc does it
1479 * not have executed. Wait for them.1550 * underneath and is reponsible for waiting for callbacks to finish
1551 * during bpf_mem_alloc_destroy().
1480 */1552 */
1481 rcu_barrier();
1482 if (!htab_is_prealloc(htab)) {1553 if (!htab_is_prealloc(htab)) {
1483 delete_all_elements(htab);1554 delete_all_elements(htab);
1484 } else {1555 } else {
@@ -1489,6 +1560,10 @@ static void htab_map_free(struct bpf_map *map) · 4 unmodified lines
1489 bpf_map_free_kptr_off_tab(map);1560 bpf_map_free_kptr_off_tab(map);
1490 free_percpu(htab->extra_elems);1561 free_percpu(htab->extra_elems);
1491 bpf_map_area_free(htab->buckets);1562 bpf_map_area_free(htab->buckets);
1563 bpf_mem_alloc_destroy(&htab->pcpu_ma);
1564 bpf_mem_alloc_destroy(&htab->ma);
1565 if (htab->use_percpu_counter)
1566 percpu_counter_destroy(&htab->pcount);
1492 for (i = 0; i < HASHTAB_MAP_LOCK_COUNT; i++)1567 for (i = 0; i < HASHTAB_MAP_LOCK_COUNT; i++)
1493 free_percpu(htab->map_locked[i]);1568 free_percpu(htab->map_locked[i]);
1494 lockdep_unregister_key(&htab->lockdep_key);1569 lockdep_unregister_key(&htab->lockdep_key);
@@ -1691,8 +1766,11 @@ again_nocopy: · 196 unmodified lines
1691 /* do not grab the lock unless need it (bucket_cnt > 0). */1766 /* do not grab the lock unless need it (bucket_cnt > 0). */
1692 if (locked) {1767 if (locked) {
1693 ret = htab_lock_bucket(htab, b, batch, &flags);1768 ret = htab_lock_bucket(htab, b, batch, &flags);
1694 if (ret)1769 if (ret) {
1695 goto next_batch;1770 rcu_read_unlock();
1771 bpf_enable_instrumentation();
1772 goto after_loop;
1773 }
1696 }1774 }
1697 1775
1698 bucket_cnt = 0;1776 bucket_cnt = 0;
kernel/bpf/helpers.c+9−39
@@ -427,40 +427,7 @@ const struct bpf_func_proto bpf_get_current_ancestor_cgroup_id_proto = { · 426 unmodified lines
427 .ret_type = RET_INTEGER,427 .ret_type = RET_INTEGER,
428 .arg1_type = ARG_ANYTHING,428 .arg1_type = ARG_ANYTHING,
429};429};
430 430#endif /* CONFIG_CGROUPS */
431#ifdef CONFIG_CGROUP_BPF
432
433BPF_CALL_2(bpf_get_local_storage, struct bpf_map *, map, u64, flags)
434{
435 /* flags argument is not used now,
436 * but provides an ability to extend the API.
437 * verifier checks that its value is correct.
438 */
439 enum bpf_cgroup_storage_type stype = cgroup_storage_type(map);
440 struct bpf_cgroup_storage *storage;
441 struct bpf_cg_run_ctx *ctx;
442 void *ptr;
443
444 /* get current cgroup storage from BPF run context */
445 ctx = container_of(current->bpf_ctx, struct bpf_cg_run_ctx, run_ctx);
446 storage = ctx->prog_item->cgroup_storage[stype];
447
448 if (stype == BPF_CGROUP_STORAGE_SHARED)
449 ptr = &READ_ONCE(storage->buf)->data[0];
450 else
451 ptr = this_cpu_ptr(storage->percpu_buf);
452
453 return (unsigned long)ptr;
454}
455
456const struct bpf_func_proto bpf_get_local_storage_proto = {
457 .func = bpf_get_local_storage,
458 .gpl_only = false,
459 .ret_type = RET_PTR_TO_MAP_VALUE,
460 .arg1_type = ARG_CONST_MAP_PTR,
461 .arg2_type = ARG_ANYTHING,
462};
463#endif
464 431
465#define BPF_STRTOX_BASE_MASK 0x1F432#define BPF_STRTOX_BASE_MASK 0x1F
466 433
@@ -589,7 +556,6 @@ const struct bpf_func_proto bpf_strtoul_proto = { · 122 unmodified lines
589 .arg3_type = ARG_ANYTHING,556 .arg3_type = ARG_ANYTHING,
590 .arg4_type = ARG_PTR_TO_LONG,557 .arg4_type = ARG_PTR_TO_LONG,
591};558};
592#endif
593 559
594BPF_CALL_3(bpf_strncmp, const char *, s1, u32, s1_sz, const char *, s2)560BPF_CALL_3(bpf_strncmp, const char *, s1, u32, s1_sz, const char *, s2)
595{561{
@@ -1647,12 +1613,12 @@ bpf_base_func_proto(enum bpf_func_id func_id) · 1051 unmodified lines
1647 return &bpf_ringbuf_submit_dynptr_proto;1613 return &bpf_ringbuf_submit_dynptr_proto;
1648 case BPF_FUNC_ringbuf_discard_dynptr:1614 case BPF_FUNC_ringbuf_discard_dynptr:
1649 return &bpf_ringbuf_discard_dynptr_proto;1615 return &bpf_ringbuf_discard_dynptr_proto;
1650 case BPF_FUNC_for_each_map_elem:
1651 return &bpf_for_each_map_elem_proto;
1652 case BPF_FUNC_loop:
1653 return &bpf_loop_proto;
1654 case BPF_FUNC_strncmp:1616 case BPF_FUNC_strncmp:
1655 return &bpf_strncmp_proto;1617 return &bpf_strncmp_proto;
1618 case BPF_FUNC_strtol:
1619 return &bpf_strtol_proto;
1620 case BPF_FUNC_strtoul:
1621 return &bpf_strtoul_proto;
1656 case BPF_FUNC_dynptr_from_mem:1622 case BPF_FUNC_dynptr_from_mem:
1657 return &bpf_dynptr_from_mem_proto;1623 return &bpf_dynptr_from_mem_proto;
1658 case BPF_FUNC_dynptr_read:1624 case BPF_FUNC_dynptr_read:
@@ -1689,6 +1655,10 @@ bpf_base_func_proto(enum bpf_func_id func_id) · 30 unmodified lines
1689 return &bpf_timer_cancel_proto;1655 return &bpf_timer_cancel_proto;
1690 case BPF_FUNC_kptr_xchg:1656 case BPF_FUNC_kptr_xchg:
1691 return &bpf_kptr_xchg_proto;1657 return &bpf_kptr_xchg_proto;
1658 case BPF_FUNC_for_each_map_elem:
1659 return &bpf_for_each_map_elem_proto;
1660 case BPF_FUNC_loop:
1661 return &bpf_loop_proto;
1692 default:1662 default:
1693 break;1663 break;
1694 }1664 }
kernel/bpf/memalloc.c+634−0
@@ -0,0 +1,634 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
3#include <linux/mm.h>
4#include <linux/llist.h>
5#include <linux/bpf.h>
6#include <linux/irq_work.h>
7#include <linux/bpf_mem_alloc.h>
8#include <linux/memcontrol.h>
9#include <asm/local.h>
10
11/* Any context (including NMI) BPF specific memory allocator.
12 *
13 * Tracing BPF programs can attach to kprobe and fentry. Hence they
14 * run in unknown context where calling plain kmalloc() might not be safe.
15 *
16 * Front-end kmalloc() with per-cpu per-bucket cache of free elements.
17 * Refill this cache asynchronously from irq_work.
18 *
19 * CPU_0 buckets
20 * 16 32 64 96 128 196 256 512 1024 2048 4096
21 * ...
22 * CPU_N buckets
23 * 16 32 64 96 128 196 256 512 1024 2048 4096
24 *
25 * The buckets are prefilled at the start.
26 * BPF programs always run with migration disabled.
27 * It's safe to allocate from cache of the current cpu with irqs disabled.
28 * Free-ing is always done into bucket of the current cpu as well.
29 * irq_work trims extra free elements from buckets with kfree
30 * and refills them with kmalloc, so global kmalloc logic takes care
31 * of freeing objects allocated by one cpu and freed on another.
32 *
33 * Every allocated objected is padded with extra 8 bytes that contains
34 * struct llist_node.
35 */
36#define LLIST_NODE_SZ sizeof(struct llist_node)
37
38/* similar to kmalloc, but sizeof == 8 bucket is gone */
39static u8 size_index[24] __ro_after_init = {
40 3, /* 8 */
41 3, /* 16 */
42 4, /* 24 */
43 4, /* 32 */
44 5, /* 40 */
45 5, /* 48 */
46 5, /* 56 */
47 5, /* 64 */
48 1, /* 72 */
49 1, /* 80 */
50 1, /* 88 */
51 1, /* 96 */
52 6, /* 104 */
53 6, /* 112 */
54 6, /* 120 */
55 6, /* 128 */
56 2, /* 136 */
57 2, /* 144 */
58 2, /* 152 */
59 2, /* 160 */
60 2, /* 168 */
61 2, /* 176 */
62 2, /* 184 */
63 2 /* 192 */
64};
65
66static int bpf_mem_cache_idx(size_t size)
67{
68 if (!size || size > 4096)
69 return -1;
70
71 if (size <= 192)
72 return size_index[(size - 1) / 8] - 1;
73
74 return fls(size - 1) - 1;
75}
76
77#define NUM_CACHES 11
78
79struct bpf_mem_cache {
80 /* per-cpu list of free objects of size 'unit_size'.
81 * All accesses are done with interrupts disabled and 'active' counter
82 * protection with __llist_add() and __llist_del_first().
83 */
84 struct llist_head free_llist;
85 local_t active;
86
87 /* Operations on the free_list from unit_alloc/unit_free/bpf_mem_refill
88 * are sequenced by per-cpu 'active' counter. But unit_free() cannot
89 * fail. When 'active' is busy the unit_free() will add an object to
90 * free_llist_extra.
91 */
92 struct llist_head free_llist_extra;
93
94 struct irq_work refill_work;
95 struct obj_cgroup *objcg;
96 int unit_size;
97 /* count of objects in free_llist */
98 int free_cnt;
99 int low_watermark, high_watermark, batch;
100 int percpu_size;
101
102 struct rcu_head rcu;
103 struct llist_head free_by_rcu;
104 struct llist_head waiting_for_gp;
105 atomic_t call_rcu_in_progress;
106};
107
108struct bpf_mem_caches {
109 struct bpf_mem_cache cache[NUM_CACHES];
110};
111
112static struct llist_node notrace *__llist_del_first(struct llist_head *head)
113{
114 struct llist_node *entry, *next;
115
116 entry = head->first;
117 if (!entry)
118 return NULL;
119 next = entry->next;
120 head->first = next;
121 return entry;
122}
123
124static void *__alloc(struct bpf_mem_cache *c, int node)
125{
126 /* Allocate, but don't deplete atomic reserves that typical
127 * GFP_ATOMIC would do. irq_work runs on this cpu and kmalloc
128 * will allocate from the current numa node which is what we
129 * want here.
130 */
131 gfp_t flags = GFP_NOWAIT | __GFP_NOWARN | __GFP_ACCOUNT;
132
133 if (c->percpu_size) {
134 void **obj = kmalloc_node(c->percpu_size, flags, node);
135 void *pptr = __alloc_percpu_gfp(c->unit_size, 8, flags);
136
137 if (!obj || !pptr) {
138 free_percpu(pptr);
139 kfree(obj);
140 return NULL;
141 }
142 obj[1] = pptr;
143 return obj;
144 }
145
146 return kmalloc_node(c->unit_size, flags, node);
147}
148
149static struct mem_cgroup *get_memcg(const struct bpf_mem_cache *c)
150{
151#ifdef CONFIG_MEMCG_KMEM
152 if (c->objcg)
153 return get_mem_cgroup_from_objcg(c->objcg);
154#endif
155
156#ifdef CONFIG_MEMCG
157 return root_mem_cgroup;
158#else
159 return NULL;
160#endif
161}
162
163/* Mostly runs from irq_work except __init phase. */
164static void alloc_bulk(struct bpf_mem_cache *c, int cnt, int node)
165{
166 struct mem_cgroup *memcg = NULL, *old_memcg;
167 unsigned long flags;
168 void *obj;
169 int i;
170
171 memcg = get_memcg(c);
172 old_memcg = set_active_memcg(memcg);
173 for (i = 0; i < cnt; i++) {
174 obj = __alloc(c, node);
175 if (!obj)
176 break;
177 if (IS_ENABLED(CONFIG_PREEMPT_RT))
178 /* In RT irq_work runs in per-cpu kthread, so disable
179 * interrupts to avoid preemption and interrupts and
180 * reduce the chance of bpf prog executing on this cpu
181 * when active counter is busy.
182 */
183 local_irq_save(flags);
184 /* alloc_bulk runs from irq_work which will not preempt a bpf
185 * program that does unit_alloc/unit_free since IRQs are
186 * disabled there. There is no race to increment 'active'
187 * counter. It protects free_llist from corruption in case NMI
188 * bpf prog preempted this loop.
189 */
190 WARN_ON_ONCE(local_inc_return(&c->active) != 1);
191 __llist_add(obj, &c->free_llist);
192 c->free_cnt++;
193 local_dec(&c->active);
194 if (IS_ENABLED(CONFIG_PREEMPT_RT))
195 local_irq_restore(flags);
196 }
197 set_active_memcg(old_memcg);
198 mem_cgroup_put(memcg);
199}
200
201static void free_one(struct bpf_mem_cache *c, void *obj)
202{
203 if (c->percpu_size) {
204 free_percpu(((void **)obj)[1]);
205 kfree(obj);
206 return;
207 }
208
209 kfree(obj);
210}
211
212static void __free_rcu(struct rcu_head *head)
213{
214 struct bpf_mem_cache *c = container_of(head, struct bpf_mem_cache, rcu);
215 struct llist_node *llnode = llist_del_all(&c->waiting_for_gp);
216 struct llist_node *pos, *t;
217
218 llist_for_each_safe(pos, t, llnode)
219 free_one(c, pos);
220 atomic_set(&c->call_rcu_in_progress, 0);
221}
222
223static void __free_rcu_tasks_trace(struct rcu_head *head)
224{
225 struct bpf_mem_cache *c = container_of(head, struct bpf_mem_cache, rcu);
226
227 call_rcu(&c->rcu, __free_rcu);
228}
229
230static void enque_to_free(struct bpf_mem_cache *c, void *obj)
231{
232 struct llist_node *llnode = obj;
233
234 /* bpf_mem_cache is a per-cpu object. Freeing happens in irq_work.
235 * Nothing races to add to free_by_rcu list.
236 */
237 __llist_add(llnode, &c->free_by_rcu);
238}
239
240static void do_call_rcu(struct bpf_mem_cache *c)
241{
242 struct llist_node *llnode, *t;
243
244 if (atomic_xchg(&c->call_rcu_in_progress, 1))
245 return;
246
247 WARN_ON_ONCE(!llist_empty(&c->waiting_for_gp));
248 llist_for_each_safe(llnode, t, __llist_del_all(&c->free_by_rcu))
249 /* There is no concurrent __llist_add(waiting_for_gp) access.
250 * It doesn't race with llist_del_all either.
251 * But there could be two concurrent llist_del_all(waiting_for_gp):
252 * from __free_rcu() and from drain_mem_cache().
253 */
254 __llist_add(llnode, &c->waiting_for_gp);
255 /* Use call_rcu_tasks_trace() to wait for sleepable progs to finish.
256 * Then use call_rcu() to wait for normal progs to finish
257 * and finally do free_one() on each element.
258 */
259 call_rcu_tasks_trace(&c->rcu, __free_rcu_tasks_trace);
260}
261
262static void free_bulk(struct bpf_mem_cache *c)
263{
264 struct llist_node *llnode, *t;
265 unsigned long flags;
266 int cnt;
267
268 do {
269 if (IS_ENABLED(CONFIG_PREEMPT_RT))
270 local_irq_save(flags);
271 WARN_ON_ONCE(local_inc_return(&c->active) != 1);
272 llnode = __llist_del_first(&c->free_llist);
273 if (llnode)
274 cnt = --c->free_cnt;
275 else
276 cnt = 0;
277 local_dec(&c->active);
278 if (IS_ENABLED(CONFIG_PREEMPT_RT))
279 local_irq_restore(flags);
280 enque_to_free(c, llnode);
281 } while (cnt > (c->high_watermark + c->low_watermark) / 2);
282
283 /* and drain free_llist_extra */
284 llist_for_each_safe(llnode, t, llist_del_all(&c->free_llist_extra))
285 enque_to_free(c, llnode);
286 do_call_rcu(c);
287}
288
289static void bpf_mem_refill(struct irq_work *work)
290{
291 struct bpf_mem_cache *c = container_of(work, struct bpf_mem_cache, refill_work);
292 int cnt;
293
294 /* Racy access to free_cnt. It doesn't need to be 100% accurate */
295 cnt = c->free_cnt;
296 if (cnt < c->low_watermark)
297 /* irq_work runs on this cpu and kmalloc will allocate
298 * from the current numa node which is what we want here.
299 */
300 alloc_bulk(c, c->batch, NUMA_NO_NODE);
301 else if (cnt > c->high_watermark)
302 free_bulk(c);
303}
304
305static void notrace irq_work_raise(struct bpf_mem_cache *c)
306{
307 irq_work_queue(&c->refill_work);
308}
309
310/* For typical bpf map case that uses bpf_mem_cache_alloc and single bucket
311 * the freelist cache will be elem_size * 64 (or less) on each cpu.
312 *
313 * For bpf programs that don't have statically known allocation sizes and
314 * assuming (low_mark + high_mark) / 2 as an average number of elements per
315 * bucket and all buckets are used the total amount of memory in freelists
316 * on each cpu will be:
317 * 64*16 + 64*32 + 64*64 + 64*96 + 64*128 + 64*196 + 64*256 + 32*512 + 16*1024 + 8*2048 + 4*4096
318 * == ~ 116 Kbyte using below heuristic.
319 * Initialized, but unused bpf allocator (not bpf map specific one) will
320 * consume ~ 11 Kbyte per cpu.
321 * Typical case will be between 11K and 116K closer to 11K.
322 * bpf progs can and should share bpf_mem_cache when possible.
323 */
324
325static void prefill_mem_cache(struct bpf_mem_cache *c, int cpu)
326{
327 init_irq_work(&c->refill_work, bpf_mem_refill);
328 if (c->unit_size <= 256) {
329 c->low_watermark = 32;
330 c->high_watermark = 96;
331 } else {
332 /* When page_size == 4k, order-0 cache will have low_mark == 2
333 * and high_mark == 6 with batch alloc of 3 individual pages at
334 * a time.
335 * 8k allocs and above low == 1, high == 3, batch == 1.
336 */
337 c->low_watermark = max(32 * 256 / c->unit_size, 1);
338 c->high_watermark = max(96 * 256 / c->unit_size, 3);
339 }
340 c->batch = max((c->high_watermark - c->low_watermark) / 4 * 3, 1);
341
342 /* To avoid consuming memory assume that 1st run of bpf
343 * prog won't be doing more than 4 map_update_elem from
344 * irq disabled region
345 */
346 alloc_bulk(c, c->unit_size <= 256 ? 4 : 1, cpu_to_node(cpu));
347}
348
349/* When size != 0 bpf_mem_cache for each cpu.
350 * This is typical bpf hash map use case when all elements have equal size.
351 *
352 * When size == 0 allocate 11 bpf_mem_cache-s for each cpu, then rely on
353 * kmalloc/kfree. Max allocation size is 4096 in this case.
354 * This is bpf_dynptr and bpf_kptr use case.
355 */
356int bpf_mem_alloc_init(struct bpf_mem_alloc *ma, int size, bool percpu)
357{
358 static u16 sizes[NUM_CACHES] = {96, 192, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096};
359 struct bpf_mem_caches *cc, __percpu *pcc;
360 struct bpf_mem_cache *c, __percpu *pc;
361 struct obj_cgroup *objcg = NULL;
362 int cpu, i, unit_size, percpu_size = 0;
363
364 if (size) {
365 pc = __alloc_percpu_gfp(sizeof(*pc), 8, GFP_KERNEL);
366 if (!pc)
367 return -ENOMEM;
368
369 if (percpu)
370 /* room for llist_node and per-cpu pointer */
371 percpu_size = LLIST_NODE_SZ + sizeof(void *);
372 else
373 size += LLIST_NODE_SZ; /* room for llist_node */
374 unit_size = size;
375
376#ifdef CONFIG_MEMCG_KMEM
377 objcg = get_obj_cgroup_from_current();
378#endif
379 for_each_possible_cpu(cpu) {
380 c = per_cpu_ptr(pc, cpu);
381 c->unit_size = unit_size;
382 c->objcg = objcg;
383 c->percpu_size = percpu_size;
384 prefill_mem_cache(c, cpu);
385 }
386 ma->cache = pc;
387 return 0;
388 }
389
390 /* size == 0 && percpu is an invalid combination */
391 if (WARN_ON_ONCE(percpu))
392 return -EINVAL;
393
394 pcc = __alloc_percpu_gfp(sizeof(*cc), 8, GFP_KERNEL);
395 if (!pcc)
396 return -ENOMEM;
397#ifdef CONFIG_MEMCG_KMEM
398 objcg = get_obj_cgroup_from_current();
399#endif
400 for_each_possible_cpu(cpu) {
401 cc = per_cpu_ptr(pcc, cpu);
402 for (i = 0; i < NUM_CACHES; i++) {
403 c = &cc->cache[i];
404 c->unit_size = sizes[i];
405 c->objcg = objcg;
406 prefill_mem_cache(c, cpu);
407 }
408 }
409 ma->caches = pcc;
410 return 0;
411}
412
413static void drain_mem_cache(struct bpf_mem_cache *c)
414{
415 struct llist_node *llnode, *t;
416
417 /* No progs are using this bpf_mem_cache, but htab_map_free() called
418 * bpf_mem_cache_free() for all remaining elements and they can be in
419 * free_by_rcu or in waiting_for_gp lists, so drain those lists now.
420 */
421 llist_for_each_safe(llnode, t, __llist_del_all(&c->free_by_rcu))
422 free_one(c, llnode);
423 llist_for_each_safe(llnode, t, llist_del_all(&c->waiting_for_gp))
424 free_one(c, llnode);
425 llist_for_each_safe(llnode, t, llist_del_all(&c->free_llist))
426 free_one(c, llnode);
427 llist_for_each_safe(llnode, t, llist_del_all(&c->free_llist_extra))
428 free_one(c, llnode);
429}
430
431static void free_mem_alloc_no_barrier(struct bpf_mem_alloc *ma)
432{
433 free_percpu(ma->cache);
434 free_percpu(ma->caches);
435 ma->cache = NULL;
436 ma->caches = NULL;
437}
438
439static void free_mem_alloc(struct bpf_mem_alloc *ma)
440{
441 /* waiting_for_gp lists was drained, but __free_rcu might
442 * still execute. Wait for it now before we freeing percpu caches.
443 */
444 rcu_barrier_tasks_trace();
445 rcu_barrier();
446 free_mem_alloc_no_barrier(ma);
447}
448
449static void free_mem_alloc_deferred(struct work_struct *work)
450{
451 struct bpf_mem_alloc *ma = container_of(work, struct bpf_mem_alloc, work);
452
453 free_mem_alloc(ma);
454 kfree(ma);
455}
456
457static void destroy_mem_alloc(struct bpf_mem_alloc *ma, int rcu_in_progress)
458{
459 struct bpf_mem_alloc *copy;
460
461 if (!rcu_in_progress) {
462 /* Fast path. No callbacks are pending, hence no need to do
463 * rcu_barrier-s.
464 */
465 free_mem_alloc_no_barrier(ma);
466 return;
467 }
468
469 copy = kmalloc(sizeof(*ma), GFP_KERNEL);
470 if (!copy) {
471 /* Slow path with inline barrier-s */
472 free_mem_alloc(ma);
473 return;
474 }
475
476 /* Defer barriers into worker to let the rest of map memory to be freed */
477 copy->cache = ma->cache;
478 ma->cache = NULL;
479 copy->caches = ma->caches;
480 ma->caches = NULL;
481 INIT_WORK(&copy->work, free_mem_alloc_deferred);
482 queue_work(system_unbound_wq, &copy->work);
483}
484
485void bpf_mem_alloc_destroy(struct bpf_mem_alloc *ma)
486{
487 struct bpf_mem_caches *cc;
488 struct bpf_mem_cache *c;
489 int cpu, i, rcu_in_progress;
490
491 if (ma->cache) {
492 rcu_in_progress = 0;
493 for_each_possible_cpu(cpu) {
494 c = per_cpu_ptr(ma->cache, cpu);
495 drain_mem_cache(c);
496 rcu_in_progress += atomic_read(&c->call_rcu_in_progress);
497 }
498 /* objcg is the same across cpus */
499 if (c->objcg)
500 obj_cgroup_put(c->objcg);
501 destroy_mem_alloc(ma, rcu_in_progress);
502 }
503 if (ma->caches) {
504 rcu_in_progress = 0;
505 for_each_possible_cpu(cpu) {
506 cc = per_cpu_ptr(ma->caches, cpu);
507 for (i = 0; i < NUM_CACHES; i++) {
508 c = &cc->cache[i];
509 drain_mem_cache(c);
510 rcu_in_progress += atomic_read(&c->call_rcu_in_progress);
511 }
512 }
513 if (c->objcg)
514 obj_cgroup_put(c->objcg);
515 destroy_mem_alloc(ma, rcu_in_progress);
516 }
517}
518
519/* notrace is necessary here and in other functions to make sure
520 * bpf programs cannot attach to them and cause llist corruptions.
521 */
522static void notrace *unit_alloc(struct bpf_mem_cache *c)
523{
524 struct llist_node *llnode = NULL;
525 unsigned long flags;
526 int cnt = 0;
527
528 /* Disable irqs to prevent the following race for majority of prog types:
529 * prog_A
530 * bpf_mem_alloc
531 * preemption or irq -> prog_B
532 * bpf_mem_alloc
533 *
534 * but prog_B could be a perf_event NMI prog.
535 * Use per-cpu 'active' counter to order free_list access between
536 * unit_alloc/unit_free/bpf_mem_refill.
537 */
538 local_irq_save(flags);
539 if (local_inc_return(&c->active) == 1) {
540 llnode = __llist_del_first(&c->free_llist);
541 if (llnode)
542 cnt = --c->free_cnt;
543 }
544 local_dec(&c->active);
545 local_irq_restore(flags);
546
547 WARN_ON(cnt < 0);
548
549 if (cnt < c->low_watermark)
550 irq_work_raise(c);
551 return llnode;
552}
553
554/* Though 'ptr' object could have been allocated on a different cpu
555 * add it to the free_llist of the current cpu.
556 * Let kfree() logic deal with it when it's later called from irq_work.
557 */
558static void notrace unit_free(struct bpf_mem_cache *c, void *ptr)
559{
560 struct llist_node *llnode = ptr - LLIST_NODE_SZ;
561 unsigned long flags;
562 int cnt = 0;
563
564 BUILD_BUG_ON(LLIST_NODE_SZ > 8);
565
566 local_irq_save(flags);
567 if (local_inc_return(&c->active) == 1) {
568 __llist_add(llnode, &c->free_llist);
569 cnt = ++c->free_cnt;
570 } else {
571 /* unit_free() cannot fail. Therefore add an object to atomic
572 * llist. free_bulk() will drain it. Though free_llist_extra is
573 * a per-cpu list we have to use atomic llist_add here, since
574 * it also can be interrupted by bpf nmi prog that does another
575 * unit_free() into the same free_llist_extra.
576 */
577 llist_add(llnode, &c->free_llist_extra);
578 }
579 local_dec(&c->active);
580 local_irq_restore(flags);
581
582 if (cnt > c->high_watermark)
583 /* free few objects from current cpu into global kmalloc pool */
584 irq_work_raise(c);
585}
586
587/* Called from BPF program or from sys_bpf syscall.
588 * In both cases migration is disabled.
589 */
590void notrace *bpf_mem_alloc(struct bpf_mem_alloc *ma, size_t size)
591{
592 int idx;
593 void *ret;
594
595 if (!size)
596 return ZERO_SIZE_PTR;
597
598 idx = bpf_mem_cache_idx(size + LLIST_NODE_SZ);
599 if (idx < 0)
600 return NULL;
601
602 ret = unit_alloc(this_cpu_ptr(ma->caches)->cache + idx);
603 return !ret ? NULL : ret + LLIST_NODE_SZ;
604}
605
606void notrace bpf_mem_free(struct bpf_mem_alloc *ma, void *ptr)
607{
608 int idx;
609
610 if (!ptr)
611 return;
612
613 idx = bpf_mem_cache_idx(__ksize(ptr - LLIST_NODE_SZ));
614 if (idx < 0)
615 return;
616
617 unit_free(this_cpu_ptr(ma->caches)->cache + idx, ptr);
618}
619
620void notrace *bpf_mem_cache_alloc(struct bpf_mem_alloc *ma)
621{
622 void *ret;
623
624 ret = unit_alloc(this_cpu_ptr(ma->cache));
625 return !ret ? NULL : ret + LLIST_NODE_SZ;
626}
627
628void notrace bpf_mem_cache_free(struct bpf_mem_alloc *ma, void *ptr)
629{
630 if (!ptr)
631 return;
632
633 unit_free(this_cpu_ptr(ma->cache), ptr);
634}
kernel/bpf/syscall.c+10−5
@@ -638,7 +638,10 @@ static void __bpf_map_put(struct bpf_map *map, bool do_idr_lock) · 637 unmodified lines
638 bpf_map_free_id(map, do_idr_lock);638 bpf_map_free_id(map, do_idr_lock);
639 btf_put(map->btf);639 btf_put(map->btf);
640 INIT_WORK(&map->work, bpf_map_free_deferred);640 INIT_WORK(&map->work, bpf_map_free_deferred);
641 schedule_work(&map->work);641 /* Avoid spawning kworkers, since they all might contend
642 * for the same mutex like slab_mutex.
643 */
644 queue_work(system_unbound_wq, &map->work);
642 }645 }
643}646}
644 647
@@ -1437,9 +1440,9 @@ err_put: · 792 unmodified lines
1437 1440
1438#define BPF_MAP_DELETE_ELEM_LAST_FIELD key1441#define BPF_MAP_DELETE_ELEM_LAST_FIELD key
1439 1442
1440static int map_delete_elem(union bpf_attr *attr)1443static int map_delete_elem(union bpf_attr *attr, bpfptr_t uattr)
1441{1444{
1442 void __user *ukey = u64_to_user_ptr(attr->key);1445 bpfptr_t ukey = make_bpfptr(attr->key, uattr.is_kernel);
1443 int ufd = attr->map_fd;1446 int ufd = attr->map_fd;
1444 struct bpf_map *map;1447 struct bpf_map *map;
1445 struct fd f;1448 struct fd f;
@@ -1459,7 +1462,7 @@ static int map_delete_elem(union bpf_attr *attr) · 13 unmodified lines
1459 goto err_put;1462 goto err_put;
1460 }1463 }
1461 1464
1462 key = __bpf_copy_key(ukey, map->key_size);1465 key = ___bpf_copy_key(ukey, map->key_size);
1463 if (IS_ERR(key)) {1466 if (IS_ERR(key)) {
1464 err = PTR_ERR(key);1467 err = PTR_ERR(key);
1465 goto err_put;1468 goto err_put;
@@ -4941,7 +4944,7 @@ static int __sys_bpf(int cmd, bpfptr_t uattr, unsigned int size) · 3475 unmodified lines
4941 err = map_update_elem(&attr, uattr);4944 err = map_update_elem(&attr, uattr);
4942 break;4945 break;
4943 case BPF_MAP_DELETE_ELEM:4946 case BPF_MAP_DELETE_ELEM:
4944 err = map_delete_elem(&attr);4947 err = map_delete_elem(&attr, uattr);
4945 break;4948 break;
4946 case BPF_MAP_GET_NEXT_KEY:4949 case BPF_MAP_GET_NEXT_KEY:
4947 err = map_get_next_key(&attr);4950 err = map_get_next_key(&attr);
@@ -5073,8 +5076,10 @@ BPF_CALL_3(bpf_sys_bpf, int, cmd, union bpf_attr *, attr, u32, attr_size) · 125 unmodified lines
5073{5076{
5074 switch (cmd) {5077 switch (cmd) {
5075 case BPF_MAP_CREATE:5078 case BPF_MAP_CREATE:
5079 case BPF_MAP_DELETE_ELEM:
5076 case BPF_MAP_UPDATE_ELEM:5080 case BPF_MAP_UPDATE_ELEM:
5077 case BPF_MAP_FREEZE:5081 case BPF_MAP_FREEZE:
5082 case BPF_MAP_GET_FD_BY_ID:
5078 case BPF_PROG_LOAD:5083 case BPF_PROG_LOAD:
5079 case BPF_BTF_LOAD:5084 case BPF_BTF_LOAD:
5080 case BPF_LINK_CREATE:5085 case BPF_LINK_CREATE:
kernel/bpf/trampoline.c+4−4
@@ -895,7 +895,7 @@ u64 notrace __bpf_prog_enter(struct bpf_prog *prog, struct bpf_tramp_run_ctx *ru · 894 unmodified lines
895 895
896 run_ctx->saved_run_ctx = bpf_set_run_ctx(&run_ctx->run_ctx);896 run_ctx->saved_run_ctx = bpf_set_run_ctx(&run_ctx->run_ctx);
897 897
898 if (unlikely(__this_cpu_inc_return(*(prog->active)) != 1)) {898 if (unlikely(this_cpu_inc_return(*(prog->active)) != 1)) {
899 inc_misses_counter(prog);899 inc_misses_counter(prog);
900 return 0;900 return 0;
901 }901 }
@@ -930,7 +930,7 @@ void notrace __bpf_prog_exit(struct bpf_prog *prog, u64 start, struct bpf_tramp_ · 28 unmodified lines
930 bpf_reset_run_ctx(run_ctx->saved_run_ctx);930 bpf_reset_run_ctx(run_ctx->saved_run_ctx);
931 931
932 update_prog_stats(prog, start);932 update_prog_stats(prog, start);
933 __this_cpu_dec(*(prog->active));933 this_cpu_dec(*(prog->active));
934 migrate_enable();934 migrate_enable();
935 rcu_read_unlock();935 rcu_read_unlock();
936}936}
@@ -966,7 +966,7 @@ u64 notrace __bpf_prog_enter_sleepable(struct bpf_prog *prog, struct bpf_tramp_r · 29 unmodified lines
966 migrate_disable();966 migrate_disable();
967 might_fault();967 might_fault();
968 968
969 if (unlikely(__this_cpu_inc_return(*(prog->active)) != 1)) {969 if (unlikely(this_cpu_inc_return(*(prog->active)) != 1)) {
970 inc_misses_counter(prog);970 inc_misses_counter(prog);
971 return 0;971 return 0;
972 }972 }
@@ -982,7 +982,7 @@ void notrace __bpf_prog_exit_sleepable(struct bpf_prog *prog, u64 start, · 9 unmodified lines
982 bpf_reset_run_ctx(run_ctx->saved_run_ctx);982 bpf_reset_run_ctx(run_ctx->saved_run_ctx);
983 983
984 update_prog_stats(prog, start);984 update_prog_stats(prog, start);
985 __this_cpu_dec(*(prog->active));985 this_cpu_dec(*(prog->active));
986 migrate_enable();986 migrate_enable();
987 rcu_read_unlock_trace();987 rcu_read_unlock_trace();
988}988}
kernel/bpf/verifier.c+33−61
@@ -1092,6 +1092,7 @@ static int acquire_reference_state(struct bpf_verifier_env *env, int insn_idx) · 1091 unmodified lines
1092 id = ++env->id_gen;1092 id = ++env->id_gen;
1093 state->refs[new_ofs].id = id;1093 state->refs[new_ofs].id = id;
1094 state->refs[new_ofs].insn_idx = insn_idx;1094 state->refs[new_ofs].insn_idx = insn_idx;
1095 state->refs[new_ofs].callback_ref = state->in_callback_fn ? state->frameno : 0;
1095 1096
1096 return id;1097 return id;
1097}1098}
@@ -1104,6 +1105,9 @@ static int release_reference_state(struct bpf_func_state *state, int ptr_id) · 6 unmodified lines
1104 last_idx = state->acquired_refs - 1;1105 last_idx = state->acquired_refs - 1;
1105 for (i = 0; i < state->acquired_refs; i++) {1106 for (i = 0; i < state->acquired_refs; i++) {
1106 if (state->refs[i].id == ptr_id) {1107 if (state->refs[i].id == ptr_id) {
1108 /* Cannot release caller references in callbacks */
1109 if (state->in_callback_fn && state->refs[i].callback_ref != state->frameno)
1110 return -EINVAL;
1107 if (last_idx && i != last_idx)1111 if (last_idx && i != last_idx)
1108 memcpy(&state->refs[i], &state->refs[last_idx],1112 memcpy(&state->refs[i], &state->refs[last_idx],
1109 sizeof(*state->refs));1113 sizeof(*state->refs));
@@ -6918,10 +6922,17 @@ static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx) · 5808 unmodified lines
6918 caller->regs[BPF_REG_0] = *r0;6922 caller->regs[BPF_REG_0] = *r0;
6919 }6923 }
6920 6924
6921 /* Transfer references to the caller */6925 /* callback_fn frame should have released its own additions to parent's
6922 err = copy_reference_state(caller, callee);6926 * reference state at this point, or check_reference_leak would
6923 if (err)6927 * complain, hence it must be the same as the caller. There is no need
6924 return err;6928 * to copy it back.
6929 */
6930 if (!callee->in_callback_fn) {
6931 /* Transfer references to the caller */
6932 err = copy_reference_state(caller, callee);
6933 if (err)
6934 return err;
6935 }
6925 6936
6926 *insn_idx = callee->callsite + 1;6937 *insn_idx = callee->callsite + 1;
6927 if (env->log.level & BPF_LOG_LEVEL) {6938 if (env->log.level & BPF_LOG_LEVEL) {
@@ -7043,13 +7054,20 @@ record_func_key(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta, · 115 unmodified lines
7043static int check_reference_leak(struct bpf_verifier_env *env)7054static int check_reference_leak(struct bpf_verifier_env *env)
7044{7055{
7045 struct bpf_func_state *state = cur_func(env);7056 struct bpf_func_state *state = cur_func(env);
7057 bool refs_lingering = false;
7046 int i;7058 int i;
7047 7059
7060 if (state->frameno && !state->in_callback_fn)
7061 return 0;
7062
7048 for (i = 0; i < state->acquired_refs; i++) {7063 for (i = 0; i < state->acquired_refs; i++) {
7064 if (state->in_callback_fn && state->refs[i].callback_ref != state->frameno)
7065 continue;
7049 verbose(env, "Unreleased reference id=%d alloc_insn=%d\n",7066 verbose(env, "Unreleased reference id=%d alloc_insn=%d\n",
7050 state->refs[i].id, state->refs[i].insn_idx);7067 state->refs[i].id, state->refs[i].insn_idx);
7068 refs_lingering = true;
7051 }7069 }
7052 return state->acquired_refs ? -EINVAL : 0;7070 return refs_lingering ? -EINVAL : 0;
7053}7071}
7054 7072
7055static int check_bpf_snprintf_call(struct bpf_verifier_env *env,7073static int check_bpf_snprintf_call(struct bpf_verifier_env *env,
@@ -12338,6 +12356,16 @@ static int do_check(struct bpf_verifier_env *env) · 5282 unmodified lines
12338 return -EINVAL;12356 return -EINVAL;
12339 }12357 }
12340 12358
12359 /* We must do check_reference_leak here before
12360 * prepare_func_exit to handle the case when
12361 * state->curframe > 0, it may be a callback
12362 * function, for which reference_state must
12363 * match caller reference state when it exits.
12364 */
12365 err = check_reference_leak(env);
12366 if (err)
12367 return err;
12368
12341 if (state->curframe) {12369 if (state->curframe) {
12342 /* exit from nested function */12370 /* exit from nested function */
12343 err = prepare_func_exit(env, &env->insn_idx);12371 err = prepare_func_exit(env, &env->insn_idx);
@@ -12347,10 +12375,6 @@ static int do_check(struct bpf_verifier_env *env) · 3 unmodified lines
12347 continue;12375 continue;
12348 }12376 }
12349 12377
12350 err = check_reference_leak(env);
12351 if (err)
12352 return err;
12353
12354 err = check_return_code(env);12378 err = check_return_code(env);
12355 if (err)12379 if (err)
12356 return err;12380 return err;
@@ -12563,14 +12587,6 @@ err_put: · 206 unmodified lines
12563 return err;12587 return err;
12564}12588}
12565 12589
12566static int check_map_prealloc(struct bpf_map *map)
12567{
12568 return (map->map_type != BPF_MAP_TYPE_HASH &&
12569 map->map_type != BPF_MAP_TYPE_PERCPU_HASH &&
12570 map->map_type != BPF_MAP_TYPE_HASH_OF_MAPS) ||
12571 !(map->map_flags & BPF_F_NO_PREALLOC);
12572}
12573
12574static bool is_tracing_prog_type(enum bpf_prog_type type)12590static bool is_tracing_prog_type(enum bpf_prog_type type)
12575{12591{
12576 switch (type) {12592 switch (type) {
@@ -12585,50 +12601,12 @@ static bool is_tracing_prog_type(enum bpf_prog_type type) · 8 unmodified lines
12585 }12601 }
12586}12602}
12587 12603
12588static bool is_preallocated_map(struct bpf_map *map)
12589{
12590 if (!check_map_prealloc(map))
12591 return false;
12592 if (map->inner_map_meta && !check_map_prealloc(map->inner_map_meta))
12593 return false;
12594 return true;
12595}
12596
12597static int check_map_prog_compatibility(struct bpf_verifier_env *env,12604static int check_map_prog_compatibility(struct bpf_verifier_env *env,
12598 struct bpf_map *map,12605 struct bpf_map *map,
12599 struct bpf_prog *prog)12606 struct bpf_prog *prog)
12600 12607
12601{12608{
12602 enum bpf_prog_type prog_type = resolve_prog_type(prog);12609 enum bpf_prog_type prog_type = resolve_prog_type(prog);
12603 /*
12604 * Validate that trace type programs use preallocated hash maps.
12605 *
12606 * For programs attached to PERF events this is mandatory as the
12607 * perf NMI can hit any arbitrary code sequence.
12608 *
12609 * All other trace types using preallocated hash maps are unsafe as
12610 * well because tracepoint or kprobes can be inside locked regions
12611 * of the memory allocator or at a place where a recursion into the
12612 * memory allocator would see inconsistent state.
12613 *
12614 * On RT enabled kernels run-time allocation of all trace type
12615 * programs is strictly prohibited due to lock type constraints. On
12616 * !RT kernels it is allowed for backwards compatibility reasons for
12617 * now, but warnings are emitted so developers are made aware of
12618 * the unsafety and can fix their programs before this is enforced.
12619 */
12620 if (is_tracing_prog_type(prog_type) && !is_preallocated_map(map)) {
12621 if (prog_type == BPF_PROG_TYPE_PERF_EVENT) {
12622 verbose(env, "perf_event programs can only use preallocated hash map\n");
12623 return -EINVAL;
12624 }
12625 if (IS_ENABLED(CONFIG_PREEMPT_RT)) {
12626 verbose(env, "trace type programs can only use preallocated hash map\n");
12627 return -EINVAL;
12628 }
12629 WARN_ONCE(1, "trace type BPF program uses run-time allocation\n");
12630 verbose(env, "trace type programs with run-time allocated hash maps are unsafe. Switch to preallocated hash maps.\n");
12631 }
12632 12610
12633 if (map_value_has_spin_lock(map)) {12611 if (map_value_has_spin_lock(map)) {
12634 if (prog_type == BPF_PROG_TYPE_SOCKET_FILTER) {12612 if (prog_type == BPF_PROG_TYPE_SOCKET_FILTER) {
@@ -12675,12 +12653,6 @@ static int check_map_prog_compatibility(struct bpf_verifier_env *env, · 40 unmodified lines
12675 case BPF_MAP_TYPE_LRU_PERCPU_HASH:12653 case BPF_MAP_TYPE_LRU_PERCPU_HASH:
12676 case BPF_MAP_TYPE_ARRAY_OF_MAPS:12654 case BPF_MAP_TYPE_ARRAY_OF_MAPS:
12677 case BPF_MAP_TYPE_HASH_OF_MAPS:12655 case BPF_MAP_TYPE_HASH_OF_MAPS:
12678 if (!is_preallocated_map(map)) {
12679 verbose(env,
12680 "Sleepable programs can only use preallocated maps\n");
12681 return -EINVAL;
12682 }
12683 break;
12684 case BPF_MAP_TYPE_RINGBUF:12656 case BPF_MAP_TYPE_RINGBUF:
12685 case BPF_MAP_TYPE_INODE_STORAGE:12657 case BPF_MAP_TYPE_INODE_STORAGE:
12686 case BPF_MAP_TYPE_SK_STORAGE:12658 case BPF_MAP_TYPE_SK_STORAGE:
kernel/cgroup/rstat.c+48−0
@@ -3,6 +3,10 @@ · 2 unmodified lines
3 3
4#include <linux/sched/cputime.h>4#include <linux/sched/cputime.h>
5 5
6#include <linux/bpf.h>
7#include <linux/btf.h>
8#include <linux/btf_ids.h>
9
6static DEFINE_SPINLOCK(cgroup_rstat_lock);10static DEFINE_SPINLOCK(cgroup_rstat_lock);
7static DEFINE_PER_CPU(raw_spinlock_t, cgroup_rstat_cpu_lock);11static DEFINE_PER_CPU(raw_spinlock_t, cgroup_rstat_cpu_lock);
8 12
@@ -141,6 +145,31 @@ static struct cgroup *cgroup_rstat_cpu_pop_updated(struct cgroup *pos, · 132 unmodified lines
141 return pos;145 return pos;
142}146}
143 147
148/*
149 * A hook for bpf stat collectors to attach to and flush their stats.
150 * Together with providing bpf kfuncs for cgroup_rstat_updated() and
151 * cgroup_rstat_flush(), this enables a complete workflow where bpf progs that
152 * collect cgroup stats can integrate with rstat for efficient flushing.
153 *
154 * A static noinline declaration here could cause the compiler to optimize away
155 * the function. A global noinline declaration will keep the definition, but may
156 * optimize away the callsite. Therefore, __weak is needed to ensure that the
157 * call is still emitted, by telling the compiler that we don't know what the
158 * function might eventually be.
159 *
160 * __diag_* below are needed to dismiss the missing prototype warning.
161 */
162__diag_push();
163__diag_ignore_all("-Wmissing-prototypes",
164 "kfuncs which will be used in BPF programs");
165
166__weak noinline void bpf_rstat_flush(struct cgroup *cgrp,
167 struct cgroup *parent, int cpu)
168{
169}
170
171__diag_pop();
172
144/* see cgroup_rstat_flush() */173/* see cgroup_rstat_flush() */
145static void cgroup_rstat_flush_locked(struct cgroup *cgrp, bool may_sleep)174static void cgroup_rstat_flush_locked(struct cgroup *cgrp, bool may_sleep)
146 __releases(&cgroup_rstat_lock) __acquires(&cgroup_rstat_lock)175 __releases(&cgroup_rstat_lock) __acquires(&cgroup_rstat_lock)
@@ -168,6 +197,7 @@ static void cgroup_rstat_flush_locked(struct cgroup *cgrp, bool may_sleep) · 21 unmodified lines
168 struct cgroup_subsys_state *css;197 struct cgroup_subsys_state *css;
169 198
170 cgroup_base_stat_flush(pos, cpu);199 cgroup_base_stat_flush(pos, cpu);
200 bpf_rstat_flush(pos, cgroup_parent(pos), cpu);
171 201
172 rcu_read_lock();202 rcu_read_lock();
173 list_for_each_entry_rcu(css, &pos->rstat_css_list,203 list_for_each_entry_rcu(css, &pos->rstat_css_list,
@@ -501,3 +531,21 @@ void cgroup_base_stat_cputime_show(struct seq_file *seq) · 327 unmodified lines
501 seq_printf(seq, "core_sched.force_idle_usec %llu\n", forceidle_time);531 seq_printf(seq, "core_sched.force_idle_usec %llu\n", forceidle_time);
502#endif532#endif
503}533}
534
535/* Add bpf kfuncs for cgroup_rstat_updated() and cgroup_rstat_flush() */
536BTF_SET8_START(bpf_rstat_kfunc_ids)
537BTF_ID_FLAGS(func, cgroup_rstat_updated)
538BTF_ID_FLAGS(func, cgroup_rstat_flush, KF_SLEEPABLE)
539BTF_SET8_END(bpf_rstat_kfunc_ids)
540
541static const struct btf_kfunc_id_set bpf_rstat_kfunc_set = {
542 .owner = THIS_MODULE,
543 .set = &bpf_rstat_kfunc_ids,
544};
545
546static int __init bpf_rstat_kfunc_init(void)
547{
548 return register_btf_kfunc_id_set(BPF_PROG_TYPE_TRACING,
549 &bpf_rstat_kfunc_set);
550}
551late_initcall(bpf_rstat_kfunc_init);
net/core/filter.c+262−373
@@ -3010,7 +3010,7 @@ BPF_CALL_0(bpf_get_cgroup_classid_curr) · 3009 unmodified lines
3010 return __task_get_classid(current);3010 return __task_get_classid(current);
3011}3011}
3012 3012
3013static const struct bpf_func_proto bpf_get_cgroup_classid_curr_proto = {3013const struct bpf_func_proto bpf_get_cgroup_classid_curr_proto = {
3014 .func = bpf_get_cgroup_classid_curr,3014 .func = bpf_get_cgroup_classid_curr,
3015 .gpl_only = false,3015 .gpl_only = false,
3016 .ret_type = RET_INTEGER,3016 .ret_type = RET_INTEGER,
@@ -4489,7 +4489,8 @@ BPF_CALL_4(bpf_skb_get_tunnel_key, struct sk_buff *, skb, struct bpf_tunnel_key · 1472 unmodified lines
4489 void *to_orig = to;4489 void *to_orig = to;
4490 int err;4490 int err;
4491 4491
4492 if (unlikely(!info || (flags & ~(BPF_F_TUNINFO_IPV6)))) {4492 if (unlikely(!info || (flags & ~(BPF_F_TUNINFO_IPV6 |
4493 BPF_F_TUNINFO_FLAGS)))) {
4493 err = -EINVAL;4494 err = -EINVAL;
4494 goto err_clear;4495 goto err_clear;
4495 }4496 }
@@ -4521,7 +4522,10 @@ set_compat: · 25 unmodified lines
4521 to->tunnel_id = be64_to_cpu(info->key.tun_id);4522 to->tunnel_id = be64_to_cpu(info->key.tun_id);
4522 to->tunnel_tos = info->key.tos;4523 to->tunnel_tos = info->key.tos;
4523 to->tunnel_ttl = info->key.ttl;4524 to->tunnel_ttl = info->key.ttl;
4524 to->tunnel_ext = 0;4525 if (flags & BPF_F_TUNINFO_FLAGS)
4526 to->tunnel_flags = info->key.tun_flags;
4527 else
4528 to->tunnel_ext = 0;
4525 4529
4526 if (flags & BPF_F_TUNINFO_IPV6) {4530 if (flags & BPF_F_TUNINFO_IPV6) {
4527 memcpy(to->remote_ipv6, &info->key.u.ipv6.src,4531 memcpy(to->remote_ipv6, &info->key.u.ipv6.src,
@@ -5014,359 +5018,259 @@ static const struct bpf_func_proto bpf_get_socket_uid_proto = { · 486 unmodified lines
5014 .arg1_type = ARG_PTR_TO_CTX,5018 .arg1_type = ARG_PTR_TO_CTX,
5015};5019};
5016 5020
5017static int __bpf_setsockopt(struct sock *sk, int level, int optname,5021static int sol_socket_sockopt(struct sock *sk, int optname,
5018 char *optval, int optlen)5022 char *optval, int *optlen,
5019{5023 bool getopt)
5020 char devname[IFNAMSIZ];5024{
5021 int val, valbool;5025 switch (optname) {
5022 struct net *net;5026 case SO_REUSEADDR:
5023 int ifindex;5027 case SO_SNDBUF:
5024 int ret = 0;5028 case SO_RCVBUF:
5025 5029 case SO_KEEPALIVE:
5026 if (!sk_fullsock(sk))5030 case SO_PRIORITY:
5031 case SO_REUSEPORT:
5032 case SO_RCVLOWAT:
5033 case SO_MARK:
5034 case SO_MAX_PACING_RATE:
5035 case SO_BINDTOIFINDEX:
5036 case SO_TXREHASH:
5037 if (*optlen != sizeof(int))
5038 return -EINVAL;
5039 break;
5040 case SO_BINDTODEVICE:
5041 break;
5042 default:
5027 return -EINVAL;5043 return -EINVAL;
5044 }
5028 5045
5029 if (level == SOL_SOCKET) {5046 if (getopt) {
5030 if (optlen != sizeof(int) && optname != SO_BINDTODEVICE)5047 if (optname == SO_BINDTODEVICE)
5031 return -EINVAL;5048 return -EINVAL;
5032 val = *((int *)optval);5049 return sk_getsockopt(sk, SOL_SOCKET, optname,
5033 valbool = val ? 1 : 0;5050 KERNEL_SOCKPTR(optval),
5034 5051 KERNEL_SOCKPTR(optlen));
5035 /* Only some socketops are supported */5052 }
5036 switch (optname) {
5037 case SO_RCVBUF:
5038 val = min_t(u32, val, READ_ONCE(sysctl_rmem_max));
5039 val = min_t(int, val, INT_MAX / 2);
5040 sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
5041 WRITE_ONCE(sk->sk_rcvbuf,
5042 max_t(int, val * 2, SOCK_MIN_RCVBUF));
5043 break;
5044 case SO_SNDBUF:
5045 val = min_t(u32, val, READ_ONCE(sysctl_wmem_max));
5046 val = min_t(int, val, INT_MAX / 2);
5047 sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
5048 WRITE_ONCE(sk->sk_sndbuf,
5049 max_t(int, val * 2, SOCK_MIN_SNDBUF));
5050 break;
5051 case SO_MAX_PACING_RATE: /* 32bit version */
5052 if (val != ~0U)
5053 cmpxchg(&sk->sk_pacing_status,
5054 SK_PACING_NONE,
5055 SK_PACING_NEEDED);
5056 sk->sk_max_pacing_rate = (val == ~0U) ?
5057 ~0UL : (unsigned int)val;
5058 sk->sk_pacing_rate = min(sk->sk_pacing_rate,
5059 sk->sk_max_pacing_rate);
5060 break;
5061 case SO_PRIORITY:
5062 sk->sk_priority = val;
5063 break;
5064 case SO_RCVLOWAT:
5065 if (val < 0)
5066 val = INT_MAX;
5067 if (sk->sk_socket && sk->sk_socket->ops->set_rcvlowat)
5068 ret = sk->sk_socket->ops->set_rcvlowat(sk, val);
5069 else
5070 WRITE_ONCE(sk->sk_rcvlowat, val ? : 1);
5071 break;
5072 case SO_MARK:
5073 if (sk->sk_mark != val) {
5074 sk->sk_mark = val;
5075 sk_dst_reset(sk);
5076 }
5077 break;
5078 case SO_BINDTODEVICE:
5079 optlen = min_t(long, optlen, IFNAMSIZ - 1);
5080 strncpy(devname, optval, optlen);
5081 devname[optlen] = 0;
5082 5053
5083 ifindex = 0;5054 return sk_setsockopt(sk, SOL_SOCKET, optname,
5084 if (devname[0] != '\0') {5055 KERNEL_SOCKPTR(optval), *optlen);
5085 struct net_device *dev;5056}
5086 5057
5087 ret = -ENODEV;5058static int bpf_sol_tcp_setsockopt(struct sock *sk, int optname,
5059 char *optval, int optlen)
5060{
5061 struct tcp_sock *tp = tcp_sk(sk);
5062 unsigned long timeout;
5063 int val;
5088 5064
5089 net = sock_net(sk);5065 if (optlen != sizeof(int))
5090 dev = dev_get_by_name(net, devname);5066 return -EINVAL;
5091 if (!dev)
5092 break;
5093 ifindex = dev->ifindex;
5094 dev_put(dev);
5095 }
5096 fallthrough;
5097 case SO_BINDTOIFINDEX:
5098 if (optname == SO_BINDTOIFINDEX)
5099 ifindex = val;
5100 ret = sock_bindtoindex(sk, ifindex, false);
5101 break;
5102 case SO_KEEPALIVE:
5103 if (sk->sk_prot->keepalive)
5104 sk->sk_prot->keepalive(sk, valbool);
5105 sock_valbool_flag(sk, SOCK_KEEPOPEN, valbool);
5106 break;
5107 case SO_REUSEPORT:
5108 sk->sk_reuseport = valbool;
5109 break;
5110 case SO_TXREHASH:
5111 if (val < -1 || val > 1) {
5112 ret = -EINVAL;
5113 break;
5114 }
5115 sk->sk_txrehash = (u8)val;
5116 break;
5117 default:
5118 ret = -EINVAL;
5119 }
5120#ifdef CONFIG_INET
5121 } else if (level == SOL_IP) {
5122 if (optlen != sizeof(int) || sk->sk_family != AF_INET)
5123 return -EINVAL;
5124 5067
5125 val = *((int *)optval);5068 val = *(int *)optval;
5126 /* Only some options are supported */
5127 switch (optname) {
5128 case IP_TOS:
5129 if (val < -1 || val > 0xff) {
5130 ret = -EINVAL;
5131 } else {
5132 struct inet_sock *inet = inet_sk(sk);
5133 5069
5134 if (val == -1)5070 /* Only some options are supported */
5135 val = 0;5071 switch (optname) {
5136 inet->tos = val;5072 case TCP_BPF_IW:
5137 }5073 if (val <= 0 || tp->data_segs_out > tp->syn_data)
5138 break;5074 return -EINVAL;
5139 default:5075 tcp_snd_cwnd_set(tp, val);
5140 ret = -EINVAL;5076 break;
5141 }5077 case TCP_BPF_SNDCWND_CLAMP:
5142#if IS_ENABLED(CONFIG_IPV6)5078 if (val <= 0)
5143 } else if (level == SOL_IPV6) {5079 return -EINVAL;
5144 if (optlen != sizeof(int) || sk->sk_family != AF_INET6)5080 tp->snd_cwnd_clamp = val;
5081 tp->snd_ssthresh = val;
5082 break;
5083 case TCP_BPF_DELACK_MAX:
5084 timeout = usecs_to_jiffies(val);
5085 if (timeout > TCP_DELACK_MAX ||
5086 timeout < TCP_TIMEOUT_MIN)
5087 return -EINVAL;
5088 inet_csk(sk)->icsk_delack_max = timeout;
5089 break;
5090 case TCP_BPF_RTO_MIN:
5091 timeout = usecs_to_jiffies(val);
5092 if (timeout > TCP_RTO_MIN ||
5093 timeout < TCP_TIMEOUT_MIN)
5145 return -EINVAL;5094 return -EINVAL;
5095 inet_csk(sk)->icsk_rto_min = timeout;
5096 break;
5097 default:
5098 return -EINVAL;
5099 }
5146 5100
5147 val = *((int *)optval);5101 return 0;
5148 /* Only some options are supported */5102}
5149 switch (optname) {
5150 case IPV6_TCLASS:
5151 if (val < -1 || val > 0xff) {
5152 ret = -EINVAL;
5153 } else {
5154 struct ipv6_pinfo *np = inet6_sk(sk);
5155 5103
5156 if (val == -1)5104static int sol_tcp_sockopt(struct sock *sk, int optname,
5157 val = 0;5105 char *optval, int *optlen,
5158 np->tclass = val;5106 bool getopt)
5159 }5107{
5160 break;5108 if (sk->sk_prot->setsockopt != tcp_setsockopt)
5161 default:5109 return -EINVAL;
5162 ret = -EINVAL;
5163 }
5164#endif
5165 } else if (level == SOL_TCP &&
5166 sk->sk_prot->setsockopt == tcp_setsockopt) {
5167 if (optname == TCP_CONGESTION) {
5168 char name[TCP_CA_NAME_MAX];
5169 5110
5170 strncpy(name, optval, min_t(long, optlen,5111 switch (optname) {
5171 TCP_CA_NAME_MAX-1));5112 case TCP_NODELAY:
5172 name[TCP_CA_NAME_MAX-1] = 0;5113 case TCP_MAXSEG:
5173 ret = tcp_set_congestion_control(sk, name, false, true);5114 case TCP_KEEPIDLE:
5174 } else {5115 case TCP_KEEPINTVL:
5175 struct inet_connection_sock *icsk = inet_csk(sk);5116 case TCP_KEEPCNT:
5117 case TCP_SYNCNT:
5118 case TCP_WINDOW_CLAMP:
5119 case TCP_THIN_LINEAR_TIMEOUTS:
5120 case TCP_USER_TIMEOUT:
5121 case TCP_NOTSENT_LOWAT:
5122 case TCP_SAVE_SYN:
5123 if (*optlen != sizeof(int))
5124 return -EINVAL;
5125 break;
5126 case TCP_CONGESTION:
5127 if (*optlen < 2)
5128 return -EINVAL;
5129 break;
5130 case TCP_SAVED_SYN:
5131 if (*optlen < 1)
5132 return -EINVAL;
5133 break;
5134 default:
5135 if (getopt)
5136 return -EINVAL;
5137 return bpf_sol_tcp_setsockopt(sk, optname, optval, *optlen);
5138 }
5139
5140 if (getopt) {
5141 if (optname == TCP_SAVED_SYN) {
5176 struct tcp_sock *tp = tcp_sk(sk);5142 struct tcp_sock *tp = tcp_sk(sk);
5177 unsigned long timeout;
5178 5143
5179 if (optlen != sizeof(int))5144 if (!tp->saved_syn ||
5145 *optlen > tcp_saved_syn_len(tp->saved_syn))
5180 return -EINVAL;5146 return -EINVAL;
5147 memcpy(optval, tp->saved_syn->data, *optlen);
5148 /* It cannot free tp->saved_syn here because it
5149 * does not know if the user space still needs it.
5150 */
5151 return 0;
5152 }
5181 5153
5182 val = *((int *)optval);5154 if (optname == TCP_CONGESTION) {
5183 /* Only some options are supported */5155 if (!inet_csk(sk)->icsk_ca_ops)
5184 switch (optname) {5156 return -EINVAL;
5185 case TCP_BPF_IW:5157 /* BPF expects NULL-terminated tcp-cc string */
5186 if (val <= 0 || tp->data_segs_out > tp->syn_data)5158 optval[--(*optlen)] = '\0';
5187 ret = -EINVAL;
5188 else
5189 tcp_snd_cwnd_set(tp, val);
5190 break;
5191 case TCP_BPF_SNDCWND_CLAMP:
5192 if (val <= 0) {
5193 ret = -EINVAL;
5194 } else {
5195 tp->snd_cwnd_clamp = val;
5196 tp->snd_ssthresh = val;
5197 }
5198 break;
5199 case TCP_BPF_DELACK_MAX:
5200 timeout = usecs_to_jiffies(val);
5201 if (timeout > TCP_DELACK_MAX ||
5202 timeout < TCP_TIMEOUT_MIN)
5203 return -EINVAL;
5204 inet_csk(sk)->icsk_delack_max = timeout;
5205 break;
5206 case TCP_BPF_RTO_MIN:
5207 timeout = usecs_to_jiffies(val);
5208 if (timeout > TCP_RTO_MIN ||
5209 timeout < TCP_TIMEOUT_MIN)
5210 return -EINVAL;
5211 inet_csk(sk)->icsk_rto_min = timeout;
5212 break;
5213 case TCP_SAVE_SYN:
5214 if (val < 0 || val > 1)
5215 ret = -EINVAL;
5216 else
5217 tp->save_syn = val;
5218 break;
5219 case TCP_KEEPIDLE:
5220 ret = tcp_sock_set_keepidle_locked(sk, val);
5221 break;
5222 case TCP_KEEPINTVL:
5223 if (val < 1 || val > MAX_TCP_KEEPINTVL)
5224 ret = -EINVAL;
5225 else
5226 tp->keepalive_intvl = val * HZ;
5227 break;
5228 case TCP_KEEPCNT:
5229 if (val < 1 || val > MAX_TCP_KEEPCNT)
5230 ret = -EINVAL;
5231 else
5232 tp->keepalive_probes = val;
5233 break;
5234 case TCP_SYNCNT:
5235 if (val < 1 || val > MAX_TCP_SYNCNT)
5236 ret = -EINVAL;
5237 else
5238 icsk->icsk_syn_retries = val;
5239 break;
5240 case TCP_USER_TIMEOUT:
5241 if (val < 0)
5242 ret = -EINVAL;
5243 else
5244 icsk->icsk_user_timeout = val;
5245 break;
5246 case TCP_NOTSENT_LOWAT:
5247 tp->notsent_lowat = val;
5248 sk->sk_write_space(sk);
5249 break;
5250 case TCP_WINDOW_CLAMP:
5251 ret = tcp_set_window_clamp(sk, val);
5252 break;
5253 default:
5254 ret = -EINVAL;
5255 }
5256 }5159 }
5257#endif5160
5258 } else {5161 return do_tcp_getsockopt(sk, SOL_TCP, optname,
5259 ret = -EINVAL;5162 KERNEL_SOCKPTR(optval),
5163 KERNEL_SOCKPTR(optlen));
5260 }5164 }
5261 return ret;5165
5166 return do_tcp_setsockopt(sk, SOL_TCP, optname,
5167 KERNEL_SOCKPTR(optval), *optlen);
5262}5168}
5263 5169
5264static int _bpf_setsockopt(struct sock *sk, int level, int optname,5170static int sol_ip_sockopt(struct sock *sk, int optname,
5265 char *optval, int optlen)5171 char *optval, int *optlen,
5172 bool getopt)
5266{5173{
5267 if (sk_fullsock(sk))5174 if (sk->sk_family != AF_INET)
5268 sock_owned_by_me(sk);5175 return -EINVAL;
5269 return __bpf_setsockopt(sk, level, optname, optval, optlen);5176
5177 switch (optname) {
5178 case IP_TOS:
5179 if (*optlen != sizeof(int))
5180 return -EINVAL;
5181 break;
5182 default:
5183 return -EINVAL;
5184 }
5185
5186 if (getopt)
5187 return do_ip_getsockopt(sk, SOL_IP, optname,
5188 KERNEL_SOCKPTR(optval),
5189 KERNEL_SOCKPTR(optlen));
5190
5191 return do_ip_setsockopt(sk, SOL_IP, optname,
5192 KERNEL_SOCKPTR(optval), *optlen);
5270}5193}
5271 5194
5272static int __bpf_getsockopt(struct sock *sk, int level, int optname,5195static int sol_ipv6_sockopt(struct sock *sk, int optname,
5273 char *optval, int optlen)5196 char *optval, int *optlen,
5197 bool getopt)
5274{5198{
5275 if (!sk_fullsock(sk))5199 if (sk->sk_family != AF_INET6)
5276 goto err_clear;5200 return -EINVAL;
5277 5201
5278 if (level == SOL_SOCKET) {5202 switch (optname) {
5279 if (optlen != sizeof(int))5203 case IPV6_TCLASS:
5280 goto err_clear;5204 case IPV6_AUTOFLOWLABEL:
5205 if (*optlen != sizeof(int))
5206 return -EINVAL;
5207 break;
5208 default:
5209 return -EINVAL;
5210 }
5281 5211
5282 switch (optname) {5212 if (getopt)
5283 case SO_RCVBUF:5213 return ipv6_bpf_stub->ipv6_getsockopt(sk, SOL_IPV6, optname,
5284 *((int *)optval) = sk->sk_rcvbuf;5214 KERNEL_SOCKPTR(optval),
5285 break;5215 KERNEL_SOCKPTR(optlen));
5286 case SO_SNDBUF:
5287 *((int *)optval) = sk->sk_sndbuf;
5288 break;
5289 case SO_MARK:
5290 *((int *)optval) = sk->sk_mark;
5291 break;
5292 case SO_PRIORITY:
5293 *((int *)optval) = sk->sk_priority;
5294 break;
5295 case SO_BINDTOIFINDEX:
5296 *((int *)optval) = sk->sk_bound_dev_if;
5297 break;
5298 case SO_REUSEPORT:
5299 *((int *)optval) = sk->sk_reuseport;
5300 break;
5301 case SO_TXREHASH:
5302 *((int *)optval) = sk->sk_txrehash;
5303 break;
5304 default:
5305 goto err_clear;
5306 }
5307#ifdef CONFIG_INET
5308 } else if (level == SOL_TCP && sk->sk_prot->getsockopt == tcp_getsockopt) {
5309 struct inet_connection_sock *icsk;
5310 struct tcp_sock *tp;
5311 5216
5312 switch (optname) {5217 return ipv6_bpf_stub->ipv6_setsockopt(sk, SOL_IPV6, optname,
5313 case TCP_CONGESTION:5218 KERNEL_SOCKPTR(optval), *optlen);
5314 icsk = inet_csk(sk);5219}
5315 5220
5316 if (!icsk->icsk_ca_ops || optlen <= 1)5221static int __bpf_setsockopt(struct sock *sk, int level, int optname,
5317 goto err_clear;5222 char *optval, int optlen)
5318 strncpy(optval, icsk->icsk_ca_ops->name, optlen);5223{
5319 optval[optlen - 1] = 0;5224 if (!sk_fullsock(sk))
5320 break;5225 return -EINVAL;
5321 case TCP_SAVED_SYN:
5322 tp = tcp_sk(sk);
5323 5226
5324 if (optlen <= 0 || !tp->saved_syn ||5227 if (level == SOL_SOCKET)
5325 optlen > tcp_saved_syn_len(tp->saved_syn))5228 return sol_socket_sockopt(sk, optname, optval, &optlen, false);
5326 goto err_clear;5229 else if (IS_ENABLED(CONFIG_INET) && level == SOL_IP)
5327 memcpy(optval, tp->saved_syn->data, optlen);5230 return sol_ip_sockopt(sk, optname, optval, &optlen, false);
5328 break;5231 else if (IS_ENABLED(CONFIG_IPV6) && level == SOL_IPV6)
5329 default:5232 return sol_ipv6_sockopt(sk, optname, optval, &optlen, false);
5330 goto err_clear;5233 else if (IS_ENABLED(CONFIG_INET) && level == SOL_TCP)
5331 }5234 return sol_tcp_sockopt(sk, optname, optval, &optlen, false);
5332 } else if (level == SOL_IP) {
5333 struct inet_sock *inet = inet_sk(sk);
5334 5235
5335 if (optlen != sizeof(int) || sk->sk_family != AF_INET)5236 return -EINVAL;
5336 goto err_clear;5237}
5337 5238
5338 /* Only some options are supported */5239static int _bpf_setsockopt(struct sock *sk, int level, int optname,
5339 switch (optname) {5240 char *optval, int optlen)
5340 case IP_TOS:5241{
5341 *((int *)optval) = (int)inet->tos;5242 if (sk_fullsock(sk))
5342 break;5243 sock_owned_by_me(sk);
5343 default:5244 return __bpf_setsockopt(sk, level, optname, optval, optlen);
5344 goto err_clear;5245}
5345 }
5346#if IS_ENABLED(CONFIG_IPV6)
5347 } else if (level == SOL_IPV6) {
5348 struct ipv6_pinfo *np = inet6_sk(sk);
5349 5246
5350 if (optlen != sizeof(int) || sk->sk_family != AF_INET6)5247static int __bpf_getsockopt(struct sock *sk, int level, int optname,
5351 goto err_clear;5248 char *optval, int optlen)
5249{
5250 int err, saved_optlen = optlen;
5352 5251
5353 /* Only some options are supported */5252 if (!sk_fullsock(sk)) {
5354 switch (optname) {5253 err = -EINVAL;
5355 case IPV6_TCLASS:5254 goto done;
5356 *((int *)optval) = (int)np->tclass;
5357 break;
5358 default:
5359 goto err_clear;
5360 }
5361#endif
5362#endif
5363 } else {
5364 goto err_clear;
5365 }5255 }
5366 return 0;5256
5367err_clear:5257 if (level == SOL_SOCKET)
5368 memset(optval, 0, optlen);5258 err = sol_socket_sockopt(sk, optname, optval, &optlen, true);
5369 return -EINVAL;5259 else if (IS_ENABLED(CONFIG_INET) && level == SOL_TCP)
5260 err = sol_tcp_sockopt(sk, optname, optval, &optlen, true);
5261 else if (IS_ENABLED(CONFIG_INET) && level == SOL_IP)
5262 err = sol_ip_sockopt(sk, optname, optval, &optlen, true);
5263 else if (IS_ENABLED(CONFIG_IPV6) && level == SOL_IPV6)
5264 err = sol_ipv6_sockopt(sk, optname, optval, &optlen, true);
5265 else
5266 err = -EINVAL;
5267
5268done:
5269 if (err)
5270 optlen = 0;
5271 if (optlen < saved_optlen)
5272 memset(optval + optlen, 0, saved_optlen - optlen);
5273 return err;
5370}5274}
5371 5275
5372static int _bpf_getsockopt(struct sock *sk, int level, int optname,5276static int _bpf_getsockopt(struct sock *sk, int level, int optname,
@@ -7667,34 +7571,23 @@ const struct bpf_func_proto bpf_sk_storage_get_cg_sock_proto __weak; · 2294 unmodified lines
7667static const struct bpf_func_proto *7571static const struct bpf_func_proto *
7668sock_filter_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)7572sock_filter_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
7669{7573{
7574 const struct bpf_func_proto *func_proto;
7575
7576 func_proto = cgroup_common_func_proto(func_id, prog);
7577 if (func_proto)
7578 return func_proto;
7579
7580 func_proto = cgroup_current_func_proto(func_id, prog);
7581 if (func_proto)
7582 return func_proto;
7583
7670 switch (func_id) {7584 switch (func_id) {
7671 /* inet and inet6 sockets are created in a process
7672 * context so there is always a valid uid/gid
7673 */
7674 case BPF_FUNC_get_current_uid_gid:
7675 return &bpf_get_current_uid_gid_proto;
7676 case BPF_FUNC_get_local_storage:
7677 return &bpf_get_local_storage_proto;
7678 case BPF_FUNC_get_socket_cookie:7585 case BPF_FUNC_get_socket_cookie:
7679 return &bpf_get_socket_cookie_sock_proto;7586 return &bpf_get_socket_cookie_sock_proto;
7680 case BPF_FUNC_get_netns_cookie:7587 case BPF_FUNC_get_netns_cookie:
7681 return &bpf_get_netns_cookie_sock_proto;7588 return &bpf_get_netns_cookie_sock_proto;
7682 case BPF_FUNC_perf_event_output:7589 case BPF_FUNC_perf_event_output:
7683 return &bpf_event_output_data_proto;7590 return &bpf_event_output_data_proto;
7684 case BPF_FUNC_get_current_pid_tgid:
7685 return &bpf_get_current_pid_tgid_proto;
7686 case BPF_FUNC_get_current_comm:
7687 return &bpf_get_current_comm_proto;
7688#ifdef CONFIG_CGROUPS
7689 case BPF_FUNC_get_current_cgroup_id:
7690 return &bpf_get_current_cgroup_id_proto;
7691 case BPF_FUNC_get_current_ancestor_cgroup_id:
7692 return &bpf_get_current_ancestor_cgroup_id_proto;
7693#endif
7694#ifdef CONFIG_CGROUP_NET_CLASSID
7695 case BPF_FUNC_get_cgroup_classid:
7696 return &bpf_get_cgroup_classid_curr_proto;
7697#endif
7698 case BPF_FUNC_sk_storage_get:7591 case BPF_FUNC_sk_storage_get:
7699 return &bpf_sk_storage_get_cg_sock_proto;7592 return &bpf_sk_storage_get_cg_sock_proto;
7700 case BPF_FUNC_ktime_get_coarse_ns:7593 case BPF_FUNC_ktime_get_coarse_ns:
@@ -7707,12 +7600,17 @@ sock_filter_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) · 6 unmodified lines
7707static const struct bpf_func_proto *7600static const struct bpf_func_proto *
7708sock_addr_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)7601sock_addr_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
7709{7602{
7603 const struct bpf_func_proto *func_proto;
7604
7605 func_proto = cgroup_common_func_proto(func_id, prog);
7606 if (func_proto)
7607 return func_proto;
7608
7609 func_proto = cgroup_current_func_proto(func_id, prog);
7610 if (func_proto)
7611 return func_proto;
7612
7710 switch (func_id) {7613 switch (func_id) {
7711 /* inet and inet6 sockets are created in a process
7712 * context so there is always a valid uid/gid
7713 */
7714 case BPF_FUNC_get_current_uid_gid:
7715 return &bpf_get_current_uid_gid_proto;
7716 case BPF_FUNC_bind:7614 case BPF_FUNC_bind:
7717 switch (prog->expected_attach_type) {7615 switch (prog->expected_attach_type) {
7718 case BPF_CGROUP_INET4_CONNECT:7616 case BPF_CGROUP_INET4_CONNECT:
@@ -7725,24 +7623,8 @@ sock_addr_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) · 6 unmodified lines
7725 return &bpf_get_socket_cookie_sock_addr_proto;7623 return &bpf_get_socket_cookie_sock_addr_proto;
7726 case BPF_FUNC_get_netns_cookie:7624 case BPF_FUNC_get_netns_cookie:
7727 return &bpf_get_netns_cookie_sock_addr_proto;7625 return &bpf_get_netns_cookie_sock_addr_proto;
7728 case BPF_FUNC_get_local_storage:
7729 return &bpf_get_local_storage_proto;
7730 case BPF_FUNC_perf_event_output:7626 case BPF_FUNC_perf_event_output:
7731 return &bpf_event_output_data_proto;7627 return &bpf_event_output_data_proto;
7732 case BPF_FUNC_get_current_pid_tgid:
7733 return &bpf_get_current_pid_tgid_proto;
7734 case BPF_FUNC_get_current_comm:
7735 return &bpf_get_current_comm_proto;
7736#ifdef CONFIG_CGROUPS
7737 case BPF_FUNC_get_current_cgroup_id:
7738 return &bpf_get_current_cgroup_id_proto;
7739 case BPF_FUNC_get_current_ancestor_cgroup_id:
7740 return &bpf_get_current_ancestor_cgroup_id_proto;
7741#endif
7742#ifdef CONFIG_CGROUP_NET_CLASSID
7743 case BPF_FUNC_get_cgroup_classid:
7744 return &bpf_get_cgroup_classid_curr_proto;
7745#endif
7746#ifdef CONFIG_INET7628#ifdef CONFIG_INET
7747 case BPF_FUNC_sk_lookup_tcp:7629 case BPF_FUNC_sk_lookup_tcp:
7748 return &bpf_sock_addr_sk_lookup_tcp_proto;7630 return &bpf_sock_addr_sk_lookup_tcp_proto;
@@ -7823,9 +7705,13 @@ const struct bpf_func_proto bpf_sk_storage_delete_proto __weak; · 74 unmodified lines
7823static const struct bpf_func_proto *7705static const struct bpf_func_proto *
7824cg_skb_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)7706cg_skb_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
7825{7707{
7708 const struct bpf_func_proto *func_proto;
7709
7710 func_proto = cgroup_common_func_proto(func_id, prog);
7711 if (func_proto)
7712 return func_proto;
7713
7826 switch (func_id) {7714 switch (func_id) {
7827 case BPF_FUNC_get_local_storage:
7828 return &bpf_get_local_storage_proto;
7829 case BPF_FUNC_sk_fullsock:7715 case BPF_FUNC_sk_fullsock:
7830 return &bpf_sk_fullsock_proto;7716 return &bpf_sk_fullsock_proto;
7831 case BPF_FUNC_sk_storage_get:7717 case BPF_FUNC_sk_storage_get:
@@ -8065,6 +7951,12 @@ const struct bpf_func_proto bpf_sock_hash_update_proto __weak; · 233 unmodified lines
8065static const struct bpf_func_proto *7951static const struct bpf_func_proto *
8066sock_ops_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)7952sock_ops_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
8067{7953{
7954 const struct bpf_func_proto *func_proto;
7955
7956 func_proto = cgroup_common_func_proto(func_id, prog);
7957 if (func_proto)
7958 return func_proto;
7959
8068 switch (func_id) {7960 switch (func_id) {
8069 case BPF_FUNC_setsockopt:7961 case BPF_FUNC_setsockopt:
8070 return &bpf_sock_ops_setsockopt_proto;7962 return &bpf_sock_ops_setsockopt_proto;
@@ -8078,8 +7970,6 @@ sock_ops_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) · 7 unmodified lines
8078 return &bpf_sock_hash_update_proto;7970 return &bpf_sock_hash_update_proto;
8079 case BPF_FUNC_get_socket_cookie:7971 case BPF_FUNC_get_socket_cookie:
8080 return &bpf_get_socket_cookie_sock_ops_proto;7972 return &bpf_get_socket_cookie_sock_ops_proto;
8081 case BPF_FUNC_get_local_storage:
8082 return &bpf_get_local_storage_proto;
8083 case BPF_FUNC_perf_event_output:7973 case BPF_FUNC_perf_event_output:
8084 return &bpf_event_output_data_proto;7974 return &bpf_event_output_data_proto;
8085 case BPF_FUNC_sk_storage_get:7975 case BPF_FUNC_sk_storage_get:
@@ -10812,14 +10702,13 @@ int sk_detach_filter(struct sock *sk) · 2726 unmodified lines
10812}10702}
10813EXPORT_SYMBOL_GPL(sk_detach_filter);10703EXPORT_SYMBOL_GPL(sk_detach_filter);
10814 10704
10815int sk_get_filter(struct sock *sk, struct sock_filter __user *ubuf,10705int sk_get_filter(struct sock *sk, sockptr_t optval, unsigned int len)
10816 unsigned int len)
10817{10706{
10818 struct sock_fprog_kern *fprog;10707 struct sock_fprog_kern *fprog;
10819 struct sk_filter *filter;10708 struct sk_filter *filter;
10820 int ret = 0;10709 int ret = 0;
10821 10710
10822 lock_sock(sk);10711 sockopt_lock_sock(sk);
10823 filter = rcu_dereference_protected(sk->sk_filter,10712 filter = rcu_dereference_protected(sk->sk_filter,
10824 lockdep_sock_is_held(sk));10713 lockdep_sock_is_held(sk));
10825 if (!filter)10714 if (!filter)
@@ -10844,7 +10733,7 @@ int sk_get_filter(struct sock *sk, struct sock_filter __user *ubuf, · 18 unmodified lines
10844 goto out;10733 goto out;
10845 10734
10846 ret = -EFAULT;10735 ret = -EFAULT;
10847 if (copy_to_user(ubuf, fprog->filter, bpf_classic_proglen(fprog)))10736 if (copy_to_sockptr(optval, fprog->filter, bpf_classic_proglen(fprog)))
10848 goto out;10737 goto out;
10849 10738
10850 /* Instead of bytes, the API requests to return the number10739 /* Instead of bytes, the API requests to return the number
@@ -10852,7 +10741,7 @@ int sk_get_filter(struct sock *sk, struct sock_filter __user *ubuf, · 1 unmodified line
10852 */10741 */
10853 ret = fprog->len;10742 ret = fprog->len;
10854out:10743out:
10855 release_sock(sk);10744 sockopt_release_sock(sk);
10856 return ret;10745 return ret;
10857}10746}
10858 10747
net/core/flow_dissector.c+10−6
@@ -866,8 +866,8 @@ static void __skb_flow_bpf_to_target(const struct bpf_flow_keys *flow_keys, · 865 unmodified lines
866 }866 }
867}867}
868 868
869bool bpf_flow_dissect(struct bpf_prog *prog, struct bpf_flow_dissector *ctx,869u32 bpf_flow_dissect(struct bpf_prog *prog, struct bpf_flow_dissector *ctx,
870 __be16 proto, int nhoff, int hlen, unsigned int flags)870 __be16 proto, int nhoff, int hlen, unsigned int flags)
871{871{
872 struct bpf_flow_keys *flow_keys = ctx->flow_keys;872 struct bpf_flow_keys *flow_keys = ctx->flow_keys;
873 u32 result;873 u32 result;
@@ -892,7 +892,7 @@ bool bpf_flow_dissect(struct bpf_prog *prog, struct bpf_flow_dissector *ctx, · 18 unmodified lines
892 flow_keys->thoff = clamp_t(u16, flow_keys->thoff,892 flow_keys->thoff = clamp_t(u16, flow_keys->thoff,
893 flow_keys->nhoff, hlen);893 flow_keys->nhoff, hlen);
894 894
895 return result == BPF_OK;895 return result;
896}896}
897 897
898static bool is_pppoe_ses_hdr_valid(const struct pppoe_hdr *hdr)898static bool is_pppoe_ses_hdr_valid(const struct pppoe_hdr *hdr)
@@ -1008,6 +1008,7 @@ bool __skb_flow_dissect(const struct net *net, · 109 unmodified lines
1008 };1008 };
1009 __be16 n_proto = proto;1009 __be16 n_proto = proto;
1010 struct bpf_prog *prog;1010 struct bpf_prog *prog;
1011 u32 result;
1011 1012
1012 if (skb) {1013 if (skb) {
1013 ctx.skb = skb;1014 ctx.skb = skb;
@@ -1019,13 +1020,16 @@ bool __skb_flow_dissect(const struct net *net, · 5 unmodified lines
1019 }1020 }
1020 1021
1021 prog = READ_ONCE(run_array->items[0].prog);1022 prog = READ_ONCE(run_array->items[0].prog);
1022 ret = bpf_flow_dissect(prog, &ctx, n_proto, nhoff,1023 result = bpf_flow_dissect(prog, &ctx, n_proto, nhoff,
1023 hlen, flags);1024 hlen, flags);
1025 if (result == BPF_FLOW_DISSECTOR_CONTINUE)
1026 goto dissect_continue;
1024 __skb_flow_bpf_to_target(&flow_keys, flow_dissector,1027 __skb_flow_bpf_to_target(&flow_keys, flow_dissector,
1025 target_container);1028 target_container);
1026 rcu_read_unlock();1029 rcu_read_unlock();
1027 return ret;1030 return result == BPF_OK;
1028 }1031 }
1032dissect_continue:
1029 rcu_read_unlock();1033 rcu_read_unlock();
1030 }1034 }
1031 1035
net/core/sock.c+94−40
@@ -703,15 +703,17 @@ static int sock_setbindtodevice(struct sock *sk, sockptr_t optval, int optlen) · 702 unmodified lines
703 goto out;703 goto out;
704 }704 }
705 705
706 return sock_bindtoindex(sk, index, true);706 sockopt_lock_sock(sk);
707 ret = sock_bindtoindex_locked(sk, index);
708 sockopt_release_sock(sk);
707out:709out:
708#endif710#endif
709 711
710 return ret;712 return ret;
711}713}
712 714
713static int sock_getbindtodevice(struct sock *sk, char __user *optval,715static int sock_getbindtodevice(struct sock *sk, sockptr_t optval,
714 int __user *optlen, int len)716 sockptr_t optlen, int len)
715{717{
716 int ret = -ENOPROTOOPT;718 int ret = -ENOPROTOOPT;
717#ifdef CONFIG_NETDEVICES719#ifdef CONFIG_NETDEVICES
@@ -735,12 +737,12 @@ static int sock_getbindtodevice(struct sock *sk, char __user *optval, · 17 unmodified lines
735 len = strlen(devname) + 1;737 len = strlen(devname) + 1;
736 738
737 ret = -EFAULT;739 ret = -EFAULT;
738 if (copy_to_user(optval, devname, len))740 if (copy_to_sockptr(optval, devname, len))
739 goto out;741 goto out;
740 742
741zero:743zero:
742 ret = -EFAULT;744 ret = -EFAULT;
743 if (put_user(len, optlen))745 if (copy_to_sockptr(optlen, &len, sizeof(int)))
744 goto out;746 goto out;
745 747
746 ret = 0;748 ret = 0;
@@ -1036,17 +1038,51 @@ static int sock_reserve_memory(struct sock *sk, int bytes) · 289 unmodified lines
1036 return 0;1038 return 0;
1037}1039}
1038 1040
1041void sockopt_lock_sock(struct sock *sk)
1042{
1043 /* When current->bpf_ctx is set, the setsockopt is called from
1044 * a bpf prog. bpf has ensured the sk lock has been
1045 * acquired before calling setsockopt().
1046 */
1047 if (has_current_bpf_ctx())
1048 return;
1049
1050 lock_sock(sk);
1051}
1052EXPORT_SYMBOL(sockopt_lock_sock);
1053
1054void sockopt_release_sock(struct sock *sk)
1055{
1056 if (has_current_bpf_ctx())
1057 return;
1058
1059 release_sock(sk);
1060}
1061EXPORT_SYMBOL(sockopt_release_sock);
1062
1063bool sockopt_ns_capable(struct user_namespace *ns, int cap)
1064{
1065 return has_current_bpf_ctx() || ns_capable(ns, cap);
1066}
1067EXPORT_SYMBOL(sockopt_ns_capable);
1068
1069bool sockopt_capable(int cap)
1070{
1071 return has_current_bpf_ctx() || capable(cap);
1072}
1073EXPORT_SYMBOL(sockopt_capable);
1074
1039/*1075/*
1040 * This is meant for all protocols to use and covers goings on1076 * This is meant for all protocols to use and covers goings on
1041 * at the socket level. Everything here is generic.1077 * at the socket level. Everything here is generic.
1042 */1078 */
1043 1079
1044int sock_setsockopt(struct socket *sock, int level, int optname,1080int sk_setsockopt(struct sock *sk, int level, int optname,
1045 sockptr_t optval, unsigned int optlen)1081 sockptr_t optval, unsigned int optlen)
1046{1082{
1047 struct so_timestamping timestamping;1083 struct so_timestamping timestamping;
1084 struct socket *sock = sk->sk_socket;
1048 struct sock_txtime sk_txtime;1085 struct sock_txtime sk_txtime;
1049 struct sock *sk = sock->sk;
1050 int val;1086 int val;
1051 int valbool;1087 int valbool;
1052 struct linger ling;1088 struct linger ling;
@@ -1067,11 +1103,11 @@ int sock_setsockopt(struct socket *sock, int level, int optname, · 14 unmodified lines
1067 1103
1068 valbool = val ? 1 : 0;1104 valbool = val ? 1 : 0;
1069 1105
1070 lock_sock(sk);1106 sockopt_lock_sock(sk);
1071 1107
1072 switch (optname) {1108 switch (optname) {
1073 case SO_DEBUG:1109 case SO_DEBUG:
1074 if (val && !capable(CAP_NET_ADMIN))1110 if (val && !sockopt_capable(CAP_NET_ADMIN))
1075 ret = -EACCES;1111 ret = -EACCES;
1076 else1112 else
1077 sock_valbool_flag(sk, SOCK_DBG, valbool);1113 sock_valbool_flag(sk, SOCK_DBG, valbool);
@@ -1115,7 +1151,7 @@ set_sndbuf: · 37 unmodified lines
1115 break;1151 break;
1116 1152
1117 case SO_SNDBUFFORCE:1153 case SO_SNDBUFFORCE:
1118 if (!capable(CAP_NET_ADMIN)) {1154 if (!sockopt_capable(CAP_NET_ADMIN)) {
1119 ret = -EPERM;1155 ret = -EPERM;
1120 break;1156 break;
1121 }1157 }
@@ -1137,7 +1173,7 @@ set_sndbuf: · 15 unmodified lines
1137 break;1173 break;
1138 1174
1139 case SO_RCVBUFFORCE:1175 case SO_RCVBUFFORCE:
1140 if (!capable(CAP_NET_ADMIN)) {1176 if (!sockopt_capable(CAP_NET_ADMIN)) {
1141 ret = -EPERM;1177 ret = -EPERM;
1142 break;1178 break;
1143 }1179 }
@@ -1164,8 +1200,8 @@ set_sndbuf: · 20 unmodified lines
1164 1200
1165 case SO_PRIORITY:1201 case SO_PRIORITY:
1166 if ((val >= 0 && val <= 6) ||1202 if ((val >= 0 && val <= 6) ||
1167 ns_capable(sock_net(sk)->user_ns, CAP_NET_RAW) ||1203 sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_RAW) ||
1168 ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))1204 sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
1169 sk->sk_priority = val;1205 sk->sk_priority = val;
1170 else1206 else
1171 ret = -EPERM;1207 ret = -EPERM;
@@ -1228,7 +1264,7 @@ set_sndbuf: · 56 unmodified lines
1228 case SO_RCVLOWAT:1264 case SO_RCVLOWAT:
1229 if (val < 0)1265 if (val < 0)
1230 val = INT_MAX;1266 val = INT_MAX;
1231 if (sock->ops->set_rcvlowat)1267 if (sock && sock->ops->set_rcvlowat)
1232 ret = sock->ops->set_rcvlowat(sk, val);1268 ret = sock->ops->set_rcvlowat(sk, val);
1233 else1269 else
1234 WRITE_ONCE(sk->sk_rcvlowat, val ? : 1);1270 WRITE_ONCE(sk->sk_rcvlowat, val ? : 1);
@@ -1310,8 +1346,8 @@ set_sndbuf: · 75 unmodified lines
1310 clear_bit(SOCK_PASSSEC, &sock->flags);1346 clear_bit(SOCK_PASSSEC, &sock->flags);
1311 break;1347 break;
1312 case SO_MARK:1348 case SO_MARK:
1313 if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_RAW) &&1349 if (!sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_RAW) &&
1314 !ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) {1350 !sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) {
1315 ret = -EPERM;1351 ret = -EPERM;
1316 break;1352 break;
1317 }1353 }
@@ -1319,8 +1355,8 @@ set_sndbuf: · 1 unmodified line
1319 __sock_set_mark(sk, val);1355 __sock_set_mark(sk, val);
1320 break;1356 break;
1321 case SO_RCVMARK:1357 case SO_RCVMARK:
1322 if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_RAW) &&1358 if (!sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_RAW) &&
1323 !ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) {1359 !sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) {
1324 ret = -EPERM;1360 ret = -EPERM;
1325 break;1361 break;
1326 }1362 }
@@ -1354,7 +1390,7 @@ set_sndbuf: · 27 unmodified lines
1354#ifdef CONFIG_NET_RX_BUSY_POLL1390#ifdef CONFIG_NET_RX_BUSY_POLL
1355 case SO_BUSY_POLL:1391 case SO_BUSY_POLL:
1356 /* allow unprivileged users to decrease the value */1392 /* allow unprivileged users to decrease the value */
1357 if ((val > sk->sk_ll_usec) && !capable(CAP_NET_ADMIN))1393 if ((val > sk->sk_ll_usec) && !sockopt_capable(CAP_NET_ADMIN))
1358 ret = -EPERM;1394 ret = -EPERM;
1359 else {1395 else {
1360 if (val < 0)1396 if (val < 0)
@@ -1364,13 +1400,13 @@ set_sndbuf: · 3 unmodified lines
1364 }1400 }
1365 break;1401 break;
1366 case SO_PREFER_BUSY_POLL:1402 case SO_PREFER_BUSY_POLL:
1367 if (valbool && !capable(CAP_NET_ADMIN))1403 if (valbool && !sockopt_capable(CAP_NET_ADMIN))
1368 ret = -EPERM;1404 ret = -EPERM;
1369 else1405 else
1370 WRITE_ONCE(sk->sk_prefer_busy_poll, valbool);1406 WRITE_ONCE(sk->sk_prefer_busy_poll, valbool);
1371 break;1407 break;
1372 case SO_BUSY_POLL_BUDGET:1408 case SO_BUSY_POLL_BUDGET:
1373 if (val > READ_ONCE(sk->sk_busy_poll_budget) && !capable(CAP_NET_ADMIN)) {1409 if (val > READ_ONCE(sk->sk_busy_poll_budget) && !sockopt_capable(CAP_NET_ADMIN)) {
1374 ret = -EPERM;1410 ret = -EPERM;
1375 } else {1411 } else {
1376 if (val < 0 || val > U16_MAX)1412 if (val < 0 || val > U16_MAX)
@@ -1441,7 +1477,7 @@ set_sndbuf: · 64 unmodified lines
1441 * scheduler has enough safe guards.1477 * scheduler has enough safe guards.
1442 */1478 */
1443 if (sk_txtime.clockid != CLOCK_MONOTONIC &&1479 if (sk_txtime.clockid != CLOCK_MONOTONIC &&
1444 !ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) {1480 !sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) {
1445 ret = -EPERM;1481 ret = -EPERM;
1446 break;1482 break;
1447 }1483 }
@@ -1496,9 +1532,16 @@ set_sndbuf: · 48 unmodified lines
1496 ret = -ENOPROTOOPT;1532 ret = -ENOPROTOOPT;
1497 break;1533 break;
1498 }1534 }
1499 release_sock(sk);1535 sockopt_release_sock(sk);
1500 return ret;1536 return ret;
1501}1537}
1538
1539int sock_setsockopt(struct socket *sock, int level, int optname,
1540 sockptr_t optval, unsigned int optlen)
1541{
1542 return sk_setsockopt(sock->sk, level, optname,
1543 optval, optlen);
1544}
1502EXPORT_SYMBOL(sock_setsockopt);1545EXPORT_SYMBOL(sock_setsockopt);
1503 1546
1504static const struct cred *sk_get_peer_cred(struct sock *sk)1547static const struct cred *sk_get_peer_cred(struct sock *sk)
@@ -1525,22 +1568,25 @@ static void cred_to_ucred(struct pid *pid, const struct cred *cred, · 20 unmodified lines
1525 }1568 }
1526}1569}
1527 1570
1528static int groups_to_user(gid_t __user *dst, const struct group_info *src)1571static int groups_to_user(sockptr_t dst, const struct group_info *src)
1529{1572{
1530 struct user_namespace *user_ns = current_user_ns();1573 struct user_namespace *user_ns = current_user_ns();
1531 int i;1574 int i;
1532 1575
1533 for (i = 0; i < src->ngroups; i++)1576 for (i = 0; i < src->ngroups; i++) {
1534 if (put_user(from_kgid_munged(user_ns, src->gid[i]), dst + i))1577 gid_t gid = from_kgid_munged(user_ns, src->gid[i]);
1578
1579 if (copy_to_sockptr_offset(dst, i * sizeof(gid), &gid, sizeof(gid)))
1535 return -EFAULT;1580 return -EFAULT;
1581 }
1536 1582
1537 return 0;1583 return 0;
1538}1584}
1539 1585
1540int sock_getsockopt(struct socket *sock, int level, int optname,1586int sk_getsockopt(struct sock *sk, int level, int optname,
1541 char __user *optval, int __user *optlen)1587 sockptr_t optval, sockptr_t optlen)
1542{1588{
1543 struct sock *sk = sock->sk;1589 struct socket *sock = sk->sk_socket;
1544 1590
1545 union {1591 union {
1546 int val;1592 int val;
@@ -1557,7 +1603,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname, · 10 unmodified lines
1557 int lv = sizeof(int);1603 int lv = sizeof(int);
1558 int len;1604 int len;
1559 1605
1560 if (get_user(len, optlen))1606 if (copy_from_sockptr(&len, optlen, sizeof(int)))
1561 return -EFAULT;1607 return -EFAULT;
1562 if (len < 0)1608 if (len < 0)
1563 return -EINVAL;1609 return -EINVAL;
@@ -1692,7 +1738,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname, · 128 unmodified lines
1692 cred_to_ucred(sk->sk_peer_pid, sk->sk_peer_cred, &peercred);1738 cred_to_ucred(sk->sk_peer_pid, sk->sk_peer_cred, &peercred);
1693 spin_unlock(&sk->sk_peer_lock);1739 spin_unlock(&sk->sk_peer_lock);
1694 1740
1695 if (copy_to_user(optval, &peercred, len))1741 if (copy_to_sockptr(optval, &peercred, len))
1696 return -EFAULT;1742 return -EFAULT;
1697 goto lenout;1743 goto lenout;
1698 }1744 }
@@ -1710,11 +1756,11 @@ int sock_getsockopt(struct socket *sock, int level, int optname, · 11 unmodified lines
1710 if (len < n * sizeof(gid_t)) {1756 if (len < n * sizeof(gid_t)) {
1711 len = n * sizeof(gid_t);1757 len = n * sizeof(gid_t);
1712 put_cred(cred);1758 put_cred(cred);
1713 return put_user(len, optlen) ? -EFAULT : -ERANGE;1759 return copy_to_sockptr(optlen, &len, sizeof(int)) ? -EFAULT : -ERANGE;
1714 }1760 }
1715 len = n * sizeof(gid_t);1761 len = n * sizeof(gid_t);
1716 1762
1717 ret = groups_to_user((gid_t __user *)optval, cred->group_info);1763 ret = groups_to_user(optval, cred->group_info);
1718 put_cred(cred);1764 put_cred(cred);
1719 if (ret)1765 if (ret)
1720 return ret;1766 return ret;
@@ -1730,7 +1776,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname, · 9 unmodified lines
1730 return -ENOTCONN;1776 return -ENOTCONN;
1731 if (lv < len)1777 if (lv < len)
1732 return -EINVAL;1778 return -EINVAL;
1733 if (copy_to_user(optval, address, len))1779 if (copy_to_sockptr(optval, address, len))
1734 return -EFAULT;1780 return -EFAULT;
1735 goto lenout;1781 goto lenout;
1736 }1782 }
@@ -1747,7 +1793,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname, · 10 unmodified lines
1747 break;1793 break;
1748 1794
1749 case SO_PEERSEC:1795 case SO_PEERSEC:
1750 return security_socket_getpeersec_stream(sock, optval, optlen, len);1796 return security_socket_getpeersec_stream(sock, optval.user, optlen.user, len);
1751 1797
1752 case SO_MARK:1798 case SO_MARK:
1753 v.val = sk->sk_mark;1799 v.val = sk->sk_mark;
@@ -1779,7 +1825,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname, · 25 unmodified lines
1779 return sock_getbindtodevice(sk, optval, optlen, len);1825 return sock_getbindtodevice(sk, optval, optlen, len);
1780 1826
1781 case SO_GET_FILTER:1827 case SO_GET_FILTER:
1782 len = sk_get_filter(sk, (struct sock_filter __user *)optval, len);1828 len = sk_get_filter(sk, optval, len);
1783 if (len < 0)1829 if (len < 0)
1784 return len;1830 return len;
1785 1831
@@ -1827,7 +1873,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname, · 41 unmodified lines
1827 sk_get_meminfo(sk, meminfo);1873 sk_get_meminfo(sk, meminfo);
1828 1874
1829 len = min_t(unsigned int, len, sizeof(meminfo));1875 len = min_t(unsigned int, len, sizeof(meminfo));
1830 if (copy_to_user(optval, &meminfo, len))1876 if (copy_to_sockptr(optval, &meminfo, len))
1831 return -EFAULT;1877 return -EFAULT;
1832 1878
1833 goto lenout;1879 goto lenout;
@@ -1896,14 +1942,22 @@ int sock_getsockopt(struct socket *sock, int level, int optname, · 62 unmodified lines
1896 1942
1897 if (len > lv)1943 if (len > lv)
1898 len = lv;1944 len = lv;
1899 if (copy_to_user(optval, &v, len))1945 if (copy_to_sockptr(optval, &v, len))
1900 return -EFAULT;1946 return -EFAULT;
1901lenout:1947lenout:
1902 if (put_user(len, optlen))1948 if (copy_to_sockptr(optlen, &len, sizeof(int)))
1903 return -EFAULT;1949 return -EFAULT;
1904 return 0;1950 return 0;
1905}1951}
1906 1952
1953int sock_getsockopt(struct socket *sock, int level, int optname,
1954 char __user *optval, int __user *optlen)
1955{
1956 return sk_getsockopt(sock->sk, level, optname,
1957 USER_SOCKPTR(optval),
1958 USER_SOCKPTR(optlen));
1959}
1960
1907/*1961/*
1908 * Initialize an sk_lock.1962 * Initialize an sk_lock.
1909 *1963 *
net/ipv4/igmp.c+13−9
@@ -2529,11 +2529,10 @@ done: · 2528 unmodified lines
2529 err = ip_mc_leave_group(sk, &imr);2529 err = ip_mc_leave_group(sk, &imr);
2530 return err;2530 return err;
2531}2531}
2532
2533int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,2532int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,
2534 struct ip_msfilter __user *optval, int __user *optlen)2533 sockptr_t optval, sockptr_t optlen)
2535{2534{
2536 int err, len, count, copycount;2535 int err, len, count, copycount, msf_size;
2537 struct ip_mreqn imr;2536 struct ip_mreqn imr;
2538 __be32 addr = msf->imsf_multiaddr;2537 __be32 addr = msf->imsf_multiaddr;
2539 struct ip_mc_socklist *pmc;2538 struct ip_mc_socklist *pmc;
@@ -2575,12 +2574,15 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf, · 35 unmodified lines
2575 copycount = count < msf->imsf_numsrc ? count : msf->imsf_numsrc;2574 copycount = count < msf->imsf_numsrc ? count : msf->imsf_numsrc;
2576 len = flex_array_size(psl, sl_addr, copycount);2575 len = flex_array_size(psl, sl_addr, copycount);
2577 msf->imsf_numsrc = count;2576 msf->imsf_numsrc = count;
2578 if (put_user(IP_MSFILTER_SIZE(copycount), optlen) ||2577 msf_size = IP_MSFILTER_SIZE(copycount);
2579 copy_to_user(optval, msf, IP_MSFILTER_SIZE(0))) {2578 if (copy_to_sockptr(optlen, &msf_size, sizeof(int)) ||
2579 copy_to_sockptr(optval, msf, IP_MSFILTER_SIZE(0))) {
2580 return -EFAULT;2580 return -EFAULT;
2581 }2581 }
2582 if (len &&2582 if (len &&
2583 copy_to_user(&optval->imsf_slist_flex[0], psl->sl_addr, len))2583 copy_to_sockptr_offset(optval,
2584 offsetof(struct ip_msfilter, imsf_slist_flex),
2585 psl->sl_addr, len))
2584 return -EFAULT;2586 return -EFAULT;
2585 return 0;2587 return 0;
2586done:2588done:
@@ -2588,7 +2590,7 @@ done: · 1 unmodified line
2588}2590}
2589 2591
2590int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,2592int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
2591 struct sockaddr_storage __user *p)2593 sockptr_t optval, size_t ss_offset)
2592{2594{
2593 int i, count, copycount;2595 int i, count, copycount;
2594 struct sockaddr_in *psin;2596 struct sockaddr_in *psin;
@@ -2618,15 +2620,17 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf, · 23 unmodified lines
2618 count = psl ? psl->sl_count : 0;2620 count = psl ? psl->sl_count : 0;
2619 copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc;2621 copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc;
2620 gsf->gf_numsrc = count;2622 gsf->gf_numsrc = count;
2621 for (i = 0; i < copycount; i++, p++) {2623 for (i = 0; i < copycount; i++) {
2622 struct sockaddr_storage ss;2624 struct sockaddr_storage ss;
2623 2625
2624 psin = (struct sockaddr_in *)&ss;2626 psin = (struct sockaddr_in *)&ss;
2625 memset(&ss, 0, sizeof(ss));2627 memset(&ss, 0, sizeof(ss));
2626 psin->sin_family = AF_INET;2628 psin->sin_family = AF_INET;
2627 psin->sin_addr.s_addr = psl->sl_addr[i];2629 psin->sin_addr.s_addr = psl->sl_addr[i];
2628 if (copy_to_user(p, &ss, sizeof(ss)))2630 if (copy_to_sockptr_offset(optval, ss_offset,
2631 &ss, sizeof(ss)))
2629 return -EFAULT;2632 return -EFAULT;
2633 ss_offset += sizeof(ss);
2630 }2634 }
2631 return 0;2635 return 0;
2632}2636}
net/ipv4/ip_sockglue.c+62−52
@@ -888,8 +888,8 @@ static int compat_ip_mcast_join_leave(struct sock *sk, int optname, · 887 unmodified lines
888 888
889DEFINE_STATIC_KEY_FALSE(ip4_min_ttl);889DEFINE_STATIC_KEY_FALSE(ip4_min_ttl);
890 890
891static int do_ip_setsockopt(struct sock *sk, int level, int optname,891int do_ip_setsockopt(struct sock *sk, int level, int optname,
892 sockptr_t optval, unsigned int optlen)892 sockptr_t optval, unsigned int optlen)
893{893{
894 struct inet_sock *inet = inet_sk(sk);894 struct inet_sock *inet = inet_sk(sk);
895 struct net *net = sock_net(sk);895 struct net *net = sock_net(sk);
@@ -944,7 +944,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, int optname, · 48 unmodified lines
944 err = 0;944 err = 0;
945 if (needs_rtnl)945 if (needs_rtnl)
946 rtnl_lock();946 rtnl_lock();
947 lock_sock(sk);947 sockopt_lock_sock(sk);
948 948
949 switch (optname) {949 switch (optname) {
950 case IP_OPTIONS:950 case IP_OPTIONS:
@@ -1333,14 +1333,14 @@ static int do_ip_setsockopt(struct sock *sk, int level, int optname, · 382 unmodified lines
1333 case IP_IPSEC_POLICY:1333 case IP_IPSEC_POLICY:
1334 case IP_XFRM_POLICY:1334 case IP_XFRM_POLICY:
1335 err = -EPERM;1335 err = -EPERM;
1336 if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))1336 if (!sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
1337 break;1337 break;
1338 err = xfrm_user_policy(sk, optname, optval, optlen);1338 err = xfrm_user_policy(sk, optname, optval, optlen);
1339 break;1339 break;
1340 1340
1341 case IP_TRANSPARENT:1341 case IP_TRANSPARENT:
1342 if (!!val && !ns_capable(sock_net(sk)->user_ns, CAP_NET_RAW) &&1342 if (!!val && !sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_RAW) &&
1343 !ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) {1343 !sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) {
1344 err = -EPERM;1344 err = -EPERM;
1345 break;1345 break;
1346 }1346 }
@@ -1368,13 +1368,13 @@ static int do_ip_setsockopt(struct sock *sk, int level, int optname, · 21 unmodified lines
1368 err = -ENOPROTOOPT;1368 err = -ENOPROTOOPT;
1369 break;1369 break;
1370 }1370 }
1371 release_sock(sk);1371 sockopt_release_sock(sk);
1372 if (needs_rtnl)1372 if (needs_rtnl)
1373 rtnl_unlock();1373 rtnl_unlock();
1374 return err;1374 return err;
1375 1375
1376e_inval:1376e_inval:
1377 release_sock(sk);1377 sockopt_release_sock(sk);
1378 if (needs_rtnl)1378 if (needs_rtnl)
1379 rtnl_unlock();1379 rtnl_unlock();
1380 return -EINVAL;1380 return -EINVAL;
@@ -1462,37 +1462,37 @@ static bool getsockopt_needs_rtnl(int optname) · 81 unmodified lines
1462 return false;1462 return false;
1463}1463}
1464 1464
1465static int ip_get_mcast_msfilter(struct sock *sk, void __user *optval,1465static int ip_get_mcast_msfilter(struct sock *sk, sockptr_t optval,
1466 int __user *optlen, int len)1466 sockptr_t optlen, int len)
1467{1467{
1468 const int size0 = offsetof(struct group_filter, gf_slist_flex);1468 const int size0 = offsetof(struct group_filter, gf_slist_flex);
1469 struct group_filter __user *p = optval;
1470 struct group_filter gsf;1469 struct group_filter gsf;
1471 int num;1470 int num, gsf_size;
1472 int err;1471 int err;
1473 1472
1474 if (len < size0)1473 if (len < size0)
1475 return -EINVAL;1474 return -EINVAL;
1476 if (copy_from_user(&gsf, p, size0))1475 if (copy_from_sockptr(&gsf, optval, size0))
1477 return -EFAULT;1476 return -EFAULT;
1478 1477
1479 num = gsf.gf_numsrc;1478 num = gsf.gf_numsrc;
1480 err = ip_mc_gsfget(sk, &gsf, p->gf_slist_flex);1479 err = ip_mc_gsfget(sk, &gsf, optval,
1480 offsetof(struct group_filter, gf_slist_flex));
1481 if (err)1481 if (err)
1482 return err;1482 return err;
1483 if (gsf.gf_numsrc < num)1483 if (gsf.gf_numsrc < num)
1484 num = gsf.gf_numsrc;1484 num = gsf.gf_numsrc;
1485 if (put_user(GROUP_FILTER_SIZE(num), optlen) ||1485 gsf_size = GROUP_FILTER_SIZE(num);
1486 copy_to_user(p, &gsf, size0))1486 if (copy_to_sockptr(optlen, &gsf_size, sizeof(int)) ||
1487 copy_to_sockptr(optval, &gsf, size0))
1487 return -EFAULT;1488 return -EFAULT;
1488 return 0;1489 return 0;
1489}1490}
1490 1491
1491static int compat_ip_get_mcast_msfilter(struct sock *sk, void __user *optval,1492static int compat_ip_get_mcast_msfilter(struct sock *sk, sockptr_t optval,
1492 int __user *optlen, int len)1493 sockptr_t optlen, int len)
1493{1494{
1494 const int size0 = offsetof(struct compat_group_filter, gf_slist_flex);1495 const int size0 = offsetof(struct compat_group_filter, gf_slist_flex);
1495 struct compat_group_filter __user *p = optval;
1496 struct compat_group_filter gf32;1496 struct compat_group_filter gf32;
1497 struct group_filter gf;1497 struct group_filter gf;
1498 int num;1498 int num;
@@ -1500,7 +1500,7 @@ static int compat_ip_get_mcast_msfilter(struct sock *sk, void __user *optval, · 1 unmodified line
1500 1500
1501 if (len < size0)1501 if (len < size0)
1502 return -EINVAL;1502 return -EINVAL;
1503 if (copy_from_user(&gf32, p, size0))1503 if (copy_from_sockptr(&gf32, optval, size0))
1504 return -EFAULT;1504 return -EFAULT;
1505 1505
1506 gf.gf_interface = gf32.gf_interface;1506 gf.gf_interface = gf32.gf_interface;
@@ -1508,21 +1508,24 @@ static int compat_ip_get_mcast_msfilter(struct sock *sk, void __user *optval, · 1 unmodified line
1508 num = gf.gf_numsrc = gf32.gf_numsrc;1508 num = gf.gf_numsrc = gf32.gf_numsrc;
1509 gf.gf_group = gf32.gf_group;1509 gf.gf_group = gf32.gf_group;
1510 1510
1511 err = ip_mc_gsfget(sk, &gf, p->gf_slist_flex);1511 err = ip_mc_gsfget(sk, &gf, optval,
1512 offsetof(struct compat_group_filter, gf_slist_flex));
1512 if (err)1513 if (err)
1513 return err;1514 return err;
1514 if (gf.gf_numsrc < num)1515 if (gf.gf_numsrc < num)
1515 num = gf.gf_numsrc;1516 num = gf.gf_numsrc;
1516 len = GROUP_FILTER_SIZE(num) - (sizeof(gf) - sizeof(gf32));1517 len = GROUP_FILTER_SIZE(num) - (sizeof(gf) - sizeof(gf32));
1517 if (put_user(len, optlen) ||1518 if (copy_to_sockptr(optlen, &len, sizeof(int)) ||
1518 put_user(gf.gf_fmode, &p->gf_fmode) ||1519 copy_to_sockptr_offset(optval, offsetof(struct compat_group_filter, gf_fmode),
1519 put_user(gf.gf_numsrc, &p->gf_numsrc))1520 &gf.gf_fmode, sizeof(gf.gf_fmode)) ||
1521 copy_to_sockptr_offset(optval, offsetof(struct compat_group_filter, gf_numsrc),
1522 &gf.gf_numsrc, sizeof(gf.gf_numsrc)))
1520 return -EFAULT;1523 return -EFAULT;
1521 return 0;1524 return 0;
1522}1525}
1523 1526
1524static int do_ip_getsockopt(struct sock *sk, int level, int optname,1527int do_ip_getsockopt(struct sock *sk, int level, int optname,
1525 char __user *optval, int __user *optlen)1528 sockptr_t optval, sockptr_t optlen)
1526{1529{
1527 struct inet_sock *inet = inet_sk(sk);1530 struct inet_sock *inet = inet_sk(sk);
1528 bool needs_rtnl = getsockopt_needs_rtnl(optname);1531 bool needs_rtnl = getsockopt_needs_rtnl(optname);
@@ -1535,14 +1538,14 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, · 6 unmodified lines
1535 if (ip_mroute_opt(optname))1538 if (ip_mroute_opt(optname))
1536 return ip_mroute_getsockopt(sk, optname, optval, optlen);1539 return ip_mroute_getsockopt(sk, optname, optval, optlen);
1537 1540
1538 if (get_user(len, optlen))1541 if (copy_from_sockptr(&len, optlen, sizeof(int)))
1539 return -EFAULT;1542 return -EFAULT;
1540 if (len < 0)1543 if (len < 0)
1541 return -EINVAL;1544 return -EINVAL;
1542 1545
1543 if (needs_rtnl)1546 if (needs_rtnl)
1544 rtnl_lock();1547 rtnl_lock();
1545 lock_sock(sk);1548 sockopt_lock_sock(sk);
1546 1549
1547 switch (optname) {1550 switch (optname) {
1548 case IP_OPTIONS:1551 case IP_OPTIONS:
@@ -1558,17 +1561,19 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, · 9 unmodified lines
1558 memcpy(optbuf, &inet_opt->opt,1561 memcpy(optbuf, &inet_opt->opt,
1559 sizeof(struct ip_options) +1562 sizeof(struct ip_options) +
1560 inet_opt->opt.optlen);1563 inet_opt->opt.optlen);
1561 release_sock(sk);1564 sockopt_release_sock(sk);
1562 1565
1563 if (opt->optlen == 0)1566 if (opt->optlen == 0) {
1564 return put_user(0, optlen);1567 len = 0;
1568 return copy_to_sockptr(optlen, &len, sizeof(int));
1569 }
1565 1570
1566 ip_options_undo(opt);1571 ip_options_undo(opt);
1567 1572
1568 len = min_t(unsigned int, len, opt->optlen);1573 len = min_t(unsigned int, len, opt->optlen);
1569 if (put_user(len, optlen))1574 if (copy_to_sockptr(optlen, &len, sizeof(int)))
1570 return -EFAULT;1575 return -EFAULT;
1571 if (copy_to_user(optval, opt->__data, len))1576 if (copy_to_sockptr(optval, opt->__data, len))
1572 return -EFAULT;1577 return -EFAULT;
1573 return 0;1578 return 0;
1574 }1579 }
@@ -1632,7 +1637,7 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, · 57 unmodified lines
1632 dst_release(dst);1637 dst_release(dst);
1633 }1638 }
1634 if (!val) {1639 if (!val) {
1635 release_sock(sk);1640 sockopt_release_sock(sk);
1636 return -ENOTCONN;1641 return -ENOTCONN;
1637 }1642 }
1638 break;1643 break;
@@ -1657,11 +1662,11 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, · 18 unmodified lines
1657 struct in_addr addr;1662 struct in_addr addr;
1658 len = min_t(unsigned int, len, sizeof(struct in_addr));1663 len = min_t(unsigned int, len, sizeof(struct in_addr));
1659 addr.s_addr = inet->mc_addr;1664 addr.s_addr = inet->mc_addr;
1660 release_sock(sk);1665 sockopt_release_sock(sk);
1661 1666
1662 if (put_user(len, optlen))1667 if (copy_to_sockptr(optlen, &len, sizeof(int)))
1663 return -EFAULT;1668 return -EFAULT;
1664 if (copy_to_user(optval, &addr, len))1669 if (copy_to_sockptr(optval, &addr, len))
1665 return -EFAULT;1670 return -EFAULT;
1666 return 0;1671 return 0;
1667 }1672 }
@@ -1673,12 +1678,11 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, · 5 unmodified lines
1673 err = -EINVAL;1678 err = -EINVAL;
1674 goto out;1679 goto out;
1675 }1680 }
1676 if (copy_from_user(&msf, optval, IP_MSFILTER_SIZE(0))) {1681 if (copy_from_sockptr(&msf, optval, IP_MSFILTER_SIZE(0))) {
1677 err = -EFAULT;1682 err = -EFAULT;
1678 goto out;1683 goto out;
1679 }1684 }
1680 err = ip_mc_msfget(sk, &msf,1685 err = ip_mc_msfget(sk, &msf, optval, optlen);
1681 (struct ip_msfilter __user *)optval, optlen);
1682 goto out;1686 goto out;
1683 }1687 }
1684 case MCAST_MSFILTER:1688 case MCAST_MSFILTER:
@@ -1695,13 +1699,18 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, · 10 unmodified lines
1695 {1699 {
1696 struct msghdr msg;1700 struct msghdr msg;
1697 1701
1698 release_sock(sk);1702 sockopt_release_sock(sk);
1699 1703
1700 if (sk->sk_type != SOCK_STREAM)1704 if (sk->sk_type != SOCK_STREAM)
1701 return -ENOPROTOOPT;1705 return -ENOPROTOOPT;
1702 1706
1703 msg.msg_control_is_user = true;1707 if (optval.is_kernel) {
1704 msg.msg_control_user = optval;1708 msg.msg_control_is_user = false;
1709 msg.msg_control = optval.kernel;
1710 } else {
1711 msg.msg_control_is_user = true;
1712 msg.msg_control_user = optval.user;
1713 }
1705 msg.msg_controllen = len;1714 msg.msg_controllen = len;
1706 msg.msg_flags = in_compat_syscall() ? MSG_CMSG_COMPAT : 0;1715 msg.msg_flags = in_compat_syscall() ? MSG_CMSG_COMPAT : 0;
1707 1716
@@ -1722,7 +1731,7 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, · 14 unmodified lines
1722 put_cmsg(&msg, SOL_IP, IP_TOS, sizeof(tos), &tos);1731 put_cmsg(&msg, SOL_IP, IP_TOS, sizeof(tos), &tos);
1723 }1732 }
1724 len -= msg.msg_controllen;1733 len -= msg.msg_controllen;
1725 return put_user(len, optlen);1734 return copy_to_sockptr(optlen, &len, sizeof(int));
1726 }1735 }
1727 case IP_FREEBIND:1736 case IP_FREEBIND:
1728 val = inet->freebind;1737 val = inet->freebind;
@@ -1734,29 +1743,29 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, · 5 unmodified lines
1734 val = inet->min_ttl;1743 val = inet->min_ttl;
1735 break;1744 break;
1736 default:1745 default:
1737 release_sock(sk);1746 sockopt_release_sock(sk);
1738 return -ENOPROTOOPT;1747 return -ENOPROTOOPT;
1739 }1748 }
1740 release_sock(sk);1749 sockopt_release_sock(sk);
1741 1750
1742 if (len < sizeof(int) && len > 0 && val >= 0 && val <= 255) {1751 if (len < sizeof(int) && len > 0 && val >= 0 && val <= 255) {
1743 unsigned char ucval = (unsigned char)val;1752 unsigned char ucval = (unsigned char)val;
1744 len = 1;1753 len = 1;
1745 if (put_user(len, optlen))1754 if (copy_to_sockptr(optlen, &len, sizeof(int)))
1746 return -EFAULT;1755 return -EFAULT;
1747 if (copy_to_user(optval, &ucval, 1))1756 if (copy_to_sockptr(optval, &ucval, 1))
1748 return -EFAULT;1757 return -EFAULT;
1749 } else {1758 } else {
1750 len = min_t(unsigned int, sizeof(int), len);1759 len = min_t(unsigned int, sizeof(int), len);
1751 if (put_user(len, optlen))1760 if (copy_to_sockptr(optlen, &len, sizeof(int)))
1752 return -EFAULT;1761 return -EFAULT;
1753 if (copy_to_user(optval, &val, len))1762 if (copy_to_sockptr(optval, &val, len))
1754 return -EFAULT;1763 return -EFAULT;
1755 }1764 }
1756 return 0;1765 return 0;
1757 1766
1758out:1767out:
1759 release_sock(sk);1768 sockopt_release_sock(sk);
1760 if (needs_rtnl)1769 if (needs_rtnl)
1761 rtnl_unlock();1770 rtnl_unlock();
1762 return err;1771 return err;
@@ -1767,7 +1776,8 @@ int ip_getsockopt(struct sock *sk, int level, · 4 unmodified lines
1767{1776{
1768 int err;1777 int err;
1769 1778
1770 err = do_ip_getsockopt(sk, level, optname, optval, optlen);1779 err = do_ip_getsockopt(sk, level, optname,
1780 USER_SOCKPTR(optval), USER_SOCKPTR(optlen));
1771 1781
1772#if IS_ENABLED(CONFIG_BPFILTER_UMH)1782#if IS_ENABLED(CONFIG_BPFILTER_UMH)
1773 if (optname >= BPFILTER_IPT_SO_GET_INFO &&1783 if (optname >= BPFILTER_IPT_SO_GET_INFO &&
net/ipv4/ipmr.c+5−4
@@ -1546,7 +1546,8 @@ out: · 1545 unmodified lines
1546}1546}
1547 1547
1548/* Getsock opt support for the multicast routing system. */1548/* Getsock opt support for the multicast routing system. */
1549int ip_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, int __user *optlen)1549int ip_mroute_getsockopt(struct sock *sk, int optname, sockptr_t optval,
1550 sockptr_t optlen)
1550{1551{
1551 int olr;1552 int olr;
1552 int val;1553 int val;
@@ -1577,14 +1578,14 @@ int ip_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, int · 24 unmodified lines
1577 return -ENOPROTOOPT;1578 return -ENOPROTOOPT;
1578 }1579 }
1579 1580
1580 if (get_user(olr, optlen))1581 if (copy_from_sockptr(&olr, optlen, sizeof(int)))
1581 return -EFAULT;1582 return -EFAULT;
1582 olr = min_t(unsigned int, olr, sizeof(int));1583 olr = min_t(unsigned int, olr, sizeof(int));
1583 if (olr < 0)1584 if (olr < 0)
1584 return -EINVAL;1585 return -EINVAL;
1585 if (put_user(olr, optlen))1586 if (copy_to_sockptr(optlen, &olr, sizeof(int)))
1586 return -EFAULT;1587 return -EFAULT;
1587 if (copy_to_user(optval, &val, olr))1588 if (copy_to_sockptr(optval, &val, olr))
1588 return -EFAULT;1589 return -EFAULT;
1589 return 0;1590 return 0;
1590}1591}
net/ipv4/tcp.c+59−57
@@ -3199,7 +3199,7 @@ EXPORT_SYMBOL(tcp_disconnect); · 3198 unmodified lines
3199 3199
3200static inline bool tcp_can_repair_sock(const struct sock *sk)3200static inline bool tcp_can_repair_sock(const struct sock *sk)
3201{3201{
3202 return ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN) &&3202 return sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN) &&
3203 (sk->sk_state != TCP_LISTEN);3203 (sk->sk_state != TCP_LISTEN);
3204}3204}
3205 3205
@@ -3476,8 +3476,8 @@ int tcp_set_window_clamp(struct sock *sk, int val) · 270 unmodified lines
3476/*3476/*
3477 * Socket option code for TCP.3477 * Socket option code for TCP.
3478 */3478 */
3479static int do_tcp_setsockopt(struct sock *sk, int level, int optname,3479int do_tcp_setsockopt(struct sock *sk, int level, int optname,
3480 sockptr_t optval, unsigned int optlen)3480 sockptr_t optval, unsigned int optlen)
3481{3481{
3482 struct tcp_sock *tp = tcp_sk(sk);3482 struct tcp_sock *tp = tcp_sk(sk);
3483 struct inet_connection_sock *icsk = inet_csk(sk);3483 struct inet_connection_sock *icsk = inet_csk(sk);
@@ -3499,11 +3499,11 @@ static int do_tcp_setsockopt(struct sock *sk, int level, int optname, · 15 unmodified lines
3499 return -EFAULT;3499 return -EFAULT;
3500 name[val] = 0;3500 name[val] = 0;
3501 3501
3502 lock_sock(sk);3502 sockopt_lock_sock(sk);
3503 err = tcp_set_congestion_control(sk, name, true,3503 err = tcp_set_congestion_control(sk, name, !has_current_bpf_ctx(),
3504 ns_capable(sock_net(sk)->user_ns,3504 sockopt_ns_capable(sock_net(sk)->user_ns,
3505 CAP_NET_ADMIN));3505 CAP_NET_ADMIN));
3506 release_sock(sk);3506 sockopt_release_sock(sk);
3507 return err;3507 return err;
3508 }3508 }
3509 case TCP_ULP: {3509 case TCP_ULP: {
@@ -3519,9 +3519,9 @@ static int do_tcp_setsockopt(struct sock *sk, int level, int optname, · 9 unmodified lines
3519 return -EFAULT;3519 return -EFAULT;
3520 name[val] = 0;3520 name[val] = 0;
3521 3521
3522 lock_sock(sk);3522 sockopt_lock_sock(sk);
3523 err = tcp_set_ulp(sk, name);3523 err = tcp_set_ulp(sk, name);
3524 release_sock(sk);3524 sockopt_release_sock(sk);
3525 return err;3525 return err;
3526 }3526 }
3527 case TCP_FASTOPEN_KEY: {3527 case TCP_FASTOPEN_KEY: {
@@ -3554,7 +3554,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level, int optname, · 26 unmodified lines
3554 if (copy_from_sockptr(&val, optval, sizeof(val)))3554 if (copy_from_sockptr(&val, optval, sizeof(val)))
3555 return -EFAULT;3555 return -EFAULT;
3556 3556
3557 lock_sock(sk);3557 sockopt_lock_sock(sk);
3558 3558
3559 switch (optname) {3559 switch (optname) {
3560 case TCP_MAXSEG:3560 case TCP_MAXSEG:
@@ -3776,7 +3776,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level, int optname, · 215 unmodified lines
3776 break;3776 break;
3777 }3777 }
3778 3778
3779 release_sock(sk);3779 sockopt_release_sock(sk);
3780 return err;3780 return err;
3781}3781}
3782 3782
@@ -4040,15 +4040,15 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, · 257 unmodified lines
4040 return stats;4040 return stats;
4041}4041}
4042 4042
4043static int do_tcp_getsockopt(struct sock *sk, int level,4043int do_tcp_getsockopt(struct sock *sk, int level,
4044 int optname, char __user *optval, int __user *optlen)4044 int optname, sockptr_t optval, sockptr_t optlen)
4045{4045{
4046 struct inet_connection_sock *icsk = inet_csk(sk);4046 struct inet_connection_sock *icsk = inet_csk(sk);
4047 struct tcp_sock *tp = tcp_sk(sk);4047 struct tcp_sock *tp = tcp_sk(sk);
4048 struct net *net = sock_net(sk);4048 struct net *net = sock_net(sk);
4049 int val, len;4049 int val, len;
4050 4050
4051 if (get_user(len, optlen))4051 if (copy_from_sockptr(&len, optlen, sizeof(int)))
4052 return -EFAULT;4052 return -EFAULT;
4053 4053
4054 len = min_t(unsigned int, len, sizeof(int));4054 len = min_t(unsigned int, len, sizeof(int));
@@ -4098,15 +4098,15 @@ static int do_tcp_getsockopt(struct sock *sk, int level, · 43 unmodified lines
4098 case TCP_INFO: {4098 case TCP_INFO: {
4099 struct tcp_info info;4099 struct tcp_info info;
4100 4100
4101 if (get_user(len, optlen))4101 if (copy_from_sockptr(&len, optlen, sizeof(int)))
4102 return -EFAULT;4102 return -EFAULT;
4103 4103
4104 tcp_get_info(sk, &info);4104 tcp_get_info(sk, &info);
4105 4105
4106 len = min_t(unsigned int, len, sizeof(info));4106 len = min_t(unsigned int, len, sizeof(info));
4107 if (put_user(len, optlen))4107 if (copy_to_sockptr(optlen, &len, sizeof(int)))
4108 return -EFAULT;4108 return -EFAULT;
4109 if (copy_to_user(optval, &info, len))4109 if (copy_to_sockptr(optval, &info, len))
4110 return -EFAULT;4110 return -EFAULT;
4111 return 0;4111 return 0;
4112 }4112 }
@@ -4116,7 +4116,7 @@ static int do_tcp_getsockopt(struct sock *sk, int level, · 3 unmodified lines
4116 size_t sz = 0;4116 size_t sz = 0;
4117 int attr;4117 int attr;
4118 4118
4119 if (get_user(len, optlen))4119 if (copy_from_sockptr(&len, optlen, sizeof(int)))
4120 return -EFAULT;4120 return -EFAULT;
4121 4121
4122 ca_ops = icsk->icsk_ca_ops;4122 ca_ops = icsk->icsk_ca_ops;
@@ -4124,9 +4124,9 @@ static int do_tcp_getsockopt(struct sock *sk, int level, · 1 unmodified line
4124 sz = ca_ops->get_info(sk, ~0U, &attr, &info);4124 sz = ca_ops->get_info(sk, ~0U, &attr, &info);
4125 4125
4126 len = min_t(unsigned int, len, sz);4126 len = min_t(unsigned int, len, sz);
4127 if (put_user(len, optlen))4127 if (copy_to_sockptr(optlen, &len, sizeof(int)))
4128 return -EFAULT;4128 return -EFAULT;
4129 if (copy_to_user(optval, &info, len))4129 if (copy_to_sockptr(optval, &info, len))
4130 return -EFAULT;4130 return -EFAULT;
4131 return 0;4131 return 0;
4132 }4132 }
@@ -4135,27 +4135,28 @@ static int do_tcp_getsockopt(struct sock *sk, int level, · 2 unmodified lines
4135 break;4135 break;
4136 4136
4137 case TCP_CONGESTION:4137 case TCP_CONGESTION:
4138 if (get_user(len, optlen))4138 if (copy_from_sockptr(&len, optlen, sizeof(int)))
4139 return -EFAULT;4139 return -EFAULT;
4140 len = min_t(unsigned int, len, TCP_CA_NAME_MAX);4140 len = min_t(unsigned int, len, TCP_CA_NAME_MAX);
4141 if (put_user(len, optlen))4141 if (copy_to_sockptr(optlen, &len, sizeof(int)))
4142 return -EFAULT;4142 return -EFAULT;
4143 if (copy_to_user(optval, icsk->icsk_ca_ops->name, len))4143 if (copy_to_sockptr(optval, icsk->icsk_ca_ops->name, len))
4144 return -EFAULT;4144 return -EFAULT;
4145 return 0;4145 return 0;
4146 4146
4147 case TCP_ULP:4147 case TCP_ULP:
4148 if (get_user(len, optlen))4148 if (copy_from_sockptr(&len, optlen, sizeof(int)))
4149 return -EFAULT;4149 return -EFAULT;
4150 len = min_t(unsigned int, len, TCP_ULP_NAME_MAX);4150 len = min_t(unsigned int, len, TCP_ULP_NAME_MAX);
4151 if (!icsk->icsk_ulp_ops) {4151 if (!icsk->icsk_ulp_ops) {
4152 if (put_user(0, optlen))4152 len = 0;
4153 if (copy_to_sockptr(optlen, &len, sizeof(int)))
4153 return -EFAULT;4154 return -EFAULT;
4154 return 0;4155 return 0;
4155 }4156 }
4156 if (put_user(len, optlen))4157 if (copy_to_sockptr(optlen, &len, sizeof(int)))
4157 return -EFAULT;4158 return -EFAULT;
4158 if (copy_to_user(optval, icsk->icsk_ulp_ops->name, len))4159 if (copy_to_sockptr(optval, icsk->icsk_ulp_ops->name, len))
4159 return -EFAULT;4160 return -EFAULT;
4160 return 0;4161 return 0;
4161 4162
@@ -4163,15 +4164,15 @@ static int do_tcp_getsockopt(struct sock *sk, int level, · 1 unmodified line
4163 u64 key[TCP_FASTOPEN_KEY_BUF_LENGTH / sizeof(u64)];4164 u64 key[TCP_FASTOPEN_KEY_BUF_LENGTH / sizeof(u64)];
4164 unsigned int key_len;4165 unsigned int key_len;
4165 4166
4166 if (get_user(len, optlen))4167 if (copy_from_sockptr(&len, optlen, sizeof(int)))
4167 return -EFAULT;4168 return -EFAULT;
4168 4169
4169 key_len = tcp_fastopen_get_cipher(net, icsk, key) *4170 key_len = tcp_fastopen_get_cipher(net, icsk, key) *
4170 TCP_FASTOPEN_KEY_LENGTH;4171 TCP_FASTOPEN_KEY_LENGTH;
4171 len = min_t(unsigned int, len, key_len);4172 len = min_t(unsigned int, len, key_len);
4172 if (put_user(len, optlen))4173 if (copy_to_sockptr(optlen, &len, sizeof(int)))
4173 return -EFAULT;4174 return -EFAULT;
4174 if (copy_to_user(optval, key, len))4175 if (copy_to_sockptr(optval, key, len))
4175 return -EFAULT;4176 return -EFAULT;
4176 return 0;4177 return 0;
4177 }4178 }
@@ -4197,7 +4198,7 @@ static int do_tcp_getsockopt(struct sock *sk, int level, · 19 unmodified lines
4197 case TCP_REPAIR_WINDOW: {4198 case TCP_REPAIR_WINDOW: {
4198 struct tcp_repair_window opt;4199 struct tcp_repair_window opt;
4199 4200
4200 if (get_user(len, optlen))4201 if (copy_from_sockptr(&len, optlen, sizeof(int)))
4201 return -EFAULT;4202 return -EFAULT;
4202 4203
4203 if (len != sizeof(opt))4204 if (len != sizeof(opt))
@@ -4212,7 +4213,7 @@ static int do_tcp_getsockopt(struct sock *sk, int level, · 8 unmodified lines
4212 opt.rcv_wnd = tp->rcv_wnd;4213 opt.rcv_wnd = tp->rcv_wnd;
4213 opt.rcv_wup = tp->rcv_wup;4214 opt.rcv_wup = tp->rcv_wup;
4214 4215
4215 if (copy_to_user(optval, &opt, len))4216 if (copy_to_sockptr(optval, &opt, len))
4216 return -EFAULT;4217 return -EFAULT;
4217 return 0;4218 return 0;
4218 }4219 }
@@ -4258,35 +4259,35 @@ static int do_tcp_getsockopt(struct sock *sk, int level, · 39 unmodified lines
4258 val = tp->save_syn;4259 val = tp->save_syn;
4259 break;4260 break;
4260 case TCP_SAVED_SYN: {4261 case TCP_SAVED_SYN: {
4261 if (get_user(len, optlen))4262 if (copy_from_sockptr(&len, optlen, sizeof(int)))
4262 return -EFAULT;4263 return -EFAULT;
4263 4264
4264 lock_sock(sk);4265 sockopt_lock_sock(sk);
4265 if (tp->saved_syn) {4266 if (tp->saved_syn) {
4266 if (len < tcp_saved_syn_len(tp->saved_syn)) {4267 if (len < tcp_saved_syn_len(tp->saved_syn)) {
4267 if (put_user(tcp_saved_syn_len(tp->saved_syn),4268 len = tcp_saved_syn_len(tp->saved_syn);
4268 optlen)) {4269 if (copy_to_sockptr(optlen, &len, sizeof(int))) {
4269 release_sock(sk);4270 sockopt_release_sock(sk);
4270 return -EFAULT;4271 return -EFAULT;
4271 }4272 }
4272 release_sock(sk);4273 sockopt_release_sock(sk);
4273 return -EINVAL;4274 return -EINVAL;
4274 }4275 }
4275 len = tcp_saved_syn_len(tp->saved_syn);4276 len = tcp_saved_syn_len(tp->saved_syn);
4276 if (put_user(len, optlen)) {4277 if (copy_to_sockptr(optlen, &len, sizeof(int))) {
4277 release_sock(sk);4278 sockopt_release_sock(sk);
4278 return -EFAULT;4279 return -EFAULT;
4279 }4280 }
4280 if (copy_to_user(optval, tp->saved_syn->data, len)) {4281 if (copy_to_sockptr(optval, tp->saved_syn->data, len)) {
4281 release_sock(sk);4282 sockopt_release_sock(sk);
4282 return -EFAULT;4283 return -EFAULT;
4283 }4284 }
4284 tcp_saved_syn_free(tp);4285 tcp_saved_syn_free(tp);
4285 release_sock(sk);4286 sockopt_release_sock(sk);
4286 } else {4287 } else {
4287 release_sock(sk);4288 sockopt_release_sock(sk);
4288 len = 0;4289 len = 0;
4289 if (put_user(len, optlen))4290 if (copy_to_sockptr(optlen, &len, sizeof(int)))
4290 return -EFAULT;4291 return -EFAULT;
4291 }4292 }
4292 return 0;4293 return 0;
@@ -4297,31 +4298,31 @@ static int do_tcp_getsockopt(struct sock *sk, int level, · 4 unmodified lines
4297 struct tcp_zerocopy_receive zc = {};4298 struct tcp_zerocopy_receive zc = {};
4298 int err;4299 int err;
4299 4300
4300 if (get_user(len, optlen))4301 if (copy_from_sockptr(&len, optlen, sizeof(int)))
4301 return -EFAULT;4302 return -EFAULT;
4302 if (len < 0 ||4303 if (len < 0 ||
4303 len < offsetofend(struct tcp_zerocopy_receive, length))4304 len < offsetofend(struct tcp_zerocopy_receive, length))
4304 return -EINVAL;4305 return -EINVAL;
4305 if (unlikely(len > sizeof(zc))) {4306 if (unlikely(len > sizeof(zc))) {
4306 err = check_zeroed_user(optval + sizeof(zc),4307 err = check_zeroed_sockptr(optval, sizeof(zc),
4307 len - sizeof(zc));4308 len - sizeof(zc));
4308 if (err < 1)4309 if (err < 1)
4309 return err == 0 ? -EINVAL : err;4310 return err == 0 ? -EINVAL : err;
4310 len = sizeof(zc);4311 len = sizeof(zc);
4311 if (put_user(len, optlen))4312 if (copy_to_sockptr(optlen, &len, sizeof(int)))
4312 return -EFAULT;4313 return -EFAULT;
4313 }4314 }
4314 if (copy_from_user(&zc, optval, len))4315 if (copy_from_sockptr(&zc, optval, len))
4315 return -EFAULT;4316 return -EFAULT;
4316 if (zc.reserved)4317 if (zc.reserved)
4317 return -EINVAL;4318 return -EINVAL;
4318 if (zc.msg_flags & ~(TCP_VALID_ZC_MSG_FLAGS))4319 if (zc.msg_flags & ~(TCP_VALID_ZC_MSG_FLAGS))
4319 return -EINVAL;4320 return -EINVAL;
4320 lock_sock(sk);4321 sockopt_lock_sock(sk);
4321 err = tcp_zerocopy_receive(sk, &zc, &tss);4322 err = tcp_zerocopy_receive(sk, &zc, &tss);
4322 err = BPF_CGROUP_RUN_PROG_GETSOCKOPT_KERN(sk, level, optname,4323 err = BPF_CGROUP_RUN_PROG_GETSOCKOPT_KERN(sk, level, optname,
4323 &zc, &len, err);4324 &zc, &len, err);
4324 release_sock(sk);4325 sockopt_release_sock(sk);
4325 if (len >= offsetofend(struct tcp_zerocopy_receive, msg_flags))4326 if (len >= offsetofend(struct tcp_zerocopy_receive, msg_flags))
4326 goto zerocopy_rcv_cmsg;4327 goto zerocopy_rcv_cmsg;
4327 switch (len) {4328 switch (len) {
@@ -4351,7 +4352,7 @@ zerocopy_rcv_sk_err: · 23 unmodified lines
4351zerocopy_rcv_inq:4352zerocopy_rcv_inq:
4352 zc.inq = tcp_inq_hint(sk);4353 zc.inq = tcp_inq_hint(sk);
4353zerocopy_rcv_out:4354zerocopy_rcv_out:
4354 if (!err && copy_to_user(optval, &zc, len))4355 if (!err && copy_to_sockptr(optval, &zc, len))
4355 err = -EFAULT;4356 err = -EFAULT;
4356 return err;4357 return err;
4357 }4358 }
@@ -4360,9 +4361,9 @@ zerocopy_rcv_out: · 2 unmodified lines
4360 return -ENOPROTOOPT;4361 return -ENOPROTOOPT;
4361 }4362 }
4362 4363
4363 if (put_user(len, optlen))4364 if (copy_to_sockptr(optlen, &len, sizeof(int)))
4364 return -EFAULT;4365 return -EFAULT;
4365 if (copy_to_user(optval, &val, len))4366 if (copy_to_sockptr(optval, &val, len))
4366 return -EFAULT;4367 return -EFAULT;
4367 return 0;4368 return 0;
4368}4369}
@@ -4387,7 +4388,8 @@ int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, · 18 unmodified lines
4387 if (level != SOL_TCP)4388 if (level != SOL_TCP)
4388 return icsk->icsk_af_ops->getsockopt(sk, level, optname,4389 return icsk->icsk_af_ops->getsockopt(sk, level, optname,
4389 optval, optlen);4390 optval, optlen);
4390 return do_tcp_getsockopt(sk, level, optname, optval, optlen);4391 return do_tcp_getsockopt(sk, level, optname, USER_SOCKPTR(optval),
4392 USER_SOCKPTR(optlen));
4391}4393}
4392EXPORT_SYMBOL(tcp_getsockopt);4394EXPORT_SYMBOL(tcp_getsockopt);
4393 4395
net/ipv6/af_inet6.c+2−0
@@ -1057,6 +1057,8 @@ static const struct ipv6_stub ipv6_stub_impl = { · 1056 unmodified lines
1057static const struct ipv6_bpf_stub ipv6_bpf_stub_impl = {1057static const struct ipv6_bpf_stub ipv6_bpf_stub_impl = {
1058 .inet6_bind = __inet6_bind,1058 .inet6_bind = __inet6_bind,
1059 .udp6_lib_lookup = __udp6_lib_lookup,1059 .udp6_lib_lookup = __udp6_lib_lookup,
1060 .ipv6_setsockopt = do_ipv6_setsockopt,
1061 .ipv6_getsockopt = do_ipv6_getsockopt,
1060};1062};
1061 1063
1062static int __init inet6_init(void)1064static int __init inet6_init(void)
net/ipv6/ip6mr.c+5−5
@@ -1827,8 +1827,8 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval, · 1826 unmodified lines
1827 * Getsock opt support for the multicast routing system.1827 * Getsock opt support for the multicast routing system.
1828 */1828 */
1829 1829
1830int ip6_mroute_getsockopt(struct sock *sk, int optname, char __user *optval,1830int ip6_mroute_getsockopt(struct sock *sk, int optname, sockptr_t optval,
1831 int __user *optlen)1831 sockptr_t optlen)
1832{1832{
1833 int olr;1833 int olr;
1834 int val;1834 int val;
@@ -1859,16 +1859,16 @@ int ip6_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, · 24 unmodified lines
1859 return -ENOPROTOOPT;1859 return -ENOPROTOOPT;
1860 }1860 }
1861 1861
1862 if (get_user(olr, optlen))1862 if (copy_from_sockptr(&olr, optlen, sizeof(int)))
1863 return -EFAULT;1863 return -EFAULT;
1864 1864
1865 olr = min_t(int, olr, sizeof(int));1865 olr = min_t(int, olr, sizeof(int));
1866 if (olr < 0)1866 if (olr < 0)
1867 return -EINVAL;1867 return -EINVAL;
1868 1868
1869 if (put_user(olr, optlen))1869 if (copy_to_sockptr(optlen, &olr, sizeof(int)))
1870 return -EFAULT;1870 return -EFAULT;
1871 if (copy_to_user(optval, &val, olr))1871 if (copy_to_sockptr(optval, &val, olr))
1872 return -EFAULT;1872 return -EFAULT;
1873 return 0;1873 return 0;
1874}1874}
net/ipv6/ipv6_sockglue.c+59−54
@@ -327,7 +327,7 @@ static int ipv6_set_opt_hdr(struct sock *sk, int optname, sockptr_t optval, · 326 unmodified lines
327 int err;327 int err;
328 328
329 /* hop-by-hop / destination options are privileged option */329 /* hop-by-hop / destination options are privileged option */
330 if (optname != IPV6_RTHDR && !ns_capable(net->user_ns, CAP_NET_RAW))330 if (optname != IPV6_RTHDR && !sockopt_ns_capable(net->user_ns, CAP_NET_RAW))
331 return -EPERM;331 return -EPERM;
332 332
333 /* remove any sticky options header with a zero option333 /* remove any sticky options header with a zero option
@@ -391,8 +391,8 @@ sticky_done: · 57 unmodified lines
391 return err;391 return err;
392}392}
393 393
394static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,394int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
395 sockptr_t optval, unsigned int optlen)395 sockptr_t optval, unsigned int optlen)
396{396{
397 struct ipv6_pinfo *np = inet6_sk(sk);397 struct ipv6_pinfo *np = inet6_sk(sk);
398 struct net *net = sock_net(sk);398 struct net *net = sock_net(sk);
@@ -417,7 +417,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, · 18 unmodified lines
417 417
418 if (needs_rtnl)418 if (needs_rtnl)
419 rtnl_lock();419 rtnl_lock();
420 lock_sock(sk);420 sockopt_lock_sock(sk);
421 421
422 switch (optname) {422 switch (optname) {
423 423
@@ -634,8 +634,8 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, · 210 unmodified lines
634 break;634 break;
635 635
636 case IPV6_TRANSPARENT:636 case IPV6_TRANSPARENT:
637 if (valbool && !ns_capable(net->user_ns, CAP_NET_RAW) &&637 if (valbool && !sockopt_ns_capable(net->user_ns, CAP_NET_RAW) &&
638 !ns_capable(net->user_ns, CAP_NET_ADMIN)) {638 !sockopt_ns_capable(net->user_ns, CAP_NET_ADMIN)) {
639 retv = -EPERM;639 retv = -EPERM;
640 break;640 break;
641 }641 }
@@ -946,7 +946,7 @@ done: · 304 unmodified lines
946 case IPV6_IPSEC_POLICY:946 case IPV6_IPSEC_POLICY:
947 case IPV6_XFRM_POLICY:947 case IPV6_XFRM_POLICY:
948 retv = -EPERM;948 retv = -EPERM;
949 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))949 if (!sockopt_ns_capable(net->user_ns, CAP_NET_ADMIN))
950 break;950 break;
951 retv = xfrm_user_policy(sk, optname, optval, optlen);951 retv = xfrm_user_policy(sk, optname, optval, optlen);
952 break;952 break;
@@ -994,14 +994,14 @@ done: · 41 unmodified lines
994 break;994 break;
995 }995 }
996 996
997 release_sock(sk);997 sockopt_release_sock(sk);
998 if (needs_rtnl)998 if (needs_rtnl)
999 rtnl_unlock();999 rtnl_unlock();
1000 1000
1001 return retv;1001 return retv;
1002 1002
1003e_inval:1003e_inval:
1004 release_sock(sk);1004 sockopt_release_sock(sk);
1005 if (needs_rtnl)1005 if (needs_rtnl)
1006 rtnl_unlock();1006 rtnl_unlock();
1007 return -EINVAL;1007 return -EINVAL;
@@ -1030,7 +1030,7 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval, · 22 unmodified lines
1030EXPORT_SYMBOL(ipv6_setsockopt);1030EXPORT_SYMBOL(ipv6_setsockopt);
1031 1031
1032static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_txoptions *opt,1032static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_txoptions *opt,
1033 int optname, char __user *optval, int len)1033 int optname, sockptr_t optval, int len)
1034{1034{
1035 struct ipv6_opt_hdr *hdr;1035 struct ipv6_opt_hdr *hdr;
1036 1036
@@ -1058,56 +1058,53 @@ static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_txoptions *opt, · 21 unmodified lines
1058 return 0;1058 return 0;
1059 1059
1060 len = min_t(unsigned int, len, ipv6_optlen(hdr));1060 len = min_t(unsigned int, len, ipv6_optlen(hdr));
1061 if (copy_to_user(optval, hdr, len))1061 if (copy_to_sockptr(optval, hdr, len))
1062 return -EFAULT;1062 return -EFAULT;
1063 return len;1063 return len;
1064}1064}
1065 1065
1066static int ipv6_get_msfilter(struct sock *sk, void __user *optval,1066static int ipv6_get_msfilter(struct sock *sk, sockptr_t optval,
1067 int __user *optlen, int len)1067 sockptr_t optlen, int len)
1068{1068{
1069 const int size0 = offsetof(struct group_filter, gf_slist_flex);1069 const int size0 = offsetof(struct group_filter, gf_slist_flex);
1070 struct group_filter __user *p = optval;
1071 struct group_filter gsf;1070 struct group_filter gsf;
1072 int num;1071 int num;
1073 int err;1072 int err;
1074 1073
1075 if (len < size0)1074 if (len < size0)
1076 return -EINVAL;1075 return -EINVAL;
1077 if (copy_from_user(&gsf, p, size0))1076 if (copy_from_sockptr(&gsf, optval, size0))
1078 return -EFAULT;1077 return -EFAULT;
1079 if (gsf.gf_group.ss_family != AF_INET6)1078 if (gsf.gf_group.ss_family != AF_INET6)
1080 return -EADDRNOTAVAIL;1079 return -EADDRNOTAVAIL;
1081 num = gsf.gf_numsrc;1080 num = gsf.gf_numsrc;
1082 lock_sock(sk);1081 sockopt_lock_sock(sk);
1083 err = ip6_mc_msfget(sk, &gsf, p->gf_slist_flex);1082 err = ip6_mc_msfget(sk, &gsf, optval, size0);
1084 if (!err) {1083 if (!err) {
1085 if (num > gsf.gf_numsrc)1084 if (num > gsf.gf_numsrc)
1086 num = gsf.gf_numsrc;1085 num = gsf.gf_numsrc;
1087 if (put_user(GROUP_FILTER_SIZE(num), optlen) ||1086 len = GROUP_FILTER_SIZE(num);
1088 copy_to_user(p, &gsf, size0))1087 if (copy_to_sockptr(optlen, &len, sizeof(int)) ||
1088 copy_to_sockptr(optval, &gsf, size0))
1089 err = -EFAULT;1089 err = -EFAULT;
1090 }1090 }
1091 release_sock(sk);1091 sockopt_release_sock(sk);
1092 return err;1092 return err;
1093}1093}
1094 1094
1095static int compat_ipv6_get_msfilter(struct sock *sk, void __user *optval,1095static int compat_ipv6_get_msfilter(struct sock *sk, sockptr_t optval,
1096 int __user *optlen)1096 sockptr_t optlen, int len)
1097{1097{
1098 const int size0 = offsetof(struct compat_group_filter, gf_slist_flex);1098 const int size0 = offsetof(struct compat_group_filter, gf_slist_flex);
1099 struct compat_group_filter __user *p = optval;
1100 struct compat_group_filter gf32;1099 struct compat_group_filter gf32;
1101 struct group_filter gf;1100 struct group_filter gf;
1102 int len, err;1101 int err;
1103 int num;1102 int num;
1104 1103
1105 if (get_user(len, optlen))
1106 return -EFAULT;
1107 if (len < size0)1104 if (len < size0)
1108 return -EINVAL;1105 return -EINVAL;
1109 1106
1110 if (copy_from_user(&gf32, p, size0))1107 if (copy_from_sockptr(&gf32, optval, size0))
1111 return -EFAULT;1108 return -EFAULT;
1112 gf.gf_interface = gf32.gf_interface;1109 gf.gf_interface = gf32.gf_interface;
1113 gf.gf_fmode = gf32.gf_fmode;1110 gf.gf_fmode = gf32.gf_fmode;
@@ -1117,23 +1114,25 @@ static int compat_ipv6_get_msfilter(struct sock *sk, void __user *optval, · 3 unmodified lines
1117 if (gf.gf_group.ss_family != AF_INET6)1114 if (gf.gf_group.ss_family != AF_INET6)
1118 return -EADDRNOTAVAIL;1115 return -EADDRNOTAVAIL;
1119 1116
1120 lock_sock(sk);1117 sockopt_lock_sock(sk);
1121 err = ip6_mc_msfget(sk, &gf, p->gf_slist_flex);1118 err = ip6_mc_msfget(sk, &gf, optval, size0);
1122 release_sock(sk);1119 sockopt_release_sock(sk);
1123 if (err)1120 if (err)
1124 return err;1121 return err;
1125 if (num > gf.gf_numsrc)1122 if (num > gf.gf_numsrc)
1126 num = gf.gf_numsrc;1123 num = gf.gf_numsrc;
1127 len = GROUP_FILTER_SIZE(num) - (sizeof(gf)-sizeof(gf32));1124 len = GROUP_FILTER_SIZE(num) - (sizeof(gf)-sizeof(gf32));
1128 if (put_user(len, optlen) ||1125 if (copy_to_sockptr(optlen, &len, sizeof(int)) ||
1129 put_user(gf.gf_fmode, &p->gf_fmode) ||1126 copy_to_sockptr_offset(optval, offsetof(struct compat_group_filter, gf_fmode),
1130 put_user(gf.gf_numsrc, &p->gf_numsrc))1127 &gf.gf_fmode, sizeof(gf32.gf_fmode)) ||
1128 copy_to_sockptr_offset(optval, offsetof(struct compat_group_filter, gf_numsrc),
1129 &gf.gf_numsrc, sizeof(gf32.gf_numsrc)))
1131 return -EFAULT;1130 return -EFAULT;
1132 return 0;1131 return 0;
1133}1132}
1134 1133
1135static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,1134int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
1136 char __user *optval, int __user *optlen, unsigned int flags)1135 sockptr_t optval, sockptr_t optlen)
1137{1136{
1138 struct ipv6_pinfo *np = inet6_sk(sk);1137 struct ipv6_pinfo *np = inet6_sk(sk);
1139 int len;1138 int len;
@@ -1142,7 +1141,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, · 2 unmodified lines
1142 if (ip6_mroute_opt(optname))1141 if (ip6_mroute_opt(optname))
1143 return ip6_mroute_getsockopt(sk, optname, optval, optlen);1142 return ip6_mroute_getsockopt(sk, optname, optval, optlen);
1144 1143
1145 if (get_user(len, optlen))1144 if (copy_from_sockptr(&len, optlen, sizeof(int)))
1146 return -EFAULT;1145 return -EFAULT;
1147 switch (optname) {1146 switch (optname) {
1148 case IPV6_ADDRFORM:1147 case IPV6_ADDRFORM:
@@ -1156,7 +1155,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, · 7 unmodified lines
1156 break;1155 break;
1157 case MCAST_MSFILTER:1156 case MCAST_MSFILTER:
1158 if (in_compat_syscall())1157 if (in_compat_syscall())
1159 return compat_ipv6_get_msfilter(sk, optval, optlen);1158 return compat_ipv6_get_msfilter(sk, optval, optlen, len);
1160 return ipv6_get_msfilter(sk, optval, optlen, len);1159 return ipv6_get_msfilter(sk, optval, optlen, len);
1161 case IPV6_2292PKTOPTIONS:1160 case IPV6_2292PKTOPTIONS:
1162 {1161 {
@@ -1166,16 +1165,21 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, · 3 unmodified lines
1166 if (sk->sk_type != SOCK_STREAM)1165 if (sk->sk_type != SOCK_STREAM)
1167 return -ENOPROTOOPT;1166 return -ENOPROTOOPT;
1168 1167
1169 msg.msg_control_user = optval;1168 if (optval.is_kernel) {
1169 msg.msg_control_is_user = false;
1170 msg.msg_control = optval.kernel;
1171 } else {
1172 msg.msg_control_is_user = true;
1173 msg.msg_control_user = optval.user;
1174 }
1170 msg.msg_controllen = len;1175 msg.msg_controllen = len;
1171 msg.msg_flags = flags;1176 msg.msg_flags = 0;
1172 msg.msg_control_is_user = true;
1173 1177
1174 lock_sock(sk);1178 sockopt_lock_sock(sk);
1175 skb = np->pktoptions;1179 skb = np->pktoptions;
1176 if (skb)1180 if (skb)
1177 ip6_datagram_recv_ctl(sk, &msg, skb);1181 ip6_datagram_recv_ctl(sk, &msg, skb);
1178 release_sock(sk);1182 sockopt_release_sock(sk);
1179 if (!skb) {1183 if (!skb) {
1180 if (np->rxopt.bits.rxinfo) {1184 if (np->rxopt.bits.rxinfo) {
1181 struct in6_pktinfo src_info;1185 struct in6_pktinfo src_info;
@@ -1212,7 +1216,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, · 30 unmodified lines
1212 }1216 }
1213 }1217 }
1214 len -= msg.msg_controllen;1218 len -= msg.msg_controllen;
1215 return put_user(len, optlen);1219 return copy_to_sockptr(optlen, &len, sizeof(int));
1216 }1220 }
1217 case IPV6_MTU:1221 case IPV6_MTU:
1218 {1222 {
@@ -1264,15 +1268,15 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, · 45 unmodified lines
1264 {1268 {
1265 struct ipv6_txoptions *opt;1269 struct ipv6_txoptions *opt;
1266 1270
1267 lock_sock(sk);1271 sockopt_lock_sock(sk);
1268 opt = rcu_dereference_protected(np->opt,1272 opt = rcu_dereference_protected(np->opt,
1269 lockdep_sock_is_held(sk));1273 lockdep_sock_is_held(sk));
1270 len = ipv6_getsockopt_sticky(sk, opt, optname, optval, len);1274 len = ipv6_getsockopt_sticky(sk, opt, optname, optval, len);
1271 release_sock(sk);1275 sockopt_release_sock(sk);
1272 /* check if ipv6_getsockopt_sticky() returns err code */1276 /* check if ipv6_getsockopt_sticky() returns err code */
1273 if (len < 0)1277 if (len < 0)
1274 return len;1278 return len;
1275 return put_user(len, optlen);1279 return copy_to_sockptr(optlen, &len, sizeof(int));
1276 }1280 }
1277 1281
1278 case IPV6_RECVHOPOPTS:1282 case IPV6_RECVHOPOPTS:
@@ -1326,9 +1330,9 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, · 47 unmodified lines
1326 if (!mtuinfo.ip6m_mtu)1330 if (!mtuinfo.ip6m_mtu)
1327 return -ENOTCONN;1331 return -ENOTCONN;
1328 1332
1329 if (put_user(len, optlen))1333 if (copy_to_sockptr(optlen, &len, sizeof(int)))
1330 return -EFAULT;1334 return -EFAULT;
1331 if (copy_to_user(optval, &mtuinfo, len))1335 if (copy_to_sockptr(optval, &mtuinfo, len))
1332 return -EFAULT;1336 return -EFAULT;
1333 1337
1334 return 0;1338 return 0;
@@ -1405,7 +1409,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, · 70 unmodified lines
1405 if (len < sizeof(freq))1409 if (len < sizeof(freq))
1406 return -EINVAL;1410 return -EINVAL;
1407 1411
1408 if (copy_from_user(&freq, optval, sizeof(freq)))1412 if (copy_from_sockptr(&freq, optval, sizeof(freq)))
1409 return -EFAULT;1413 return -EFAULT;
1410 1414
1411 if (freq.flr_action != IPV6_FL_A_GET)1415 if (freq.flr_action != IPV6_FL_A_GET)
@@ -1420,9 +1424,9 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, · 8 unmodified lines
1420 if (val < 0)1424 if (val < 0)
1421 return val;1425 return val;
1422 1426
1423 if (put_user(len, optlen))1427 if (copy_to_sockptr(optlen, &len, sizeof(int)))
1424 return -EFAULT;1428 return -EFAULT;
1425 if (copy_to_user(optval, &freq, len))1429 if (copy_to_sockptr(optval, &freq, len))
1426 return -EFAULT;1430 return -EFAULT;
1427 1431
1428 return 0;1432 return 0;
@@ -1474,9 +1478,9 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, · 45 unmodified lines
1474 return -ENOPROTOOPT;1478 return -ENOPROTOOPT;
1475 }1479 }
1476 len = min_t(unsigned int, sizeof(int), len);1480 len = min_t(unsigned int, sizeof(int), len);
1477 if (put_user(len, optlen))1481 if (copy_to_sockptr(optlen, &len, sizeof(int)))
1478 return -EFAULT;1482 return -EFAULT;
1479 if (copy_to_user(optval, &val, len))1483 if (copy_to_sockptr(optval, &val, len))
1480 return -EFAULT;1484 return -EFAULT;
1481 return 0;1485 return 0;
1482}1486}
@@ -1492,7 +1496,8 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname, · 9 unmodified lines
1492 if (level != SOL_IPV6)1496 if (level != SOL_IPV6)
1493 return -ENOPROTOOPT;1497 return -ENOPROTOOPT;
1494 1498
1495 err = do_ipv6_getsockopt(sk, level, optname, optval, optlen, 0);1499 err = do_ipv6_getsockopt(sk, level, optname,
1500 USER_SOCKPTR(optval), USER_SOCKPTR(optlen));
1496#ifdef CONFIG_NETFILTER1501#ifdef CONFIG_NETFILTER
1497 /* we need to exclude all possible ENOPROTOOPTs except default case */1502 /* we need to exclude all possible ENOPROTOOPTs except default case */
1498 if (err == -ENOPROTOOPT && optname != IPV6_2292PKTOPTIONS) {1503 if (err == -ENOPROTOOPT && optname != IPV6_2292PKTOPTIONS) {
net/ipv6/mcast.c+4−4
@@ -580,7 +580,7 @@ done: · 579 unmodified lines
580}580}
581 581
582int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,582int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
583 struct sockaddr_storage __user *p)583 sockptr_t optval, size_t ss_offset)
584{584{
585 struct ipv6_pinfo *inet6 = inet6_sk(sk);585 struct ipv6_pinfo *inet6 = inet6_sk(sk);
586 const struct in6_addr *group;586 const struct in6_addr *group;
@@ -612,8 +612,7 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf, · 25 unmodified lines
612 612
613 copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc;613 copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc;
614 gsf->gf_numsrc = count;614 gsf->gf_numsrc = count;
615 615 for (i = 0; i < copycount; i++) {
616 for (i = 0; i < copycount; i++, p++) {
617 struct sockaddr_in6 *psin6;616 struct sockaddr_in6 *psin6;
618 struct sockaddr_storage ss;617 struct sockaddr_storage ss;
619 618
@@ -621,8 +620,9 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf, · 1 unmodified line
621 memset(&ss, 0, sizeof(ss));620 memset(&ss, 0, sizeof(ss));
622 psin6->sin6_family = AF_INET6;621 psin6->sin6_family = AF_INET6;
623 psin6->sin6_addr = psl->sl_addr[i];622 psin6->sin6_addr = psl->sl_addr[i];
624 if (copy_to_user(p, &ss, sizeof(ss)))623 if (copy_to_sockptr_offset(optval, ss_offset, &ss, sizeof(ss)))
625 return -EFAULT;624 return -EFAULT;
625 ss_offset += sizeof(ss);
626 }626 }
627 return 0;627 return 0;
628}628}
samples/bpf/map_perf_test_kern.c+28−16
@@ -108,11 +108,14 @@ int stress_hmap(struct pt_regs *ctx) · 107 unmodified lines
108 u32 key = bpf_get_current_pid_tgid();108 u32 key = bpf_get_current_pid_tgid();
109 long init_val = 1;109 long init_val = 1;
110 long *value;110 long *value;
111 int i;
111 112
112 bpf_map_update_elem(&hash_map, &key, &init_val, BPF_ANY);113 for (i = 0; i < 10; i++) {
113 value = bpf_map_lookup_elem(&hash_map, &key);114 bpf_map_update_elem(&hash_map, &key, &init_val, BPF_ANY);
114 if (value)115 value = bpf_map_lookup_elem(&hash_map, &key);
115 bpf_map_delete_elem(&hash_map, &key);116 if (value)
117 bpf_map_delete_elem(&hash_map, &key);
118 }
116 119
117 return 0;120 return 0;
118}121}
@@ -123,11 +126,14 @@ int stress_percpu_hmap(struct pt_regs *ctx) · 4 unmodified lines
123 u32 key = bpf_get_current_pid_tgid();126 u32 key = bpf_get_current_pid_tgid();
124 long init_val = 1;127 long init_val = 1;
125 long *value;128 long *value;
129 int i;
126 130
127 bpf_map_update_elem(&percpu_hash_map, &key, &init_val, BPF_ANY);131 for (i = 0; i < 10; i++) {
128 value = bpf_map_lookup_elem(&percpu_hash_map, &key);132 bpf_map_update_elem(&percpu_hash_map, &key, &init_val, BPF_ANY);
129 if (value)133 value = bpf_map_lookup_elem(&percpu_hash_map, &key);
130 bpf_map_delete_elem(&percpu_hash_map, &key);134 if (value)
135 bpf_map_delete_elem(&percpu_hash_map, &key);
136 }
131 return 0;137 return 0;
132}138}
133 139
@@ -137,11 +143,14 @@ int stress_hmap_alloc(struct pt_regs *ctx) · 3 unmodified lines
137 u32 key = bpf_get_current_pid_tgid();143 u32 key = bpf_get_current_pid_tgid();
138 long init_val = 1;144 long init_val = 1;
139 long *value;145 long *value;
146 int i;
140 147
141 bpf_map_update_elem(&hash_map_alloc, &key, &init_val, BPF_ANY);148 for (i = 0; i < 10; i++) {
142 value = bpf_map_lookup_elem(&hash_map_alloc, &key);149 bpf_map_update_elem(&hash_map_alloc, &key, &init_val, BPF_ANY);
143 if (value)150 value = bpf_map_lookup_elem(&hash_map_alloc, &key);
144 bpf_map_delete_elem(&hash_map_alloc, &key);151 if (value)
152 bpf_map_delete_elem(&hash_map_alloc, &key);
153 }
145 return 0;154 return 0;
146}155}
147 156
@@ -151,11 +160,14 @@ int stress_percpu_hmap_alloc(struct pt_regs *ctx) · 3 unmodified lines
151 u32 key = bpf_get_current_pid_tgid();160 u32 key = bpf_get_current_pid_tgid();
152 long init_val = 1;161 long init_val = 1;
153 long *value;162 long *value;
163 int i;
154 164
155 bpf_map_update_elem(&percpu_hash_map_alloc, &key, &init_val, BPF_ANY);165 for (i = 0; i < 10; i++) {
156 value = bpf_map_lookup_elem(&percpu_hash_map_alloc, &key);166 bpf_map_update_elem(&percpu_hash_map_alloc, &key, &init_val, BPF_ANY);
157 if (value)167 value = bpf_map_lookup_elem(&percpu_hash_map_alloc, &key);
158 bpf_map_delete_elem(&percpu_hash_map_alloc, &key);168 if (value)
169 bpf_map_delete_elem(&percpu_hash_map_alloc, &key);
170 }
159 return 0;171 return 0;
160}172}
161 173
samples/bpf/map_perf_test_user.c+1−1
@@ -72,7 +72,7 @@ static int test_flags = ~0; · 71 unmodified lines
72static uint32_t num_map_entries;72static uint32_t num_map_entries;
73static uint32_t inner_lru_hash_size;73static uint32_t inner_lru_hash_size;
74static int lru_hash_lookup_test_entries = 32;74static int lru_hash_lookup_test_entries = 32;
75static uint32_t max_cnt = 1000000;75static uint32_t max_cnt = 10000;
76 76
77static int check_test_flags(enum test_type t)77static int check_test_flags(enum test_type t)
78{78{
scripts/bpf_doc.py+71−7
@@ -10,6 +10,9 @@ from __future__ import print_function · 9 unmodified lines
10import argparse10import argparse
11import re11import re
12import sys, os12import sys, os
13import subprocess
14
15helpersDocStart = 'Start of BPF helper function descriptions:'
13 16
14class NoHelperFound(BaseException):17class NoHelperFound(BaseException):
15 pass18 pass
@@ -47,6 +50,10 @@ class Helper(APIElement): · 31 unmodified lines
47 @desc: textual description of the helper function50 @desc: textual description of the helper function
48 @ret: description of the return value of the helper function51 @ret: description of the return value of the helper function
49 """52 """
53 def __init__(self, *args, **kwargs):
54 super().__init__(*args, **kwargs)
55 self.enum_val = None
56
50 def proto_break_down(self):57 def proto_break_down(self):
51 """58 """
52 Break down helper function protocol into smaller chunks: return type,59 Break down helper function protocol into smaller chunks: return type,
@@ -89,6 +96,7 @@ class HeaderParser(object): · 36 unmodified lines
89 self.commands = []96 self.commands = []
90 self.desc_unique_helpers = set()97 self.desc_unique_helpers = set()
91 self.define_unique_helpers = []98 self.define_unique_helpers = []
99 self.helper_enum_vals = {}
92 self.desc_syscalls = []100 self.desc_syscalls = []
93 self.enum_syscalls = []101 self.enum_syscalls = []
94 102
@@ -233,7 +241,7 @@ class HeaderParser(object): · 138 unmodified lines
233 self.enum_syscalls = re.findall('(BPF\w+)+', bpf_cmd_str)241 self.enum_syscalls = re.findall('(BPF\w+)+', bpf_cmd_str)
234 242
235 def parse_desc_helpers(self):243 def parse_desc_helpers(self):
236 self.seek_to('* Start of BPF helper function descriptions:',244 self.seek_to(helpersDocStart,
237 'Could not find start of eBPF helper descriptions list')245 'Could not find start of eBPF helper descriptions list')
238 while True:246 while True:
239 try:247 try:
@@ -245,30 +253,54 @@ class HeaderParser(object): · 5 unmodified lines
245 break253 break
246 254
247 def parse_define_helpers(self):255 def parse_define_helpers(self):
248 # Parse the number of FN(...) in #define __BPF_FUNC_MAPPER to compare256 # Parse FN(...) in #define __BPF_FUNC_MAPPER to compare later with the
249 # later with the number of unique function names present in description.257 # number of unique function names present in description and use the
258 # correct enumeration value.
250 # Note: seek_to(..) discards the first line below the target search text,259 # Note: seek_to(..) discards the first line below the target search text,
251 # resulting in FN(unspec) being skipped and not added to self.define_unique_helpers.260 # resulting in FN(unspec) being skipped and not added to self.define_unique_helpers.
252 self.seek_to('#define __BPF_FUNC_MAPPER(FN)',261 self.seek_to('#define __BPF_FUNC_MAPPER(FN)',
253 'Could not find start of eBPF helper definition list')262 'Could not find start of eBPF helper definition list')
254 # Searches for either one or more FN(\w+) defines or a backslash for newline263 # Searches for one FN(\w+) define or a backslash for newline
255 p = re.compile('\s*(FN\(\w+\))+|\\\\')264 p = re.compile('\s*FN\((\w+)\)|\\\\')
256 fn_defines_str = ''265 fn_defines_str = ''
266 i = 1 # 'unspec' is skipped as mentioned above
257 while True:267 while True:
258 capture = p.match(self.line)268 capture = p.match(self.line)
259 if capture:269 if capture:
260 fn_defines_str += self.line270 fn_defines_str += self.line
271 self.helper_enum_vals[capture.expand(r'bpf_\1')] = i
272 i += 1
261 else:273 else:
262 break274 break
263 self.line = self.reader.readline()275 self.line = self.reader.readline()
264 # Find the number of occurences of FN(\w+)276 # Find the number of occurences of FN(\w+)
265 self.define_unique_helpers = re.findall('FN\(\w+\)', fn_defines_str)277 self.define_unique_helpers = re.findall('FN\(\w+\)', fn_defines_str)
266 278
279 def assign_helper_values(self):
280 seen_helpers = set()
281 for helper in self.helpers:
282 proto = helper.proto_break_down()
283 name = proto['name']
284 try:
285 enum_val = self.helper_enum_vals[name]
286 except KeyError:
287 raise Exception("Helper %s is missing from enum bpf_func_id" % name)
288
289 # Enforce current practice of having the descriptions ordered
290 # by enum value.
291 seen_helpers.add(name)
292 desc_val = len(seen_helpers)
293 if desc_val != enum_val:
294 raise Exception("Helper %s comment order (#%d) must be aligned with its position (#%d) in enum bpf_func_id" % (name, desc_val, enum_val))
295
296 helper.enum_val = enum_val
297
267 def run(self):298 def run(self):
268 self.parse_desc_syscall()299 self.parse_desc_syscall()
269 self.parse_enum_syscall()300 self.parse_enum_syscall()
270 self.parse_desc_helpers()301 self.parse_desc_helpers()
271 self.parse_define_helpers()302 self.parse_define_helpers()
303 self.assign_helper_values()
272 self.reader.close()304 self.reader.close()
273 305
274###############################################################################306###############################################################################
@@ -357,6 +389,31 @@ class PrinterRST(Printer): · 82 unmodified lines
357 389
358 print('')390 print('')
359 391
392 def get_kernel_version(self):
393 try:
394 version = subprocess.run(['git', 'describe'], cwd=linuxRoot,
395 capture_output=True, check=True)
396 version = version.stdout.decode().rstrip()
397 except:
398 try:
399 version = subprocess.run(['make', 'kernelversion'], cwd=linuxRoot,
400 capture_output=True, check=True)
401 version = version.stdout.decode().rstrip()
402 except:
403 return 'Linux'
404 return 'Linux {version}'.format(version=version)
405
406 def get_last_doc_update(self, delimiter):
407 try:
408 cmd = ['git', 'log', '-1', '--pretty=format:%cs', '--no-patch',
409 '-L',
410 '/{}/,/\*\//:include/uapi/linux/bpf.h'.format(delimiter)]
411 date = subprocess.run(cmd, cwd=linuxRoot,
412 capture_output=True, check=True)
413 return date.stdout.decode().rstrip()
414 except:
415 return ''
416
360class PrinterHelpersRST(PrinterRST):417class PrinterHelpersRST(PrinterRST):
361 """418 """
362 A printer for dumping collected information about helpers as a ReStructured419 A printer for dumping collected information about helpers as a ReStructured
@@ -378,6 +435,8 @@ list of eBPF helper functions · 15 unmodified lines
378-------------------------------------------------------------------------------435-------------------------------------------------------------------------------
379 436
380:Manual section: 7437:Manual section: 7
438:Version: {version}
439{date_field}{date}
381 440
382DESCRIPTION441DESCRIPTION
383===========442===========
@@ -410,8 +469,13 @@ kernel at the top). · 26 unmodified lines
410HELPERS469HELPERS
411=======470=======
412'''471'''
472 kernelVersion = self.get_kernel_version()
473 lastUpdate = self.get_last_doc_update(helpersDocStart)
474
413 PrinterRST.print_license(self)475 PrinterRST.print_license(self)
414 print(header)476 print(header.format(version=kernelVersion,
477 date_field = ':Date: ' if lastUpdate else '',
478 date=lastUpdate))
415 479
416 def print_footer(self):480 def print_footer(self):
417 footer = '''481 footer = '''
@@ -761,7 +825,7 @@ class PrinterHelpers(Printer): · 343 unmodified lines
761 comma = ', '825 comma = ', '
762 print(one_arg, end='')826 print(one_arg, end='')
763 827
764 print(') = (void *) %d;' % len(self.seen_helpers))828 print(') = (void *) %d;' % helper.enum_val)
765 print('')829 print('')
766 830
767###############################################################################831###############################################################################
tools/bpf/bpftool/btf_dumper.c+1−1
@@ -452,7 +452,7 @@ static int btf_dumper_int(const struct btf_type *t, __u8 bit_offset, · 451 unmodified lines
452 *(char *)data);452 *(char *)data);
453 break;453 break;
454 case BTF_INT_BOOL:454 case BTF_INT_BOOL:
455 jsonw_bool(jw, *(int *)data);455 jsonw_bool(jw, *(bool *)data);
456 break;456 break;
457 default:457 default:
458 /* shouldn't happen */458 /* shouldn't happen */
tools/bpf/bpftool/link.c+35−0
@@ -83,6 +83,29 @@ static bool is_iter_map_target(const char *target_name) · 82 unmodified lines
83 strcmp(target_name, "bpf_sk_storage_map") == 0;83 strcmp(target_name, "bpf_sk_storage_map") == 0;
84}84}
85 85
86static bool is_iter_cgroup_target(const char *target_name)
87{
88 return strcmp(target_name, "cgroup") == 0;
89}
90
91static const char *cgroup_order_string(__u32 order)
92{
93 switch (order) {
94 case BPF_CGROUP_ITER_ORDER_UNSPEC:
95 return "order_unspec";
96 case BPF_CGROUP_ITER_SELF_ONLY:
97 return "self_only";
98 case BPF_CGROUP_ITER_DESCENDANTS_PRE:
99 return "descendants_pre";
100 case BPF_CGROUP_ITER_DESCENDANTS_POST:
101 return "descendants_post";
102 case BPF_CGROUP_ITER_ANCESTORS_UP:
103 return "ancestors_up";
104 default: /* won't happen */
105 return "unknown";
106 }
107}
108
86static void show_iter_json(struct bpf_link_info *info, json_writer_t *wtr)109static void show_iter_json(struct bpf_link_info *info, json_writer_t *wtr)
87{110{
88 const char *target_name = u64_to_ptr(info->iter.target_name);111 const char *target_name = u64_to_ptr(info->iter.target_name);
@@ -91,6 +114,12 @@ static void show_iter_json(struct bpf_link_info *info, json_writer_t *wtr) · 2 unmodified lines
91 114
92 if (is_iter_map_target(target_name))115 if (is_iter_map_target(target_name))
93 jsonw_uint_field(wtr, "map_id", info->iter.map.map_id);116 jsonw_uint_field(wtr, "map_id", info->iter.map.map_id);
117
118 if (is_iter_cgroup_target(target_name)) {
119 jsonw_lluint_field(wtr, "cgroup_id", info->iter.cgroup.cgroup_id);
120 jsonw_string_field(wtr, "order",
121 cgroup_order_string(info->iter.cgroup.order));
122 }
94}123}
95 124
96static int get_prog_info(int prog_id, struct bpf_prog_info *info)125static int get_prog_info(int prog_id, struct bpf_prog_info *info)
@@ -208,6 +237,12 @@ static void show_iter_plain(struct bpf_link_info *info) · 111 unmodified lines
208 237
209 if (is_iter_map_target(target_name))238 if (is_iter_map_target(target_name))
210 printf("map_id %u ", info->iter.map.map_id);239 printf("map_id %u ", info->iter.map.map_id);
240
241 if (is_iter_cgroup_target(target_name)) {
242 printf("cgroup_id %llu ", info->iter.cgroup.cgroup_id);
243 printf("order %s ",
244 cgroup_order_string(info->iter.cgroup.order));
245 }
211}246}
212 247
213static int show_link_close_plain(int fd, struct bpf_link_info *info)248static int show_link_close_plain(int fd, struct bpf_link_info *info)
tools/include/uapi/linux/bpf.h+69−14
@@ -87,10 +87,29 @@ struct bpf_cgroup_storage_key { · 86 unmodified lines
87 __u32 attach_type; /* program attach type (enum bpf_attach_type) */87 __u32 attach_type; /* program attach type (enum bpf_attach_type) */
88};88};
89 89
90enum bpf_cgroup_iter_order {
91 BPF_CGROUP_ITER_ORDER_UNSPEC = 0,
92 BPF_CGROUP_ITER_SELF_ONLY, /* process only a single object. */
93 BPF_CGROUP_ITER_DESCENDANTS_PRE, /* walk descendants in pre-order. */
94 BPF_CGROUP_ITER_DESCENDANTS_POST, /* walk descendants in post-order. */
95 BPF_CGROUP_ITER_ANCESTORS_UP, /* walk ancestors upward. */
96};
97
90union bpf_iter_link_info {98union bpf_iter_link_info {
91 struct {99 struct {
92 __u32 map_fd;100 __u32 map_fd;
93 } map;101 } map;
102 struct {
103 enum bpf_cgroup_iter_order order;
104
105 /* At most one of cgroup_fd and cgroup_id can be non-zero. If
106 * both are zero, the walk starts from the default cgroup v2
107 * root. For walking v1 hierarchy, one should always explicitly
108 * specify cgroup_fd.
109 */
110 __u32 cgroup_fd;
111 __u64 cgroup_id;
112 } cgroup;
94};113};
95 114
96/* BPF syscall commands, see bpf(2) man-page for more details. */115/* BPF syscall commands, see bpf(2) man-page for more details. */
@@ -4437,7 +4456,7 @@ union bpf_attr { · 4340 unmodified lines
4437 *4456 *
4438 * **-EEXIST** if the option already exists.4457 * **-EEXIST** if the option already exists.
4439 *4458 *
4440 * **-EFAULT** on failrue to parse the existing header options.4459 * **-EFAULT** on failure to parse the existing header options.
4441 *4460 *
4442 * **-EPERM** if the helper cannot be used under the current4461 * **-EPERM** if the helper cannot be used under the current
4443 * *skops*\ **->op**.4462 * *skops*\ **->op**.
@@ -4646,7 +4665,7 @@ union bpf_attr { · 202 unmodified lines
4646 * a *map* with *task* as the **key**. From this4665 * a *map* with *task* as the **key**. From this
4647 * perspective, the usage is not much different from4666 * perspective, the usage is not much different from
4648 * **bpf_map_lookup_elem**\ (*map*, **&**\ *task*) except this4667 * **bpf_map_lookup_elem**\ (*map*, **&**\ *task*) except this
4649 * helper enforces the key must be an task_struct and the map must also4668 * helper enforces the key must be a task_struct and the map must also
4650 * be a **BPF_MAP_TYPE_TASK_STORAGE**.4669 * be a **BPF_MAP_TYPE_TASK_STORAGE**.
4651 *4670 *
4652 * Underneath, the value is stored locally at *task* instead of4671 * Underneath, the value is stored locally at *task* instead of
@@ -4704,7 +4723,7 @@ union bpf_attr { · 51 unmodified lines
4704 *4723 *
4705 * long bpf_ima_inode_hash(struct inode *inode, void *dst, u32 size)4724 * long bpf_ima_inode_hash(struct inode *inode, void *dst, u32 size)
4706 * Description4725 * Description
4707 * Returns the stored IMA hash of the *inode* (if it's avaialable).4726 * Returns the stored IMA hash of the *inode* (if it's available).
4708 * If the hash is larger than *size*, then only *size*4727 * If the hash is larger than *size*, then only *size*
4709 * bytes will be copied to *dst*4728 * bytes will be copied to *dst*
4710 * Return4729 * Return
@@ -4728,12 +4747,12 @@ union bpf_attr { · 17 unmodified lines
4728 *4747 *
4729 * The argument *len_diff* can be used for querying with a planned4748 * The argument *len_diff* can be used for querying with a planned
4730 * size change. This allows to check MTU prior to changing packet4749 * size change. This allows to check MTU prior to changing packet
4731 * ctx. Providing an *len_diff* adjustment that is larger than the4750 * ctx. Providing a *len_diff* adjustment that is larger than the
4732 * actual packet size (resulting in negative packet size) will in4751 * actual packet size (resulting in negative packet size) will in
4733 * principle not exceed the MTU, why it is not considered a4752 * principle not exceed the MTU, which is why it is not considered
4734 * failure. Other BPF-helpers are needed for performing the4753 * a failure. Other BPF helpers are needed for performing the
4735 * planned size change, why the responsability for catch a negative4754 * planned size change; therefore the responsibility for catching
4736 * packet size belong in those helpers.4755 * a negative packet size belongs in those helpers.
4737 *4756 *
4738 * Specifying *ifindex* zero means the MTU check is performed4757 * Specifying *ifindex* zero means the MTU check is performed
4739 * against the current net device. This is practical if this isn't4758 * against the current net device. This is practical if this isn't
@@ -5085,17 +5104,29 @@ union bpf_attr { · 345 unmodified lines
5085 *5104 *
5086 * int bpf_get_retval(void)5105 * int bpf_get_retval(void)
5087 * Description5106 * Description
5088 * Get the syscall's return value that will be returned to userspace.5107 * Get the BPF program's return value that will be returned to the upper layers.
5089 *5108 *
5090 * This helper is currently supported by cgroup programs only.5109 * This helper is currently supported by cgroup programs and only by the hooks
5110 * where BPF program's return value is returned to the userspace via errno.
5091 * Return5111 * Return
5092 * The syscall's return value.5112 * The BPF program's return value.
5093 *5113 *
5094 * int bpf_set_retval(int retval)5114 * int bpf_set_retval(int retval)
5095 * Description5115 * Description
5096 * Set the syscall's return value that will be returned to userspace.5116 * Set the BPF program's return value that will be returned to the upper layers.
5117 *
5118 * This helper is currently supported by cgroup programs and only by the hooks
5119 * where BPF program's return value is returned to the userspace via errno.
5120 *
5121 * Note that there is the following corner case where the program exports an error
5122 * via bpf_set_retval but signals success via 'return 1':
5123 *
5124 * bpf_set_retval(-EPERM);
5125 * return 1;
5126 *
5127 * In this case, the BPF program's return value will use helper's -EPERM. This
5128 * still holds true for cgroup/bind{4,6} which supports extra 'return 3' success case.
5097 *5129 *
5098 * This helper is currently supported by cgroup programs only.
5099 * Return5130 * Return
5100 * 0 on success, or a negative error in case of failure.5131 * 0 on success, or a negative error in case of failure.
5101 *5132 *
@@ -5628,6 +5659,11 @@ enum { · 526 unmodified lines
5628 BPF_F_SEQ_NUMBER = (1ULL << 3),5659 BPF_F_SEQ_NUMBER = (1ULL << 3),
5629};5660};
5630 5661
5662/* BPF_FUNC_skb_get_tunnel_key flags. */
5663enum {
5664 BPF_F_TUNINFO_FLAGS = (1ULL << 4),
5665};
5666
5631/* BPF_FUNC_perf_event_output, BPF_FUNC_perf_event_read and5667/* BPF_FUNC_perf_event_output, BPF_FUNC_perf_event_read and
5632 * BPF_FUNC_perf_event_read_value flags.5668 * BPF_FUNC_perf_event_read_value flags.
5633 */5669 */
@@ -5817,7 +5853,10 @@ struct bpf_tunnel_key { · 183 unmodified lines
5817 };5853 };
5818 __u8 tunnel_tos;5854 __u8 tunnel_tos;
5819 __u8 tunnel_ttl;5855 __u8 tunnel_ttl;
5820 __u16 tunnel_ext; /* Padding, future use. */5856 union {
5857 __u16 tunnel_ext; /* compat */
5858 __be16 tunnel_flags;
5859 };
5821 __u32 tunnel_label;5860 __u32 tunnel_label;
5822 union {5861 union {
5823 __u32 local_ipv4;5862 __u32 local_ipv4;
@@ -5861,6 +5900,11 @@ enum bpf_ret_code { · 37 unmodified lines
5861 * represented by BPF_REDIRECT above).5900 * represented by BPF_REDIRECT above).
5862 */5901 */
5863 BPF_LWT_REROUTE = 128,5902 BPF_LWT_REROUTE = 128,
5903 /* BPF_FLOW_DISSECTOR_CONTINUE: used by BPF_PROG_TYPE_FLOW_DISSECTOR
5904 * to indicate that no custom dissection was performed, and
5905 * fallback to standard dissector is requested.
5906 */
5907 BPF_FLOW_DISSECTOR_CONTINUE = 129,
5864};5908};
5865 5909
5866struct bpf_sock {5910struct bpf_sock {
@@ -6159,11 +6203,22 @@ struct bpf_link_info { · 292 unmodified lines
6159 struct {6203 struct {
6160 __aligned_u64 target_name; /* in/out: target_name buffer ptr */6204 __aligned_u64 target_name; /* in/out: target_name buffer ptr */
6161 __u32 target_name_len; /* in/out: target_name buffer len */6205 __u32 target_name_len; /* in/out: target_name buffer len */
6206
6207 /* If the iter specific field is 32 bits, it can be put
6208 * in the first or second union. Otherwise it should be
6209 * put in the second union.
6210 */
6162 union {6211 union {
6163 struct {6212 struct {
6164 __u32 map_id;6213 __u32 map_id;
6165 } map;6214 } map;
6166 };6215 };
6216 union {
6217 struct {
6218 __u64 cgroup_id;
6219 __u32 order;
6220 } cgroup;
6221 };
6167 } iter;6222 } iter;
6168 struct {6223 struct {
6169 __u32 netns_ino;6224 __u32 netns_ino;
tools/lib/bpf/bpf_helpers.h+13−6
@@ -131,7 +131,7 @@ · 130 unmodified lines
131/*131/*
132 * Helper function to perform a tail call with a constant/immediate map slot.132 * Helper function to perform a tail call with a constant/immediate map slot.
133 */133 */
134#if __clang_major__ >= 8 && defined(__bpf__)134#if (!defined(__clang__) || __clang_major__ >= 8) && defined(__bpf__)
135static __always_inline void135static __always_inline void
136bpf_tail_call_static(void *ctx, const void *map, const __u32 slot)136bpf_tail_call_static(void *ctx, const void *map, const __u32 slot)
137{137{
@@ -139,8 +139,8 @@ bpf_tail_call_static(void *ctx, const void *map, const __u32 slot) · 1 unmodified line
139 __bpf_unreachable();139 __bpf_unreachable();
140 140
141 /*141 /*
142 * Provide a hard guarantee that LLVM won't optimize setting r2 (map142 * Provide a hard guarantee that the compiler won't optimize setting r2
143 * pointer) and r3 (constant map index) from _different paths_ ending143 * (map pointer) and r3 (constant map index) from _different paths_ ending
144 * up at the _same_ call insn as otherwise we won't be able to use the144 * up at the _same_ call insn as otherwise we won't be able to use the
145 * jmpq/nopl retpoline-free patching by the x86-64 JIT in the kernel145 * jmpq/nopl retpoline-free patching by the x86-64 JIT in the kernel
146 * given they mismatch. See also d2e4c1e6c294 ("bpf: Constant map key146 * given they mismatch. See also d2e4c1e6c294 ("bpf: Constant map key
@@ -148,12 +148,19 @@ bpf_tail_call_static(void *ctx, const void *map, const __u32 slot) · 1 unmodified line
148 *148 *
149 * Note on clobber list: we need to stay in-line with BPF calling149 * Note on clobber list: we need to stay in-line with BPF calling
150 * convention, so even if we don't end up using r0, r4, r5, we need150 * convention, so even if we don't end up using r0, r4, r5, we need
151 * to mark them as clobber so that LLVM doesn't end up using them151 * to mark them as clobber so that the compiler doesn't end up using
152 * before / after the call.152 * them before / after the call.
153 */153 */
154 asm volatile("r1 = %[ctx]\n\t"154 asm volatile(
155#ifdef __clang__
156 "r1 = %[ctx]\n\t"
155 "r2 = %[map]\n\t"157 "r2 = %[map]\n\t"
156 "r3 = %[slot]\n\t"158 "r3 = %[slot]\n\t"
159#else
160 "mov %%r1,%[ctx]\n\t"
161 "mov %%r2,%[map]\n\t"
162 "mov %%r3,%[slot]\n\t"
163#endif
157 "call 12"164 "call 12"
158 :: [ctx]"r"(ctx), [map]"r"(map), [slot]"i"(slot)165 :: [ctx]"r"(ctx), [map]"r"(map), [slot]"i"(slot)
159 : "r0", "r1", "r2", "r3", "r4", "r5");166 : "r0", "r1", "r2", "r3", "r4", "r5");
tools/lib/bpf/skel_internal.h+23−0
@@ -251,6 +251,29 @@ static inline int skel_map_update_elem(int fd, const void *key, · 250 unmodified lines
251 return skel_sys_bpf(BPF_MAP_UPDATE_ELEM, &attr, attr_sz);251 return skel_sys_bpf(BPF_MAP_UPDATE_ELEM, &attr, attr_sz);
252}252}
253 253
254static inline int skel_map_delete_elem(int fd, const void *key)
255{
256 const size_t attr_sz = offsetofend(union bpf_attr, flags);
257 union bpf_attr attr;
258
259 memset(&attr, 0, attr_sz);
260 attr.map_fd = fd;
261 attr.key = (long)key;
262
263 return skel_sys_bpf(BPF_MAP_DELETE_ELEM, &attr, attr_sz);
264}
265
266static inline int skel_map_get_fd_by_id(__u32 id)
267{
268 const size_t attr_sz = offsetofend(union bpf_attr, flags);
269 union bpf_attr attr;
270
271 memset(&attr, 0, attr_sz);
272 attr.map_id = id;
273
274 return skel_sys_bpf(BPF_MAP_GET_FD_BY_ID, &attr, attr_sz);
275}
276
254static inline int skel_raw_tracepoint_open(const char *name, int prog_fd)277static inline int skel_raw_tracepoint_open(const char *name, int prog_fd)
255{278{
256 const size_t attr_sz = offsetofend(union bpf_attr, raw_tracepoint.prog_fd);279 const size_t attr_sz = offsetofend(union bpf_attr, raw_tracepoint.prog_fd);
tools/testing/selftests/bpf/DENYLIST.s390x+4−0
@@ -66,3 +66,7 @@ select_reuseport # intermittently fails on new s390x set · 65 unmodified lines
66xdp_synproxy # JIT does not support calling kernel function (kfunc)66xdp_synproxy # JIT does not support calling kernel function (kfunc)
67unpriv_bpf_disabled # fentry67unpriv_bpf_disabled # fentry
68lru_bug # prog 'printk': failed to auto-attach: -52468lru_bug # prog 'printk': failed to auto-attach: -524
69setget_sockopt # attach unexpected error: -524 (trampoline)
70cb_refs # expected error message unexpected error: -524 (trampoline)
71cgroup_hierarchical_stats # JIT does not support calling kernel function (kfunc)
72htab_update # failed to attach: ERROR: strerror_r(-524)=22 (trampoline)
tools/testing/selftests/bpf/Makefile+19−18
@@ -45,7 +45,7 @@ ifneq ($(BPF_GCC),) · 44 unmodified lines
45TEST_GEN_PROGS += test_progs-bpf_gcc45TEST_GEN_PROGS += test_progs-bpf_gcc
46endif46endif
47 47
48TEST_GEN_FILES = test_lwt_ip_encap.o test_tc_edt.o48TEST_GEN_FILES = test_lwt_ip_encap.bpf.o test_tc_edt.bpf.o
49TEST_FILES = xsk_prereqs.sh $(wildcard progs/btf_dump_test_case_*.c)49TEST_FILES = xsk_prereqs.sh $(wildcard progs/btf_dump_test_case_*.c)
50 50
51# Order correspond to 'make run_tests' order51# Order correspond to 'make run_tests' order
@@ -323,6 +323,7 @@ $(OUTPUT)/test_l4lb_noinline.o: BPF_CFLAGS += -fno-inline · 271 unmodified lines
323$(OUTPUT)/test_xdp_noinline.o: BPF_CFLAGS += -fno-inline323$(OUTPUT)/test_xdp_noinline.o: BPF_CFLAGS += -fno-inline
324 324
325$(OUTPUT)/flow_dissector_load.o: flow_dissector_load.h325$(OUTPUT)/flow_dissector_load.o: flow_dissector_load.h
326$(OUTPUT)/cgroup_getset_retval_hooks.o: cgroup_getset_retval_hooks.h
326 327
327# Build BPF object using Clang328# Build BPF object using Clang
328# $1 - input .c file329# $1 - input .c file
@@ -357,17 +358,17 @@ LSKELS := kfunc_call_test.c fentry_test.c fexit_test.c fexit_sleep.c \ · 28 unmodified lines
357LSKELS_EXTRA := test_ksyms_module.c test_ksyms_weak.c kfunc_call_test_subprog.c358LSKELS_EXTRA := test_ksyms_module.c test_ksyms_weak.c kfunc_call_test_subprog.c
358SKEL_BLACKLIST += $$(LSKELS)359SKEL_BLACKLIST += $$(LSKELS)
359 360
360test_static_linked.skel.h-deps := test_static_linked1.o test_static_linked2.o361test_static_linked.skel.h-deps := test_static_linked1.bpf.o test_static_linked2.bpf.o
361linked_funcs.skel.h-deps := linked_funcs1.o linked_funcs2.o362linked_funcs.skel.h-deps := linked_funcs1.bpf.o linked_funcs2.bpf.o
362linked_vars.skel.h-deps := linked_vars1.o linked_vars2.o363linked_vars.skel.h-deps := linked_vars1.bpf.o linked_vars2.bpf.o
363linked_maps.skel.h-deps := linked_maps1.o linked_maps2.o364linked_maps.skel.h-deps := linked_maps1.bpf.o linked_maps2.bpf.o
364# In the subskeleton case, we want the test_subskeleton_lib.subskel.h file365# In the subskeleton case, we want the test_subskeleton_lib.subskel.h file
365# but that's created as a side-effect of the skel.h generation.366# but that's created as a side-effect of the skel.h generation.
366test_subskeleton.skel.h-deps := test_subskeleton_lib2.o test_subskeleton_lib.o test_subskeleton.o367test_subskeleton.skel.h-deps := test_subskeleton_lib2.bpf.o test_subskeleton_lib.bpf.o test_subskeleton.bpf.o
367test_subskeleton_lib.skel.h-deps := test_subskeleton_lib2.o test_subskeleton_lib.o368test_subskeleton_lib.skel.h-deps := test_subskeleton_lib2.bpf.o test_subskeleton_lib.bpf.o
368test_usdt.skel.h-deps := test_usdt.o test_usdt_multispec.o369test_usdt.skel.h-deps := test_usdt.bpf.o test_usdt_multispec.bpf.o
369 370
370LINKED_BPF_SRCS := $(patsubst %.o,%.c,$(foreach skel,$(LINKED_SKELS),$($(skel)-deps)))371LINKED_BPF_SRCS := $(patsubst %.bpf.o,%.c,$(foreach skel,$(LINKED_SKELS),$($(skel)-deps)))
371 372
372# Set up extra TRUNNER_XXX "temporary" variables in the environment (relies on373# Set up extra TRUNNER_XXX "temporary" variables in the environment (relies on
373# $eval()) and pass control to DEFINE_TEST_RUNNER_RULES.374# $eval()) and pass control to DEFINE_TEST_RUNNER_RULES.
@@ -385,7 +386,7 @@ TRUNNER_EXTRA_OBJS := $$(patsubst %.c,$$(TRUNNER_OUTPUT)/%.o, \ · 11 unmodified lines
385TRUNNER_EXTRA_HDRS := $$(filter %.h,$(TRUNNER_EXTRA_SOURCES))386TRUNNER_EXTRA_HDRS := $$(filter %.h,$(TRUNNER_EXTRA_SOURCES))
386TRUNNER_TESTS_HDR := $(TRUNNER_TESTS_DIR)/tests.h387TRUNNER_TESTS_HDR := $(TRUNNER_TESTS_DIR)/tests.h
387TRUNNER_BPF_SRCS := $$(notdir $$(wildcard $(TRUNNER_BPF_PROGS_DIR)/*.c))388TRUNNER_BPF_SRCS := $$(notdir $$(wildcard $(TRUNNER_BPF_PROGS_DIR)/*.c))
388TRUNNER_BPF_OBJS := $$(patsubst %.c,$$(TRUNNER_OUTPUT)/%.o, $$(TRUNNER_BPF_SRCS))389TRUNNER_BPF_OBJS := $$(patsubst %.c,$$(TRUNNER_OUTPUT)/%.bpf.o, $$(TRUNNER_BPF_SRCS))
389TRUNNER_BPF_SKELS := $$(patsubst %.c,$$(TRUNNER_OUTPUT)/%.skel.h, \390TRUNNER_BPF_SKELS := $$(patsubst %.c,$$(TRUNNER_OUTPUT)/%.skel.h, \
390 $$(filter-out $(SKEL_BLACKLIST) $(LINKED_BPF_SRCS),\391 $$(filter-out $(SKEL_BLACKLIST) $(LINKED_BPF_SRCS),\
391 $$(TRUNNER_BPF_SRCS)))392 $$(TRUNNER_BPF_SRCS)))
@@ -415,7 +416,7 @@ endif · 23 unmodified lines
415# input/output directory combination416# input/output directory combination
416ifeq ($($(TRUNNER_BPF_PROGS_DIR)$(if $2,-)$2-bpfobjs),)417ifeq ($($(TRUNNER_BPF_PROGS_DIR)$(if $2,-)$2-bpfobjs),)
417$(TRUNNER_BPF_PROGS_DIR)$(if $2,-)$2-bpfobjs := y418$(TRUNNER_BPF_PROGS_DIR)$(if $2,-)$2-bpfobjs := y
418$(TRUNNER_BPF_OBJS): $(TRUNNER_OUTPUT)/%.o: \419$(TRUNNER_BPF_OBJS): $(TRUNNER_OUTPUT)/%.bpf.o: \
419 $(TRUNNER_BPF_PROGS_DIR)/%.c \420 $(TRUNNER_BPF_PROGS_DIR)/%.c \
420 $(TRUNNER_BPF_PROGS_DIR)/*.h \421 $(TRUNNER_BPF_PROGS_DIR)/*.h \
421 $$(INCLUDE_DIR)/vmlinux.h \422 $$(INCLUDE_DIR)/vmlinux.h \
@@ -425,25 +426,25 @@ $(TRUNNER_BPF_OBJS): $(TRUNNER_OUTPUT)/%.o: \ · 3 unmodified lines
425 $$(call $(TRUNNER_BPF_BUILD_RULE),$$<,$$@, \426 $$(call $(TRUNNER_BPF_BUILD_RULE),$$<,$$@, \
426 $(TRUNNER_BPF_CFLAGS))427 $(TRUNNER_BPF_CFLAGS))
427 428
428$(TRUNNER_BPF_SKELS): %.skel.h: %.o $(BPFTOOL) | $(TRUNNER_OUTPUT)429$(TRUNNER_BPF_SKELS): %.skel.h: %.bpf.o $(BPFTOOL) | $(TRUNNER_OUTPUT)
429 $$(call msg,GEN-SKEL,$(TRUNNER_BINARY),$$@)430 $$(call msg,GEN-SKEL,$(TRUNNER_BINARY),$$@)
430 $(Q)$$(BPFTOOL) gen object $$(<:.o=.linked1.o) $$<431 $(Q)$$(BPFTOOL) gen object $$(<:.o=.linked1.o) $$<
431 $(Q)$$(BPFTOOL) gen object $$(<:.o=.linked2.o) $$(<:.o=.linked1.o)432 $(Q)$$(BPFTOOL) gen object $$(<:.o=.linked2.o) $$(<:.o=.linked1.o)
432 $(Q)$$(BPFTOOL) gen object $$(<:.o=.linked3.o) $$(<:.o=.linked2.o)433 $(Q)$$(BPFTOOL) gen object $$(<:.o=.linked3.o) $$(<:.o=.linked2.o)
433 $(Q)diff $$(<:.o=.linked2.o) $$(<:.o=.linked3.o)434 $(Q)diff $$(<:.o=.linked2.o) $$(<:.o=.linked3.o)
434 $(Q)$$(BPFTOOL) gen skeleton $$(<:.o=.linked3.o) name $$(notdir $$(<:.o=)) > $$@435 $(Q)$$(BPFTOOL) gen skeleton $$(<:.o=.linked3.o) name $$(notdir $$(<:.bpf.o=)) > $$@
435 $(Q)$$(BPFTOOL) gen subskeleton $$(<:.o=.linked3.o) name $$(notdir $$(<:.o=)) > $$(@:.skel.h=.subskel.h)436 $(Q)$$(BPFTOOL) gen subskeleton $$(<:.o=.linked3.o) name $$(notdir $$(<:.bpf.o=)) > $$(@:.skel.h=.subskel.h)
436 437
437$(TRUNNER_BPF_LSKELS): %.lskel.h: %.o $(BPFTOOL) | $(TRUNNER_OUTPUT)438$(TRUNNER_BPF_LSKELS): %.lskel.h: %.bpf.o $(BPFTOOL) | $(TRUNNER_OUTPUT)
438 $$(call msg,GEN-SKEL,$(TRUNNER_BINARY),$$@)439 $$(call msg,GEN-SKEL,$(TRUNNER_BINARY),$$@)
439 $(Q)$$(BPFTOOL) gen object $$(<:.o=.llinked1.o) $$<440 $(Q)$$(BPFTOOL) gen object $$(<:.o=.llinked1.o) $$<
440 $(Q)$$(BPFTOOL) gen object $$(<:.o=.llinked2.o) $$(<:.o=.llinked1.o)441 $(Q)$$(BPFTOOL) gen object $$(<:.o=.llinked2.o) $$(<:.o=.llinked1.o)
441 $(Q)$$(BPFTOOL) gen object $$(<:.o=.llinked3.o) $$(<:.o=.llinked2.o)442 $(Q)$$(BPFTOOL) gen object $$(<:.o=.llinked3.o) $$(<:.o=.llinked2.o)
442 $(Q)diff $$(<:.o=.llinked2.o) $$(<:.o=.llinked3.o)443 $(Q)diff $$(<:.o=.llinked2.o) $$(<:.o=.llinked3.o)
443 $(Q)$$(BPFTOOL) gen skeleton -L $$(<:.o=.llinked3.o) name $$(notdir $$(<:.o=_lskel)) > $$@444 $(Q)$$(BPFTOOL) gen skeleton -L $$(<:.o=.llinked3.o) name $$(notdir $$(<:.bpf.o=_lskel)) > $$@
444 445
445$(TRUNNER_BPF_SKELS_LINKED): $(TRUNNER_BPF_OBJS) $(BPFTOOL) | $(TRUNNER_OUTPUT)446$(TRUNNER_BPF_SKELS_LINKED): $(TRUNNER_BPF_OBJS) $(BPFTOOL) | $(TRUNNER_OUTPUT)
446 $$(call msg,LINK-BPF,$(TRUNNER_BINARY),$$(@:.skel.h=.o))447 $$(call msg,LINK-BPF,$(TRUNNER_BINARY),$$(@:.skel.h=.bpf.o))
447 $(Q)$$(BPFTOOL) gen object $$(@:.skel.h=.linked1.o) $$(addprefix $(TRUNNER_OUTPUT)/,$$($$(@F)-deps))448 $(Q)$$(BPFTOOL) gen object $$(@:.skel.h=.linked1.o) $$(addprefix $(TRUNNER_OUTPUT)/,$$($$(@F)-deps))
448 $(Q)$$(BPFTOOL) gen object $$(@:.skel.h=.linked2.o) $$(@:.skel.h=.linked1.o)449 $(Q)$$(BPFTOOL) gen object $$(@:.skel.h=.linked2.o) $$(@:.skel.h=.linked1.o)
449 $(Q)$$(BPFTOOL) gen object $$(@:.skel.h=.linked3.o) $$(@:.skel.h=.linked2.o)450 $(Q)$$(BPFTOOL) gen object $$(@:.skel.h=.linked3.o) $$(@:.skel.h=.linked2.o)
@@ -499,7 +500,7 @@ $(OUTPUT)/$(TRUNNER_BINARY): $(TRUNNER_TEST_OBJS) \ · 49 unmodified lines
499 | $(TRUNNER_BINARY)-extras500 | $(TRUNNER_BINARY)-extras
500 $$(call msg,BINARY,,$$@)501 $$(call msg,BINARY,,$$@)
501 $(Q)$$(CC) $$(CFLAGS) $$(filter %.a %.o,$$^) $$(LDLIBS) -o $$@502 $(Q)$$(CC) $$(CFLAGS) $$(filter %.a %.o,$$^) $$(LDLIBS) -o $$@
502 $(Q)$(RESOLVE_BTFIDS) --btf $(TRUNNER_OUTPUT)/btf_data.o $$@503 $(Q)$(RESOLVE_BTFIDS) --btf $(TRUNNER_OUTPUT)/btf_data.bpf.o $$@
503 $(Q)ln -sf $(if $2,..,.)/tools/build/bpftool/bootstrap/bpftool $(if $2,$2/)bpftool504 $(Q)ln -sf $(if $2,..,.)/tools/build/bpftool/bootstrap/bpftool $(if $2,$2/)bpftool
504 505
505endef506endef
tools/testing/selftests/bpf/README.rst+4−4
@@ -126,11 +126,11 @@ available in 10.0.1. The patch is available in llvm 11.0.0 trunk. · 125 unmodified lines
126 126
127__ https://reviews.llvm.org/D78466127__ https://reviews.llvm.org/D78466
128 128
129bpf_verif_scale/loop6.o test failure with Clang 12129bpf_verif_scale/loop6.bpf.o test failure with Clang 12
130==================================================130======================================================
131 131
132With Clang 12, the following bpf_verif_scale test failed:132With Clang 12, the following bpf_verif_scale test failed:
133 * ``bpf_verif_scale/loop6.o``133 * ``bpf_verif_scale/loop6.bpf.o``
134 134
135The verifier output looks like135The verifier output looks like
136 136
@@ -245,7 +245,7 @@ See `kernel llvm reloc`_ for more explanation and some examples. · 108 unmodified lines
245Using clang 13 to compile old libbpf which has static linker support,245Using clang 13 to compile old libbpf which has static linker support,
246there will be a compilation failure::246there will be a compilation failure::
247 247
248 libbpf: ELF relo #0 in section #6 has unexpected type 2 in .../bpf_tcp_nogpl.o248 libbpf: ELF relo #0 in section #6 has unexpected type 2 in .../bpf_tcp_nogpl.bpf.o
249 249
250Here, ``type 2`` refers to new relocation type ``R_BPF_64_ABS64``.250Here, ``type 2`` refers to new relocation type ``R_BPF_64_ABS64``.
251To fix this issue, user newer libbpf.251To fix this issue, user newer libbpf.
tools/testing/selftests/bpf/cgroup_getset_retval_hooks.h+25−0
@@ -0,0 +1,25 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2
3BPF_RETVAL_HOOK(ingress, "cgroup_skb/ingress", __sk_buff, -EINVAL)
4BPF_RETVAL_HOOK(egress, "cgroup_skb/egress", __sk_buff, -EINVAL)
5BPF_RETVAL_HOOK(sock_create, "cgroup/sock_create", bpf_sock, 0)
6BPF_RETVAL_HOOK(sock_ops, "sockops", bpf_sock_ops, -EINVAL)
7BPF_RETVAL_HOOK(dev, "cgroup/dev", bpf_cgroup_dev_ctx, 0)
8BPF_RETVAL_HOOK(bind4, "cgroup/bind4", bpf_sock_addr, 0)
9BPF_RETVAL_HOOK(bind6, "cgroup/bind6", bpf_sock_addr, 0)
10BPF_RETVAL_HOOK(connect4, "cgroup/connect4", bpf_sock_addr, 0)
11BPF_RETVAL_HOOK(connect6, "cgroup/connect6", bpf_sock_addr, 0)
12BPF_RETVAL_HOOK(post_bind4, "cgroup/post_bind4", bpf_sock_addr, 0)
13BPF_RETVAL_HOOK(post_bind6, "cgroup/post_bind6", bpf_sock_addr, 0)
14BPF_RETVAL_HOOK(sendmsg4, "cgroup/sendmsg4", bpf_sock_addr, 0)
15BPF_RETVAL_HOOK(sendmsg6, "cgroup/sendmsg6", bpf_sock_addr, 0)
16BPF_RETVAL_HOOK(sysctl, "cgroup/sysctl", bpf_sysctl, 0)
17BPF_RETVAL_HOOK(recvmsg4, "cgroup/recvmsg4", bpf_sock_addr, -EINVAL)
18BPF_RETVAL_HOOK(recvmsg6, "cgroup/recvmsg6", bpf_sock_addr, -EINVAL)
19BPF_RETVAL_HOOK(getsockopt, "cgroup/getsockopt", bpf_sockopt, 0)
20BPF_RETVAL_HOOK(setsockopt, "cgroup/setsockopt", bpf_sockopt, 0)
21BPF_RETVAL_HOOK(getpeername4, "cgroup/getpeername4", bpf_sock_addr, -EINVAL)
22BPF_RETVAL_HOOK(getpeername6, "cgroup/getpeername6", bpf_sock_addr, -EINVAL)
23BPF_RETVAL_HOOK(getsockname4, "cgroup/getsockname4", bpf_sock_addr, -EINVAL)
24BPF_RETVAL_HOOK(getsockname6, "cgroup/getsockname6", bpf_sock_addr, -EINVAL)
25BPF_RETVAL_HOOK(sock_release, "cgroup/sock_release", bpf_sock, 0)
tools/testing/selftests/bpf/cgroup_helpers.c+161−41
@@ -33,49 +33,52 @@ · 32 unmodified lines
33#define CGROUP_MOUNT_DFLT "/sys/fs/cgroup"33#define CGROUP_MOUNT_DFLT "/sys/fs/cgroup"
34#define NETCLS_MOUNT_PATH CGROUP_MOUNT_DFLT "/net_cls"34#define NETCLS_MOUNT_PATH CGROUP_MOUNT_DFLT "/net_cls"
35#define CGROUP_WORK_DIR "/cgroup-test-work-dir"35#define CGROUP_WORK_DIR "/cgroup-test-work-dir"
36#define format_cgroup_path(buf, path) \36
37#define format_cgroup_path_pid(buf, path, pid) \
37 snprintf(buf, sizeof(buf), "%s%s%d%s", CGROUP_MOUNT_PATH, \38 snprintf(buf, sizeof(buf), "%s%s%d%s", CGROUP_MOUNT_PATH, \
38 CGROUP_WORK_DIR, getpid(), path)39 CGROUP_WORK_DIR, pid, path)
40
41#define format_cgroup_path(buf, path) \
42 format_cgroup_path_pid(buf, path, getpid())
43
44#define format_parent_cgroup_path(buf, path) \
45 format_cgroup_path_pid(buf, path, getppid())
39 46
40#define format_classid_path(buf) \47#define format_classid_path(buf) \
41 snprintf(buf, sizeof(buf), "%s%s", NETCLS_MOUNT_PATH, \48 snprintf(buf, sizeof(buf), "%s%s", NETCLS_MOUNT_PATH, \
42 CGROUP_WORK_DIR)49 CGROUP_WORK_DIR)
43 50
44/**51static int __enable_controllers(const char *cgroup_path, const char *controllers)
45 * enable_all_controllers() - Enable all available cgroup v2 controllers
46 *
47 * Enable all available cgroup v2 controllers in order to increase
48 * the code coverage.
49 *
50 * If successful, 0 is returned.
51 */
52static int enable_all_controllers(char *cgroup_path)
53{52{
54 char path[PATH_MAX + 1];53 char path[PATH_MAX + 1];
55 char buf[PATH_MAX];54 char enable[PATH_MAX + 1];
56 char *c, *c2;55 char *c, *c2;
57 int fd, cfd;56 int fd, cfd;
58 ssize_t len;57 ssize_t len;
59 58
60 snprintf(path, sizeof(path), "%s/cgroup.controllers", cgroup_path);59 /* If not controllers are passed, enable all available controllers */
61 fd = open(path, O_RDONLY);60 if (!controllers) {
62 if (fd < 0) {61 snprintf(path, sizeof(path), "%s/cgroup.controllers",
63 log_err("Opening cgroup.controllers: %s", path);62 cgroup_path);
64 return 1;63 fd = open(path, O_RDONLY);
65 }64 if (fd < 0) {
66 65 log_err("Opening cgroup.controllers: %s", path);
67 len = read(fd, buf, sizeof(buf) - 1);66 return 1;
68 if (len < 0) {67 }
68 len = read(fd, enable, sizeof(enable) - 1);
69 if (len < 0) {
70 close(fd);
71 log_err("Reading cgroup.controllers: %s", path);
72 return 1;
73 } else if (len == 0) { /* No controllers to enable */
74 close(fd);
75 return 0;
76 }
77 enable[len] = 0;
69 close(fd);78 close(fd);
70 log_err("Reading cgroup.controllers: %s", path);79 } else {
71 return 1;80 strncpy(enable, controllers, sizeof(enable));
72 }81 }
73 buf[len] = 0;
74 close(fd);
75
76 /* No controllers available? We're probably on cgroup v1. */
77 if (len == 0)
78 return 0;
79 82
80 snprintf(path, sizeof(path), "%s/cgroup.subtree_control", cgroup_path);83 snprintf(path, sizeof(path), "%s/cgroup.subtree_control", cgroup_path);
81 cfd = open(path, O_RDWR);84 cfd = open(path, O_RDWR);
@@ -84,7 +87,7 @@ static int enable_all_controllers(char *cgroup_path) · 2 unmodified lines
84 return 1;87 return 1;
85 }88 }
86 89
87 for (c = strtok_r(buf, " ", &c2); c; c = strtok_r(NULL, " ", &c2)) {90 for (c = strtok_r(enable, " ", &c2); c; c = strtok_r(NULL, " ", &c2)) {
88 if (dprintf(cfd, "+%s\n", c) <= 0) {91 if (dprintf(cfd, "+%s\n", c) <= 0) {
89 log_err("Enabling controller %s: %s", c, path);92 log_err("Enabling controller %s: %s", c, path);
90 close(cfd);93 close(cfd);
@@ -95,6 +98,87 @@ static int enable_all_controllers(char *cgroup_path) · 4 unmodified lines
95 return 0;98 return 0;
96}99}
97 100
101/**
102 * enable_controllers() - Enable cgroup v2 controllers
103 * @relative_path: The cgroup path, relative to the workdir
104 * @controllers: List of controllers to enable in cgroup.controllers format
105 *
106 *
107 * Enable given cgroup v2 controllers, if @controllers is NULL, enable all
108 * available controllers.
109 *
110 * If successful, 0 is returned.
111 */
112int enable_controllers(const char *relative_path, const char *controllers)
113{
114 char cgroup_path[PATH_MAX + 1];
115
116 format_cgroup_path(cgroup_path, relative_path);
117 return __enable_controllers(cgroup_path, controllers);
118}
119
120static int __write_cgroup_file(const char *cgroup_path, const char *file,
121 const char *buf)
122{
123 char file_path[PATH_MAX + 1];
124 int fd;
125
126 snprintf(file_path, sizeof(file_path), "%s/%s", cgroup_path, file);
127 fd = open(file_path, O_RDWR);
128 if (fd < 0) {
129 log_err("Opening %s", file_path);
130 return 1;
131 }
132
133 if (dprintf(fd, "%s", buf) <= 0) {
134 log_err("Writing to %s", file_path);
135 close(fd);
136 return 1;
137 }
138 close(fd);
139 return 0;
140}
141
142/**
143 * write_cgroup_file() - Write to a cgroup file
144 * @relative_path: The cgroup path, relative to the workdir
145 * @file: The name of the file in cgroupfs to write to
146 * @buf: Buffer to write to the file
147 *
148 * Write to a file in the given cgroup's directory.
149 *
150 * If successful, 0 is returned.
151 */
152int write_cgroup_file(const char *relative_path, const char *file,
153 const char *buf)
154{
155 char cgroup_path[PATH_MAX - 24];
156
157 format_cgroup_path(cgroup_path, relative_path);
158 return __write_cgroup_file(cgroup_path, file, buf);
159}
160
161/**
162 * write_cgroup_file_parent() - Write to a cgroup file in the parent process
163 * workdir
164 * @relative_path: The cgroup path, relative to the parent process workdir
165 * @file: The name of the file in cgroupfs to write to
166 * @buf: Buffer to write to the file
167 *
168 * Write to a file in the given cgroup's directory under the parent process
169 * workdir.
170 *
171 * If successful, 0 is returned.
172 */
173int write_cgroup_file_parent(const char *relative_path, const char *file,
174 const char *buf)
175{
176 char cgroup_path[PATH_MAX - 24];
177
178 format_parent_cgroup_path(cgroup_path, relative_path);
179 return __write_cgroup_file(cgroup_path, file, buf);
180}
181
98/**182/**
99 * setup_cgroup_environment() - Setup the cgroup environment183 * setup_cgroup_environment() - Setup the cgroup environment
100 *184 *
@@ -133,7 +217,9 @@ int setup_cgroup_environment(void) · 32 unmodified lines
133 return 1;217 return 1;
134 }218 }
135 219
136 if (enable_all_controllers(cgroup_workdir))220 /* Enable all available controllers to increase test coverage */
221 if (__enable_controllers(CGROUP_MOUNT_PATH, NULL) ||
222 __enable_controllers(cgroup_workdir, NULL))
137 return 1;223 return 1;
138 224
139 return 0;225 return 0;
@@ -173,7 +259,7 @@ static int join_cgroup_from_top(const char *cgroup_path) · 33 unmodified lines
173 259
174/**260/**
175 * join_cgroup() - Join a cgroup261 * join_cgroup() - Join a cgroup
176 * @path: The cgroup path, relative to the workdir, to join262 * @relative_path: The cgroup path, relative to the workdir, to join
177 *263 *
178 * This function expects a cgroup to already be created, relative to the cgroup264 * This function expects a cgroup to already be created, relative to the cgroup
179 * work dir, and it joins it. For example, passing "/my-cgroup" as the path265 * work dir, and it joins it. For example, passing "/my-cgroup" as the path
@@ -182,11 +268,27 @@ static int join_cgroup_from_top(const char *cgroup_path) · 2 unmodified lines
182 *268 *
183 * On success, it returns 0, otherwise on failure it returns 1.269 * On success, it returns 0, otherwise on failure it returns 1.
184 */270 */
185int join_cgroup(const char *path)271int join_cgroup(const char *relative_path)
272{
273 char cgroup_path[PATH_MAX + 1];
274
275 format_cgroup_path(cgroup_path, relative_path);
276 return join_cgroup_from_top(cgroup_path);
277}
278
279/**
280 * join_parent_cgroup() - Join a cgroup in the parent process workdir
281 * @relative_path: The cgroup path, relative to parent process workdir, to join
282 *
283 * See join_cgroup().
284 *
285 * On success, it returns 0, otherwise on failure it returns 1.
286 */
287int join_parent_cgroup(const char *relative_path)
186{288{
187 char cgroup_path[PATH_MAX + 1];289 char cgroup_path[PATH_MAX + 1];
188 290
189 format_cgroup_path(cgroup_path, path);291 format_parent_cgroup_path(cgroup_path, relative_path);
190 return join_cgroup_from_top(cgroup_path);292 return join_cgroup_from_top(cgroup_path);
191}293}
192 294
@@ -212,9 +314,27 @@ void cleanup_cgroup_environment(void) · 19 unmodified lines
212 nftw(cgroup_workdir, nftwfunc, WALK_FD_LIMIT, FTW_DEPTH | FTW_MOUNT);314 nftw(cgroup_workdir, nftwfunc, WALK_FD_LIMIT, FTW_DEPTH | FTW_MOUNT);
213}315}
214 316
317/**
318 * get_root_cgroup() - Get the FD of the root cgroup
319 *
320 * On success, it returns the file descriptor. On failure, it returns -1.
321 * If there is a failure, it prints the error to stderr.
322 */
323int get_root_cgroup(void)
324{
325 int fd;
326
327 fd = open(CGROUP_MOUNT_PATH, O_RDONLY);
328 if (fd < 0) {
329 log_err("Opening root cgroup");
330 return -1;
331 }
332 return fd;
333}
334
215/**335/**
216 * create_and_get_cgroup() - Create a cgroup, relative to workdir, and get the FD336 * create_and_get_cgroup() - Create a cgroup, relative to workdir, and get the FD
217 * @path: The cgroup path, relative to the workdir, to join337 * @relative_path: The cgroup path, relative to the workdir, to join
218 *338 *
219 * This function creates a cgroup under the top level workdir and returns the339 * This function creates a cgroup under the top level workdir and returns the
220 * file descriptor. It is idempotent.340 * file descriptor. It is idempotent.
@@ -222,14 +342,14 @@ void cleanup_cgroup_environment(void) · 1 unmodified line
222 * On success, it returns the file descriptor. On failure it returns -1.342 * On success, it returns the file descriptor. On failure it returns -1.
223 * If there is a failure, it prints the error to stderr.343 * If there is a failure, it prints the error to stderr.
224 */344 */
225int create_and_get_cgroup(const char *path)345int create_and_get_cgroup(const char *relative_path)
226{346{
227 char cgroup_path[PATH_MAX + 1];347 char cgroup_path[PATH_MAX + 1];
228 int fd;348 int fd;
229 349
230 format_cgroup_path(cgroup_path, path);350 format_cgroup_path(cgroup_path, relative_path);
231 if (mkdir(cgroup_path, 0777) && errno != EEXIST) {351 if (mkdir(cgroup_path, 0777) && errno != EEXIST) {
232 log_err("mkdiring cgroup %s .. %s", path, cgroup_path);352 log_err("mkdiring cgroup %s .. %s", relative_path, cgroup_path);
233 return -1;353 return -1;
234 }354 }
235 355
@@ -244,13 +364,13 @@ int create_and_get_cgroup(const char *path) · 8 unmodified lines
244 364
245/**365/**
246 * get_cgroup_id() - Get cgroup id for a particular cgroup path366 * get_cgroup_id() - Get cgroup id for a particular cgroup path
247 * @path: The cgroup path, relative to the workdir, to join367 * @relative_path: The cgroup path, relative to the workdir, to join
248 *368 *
249 * On success, it returns the cgroup id. On failure it returns 0,369 * On success, it returns the cgroup id. On failure it returns 0,
250 * which is an invalid cgroup id.370 * which is an invalid cgroup id.
251 * If there is a failure, it prints the error to stderr.371 * If there is a failure, it prints the error to stderr.
252 */372 */
253unsigned long long get_cgroup_id(const char *path)373unsigned long long get_cgroup_id(const char *relative_path)
254{374{
255 int dirfd, err, flags, mount_id, fhsize;375 int dirfd, err, flags, mount_id, fhsize;
256 union {376 union {
@@ -261,7 +381,7 @@ unsigned long long get_cgroup_id(const char *path) · 4 unmodified lines
261 struct file_handle *fhp, *fhp2;381 struct file_handle *fhp, *fhp2;
262 unsigned long long ret = 0;382 unsigned long long ret = 0;
263 383
264 format_cgroup_path(cgroup_workdir, path);384 format_cgroup_path(cgroup_workdir, relative_path);
265 385
266 dirfd = AT_FDCWD;386 dirfd = AT_FDCWD;
267 flags = 0;387 flags = 0;
tools/testing/selftests/bpf/cgroup_helpers.h+13−6
@@ -10,11 +10,18 @@ · 9 unmodified lines
10 __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)10 __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)
11 11
12/* cgroupv2 related */12/* cgroupv2 related */
13int cgroup_setup_and_join(const char *path);13int enable_controllers(const char *relative_path, const char *controllers);
14int create_and_get_cgroup(const char *path);14int write_cgroup_file(const char *relative_path, const char *file,
15unsigned long long get_cgroup_id(const char *path);15 const char *buf);
16 16int write_cgroup_file_parent(const char *relative_path, const char *file,
17int join_cgroup(const char *path);17 const char *buf);
18int cgroup_setup_and_join(const char *relative_path);
19int get_root_cgroup(void);
20int create_and_get_cgroup(const char *relative_path);
21unsigned long long get_cgroup_id(const char *relative_path);
22
23int join_cgroup(const char *relative_path);
24int join_parent_cgroup(const char *relative_path);
18 25
19int setup_cgroup_environment(void);26int setup_cgroup_environment(void);
20void cleanup_cgroup_environment(void);27void cleanup_cgroup_environment(void);
@@ -26,4 +33,4 @@ int join_classid(void); · 5 unmodified lines
26int setup_classid_environment(void);33int setup_classid_environment(void);
27void cleanup_classid_environment(void);34void cleanup_classid_environment(void);
28 35
29#endif /* __CGROUP_HELPERS_H */36#endif /* __CGROUP_HELPERS_H */
tools/testing/selftests/bpf/get_cgroup_id_user.c+1−1
@@ -48,7 +48,7 @@ static int bpf_find_map(const char *test, struct bpf_object *obj, · 47 unmodified lines
48int main(int argc, char **argv)48int main(int argc, char **argv)
49{49{
50 const char *probe_name = "syscalls/sys_enter_nanosleep";50 const char *probe_name = "syscalls/sys_enter_nanosleep";
51 const char *file = "get_cgroup_id_kern.o";51 const char *file = "get_cgroup_id_kern.bpf.o";
52 int err, bytes, efd, prog_fd, pmu_fd;52 int err, bytes, efd, prog_fd, pmu_fd;
53 int cgroup_fd, cgidmap_fd, pidmap_fd;53 int cgroup_fd, cgidmap_fd, pidmap_fd;
54 struct perf_event_attr attr = {};54 struct perf_event_attr attr = {};
tools/testing/selftests/bpf/map_tests/task_storage_map.c+122−0
@@ -0,0 +1,122 @@
1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (C) 2022. Huawei Technologies Co., Ltd */
3#define _GNU_SOURCE
4#include <sched.h>
5#include <unistd.h>
6#include <stdlib.h>
7#include <stdbool.h>
8#include <errno.h>
9#include <string.h>
10#include <pthread.h>
11
12#include <bpf/bpf.h>
13#include <bpf/libbpf.h>
14
15#include "test_maps.h"
16#include "task_local_storage_helpers.h"
17#include "read_bpf_task_storage_busy.skel.h"
18
19struct lookup_ctx {
20 bool start;
21 bool stop;
22 int pid_fd;
23 int map_fd;
24 int loop;
25};
26
27static void *lookup_fn(void *arg)
28{
29 struct lookup_ctx *ctx = arg;
30 long value;
31 int i = 0;
32
33 while (!ctx->start)
34 usleep(1);
35
36 while (!ctx->stop && i++ < ctx->loop)
37 bpf_map_lookup_elem(ctx->map_fd, &ctx->pid_fd, &value);
38 return NULL;
39}
40
41static void abort_lookup(struct lookup_ctx *ctx, pthread_t *tids, unsigned int nr)
42{
43 unsigned int i;
44
45 ctx->stop = true;
46 ctx->start = true;
47 for (i = 0; i < nr; i++)
48 pthread_join(tids[i], NULL);
49}
50
51void test_task_storage_map_stress_lookup(void)
52{
53#define MAX_NR_THREAD 4096
54 unsigned int i, nr = 256, loop = 8192, cpu = 0;
55 struct read_bpf_task_storage_busy *skel;
56 pthread_t tids[MAX_NR_THREAD];
57 struct lookup_ctx ctx;
58 cpu_set_t old, new;
59 const char *cfg;
60 int err;
61
62 cfg = getenv("TASK_STORAGE_MAP_NR_THREAD");
63 if (cfg) {
64 nr = atoi(cfg);
65 if (nr > MAX_NR_THREAD)
66 nr = MAX_NR_THREAD;
67 }
68 cfg = getenv("TASK_STORAGE_MAP_NR_LOOP");
69 if (cfg)
70 loop = atoi(cfg);
71 cfg = getenv("TASK_STORAGE_MAP_PIN_CPU");
72 if (cfg)
73 cpu = atoi(cfg);
74
75 skel = read_bpf_task_storage_busy__open_and_load();
76 err = libbpf_get_error(skel);
77 CHECK(err, "open_and_load", "error %d\n", err);
78
79 /* Only for a fully preemptible kernel */
80 if (!skel->kconfig->CONFIG_PREEMPT)
81 return;
82
83 /* Save the old affinity setting */
84 sched_getaffinity(getpid(), sizeof(old), &old);
85
86 /* Pinned on a specific CPU */
87 CPU_ZERO(&new);
88 CPU_SET(cpu, &new);
89 sched_setaffinity(getpid(), sizeof(new), &new);
90
91 ctx.start = false;
92 ctx.stop = false;
93 ctx.pid_fd = sys_pidfd_open(getpid(), 0);
94 ctx.map_fd = bpf_map__fd(skel->maps.task);
95 ctx.loop = loop;
96 for (i = 0; i < nr; i++) {
97 err = pthread_create(&tids[i], NULL, lookup_fn, &ctx);
98 if (err) {
99 abort_lookup(&ctx, tids, i);
100 CHECK(err, "pthread_create", "error %d\n", err);
101 goto out;
102 }
103 }
104
105 ctx.start = true;
106 for (i = 0; i < nr; i++)
107 pthread_join(tids[i], NULL);
108
109 skel->bss->pid = getpid();
110 err = read_bpf_task_storage_busy__attach(skel);
111 CHECK(err, "attach", "error %d\n", err);
112
113 /* Trigger program */
114 syscall(SYS_gettid);
115 skel->bss->pid = 0;
116
117 CHECK(skel->bss->busy != 0, "bad bpf_task_storage_busy", "got %d\n", skel->bss->busy);
118out:
119 read_bpf_task_storage_busy__destroy(skel);
120 /* Restore affinity setting */
121 sched_setaffinity(getpid(), sizeof(old), &old);
122}
tools/testing/selftests/bpf/prog_tests/bpf_obj_id.c+1−1
@@ -7,7 +7,7 @@ void serial_test_bpf_obj_id(void) · 6 unmodified lines
7{7{
8 const __u64 array_magic_value = 0xfaceb00c;8 const __u64 array_magic_value = 0xfaceb00c;
9 const __u32 array_key = 0;9 const __u32 array_key = 0;
10 const char *file = "./test_obj_id.o";10 const char *file = "./test_obj_id.bpf.o";
11 const char *expected_prog_name = "test_obj_id";11 const char *expected_prog_name = "test_obj_id";
12 const char *expected_map_name = "test_map_id";12 const char *expected_map_name = "test_map_id";
13 const __u64 nsec_per_sec = 1000000000;13 const __u64 nsec_per_sec = 1000000000;
tools/testing/selftests/bpf/prog_tests/bpf_verif_scale.c+27−27
@@ -75,45 +75,45 @@ static void scale_test(const char *file, · 74 unmodified lines
75 75
76void test_verif_scale1()76void test_verif_scale1()
77{77{
78 scale_test("test_verif_scale1.o", BPF_PROG_TYPE_SCHED_CLS, false);78 scale_test("test_verif_scale1.bpf.o", BPF_PROG_TYPE_SCHED_CLS, false);
79}79}
80 80
81void test_verif_scale2()81void test_verif_scale2()
82{82{
83 scale_test("test_verif_scale2.o", BPF_PROG_TYPE_SCHED_CLS, false);83 scale_test("test_verif_scale2.bpf.o", BPF_PROG_TYPE_SCHED_CLS, false);
84}84}
85 85
86void test_verif_scale3()86void test_verif_scale3()
87{87{
88 scale_test("test_verif_scale3.o", BPF_PROG_TYPE_SCHED_CLS, false);88 scale_test("test_verif_scale3.bpf.o", BPF_PROG_TYPE_SCHED_CLS, false);
89}89}
90 90
91void test_verif_scale_pyperf_global()91void test_verif_scale_pyperf_global()
92{92{
93 scale_test("pyperf_global.o", BPF_PROG_TYPE_RAW_TRACEPOINT, false);93 scale_test("pyperf_global.bpf.o", BPF_PROG_TYPE_RAW_TRACEPOINT, false);
94}94}
95 95
96void test_verif_scale_pyperf_subprogs()96void test_verif_scale_pyperf_subprogs()
97{97{
98 scale_test("pyperf_subprogs.o", BPF_PROG_TYPE_RAW_TRACEPOINT, false);98 scale_test("pyperf_subprogs.bpf.o", BPF_PROG_TYPE_RAW_TRACEPOINT, false);
99}99}
100 100
101void test_verif_scale_pyperf50()101void test_verif_scale_pyperf50()
102{102{
103 /* full unroll by llvm */103 /* full unroll by llvm */
104 scale_test("pyperf50.o", BPF_PROG_TYPE_RAW_TRACEPOINT, false);104 scale_test("pyperf50.bpf.o", BPF_PROG_TYPE_RAW_TRACEPOINT, false);
105}105}
106 106
107void test_verif_scale_pyperf100()107void test_verif_scale_pyperf100()
108{108{
109 /* full unroll by llvm */109 /* full unroll by llvm */
110 scale_test("pyperf100.o", BPF_PROG_TYPE_RAW_TRACEPOINT, false);110 scale_test("pyperf100.bpf.o", BPF_PROG_TYPE_RAW_TRACEPOINT, false);
111}111}
112 112
113void test_verif_scale_pyperf180()113void test_verif_scale_pyperf180()
114{114{
115 /* full unroll by llvm */115 /* full unroll by llvm */
116 scale_test("pyperf180.o", BPF_PROG_TYPE_RAW_TRACEPOINT, false);116 scale_test("pyperf180.bpf.o", BPF_PROG_TYPE_RAW_TRACEPOINT, false);
117}117}
118 118
119void test_verif_scale_pyperf600()119void test_verif_scale_pyperf600()
@@ -124,13 +124,13 @@ void test_verif_scale_pyperf600() · 4 unmodified lines
124 * 16k insns in loop body.124 * 16k insns in loop body.
125 * Total of 5 such loops. Total program size ~82k insns.125 * Total of 5 such loops. Total program size ~82k insns.
126 */126 */
127 scale_test("pyperf600.o", BPF_PROG_TYPE_RAW_TRACEPOINT, false);127 scale_test("pyperf600.bpf.o", BPF_PROG_TYPE_RAW_TRACEPOINT, false);
128}128}
129 129
130void test_verif_scale_pyperf600_bpf_loop(void)130void test_verif_scale_pyperf600_bpf_loop(void)
131{131{
132 /* use the bpf_loop helper*/132 /* use the bpf_loop helper*/
133 scale_test("pyperf600_bpf_loop.o", BPF_PROG_TYPE_RAW_TRACEPOINT, false);133 scale_test("pyperf600_bpf_loop.bpf.o", BPF_PROG_TYPE_RAW_TRACEPOINT, false);
134}134}
135 135
136void test_verif_scale_pyperf600_nounroll()136void test_verif_scale_pyperf600_nounroll()
@@ -141,37 +141,37 @@ void test_verif_scale_pyperf600_nounroll() · 4 unmodified lines
141 * ~110 insns in loop body.141 * ~110 insns in loop body.
142 * Total of 5 such loops. Total program size ~1500 insns.142 * Total of 5 such loops. Total program size ~1500 insns.
143 */143 */
144 scale_test("pyperf600_nounroll.o", BPF_PROG_TYPE_RAW_TRACEPOINT, false);144 scale_test("pyperf600_nounroll.bpf.o", BPF_PROG_TYPE_RAW_TRACEPOINT, false);
145}145}
146 146
147void test_verif_scale_loop1()147void test_verif_scale_loop1()
148{148{
149 scale_test("loop1.o", BPF_PROG_TYPE_RAW_TRACEPOINT, false);149 scale_test("loop1.bpf.o", BPF_PROG_TYPE_RAW_TRACEPOINT, false);
150}150}
151 151
152void test_verif_scale_loop2()152void test_verif_scale_loop2()
153{153{
154 scale_test("loop2.o", BPF_PROG_TYPE_RAW_TRACEPOINT, false);154 scale_test("loop2.bpf.o", BPF_PROG_TYPE_RAW_TRACEPOINT, false);
155}155}
156 156
157void test_verif_scale_loop3_fail()157void test_verif_scale_loop3_fail()
158{158{
159 scale_test("loop3.o", BPF_PROG_TYPE_RAW_TRACEPOINT, true /* fails */);159 scale_test("loop3.bpf.o", BPF_PROG_TYPE_RAW_TRACEPOINT, true /* fails */);
160}160}
161 161
162void test_verif_scale_loop4()162void test_verif_scale_loop4()
163{163{
164 scale_test("loop4.o", BPF_PROG_TYPE_SCHED_CLS, false);164 scale_test("loop4.bpf.o", BPF_PROG_TYPE_SCHED_CLS, false);
165}165}
166 166
167void test_verif_scale_loop5()167void test_verif_scale_loop5()
168{168{
169 scale_test("loop5.o", BPF_PROG_TYPE_SCHED_CLS, false);169 scale_test("loop5.bpf.o", BPF_PROG_TYPE_SCHED_CLS, false);
170}170}
171 171
172void test_verif_scale_loop6()172void test_verif_scale_loop6()
173{173{
174 scale_test("loop6.o", BPF_PROG_TYPE_KPROBE, false);174 scale_test("loop6.bpf.o", BPF_PROG_TYPE_KPROBE, false);
175}175}
176 176
177void test_verif_scale_strobemeta()177void test_verif_scale_strobemeta()
@@ -180,54 +180,54 @@ void test_verif_scale_strobemeta() · 2 unmodified lines
180 * Total program size 20.8k insn.180 * Total program size 20.8k insn.
181 * ~350k processed_insns181 * ~350k processed_insns
182 */182 */
183 scale_test("strobemeta.o", BPF_PROG_TYPE_RAW_TRACEPOINT, false);183 scale_test("strobemeta.bpf.o", BPF_PROG_TYPE_RAW_TRACEPOINT, false);
184}184}
185 185
186void test_verif_scale_strobemeta_bpf_loop(void)186void test_verif_scale_strobemeta_bpf_loop(void)
187{187{
188 /* use the bpf_loop helper*/188 /* use the bpf_loop helper*/
189 scale_test("strobemeta_bpf_loop.o", BPF_PROG_TYPE_RAW_TRACEPOINT, false);189 scale_test("strobemeta_bpf_loop.bpf.o", BPF_PROG_TYPE_RAW_TRACEPOINT, false);
190}190}
191 191
192void test_verif_scale_strobemeta_nounroll1()192void test_verif_scale_strobemeta_nounroll1()
193{193{
194 /* no unroll, tiny loops */194 /* no unroll, tiny loops */
195 scale_test("strobemeta_nounroll1.o", BPF_PROG_TYPE_RAW_TRACEPOINT, false);195 scale_test("strobemeta_nounroll1.bpf.o", BPF_PROG_TYPE_RAW_TRACEPOINT, false);
196}196}
197 197
198void test_verif_scale_strobemeta_nounroll2()198void test_verif_scale_strobemeta_nounroll2()
199{199{
200 /* no unroll, tiny loops */200 /* no unroll, tiny loops */
201 scale_test("strobemeta_nounroll2.o", BPF_PROG_TYPE_RAW_TRACEPOINT, false);201 scale_test("strobemeta_nounroll2.bpf.o", BPF_PROG_TYPE_RAW_TRACEPOINT, false);
202}202}
203 203
204void test_verif_scale_strobemeta_subprogs()204void test_verif_scale_strobemeta_subprogs()
205{205{
206 /* non-inlined subprogs */206 /* non-inlined subprogs */
207 scale_test("strobemeta_subprogs.o", BPF_PROG_TYPE_RAW_TRACEPOINT, false);207 scale_test("strobemeta_subprogs.bpf.o", BPF_PROG_TYPE_RAW_TRACEPOINT, false);
208}208}
209 209
210void test_verif_scale_sysctl_loop1()210void test_verif_scale_sysctl_loop1()
211{211{
212 scale_test("test_sysctl_loop1.o", BPF_PROG_TYPE_CGROUP_SYSCTL, false);212 scale_test("test_sysctl_loop1.bpf.o", BPF_PROG_TYPE_CGROUP_SYSCTL, false);
213}213}
214 214
215void test_verif_scale_sysctl_loop2()215void test_verif_scale_sysctl_loop2()
216{216{
217 scale_test("test_sysctl_loop2.o", BPF_PROG_TYPE_CGROUP_SYSCTL, false);217 scale_test("test_sysctl_loop2.bpf.o", BPF_PROG_TYPE_CGROUP_SYSCTL, false);
218}218}
219 219
220void test_verif_scale_xdp_loop()220void test_verif_scale_xdp_loop()
221{221{
222 scale_test("test_xdp_loop.o", BPF_PROG_TYPE_XDP, false);222 scale_test("test_xdp_loop.bpf.o", BPF_PROG_TYPE_XDP, false);
223}223}
224 224
225void test_verif_scale_seg6_loop()225void test_verif_scale_seg6_loop()
226{226{
227 scale_test("test_seg6_loop.o", BPF_PROG_TYPE_LWT_SEG6LOCAL, false);227 scale_test("test_seg6_loop.bpf.o", BPF_PROG_TYPE_LWT_SEG6LOCAL, false);
228}228}
229 229
230void test_verif_twfw()230void test_verif_twfw()
231{231{
232 scale_test("twfw.o", BPF_PROG_TYPE_CGROUP_SKB, false);232 scale_test("twfw.bpf.o", BPF_PROG_TYPE_CGROUP_SKB, false);
233}233}
tools/testing/selftests/bpf/prog_tests/btf.c+2−2
@@ -4651,8 +4651,8 @@ struct btf_file_test { · 4650 unmodified lines
4651};4651};
4652 4652
4653static struct btf_file_test file_tests[] = {4653static struct btf_file_test file_tests[] = {
4654 { .file = "test_btf_newkv.o", },4654 { .file = "test_btf_newkv.bpf.o", },
4655 { .file = "test_btf_nokv.o", .btf_kv_notfound = true, },4655 { .file = "test_btf_nokv.bpf.o", .btf_kv_notfound = true, },
4656};4656};
4657 4657
4658static void do_test_file(unsigned int test_num)4658static void do_test_file(unsigned int test_num)
tools/testing/selftests/bpf/prog_tests/btf_dump.c+5−5
@@ -52,7 +52,7 @@ static int test_btf_dump_case(int n, struct btf_dump_test_case *t) · 51 unmodified lines
52 int err = 0, fd = -1;52 int err = 0, fd = -1;
53 FILE *f = NULL;53 FILE *f = NULL;
54 54
55 snprintf(test_file, sizeof(test_file), "%s.o", t->file);55 snprintf(test_file, sizeof(test_file), "%s.bpf.o", t->file);
56 56
57 btf = btf__parse_elf(test_file, NULL);57 btf = btf__parse_elf(test_file, NULL);
58 if (!ASSERT_OK_PTR(btf, "btf_parse_elf")) {58 if (!ASSERT_OK_PTR(btf, "btf_parse_elf")) {
@@ -764,8 +764,8 @@ static void test_btf_dump_struct_data(struct btf *btf, struct btf_dump *d, · 705 unmodified lines
764 764
765 /* union with nested struct */765 /* union with nested struct */
766 TEST_BTF_DUMP_DATA(btf, d, "union", str, union bpf_iter_link_info, BTF_F_COMPACT,766 TEST_BTF_DUMP_DATA(btf, d, "union", str, union bpf_iter_link_info, BTF_F_COMPACT,
767 "(union bpf_iter_link_info){.map = (struct){.map_fd = (__u32)1,},}",767 "(union bpf_iter_link_info){.map = (struct){.map_fd = (__u32)1,},.cgroup = (struct){.order = (enum bpf_cgroup_iter_order)BPF_CGROUP_ITER_SELF_ONLY,.cgroup_fd = (__u32)1,},}",
768 { .map = { .map_fd = 1 }});768 { .cgroup = { .order = 1, .cgroup_fd = 1, }});
769 769
770 /* struct skb with nested structs/unions; because type output is so770 /* struct skb with nested structs/unions; because type output is so
771 * complex, we don't do a string comparison, just verify we return771 * complex, we don't do a string comparison, just verify we return
@@ -841,8 +841,8 @@ static void test_btf_dump_datasec_data(char *str) · 69 unmodified lines
841 char license[4] = "GPL";841 char license[4] = "GPL";
842 struct btf_dump *d;842 struct btf_dump *d;
843 843
844 btf = btf__parse("xdping_kern.o", NULL);844 btf = btf__parse("xdping_kern.bpf.o", NULL);
845 if (!ASSERT_OK_PTR(btf, "xdping_kern.o BTF not found"))845 if (!ASSERT_OK_PTR(btf, "xdping_kern.bpf.o BTF not found"))
846 return;846 return;
847 847
848 d = btf_dump__new(btf, btf_dump_snprintf, str, NULL);848 d = btf_dump__new(btf, btf_dump_snprintf, str, NULL);
tools/testing/selftests/bpf/prog_tests/btf_endian.c+1−1
@@ -23,7 +23,7 @@ void test_btf_endian() { · 22 unmodified lines
23 int var_id;23 int var_id;
24 24
25 /* Load BTF in native endianness */25 /* Load BTF in native endianness */
26 btf = btf__parse_elf("btf_dump_test_case_syntax.o", NULL);26 btf = btf__parse_elf("btf_dump_test_case_syntax.bpf.o", NULL);
27 if (!ASSERT_OK_PTR(btf, "parse_native_btf"))27 if (!ASSERT_OK_PTR(btf, "parse_native_btf"))
28 goto err_out;28 goto err_out;
29 29
tools/testing/selftests/bpf/prog_tests/cb_refs.c+48−0
@@ -0,0 +1,48 @@
1// SPDX-License-Identifier: GPL-2.0
2#include "bpf/libbpf.h"
3#include <test_progs.h>
4#include <network_helpers.h>
5
6#include "cb_refs.skel.h"
7
8static char log_buf[1024 * 1024];
9
10struct {
11 const char *prog_name;
12 const char *err_msg;
13} cb_refs_tests[] = {
14 { "underflow_prog", "reference has not been acquired before" },
15 { "leak_prog", "Unreleased reference" },
16 { "nested_cb", "Unreleased reference id=4 alloc_insn=2" }, /* alloc_insn=2{4,5} */
17 { "non_cb_transfer_ref", "Unreleased reference id=4 alloc_insn=1" }, /* alloc_insn=1{1,2} */
18};
19
20void test_cb_refs(void)
21{
22 LIBBPF_OPTS(bpf_object_open_opts, opts, .kernel_log_buf = log_buf,
23 .kernel_log_size = sizeof(log_buf),
24 .kernel_log_level = 1);
25 struct bpf_program *prog;
26 struct cb_refs *skel;
27 int i;
28
29 for (i = 0; i < ARRAY_SIZE(cb_refs_tests); i++) {
30 LIBBPF_OPTS(bpf_test_run_opts, run_opts,
31 .data_in = &pkt_v4,
32 .data_size_in = sizeof(pkt_v4),
33 .repeat = 1,
34 );
35 skel = cb_refs__open_opts(&opts);
36 if (!ASSERT_OK_PTR(skel, "cb_refs__open_and_load"))
37 return;
38 prog = bpf_object__find_program_by_name(skel->obj, cb_refs_tests[i].prog_name);
39 bpf_program__set_autoload(prog, true);
40 if (!ASSERT_ERR(cb_refs__load(skel), "cb_refs__load"))
41 bpf_prog_test_run_opts(bpf_program__fd(prog), &run_opts);
42 if (!ASSERT_OK_PTR(strstr(log_buf, cb_refs_tests[i].err_msg), "expected error message")) {
43 fprintf(stderr, "Expected: %s\n", cb_refs_tests[i].err_msg);
44 fprintf(stderr, "Verifier: %s\n", log_buf);
45 }
46 cb_refs__destroy(skel);
47 }
48}
tools/testing/selftests/bpf/prog_tests/cgroup_getset_retval.c+48−0
@@ -10,6 +10,7 @@ · 9 unmodified lines
10 10
11#include "cgroup_getset_retval_setsockopt.skel.h"11#include "cgroup_getset_retval_setsockopt.skel.h"
12#include "cgroup_getset_retval_getsockopt.skel.h"12#include "cgroup_getset_retval_getsockopt.skel.h"
13#include "cgroup_getset_retval_hooks.skel.h"
13 14
14#define SOL_CUSTOM 0xdeadbeef15#define SOL_CUSTOM 0xdeadbeef
15 16
@@ -433,6 +434,50 @@ close_bpf_object: · 417 unmodified lines
433 cgroup_getset_retval_getsockopt__destroy(obj);434 cgroup_getset_retval_getsockopt__destroy(obj);
434}435}
435 436
437struct exposed_hook {
438 const char *name;
439 int expected_err;
440} exposed_hooks[] = {
441
442#define BPF_RETVAL_HOOK(NAME, SECTION, CTX, EXPECTED_ERR) \
443 { \
444 .name = #NAME, \
445 .expected_err = EXPECTED_ERR, \
446 },
447
448#include "cgroup_getset_retval_hooks.h"
449
450#undef BPF_RETVAL_HOOK
451};
452
453static void test_exposed_hooks(int cgroup_fd, int sock_fd)
454{
455 struct cgroup_getset_retval_hooks *skel;
456 struct bpf_program *prog;
457 int err;
458 int i;
459
460 for (i = 0; i < ARRAY_SIZE(exposed_hooks); i++) {
461 skel = cgroup_getset_retval_hooks__open();
462 if (!ASSERT_OK_PTR(skel, "cgroup_getset_retval_hooks__open"))
463 continue;
464
465 prog = bpf_object__find_program_by_name(skel->obj, exposed_hooks[i].name);
466 if (!ASSERT_NEQ(prog, NULL, "bpf_object__find_program_by_name"))
467 goto close_skel;
468
469 err = bpf_program__set_autoload(prog, true);
470 if (!ASSERT_OK(err, "bpf_program__set_autoload"))
471 goto close_skel;
472
473 err = cgroup_getset_retval_hooks__load(skel);
474 ASSERT_EQ(err, exposed_hooks[i].expected_err, "expected_err");
475
476close_skel:
477 cgroup_getset_retval_hooks__destroy(skel);
478 }
479}
480
436void test_cgroup_getset_retval(void)481void test_cgroup_getset_retval(void)
437{482{
438 int cgroup_fd = -1;483 int cgroup_fd = -1;
@@ -476,6 +521,9 @@ void test_cgroup_getset_retval(void) · 37 unmodified lines
476 if (test__start_subtest("getsockopt-retval_sync"))521 if (test__start_subtest("getsockopt-retval_sync"))
477 test_getsockopt_retval_sync(cgroup_fd, sock_fd);522 test_getsockopt_retval_sync(cgroup_fd, sock_fd);
478 523
524 if (test__start_subtest("exposed_hooks"))
525 test_exposed_hooks(cgroup_fd, sock_fd);
526
479close_fd:527close_fd:
480 close(cgroup_fd);528 close(cgroup_fd);
481}529}
tools/testing/selftests/bpf/prog_tests/cgroup_hierarchical_stats.c+357−0
@@ -0,0 +1,357 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Functions to manage eBPF programs attached to cgroup subsystems
4 *
5 * Copyright 2022 Google LLC.
6 */
7#include <asm-generic/errno.h>
8#include <errno.h>
9#include <sys/types.h>
10#include <sys/mount.h>
11#include <sys/stat.h>
12#include <unistd.h>
13
14#include <test_progs.h>
15#include <bpf/libbpf.h>
16#include <bpf/bpf.h>
17
18#include "cgroup_helpers.h"
19#include "cgroup_hierarchical_stats.skel.h"
20
21#define PAGE_SIZE 4096
22#define MB(x) (x << 20)
23
24#define BPFFS_ROOT "/sys/fs/bpf/"
25#define BPFFS_VMSCAN BPFFS_ROOT"vmscan/"
26
27#define CG_ROOT_NAME "root"
28#define CG_ROOT_ID 1
29
30#define CGROUP_PATH(p, n) {.path = p"/"n, .name = n}
31
32static struct {
33 const char *path, *name;
34 unsigned long long id;
35 int fd;
36} cgroups[] = {
37 CGROUP_PATH("/", "test"),
38 CGROUP_PATH("/test", "child1"),
39 CGROUP_PATH("/test", "child2"),
40 CGROUP_PATH("/test/child1", "child1_1"),
41 CGROUP_PATH("/test/child1", "child1_2"),
42 CGROUP_PATH("/test/child2", "child2_1"),
43 CGROUP_PATH("/test/child2", "child2_2"),
44};
45
46#define N_CGROUPS ARRAY_SIZE(cgroups)
47#define N_NON_LEAF_CGROUPS 3
48
49static int root_cgroup_fd;
50static bool mounted_bpffs;
51
52/* reads file at 'path' to 'buf', returns 0 on success. */
53static int read_from_file(const char *path, char *buf, size_t size)
54{
55 int fd, len;
56
57 fd = open(path, O_RDONLY);
58 if (fd < 0)
59 return fd;
60
61 len = read(fd, buf, size);
62 close(fd);
63 if (len < 0)
64 return len;
65
66 buf[len] = 0;
67 return 0;
68}
69
70/* mounts bpffs and mkdir for reading stats, returns 0 on success. */
71static int setup_bpffs(void)
72{
73 int err;
74
75 /* Mount bpffs */
76 err = mount("bpf", BPFFS_ROOT, "bpf", 0, NULL);
77 mounted_bpffs = !err;
78 if (ASSERT_FALSE(err && errno != EBUSY, "mount"))
79 return err;
80
81 /* Create a directory to contain stat files in bpffs */
82 err = mkdir(BPFFS_VMSCAN, 0755);
83 if (!ASSERT_OK(err, "mkdir"))
84 return err;
85
86 return 0;
87}
88
89static void cleanup_bpffs(void)
90{
91 /* Remove created directory in bpffs */
92 ASSERT_OK(rmdir(BPFFS_VMSCAN), "rmdir "BPFFS_VMSCAN);
93
94 /* Unmount bpffs, if it wasn't already mounted when we started */
95 if (mounted_bpffs)
96 return;
97
98 ASSERT_OK(umount(BPFFS_ROOT), "unmount bpffs");
99}
100
101/* sets up cgroups, returns 0 on success. */
102static int setup_cgroups(void)
103{
104 int i, fd, err;
105
106 err = setup_cgroup_environment();
107 if (!ASSERT_OK(err, "setup_cgroup_environment"))
108 return err;
109
110 root_cgroup_fd = get_root_cgroup();
111 if (!ASSERT_GE(root_cgroup_fd, 0, "get_root_cgroup"))
112 return root_cgroup_fd;
113
114 for (i = 0; i < N_CGROUPS; i++) {
115 fd = create_and_get_cgroup(cgroups[i].path);
116 if (!ASSERT_GE(fd, 0, "create_and_get_cgroup"))
117 return fd;
118
119 cgroups[i].fd = fd;
120 cgroups[i].id = get_cgroup_id(cgroups[i].path);
121
122 /*
123 * Enable memcg controller for the entire hierarchy.
124 * Note that stats are collected for all cgroups in a hierarchy
125 * with memcg enabled anyway, but are only exposed for cgroups
126 * that have memcg enabled.
127 */
128 if (i < N_NON_LEAF_CGROUPS) {
129 err = enable_controllers(cgroups[i].path, "memory");
130 if (!ASSERT_OK(err, "enable_controllers"))
131 return err;
132 }
133 }
134 return 0;
135}
136
137static void cleanup_cgroups(void)
138{
139 close(root_cgroup_fd);
140 for (int i = 0; i < N_CGROUPS; i++)
141 close(cgroups[i].fd);
142 cleanup_cgroup_environment();
143}
144
145/* Sets up cgroup hiearchary, returns 0 on success. */
146static int setup_hierarchy(void)
147{
148 return setup_bpffs() || setup_cgroups();
149}
150
151static void destroy_hierarchy(void)
152{
153 cleanup_cgroups();
154 cleanup_bpffs();
155}
156
157static int reclaimer(const char *cgroup_path, size_t size)
158{
159 static char size_buf[128];
160 char *buf, *ptr;
161 int err;
162
163 /* Join cgroup in the parent process workdir */
164 if (join_parent_cgroup(cgroup_path))
165 return EACCES;
166
167 /* Allocate memory */
168 buf = malloc(size);
169 if (!buf)
170 return ENOMEM;
171
172 /* Write to memory to make sure it's actually allocated */
173 for (ptr = buf; ptr < buf + size; ptr += PAGE_SIZE)
174 *ptr = 1;
175
176 /* Try to reclaim memory */
177 snprintf(size_buf, 128, "%lu", size);
178 err = write_cgroup_file_parent(cgroup_path, "memory.reclaim", size_buf);
179
180 free(buf);
181 /* memory.reclaim returns EAGAIN if the amount is not fully reclaimed */
182 if (err && errno != EAGAIN)
183 return errno;
184
185 return 0;
186}
187
188static int induce_vmscan(void)
189{
190 int i, status;
191
192 /*
193 * In every leaf cgroup, run a child process that allocates some memory
194 * and attempts to reclaim some of it.
195 */
196 for (i = N_NON_LEAF_CGROUPS; i < N_CGROUPS; i++) {
197 pid_t pid;
198
199 /* Create reclaimer child */
200 pid = fork();
201 if (pid == 0) {
202 status = reclaimer(cgroups[i].path, MB(5));
203 exit(status);
204 }
205
206 /* Cleanup reclaimer child */
207 waitpid(pid, &status, 0);
208 ASSERT_TRUE(WIFEXITED(status), "reclaimer exited");
209 ASSERT_EQ(WEXITSTATUS(status), 0, "reclaim exit code");
210 }
211 return 0;
212}
213
214static unsigned long long
215get_cgroup_vmscan_delay(unsigned long long cgroup_id, const char *file_name)
216{
217 unsigned long long vmscan = 0, id = 0;
218 static char buf[128], path[128];
219
220 /* For every cgroup, read the file generated by cgroup_iter */
221 snprintf(path, 128, "%s%s", BPFFS_VMSCAN, file_name);
222 if (!ASSERT_OK(read_from_file(path, buf, 128), "read cgroup_iter"))
223 return 0;
224
225 /* Check the output file formatting */
226 ASSERT_EQ(sscanf(buf, "cg_id: %llu, total_vmscan_delay: %llu\n",
227 &id, &vmscan), 2, "output format");
228
229 /* Check that the cgroup_id is displayed correctly */
230 ASSERT_EQ(id, cgroup_id, "cgroup_id");
231 /* Check that the vmscan reading is non-zero */
232 ASSERT_GT(vmscan, 0, "vmscan_reading");
233 return vmscan;
234}
235
236static void check_vmscan_stats(void)
237{
238 unsigned long long vmscan_readings[N_CGROUPS], vmscan_root;
239 int i;
240
241 for (i = 0; i < N_CGROUPS; i++) {
242 vmscan_readings[i] = get_cgroup_vmscan_delay(cgroups[i].id,
243 cgroups[i].name);
244 }
245
246 /* Read stats for root too */
247 vmscan_root = get_cgroup_vmscan_delay(CG_ROOT_ID, CG_ROOT_NAME);
248
249 /* Check that child1 == child1_1 + child1_2 */
250 ASSERT_EQ(vmscan_readings[1], vmscan_readings[3] + vmscan_readings[4],
251 "child1_vmscan");
252 /* Check that child2 == child2_1 + child2_2 */
253 ASSERT_EQ(vmscan_readings[2], vmscan_readings[5] + vmscan_readings[6],
254 "child2_vmscan");
255 /* Check that test == child1 + child2 */
256 ASSERT_EQ(vmscan_readings[0], vmscan_readings[1] + vmscan_readings[2],
257 "test_vmscan");
258 /* Check that root >= test */
259 ASSERT_GE(vmscan_root, vmscan_readings[1], "root_vmscan");
260}
261
262/* Creates iter link and pins in bpffs, returns 0 on success, -errno on failure.
263 */
264static int setup_cgroup_iter(struct cgroup_hierarchical_stats *obj,
265 int cgroup_fd, const char *file_name)
266{
267 DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
268 union bpf_iter_link_info linfo = {};
269 struct bpf_link *link;
270 static char path[128];
271 int err;
272
273 /*
274 * Create an iter link, parameterized by cgroup_fd. We only want to
275 * traverse one cgroup, so set the traversal order to "self".
276 */
277 linfo.cgroup.cgroup_fd = cgroup_fd;
278 linfo.cgroup.order = BPF_CGROUP_ITER_SELF_ONLY;
279 opts.link_info = &linfo;
280 opts.link_info_len = sizeof(linfo);
281 link = bpf_program__attach_iter(obj->progs.dump_vmscan, &opts);
282 if (!ASSERT_OK_PTR(link, "attach_iter"))
283 return -EFAULT;
284
285 /* Pin the link to a bpffs file */
286 snprintf(path, 128, "%s%s", BPFFS_VMSCAN, file_name);
287 err = bpf_link__pin(link, path);
288 ASSERT_OK(err, "pin cgroup_iter");
289
290 /* Remove the link, leaving only the ref held by the pinned file */
291 bpf_link__destroy(link);
292 return err;
293}
294
295/* Sets up programs for collecting stats, returns 0 on success. */
296static int setup_progs(struct cgroup_hierarchical_stats **skel)
297{
298 int i, err;
299
300 *skel = cgroup_hierarchical_stats__open_and_load();
301 if (!ASSERT_OK_PTR(*skel, "open_and_load"))
302 return 1;
303
304 /* Attach cgroup_iter program that will dump the stats to cgroups */
305 for (i = 0; i < N_CGROUPS; i++) {
306 err = setup_cgroup_iter(*skel, cgroups[i].fd, cgroups[i].name);
307 if (!ASSERT_OK(err, "setup_cgroup_iter"))
308 return err;
309 }
310
311 /* Also dump stats for root */
312 err = setup_cgroup_iter(*skel, root_cgroup_fd, CG_ROOT_NAME);
313 if (!ASSERT_OK(err, "setup_cgroup_iter"))
314 return err;
315
316 bpf_program__set_autoattach((*skel)->progs.dump_vmscan, false);
317 err = cgroup_hierarchical_stats__attach(*skel);
318 if (!ASSERT_OK(err, "attach"))
319 return err;
320
321 return 0;
322}
323
324static void destroy_progs(struct cgroup_hierarchical_stats *skel)
325{
326 static char path[128];
327 int i;
328
329 for (i = 0; i < N_CGROUPS; i++) {
330 /* Delete files in bpffs that cgroup_iters are pinned in */
331 snprintf(path, 128, "%s%s", BPFFS_VMSCAN,
332 cgroups[i].name);
333 ASSERT_OK(remove(path), "remove cgroup_iter pin");
334 }
335
336 /* Delete root file in bpffs */
337 snprintf(path, 128, "%s%s", BPFFS_VMSCAN, CG_ROOT_NAME);
338 ASSERT_OK(remove(path), "remove cgroup_iter root pin");
339 cgroup_hierarchical_stats__destroy(skel);
340}
341
342void test_cgroup_hierarchical_stats(void)
343{
344 struct cgroup_hierarchical_stats *skel = NULL;
345
346 if (setup_hierarchy())
347 goto hierarchy_cleanup;
348 if (setup_progs(&skel))
349 goto cleanup;
350 if (induce_vmscan())
351 goto cleanup;
352 check_vmscan_stats();
353cleanup:
354 destroy_progs(skel);
355hierarchy_cleanup:
356 destroy_hierarchy();
357}
tools/testing/selftests/bpf/prog_tests/cgroup_iter.c+224−0
@@ -0,0 +1,224 @@
1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (c) 2022 Google */
3
4#include <test_progs.h>
5#include <bpf/libbpf.h>
6#include <bpf/btf.h>
7#include "cgroup_iter.skel.h"
8#include "cgroup_helpers.h"
9
10#define ROOT 0
11#define PARENT 1
12#define CHILD1 2
13#define CHILD2 3
14#define NUM_CGROUPS 4
15
16#define PROLOGUE "prologue\n"
17#define EPILOGUE "epilogue\n"
18
19static const char *cg_path[] = {
20 "/", "/parent", "/parent/child1", "/parent/child2"
21};
22
23static int cg_fd[] = {-1, -1, -1, -1};
24static unsigned long long cg_id[] = {0, 0, 0, 0};
25static char expected_output[64];
26
27static int setup_cgroups(void)
28{
29 int fd, i = 0;
30
31 for (i = 0; i < NUM_CGROUPS; i++) {
32 fd = create_and_get_cgroup(cg_path[i]);
33 if (fd < 0)
34 return fd;
35
36 cg_fd[i] = fd;
37 cg_id[i] = get_cgroup_id(cg_path[i]);
38 }
39 return 0;
40}
41
42static void cleanup_cgroups(void)
43{
44 int i;
45
46 for (i = 0; i < NUM_CGROUPS; i++)
47 close(cg_fd[i]);
48}
49
50static void read_from_cgroup_iter(struct bpf_program *prog, int cgroup_fd,
51 int order, const char *testname)
52{
53 DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
54 union bpf_iter_link_info linfo;
55 struct bpf_link *link;
56 int len, iter_fd;
57 static char buf[128];
58 size_t left;
59 char *p;
60
61 memset(&linfo, 0, sizeof(linfo));
62 linfo.cgroup.cgroup_fd = cgroup_fd;
63 linfo.cgroup.order = order;
64 opts.link_info = &linfo;
65 opts.link_info_len = sizeof(linfo);
66
67 link = bpf_program__attach_iter(prog, &opts);
68 if (!ASSERT_OK_PTR(link, "attach_iter"))
69 return;
70
71 iter_fd = bpf_iter_create(bpf_link__fd(link));
72 if (iter_fd < 0)
73 goto free_link;
74
75 memset(buf, 0, sizeof(buf));
76 left = ARRAY_SIZE(buf);
77 p = buf;
78 while ((len = read(iter_fd, p, left)) > 0) {
79 p += len;
80 left -= len;
81 }
82
83 ASSERT_STREQ(buf, expected_output, testname);
84
85 /* read() after iter finishes should be ok. */
86 if (len == 0)
87 ASSERT_OK(read(iter_fd, buf, sizeof(buf)), "second_read");
88
89 close(iter_fd);
90free_link:
91 bpf_link__destroy(link);
92}
93
94/* Invalid cgroup. */
95static void test_invalid_cgroup(struct cgroup_iter *skel)
96{
97 DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
98 union bpf_iter_link_info linfo;
99 struct bpf_link *link;
100
101 memset(&linfo, 0, sizeof(linfo));
102 linfo.cgroup.cgroup_fd = (__u32)-1;
103 opts.link_info = &linfo;
104 opts.link_info_len = sizeof(linfo);
105
106 link = bpf_program__attach_iter(skel->progs.cgroup_id_printer, &opts);
107 ASSERT_ERR_PTR(link, "attach_iter");
108 bpf_link__destroy(link);
109}
110
111/* Specifying both cgroup_fd and cgroup_id is invalid. */
112static void test_invalid_cgroup_spec(struct cgroup_iter *skel)
113{
114 DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
115 union bpf_iter_link_info linfo;
116 struct bpf_link *link;
117
118 memset(&linfo, 0, sizeof(linfo));
119 linfo.cgroup.cgroup_fd = (__u32)cg_fd[PARENT];
120 linfo.cgroup.cgroup_id = (__u64)cg_id[PARENT];
121 opts.link_info = &linfo;
122 opts.link_info_len = sizeof(linfo);
123
124 link = bpf_program__attach_iter(skel->progs.cgroup_id_printer, &opts);
125 ASSERT_ERR_PTR(link, "attach_iter");
126 bpf_link__destroy(link);
127}
128
129/* Preorder walk prints parent and child in order. */
130static void test_walk_preorder(struct cgroup_iter *skel)
131{
132 snprintf(expected_output, sizeof(expected_output),
133 PROLOGUE "%8llu\n%8llu\n%8llu\n" EPILOGUE,
134 cg_id[PARENT], cg_id[CHILD1], cg_id[CHILD2]);
135
136 read_from_cgroup_iter(skel->progs.cgroup_id_printer, cg_fd[PARENT],
137 BPF_CGROUP_ITER_DESCENDANTS_PRE, "preorder");
138}
139
140/* Postorder walk prints child and parent in order. */
141static void test_walk_postorder(struct cgroup_iter *skel)
142{
143 snprintf(expected_output, sizeof(expected_output),
144 PROLOGUE "%8llu\n%8llu\n%8llu\n" EPILOGUE,
145 cg_id[CHILD1], cg_id[CHILD2], cg_id[PARENT]);
146
147 read_from_cgroup_iter(skel->progs.cgroup_id_printer, cg_fd[PARENT],
148 BPF_CGROUP_ITER_DESCENDANTS_POST, "postorder");
149}
150
151/* Walking parents prints parent and then root. */
152static void test_walk_ancestors_up(struct cgroup_iter *skel)
153{
154 /* terminate the walk when ROOT is met. */
155 skel->bss->terminal_cgroup = cg_id[ROOT];
156
157 snprintf(expected_output, sizeof(expected_output),
158 PROLOGUE "%8llu\n%8llu\n" EPILOGUE,
159 cg_id[PARENT], cg_id[ROOT]);
160
161 read_from_cgroup_iter(skel->progs.cgroup_id_printer, cg_fd[PARENT],
162 BPF_CGROUP_ITER_ANCESTORS_UP, "ancestors_up");
163
164 skel->bss->terminal_cgroup = 0;
165}
166
167/* Early termination prints parent only. */
168static void test_early_termination(struct cgroup_iter *skel)
169{
170 /* terminate the walk after the first element is processed. */
171 skel->bss->terminate_early = 1;
172
173 snprintf(expected_output, sizeof(expected_output),
174 PROLOGUE "%8llu\n" EPILOGUE, cg_id[PARENT]);
175
176 read_from_cgroup_iter(skel->progs.cgroup_id_printer, cg_fd[PARENT],
177 BPF_CGROUP_ITER_DESCENDANTS_PRE, "early_termination");
178
179 skel->bss->terminate_early = 0;
180}
181
182/* Waling self prints self only. */
183static void test_walk_self_only(struct cgroup_iter *skel)
184{
185 snprintf(expected_output, sizeof(expected_output),
186 PROLOGUE "%8llu\n" EPILOGUE, cg_id[PARENT]);
187
188 read_from_cgroup_iter(skel->progs.cgroup_id_printer, cg_fd[PARENT],
189 BPF_CGROUP_ITER_SELF_ONLY, "self_only");
190}
191
192void test_cgroup_iter(void)
193{
194 struct cgroup_iter *skel = NULL;
195
196 if (setup_cgroup_environment())
197 return;
198
199 if (setup_cgroups())
200 goto out;
201
202 skel = cgroup_iter__open_and_load();
203 if (!ASSERT_OK_PTR(skel, "cgroup_iter__open_and_load"))
204 goto out;
205
206 if (test__start_subtest("cgroup_iter__invalid_cgroup"))
207 test_invalid_cgroup(skel);
208 if (test__start_subtest("cgroup_iter__invalid_cgroup_spec"))
209 test_invalid_cgroup_spec(skel);
210 if (test__start_subtest("cgroup_iter__preorder"))
211 test_walk_preorder(skel);
212 if (test__start_subtest("cgroup_iter__postorder"))
213 test_walk_postorder(skel);
214 if (test__start_subtest("cgroup_iter__ancestors_up_walk"))
215 test_walk_ancestors_up(skel);
216 if (test__start_subtest("cgroup_iter__early_termination"))
217 test_early_termination(skel);
218 if (test__start_subtest("cgroup_iter__self_only"))
219 test_walk_self_only(skel);
220out:
221 cgroup_iter__destroy(skel);
222 cleanup_cgroups();
223 cleanup_cgroup_environment();
224}
tools/testing/selftests/bpf/prog_tests/connect_force_port.c+1−1
@@ -53,7 +53,7 @@ static int run_test(int cgroup_fd, int server_fd, int family, int type) · 52 unmodified lines
53 __u16 expected_peer_port = 60000;53 __u16 expected_peer_port = 60000;
54 struct bpf_program *prog;54 struct bpf_program *prog;
55 struct bpf_object *obj;55 struct bpf_object *obj;
56 const char *obj_file = v4 ? "connect_force_port4.o" : "connect_force_port6.o";56 const char *obj_file = v4 ? "connect_force_port4.bpf.o" : "connect_force_port6.bpf.o";
57 int fd, err;57 int fd, err;
58 __u32 duration = 0;58 __u32 duration = 0;
59 59
tools/testing/selftests/bpf/prog_tests/core_reloc.c+37−37
@@ -13,7 +13,7 @@ static int duration = 0; · 12 unmodified lines
13 13
14#define MODULES_CASE(name, pg_name, tp_name) { \14#define MODULES_CASE(name, pg_name, tp_name) { \
15 .case_name = name, \15 .case_name = name, \
16 .bpf_obj_file = "test_core_reloc_module.o", \16 .bpf_obj_file = "test_core_reloc_module.bpf.o", \
17 .btf_src_file = NULL, /* find in kernel module BTFs */ \17 .btf_src_file = NULL, /* find in kernel module BTFs */ \
18 .input = "", \18 .input = "", \
19 .input_len = 0, \19 .input_len = 0, \
@@ -43,8 +43,8 @@ static int duration = 0; · 23 unmodified lines
43 43
44#define FLAVORS_CASE_COMMON(name) \44#define FLAVORS_CASE_COMMON(name) \
45 .case_name = #name, \45 .case_name = #name, \
46 .bpf_obj_file = "test_core_reloc_flavors.o", \46 .bpf_obj_file = "test_core_reloc_flavors.bpf.o", \
47 .btf_src_file = "btf__core_reloc_" #name ".o", \47 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \
48 .raw_tp_name = "sys_enter", \48 .raw_tp_name = "sys_enter", \
49 .prog_name = "test_core_flavors" \49 .prog_name = "test_core_flavors" \
50 50
@@ -68,8 +68,8 @@ static int duration = 0; · 17 unmodified lines
68 68
69#define NESTING_CASE_COMMON(name) \69#define NESTING_CASE_COMMON(name) \
70 .case_name = #name, \70 .case_name = #name, \
71 .bpf_obj_file = "test_core_reloc_nesting.o", \71 .bpf_obj_file = "test_core_reloc_nesting.bpf.o", \
72 .btf_src_file = "btf__core_reloc_" #name ".o", \72 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \
73 .raw_tp_name = "sys_enter", \73 .raw_tp_name = "sys_enter", \
74 .prog_name = "test_core_nesting" \74 .prog_name = "test_core_nesting" \
75 75
@@ -96,8 +96,8 @@ static int duration = 0; · 20 unmodified lines
96 96
97#define ARRAYS_CASE_COMMON(name) \97#define ARRAYS_CASE_COMMON(name) \
98 .case_name = #name, \98 .case_name = #name, \
99 .bpf_obj_file = "test_core_reloc_arrays.o", \99 .bpf_obj_file = "test_core_reloc_arrays.bpf.o", \
100 .btf_src_file = "btf__core_reloc_" #name ".o", \100 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \
101 .raw_tp_name = "sys_enter", \101 .raw_tp_name = "sys_enter", \
102 .prog_name = "test_core_arrays" \102 .prog_name = "test_core_arrays" \
103 103
@@ -130,8 +130,8 @@ static int duration = 0; · 26 unmodified lines
130 130
131#define PRIMITIVES_CASE_COMMON(name) \131#define PRIMITIVES_CASE_COMMON(name) \
132 .case_name = #name, \132 .case_name = #name, \
133 .bpf_obj_file = "test_core_reloc_primitives.o", \133 .bpf_obj_file = "test_core_reloc_primitives.bpf.o", \
134 .btf_src_file = "btf__core_reloc_" #name ".o", \134 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \
135 .raw_tp_name = "sys_enter", \135 .raw_tp_name = "sys_enter", \
136 .prog_name = "test_core_primitives" \136 .prog_name = "test_core_primitives" \
137 137
@@ -150,8 +150,8 @@ static int duration = 0; · 12 unmodified lines
150 150
151#define MODS_CASE(name) { \151#define MODS_CASE(name) { \
152 .case_name = #name, \152 .case_name = #name, \
153 .bpf_obj_file = "test_core_reloc_mods.o", \153 .bpf_obj_file = "test_core_reloc_mods.bpf.o", \
154 .btf_src_file = "btf__core_reloc_" #name ".o", \154 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \
155 .input = STRUCT_TO_CHAR_PTR(core_reloc_##name) { \155 .input = STRUCT_TO_CHAR_PTR(core_reloc_##name) { \
156 .a = 1, \156 .a = 1, \
157 .b = 2, \157 .b = 2, \
@@ -174,8 +174,8 @@ static int duration = 0; · 16 unmodified lines
174 174
175#define PTR_AS_ARR_CASE(name) { \175#define PTR_AS_ARR_CASE(name) { \
176 .case_name = #name, \176 .case_name = #name, \
177 .bpf_obj_file = "test_core_reloc_ptr_as_arr.o", \177 .bpf_obj_file = "test_core_reloc_ptr_as_arr.bpf.o", \
178 .btf_src_file = "btf__core_reloc_" #name ".o", \178 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \
179 .input = (const char *)&(struct core_reloc_##name []){ \179 .input = (const char *)&(struct core_reloc_##name []){ \
180 { .a = 1 }, \180 { .a = 1 }, \
181 { .a = 2 }, \181 { .a = 2 }, \
@@ -203,8 +203,8 @@ static int duration = 0; · 21 unmodified lines
203 203
204#define INTS_CASE_COMMON(name) \204#define INTS_CASE_COMMON(name) \
205 .case_name = #name, \205 .case_name = #name, \
206 .bpf_obj_file = "test_core_reloc_ints.o", \206 .bpf_obj_file = "test_core_reloc_ints.bpf.o", \
207 .btf_src_file = "btf__core_reloc_" #name ".o", \207 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \
208 .raw_tp_name = "sys_enter", \208 .raw_tp_name = "sys_enter", \
209 .prog_name = "test_core_ints"209 .prog_name = "test_core_ints"
210 210
@@ -223,18 +223,18 @@ static int duration = 0; · 12 unmodified lines
223 223
224#define FIELD_EXISTS_CASE_COMMON(name) \224#define FIELD_EXISTS_CASE_COMMON(name) \
225 .case_name = #name, \225 .case_name = #name, \
226 .bpf_obj_file = "test_core_reloc_existence.o", \226 .bpf_obj_file = "test_core_reloc_existence.bpf.o", \
227 .btf_src_file = "btf__core_reloc_" #name ".o", \227 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \
228 .raw_tp_name = "sys_enter", \228 .raw_tp_name = "sys_enter", \
229 .prog_name = "test_core_existence"229 .prog_name = "test_core_existence"
230 230
231#define BITFIELDS_CASE_COMMON(objfile, test_name_prefix, name) \231#define BITFIELDS_CASE_COMMON(objfile, test_name_prefix, name) \
232 .case_name = test_name_prefix#name, \232 .case_name = test_name_prefix#name, \
233 .bpf_obj_file = objfile, \233 .bpf_obj_file = objfile, \
234 .btf_src_file = "btf__core_reloc_" #name ".o"234 .btf_src_file = "btf__core_reloc_" #name ".bpf.o"
235 235
236#define BITFIELDS_CASE(name, ...) { \236#define BITFIELDS_CASE(name, ...) { \
237 BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_probed.o", \237 BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_probed.bpf.o", \
238 "probed:", name), \238 "probed:", name), \
239 .input = STRUCT_TO_CHAR_PTR(core_reloc_##name) __VA_ARGS__, \239 .input = STRUCT_TO_CHAR_PTR(core_reloc_##name) __VA_ARGS__, \
240 .input_len = sizeof(struct core_reloc_##name), \240 .input_len = sizeof(struct core_reloc_##name), \
@@ -244,7 +244,7 @@ static int duration = 0; · 3 unmodified lines
244 .raw_tp_name = "sys_enter", \244 .raw_tp_name = "sys_enter", \
245 .prog_name = "test_core_bitfields", \245 .prog_name = "test_core_bitfields", \
246}, { \246}, { \
247 BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_direct.o", \247 BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_direct.bpf.o", \
248 "direct:", name), \248 "direct:", name), \
249 .input = STRUCT_TO_CHAR_PTR(core_reloc_##name) __VA_ARGS__, \249 .input = STRUCT_TO_CHAR_PTR(core_reloc_##name) __VA_ARGS__, \
250 .input_len = sizeof(struct core_reloc_##name), \250 .input_len = sizeof(struct core_reloc_##name), \
@@ -256,14 +256,14 @@ static int duration = 0; · 5 unmodified lines
256 256
257 257
258#define BITFIELDS_ERR_CASE(name) { \258#define BITFIELDS_ERR_CASE(name) { \
259 BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_probed.o", \259 BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_probed.bpf.o", \
260 "probed:", name), \260 "probed:", name), \
261 .fails = true, \261 .fails = true, \
262 .run_btfgen_fails = true, \262 .run_btfgen_fails = true, \
263 .raw_tp_name = "sys_enter", \263 .raw_tp_name = "sys_enter", \
264 .prog_name = "test_core_bitfields", \264 .prog_name = "test_core_bitfields", \
265}, { \265}, { \
266 BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_direct.o", \266 BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_direct.bpf.o", \
267 "direct:", name), \267 "direct:", name), \
268 .fails = true, \268 .fails = true, \
269 .run_btfgen_fails = true, \269 .run_btfgen_fails = true, \
@@ -272,8 +272,8 @@ static int duration = 0; · 2 unmodified lines
272 272
273#define SIZE_CASE_COMMON(name) \273#define SIZE_CASE_COMMON(name) \
274 .case_name = #name, \274 .case_name = #name, \
275 .bpf_obj_file = "test_core_reloc_size.o", \275 .bpf_obj_file = "test_core_reloc_size.bpf.o", \
276 .btf_src_file = "btf__core_reloc_" #name ".o", \276 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \
277 .raw_tp_name = "sys_enter", \277 .raw_tp_name = "sys_enter", \
278 .prog_name = "test_core_size"278 .prog_name = "test_core_size"
279 279
@@ -307,13 +307,13 @@ static int duration = 0; · 27 unmodified lines
307#define SIZE_ERR_CASE(name) { \307#define SIZE_ERR_CASE(name) { \
308 SIZE_CASE_COMMON(name), \308 SIZE_CASE_COMMON(name), \
309 .fails = true, \309 .fails = true, \
310 .run_btfgen_fails = true, \310 .run_btfgen_fails = true, \
311}311}
312 312
313#define TYPE_BASED_CASE_COMMON(name) \313#define TYPE_BASED_CASE_COMMON(name) \
314 .case_name = #name, \314 .case_name = #name, \
315 .bpf_obj_file = "test_core_reloc_type_based.o", \315 .bpf_obj_file = "test_core_reloc_type_based.bpf.o", \
316 .btf_src_file = "btf__core_reloc_" #name ".o", \316 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \
317 .raw_tp_name = "sys_enter", \317 .raw_tp_name = "sys_enter", \
318 .prog_name = "test_core_type_based"318 .prog_name = "test_core_type_based"
319 319
@@ -331,8 +331,8 @@ static int duration = 0; · 11 unmodified lines
331 331
332#define TYPE_ID_CASE_COMMON(name) \332#define TYPE_ID_CASE_COMMON(name) \
333 .case_name = #name, \333 .case_name = #name, \
334 .bpf_obj_file = "test_core_reloc_type_id.o", \334 .bpf_obj_file = "test_core_reloc_type_id.bpf.o", \
335 .btf_src_file = "btf__core_reloc_" #name ".o", \335 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \
336 .raw_tp_name = "sys_enter", \336 .raw_tp_name = "sys_enter", \
337 .prog_name = "test_core_type_id"337 .prog_name = "test_core_type_id"
338 338
@@ -350,8 +350,8 @@ static int duration = 0; · 11 unmodified lines
350 350
351#define ENUMVAL_CASE_COMMON(name) \351#define ENUMVAL_CASE_COMMON(name) \
352 .case_name = #name, \352 .case_name = #name, \
353 .bpf_obj_file = "test_core_reloc_enumval.o", \353 .bpf_obj_file = "test_core_reloc_enumval.bpf.o", \
354 .btf_src_file = "btf__core_reloc_" #name ".o", \354 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \
355 .raw_tp_name = "sys_enter", \355 .raw_tp_name = "sys_enter", \
356 .prog_name = "test_core_enumval"356 .prog_name = "test_core_enumval"
357 357
@@ -369,8 +369,8 @@ static int duration = 0; · 11 unmodified lines
369 369
370#define ENUM64VAL_CASE_COMMON(name) \370#define ENUM64VAL_CASE_COMMON(name) \
371 .case_name = #name, \371 .case_name = #name, \
372 .bpf_obj_file = "test_core_reloc_enum64val.o", \372 .bpf_obj_file = "test_core_reloc_enum64val.bpf.o", \
373 .btf_src_file = "btf__core_reloc_" #name ".o", \373 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \
374 .raw_tp_name = "sys_enter", \374 .raw_tp_name = "sys_enter", \
375 .prog_name = "test_core_enum64val"375 .prog_name = "test_core_enum64val"
376 376
@@ -547,7 +547,7 @@ static const struct core_reloc_test_case test_cases[] = { · 170 unmodified lines
547 /* validate we can find kernel image and use its BTF for relocs */547 /* validate we can find kernel image and use its BTF for relocs */
548 {548 {
549 .case_name = "kernel",549 .case_name = "kernel",
550 .bpf_obj_file = "test_core_reloc_kernel.o",550 .bpf_obj_file = "test_core_reloc_kernel.bpf.o",
551 .btf_src_file = NULL, /* load from /lib/modules/$(uname -r) */551 .btf_src_file = NULL, /* load from /lib/modules/$(uname -r) */
552 .input = "",552 .input = "",
553 .input_len = 0,553 .input_len = 0,
@@ -629,8 +629,8 @@ static const struct core_reloc_test_case test_cases[] = { · 75 unmodified lines
629 /* validate edge cases of capturing relocations */629 /* validate edge cases of capturing relocations */
630 {630 {
631 .case_name = "misc",631 .case_name = "misc",
632 .bpf_obj_file = "test_core_reloc_misc.o",632 .bpf_obj_file = "test_core_reloc_misc.bpf.o",
633 .btf_src_file = "btf__core_reloc_misc.o",633 .btf_src_file = "btf__core_reloc_misc.bpf.o",
634 .input = (const char *)&(struct core_reloc_misc_extensible[]){634 .input = (const char *)&(struct core_reloc_misc_extensible[]){
635 { .a = 1 },635 { .a = 1 },
636 { .a = 2 }, /* not read */636 { .a = 2 }, /* not read */
tools/testing/selftests/bpf/prog_tests/fexit_bpf2bpf.c+22−22
@@ -174,8 +174,8 @@ static void test_target_no_callees(void) · 173 unmodified lines
174 const char *prog_name[] = {174 const char *prog_name[] = {
175 "fexit/test_pkt_md_access",175 "fexit/test_pkt_md_access",
176 };176 };
177 test_fexit_bpf2bpf_common("./fexit_bpf2bpf_simple.o",177 test_fexit_bpf2bpf_common("./fexit_bpf2bpf_simple.bpf.o",
178 "./test_pkt_md_access.o",178 "./test_pkt_md_access.bpf.o",
179 ARRAY_SIZE(prog_name),179 ARRAY_SIZE(prog_name),
180 prog_name, true, NULL);180 prog_name, true, NULL);
181}181}
@@ -188,8 +188,8 @@ static void test_target_yes_callees(void) · 6 unmodified lines
188 "fexit/test_pkt_access_subprog2",188 "fexit/test_pkt_access_subprog2",
189 "fexit/test_pkt_access_subprog3",189 "fexit/test_pkt_access_subprog3",
190 };190 };
191 test_fexit_bpf2bpf_common("./fexit_bpf2bpf.o",191 test_fexit_bpf2bpf_common("./fexit_bpf2bpf.bpf.o",
192 "./test_pkt_access.o",192 "./test_pkt_access.bpf.o",
193 ARRAY_SIZE(prog_name),193 ARRAY_SIZE(prog_name),
194 prog_name, true, NULL);194 prog_name, true, NULL);
195}195}
@@ -206,8 +206,8 @@ static void test_func_replace(void) · 10 unmodified lines
206 "freplace/get_constant",206 "freplace/get_constant",
207 "freplace/test_pkt_write_access_subprog",207 "freplace/test_pkt_write_access_subprog",
208 };208 };
209 test_fexit_bpf2bpf_common("./fexit_bpf2bpf.o",209 test_fexit_bpf2bpf_common("./fexit_bpf2bpf.bpf.o",
210 "./test_pkt_access.o",210 "./test_pkt_access.bpf.o",
211 ARRAY_SIZE(prog_name),211 ARRAY_SIZE(prog_name),
212 prog_name, true, NULL);212 prog_name, true, NULL);
213}213}
@@ -217,8 +217,8 @@ static void test_func_replace_verify(void) · 3 unmodified lines
217 const char *prog_name[] = {217 const char *prog_name[] = {
218 "freplace/do_bind",218 "freplace/do_bind",
219 };219 };
220 test_fexit_bpf2bpf_common("./freplace_connect4.o",220 test_fexit_bpf2bpf_common("./freplace_connect4.bpf.o",
221 "./connect4_prog.o",221 "./connect4_prog.bpf.o",
222 ARRAY_SIZE(prog_name),222 ARRAY_SIZE(prog_name),
223 prog_name, false, NULL);223 prog_name, false, NULL);
224}224}
@@ -227,7 +227,7 @@ static int test_second_attach(struct bpf_object *obj) · 2 unmodified lines
227{227{
228 const char *prog_name = "security_new_get_constant";228 const char *prog_name = "security_new_get_constant";
229 const char *tgt_name = "get_constant";229 const char *tgt_name = "get_constant";
230 const char *tgt_obj_file = "./test_pkt_access.o";230 const char *tgt_obj_file = "./test_pkt_access.bpf.o";
231 struct bpf_program *prog = NULL;231 struct bpf_program *prog = NULL;
232 struct bpf_object *tgt_obj;232 struct bpf_object *tgt_obj;
233 struct bpf_link *link;233 struct bpf_link *link;
@@ -272,8 +272,8 @@ static void test_func_replace_multi(void) · 38 unmodified lines
272 const char *prog_name[] = {272 const char *prog_name[] = {
273 "freplace/get_constant",273 "freplace/get_constant",
274 };274 };
275 test_fexit_bpf2bpf_common("./freplace_get_constant.o",275 test_fexit_bpf2bpf_common("./freplace_get_constant.bpf.o",
276 "./test_pkt_access.o",276 "./test_pkt_access.bpf.o",
277 ARRAY_SIZE(prog_name),277 ARRAY_SIZE(prog_name),
278 prog_name, true, test_second_attach);278 prog_name, true, test_second_attach);
279}279}
@@ -281,10 +281,10 @@ static void test_func_replace_multi(void) · 1 unmodified line
281static void test_fmod_ret_freplace(void)281static void test_fmod_ret_freplace(void)
282{282{
283 struct bpf_object *freplace_obj = NULL, *pkt_obj, *fmod_obj = NULL;283 struct bpf_object *freplace_obj = NULL, *pkt_obj, *fmod_obj = NULL;
284 const char *freplace_name = "./freplace_get_constant.o";284 const char *freplace_name = "./freplace_get_constant.bpf.o";
285 const char *fmod_ret_name = "./fmod_ret_freplace.o";285 const char *fmod_ret_name = "./fmod_ret_freplace.bpf.o";
286 DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts);286 DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts);
287 const char *tgt_name = "./test_pkt_access.o";287 const char *tgt_name = "./test_pkt_access.bpf.o";
288 struct bpf_link *freplace_link = NULL;288 struct bpf_link *freplace_link = NULL;
289 struct bpf_program *prog;289 struct bpf_program *prog;
290 __u32 duration = 0;290 __u32 duration = 0;
@@ -339,8 +339,8 @@ static void test_func_sockmap_update(void) · 48 unmodified lines
339 const char *prog_name[] = {339 const char *prog_name[] = {
340 "freplace/cls_redirect",340 "freplace/cls_redirect",
341 };341 };
342 test_fexit_bpf2bpf_common("./freplace_cls_redirect.o",342 test_fexit_bpf2bpf_common("./freplace_cls_redirect.bpf.o",
343 "./test_cls_redirect.o",343 "./test_cls_redirect.bpf.o",
344 ARRAY_SIZE(prog_name),344 ARRAY_SIZE(prog_name),
345 prog_name, false, NULL);345 prog_name, false, NULL);
346}346}
@@ -385,15 +385,15 @@ close_prog: · 38 unmodified lines
385static void test_func_replace_return_code(void)385static void test_func_replace_return_code(void)
386{386{
387 /* test invalid return code in the replaced program */387 /* test invalid return code in the replaced program */
388 test_obj_load_failure_common("./freplace_connect_v4_prog.o",388 test_obj_load_failure_common("./freplace_connect_v4_prog.bpf.o",
389 "./connect4_prog.o");389 "./connect4_prog.bpf.o");
390}390}
391 391
392static void test_func_map_prog_compatibility(void)392static void test_func_map_prog_compatibility(void)
393{393{
394 /* test with spin lock map value in the replaced program */394 /* test with spin lock map value in the replaced program */
395 test_obj_load_failure_common("./freplace_attach_probe.o",395 test_obj_load_failure_common("./freplace_attach_probe.bpf.o",
396 "./test_attach_probe.o");396 "./test_attach_probe.bpf.o");
397}397}
398 398
399static void test_func_replace_global_func(void)399static void test_func_replace_global_func(void)
@@ -402,8 +402,8 @@ static void test_func_replace_global_func(void) · 2 unmodified lines
402 "freplace/test_pkt_access",402 "freplace/test_pkt_access",
403 };403 };
404 404
405 test_fexit_bpf2bpf_common("./freplace_global_func.o",405 test_fexit_bpf2bpf_common("./freplace_global_func.bpf.o",
406 "./test_pkt_access.o",406 "./test_pkt_access.bpf.o",
407 ARRAY_SIZE(prog_name),407 ARRAY_SIZE(prog_name),
408 prog_name, false, NULL);408 prog_name, false, NULL);
409}409}
tools/testing/selftests/bpf/prog_tests/flow_dissector.c+43−1
@@ -8,6 +8,8 @@ · 7 unmodified lines
8 8
9#include "bpf_flow.skel.h"9#include "bpf_flow.skel.h"
10 10
11#define FLOW_CONTINUE_SADDR 0x7f00007f /* 127.0.0.127 */
12
11#ifndef IP_MF13#ifndef IP_MF
12#define IP_MF 0x200014#define IP_MF 0x2000
13#endif15#endif
@@ -100,6 +102,7 @@ struct test { · 86 unmodified lines
100 } pkt;102 } pkt;
101 struct bpf_flow_keys keys;103 struct bpf_flow_keys keys;
102 __u32 flags;104 __u32 flags;
105 __u32 retval;
103};106};
104 107
105#define VLAN_HLEN 4108#define VLAN_HLEN 4
@@ -126,6 +129,7 @@ struct test tests[] = { · 20 unmodified lines
126 .sport = 80,129 .sport = 80,
127 .dport = 8080,130 .dport = 8080,
128 },131 },
132 .retval = BPF_OK,
129 },133 },
130 {134 {
131 .name = "ipv6",135 .name = "ipv6",
@@ -146,6 +150,7 @@ struct test tests[] = { · 14 unmodified lines
146 .sport = 80,150 .sport = 80,
147 .dport = 8080,151 .dport = 8080,
148 },152 },
153 .retval = BPF_OK,
149 },154 },
150 {155 {
151 .name = "802.1q-ipv4",156 .name = "802.1q-ipv4",
@@ -168,6 +173,7 @@ struct test tests[] = { · 16 unmodified lines
168 .sport = 80,173 .sport = 80,
169 .dport = 8080,174 .dport = 8080,
170 },175 },
176 .retval = BPF_OK,
171 },177 },
172 {178 {
173 .name = "802.1ad-ipv6",179 .name = "802.1ad-ipv6",
@@ -191,6 +197,7 @@ struct test tests[] = { · 17 unmodified lines
191 .sport = 80,197 .sport = 80,
192 .dport = 8080,198 .dport = 8080,
193 },199 },
200 .retval = BPF_OK,
194 },201 },
195 {202 {
196 .name = "ipv4-frag",203 .name = "ipv4-frag",
@@ -217,6 +224,7 @@ struct test tests[] = { · 20 unmodified lines
217 .dport = 8080,224 .dport = 8080,
218 },225 },
219 .flags = BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG,226 .flags = BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG,
227 .retval = BPF_OK,
220 },228 },
221 {229 {
222 .name = "ipv4-no-frag",230 .name = "ipv4-no-frag",
@@ -239,6 +247,7 @@ struct test tests[] = { · 16 unmodified lines
239 .is_frag = true,247 .is_frag = true,
240 .is_first_frag = true,248 .is_first_frag = true,
241 },249 },
250 .retval = BPF_OK,
242 },251 },
243 {252 {
244 .name = "ipv6-frag",253 .name = "ipv6-frag",
@@ -265,6 +274,7 @@ struct test tests[] = { · 20 unmodified lines
265 .dport = 8080,274 .dport = 8080,
266 },275 },
267 .flags = BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG,276 .flags = BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG,
277 .retval = BPF_OK,
268 },278 },
269 {279 {
270 .name = "ipv6-no-frag",280 .name = "ipv6-no-frag",
@@ -287,6 +297,7 @@ struct test tests[] = { · 16 unmodified lines
287 .is_frag = true,297 .is_frag = true,
288 .is_first_frag = true,298 .is_first_frag = true,
289 },299 },
300 .retval = BPF_OK,
290 },301 },
291 {302 {
292 .name = "ipv6-flow-label",303 .name = "ipv6-flow-label",
@@ -309,6 +320,7 @@ struct test tests[] = { · 16 unmodified lines
309 .dport = 8080,320 .dport = 8080,
310 .flow_label = __bpf_constant_htonl(0xbeeef),321 .flow_label = __bpf_constant_htonl(0xbeeef),
311 },322 },
323 .retval = BPF_OK,
312 },324 },
313 {325 {
314 .name = "ipv6-no-flow-label",326 .name = "ipv6-no-flow-label",
@@ -331,6 +343,7 @@ struct test tests[] = { · 16 unmodified lines
331 .flow_label = __bpf_constant_htonl(0xbeeef),343 .flow_label = __bpf_constant_htonl(0xbeeef),
332 },344 },
333 .flags = BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL,345 .flags = BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL,
346 .retval = BPF_OK,
334 },347 },
335 {348 {
336 .name = "ipip-encap",349 .name = "ipip-encap",
@@ -359,6 +372,7 @@ struct test tests[] = { · 22 unmodified lines
359 .sport = 80,372 .sport = 80,
360 .dport = 8080,373 .dport = 8080,
361 },374 },
375 .retval = BPF_OK,
362 },376 },
363 {377 {
364 .name = "ipip-no-encap",378 .name = "ipip-no-encap",
@@ -386,6 +400,26 @@ struct test tests[] = { · 21 unmodified lines
386 .is_encap = true,400 .is_encap = true,
387 },401 },
388 .flags = BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP,402 .flags = BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP,
403 .retval = BPF_OK,
404 },
405 {
406 .name = "ipip-encap-dissector-continue",
407 .pkt.ipip = {
408 .eth.h_proto = __bpf_constant_htons(ETH_P_IP),
409 .iph.ihl = 5,
410 .iph.protocol = IPPROTO_IPIP,
411 .iph.tot_len = __bpf_constant_htons(MAGIC_BYTES),
412 .iph.saddr = __bpf_constant_htonl(FLOW_CONTINUE_SADDR),
413 .iph_inner.ihl = 5,
414 .iph_inner.protocol = IPPROTO_TCP,
415 .iph_inner.tot_len =
416 __bpf_constant_htons(MAGIC_BYTES) -
417 sizeof(struct iphdr),
418 .tcp.doff = 5,
419 .tcp.source = 99,
420 .tcp.dest = 9090,
421 },
422 .retval = BPF_FLOW_DISSECTOR_CONTINUE,
389 },423 },
390};424};
391 425
@@ -503,6 +537,10 @@ static void run_tests_skb_less(int tap_fd, struct bpf_map *keys) · 111 unmodified lines
503 err = tx_tap(tap_fd, &tests[i].pkt, sizeof(tests[i].pkt));537 err = tx_tap(tap_fd, &tests[i].pkt, sizeof(tests[i].pkt));
504 CHECK(err < 0, "tx_tap", "err %d errno %d\n", err, errno);538 CHECK(err < 0, "tx_tap", "err %d errno %d\n", err, errno);
505 539
540 /* check the stored flow_keys only if BPF_OK expected */
541 if (tests[i].retval != BPF_OK)
542 continue;
543
506 err = bpf_map_lookup_elem(keys_fd, &key, &flow_keys);544 err = bpf_map_lookup_elem(keys_fd, &key, &flow_keys);
507 ASSERT_OK(err, "bpf_map_lookup_elem");545 ASSERT_OK(err, "bpf_map_lookup_elem");
508 546
@@ -588,7 +626,11 @@ void test_flow_dissector(void) · 79 unmodified lines
588 626
589 err = bpf_prog_test_run_opts(prog_fd, &topts);627 err = bpf_prog_test_run_opts(prog_fd, &topts);
590 ASSERT_OK(err, "test_run");628 ASSERT_OK(err, "test_run");
591 ASSERT_EQ(topts.retval, 1, "test_run retval");629 ASSERT_EQ(topts.retval, tests[i].retval, "test_run retval");
630
631 /* check the resulting flow_keys only if BPF_OK returned */
632 if (topts.retval != BPF_OK)
633 continue;
592 ASSERT_EQ(topts.data_size_out, sizeof(flow_keys),634 ASSERT_EQ(topts.data_size_out, sizeof(flow_keys),
593 "test_run data_size_out");635 "test_run data_size_out");
594 CHECK_FLOW_KEYS(tests[i].name, flow_keys, tests[i].keys);636 CHECK_FLOW_KEYS(tests[i].name, flow_keys, tests[i].keys);
tools/testing/selftests/bpf/prog_tests/flow_dissector_load_bytes.c+1−1
@@ -44,7 +44,7 @@ void serial_test_flow_dissector_load_bytes(void) · 43 unmodified lines
44 ASSERT_OK(err, "test_run");44 ASSERT_OK(err, "test_run");
45 ASSERT_EQ(topts.data_size_out, sizeof(flow_keys),45 ASSERT_EQ(topts.data_size_out, sizeof(flow_keys),
46 "test_run data_size_out");46 "test_run data_size_out");
47 ASSERT_EQ(topts.retval, 1, "test_run retval");47 ASSERT_EQ(topts.retval, BPF_OK, "test_run retval");
48 48
49 if (fd >= -1)49 if (fd >= -1)
50 close(fd);50 close(fd);
tools/testing/selftests/bpf/prog_tests/get_stack_raw_tp.c+2−2
@@ -84,8 +84,8 @@ static void get_stack_print_output(void *ctx, int cpu, void *data, __u32 size) · 83 unmodified lines
84 84
85void test_get_stack_raw_tp(void)85void test_get_stack_raw_tp(void)
86{86{
87 const char *file = "./test_get_stack_rawtp.o";87 const char *file = "./test_get_stack_rawtp.bpf.o";
88 const char *file_err = "./test_get_stack_rawtp_err.o";88 const char *file_err = "./test_get_stack_rawtp_err.bpf.o";
89 const char *prog_name = "bpf_prog1";89 const char *prog_name = "bpf_prog1";
90 int i, err, prog_fd, exp_cnt = MAX_CNT_RAWTP;90 int i, err, prog_fd, exp_cnt = MAX_CNT_RAWTP;
91 struct perf_buffer *pb = NULL;91 struct perf_buffer *pb = NULL;
tools/testing/selftests/bpf/prog_tests/global_data.c+1−1
@@ -131,7 +131,7 @@ static void test_global_data_rdonly(struct bpf_object *obj, __u32 duration) · 130 unmodified lines
131 131
132void test_global_data(void)132void test_global_data(void)
133{133{
134 const char *file = "./test_global_data.o";134 const char *file = "./test_global_data.bpf.o";
135 struct bpf_object *obj;135 struct bpf_object *obj;
136 int err, prog_fd;136 int err, prog_fd;
137 LIBBPF_OPTS(bpf_test_run_opts, topts,137 LIBBPF_OPTS(bpf_test_run_opts, topts,
tools/testing/selftests/bpf/prog_tests/global_data_init.c+1−1
@@ -3,7 +3,7 @@ · 2 unmodified lines
3 3
4void test_global_data_init(void)4void test_global_data_init(void)
5{5{
6 const char *file = "./test_global_data.o";6 const char *file = "./test_global_data.bpf.o";
7 int err = -ENOMEM, map_fd, zero = 0;7 int err = -ENOMEM, map_fd, zero = 0;
8 __u8 *buff = NULL, *newval = NULL;8 __u8 *buff = NULL, *newval = NULL;
9 struct bpf_object *obj;9 struct bpf_object *obj;
tools/testing/selftests/bpf/prog_tests/global_func_args.c+1−1
@@ -39,7 +39,7 @@ static void test_global_func_args0(struct bpf_object *obj) · 38 unmodified lines
39 39
40void test_global_func_args(void)40void test_global_func_args(void)
41{41{
42 const char *file = "./test_global_func_args.o";42 const char *file = "./test_global_func_args.bpf.o";
43 struct bpf_object *obj;43 struct bpf_object *obj;
44 int err, prog_fd;44 int err, prog_fd;
45 LIBBPF_OPTS(bpf_test_run_opts, topts,45 LIBBPF_OPTS(bpf_test_run_opts, topts,
tools/testing/selftests/bpf/prog_tests/htab_update.c+126−0
@@ -0,0 +1,126 @@
1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (C) 2022. Huawei Technologies Co., Ltd */
3#define _GNU_SOURCE
4#include <sched.h>
5#include <stdbool.h>
6#include <test_progs.h>
7#include "htab_update.skel.h"
8
9struct htab_update_ctx {
10 int fd;
11 int loop;
12 bool stop;
13};
14
15static void test_reenter_update(void)
16{
17 struct htab_update *skel;
18 unsigned int key, value;
19 int err;
20
21 skel = htab_update__open();
22 if (!ASSERT_OK_PTR(skel, "htab_update__open"))
23 return;
24
25 /* lookup_elem_raw() may be inlined and find_kernel_btf_id() will return -ESRCH */
26 bpf_program__set_autoload(skel->progs.lookup_elem_raw, true);
27 err = htab_update__load(skel);
28 if (!ASSERT_TRUE(!err || err == -ESRCH, "htab_update__load") || err)
29 goto out;
30
31 skel->bss->pid = getpid();
32 err = htab_update__attach(skel);
33 if (!ASSERT_OK(err, "htab_update__attach"))
34 goto out;
35
36 /* Will trigger the reentrancy of bpf_map_update_elem() */
37 key = 0;
38 value = 0;
39 err = bpf_map_update_elem(bpf_map__fd(skel->maps.htab), &key, &value, 0);
40 if (!ASSERT_OK(err, "add element"))
41 goto out;
42
43 ASSERT_EQ(skel->bss->update_err, -EBUSY, "no reentrancy");
44out:
45 htab_update__destroy(skel);
46}
47
48static void *htab_update_thread(void *arg)
49{
50 struct htab_update_ctx *ctx = arg;
51 cpu_set_t cpus;
52 int i;
53
54 /* Pinned on CPU 0 */
55 CPU_ZERO(&cpus);
56 CPU_SET(0, &cpus);
57 pthread_setaffinity_np(pthread_self(), sizeof(cpus), &cpus);
58
59 i = 0;
60 while (i++ < ctx->loop && !ctx->stop) {
61 unsigned int key = 0, value = 0;
62 int err;
63
64 err = bpf_map_update_elem(ctx->fd, &key, &value, 0);
65 if (err) {
66 ctx->stop = true;
67 return (void *)(long)err;
68 }
69 }
70
71 return NULL;
72}
73
74static void test_concurrent_update(void)
75{
76 struct htab_update_ctx ctx;
77 struct htab_update *skel;
78 unsigned int i, nr;
79 pthread_t *tids;
80 int err;
81
82 skel = htab_update__open_and_load();
83 if (!ASSERT_OK_PTR(skel, "htab_update__open_and_load"))
84 return;
85
86 ctx.fd = bpf_map__fd(skel->maps.htab);
87 ctx.loop = 1000;
88 ctx.stop = false;
89
90 nr = 4;
91 tids = calloc(nr, sizeof(*tids));
92 if (!ASSERT_NEQ(tids, NULL, "no mem"))
93 goto out;
94
95 for (i = 0; i < nr; i++) {
96 err = pthread_create(&tids[i], NULL, htab_update_thread, &ctx);
97 if (!ASSERT_OK(err, "pthread_create")) {
98 unsigned int j;
99
100 ctx.stop = true;
101 for (j = 0; j < i; j++)
102 pthread_join(tids[j], NULL);
103 goto out;
104 }
105 }
106
107 for (i = 0; i < nr; i++) {
108 void *thread_err = NULL;
109
110 pthread_join(tids[i], &thread_err);
111 ASSERT_EQ(thread_err, NULL, "update error");
112 }
113
114out:
115 if (tids)
116 free(tids);
117 htab_update__destroy(skel);
118}
119
120void test_htab_update(void)
121{
122 if (test__start_subtest("reenter_update"))
123 test_reenter_update();
124 if (test__start_subtest("concurrent_update"))
125 test_concurrent_update();
126}
tools/testing/selftests/bpf/prog_tests/kfree_skb.c+1−1
@@ -69,7 +69,7 @@ void serial_test_kfree_skb(void) · 68 unmodified lines
69 const int zero = 0;69 const int zero = 0;
70 bool test_ok[2];70 bool test_ok[2];
71 71
72 err = bpf_prog_test_load("./test_pkt_access.o", BPF_PROG_TYPE_SCHED_CLS,72 err = bpf_prog_test_load("./test_pkt_access.bpf.o", BPF_PROG_TYPE_SCHED_CLS,
73 &obj, &prog_fd);73 &obj, &prog_fd);
74 if (CHECK(err, "prog_load sched cls", "err %d errno %d\n", err, errno))74 if (CHECK(err, "prog_load sched cls", "err %d errno %d\n", err, errno))
75 return;75 return;
tools/testing/selftests/bpf/prog_tests/kfunc_call.c+1−1
@@ -109,7 +109,7 @@ static void test_destructive(void) · 108 unmodified lines
109{109{
110 __u64 save_caps = 0;110 __u64 save_caps = 0;
111 111
112 ASSERT_OK(test_destructive_open_and_load(), "succesful_load");112 ASSERT_OK(test_destructive_open_and_load(), "successful_load");
113 113
114 if (!ASSERT_OK(cap_disable_effective(1ULL << CAP_SYS_BOOT, &save_caps), "drop_caps"))114 if (!ASSERT_OK(cap_disable_effective(1ULL << CAP_SYS_BOOT, &save_caps), "drop_caps"))
115 return;115 return;
tools/testing/selftests/bpf/prog_tests/l4lb_all.c+2−2
@@ -90,7 +90,7 @@ out: · 89 unmodified lines
90void test_l4lb_all(void)90void test_l4lb_all(void)
91{91{
92 if (test__start_subtest("l4lb_inline"))92 if (test__start_subtest("l4lb_inline"))
93 test_l4lb("test_l4lb.o");93 test_l4lb("test_l4lb.bpf.o");
94 if (test__start_subtest("l4lb_noinline"))94 if (test__start_subtest("l4lb_noinline"))
95 test_l4lb("test_l4lb_noinline.o");95 test_l4lb("test_l4lb_noinline.bpf.o");
96}96}
tools/testing/selftests/bpf/prog_tests/load_bytes_relative.c+2−2
@@ -27,8 +27,8 @@ void test_load_bytes_relative(void) · 26 unmodified lines
27 if (CHECK_FAIL(server_fd < 0))27 if (CHECK_FAIL(server_fd < 0))
28 goto close_cgroup_fd;28 goto close_cgroup_fd;
29 29
30 err = bpf_prog_test_load("./load_bytes_relative.o", BPF_PROG_TYPE_CGROUP_SKB,30 err = bpf_prog_test_load("./load_bytes_relative.bpf.o", BPF_PROG_TYPE_CGROUP_SKB,
31 &obj, &prog_fd);31 &obj, &prog_fd);
32 if (CHECK_FAIL(err))32 if (CHECK_FAIL(err))
33 goto close_server_fd;33 goto close_server_fd;
34 34
tools/testing/selftests/bpf/prog_tests/map_lock.c+1−1
@@ -49,7 +49,7 @@ out: · 48 unmodified lines
49 49
50void test_map_lock(void)50void test_map_lock(void)
51{51{
52 const char *file = "./test_map_lock.o";52 const char *file = "./test_map_lock.bpf.o";
53 int prog_fd, map_fd[2], vars[17] = {};53 int prog_fd, map_fd[2], vars[17] = {};
54 pthread_t thread_id[6];54 pthread_t thread_id[6];
55 struct bpf_object *obj = NULL;55 struct bpf_object *obj = NULL;
tools/testing/selftests/bpf/prog_tests/pinning.c+2−2
@@ -26,13 +26,13 @@ __u32 get_map_id(struct bpf_object *obj, const char *name) · 25 unmodified lines
26 26
27void test_pinning(void)27void test_pinning(void)
28{28{
29 const char *file_invalid = "./test_pinning_invalid.o";29 const char *file_invalid = "./test_pinning_invalid.bpf.o";
30 const char *custpinpath = "/sys/fs/bpf/custom/pinmap";30 const char *custpinpath = "/sys/fs/bpf/custom/pinmap";
31 const char *nopinpath = "/sys/fs/bpf/nopinmap";31 const char *nopinpath = "/sys/fs/bpf/nopinmap";
32 const char *nopinpath2 = "/sys/fs/bpf/nopinmap2";32 const char *nopinpath2 = "/sys/fs/bpf/nopinmap2";
33 const char *custpath = "/sys/fs/bpf/custom";33 const char *custpath = "/sys/fs/bpf/custom";
34 const char *pinpath = "/sys/fs/bpf/pinmap";34 const char *pinpath = "/sys/fs/bpf/pinmap";
35 const char *file = "./test_pinning.o";35 const char *file = "./test_pinning.bpf.o";
36 __u32 map_id, map_id2, duration = 0;36 __u32 map_id, map_id2, duration = 0;
37 struct stat statbuf = {};37 struct stat statbuf = {};
38 struct bpf_object *obj;38 struct bpf_object *obj;
tools/testing/selftests/bpf/prog_tests/pkt_access.c+1−1
@@ -4,7 +4,7 @@ · 3 unmodified lines
4 4
5void test_pkt_access(void)5void test_pkt_access(void)
6{6{
7 const char *file = "./test_pkt_access.o";7 const char *file = "./test_pkt_access.bpf.o";
8 struct bpf_object *obj;8 struct bpf_object *obj;
9 int err, prog_fd;9 int err, prog_fd;
10 LIBBPF_OPTS(bpf_test_run_opts, topts,10 LIBBPF_OPTS(bpf_test_run_opts, topts,
tools/testing/selftests/bpf/prog_tests/pkt_md_access.c+1−1
@@ -4,7 +4,7 @@ · 3 unmodified lines
4 4
5void test_pkt_md_access(void)5void test_pkt_md_access(void)
6{6{
7 const char *file = "./test_pkt_md_access.o";7 const char *file = "./test_pkt_md_access.bpf.o";
8 struct bpf_object *obj;8 struct bpf_object *obj;
9 int err, prog_fd;9 int err, prog_fd;
10 LIBBPF_OPTS(bpf_test_run_opts, topts,10 LIBBPF_OPTS(bpf_test_run_opts, topts,
tools/testing/selftests/bpf/prog_tests/probe_user.c+1−1
@@ -11,7 +11,7 @@ void serial_test_probe_user(void) · 10 unmodified lines
11#endif11#endif
12 };12 };
13 enum { prog_count = ARRAY_SIZE(prog_names) };13 enum { prog_count = ARRAY_SIZE(prog_names) };
14 const char *obj_file = "./test_probe_user.o";14 const char *obj_file = "./test_probe_user.bpf.o";
15 DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts, );15 DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts, );
16 int err, results_map_fd, sock_fd, duration = 0;16 int err, results_map_fd, sock_fd, duration = 0;
17 struct sockaddr curr, orig, tmp;17 struct sockaddr curr, orig, tmp;
tools/testing/selftests/bpf/prog_tests/queue_stack_map.c+2−2
@@ -28,9 +28,9 @@ static void test_queue_stack_map_by_type(int type) · 27 unmodified lines
28 vals[i] = rand();28 vals[i] = rand();
29 29
30 if (type == QUEUE)30 if (type == QUEUE)
31 strncpy(file, "./test_queue_map.o", sizeof(file));31 strncpy(file, "./test_queue_map.bpf.o", sizeof(file));
32 else if (type == STACK)32 else if (type == STACK)
33 strncpy(file, "./test_stack_map.o", sizeof(file));33 strncpy(file, "./test_stack_map.bpf.o", sizeof(file));
34 else34 else
35 return;35 return;
36 36
tools/testing/selftests/bpf/prog_tests/rdonly_maps.c+1−1
@@ -16,7 +16,7 @@ struct rdonly_map_subtest { · 15 unmodified lines
16 16
17void test_rdonly_maps(void)17void test_rdonly_maps(void)
18{18{
19 const char *file = "test_rdonly_maps.o";19 const char *file = "test_rdonly_maps.bpf.o";
20 struct rdonly_map_subtest subtests[] = {20 struct rdonly_map_subtest subtests[] = {
21 { "skip loop", "skip_loop", 0, 0 },21 { "skip loop", "skip_loop", 0, 0 },
22 { "part loop", "part_loop", 3, 2 + 3 + 4 },22 { "part loop", "part_loop", 3, 2 + 3 + 4 },
tools/testing/selftests/bpf/prog_tests/reference_tracking.c+1−1
@@ -3,7 +3,7 @@ · 2 unmodified lines
3 3
4void test_reference_tracking(void)4void test_reference_tracking(void)
5{5{
6 const char *file = "test_sk_lookup_kern.o";6 const char *file = "test_sk_lookup_kern.bpf.o";
7 const char *obj_name = "ref_track";7 const char *obj_name = "ref_track";
8 DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts,8 DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts,
9 .object_name = obj_name,9 .object_name = obj_name,
tools/testing/selftests/bpf/prog_tests/resolve_btfids.c+1−1
@@ -101,7 +101,7 @@ static int resolve_symbols(void) · 100 unmodified lines
101 int type_id;101 int type_id;
102 __u32 nr;102 __u32 nr;
103 103
104 btf = btf__parse_elf("btf_data.o", NULL);104 btf = btf__parse_elf("btf_data.bpf.o", NULL);
105 if (CHECK(libbpf_get_error(btf), "resolve",105 if (CHECK(libbpf_get_error(btf), "resolve",
106 "Failed to load BTF from btf_data.o\n"))106 "Failed to load BTF from btf_data.o\n"))
107 return -1;107 return -1;
tools/testing/selftests/bpf/prog_tests/select_reuseport.c+2−2
@@ -91,9 +91,9 @@ static int prepare_bpf_obj(void) · 90 unmodified lines
91 struct bpf_map *map;91 struct bpf_map *map;
92 int err;92 int err;
93 93
94 obj = bpf_object__open("test_select_reuseport_kern.o");94 obj = bpf_object__open("test_select_reuseport_kern.bpf.o");
95 err = libbpf_get_error(obj);95 err = libbpf_get_error(obj);
96 RET_ERR(err, "open test_select_reuseport_kern.o",96 RET_ERR(err, "open test_select_reuseport_kern.bpf.o",
97 "obj:%p PTR_ERR(obj):%d\n", obj, err);97 "obj:%p PTR_ERR(obj):%d\n", obj, err);
98 98
99 map = bpf_object__find_map_by_name(obj, "outer_map");99 map = bpf_object__find_map_by_name(obj, "outer_map");
tools/testing/selftests/bpf/prog_tests/setget_sockopt.c+125−0
@@ -0,0 +1,125 @@
1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (c) Meta Platforms, Inc. and affiliates. */
3
4#define _GNU_SOURCE
5#include <sched.h>
6#include <linux/socket.h>
7#include <net/if.h>
8
9#include "test_progs.h"
10#include "cgroup_helpers.h"
11#include "network_helpers.h"
12
13#include "setget_sockopt.skel.h"
14
15#define CG_NAME "/setget-sockopt-test"
16
17static const char addr4_str[] = "127.0.0.1";
18static const char addr6_str[] = "::1";
19static struct setget_sockopt *skel;
20static int cg_fd;
21
22static int create_netns(void)
23{
24 if (!ASSERT_OK(unshare(CLONE_NEWNET), "create netns"))
25 return -1;
26
27 if (!ASSERT_OK(system("ip link set dev lo up"), "set lo up"))
28 return -1;
29
30 if (!ASSERT_OK(system("ip link add dev binddevtest1 type veth peer name binddevtest2"),
31 "add veth"))
32 return -1;
33
34 if (!ASSERT_OK(system("ip link set dev binddevtest1 up"),
35 "bring veth up"))
36 return -1;
37
38 return 0;
39}
40
41static void test_tcp(int family)
42{
43 struct setget_sockopt__bss *bss = skel->bss;
44 int sfd, cfd;
45
46 memset(bss, 0, sizeof(*bss));
47
48 sfd = start_server(family, SOCK_STREAM,
49 family == AF_INET6 ? addr6_str : addr4_str, 0, 0);
50 if (!ASSERT_GE(sfd, 0, "start_server"))
51 return;
52
53 cfd = connect_to_fd(sfd, 0);
54 if (!ASSERT_GE(cfd, 0, "connect_to_fd_server")) {
55 close(sfd);
56 return;
57 }
58 close(sfd);
59 close(cfd);
60
61 ASSERT_EQ(bss->nr_listen, 1, "nr_listen");
62 ASSERT_EQ(bss->nr_connect, 1, "nr_connect");
63 ASSERT_EQ(bss->nr_active, 1, "nr_active");
64 ASSERT_EQ(bss->nr_passive, 1, "nr_passive");
65 ASSERT_EQ(bss->nr_socket_post_create, 2, "nr_socket_post_create");
66 ASSERT_EQ(bss->nr_binddev, 2, "nr_bind");
67}
68
69static void test_udp(int family)
70{
71 struct setget_sockopt__bss *bss = skel->bss;
72 int sfd;
73
74 memset(bss, 0, sizeof(*bss));
75
76 sfd = start_server(family, SOCK_DGRAM,
77 family == AF_INET6 ? addr6_str : addr4_str, 0, 0);
78 if (!ASSERT_GE(sfd, 0, "start_server"))
79 return;
80 close(sfd);
81
82 ASSERT_GE(bss->nr_socket_post_create, 1, "nr_socket_post_create");
83 ASSERT_EQ(bss->nr_binddev, 1, "nr_bind");
84}
85
86void test_setget_sockopt(void)
87{
88 cg_fd = test__join_cgroup(CG_NAME);
89 if (cg_fd < 0)
90 return;
91
92 if (create_netns())
93 goto done;
94
95 skel = setget_sockopt__open();
96 if (!ASSERT_OK_PTR(skel, "open skel"))
97 goto done;
98
99 strcpy(skel->rodata->veth, "binddevtest1");
100 skel->rodata->veth_ifindex = if_nametoindex("binddevtest1");
101 if (!ASSERT_GT(skel->rodata->veth_ifindex, 0, "if_nametoindex"))
102 goto done;
103
104 if (!ASSERT_OK(setget_sockopt__load(skel), "load skel"))
105 goto done;
106
107 skel->links.skops_sockopt =
108 bpf_program__attach_cgroup(skel->progs.skops_sockopt, cg_fd);
109 if (!ASSERT_OK_PTR(skel->links.skops_sockopt, "attach cgroup"))
110 goto done;
111
112 skel->links.socket_post_create =
113 bpf_program__attach_cgroup(skel->progs.socket_post_create, cg_fd);
114 if (!ASSERT_OK_PTR(skel->links.socket_post_create, "attach_cgroup"))
115 goto done;
116
117 test_tcp(AF_INET6);
118 test_tcp(AF_INET);
119 test_udp(AF_INET6);
120 test_udp(AF_INET);
121
122done:
123 setget_sockopt__destroy(skel);
124 close(cg_fd);
125}
tools/testing/selftests/bpf/prog_tests/sk_assign.c+1−1
@@ -47,7 +47,7 @@ configure_stack(void) · 46 unmodified lines
47 if (CHECK_FAIL(system("tc qdisc add dev lo clsact")))47 if (CHECK_FAIL(system("tc qdisc add dev lo clsact")))
48 return false;48 return false;
49 sprintf(tc_cmd, "%s %s %s %s", "tc filter add dev lo ingress bpf",49 sprintf(tc_cmd, "%s %s %s %s", "tc filter add dev lo ingress bpf",
50 "direct-action object-file ./test_sk_assign.o",50 "direct-action object-file ./test_sk_assign.bpf.o",
51 "section tc",51 "section tc",
52 (env.verbosity < VERBOSE_VERY) ? " 2>/dev/null" : "verbose");52 (env.verbosity < VERBOSE_VERY) ? " 2>/dev/null" : "verbose");
53 if (CHECK(system(tc_cmd), "BPF load failed;",53 if (CHECK(system(tc_cmd), "BPF load failed;",
tools/testing/selftests/bpf/prog_tests/skb_ctx.c+1−1
@@ -31,7 +31,7 @@ void test_skb_ctx(void) · 30 unmodified lines
31 struct bpf_object *obj;31 struct bpf_object *obj;
32 int err, prog_fd, i;32 int err, prog_fd, i;
33 33
34 err = bpf_prog_test_load("./test_skb_ctx.o", BPF_PROG_TYPE_SCHED_CLS,34 err = bpf_prog_test_load("./test_skb_ctx.bpf.o", BPF_PROG_TYPE_SCHED_CLS,
35 &obj, &prog_fd);35 &obj, &prog_fd);
36 if (!ASSERT_OK(err, "load"))36 if (!ASSERT_OK(err, "load"))
37 return;37 return;
tools/testing/selftests/bpf/prog_tests/skb_helpers.c+1−1
@@ -20,7 +20,7 @@ void test_skb_helpers(void) · 19 unmodified lines
20 struct bpf_object *obj;20 struct bpf_object *obj;
21 int err, prog_fd;21 int err, prog_fd;
22 22
23 err = bpf_prog_test_load("./test_skb_helpers.o",23 err = bpf_prog_test_load("./test_skb_helpers.bpf.o",
24 BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd);24 BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd);
25 if (!ASSERT_OK(err, "load"))25 if (!ASSERT_OK(err, "load"))
26 return;26 return;
tools/testing/selftests/bpf/prog_tests/sockopt_inherit.c+1−1
@@ -174,7 +174,7 @@ static void run_test(int cgroup_fd) · 173 unmodified lines
174 pthread_t tid;174 pthread_t tid;
175 int err;175 int err;
176 176
177 obj = bpf_object__open_file("sockopt_inherit.o", NULL);177 obj = bpf_object__open_file("sockopt_inherit.bpf.o", NULL);
178 if (!ASSERT_OK_PTR(obj, "obj_open"))178 if (!ASSERT_OK_PTR(obj, "obj_open"))
179 return;179 return;
180 180
tools/testing/selftests/bpf/prog_tests/sockopt_multi.c+1−1
@@ -310,7 +310,7 @@ void test_sockopt_multi(void) · 309 unmodified lines
310 if (CHECK_FAIL(cg_child < 0))310 if (CHECK_FAIL(cg_child < 0))
311 goto out;311 goto out;
312 312
313 obj = bpf_object__open_file("sockopt_multi.o", NULL);313 obj = bpf_object__open_file("sockopt_multi.bpf.o", NULL);
314 if (!ASSERT_OK_PTR(obj, "obj_load"))314 if (!ASSERT_OK_PTR(obj, "obj_load"))
315 goto out;315 goto out;
316 316
tools/testing/selftests/bpf/prog_tests/spinlock.c+1−1
@@ -19,7 +19,7 @@ static void *spin_lock_thread(void *arg) · 18 unmodified lines
19 19
20void test_spinlock(void)20void test_spinlock(void)
21{21{
22 const char *file = "./test_spin_lock.o";22 const char *file = "./test_spin_lock.bpf.o";
23 pthread_t thread_id[4];23 pthread_t thread_id[4];
24 struct bpf_object *obj = NULL;24 struct bpf_object *obj = NULL;
25 int prog_fd;25 int prog_fd;
tools/testing/selftests/bpf/prog_tests/stacktrace_map.c+1−1
@@ -6,7 +6,7 @@ void test_stacktrace_map(void) · 5 unmodified lines
6 int control_map_fd, stackid_hmap_fd, stackmap_fd, stack_amap_fd;6 int control_map_fd, stackid_hmap_fd, stackmap_fd, stack_amap_fd;
7 const char *prog_name = "oncpu";7 const char *prog_name = "oncpu";
8 int err, prog_fd, stack_trace_len;8 int err, prog_fd, stack_trace_len;
9 const char *file = "./test_stacktrace_map.o";9 const char *file = "./test_stacktrace_map.bpf.o";
10 __u32 key, val, duration = 0;10 __u32 key, val, duration = 0;
11 struct bpf_program *prog;11 struct bpf_program *prog;
12 struct bpf_object *obj;12 struct bpf_object *obj;
tools/testing/selftests/bpf/prog_tests/stacktrace_map_raw_tp.c+1−1
@@ -5,7 +5,7 @@ void test_stacktrace_map_raw_tp(void) · 4 unmodified lines
5{5{
6 const char *prog_name = "oncpu";6 const char *prog_name = "oncpu";
7 int control_map_fd, stackid_hmap_fd, stackmap_fd;7 int control_map_fd, stackid_hmap_fd, stackmap_fd;
8 const char *file = "./test_stacktrace_map.o";8 const char *file = "./test_stacktrace_map.bpf.o";
9 __u32 key, val, duration = 0;9 __u32 key, val, duration = 0;
10 int err, prog_fd;10 int err, prog_fd;
11 struct bpf_program *prog;11 struct bpf_program *prog;
tools/testing/selftests/bpf/prog_tests/tailcalls.c+18−18
@@ -20,8 +20,8 @@ static void test_tailcall_1(void) · 19 unmodified lines
20 .repeat = 1,20 .repeat = 1,
21 );21 );
22 22
23 err = bpf_prog_test_load("tailcall1.o", BPF_PROG_TYPE_SCHED_CLS, &obj,23 err = bpf_prog_test_load("tailcall1.bpf.o", BPF_PROG_TYPE_SCHED_CLS, &obj,
24 &prog_fd);24 &prog_fd);
25 if (CHECK_FAIL(err))25 if (CHECK_FAIL(err))
26 return;26 return;
27 27
@@ -156,8 +156,8 @@ static void test_tailcall_2(void) · 128 unmodified lines
156 .repeat = 1,156 .repeat = 1,
157 );157 );
158 158
159 err = bpf_prog_test_load("tailcall2.o", BPF_PROG_TYPE_SCHED_CLS, &obj,159 err = bpf_prog_test_load("tailcall2.bpf.o", BPF_PROG_TYPE_SCHED_CLS, &obj,
160 &prog_fd);160 &prog_fd);
161 if (CHECK_FAIL(err))161 if (CHECK_FAIL(err))
162 return;162 return;
163 163
@@ -299,7 +299,7 @@ out: · 135 unmodified lines
299 */299 */
300static void test_tailcall_3(void)300static void test_tailcall_3(void)
301{301{
302 test_tailcall_count("tailcall3.o");302 test_tailcall_count("tailcall3.bpf.o");
303}303}
304 304
305/* test_tailcall_6 checks that the count value of the tail call limit305/* test_tailcall_6 checks that the count value of the tail call limit
@@ -307,7 +307,7 @@ static void test_tailcall_3(void) · 1 unmodified line
307 */307 */
308static void test_tailcall_6(void)308static void test_tailcall_6(void)
309{309{
310 test_tailcall_count("tailcall6.o");310 test_tailcall_count("tailcall6.bpf.o");
311}311}
312 312
313/* test_tailcall_4 checks that the kernel properly selects indirect jump313/* test_tailcall_4 checks that the kernel properly selects indirect jump
@@ -329,8 +329,8 @@ static void test_tailcall_4(void) · 15 unmodified lines
329 .repeat = 1,329 .repeat = 1,
330 );330 );
331 331
332 err = bpf_prog_test_load("tailcall4.o", BPF_PROG_TYPE_SCHED_CLS, &obj,332 err = bpf_prog_test_load("tailcall4.bpf.o", BPF_PROG_TYPE_SCHED_CLS, &obj,
333 &prog_fd);333 &prog_fd);
334 if (CHECK_FAIL(err))334 if (CHECK_FAIL(err))
335 return;335 return;
336 336
@@ -419,8 +419,8 @@ static void test_tailcall_5(void) · 82 unmodified lines
419 .repeat = 1,419 .repeat = 1,
420 );420 );
421 421
422 err = bpf_prog_test_load("tailcall5.o", BPF_PROG_TYPE_SCHED_CLS, &obj,422 err = bpf_prog_test_load("tailcall5.bpf.o", BPF_PROG_TYPE_SCHED_CLS, &obj,
423 &prog_fd);423 &prog_fd);
424 if (CHECK_FAIL(err))424 if (CHECK_FAIL(err))
425 return;425 return;
426 426
@@ -507,8 +507,8 @@ static void test_tailcall_bpf2bpf_1(void) · 80 unmodified lines
507 .repeat = 1,507 .repeat = 1,
508 );508 );
509 509
510 err = bpf_prog_test_load("tailcall_bpf2bpf1.o", BPF_PROG_TYPE_SCHED_CLS,510 err = bpf_prog_test_load("tailcall_bpf2bpf1.bpf.o", BPF_PROG_TYPE_SCHED_CLS,
511 &obj, &prog_fd);511 &obj, &prog_fd);
512 if (CHECK_FAIL(err))512 if (CHECK_FAIL(err))
513 return;513 return;
514 514
@@ -591,8 +591,8 @@ static void test_tailcall_bpf2bpf_2(void) · 76 unmodified lines
591 .repeat = 1,591 .repeat = 1,
592 );592 );
593 593
594 err = bpf_prog_test_load("tailcall_bpf2bpf2.o", BPF_PROG_TYPE_SCHED_CLS,594 err = bpf_prog_test_load("tailcall_bpf2bpf2.bpf.o", BPF_PROG_TYPE_SCHED_CLS,
595 &obj, &prog_fd);595 &obj, &prog_fd);
596 if (CHECK_FAIL(err))596 if (CHECK_FAIL(err))
597 return;597 return;
598 598
@@ -671,8 +671,8 @@ static void test_tailcall_bpf2bpf_3(void) · 72 unmodified lines
671 .repeat = 1,671 .repeat = 1,
672 );672 );
673 673
674 err = bpf_prog_test_load("tailcall_bpf2bpf3.o", BPF_PROG_TYPE_SCHED_CLS,674 err = bpf_prog_test_load("tailcall_bpf2bpf3.bpf.o", BPF_PROG_TYPE_SCHED_CLS,
675 &obj, &prog_fd);675 &obj, &prog_fd);
676 if (CHECK_FAIL(err))676 if (CHECK_FAIL(err))
677 return;677 return;
678 678
@@ -766,8 +766,8 @@ static void test_tailcall_bpf2bpf_4(bool noise) · 87 unmodified lines
766 .repeat = 1,766 .repeat = 1,
767 );767 );
768 768
769 err = bpf_prog_test_load("tailcall_bpf2bpf4.o", BPF_PROG_TYPE_SCHED_CLS,769 err = bpf_prog_test_load("tailcall_bpf2bpf4.bpf.o", BPF_PROG_TYPE_SCHED_CLS,
770 &obj, &prog_fd);770 &obj, &prog_fd);
771 if (CHECK_FAIL(err))771 if (CHECK_FAIL(err))
772 return;772 return;
773 773
tools/testing/selftests/bpf/prog_tests/task_fd_query_rawtp.c+1−1
@@ -3,7 +3,7 @@ · 2 unmodified lines
3 3
4void test_task_fd_query_rawtp(void)4void test_task_fd_query_rawtp(void)
5{5{
6 const char *file = "./test_get_stack_rawtp.o";6 const char *file = "./test_get_stack_rawtp.bpf.o";
7 __u64 probe_offset, probe_addr;7 __u64 probe_offset, probe_addr;
8 __u32 len, prog_id, fd_type;8 __u32 len, prog_id, fd_type;
9 struct bpf_object *obj;9 struct bpf_object *obj;
tools/testing/selftests/bpf/prog_tests/task_fd_query_tp.c+1−1
@@ -4,7 +4,7 @@ · 3 unmodified lines
4static void test_task_fd_query_tp_core(const char *probe_name,4static void test_task_fd_query_tp_core(const char *probe_name,
5 const char *tp_name)5 const char *tp_name)
6{6{
7 const char *file = "./test_tracepoint.o";7 const char *file = "./test_tracepoint.bpf.o";
8 int err, bytes, efd, prog_fd, pmu_fd;8 int err, bytes, efd, prog_fd, pmu_fd;
9 struct perf_event_attr attr = {};9 struct perf_event_attr attr = {};
10 __u64 probe_offset, probe_addr;10 __u64 probe_offset, probe_addr;
tools/testing/selftests/bpf/prog_tests/tcp_estats.c+1−1
@@ -3,7 +3,7 @@ · 2 unmodified lines
3 3
4void test_tcp_estats(void)4void test_tcp_estats(void)
5{5{
6 const char *file = "./test_tcp_estats.o";6 const char *file = "./test_tcp_estats.bpf.o";
7 int err, prog_fd;7 int err, prog_fd;
8 struct bpf_object *obj;8 struct bpf_object *obj;
9 __u32 duration = 0;9 __u32 duration = 0;
tools/testing/selftests/bpf/prog_tests/test_bprm_opts.c+1−9
@@ -9,18 +9,10 @@ · 8 unmodified lines
9 9
10#include "bprm_opts.skel.h"10#include "bprm_opts.skel.h"
11#include "network_helpers.h"11#include "network_helpers.h"
12 12#include "task_local_storage_helpers.h"
13#ifndef __NR_pidfd_open
14#define __NR_pidfd_open 434
15#endif
16 13
17static const char * const bash_envp[] = { "TMPDIR=shouldnotbeset", NULL };14static const char * const bash_envp[] = { "TMPDIR=shouldnotbeset", NULL };
18 15
19static inline int sys_pidfd_open(pid_t pid, unsigned int flags)
20{
21 return syscall(__NR_pidfd_open, pid, flags);
22}
23
24static int update_storage(int map_fd, int secureexec)16static int update_storage(int map_fd, int secureexec)
25{17{
26 int task_fd, ret = 0;18 int task_fd, ret = 0;
tools/testing/selftests/bpf/prog_tests/test_global_funcs.c+17−17
@@ -65,23 +65,23 @@ struct test_def { · 64 unmodified lines
65void test_test_global_funcs(void)65void test_test_global_funcs(void)
66{66{
67 struct test_def tests[] = {67 struct test_def tests[] = {
68 { "test_global_func1.o", "combined stack size of 4 calls is 544" },68 { "test_global_func1.bpf.o", "combined stack size of 4 calls is 544" },
69 { "test_global_func2.o" },69 { "test_global_func2.bpf.o" },
70 { "test_global_func3.o" , "the call stack of 8 frames" },70 { "test_global_func3.bpf.o", "the call stack of 8 frames" },
71 { "test_global_func4.o" },71 { "test_global_func4.bpf.o" },
72 { "test_global_func5.o" , "expected pointer to ctx, but got PTR" },72 { "test_global_func5.bpf.o", "expected pointer to ctx, but got PTR" },
73 { "test_global_func6.o" , "modified ctx ptr R2" },73 { "test_global_func6.bpf.o", "modified ctx ptr R2" },
74 { "test_global_func7.o" , "foo() doesn't return scalar" },74 { "test_global_func7.bpf.o", "foo() doesn't return scalar" },
75 { "test_global_func8.o" },75 { "test_global_func8.bpf.o" },
76 { "test_global_func9.o" },76 { "test_global_func9.bpf.o" },
77 { "test_global_func10.o", "invalid indirect read from stack" },77 { "test_global_func10.bpf.o", "invalid indirect read from stack" },
78 { "test_global_func11.o", "Caller passes invalid args into func#1" },78 { "test_global_func11.bpf.o", "Caller passes invalid args into func#1" },
79 { "test_global_func12.o", "invalid mem access 'mem_or_null'" },79 { "test_global_func12.bpf.o", "invalid mem access 'mem_or_null'" },
80 { "test_global_func13.o", "Caller passes invalid args into func#1" },80 { "test_global_func13.bpf.o", "Caller passes invalid args into func#1" },
81 { "test_global_func14.o", "reference type('FWD S') size cannot be determined" },81 { "test_global_func14.bpf.o", "reference type('FWD S') size cannot be determined" },
82 { "test_global_func15.o", "At program exit the register R0 has value" },82 { "test_global_func15.bpf.o", "At program exit the register R0 has value" },
83 { "test_global_func16.o", "invalid indirect read from stack" },83 { "test_global_func16.bpf.o", "invalid indirect read from stack" },
84 { "test_global_func17.o", "Caller passes invalid args into func#1" },84 { "test_global_func17.bpf.o", "Caller passes invalid args into func#1" },
85 };85 };
86 libbpf_print_fn_t old_print_fn = NULL;86 libbpf_print_fn_t old_print_fn = NULL;
87 int err, i, duration = 0;87 int err, i, duration = 0;
tools/testing/selftests/bpf/prog_tests/test_local_storage.c+1−9
@@ -11,15 +11,7 @@ · 10 unmodified lines
11 11
12#include "local_storage.skel.h"12#include "local_storage.skel.h"
13#include "network_helpers.h"13#include "network_helpers.h"
14 14#include "task_local_storage_helpers.h"
15#ifndef __NR_pidfd_open
16#define __NR_pidfd_open 434
17#endif
18
19static inline int sys_pidfd_open(pid_t pid, unsigned int flags)
20{
21 return syscall(__NR_pidfd_open, pid, flags);
22}
23 15
24static unsigned int duration;16static unsigned int duration;
25 17
tools/testing/selftests/bpf/prog_tests/test_overhead.c+1−1
@@ -72,7 +72,7 @@ void test_test_overhead(void) · 71 unmodified lines
72 if (CHECK_FAIL(prctl(PR_GET_NAME, comm, 0L, 0L, 0L)))72 if (CHECK_FAIL(prctl(PR_GET_NAME, comm, 0L, 0L, 0L)))
73 return;73 return;
74 74
75 obj = bpf_object__open_file("./test_overhead.o", NULL);75 obj = bpf_object__open_file("./test_overhead.bpf.o", NULL);
76 if (!ASSERT_OK_PTR(obj, "obj_open_file"))76 if (!ASSERT_OK_PTR(obj, "obj_open_file"))
77 return;77 return;
78 78
tools/testing/selftests/bpf/prog_tests/tp_attach_query.c+1−1
@@ -6,7 +6,7 @@ void serial_test_tp_attach_query(void) · 5 unmodified lines
6 const int num_progs = 3;6 const int num_progs = 3;
7 int i, j, bytes, efd, err, prog_fd[num_progs], pmu_fd[num_progs];7 int i, j, bytes, efd, err, prog_fd[num_progs], pmu_fd[num_progs];
8 __u32 duration = 0, info_len, saved_prog_ids[num_progs];8 __u32 duration = 0, info_len, saved_prog_ids[num_progs];
9 const char *file = "./test_tracepoint.o";9 const char *file = "./test_tracepoint.bpf.o";
10 struct perf_event_query_bpf *query;10 struct perf_event_query_bpf *query;
11 struct perf_event_attr attr = {};11 struct perf_event_attr attr = {};
12 struct bpf_object *obj[num_progs];12 struct bpf_object *obj[num_progs];
tools/testing/selftests/bpf/prog_tests/trampoline_count.c+1−1
@@ -35,7 +35,7 @@ static struct bpf_program *load_prog(char *file, char *name, struct inst *inst) · 34 unmodified lines
35/* TODO: use different target function to run in concurrent mode */35/* TODO: use different target function to run in concurrent mode */
36void serial_test_trampoline_count(void)36void serial_test_trampoline_count(void)
37{37{
38 char *file = "test_trampoline_count.o";38 char *file = "test_trampoline_count.bpf.o";
39 char *const progs[] = { "fentry_test", "fmod_ret_test", "fexit_test" };39 char *const progs[] = { "fentry_test", "fmod_ret_test", "fexit_test" };
40 struct inst inst[MAX_TRAMP_PROGS + 1] = {};40 struct inst inst[MAX_TRAMP_PROGS + 1] = {};
41 struct bpf_program *prog;41 struct bpf_program *prog;
tools/testing/selftests/bpf/prog_tests/xdp.c+1−1
@@ -8,7 +8,7 @@ void test_xdp(void) · 7 unmodified lines
8 struct vip key6 = {.protocol = 6, .family = AF_INET6};8 struct vip key6 = {.protocol = 6, .family = AF_INET6};
9 struct iptnl_info value4 = {.family = AF_INET};9 struct iptnl_info value4 = {.family = AF_INET};
10 struct iptnl_info value6 = {.family = AF_INET6};10 struct iptnl_info value6 = {.family = AF_INET6};
11 const char *file = "./test_xdp.o";11 const char *file = "./test_xdp.bpf.o";
12 struct bpf_object *obj;12 struct bpf_object *obj;
13 char buf[128];13 char buf[128];
14 struct ipv6hdr iph6;14 struct ipv6hdr iph6;
tools/testing/selftests/bpf/prog_tests/xdp_adjust_frags.c+1−1
@@ -4,7 +4,7 @@ · 3 unmodified lines
4 4
5static void test_xdp_update_frags(void)5static void test_xdp_update_frags(void)
6{6{
7 const char *file = "./test_xdp_update_frags.o";7 const char *file = "./test_xdp_update_frags.bpf.o";
8 int err, prog_fd, max_skb_frags, buf_size, num;8 int err, prog_fd, max_skb_frags, buf_size, num;
9 struct bpf_program *prog;9 struct bpf_program *prog;
10 struct bpf_object *obj;10 struct bpf_object *obj;
tools/testing/selftests/bpf/prog_tests/xdp_adjust_tail.c+5−5
@@ -4,7 +4,7 @@ · 3 unmodified lines
4 4
5static void test_xdp_adjust_tail_shrink(void)5static void test_xdp_adjust_tail_shrink(void)
6{6{
7 const char *file = "./test_xdp_adjust_tail_shrink.o";7 const char *file = "./test_xdp_adjust_tail_shrink.bpf.o";
8 __u32 expect_sz;8 __u32 expect_sz;
9 struct bpf_object *obj;9 struct bpf_object *obj;
10 int err, prog_fd;10 int err, prog_fd;
@@ -39,7 +39,7 @@ static void test_xdp_adjust_tail_shrink(void) · 28 unmodified lines
39 39
40static void test_xdp_adjust_tail_grow(void)40static void test_xdp_adjust_tail_grow(void)
41{41{
42 const char *file = "./test_xdp_adjust_tail_grow.o";42 const char *file = "./test_xdp_adjust_tail_grow.bpf.o";
43 struct bpf_object *obj;43 struct bpf_object *obj;
44 char buf[4096]; /* avoid segfault: large buf to hold grow results */44 char buf[4096]; /* avoid segfault: large buf to hold grow results */
45 __u32 expect_sz;45 __u32 expect_sz;
@@ -73,7 +73,7 @@ static void test_xdp_adjust_tail_grow(void) · 27 unmodified lines
73 73
74static void test_xdp_adjust_tail_grow2(void)74static void test_xdp_adjust_tail_grow2(void)
75{75{
76 const char *file = "./test_xdp_adjust_tail_grow.o";76 const char *file = "./test_xdp_adjust_tail_grow.bpf.o";
77 char buf[4096]; /* avoid segfault: large buf to hold grow results */77 char buf[4096]; /* avoid segfault: large buf to hold grow results */
78 int tailroom = 320; /* SKB_DATA_ALIGN(sizeof(struct skb_shared_info))*/;78 int tailroom = 320; /* SKB_DATA_ALIGN(sizeof(struct skb_shared_info))*/;
79 struct bpf_object *obj;79 struct bpf_object *obj;
@@ -135,7 +135,7 @@ static void test_xdp_adjust_tail_grow2(void) · 55 unmodified lines
135 135
136static void test_xdp_adjust_frags_tail_shrink(void)136static void test_xdp_adjust_frags_tail_shrink(void)
137{137{
138 const char *file = "./test_xdp_adjust_tail_shrink.o";138 const char *file = "./test_xdp_adjust_tail_shrink.bpf.o";
139 __u32 exp_size;139 __u32 exp_size;
140 struct bpf_program *prog;140 struct bpf_program *prog;
141 struct bpf_object *obj;141 struct bpf_object *obj;
@@ -202,7 +202,7 @@ out: · 60 unmodified lines
202 202
203static void test_xdp_adjust_frags_tail_grow(void)203static void test_xdp_adjust_frags_tail_grow(void)
204{204{
205 const char *file = "./test_xdp_adjust_tail_grow.o";205 const char *file = "./test_xdp_adjust_tail_grow.bpf.o";
206 __u32 exp_size;206 __u32 exp_size;
207 struct bpf_program *prog;207 struct bpf_program *prog;
208 struct bpf_object *obj;208 struct bpf_object *obj;
tools/testing/selftests/bpf/prog_tests/xdp_attach.c+1−1
@@ -8,7 +8,7 @@ void serial_test_xdp_attach(void) · 7 unmodified lines
8{8{
9 __u32 duration = 0, id1, id2, id0 = 0, len;9 __u32 duration = 0, id1, id2, id0 = 0, len;
10 struct bpf_object *obj1, *obj2, *obj3;10 struct bpf_object *obj1, *obj2, *obj3;
11 const char *file = "./test_xdp.o";11 const char *file = "./test_xdp.bpf.o";
12 struct bpf_prog_info info = {};12 struct bpf_prog_info info = {};
13 int err, fd1, fd2, fd3;13 int err, fd1, fd2, fd3;
14 LIBBPF_OPTS(bpf_xdp_attach_opts, opts);14 LIBBPF_OPTS(bpf_xdp_attach_opts, opts);
tools/testing/selftests/bpf/prog_tests/xdp_info.c+1−1
@@ -7,7 +7,7 @@ · 6 unmodified lines
7void serial_test_xdp_info(void)7void serial_test_xdp_info(void)
8{8{
9 __u32 len = sizeof(struct bpf_prog_info), duration = 0, prog_id;9 __u32 len = sizeof(struct bpf_prog_info), duration = 0, prog_id;
10 const char *file = "./xdp_dummy.o";10 const char *file = "./xdp_dummy.bpf.o";
11 struct bpf_prog_info info = {};11 struct bpf_prog_info info = {};
12 struct bpf_object *obj;12 struct bpf_object *obj;
13 int err, prog_fd;13 int err, prog_fd;
tools/testing/selftests/bpf/prog_tests/xdp_perf.c+1−1
@@ -3,7 +3,7 @@ · 2 unmodified lines
3 3
4void test_xdp_perf(void)4void test_xdp_perf(void)
5{5{
6 const char *file = "./xdp_dummy.o";6 const char *file = "./xdp_dummy.bpf.o";
7 struct bpf_object *obj;7 struct bpf_object *obj;
8 char in[128], out[128];8 char in[128], out[128];
9 int err, prog_fd;9 int err, prog_fd;
tools/testing/selftests/bpf/prog_tests/xdp_synproxy.c+1−1
@@ -82,7 +82,7 @@ static void test_synproxy(bool xdp) · 81 unmodified lines
82 SYS("ethtool -K tmp0 tx off");82 SYS("ethtool -K tmp0 tx off");
83 if (xdp)83 if (xdp)
84 /* Workaround required for veth. */84 /* Workaround required for veth. */
85 SYS("ip link set tmp0 xdp object xdp_dummy.o section xdp 2> /dev/null");85 SYS("ip link set tmp0 xdp object xdp_dummy.bpf.o section xdp 2> /dev/null");
86 86
87 ns = open_netns("synproxy");87 ns = open_netns("synproxy");
88 if (!ASSERT_OK_PTR(ns, "setns"))88 if (!ASSERT_OK_PTR(ns, "setns"))
tools/testing/selftests/bpf/progs/bind4_prog.c+0−2
@@ -6,8 +6,6 @@ · 5 unmodified lines
6#include <linux/bpf.h>6#include <linux/bpf.h>
7#include <linux/in.h>7#include <linux/in.h>
8#include <linux/in6.h>8#include <linux/in6.h>
9#include <sys/socket.h>
10#include <netinet/tcp.h>
11#include <linux/if.h>9#include <linux/if.h>
12#include <errno.h>10#include <errno.h>
13 11
tools/testing/selftests/bpf/progs/bind6_prog.c+0−2
@@ -6,8 +6,6 @@ · 5 unmodified lines
6#include <linux/bpf.h>6#include <linux/bpf.h>
7#include <linux/in.h>7#include <linux/in.h>
8#include <linux/in6.h>8#include <linux/in6.h>
9#include <sys/socket.h>
10#include <netinet/tcp.h>
11#include <linux/if.h>9#include <linux/if.h>
12#include <errno.h>10#include <errno.h>
13 11
tools/testing/selftests/bpf/progs/bpf_flow.c+15−0
@@ -22,6 +22,8 @@ · 21 unmodified lines
22#define PROG(F) PROG_(F, _##F)22#define PROG(F) PROG_(F, _##F)
23#define PROG_(NUM, NAME) SEC("flow_dissector") int flow_dissector_##NUM23#define PROG_(NUM, NAME) SEC("flow_dissector") int flow_dissector_##NUM
24 24
25#define FLOW_CONTINUE_SADDR 0x7f00007f /* 127.0.0.127 */
26
25/* These are the identifiers of the BPF programs that will be used in tail27/* 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 and28 * 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.29 * bpf_func_ above, we have only 6 to work with, anything after will be cropped.
@@ -143,6 +145,19 @@ int _dissect(struct __sk_buff *skb) · 115 unmodified lines
143{145{
144 struct bpf_flow_keys *keys = skb->flow_keys;146 struct bpf_flow_keys *keys = skb->flow_keys;
145 147
148 if (keys->n_proto == bpf_htons(ETH_P_IP)) {
149 /* IP traffic from FLOW_CONTINUE_SADDR falls-back to
150 * standard dissector
151 */
152 struct iphdr *iph, _iph;
153
154 iph = bpf_flow_dissect_get_header(skb, sizeof(*iph), &_iph);
155 if (iph && iph->ihl == 5 &&
156 iph->saddr == bpf_htonl(FLOW_CONTINUE_SADDR)) {
157 return BPF_FLOW_DISSECTOR_CONTINUE;
158 }
159 }
160
146 return parse_eth_proto(skb, keys->n_proto);161 return parse_eth_proto(skb, keys->n_proto);
147}162}
148 163
tools/testing/selftests/bpf/progs/bpf_iter.h+7−0
@@ -17,6 +17,7 @@ · 16 unmodified lines
17#define bpf_iter__bpf_sk_storage_map bpf_iter__bpf_sk_storage_map___not_used17#define bpf_iter__bpf_sk_storage_map bpf_iter__bpf_sk_storage_map___not_used
18#define bpf_iter__sockmap bpf_iter__sockmap___not_used18#define bpf_iter__sockmap bpf_iter__sockmap___not_used
19#define bpf_iter__bpf_link bpf_iter__bpf_link___not_used19#define bpf_iter__bpf_link bpf_iter__bpf_link___not_used
20#define bpf_iter__cgroup bpf_iter__cgroup___not_used
20#define btf_ptr btf_ptr___not_used21#define btf_ptr btf_ptr___not_used
21#define BTF_F_COMPACT BTF_F_COMPACT___not_used22#define BTF_F_COMPACT BTF_F_COMPACT___not_used
22#define BTF_F_NONAME BTF_F_NONAME___not_used23#define BTF_F_NONAME BTF_F_NONAME___not_used
@@ -40,6 +41,7 @@ · 17 unmodified lines
40#undef bpf_iter__bpf_sk_storage_map41#undef bpf_iter__bpf_sk_storage_map
41#undef bpf_iter__sockmap42#undef bpf_iter__sockmap
42#undef bpf_iter__bpf_link43#undef bpf_iter__bpf_link
44#undef bpf_iter__cgroup
43#undef btf_ptr45#undef btf_ptr
44#undef BTF_F_COMPACT46#undef BTF_F_COMPACT
45#undef BTF_F_NONAME47#undef BTF_F_NONAME
@@ -141,6 +143,11 @@ struct bpf_iter__bpf_link { · 95 unmodified lines
141 struct bpf_link *link;143 struct bpf_link *link;
142};144};
143 145
146struct bpf_iter__cgroup {
147 struct bpf_iter_meta *meta;
148 struct cgroup *cgroup;
149} __attribute__((preserve_access_index));
150
144struct btf_ptr {151struct btf_ptr {
145 void *ptr;152 void *ptr;
146 __u32 type_id;153 __u32 type_id;
tools/testing/selftests/bpf/progs/bpf_tracing_net.h+31−1
@@ -6,13 +6,41 @@ · 5 unmodified lines
6#define AF_INET6 106#define AF_INET6 10
7 7
8#define SOL_SOCKET 18#define SOL_SOCKET 1
9#define SO_REUSEADDR 2
9#define SO_SNDBUF 710#define SO_SNDBUF 7
10#define __SO_ACCEPTCON (1 << 16)11#define SO_RCVBUF 8
12#define SO_KEEPALIVE 9
11#define SO_PRIORITY 1213#define SO_PRIORITY 12
14#define SO_REUSEPORT 15
15#define SO_RCVLOWAT 18
16#define SO_BINDTODEVICE 25
17#define SO_MARK 36
18#define SO_MAX_PACING_RATE 47
19#define SO_BINDTOIFINDEX 62
20#define SO_TXREHASH 74
21#define __SO_ACCEPTCON (1 << 16)
22
23#define IP_TOS 1
24
25#define IPV6_TCLASS 67
26#define IPV6_AUTOFLOWLABEL 70
12 27
13#define SOL_TCP 628#define SOL_TCP 6
29#define TCP_NODELAY 1
30#define TCP_MAXSEG 2
31#define TCP_KEEPIDLE 4
32#define TCP_KEEPINTVL 5
33#define TCP_KEEPCNT 6
34#define TCP_SYNCNT 7
35#define TCP_WINDOW_CLAMP 10
14#define TCP_CONGESTION 1336#define TCP_CONGESTION 13
37#define TCP_THIN_LINEAR_TIMEOUTS 16
38#define TCP_USER_TIMEOUT 18
39#define TCP_NOTSENT_LOWAT 25
40#define TCP_SAVE_SYN 27
41#define TCP_SAVED_SYN 28
15#define TCP_CA_NAME_MAX 1642#define TCP_CA_NAME_MAX 16
43#define TCP_NAGLE_OFF 1
16 44
17#define ICSK_TIME_RETRANS 145#define ICSK_TIME_RETRANS 1
18#define ICSK_TIME_PROBE0 346#define ICSK_TIME_PROBE0 3
@@ -49,6 +77,8 @@ · 30 unmodified lines
49#define sk_state __sk_common.skc_state77#define sk_state __sk_common.skc_state
50#define sk_v6_daddr __sk_common.skc_v6_daddr78#define sk_v6_daddr __sk_common.skc_v6_daddr
51#define sk_v6_rcv_saddr __sk_common.skc_v6_rcv_saddr79#define sk_v6_rcv_saddr __sk_common.skc_v6_rcv_saddr
80#define sk_flags __sk_common.skc_flags
81#define sk_reuse __sk_common.skc_reuse
52 82
53#define s6_addr32 in6_u.u6_addr3283#define s6_addr32 in6_u.u6_addr32
54 84
tools/testing/selftests/bpf/progs/cb_refs.c+116−0
@@ -0,0 +1,116 @@
1// SPDX-License-Identifier: GPL-2.0
2#include <vmlinux.h>
3#include <bpf/bpf_tracing.h>
4#include <bpf/bpf_helpers.h>
5
6struct map_value {
7 struct prog_test_ref_kfunc __kptr_ref *ptr;
8};
9
10struct {
11 __uint(type, BPF_MAP_TYPE_ARRAY);
12 __type(key, int);
13 __type(value, struct map_value);
14 __uint(max_entries, 16);
15} array_map SEC(".maps");
16
17extern struct prog_test_ref_kfunc *bpf_kfunc_call_test_acquire(unsigned long *sp) __ksym;
18extern void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym;
19
20static __noinline int cb1(void *map, void *key, void *value, void *ctx)
21{
22 void *p = *(void **)ctx;
23 bpf_kfunc_call_test_release(p);
24 /* Without the fix this would cause underflow */
25 return 0;
26}
27
28SEC("?tc")
29int underflow_prog(void *ctx)
30{
31 struct prog_test_ref_kfunc *p;
32 unsigned long sl = 0;
33
34 p = bpf_kfunc_call_test_acquire(&sl);
35 if (!p)
36 return 0;
37 bpf_for_each_map_elem(&array_map, cb1, &p, 0);
38 return 0;
39}
40
41static __always_inline int cb2(void *map, void *key, void *value, void *ctx)
42{
43 unsigned long sl = 0;
44
45 *(void **)ctx = bpf_kfunc_call_test_acquire(&sl);
46 /* Without the fix this would leak memory */
47 return 0;
48}
49
50SEC("?tc")
51int leak_prog(void *ctx)
52{
53 struct prog_test_ref_kfunc *p;
54 struct map_value *v;
55 unsigned long sl;
56
57 v = bpf_map_lookup_elem(&array_map, &(int){0});
58 if (!v)
59 return 0;
60
61 p = NULL;
62 bpf_for_each_map_elem(&array_map, cb2, &p, 0);
63 p = bpf_kptr_xchg(&v->ptr, p);
64 if (p)
65 bpf_kfunc_call_test_release(p);
66 return 0;
67}
68
69static __always_inline int cb(void *map, void *key, void *value, void *ctx)
70{
71 return 0;
72}
73
74static __always_inline int cb3(void *map, void *key, void *value, void *ctx)
75{
76 unsigned long sl = 0;
77 void *p;
78
79 bpf_kfunc_call_test_acquire(&sl);
80 bpf_for_each_map_elem(&array_map, cb, &p, 0);
81 /* It should only complain here, not in cb. This is why we need
82 * callback_ref to be set to frameno.
83 */
84 return 0;
85}
86
87SEC("?tc")
88int nested_cb(void *ctx)
89{
90 struct prog_test_ref_kfunc *p;
91 unsigned long sl = 0;
92 int sp = 0;
93
94 p = bpf_kfunc_call_test_acquire(&sl);
95 if (!p)
96 return 0;
97 bpf_for_each_map_elem(&array_map, cb3, &sp, 0);
98 bpf_kfunc_call_test_release(p);
99 return 0;
100}
101
102SEC("?tc")
103int non_cb_transfer_ref(void *ctx)
104{
105 struct prog_test_ref_kfunc *p;
106 unsigned long sl = 0;
107
108 p = bpf_kfunc_call_test_acquire(&sl);
109 if (!p)
110 return 0;
111 cb1(NULL, NULL, NULL, &p);
112 bpf_kfunc_call_test_acquire(&sl);
113 return 0;
114}
115
116char _license[] SEC("license") = "GPL";
tools/testing/selftests/bpf/progs/cgroup_getset_retval_hooks.c+16−0
@@ -0,0 +1,16 @@
1// SPDX-License-Identifier: GPL-2.0-only
2
3#include <linux/bpf.h>
4#include <bpf/bpf_helpers.h>
5
6#define BPF_RETVAL_HOOK(name, section, ctx, expected_err) \
7 __attribute__((__section__("?" section))) \
8 int name(struct ctx *_ctx) \
9 { \
10 bpf_set_retval(bpf_get_retval()); \
11 return 1; \
12 }
13
14#include "cgroup_getset_retval_hooks.h"
15
16#undef BPF_RETVAL_HOOK
tools/testing/selftests/bpf/progs/cgroup_hierarchical_stats.c+226−0
@@ -0,0 +1,226 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Functions to manage eBPF programs attached to cgroup subsystems
4 *
5 * Copyright 2022 Google LLC.
6 */
7#include "vmlinux.h"
8#include <bpf/bpf_helpers.h>
9#include <bpf/bpf_tracing.h>
10#include <bpf/bpf_core_read.h>
11
12char _license[] SEC("license") = "GPL";
13
14/*
15 * Start times are stored per-task, not per-cgroup, as multiple tasks in one
16 * cgroup can perform reclaim concurrently.
17 */
18struct {
19 __uint(type, BPF_MAP_TYPE_TASK_STORAGE);
20 __uint(map_flags, BPF_F_NO_PREALLOC);
21 __type(key, int);
22 __type(value, __u64);
23} vmscan_start_time SEC(".maps");
24
25struct vmscan_percpu {
26 /* Previous percpu state, to figure out if we have new updates */
27 __u64 prev;
28 /* Current percpu state */
29 __u64 state;
30};
31
32struct vmscan {
33 /* State propagated through children, pending aggregation */
34 __u64 pending;
35 /* Total state, including all cpus and all children */
36 __u64 state;
37};
38
39struct {
40 __uint(type, BPF_MAP_TYPE_PERCPU_HASH);
41 __uint(max_entries, 100);
42 __type(key, __u64);
43 __type(value, struct vmscan_percpu);
44} pcpu_cgroup_vmscan_elapsed SEC(".maps");
45
46struct {
47 __uint(type, BPF_MAP_TYPE_HASH);
48 __uint(max_entries, 100);
49 __type(key, __u64);
50 __type(value, struct vmscan);
51} cgroup_vmscan_elapsed SEC(".maps");
52
53extern void cgroup_rstat_updated(struct cgroup *cgrp, int cpu) __ksym;
54extern void cgroup_rstat_flush(struct cgroup *cgrp) __ksym;
55
56static struct cgroup *task_memcg(struct task_struct *task)
57{
58 int cgrp_id;
59
60#if __has_builtin(__builtin_preserve_enum_value)
61 cgrp_id = bpf_core_enum_value(enum cgroup_subsys_id, memory_cgrp_id);
62#else
63 cgrp_id = memory_cgrp_id;
64#endif
65 return task->cgroups->subsys[cgrp_id]->cgroup;
66}
67
68static uint64_t cgroup_id(struct cgroup *cgrp)
69{
70 return cgrp->kn->id;
71}
72
73static int create_vmscan_percpu_elem(__u64 cg_id, __u64 state)
74{
75 struct vmscan_percpu pcpu_init = {.state = state, .prev = 0};
76
77 return bpf_map_update_elem(&pcpu_cgroup_vmscan_elapsed, &cg_id,
78 &pcpu_init, BPF_NOEXIST);
79}
80
81static int create_vmscan_elem(__u64 cg_id, __u64 state, __u64 pending)
82{
83 struct vmscan init = {.state = state, .pending = pending};
84
85 return bpf_map_update_elem(&cgroup_vmscan_elapsed, &cg_id,
86 &init, BPF_NOEXIST);
87}
88
89SEC("tp_btf/mm_vmscan_memcg_reclaim_begin")
90int BPF_PROG(vmscan_start, int order, gfp_t gfp_flags)
91{
92 struct task_struct *task = bpf_get_current_task_btf();
93 __u64 *start_time_ptr;
94
95 start_time_ptr = bpf_task_storage_get(&vmscan_start_time, task, 0,
96 BPF_LOCAL_STORAGE_GET_F_CREATE);
97 if (start_time_ptr)
98 *start_time_ptr = bpf_ktime_get_ns();
99 return 0;
100}
101
102SEC("tp_btf/mm_vmscan_memcg_reclaim_end")
103int BPF_PROG(vmscan_end, unsigned long nr_reclaimed)
104{
105 struct vmscan_percpu *pcpu_stat;
106 struct task_struct *current = bpf_get_current_task_btf();
107 struct cgroup *cgrp;
108 __u64 *start_time_ptr;
109 __u64 current_elapsed, cg_id;
110 __u64 end_time = bpf_ktime_get_ns();
111
112 /*
113 * cgrp is the first parent cgroup of current that has memcg enabled in
114 * its subtree_control, or NULL if memcg is disabled in the entire tree.
115 * In a cgroup hierarchy like this:
116 * a
117 * / \
118 * b c
119 * If "a" has memcg enabled, while "b" doesn't, then processes in "b"
120 * will accumulate their stats directly to "a". This makes sure that no
121 * stats are lost from processes in leaf cgroups that don't have memcg
122 * enabled, but only exposes stats for cgroups that have memcg enabled.
123 */
124 cgrp = task_memcg(current);
125 if (!cgrp)
126 return 0;
127
128 cg_id = cgroup_id(cgrp);
129 start_time_ptr = bpf_task_storage_get(&vmscan_start_time, current, 0,
130 BPF_LOCAL_STORAGE_GET_F_CREATE);
131 if (!start_time_ptr)
132 return 0;
133
134 current_elapsed = end_time - *start_time_ptr;
135 pcpu_stat = bpf_map_lookup_elem(&pcpu_cgroup_vmscan_elapsed,
136 &cg_id);
137 if (pcpu_stat)
138 pcpu_stat->state += current_elapsed;
139 else if (create_vmscan_percpu_elem(cg_id, current_elapsed))
140 return 0;
141
142 cgroup_rstat_updated(cgrp, bpf_get_smp_processor_id());
143 return 0;
144}
145
146SEC("fentry/bpf_rstat_flush")
147int BPF_PROG(vmscan_flush, struct cgroup *cgrp, struct cgroup *parent, int cpu)
148{
149 struct vmscan_percpu *pcpu_stat;
150 struct vmscan *total_stat, *parent_stat;
151 __u64 cg_id = cgroup_id(cgrp);
152 __u64 parent_cg_id = parent ? cgroup_id(parent) : 0;
153 __u64 *pcpu_vmscan;
154 __u64 state;
155 __u64 delta = 0;
156
157 /* Add CPU changes on this level since the last flush */
158 pcpu_stat = bpf_map_lookup_percpu_elem(&pcpu_cgroup_vmscan_elapsed,
159 &cg_id, cpu);
160 if (pcpu_stat) {
161 state = pcpu_stat->state;
162 delta += state - pcpu_stat->prev;
163 pcpu_stat->prev = state;
164 }
165
166 total_stat = bpf_map_lookup_elem(&cgroup_vmscan_elapsed, &cg_id);
167 if (!total_stat) {
168 if (create_vmscan_elem(cg_id, delta, 0))
169 return 0;
170
171 goto update_parent;
172 }
173
174 /* Collect pending stats from subtree */
175 if (total_stat->pending) {
176 delta += total_stat->pending;
177 total_stat->pending = 0;
178 }
179
180 /* Propagate changes to this cgroup's total */
181 total_stat->state += delta;
182
183update_parent:
184 /* Skip if there are no changes to propagate, or no parent */
185 if (!delta || !parent_cg_id)
186 return 0;
187
188 /* Propagate changes to cgroup's parent */
189 parent_stat = bpf_map_lookup_elem(&cgroup_vmscan_elapsed,
190 &parent_cg_id);
191 if (parent_stat)
192 parent_stat->pending += delta;
193 else
194 create_vmscan_elem(parent_cg_id, 0, delta);
195 return 0;
196}
197
198SEC("iter.s/cgroup")
199int BPF_PROG(dump_vmscan, struct bpf_iter_meta *meta, struct cgroup *cgrp)
200{
201 struct seq_file *seq = meta->seq;
202 struct vmscan *total_stat;
203 __u64 cg_id = cgrp ? cgroup_id(cgrp) : 0;
204
205 /* Do nothing for the terminal call */
206 if (!cg_id)
207 return 1;
208
209 /* Flush the stats to make sure we get the most updated numbers */
210 cgroup_rstat_flush(cgrp);
211
212 total_stat = bpf_map_lookup_elem(&cgroup_vmscan_elapsed, &cg_id);
213 if (!total_stat) {
214 BPF_SEQ_PRINTF(seq, "cg_id: %llu, total_vmscan_delay: 0\n",
215 cg_id);
216 } else {
217 BPF_SEQ_PRINTF(seq, "cg_id: %llu, total_vmscan_delay: %llu\n",
218 cg_id, total_stat->state);
219 }
220
221 /*
222 * We only dump stats for one cgroup here, so return 1 to stop
223 * iteration after the first cgroup.
224 */
225 return 1;
226}
tools/testing/selftests/bpf/progs/cgroup_iter.c+39−0
@@ -0,0 +1,39 @@
1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (c) 2022 Google */
3
4#include "bpf_iter.h"
5#include <bpf/bpf_helpers.h>
6#include <bpf/bpf_tracing.h>
7
8char _license[] SEC("license") = "GPL";
9int terminate_early = 0;
10u64 terminal_cgroup = 0;
11
12static inline u64 cgroup_id(struct cgroup *cgrp)
13{
14 return cgrp->kn->id;
15}
16
17SEC("iter/cgroup")
18int cgroup_id_printer(struct bpf_iter__cgroup *ctx)
19{
20 struct seq_file *seq = ctx->meta->seq;
21 struct cgroup *cgrp = ctx->cgroup;
22
23 /* epilogue */
24 if (cgrp == NULL) {
25 BPF_SEQ_PRINTF(seq, "epilogue\n");
26 return 0;
27 }
28
29 /* prologue */
30 if (ctx->meta->seq_num == 0)
31 BPF_SEQ_PRINTF(seq, "prologue\n");
32
33 BPF_SEQ_PRINTF(seq, "%8llu\n", cgroup_id(cgrp));
34
35 if (terminal_cgroup == cgroup_id(cgrp))
36 return 1;
37
38 return terminate_early ? 1 : 0;
39}
tools/testing/selftests/bpf/progs/connect4_prog.c+3−2
@@ -7,14 +7,15 @@ · 6 unmodified lines
7#include <linux/bpf.h>7#include <linux/bpf.h>
8#include <linux/in.h>8#include <linux/in.h>
9#include <linux/in6.h>9#include <linux/in6.h>
10#include <sys/socket.h>10#include <linux/tcp.h>
11#include <netinet/tcp.h>
12#include <linux/if.h>11#include <linux/if.h>
13#include <errno.h>12#include <errno.h>
14 13
15#include <bpf/bpf_helpers.h>14#include <bpf/bpf_helpers.h>
16#include <bpf/bpf_endian.h>15#include <bpf/bpf_endian.h>
17 16
17#include "bpf_tcp_helpers.h"
18
18#define SRC_REWRITE_IP4 0x7f000004U19#define SRC_REWRITE_IP4 0x7f000004U
19#define DST_REWRITE_IP4 0x7f000001U20#define DST_REWRITE_IP4 0x7f000001U
20#define DST_REWRITE_PORT4 444421#define DST_REWRITE_PORT4 4444
tools/testing/selftests/bpf/progs/fexit_bpf2bpf.c+4−4
@@ -73,10 +73,10 @@ int test_subprog2(struct args_subprog2 *ctx) · 72 unmodified lines
73 __builtin_preserve_access_index(&skb->len));73 __builtin_preserve_access_index(&skb->len));
74 74
75 ret = ctx->ret;75 ret = ctx->ret;
76 /* bpf_prog_test_load() loads "test_pkt_access.o" with BPF_F_TEST_RND_HI3276 /* bpf_prog_test_load() loads "test_pkt_access.bpf.o" with
77 * which randomizes upper 32 bits after BPF_ALU32 insns.77 * BPF_F_TEST_RND_HI32 which randomizes upper 32 bits after BPF_ALU32
78 * Hence after 'w0 <<= 1' upper bits of $rax are random.78 * insns. Hence after 'w0 <<= 1' upper bits of $rax are random. That is
79 * That is expected and correct. Trim them.79 * expected and correct. Trim them.
80 */80 */
81 ret = (__u32) ret;81 ret = (__u32) ret;
82 if (len != 74 || ret != 148)82 if (len != 74 || ret != 148)
tools/testing/selftests/bpf/progs/htab_update.c+29−0
@@ -0,0 +1,29 @@
1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (C) 2022. Huawei Technologies Co., Ltd */
3#include <linux/bpf.h>
4#include <bpf/bpf_helpers.h>
5#include <bpf/bpf_tracing.h>
6
7char _license[] SEC("license") = "GPL";
8
9struct {
10 __uint(type, BPF_MAP_TYPE_HASH);
11 __uint(max_entries, 1);
12 __uint(key_size, sizeof(__u32));
13 __uint(value_size, sizeof(__u32));
14} htab SEC(".maps");
15
16int pid = 0;
17int update_err = 0;
18
19SEC("?fentry/lookup_elem_raw")
20int lookup_elem_raw(void *ctx)
21{
22 __u32 key = 0, value = 1;
23
24 if ((bpf_get_current_pid_tgid() >> 32) != pid)
25 return 0;
26
27 update_err = bpf_map_update_elem(&htab, &key, &value, 0);
28 return 0;
29}
tools/testing/selftests/bpf/progs/read_bpf_task_storage_busy.c+39−0
@@ -0,0 +1,39 @@
1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (C) 2022. Huawei Technologies Co., Ltd */
3#include "vmlinux.h"
4#include <bpf/bpf_helpers.h>
5#include <bpf/bpf_tracing.h>
6
7extern bool CONFIG_PREEMPT __kconfig __weak;
8extern const int bpf_task_storage_busy __ksym;
9
10char _license[] SEC("license") = "GPL";
11
12int pid = 0;
13int busy = 0;
14
15struct {
16 __uint(type, BPF_MAP_TYPE_TASK_STORAGE);
17 __uint(map_flags, BPF_F_NO_PREALLOC);
18 __type(key, int);
19 __type(value, long);
20} task SEC(".maps");
21
22SEC("raw_tp/sys_enter")
23int BPF_PROG(read_bpf_task_storage_busy)
24{
25 int *value;
26 int key;
27
28 if (!CONFIG_PREEMPT)
29 return 0;
30
31 if (bpf_get_current_pid_tgid() >> 32 != pid)
32 return 0;
33
34 value = bpf_this_cpu_ptr(&bpf_task_storage_busy);
35 if (value)
36 busy = *value;
37
38 return 0;
39}
tools/testing/selftests/bpf/progs/setget_sockopt.c+395−0
@@ -0,0 +1,395 @@
1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (c) Meta Platforms, Inc. and affiliates. */
3
4#include "vmlinux.h"
5#include "bpf_tracing_net.h"
6#include <bpf/bpf_core_read.h>
7#include <bpf/bpf_helpers.h>
8#include <bpf/bpf_tracing.h>
9
10#ifndef ARRAY_SIZE
11#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
12#endif
13
14extern unsigned long CONFIG_HZ __kconfig;
15
16const volatile char veth[IFNAMSIZ];
17const volatile int veth_ifindex;
18
19int nr_listen;
20int nr_passive;
21int nr_active;
22int nr_connect;
23int nr_binddev;
24int nr_socket_post_create;
25
26struct sockopt_test {
27 int opt;
28 int new;
29 int restore;
30 int expected;
31 int tcp_expected;
32 unsigned int flip:1;
33};
34
35static const char not_exist_cc[] = "not_exist";
36static const char cubic_cc[] = "cubic";
37static const char reno_cc[] = "reno";
38
39static const struct sockopt_test sol_socket_tests[] = {
40 { .opt = SO_REUSEADDR, .flip = 1, },
41 { .opt = SO_SNDBUF, .new = 8123, .expected = 8123 * 2, },
42 { .opt = SO_RCVBUF, .new = 8123, .expected = 8123 * 2, },
43 { .opt = SO_KEEPALIVE, .flip = 1, },
44 { .opt = SO_PRIORITY, .new = 0xeb9f, .expected = 0xeb9f, },
45 { .opt = SO_REUSEPORT, .flip = 1, },
46 { .opt = SO_RCVLOWAT, .new = 8123, .expected = 8123, },
47 { .opt = SO_MARK, .new = 0xeb9f, .expected = 0xeb9f, },
48 { .opt = SO_MAX_PACING_RATE, .new = 0xeb9f, .expected = 0xeb9f, },
49 { .opt = SO_TXREHASH, .flip = 1, },
50 { .opt = 0, },
51};
52
53static const struct sockopt_test sol_tcp_tests[] = {
54 { .opt = TCP_NODELAY, .flip = 1, },
55 { .opt = TCP_KEEPIDLE, .new = 123, .expected = 123, .restore = 321, },
56 { .opt = TCP_KEEPINTVL, .new = 123, .expected = 123, .restore = 321, },
57 { .opt = TCP_KEEPCNT, .new = 123, .expected = 123, .restore = 124, },
58 { .opt = TCP_SYNCNT, .new = 123, .expected = 123, .restore = 124, },
59 { .opt = TCP_WINDOW_CLAMP, .new = 8123, .expected = 8123, .restore = 8124, },
60 { .opt = TCP_CONGESTION, },
61 { .opt = TCP_THIN_LINEAR_TIMEOUTS, .flip = 1, },
62 { .opt = TCP_USER_TIMEOUT, .new = 123400, .expected = 123400, },
63 { .opt = TCP_NOTSENT_LOWAT, .new = 1314, .expected = 1314, },
64 { .opt = 0, },
65};
66
67static const struct sockopt_test sol_ip_tests[] = {
68 { .opt = IP_TOS, .new = 0xe1, .expected = 0xe1, .tcp_expected = 0xe0, },
69 { .opt = 0, },
70};
71
72static const struct sockopt_test sol_ipv6_tests[] = {
73 { .opt = IPV6_TCLASS, .new = 0xe1, .expected = 0xe1, .tcp_expected = 0xe0, },
74 { .opt = IPV6_AUTOFLOWLABEL, .flip = 1, },
75 { .opt = 0, },
76};
77
78struct loop_ctx {
79 void *ctx;
80 struct sock *sk;
81};
82
83static int bpf_test_sockopt_flip(void *ctx, struct sock *sk,
84 const struct sockopt_test *t,
85 int level)
86{
87 int old, tmp, new, opt = t->opt;
88
89 opt = t->opt;
90
91 if (bpf_getsockopt(ctx, level, opt, &old, sizeof(old)))
92 return 1;
93 /* kernel initialized txrehash to 255 */
94 if (level == SOL_SOCKET && opt == SO_TXREHASH && old != 0 && old != 1)
95 old = 1;
96
97 new = !old;
98 if (bpf_setsockopt(ctx, level, opt, &new, sizeof(new)))
99 return 1;
100 if (bpf_getsockopt(ctx, level, opt, &tmp, sizeof(tmp)) ||
101 tmp != new)
102 return 1;
103
104 if (bpf_setsockopt(ctx, level, opt, &old, sizeof(old)))
105 return 1;
106
107 return 0;
108}
109
110static int bpf_test_sockopt_int(void *ctx, struct sock *sk,
111 const struct sockopt_test *t,
112 int level)
113{
114 int old, tmp, new, expected, opt;
115
116 opt = t->opt;
117 new = t->new;
118 if (sk->sk_type == SOCK_STREAM && t->tcp_expected)
119 expected = t->tcp_expected;
120 else
121 expected = t->expected;
122
123 if (bpf_getsockopt(ctx, level, opt, &old, sizeof(old)) ||
124 old == new)
125 return 1;
126
127 if (bpf_setsockopt(ctx, level, opt, &new, sizeof(new)))
128 return 1;
129 if (bpf_getsockopt(ctx, level, opt, &tmp, sizeof(tmp)) ||
130 tmp != expected)
131 return 1;
132
133 if (t->restore)
134 old = t->restore;
135 if (bpf_setsockopt(ctx, level, opt, &old, sizeof(old)))
136 return 1;
137
138 return 0;
139}
140
141static int bpf_test_socket_sockopt(__u32 i, struct loop_ctx *lc)
142{
143 const struct sockopt_test *t;
144
145 if (i >= ARRAY_SIZE(sol_socket_tests))
146 return 1;
147
148 t = &sol_socket_tests[i];
149 if (!t->opt)
150 return 1;
151
152 if (t->flip)
153 return bpf_test_sockopt_flip(lc->ctx, lc->sk, t, SOL_SOCKET);
154
155 return bpf_test_sockopt_int(lc->ctx, lc->sk, t, SOL_SOCKET);
156}
157
158static int bpf_test_ip_sockopt(__u32 i, struct loop_ctx *lc)
159{
160 const struct sockopt_test *t;
161
162 if (i >= ARRAY_SIZE(sol_ip_tests))
163 return 1;
164
165 t = &sol_ip_tests[i];
166 if (!t->opt)
167 return 1;
168
169 if (t->flip)
170 return bpf_test_sockopt_flip(lc->ctx, lc->sk, t, IPPROTO_IP);
171
172 return bpf_test_sockopt_int(lc->ctx, lc->sk, t, IPPROTO_IP);
173}
174
175static int bpf_test_ipv6_sockopt(__u32 i, struct loop_ctx *lc)
176{
177 const struct sockopt_test *t;
178
179 if (i >= ARRAY_SIZE(sol_ipv6_tests))
180 return 1;
181
182 t = &sol_ipv6_tests[i];
183 if (!t->opt)
184 return 1;
185
186 if (t->flip)
187 return bpf_test_sockopt_flip(lc->ctx, lc->sk, t, IPPROTO_IPV6);
188
189 return bpf_test_sockopt_int(lc->ctx, lc->sk, t, IPPROTO_IPV6);
190}
191
192static int bpf_test_tcp_sockopt(__u32 i, struct loop_ctx *lc)
193{
194 const struct sockopt_test *t;
195 struct sock *sk;
196 void *ctx;
197
198 if (i >= ARRAY_SIZE(sol_tcp_tests))
199 return 1;
200
201 t = &sol_tcp_tests[i];
202 if (!t->opt)
203 return 1;
204
205 ctx = lc->ctx;
206 sk = lc->sk;
207
208 if (t->opt == TCP_CONGESTION) {
209 char old_cc[16], tmp_cc[16];
210 const char *new_cc;
211 int new_cc_len;
212
213 if (!bpf_setsockopt(ctx, IPPROTO_TCP, TCP_CONGESTION,
214 (void *)not_exist_cc, sizeof(not_exist_cc)))
215 return 1;
216 if (bpf_getsockopt(ctx, IPPROTO_TCP, TCP_CONGESTION, old_cc, sizeof(old_cc)))
217 return 1;
218 if (!bpf_strncmp(old_cc, sizeof(old_cc), cubic_cc)) {
219 new_cc = reno_cc;
220 new_cc_len = sizeof(reno_cc);
221 } else {
222 new_cc = cubic_cc;
223 new_cc_len = sizeof(cubic_cc);
224 }
225 if (bpf_setsockopt(ctx, IPPROTO_TCP, TCP_CONGESTION, (void *)new_cc,
226 new_cc_len))
227 return 1;
228 if (bpf_getsockopt(ctx, IPPROTO_TCP, TCP_CONGESTION, tmp_cc, sizeof(tmp_cc)))
229 return 1;
230 if (bpf_strncmp(tmp_cc, sizeof(tmp_cc), new_cc))
231 return 1;
232 if (bpf_setsockopt(ctx, IPPROTO_TCP, TCP_CONGESTION, old_cc, sizeof(old_cc)))
233 return 1;
234 return 0;
235 }
236
237 if (t->flip)
238 return bpf_test_sockopt_flip(ctx, sk, t, IPPROTO_TCP);
239
240 return bpf_test_sockopt_int(ctx, sk, t, IPPROTO_TCP);
241}
242
243static int bpf_test_sockopt(void *ctx, struct sock *sk)
244{
245 struct loop_ctx lc = { .ctx = ctx, .sk = sk, };
246 __u16 family, proto;
247 int n;
248
249 family = sk->sk_family;
250 proto = sk->sk_protocol;
251
252 n = bpf_loop(ARRAY_SIZE(sol_socket_tests), bpf_test_socket_sockopt, &lc, 0);
253 if (n != ARRAY_SIZE(sol_socket_tests))
254 return -1;
255
256 if (proto == IPPROTO_TCP) {
257 n = bpf_loop(ARRAY_SIZE(sol_tcp_tests), bpf_test_tcp_sockopt, &lc, 0);
258 if (n != ARRAY_SIZE(sol_tcp_tests))
259 return -1;
260 }
261
262 if (family == AF_INET) {
263 n = bpf_loop(ARRAY_SIZE(sol_ip_tests), bpf_test_ip_sockopt, &lc, 0);
264 if (n != ARRAY_SIZE(sol_ip_tests))
265 return -1;
266 } else {
267 n = bpf_loop(ARRAY_SIZE(sol_ipv6_tests), bpf_test_ipv6_sockopt, &lc, 0);
268 if (n != ARRAY_SIZE(sol_ipv6_tests))
269 return -1;
270 }
271
272 return 0;
273}
274
275static int binddev_test(void *ctx)
276{
277 const char empty_ifname[] = "";
278 int ifindex, zero = 0;
279
280 if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
281 (void *)veth, sizeof(veth)))
282 return -1;
283 if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,
284 &ifindex, sizeof(int)) ||
285 ifindex != veth_ifindex)
286 return -1;
287
288 if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
289 (void *)empty_ifname, sizeof(empty_ifname)))
290 return -1;
291 if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,
292 &ifindex, sizeof(int)) ||
293 ifindex != 0)
294 return -1;
295
296 if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,
297 (void *)&veth_ifindex, sizeof(int)))
298 return -1;
299 if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,
300 &ifindex, sizeof(int)) ||
301 ifindex != veth_ifindex)
302 return -1;
303
304 if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,
305 &zero, sizeof(int)))
306 return -1;
307 if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,
308 &ifindex, sizeof(int)) ||
309 ifindex != 0)
310 return -1;
311
312 return 0;
313}
314
315static int test_tcp_maxseg(void *ctx, struct sock *sk)
316{
317 int val = 1314, tmp;
318
319 if (sk->sk_state != TCP_ESTABLISHED)
320 return bpf_setsockopt(ctx, IPPROTO_TCP, TCP_MAXSEG,
321 &val, sizeof(val));
322
323 if (bpf_getsockopt(ctx, IPPROTO_TCP, TCP_MAXSEG, &tmp, sizeof(tmp)) ||
324 tmp > val)
325 return -1;
326
327 return 0;
328}
329
330static int test_tcp_saved_syn(void *ctx, struct sock *sk)
331{
332 __u8 saved_syn[20];
333 int one = 1;
334
335 if (sk->sk_state == TCP_LISTEN)
336 return bpf_setsockopt(ctx, IPPROTO_TCP, TCP_SAVE_SYN,
337 &one, sizeof(one));
338
339 return bpf_getsockopt(ctx, IPPROTO_TCP, TCP_SAVED_SYN,
340 saved_syn, sizeof(saved_syn));
341}
342
343SEC("lsm_cgroup/socket_post_create")
344int BPF_PROG(socket_post_create, struct socket *sock, int family,
345 int type, int protocol, int kern)
346{
347 struct sock *sk = sock->sk;
348
349 if (!sk)
350 return 1;
351
352 nr_socket_post_create += !bpf_test_sockopt(sk, sk);
353 nr_binddev += !binddev_test(sk);
354
355 return 1;
356}
357
358SEC("sockops")
359int skops_sockopt(struct bpf_sock_ops *skops)
360{
361 struct bpf_sock *bpf_sk = skops->sk;
362 struct sock *sk;
363
364 if (!bpf_sk)
365 return 1;
366
367 sk = (struct sock *)bpf_skc_to_tcp_sock(bpf_sk);
368 if (!sk)
369 return 1;
370
371 switch (skops->op) {
372 case BPF_SOCK_OPS_TCP_LISTEN_CB:
373 nr_listen += !(bpf_test_sockopt(skops, sk) ||
374 test_tcp_maxseg(skops, sk) ||
375 test_tcp_saved_syn(skops, sk));
376 break;
377 case BPF_SOCK_OPS_TCP_CONNECT_CB:
378 nr_connect += !(bpf_test_sockopt(skops, sk) ||
379 test_tcp_maxseg(skops, sk));
380 break;
381 case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB:
382 nr_active += !(bpf_test_sockopt(skops, sk) ||
383 test_tcp_maxseg(skops, sk));
384 break;
385 case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB:
386 nr_passive += !(bpf_test_sockopt(skops, sk) ||
387 test_tcp_maxseg(skops, sk) ||
388 test_tcp_saved_syn(skops, sk));
389 break;
390 }
391
392 return 1;
393}
394
395char _license[] SEC("license") = "GPL";
tools/testing/selftests/bpf/progs/tailcall_bpf2bpf4.c+1−1
@@ -19,7 +19,7 @@ struct { · 18 unmodified lines
19int count = 0;19int count = 0;
20int noise = 0;20int noise = 0;
21 21
22__always_inline int subprog_noise(void)22static __always_inline int subprog_noise(void)
23{23{
24 __u32 key = 0;24 __u32 key = 0;
25 25
tools/testing/selftests/bpf/progs/test_tc_dtime.c+0−1
@@ -15,7 +15,6 @@ · 14 unmodified lines
15#include <linux/udp.h>15#include <linux/udp.h>
16#include <bpf/bpf_helpers.h>16#include <bpf/bpf_helpers.h>
17#include <bpf/bpf_endian.h>17#include <bpf/bpf_endian.h>
18#include <sys/socket.h>
19 18
20/* veth_src --- veth_src_fwd --- veth_det_fwd --- veth_dst19/* veth_src --- veth_src_fwd --- veth_det_fwd --- veth_dst
21 * | |20 * | |
tools/testing/selftests/bpf/progs/test_tunnel_kern.c+16−8
@@ -12,6 +12,7 @@ · 11 unmodified lines
12#include <linux/bpf.h>12#include <linux/bpf.h>
13#include <linux/if_ether.h>13#include <linux/if_ether.h>
14#include <linux/if_packet.h>14#include <linux/if_packet.h>
15#include <linux/if_tunnel.h>
15#include <linux/ip.h>16#include <linux/ip.h>
16#include <linux/ipv6.h>17#include <linux/ipv6.h>
17#include <linux/icmp.h>18#include <linux/icmp.h>
@@ -386,7 +387,8 @@ int vxlan_get_tunnel_src(struct __sk_buff *skb) · 368 unmodified lines
386 __u32 orig_daddr;387 __u32 orig_daddr;
387 __u32 index = 0;388 __u32 index = 0;
388 389
389 ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0);390 ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key),
391 BPF_F_TUNINFO_FLAGS);
390 if (ret < 0) {392 if (ret < 0) {
391 log_err(ret);393 log_err(ret);
392 return TC_ACT_SHOT;394 return TC_ACT_SHOT;
@@ -398,10 +400,13 @@ int vxlan_get_tunnel_src(struct __sk_buff *skb) · 5 unmodified lines
398 return TC_ACT_SHOT;400 return TC_ACT_SHOT;
399 }401 }
400 402
401 if (key.local_ipv4 != ASSIGNED_ADDR_VETH1 || md.gbp != 0x800FF) {403 if (key.local_ipv4 != ASSIGNED_ADDR_VETH1 || md.gbp != 0x800FF ||
402 bpf_printk("vxlan key %d local ip 0x%x remote ip 0x%x gbp 0x%x\n",404 !(key.tunnel_flags & TUNNEL_KEY) ||
405 (key.tunnel_flags & TUNNEL_CSUM)) {
406 bpf_printk("vxlan key %d local ip 0x%x remote ip 0x%x gbp 0x%x flags 0x%x\n",
403 key.tunnel_id, key.local_ipv4,407 key.tunnel_id, key.local_ipv4,
404 key.remote_ipv4, md.gbp);408 key.remote_ipv4, md.gbp,
409 bpf_ntohs(key.tunnel_flags));
405 log_err(ret);410 log_err(ret);
406 return TC_ACT_SHOT;411 return TC_ACT_SHOT;
407 }412 }
@@ -541,16 +546,19 @@ int ip6vxlan_get_tunnel_src(struct __sk_buff *skb) · 133 unmodified lines
541 }546 }
542 547
543 ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key),548 ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key),
544 BPF_F_TUNINFO_IPV6);549 BPF_F_TUNINFO_IPV6 | BPF_F_TUNINFO_FLAGS);
545 if (ret < 0) {550 if (ret < 0) {
546 log_err(ret);551 log_err(ret);
547 return TC_ACT_SHOT;552 return TC_ACT_SHOT;
548 }553 }
549 554
550 if (bpf_ntohl(key.local_ipv6[3]) != *local_ip) {555 if (bpf_ntohl(key.local_ipv6[3]) != *local_ip ||
551 bpf_printk("ip6vxlan key %d local ip6 ::%x remote ip6 ::%x label 0x%x\n",556 !(key.tunnel_flags & TUNNEL_KEY) ||
557 !(key.tunnel_flags & TUNNEL_CSUM)) {
558 bpf_printk("ip6vxlan key %d local ip6 ::%x remote ip6 ::%x label 0x%x flags 0x%x\n",
552 key.tunnel_id, bpf_ntohl(key.local_ipv6[3]),559 key.tunnel_id, bpf_ntohl(key.local_ipv6[3]),
553 bpf_ntohl(key.remote_ipv6[3]), key.tunnel_label);560 bpf_ntohl(key.remote_ipv6[3]), key.tunnel_label,
561 bpf_ntohs(key.tunnel_flags));
554 bpf_printk("local_ip 0x%x\n", *local_ip);562 bpf_printk("local_ip 0x%x\n", *local_ip);
555 log_err(ret);563 log_err(ret);
556 return TC_ACT_SHOT;564 return TC_ACT_SHOT;
tools/testing/selftests/bpf/progs/timer.c+0−11
@@ -208,17 +208,6 @@ static int timer_cb2(void *map, int *key, struct hmap_elem *val) · 207 unmodified lines
208 */208 */
209 bpf_map_delete_elem(map, key);209 bpf_map_delete_elem(map, key);
210 210
211 /* in non-preallocated hashmap both 'key' and 'val' are RCU
212 * protected and still valid though this element was deleted
213 * from the map. Arm this timer for ~35 seconds. When callback
214 * finishes the call_rcu will invoke:
215 * htab_elem_free_rcu
216 * check_and_free_timer
217 * bpf_timer_cancel_and_free
218 * to cancel this 35 second sleep and delete the timer for real.
219 */
220 if (bpf_timer_start(&val->timer, 1ull << 35, 0) != 0)
221 err |= 256;
222 ok |= 4;211 ok |= 4;
223 }212 }
224 return 0;213 return 0;
tools/testing/selftests/bpf/task_local_storage_helpers.h+18−0
@@ -0,0 +1,18 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2#ifndef __TASK_LOCAL_STORAGE_HELPER_H
3#define __TASK_LOCAL_STORAGE_HELPER_H
4
5#include <unistd.h>
6#include <sys/syscall.h>
7#include <sys/types.h>
8
9#ifndef __NR_pidfd_open
10#define __NR_pidfd_open 434
11#endif
12
13static inline int sys_pidfd_open(pid_t pid, unsigned int flags)
14{
15 return syscall(__NR_pidfd_open, pid, flags);
16}
17
18#endif
tools/testing/selftests/bpf/test_dev_cgroup.c+1−1
@@ -16,7 +16,7 @@ · 15 unmodified lines
16#include "cgroup_helpers.h"16#include "cgroup_helpers.h"
17#include "testing_helpers.h"17#include "testing_helpers.h"
18 18
19#define DEV_CGROUP_PROG "./dev_cgroup.o"19#define DEV_CGROUP_PROG "./dev_cgroup.bpf.o"
20 20
21#define TEST_CGROUP "/test-bpf-based-device-cgroup/"21#define TEST_CGROUP "/test-bpf-based-device-cgroup/"
22 22
tools/testing/selftests/bpf/test_flow_dissector.sh+8−0
@@ -115,6 +115,14 @@ tc filter add dev lo parent ffff: protocol ip pref 1337 flower ip_proto \ · 114 unmodified lines
115# Send 10 IPv4/UDP packets from port 10. Filter should not drop any.115# Send 10 IPv4/UDP packets from port 10. Filter should not drop any.
116./test_flow_dissector -i 4 -f 10116./test_flow_dissector -i 4 -f 10
117 117
118echo "Testing IPv4 from 127.0.0.127 (fallback to generic dissector)..."
119# Send 10 IPv4/UDP packets from port 8. Filter should not drop any.
120./test_flow_dissector -i 4 -S 127.0.0.127 -f 8
121# Send 10 IPv4/UDP packets from port 9. Filter should drop all.
122./test_flow_dissector -i 4 -S 127.0.0.127 -f 9 -F
123# Send 10 IPv4/UDP packets from port 10. Filter should not drop any.
124./test_flow_dissector -i 4 -S 127.0.0.127 -f 10
125
118echo "Testing IPIP..."126echo "Testing IPIP..."
119# Send 10 IPv4/IPv4/UDP packets from port 8. Filter should not drop any.127# Send 10 IPv4/IPv4/UDP packets from port 8. Filter should not drop any.
120./with_addr.sh ./with_tunnels.sh ./test_flow_dissector -o 4 -e bare -i 4 \128./with_addr.sh ./with_tunnels.sh ./test_flow_dissector -o 4 -e bare -i 4 \
tools/testing/selftests/bpf/test_lirc_mode2_user.c+1−1
@@ -59,7 +59,7 @@ int main(int argc, char **argv) · 58 unmodified lines
59 return 2;59 return 2;
60 }60 }
61 61
62 ret = bpf_prog_test_load("test_lirc_mode2_kern.o",62 ret = bpf_prog_test_load("test_lirc_mode2_kern.bpf.o",
63 BPF_PROG_TYPE_LIRC_MODE2, &obj, &progfd);63 BPF_PROG_TYPE_LIRC_MODE2, &obj, &progfd);
64 if (ret) {64 if (ret) {
65 printf("Failed to load bpf program\n");65 printf("Failed to load bpf program\n");
tools/testing/selftests/bpf/test_maps.c+29−19
@@ -264,10 +264,11 @@ static void test_hashmap_percpu(unsigned int task, void *data) · 263 unmodified lines
264 close(fd);264 close(fd);
265}265}
266 266
267#define VALUE_SIZE 3
267static int helper_fill_hashmap(int max_entries)268static int helper_fill_hashmap(int max_entries)
268{269{
269 int i, fd, ret;270 int i, fd, ret;
270 long long key, value;271 long long key, value[VALUE_SIZE] = {};
271 272
272 fd = bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(key), sizeof(value),273 fd = bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(key), sizeof(value),
273 max_entries, &map_opts);274 max_entries, &map_opts);
@@ -276,8 +277,8 @@ static int helper_fill_hashmap(int max_entries) · 2 unmodified lines
276 "err: %s, flags: 0x%x\n", strerror(errno), map_opts.map_flags);277 "err: %s, flags: 0x%x\n", strerror(errno), map_opts.map_flags);
277 278
278 for (i = 0; i < max_entries; i++) {279 for (i = 0; i < max_entries; i++) {
279 key = i; value = key;280 key = i; value[0] = key;
280 ret = bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST);281 ret = bpf_map_update_elem(fd, &key, value, BPF_NOEXIST);
281 CHECK(ret != 0,282 CHECK(ret != 0,
282 "can't update hashmap",283 "can't update hashmap",
283 "err: %s\n", strerror(ret));284 "err: %s\n", strerror(ret));
@@ -288,8 +289,8 @@ static int helper_fill_hashmap(int max_entries) · 4 unmodified lines
288 289
289static void test_hashmap_walk(unsigned int task, void *data)290static void test_hashmap_walk(unsigned int task, void *data)
290{291{
291 int fd, i, max_entries = 1000;292 int fd, i, max_entries = 10000;
292 long long key, value, next_key;293 long long key, value[VALUE_SIZE], next_key;
293 bool next_key_valid = true;294 bool next_key_valid = true;
294 295
295 fd = helper_fill_hashmap(max_entries);296 fd = helper_fill_hashmap(max_entries);
@@ -297,7 +298,7 @@ static void test_hashmap_walk(unsigned int task, void *data) · 1 unmodified line
297 for (i = 0; bpf_map_get_next_key(fd, !i ? NULL : &key,298 for (i = 0; bpf_map_get_next_key(fd, !i ? NULL : &key,
298 &next_key) == 0; i++) {299 &next_key) == 0; i++) {
299 key = next_key;300 key = next_key;
300 assert(bpf_map_lookup_elem(fd, &key, &value) == 0);301 assert(bpf_map_lookup_elem(fd, &key, value) == 0);
301 }302 }
302 303
303 assert(i == max_entries);304 assert(i == max_entries);
@@ -305,9 +306,9 @@ static void test_hashmap_walk(unsigned int task, void *data) · 1 unmodified line
305 assert(bpf_map_get_next_key(fd, NULL, &key) == 0);306 assert(bpf_map_get_next_key(fd, NULL, &key) == 0);
306 for (i = 0; next_key_valid; i++) {307 for (i = 0; next_key_valid; i++) {
307 next_key_valid = bpf_map_get_next_key(fd, &key, &next_key) == 0;308 next_key_valid = bpf_map_get_next_key(fd, &key, &next_key) == 0;
308 assert(bpf_map_lookup_elem(fd, &key, &value) == 0);309 assert(bpf_map_lookup_elem(fd, &key, value) == 0);
309 value++;310 value[0]++;
310 assert(bpf_map_update_elem(fd, &key, &value, BPF_EXIST) == 0);311 assert(bpf_map_update_elem(fd, &key, value, BPF_EXIST) == 0);
311 key = next_key;312 key = next_key;
312 }313 }
313 314
@@ -316,8 +317,8 @@ static void test_hashmap_walk(unsigned int task, void *data) · 2 unmodified lines
316 for (i = 0; bpf_map_get_next_key(fd, !i ? NULL : &key,317 for (i = 0; bpf_map_get_next_key(fd, !i ? NULL : &key,
317 &next_key) == 0; i++) {318 &next_key) == 0; i++) {
318 key = next_key;319 key = next_key;
319 assert(bpf_map_lookup_elem(fd, &key, &value) == 0);320 assert(bpf_map_lookup_elem(fd, &key, value) == 0);
320 assert(value - 1 == key);321 assert(value[0] - 1 == key);
321 }322 }
322 323
323 assert(i == max_entries);324 assert(i == max_entries);
@@ -651,9 +652,9 @@ static void test_stackmap(unsigned int task, void *data) · 327 unmodified lines
651#include <arpa/inet.h>652#include <arpa/inet.h>
652#include <sys/select.h>653#include <sys/select.h>
653#include <linux/err.h>654#include <linux/err.h>
654#define SOCKMAP_PARSE_PROG "./sockmap_parse_prog.o"655#define SOCKMAP_PARSE_PROG "./sockmap_parse_prog.bpf.o"
655#define SOCKMAP_VERDICT_PROG "./sockmap_verdict_prog.o"656#define SOCKMAP_VERDICT_PROG "./sockmap_verdict_prog.bpf.o"
656#define SOCKMAP_TCP_MSG_PROG "./sockmap_tcp_msg_prog.o"657#define SOCKMAP_TCP_MSG_PROG "./sockmap_tcp_msg_prog.bpf.o"
657static void test_sockmap(unsigned int tasks, void *data)658static void test_sockmap(unsigned int tasks, void *data)
658{659{
659 struct bpf_map *bpf_map_rx, *bpf_map_tx, *bpf_map_msg, *bpf_map_break;660 struct bpf_map *bpf_map_rx, *bpf_map_tx, *bpf_map_msg, *bpf_map_break;
@@ -1143,8 +1144,8 @@ out_sockmap: · 483 unmodified lines
1143 exit(1);1144 exit(1);
1144}1145}
1145 1146
1146#define MAPINMAP_PROG "./test_map_in_map.o"1147#define MAPINMAP_PROG "./test_map_in_map.bpf.o"
1147#define MAPINMAP_INVALID_PROG "./test_map_in_map_invalid.o"1148#define MAPINMAP_INVALID_PROG "./test_map_in_map_invalid.bpf.o"
1148static void test_map_in_map(void)1149static void test_map_in_map(void)
1149{1150{
1150 struct bpf_object *obj;1151 struct bpf_object *obj;
@@ -1371,16 +1372,16 @@ static void __run_parallel(unsigned int tasks, · 220 unmodified lines
1371 1372
1372static void test_map_stress(void)1373static void test_map_stress(void)
1373{1374{
1375 run_parallel(100, test_hashmap_walk, NULL);
1374 run_parallel(100, test_hashmap, NULL);1376 run_parallel(100, test_hashmap, NULL);
1375 run_parallel(100, test_hashmap_percpu, NULL);1377 run_parallel(100, test_hashmap_percpu, NULL);
1376 run_parallel(100, test_hashmap_sizes, NULL);1378 run_parallel(100, test_hashmap_sizes, NULL);
1377 run_parallel(100, test_hashmap_walk, NULL);
1378 1379
1379 run_parallel(100, test_arraymap, NULL);1380 run_parallel(100, test_arraymap, NULL);
1380 run_parallel(100, test_arraymap_percpu, NULL);1381 run_parallel(100, test_arraymap_percpu, NULL);
1381}1382}
1382 1383
1383#define TASKS 10241384#define TASKS 100
1384 1385
1385#define DO_UPDATE 11386#define DO_UPDATE 1
1386#define DO_DELETE 01387#define DO_DELETE 0
@@ -1432,6 +1433,8 @@ static void test_update_delete(unsigned int fn, void *data) · 45 unmodified lines
1432 int fd = ((int *)data)[0];1433 int fd = ((int *)data)[0];
1433 int i, key, value, err;1434 int i, key, value, err;
1434 1435
1436 if (fn & 1)
1437 test_hashmap_walk(fn, NULL);
1435 for (i = fn; i < MAP_SIZE; i += TASKS) {1438 for (i = fn; i < MAP_SIZE; i += TASKS) {
1436 key = value = i;1439 key = value = i;
1437 1440
@@ -1455,7 +1458,7 @@ static void test_update_delete(unsigned int fn, void *data) · 17 unmodified lines
1455 1458
1456static void test_map_parallel(void)1459static void test_map_parallel(void)
1457{1460{
1458 int i, fd, key = 0, value = 0;1461 int i, fd, key = 0, value = 0, j = 0;
1459 int data[2];1462 int data[2];
1460 1463
1461 fd = bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(key), sizeof(value),1464 fd = bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(key), sizeof(value),
@@ -1466,6 +1469,7 @@ static void test_map_parallel(void) · 4 unmodified lines
1466 exit(1);1469 exit(1);
1467 }1470 }
1468 1471
1472again:
1469 /* Use the same fd in children to add elements to this map:1473 /* Use the same fd in children to add elements to this map:
1470 * child_0 adds key=0, key=1024, key=2048, ...1474 * child_0 adds key=0, key=1024, key=2048, ...
1471 * child_1 adds key=1, key=1025, key=2049, ...1475 * child_1 adds key=1, key=1025, key=2049, ...
@@ -1502,6 +1506,12 @@ static void test_map_parallel(void) · 30 unmodified lines
1502 key = -1;1506 key = -1;
1503 assert(bpf_map_get_next_key(fd, NULL, &key) < 0 && errno == ENOENT);1507 assert(bpf_map_get_next_key(fd, NULL, &key) < 0 && errno == ENOENT);
1504 assert(bpf_map_get_next_key(fd, &key, &key) < 0 && errno == ENOENT);1508 assert(bpf_map_get_next_key(fd, &key, &key) < 0 && errno == ENOENT);
1509
1510 key = 0;
1511 bpf_map_delete_elem(fd, &key);
1512 if (j++ < 5)
1513 goto again;
1514 close(fd);
1505}1515}
1506 1516
1507static void test_map_rdonly(void)1517static void test_map_rdonly(void)
tools/testing/selftests/bpf/test_offload.py+11−11
@@ -782,7 +782,7 @@ if out.find("/sys/kernel/debug type debugfs") == -1: · 781 unmodified lines
782 cmd("mount -t debugfs none /sys/kernel/debug")782 cmd("mount -t debugfs none /sys/kernel/debug")
783 783
784# Check samples are compiled784# Check samples are compiled
785samples = ["sample_ret0.o", "sample_map_ret0.o"]785samples = ["sample_ret0.bpf.o", "sample_map_ret0.bpf.o"]
786for s in samples:786for s in samples:
787 ret, out = cmd("ls %s/%s" % (bpf_test_dir, s), fail=False)787 ret, out = cmd("ls %s/%s" % (bpf_test_dir, s), fail=False)
788 skip(ret != 0, "sample %s/%s not found, please compile it" %788 skip(ret != 0, "sample %s/%s not found, please compile it" %
@@ -803,7 +803,7 @@ cmd("ip netns delete %s" % (ns)) · 14 unmodified lines
803netns = []803netns = []
804 804
805try:805try:
806 obj = bpf_obj("sample_ret0.o")806 obj = bpf_obj("sample_ret0.bpf.o")
807 bytecode = bpf_bytecode("1,6 0 0 4294967295,")807 bytecode = bpf_bytecode("1,6 0 0 4294967295,")
808 808
809 start_test("Test destruction of generic XDP...")809 start_test("Test destruction of generic XDP...")
@@ -1023,7 +1023,7 @@ try: · 213 unmodified lines
1023 1023
1024 sim.wait_for_flush()1024 sim.wait_for_flush()
1025 start_test("Test non-offload XDP attaching to HW...")1025 start_test("Test non-offload XDP attaching to HW...")
1026 bpftool_prog_load("sample_ret0.o", "/sys/fs/bpf/nooffload")1026 bpftool_prog_load("sample_ret0.bpf.o", "/sys/fs/bpf/nooffload")
1027 nooffload = bpf_pinned("/sys/fs/bpf/nooffload")1027 nooffload = bpf_pinned("/sys/fs/bpf/nooffload")
1028 ret, _, err = sim.set_xdp(nooffload, "offload",1028 ret, _, err = sim.set_xdp(nooffload, "offload",
1029 fail=False, include_stderr=True)1029 fail=False, include_stderr=True)
@@ -1032,7 +1032,7 @@ try: · 2 unmodified lines
1032 rm("/sys/fs/bpf/nooffload")1032 rm("/sys/fs/bpf/nooffload")
1033 1033
1034 start_test("Test offload XDP attaching to drv...")1034 start_test("Test offload XDP attaching to drv...")
1035 bpftool_prog_load("sample_ret0.o", "/sys/fs/bpf/offload",1035 bpftool_prog_load("sample_ret0.bpf.o", "/sys/fs/bpf/offload",
1036 dev=sim['ifname'])1036 dev=sim['ifname'])
1037 offload = bpf_pinned("/sys/fs/bpf/offload")1037 offload = bpf_pinned("/sys/fs/bpf/offload")
1038 ret, _, err = sim.set_xdp(offload, "drv", fail=False, include_stderr=True)1038 ret, _, err = sim.set_xdp(offload, "drv", fail=False, include_stderr=True)
@@ -1043,7 +1043,7 @@ try: · 4 unmodified lines
1043 1043
1044 start_test("Test XDP load failure...")1044 start_test("Test XDP load failure...")
1045 sim.dfs["dev/bpf_bind_verifier_accept"] = 01045 sim.dfs["dev/bpf_bind_verifier_accept"] = 0
1046 ret, _, err = bpftool_prog_load("sample_ret0.o", "/sys/fs/bpf/offload",1046 ret, _, err = bpftool_prog_load("sample_ret0.bpf.o", "/sys/fs/bpf/offload",
1047 dev=sim['ifname'], fail=False, include_stderr=True)1047 dev=sim['ifname'], fail=False, include_stderr=True)
1048 fail(ret == 0, "verifier should fail on load")1048 fail(ret == 0, "verifier should fail on load")
1049 check_verifier_log(err, "[netdevsim] Hello from netdevsim!")1049 check_verifier_log(err, "[netdevsim] Hello from netdevsim!")
@@ -1169,7 +1169,7 @@ try: · 119 unmodified lines
1169 1169
1170 simdev = NetdevSimDev()1170 simdev = NetdevSimDev()
1171 sim, = simdev.nsims1171 sim, = simdev.nsims
1172 map_obj = bpf_obj("sample_map_ret0.o")1172 map_obj = bpf_obj("sample_map_ret0.bpf.o")
1173 start_test("Test loading program with maps...")1173 start_test("Test loading program with maps...")
1174 sim.set_xdp(map_obj, "offload", JSON=False) # map fixup msg breaks JSON1174 sim.set_xdp(map_obj, "offload", JSON=False) # map fixup msg breaks JSON
1175 1175
@@ -1307,10 +1307,10 @@ try: · 131 unmodified lines
1307 sims = (simA, simB1, simB2, simB3)1307 sims = (simA, simB1, simB2, simB3)
1308 simB = (simB1, simB2, simB3)1308 simB = (simB1, simB2, simB3)
1309 1309
1310 bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimA",1310 bpftool_prog_load("sample_map_ret0.bpf.o", "/sys/fs/bpf/nsimA",
1311 dev=simA['ifname'])1311 dev=simA['ifname'])
1312 progA = bpf_pinned("/sys/fs/bpf/nsimA")1312 progA = bpf_pinned("/sys/fs/bpf/nsimA")
1313 bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimB",1313 bpftool_prog_load("sample_map_ret0.bpf.o", "/sys/fs/bpf/nsimB",
1314 dev=simB1['ifname'])1314 dev=simB1['ifname'])
1315 progB = bpf_pinned("/sys/fs/bpf/nsimB")1315 progB = bpf_pinned("/sys/fs/bpf/nsimB")
1316 1316
@@ -1344,14 +1344,14 @@ try: · 27 unmodified lines
1344 mapA = bpftool("prog show %s" % (progA))[1]["map_ids"][0]1344 mapA = bpftool("prog show %s" % (progA))[1]["map_ids"][0]
1345 mapB = bpftool("prog show %s" % (progB))[1]["map_ids"][0]1345 mapB = bpftool("prog show %s" % (progB))[1]["map_ids"][0]
1346 1346
1347 ret, _ = bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimB_",1347 ret, _ = bpftool_prog_load("sample_map_ret0.bpf.o", "/sys/fs/bpf/nsimB_",
1348 dev=simB3['ifname'],1348 dev=simB3['ifname'],
1349 maps=["idx 0 id %d" % (mapB)],1349 maps=["idx 0 id %d" % (mapB)],
1350 fail=False)1350 fail=False)
1351 fail(ret != 0, "couldn't reuse a map on the same ASIC")1351 fail(ret != 0, "couldn't reuse a map on the same ASIC")
1352 rm("/sys/fs/bpf/nsimB_")1352 rm("/sys/fs/bpf/nsimB_")
1353 1353
1354 ret, _, err = bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimA_",1354 ret, _, err = bpftool_prog_load("sample_map_ret0.bpf.o", "/sys/fs/bpf/nsimA_",
1355 dev=simA['ifname'],1355 dev=simA['ifname'],
1356 maps=["idx 0 id %d" % (mapB)],1356 maps=["idx 0 id %d" % (mapB)],
1357 fail=False, include_stderr=True)1357 fail=False, include_stderr=True)
@@ -1359,7 +1359,7 @@ try: · 1 unmodified line
1359 fail(err.count("offload device mismatch between prog and map") == 0,1359 fail(err.count("offload device mismatch between prog and map") == 0,
1360 "error message missing for cross-ASIC map")1360 "error message missing for cross-ASIC map")
1361 1361
1362 ret, _, err = bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimB_",1362 ret, _, err = bpftool_prog_load("sample_map_ret0.bpf.o", "/sys/fs/bpf/nsimB_",
1363 dev=simB1['ifname'],1363 dev=simB1['ifname'],
1364 maps=["idx 0 id %d" % (mapA)],1364 maps=["idx 0 id %d" % (mapA)],
1365 fail=False, include_stderr=True)1365 fail=False, include_stderr=True)
tools/testing/selftests/bpf/test_skb_cgroup_id.sh+1−1
@@ -54,7 +54,7 @@ DIR=$(dirname $0) · 53 unmodified lines
54TEST_IF="test_cgid_1"54TEST_IF="test_cgid_1"
55TEST_IF_PEER="test_cgid_2"55TEST_IF_PEER="test_cgid_2"
56MAX_PING_TRIES=556MAX_PING_TRIES=5
57BPF_PROG_OBJ="${DIR}/test_skb_cgroup_id_kern.o"57BPF_PROG_OBJ="${DIR}/test_skb_cgroup_id_kern.bpf.o"
58BPF_PROG_SECTION="cgroup_id_logger"58BPF_PROG_SECTION="cgroup_id_logger"
59BPF_PROG_ID=059BPF_PROG_ID=0
60PROG="${DIR}/test_skb_cgroup_id_user"60PROG="${DIR}/test_skb_cgroup_id_user"
tools/testing/selftests/bpf/test_sock_addr.c+8−8
@@ -26,14 +26,14 @@ · 25 unmodified lines
26#endif26#endif
27 27
28#define CG_PATH "/foo"28#define CG_PATH "/foo"
29#define CONNECT4_PROG_PATH "./connect4_prog.o"29#define CONNECT4_PROG_PATH "./connect4_prog.bpf.o"
30#define CONNECT6_PROG_PATH "./connect6_prog.o"30#define CONNECT6_PROG_PATH "./connect6_prog.bpf.o"
31#define SENDMSG4_PROG_PATH "./sendmsg4_prog.o"31#define SENDMSG4_PROG_PATH "./sendmsg4_prog.bpf.o"
32#define SENDMSG6_PROG_PATH "./sendmsg6_prog.o"32#define SENDMSG6_PROG_PATH "./sendmsg6_prog.bpf.o"
33#define RECVMSG4_PROG_PATH "./recvmsg4_prog.o"33#define RECVMSG4_PROG_PATH "./recvmsg4_prog.bpf.o"
34#define RECVMSG6_PROG_PATH "./recvmsg6_prog.o"34#define RECVMSG6_PROG_PATH "./recvmsg6_prog.bpf.o"
35#define BIND4_PROG_PATH "./bind4_prog.o"35#define BIND4_PROG_PATH "./bind4_prog.bpf.o"
36#define BIND6_PROG_PATH "./bind6_prog.o"36#define BIND6_PROG_PATH "./bind6_prog.bpf.o"
37 37
38#define SERV4_IP "192.168.1.254"38#define SERV4_IP "192.168.1.254"
39#define SERV4_REWRITE_IP "127.0.0.1"39#define SERV4_REWRITE_IP "127.0.0.1"
tools/testing/selftests/bpf/test_sockmap.c+2−2
@@ -52,8 +52,8 @@ static void running_handler(int a); · 51 unmodified lines
52#define S1_PORT 1000052#define S1_PORT 10000
53#define S2_PORT 1000153#define S2_PORT 10001
54 54
55#define BPF_SOCKMAP_FILENAME "test_sockmap_kern.o"55#define BPF_SOCKMAP_FILENAME "test_sockmap_kern.bpf.o"
56#define BPF_SOCKHASH_FILENAME "test_sockhash_kern.o"56#define BPF_SOCKHASH_FILENAME "test_sockhash_kern.bpf.o"
57#define CG_PATH "/sockmap"57#define CG_PATH "/sockmap"
58 58
59/* global sockets */59/* global sockets */
tools/testing/selftests/bpf/test_sysctl.c+3−3
@@ -1372,7 +1372,7 @@ static struct sysctl_test tests[] = { · 1371 unmodified lines
1372 },1372 },
1373 {1373 {
1374 "C prog: deny all writes",1374 "C prog: deny all writes",
1375 .prog_file = "./test_sysctl_prog.o",1375 .prog_file = "./test_sysctl_prog.bpf.o",
1376 .attach_type = BPF_CGROUP_SYSCTL,1376 .attach_type = BPF_CGROUP_SYSCTL,
1377 .sysctl = "net/ipv4/tcp_mem",1377 .sysctl = "net/ipv4/tcp_mem",
1378 .open_flags = O_WRONLY,1378 .open_flags = O_WRONLY,
@@ -1381,7 +1381,7 @@ static struct sysctl_test tests[] = { · 2 unmodified lines
1381 },1381 },
1382 {1382 {
1383 "C prog: deny access by name",1383 "C prog: deny access by name",
1384 .prog_file = "./test_sysctl_prog.o",1384 .prog_file = "./test_sysctl_prog.bpf.o",
1385 .attach_type = BPF_CGROUP_SYSCTL,1385 .attach_type = BPF_CGROUP_SYSCTL,
1386 .sysctl = "net/ipv4/route/mtu_expires",1386 .sysctl = "net/ipv4/route/mtu_expires",
1387 .open_flags = O_RDONLY,1387 .open_flags = O_RDONLY,
@@ -1389,7 +1389,7 @@ static struct sysctl_test tests[] = { · 1 unmodified line
1389 },1389 },
1390 {1390 {
1391 "C prog: read tcp_mem",1391 "C prog: read tcp_mem",
1392 .prog_file = "./test_sysctl_prog.o",1392 .prog_file = "./test_sysctl_prog.bpf.o",
1393 .attach_type = BPF_CGROUP_SYSCTL,1393 .attach_type = BPF_CGROUP_SYSCTL,
1394 .sysctl = "net/ipv4/tcp_mem",1394 .sysctl = "net/ipv4/tcp_mem",
1395 .open_flags = O_RDONLY,1395 .open_flags = O_RDONLY,
tools/testing/selftests/bpf/test_tcp_check_syncookie.sh+1−1
@@ -76,7 +76,7 @@ main() · 75 unmodified lines
76DIR=$(dirname $0)76DIR=$(dirname $0)
77TEST_IF=lo77TEST_IF=lo
78MAX_PING_TRIES=578MAX_PING_TRIES=5
79BPF_PROG_OBJ="${DIR}/test_tcp_check_syncookie_kern.o"79BPF_PROG_OBJ="${DIR}/test_tcp_check_syncookie_kern.bpf.o"
80CLSACT_SECTION="tc"80CLSACT_SECTION="tc"
81XDP_SECTION="xdp"81XDP_SECTION="xdp"
82BPF_PROG_ID=082BPF_PROG_ID=0
tools/testing/selftests/bpf/test_tcpnotify_user.c+1−1
@@ -69,7 +69,7 @@ int verify_result(const struct tcpnotify_globals *result) · 68 unmodified lines
69 69
70int main(int argc, char **argv)70int main(int argc, char **argv)
71{71{
72 const char *file = "test_tcpnotify_kern.o";72 const char *file = "test_tcpnotify_kern.bpf.o";
73 struct bpf_map *perf_map, *global_map;73 struct bpf_map *perf_map, *global_map;
74 struct tcpnotify_globals g = {0};74 struct tcpnotify_globals g = {0};
75 struct perf_buffer *pb = NULL;75 struct perf_buffer *pb = NULL;
tools/testing/selftests/bpf/test_xdp_redirect.sh+4−4
@@ -54,10 +54,10 @@ test_xdp_redirect() · 53 unmodified lines
54 return 054 return 0
55 fi55 fi
56 56
57 ip -n ${NS1} link set veth11 $xdpmode obj xdp_dummy.o sec xdp &> /dev/null57 ip -n ${NS1} link set veth11 $xdpmode obj xdp_dummy.bpf.o sec xdp &> /dev/null
58 ip -n ${NS2} link set veth22 $xdpmode obj xdp_dummy.o sec xdp &> /dev/null58 ip -n ${NS2} link set veth22 $xdpmode obj xdp_dummy.bpf.o sec xdp &> /dev/null
59 ip link set dev veth1 $xdpmode obj test_xdp_redirect.o sec redirect_to_222 &> /dev/null59 ip link set dev veth1 $xdpmode obj test_xdp_redirect.bpf.o sec redirect_to_222 &> /dev/null
60 ip link set dev veth2 $xdpmode obj test_xdp_redirect.o sec redirect_to_111 &> /dev/null60 ip link set dev veth2 $xdpmode obj test_xdp_redirect.bpf.o sec redirect_to_111 &> /dev/null
61 61
62 if ip netns exec ${NS1} ping -c 1 10.1.1.22 &> /dev/null &&62 if ip netns exec ${NS1} ping -c 1 10.1.1.22 &> /dev/null &&
63 ip netns exec ${NS2} ping -c 1 10.1.1.11 &> /dev/null; then63 ip netns exec ${NS2} ping -c 1 10.1.1.11 &> /dev/null; then
tools/testing/selftests/bpf/test_xdp_redirect_multi.sh+1−1
@@ -94,7 +94,7 @@ setup_ns() · 93 unmodified lines
94 # Add a neigh entry for IPv4 ping test94 # Add a neigh entry for IPv4 ping test
95 ip -n ${NS[$i]} neigh add 192.0.2.253 lladdr 00:00:00:00:00:01 dev veth095 ip -n ${NS[$i]} neigh add 192.0.2.253 lladdr 00:00:00:00:00:01 dev veth0
96 ip -n ${NS[$i]} link set veth0 $mode obj \96 ip -n ${NS[$i]} link set veth0 $mode obj \
97 xdp_dummy.o sec xdp &> /dev/null || \97 xdp_dummy.bpf.o sec xdp &> /dev/null || \
98 { test_fail "Unable to load dummy xdp" && exit 1; }98 { test_fail "Unable to load dummy xdp" && exit 1; }
99 IFACES="$IFACES veth$i"99 IFACES="$IFACES veth$i"
100 veth_mac[$i]=$(ip -n ${NS[0]} link show veth$i | awk '/link\/ether/ {print $2}')100 veth_mac[$i]=$(ip -n ${NS[0]} link show veth$i | awk '/link\/ether/ {print $2}')
tools/testing/selftests/bpf/test_xdp_veth.sh+4−4
@@ -101,7 +101,7 @@ ip -n ${NS3} link set dev veth33 up · 100 unmodified lines
101 101
102mkdir $BPF_DIR102mkdir $BPF_DIR
103bpftool prog loadall \103bpftool prog loadall \
104 xdp_redirect_map.o $BPF_DIR/progs type xdp \104 xdp_redirect_map.bpf.o $BPF_DIR/progs type xdp \
105 pinmaps $BPF_DIR/maps105 pinmaps $BPF_DIR/maps
106bpftool map update pinned $BPF_DIR/maps/tx_port key 0 0 0 0 value 122 0 0 0106bpftool map update pinned $BPF_DIR/maps/tx_port key 0 0 0 0 value 122 0 0 0
107bpftool map update pinned $BPF_DIR/maps/tx_port key 1 0 0 0 value 133 0 0 0107bpftool map update pinned $BPF_DIR/maps/tx_port key 1 0 0 0 value 133 0 0 0
@@ -110,9 +110,9 @@ ip link set dev veth1 xdp pinned $BPF_DIR/progs/xdp_redirect_map_0 · 2 unmodified lines
110ip link set dev veth2 xdp pinned $BPF_DIR/progs/xdp_redirect_map_1110ip link set dev veth2 xdp pinned $BPF_DIR/progs/xdp_redirect_map_1
111ip link set dev veth3 xdp pinned $BPF_DIR/progs/xdp_redirect_map_2111ip link set dev veth3 xdp pinned $BPF_DIR/progs/xdp_redirect_map_2
112 112
113ip -n ${NS1} link set dev veth11 xdp obj xdp_dummy.o sec xdp113ip -n ${NS1} link set dev veth11 xdp obj xdp_dummy.bpf.o sec xdp
114ip -n ${NS2} link set dev veth22 xdp obj xdp_tx.o sec xdp114ip -n ${NS2} link set dev veth22 xdp obj xdp_tx.bpf.o sec xdp
115ip -n ${NS3} link set dev veth33 xdp obj xdp_dummy.o sec xdp115ip -n ${NS3} link set dev veth33 xdp obj xdp_dummy.bpf.o sec xdp
116 116
117trap cleanup EXIT117trap cleanup EXIT
118 118
tools/testing/selftests/bpf/test_xsk.sh+36−16
@@ -73,14 +73,20 @@ · 72 unmodified lines
73#73#
74# Run and dump packet contents:74# Run and dump packet contents:
75# sudo ./test_xsk.sh -D75# sudo ./test_xsk.sh -D
76#
77# Run test suite for physical device in loopback mode
78# sudo ./test_xsk.sh -i IFACE
76 79
77. xsk_prereqs.sh80. xsk_prereqs.sh
78 81
79while getopts "vD" flag82ETH=""
83
84while getopts "vDi:" flag
80do85do
81 case "${flag}" in86 case "${flag}" in
82 v) verbose=1;;87 v) verbose=1;;
83 D) dump_pkts=1;;88 D) dump_pkts=1;;
89 i) ETH=${OPTARG};;
84 esac90 esac
85done91done
86 92
@@ -132,18 +138,25 @@ setup_vethPairs() { · 45 unmodified lines
132 ip link set ${VETH0} up138 ip link set ${VETH0} up
133}139}
134 140
135validate_root_exec141if [ ! -z $ETH ]; then
136validate_veth_support ${VETH0}142 VETH0=${ETH}
137validate_ip_utility143 VETH1=${ETH}
138setup_vethPairs144 NS1=""
139 145else
140retval=$?146 validate_root_exec
141if [ $retval -ne 0 ]; then147 validate_veth_support ${VETH0}
142 test_status $retval "${TEST_NAME}"148 validate_ip_utility
143 cleanup_exit ${VETH0} ${VETH1} ${NS1}149 setup_vethPairs
144 exit $retval150
151 retval=$?
152 if [ $retval -ne 0 ]; then
153 test_status $retval "${TEST_NAME}"
154 cleanup_exit ${VETH0} ${VETH1} ${NS1}
155 exit $retval
156 fi
145fi157fi
146 158
159
147if [[ $verbose -eq 1 ]]; then160if [[ $verbose -eq 1 ]]; then
148 ARGS+="-v "161 ARGS+="-v "
149fi162fi
@@ -152,26 +165,33 @@ if [[ $dump_pkts -eq 1 ]]; then · 2 unmodified lines
152 ARGS="-D "165 ARGS="-D "
153fi166fi
154 167
168retval=$?
155test_status $retval "${TEST_NAME}"169test_status $retval "${TEST_NAME}"
156 170
157## START TESTS171## START TESTS
158 172
159statusList=()173statusList=()
160 174
161TEST_NAME="XSK_SELFTESTS_SOFTIRQ"175TEST_NAME="XSK_SELFTESTS_${VETH0}_SOFTIRQ"
162 176
163exec_xskxceiver177exec_xskxceiver
164 178
165cleanup_exit ${VETH0} ${VETH1} ${NS1}179if [ -z $ETH ]; then
166TEST_NAME="XSK_SELFTESTS_BUSY_POLL"180 cleanup_exit ${VETH0} ${VETH1} ${NS1}
181fi
182TEST_NAME="XSK_SELFTESTS_${VETH0}_BUSY_POLL"
167busy_poll=1183busy_poll=1
168 184
169setup_vethPairs185if [ -z $ETH ]; then
186 setup_vethPairs
187fi
170exec_xskxceiver188exec_xskxceiver
171 189
172## END TESTS190## END TESTS
173 191
174cleanup_exit ${VETH0} ${VETH1} ${NS1}192if [ -z $ETH ]; then
193 cleanup_exit ${VETH0} ${VETH1} ${NS1}
194fi
175 195
176failures=0196failures=0
177echo -e "\nSummary:"197echo -e "\nSummary:"
tools/testing/selftests/bpf/xdp_redirect_multi.c+1−1
@@ -142,7 +142,7 @@ int main(int argc, char **argv) · 141 unmodified lines
142 }142 }
143 printf("\n");143 printf("\n");
144 144
145 snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);145 snprintf(filename, sizeof(filename), "%s_kern.bpf.o", argv[0]);
146 obj = bpf_object__open_file(filename, NULL);146 obj = bpf_object__open_file(filename, NULL);
147 err = libbpf_get_error(obj);147 err = libbpf_get_error(obj);
148 if (err)148 if (err)
tools/testing/selftests/bpf/xdp_synproxy.c+1−1
@@ -193,7 +193,7 @@ static int syncookie_attach(const char *argv0, unsigned int ifindex, bool tc) · 192 unmodified lines
193 int prog_fd;193 int prog_fd;
194 int err;194 int err;
195 195
196 snprintf(xdp_filename, sizeof(xdp_filename), "%s_kern.o", argv0);196 snprintf(xdp_filename, sizeof(xdp_filename), "%s_kern.bpf.o", argv0);
197 obj = bpf_object__open_file(xdp_filename, NULL);197 obj = bpf_object__open_file(xdp_filename, NULL);
198 err = libbpf_get_error(obj);198 err = libbpf_get_error(obj);
199 if (err < 0) {199 if (err < 0) {
tools/testing/selftests/bpf/xdping.c+1−1
@@ -168,7 +168,7 @@ int main(int argc, char **argv) · 167 unmodified lines
168 /* Use libbpf 1.0 API mode */168 /* Use libbpf 1.0 API mode */
169 libbpf_set_strict_mode(LIBBPF_STRICT_ALL);169 libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
170 170
171 snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);171 snprintf(filename, sizeof(filename), "%s_kern.bpf.o", argv[0]);
172 172
173 if (bpf_prog_test_load(filename, BPF_PROG_TYPE_XDP, &obj, &prog_fd)) {173 if (bpf_prog_test_load(filename, BPF_PROG_TYPE_XDP, &obj, &prog_fd)) {
174 fprintf(stderr, "load of %s failed\n", filename);174 fprintf(stderr, "load of %s failed\n", filename);
tools/testing/selftests/bpf/xsk.c+3−3
@@ -1237,15 +1237,15 @@ void xsk_socket__delete(struct xsk_socket *xsk) · 1236 unmodified lines
1237 ctx = xsk->ctx;1237 ctx = xsk->ctx;
1238 umem = ctx->umem;1238 umem = ctx->umem;
1239 1239
1240 xsk_put_ctx(ctx, true);1240 if (ctx->refcount == 1) {
1241
1242 if (!ctx->refcount) {
1243 xsk_delete_bpf_maps(xsk);1241 xsk_delete_bpf_maps(xsk);
1244 close(ctx->prog_fd);1242 close(ctx->prog_fd);
1245 if (ctx->has_bpf_link)1243 if (ctx->has_bpf_link)
1246 close(ctx->link_fd);1244 close(ctx->link_fd);
1247 }1245 }
1248 1246
1247 xsk_put_ctx(ctx, true);
1248
1249 err = xsk_get_mmap_offsets(xsk->fd, &off);1249 err = xsk_get_mmap_offsets(xsk->fd, &off);
1250 if (!err) {1250 if (!err) {
1251 if (xsk->rx) {1251 if (xsk->rx) {
tools/testing/selftests/bpf/xskxceiver.c+296−102
@@ -99,6 +99,8 @@ · 98 unmodified lines
99#include <stdatomic.h>99#include <stdatomic.h>
100#include "xsk.h"100#include "xsk.h"
101#include "xskxceiver.h"101#include "xskxceiver.h"
102#include <bpf/bpf.h>
103#include <linux/filter.h>
102#include "../kselftest.h"104#include "../kselftest.h"
103 105
104/* AF_XDP APIs were moved into libxdp and marked as deprecated in libbpf.106/* AF_XDP APIs were moved into libxdp and marked as deprecated in libbpf.
@@ -122,9 +124,20 @@ static void __exit_with_error(int error, const char *file, const char *func, int · 17 unmodified lines
122}124}
123 125
124#define exit_with_error(error) __exit_with_error(error, __FILE__, __func__, __LINE__)126#define exit_with_error(error) __exit_with_error(error, __FILE__, __func__, __LINE__)
125
126#define mode_string(test) (test)->ifobj_tx->xdp_flags & XDP_FLAGS_SKB_MODE ? "SKB" : "DRV"
127#define busy_poll_string(test) (test)->ifobj_tx->busy_poll ? "BUSY-POLL " : ""127#define busy_poll_string(test) (test)->ifobj_tx->busy_poll ? "BUSY-POLL " : ""
128static char *mode_string(struct test_spec *test)
129{
130 switch (test->mode) {
131 case TEST_MODE_SKB:
132 return "SKB";
133 case TEST_MODE_DRV:
134 return "DRV";
135 case TEST_MODE_ZC:
136 return "ZC";
137 default:
138 return "BOGUS";
139 }
140}
128 141
129static void report_failure(struct test_spec *test)142static void report_failure(struct test_spec *test)
130{143{
@@ -299,8 +312,8 @@ static void enable_busy_poll(struct xsk_socket_info *xsk) · 168 unmodified lines
299 exit_with_error(errno);312 exit_with_error(errno);
300}313}
301 314
302static int xsk_configure_socket(struct xsk_socket_info *xsk, struct xsk_umem_info *umem,315static int __xsk_configure_socket(struct xsk_socket_info *xsk, struct xsk_umem_info *umem,
303 struct ifobject *ifobject, bool shared)316 struct ifobject *ifobject, bool shared)
304{317{
305 struct xsk_socket_config cfg = {};318 struct xsk_socket_config cfg = {};
306 struct xsk_ring_cons *rxr;319 struct xsk_ring_cons *rxr;
@@ -320,6 +333,51 @@ static int xsk_configure_socket(struct xsk_socket_info *xsk, struct xsk_umem_inf · 13 unmodified lines
320 return xsk_socket__create(&xsk->xsk, ifobject->ifname, 0, umem->umem, rxr, txr, &cfg);333 return xsk_socket__create(&xsk->xsk, ifobject->ifname, 0, umem->umem, rxr, txr, &cfg);
321}334}
322 335
336static bool ifobj_zc_avail(struct ifobject *ifobject)
337{
338 size_t umem_sz = DEFAULT_UMEM_BUFFERS * XSK_UMEM__DEFAULT_FRAME_SIZE;
339 int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
340 struct xsk_socket_info *xsk;
341 struct xsk_umem_info *umem;
342 bool zc_avail = false;
343 void *bufs;
344 int ret;
345
346 bufs = mmap(NULL, umem_sz, PROT_READ | PROT_WRITE, mmap_flags, -1, 0);
347 if (bufs == MAP_FAILED)
348 exit_with_error(errno);
349
350 umem = calloc(1, sizeof(struct xsk_umem_info));
351 if (!umem) {
352 munmap(bufs, umem_sz);
353 exit_with_error(-ENOMEM);
354 }
355 umem->frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE;
356 ret = xsk_configure_umem(umem, bufs, umem_sz);
357 if (ret)
358 exit_with_error(-ret);
359
360 xsk = calloc(1, sizeof(struct xsk_socket_info));
361 if (!xsk)
362 goto out;
363 ifobject->xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
364 ifobject->xdp_flags |= XDP_FLAGS_DRV_MODE;
365 ifobject->bind_flags = XDP_USE_NEED_WAKEUP | XDP_ZEROCOPY;
366 ifobject->rx_on = true;
367 xsk->rxqsize = XSK_RING_CONS__DEFAULT_NUM_DESCS;
368 ret = __xsk_configure_socket(xsk, umem, ifobject, false);
369 if (!ret)
370 zc_avail = true;
371
372 xsk_socket__delete(xsk->xsk);
373 free(xsk);
374out:
375 munmap(umem->buffer, umem_sz);
376 xsk_umem__delete(umem->umem);
377 free(umem);
378 return zc_avail;
379}
380
323static struct option long_options[] = {381static struct option long_options[] = {
324 {"interface", required_argument, 0, 'i'},382 {"interface", required_argument, 0, 'i'},
325 {"busy-poll", no_argument, 0, 'b'},383 {"busy-poll", no_argument, 0, 'b'},
@@ -431,20 +489,24 @@ static void __test_spec_init(struct test_spec *test, struct ifobject *ifobj_tx, · 105 unmodified lines
431 ifobj->use_poll = false;489 ifobj->use_poll = false;
432 ifobj->use_fill_ring = true;490 ifobj->use_fill_ring = true;
433 ifobj->release_rx = true;491 ifobj->release_rx = true;
434 ifobj->pkt_stream = test->pkt_stream_default;
435 ifobj->validation_func = NULL;492 ifobj->validation_func = NULL;
436 493
437 if (i == 0) {494 if (i == 0) {
438 ifobj->rx_on = false;495 ifobj->rx_on = false;
439 ifobj->tx_on = true;496 ifobj->tx_on = true;
497 ifobj->pkt_stream = test->tx_pkt_stream_default;
440 } else {498 } else {
441 ifobj->rx_on = true;499 ifobj->rx_on = true;
442 ifobj->tx_on = false;500 ifobj->tx_on = false;
501 ifobj->pkt_stream = test->rx_pkt_stream_default;
443 }502 }
444 503
445 memset(ifobj->umem, 0, sizeof(*ifobj->umem));504 memset(ifobj->umem, 0, sizeof(*ifobj->umem));
446 ifobj->umem->num_frames = DEFAULT_UMEM_BUFFERS;505 ifobj->umem->num_frames = DEFAULT_UMEM_BUFFERS;
447 ifobj->umem->frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE;506 ifobj->umem->frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE;
507 if (ifobj->shared_umem && ifobj->rx_on)
508 ifobj->umem->base_addr = DEFAULT_UMEM_BUFFERS *
509 XSK_UMEM__DEFAULT_FRAME_SIZE;
448 510
449 for (j = 0; j < MAX_SOCKETS; j++) {511 for (j = 0; j < MAX_SOCKETS; j++) {
450 memset(&ifobj->xsk_arr[j], 0, sizeof(ifobj->xsk_arr[j]));512 memset(&ifobj->xsk_arr[j], 0, sizeof(ifobj->xsk_arr[j]));
@@ -463,12 +525,15 @@ static void __test_spec_init(struct test_spec *test, struct ifobject *ifobj_tx, · 12 unmodified lines
463static void test_spec_init(struct test_spec *test, struct ifobject *ifobj_tx,525static void test_spec_init(struct test_spec *test, struct ifobject *ifobj_tx,
464 struct ifobject *ifobj_rx, enum test_mode mode)526 struct ifobject *ifobj_rx, enum test_mode mode)
465{527{
466 struct pkt_stream *pkt_stream;528 struct pkt_stream *tx_pkt_stream;
529 struct pkt_stream *rx_pkt_stream;
467 u32 i;530 u32 i;
468 531
469 pkt_stream = test->pkt_stream_default;532 tx_pkt_stream = test->tx_pkt_stream_default;
533 rx_pkt_stream = test->rx_pkt_stream_default;
470 memset(test, 0, sizeof(*test));534 memset(test, 0, sizeof(*test));
471 test->pkt_stream_default = pkt_stream;535 test->tx_pkt_stream_default = tx_pkt_stream;
536 test->rx_pkt_stream_default = rx_pkt_stream;
472 537
473 for (i = 0; i < MAX_INTERFACES; i++) {538 for (i = 0; i < MAX_INTERFACES; i++) {
474 struct ifobject *ifobj = i ? ifobj_rx : ifobj_tx;539 struct ifobject *ifobj = i ? ifobj_rx : ifobj_tx;
@@ -479,9 +544,14 @@ static void test_spec_init(struct test_spec *test, struct ifobject *ifobj_tx, · 4 unmodified lines
479 else544 else
480 ifobj->xdp_flags |= XDP_FLAGS_DRV_MODE;545 ifobj->xdp_flags |= XDP_FLAGS_DRV_MODE;
481 546
482 ifobj->bind_flags = XDP_USE_NEED_WAKEUP | XDP_COPY;547 ifobj->bind_flags = XDP_USE_NEED_WAKEUP;
548 if (mode == TEST_MODE_ZC)
549 ifobj->bind_flags |= XDP_ZEROCOPY;
550 else
551 ifobj->bind_flags |= XDP_COPY;
483 }552 }
484 553
554 test->mode = mode;
485 __test_spec_init(test, ifobj_tx, ifobj_rx);555 __test_spec_init(test, ifobj_tx, ifobj_rx);
486}556}
487 557
@@ -529,16 +599,17 @@ static void pkt_stream_delete(struct pkt_stream *pkt_stream) · 41 unmodified lines
529static void pkt_stream_restore_default(struct test_spec *test)599static void pkt_stream_restore_default(struct test_spec *test)
530{600{
531 struct pkt_stream *tx_pkt_stream = test->ifobj_tx->pkt_stream;601 struct pkt_stream *tx_pkt_stream = test->ifobj_tx->pkt_stream;
602 struct pkt_stream *rx_pkt_stream = test->ifobj_rx->pkt_stream;
532 603
533 if (tx_pkt_stream != test->pkt_stream_default) {604 if (tx_pkt_stream != test->tx_pkt_stream_default) {
534 pkt_stream_delete(test->ifobj_tx->pkt_stream);605 pkt_stream_delete(test->ifobj_tx->pkt_stream);
535 test->ifobj_tx->pkt_stream = test->pkt_stream_default;606 test->ifobj_tx->pkt_stream = test->tx_pkt_stream_default;
536 }607 }
537 608
538 if (test->ifobj_rx->pkt_stream != test->pkt_stream_default &&609 if (rx_pkt_stream != test->rx_pkt_stream_default) {
539 test->ifobj_rx->pkt_stream != tx_pkt_stream)
540 pkt_stream_delete(test->ifobj_rx->pkt_stream);610 pkt_stream_delete(test->ifobj_rx->pkt_stream);
541 test->ifobj_rx->pkt_stream = test->pkt_stream_default;611 test->ifobj_rx->pkt_stream = test->rx_pkt_stream_default;
612 }
542}613}
543 614
544static struct pkt_stream *__pkt_stream_alloc(u32 nb_pkts)615static struct pkt_stream *__pkt_stream_alloc(u32 nb_pkts)
@@ -561,7 +632,7 @@ static struct pkt_stream *__pkt_stream_alloc(u32 nb_pkts) · 16 unmodified lines
561 632
562static void pkt_set(struct xsk_umem_info *umem, struct pkt *pkt, u64 addr, u32 len)633static void pkt_set(struct xsk_umem_info *umem, struct pkt *pkt, u64 addr, u32 len)
563{634{
564 pkt->addr = addr;635 pkt->addr = addr + umem->base_addr;
565 pkt->len = len;636 pkt->len = len;
566 if (len > umem->frame_size - XDP_PACKET_HEADROOM - MIN_PKT_SIZE * 2 - umem->frame_headroom)637 if (len > umem->frame_size - XDP_PACKET_HEADROOM - MIN_PKT_SIZE * 2 - umem->frame_headroom)
567 pkt->valid = false;638 pkt->valid = false;
@@ -600,22 +671,29 @@ static void pkt_stream_replace(struct test_spec *test, u32 nb_pkts, u32 pkt_len) · 32 unmodified lines
600 671
601 pkt_stream = pkt_stream_generate(test->ifobj_tx->umem, nb_pkts, pkt_len);672 pkt_stream = pkt_stream_generate(test->ifobj_tx->umem, nb_pkts, pkt_len);
602 test->ifobj_tx->pkt_stream = pkt_stream;673 test->ifobj_tx->pkt_stream = pkt_stream;
674 pkt_stream = pkt_stream_generate(test->ifobj_rx->umem, nb_pkts, pkt_len);
603 test->ifobj_rx->pkt_stream = pkt_stream;675 test->ifobj_rx->pkt_stream = pkt_stream;
604}676}
605 677
606static void pkt_stream_replace_half(struct test_spec *test, u32 pkt_len, int offset)678static void __pkt_stream_replace_half(struct ifobject *ifobj, u32 pkt_len,
679 int offset)
607{680{
608 struct xsk_umem_info *umem = test->ifobj_tx->umem;681 struct xsk_umem_info *umem = ifobj->umem;
609 struct pkt_stream *pkt_stream;682 struct pkt_stream *pkt_stream;
610 u32 i;683 u32 i;
611 684
612 pkt_stream = pkt_stream_clone(umem, test->pkt_stream_default);685 pkt_stream = pkt_stream_clone(umem, ifobj->pkt_stream);
613 for (i = 1; i < test->pkt_stream_default->nb_pkts; i += 2)686 for (i = 1; i < ifobj->pkt_stream->nb_pkts; i += 2)
614 pkt_set(umem, &pkt_stream->pkts[i],687 pkt_set(umem, &pkt_stream->pkts[i],
615 (i % umem->num_frames) * umem->frame_size + offset, pkt_len);688 (i % umem->num_frames) * umem->frame_size + offset, pkt_len);
616 689
617 test->ifobj_tx->pkt_stream = pkt_stream;690 ifobj->pkt_stream = pkt_stream;
618 test->ifobj_rx->pkt_stream = pkt_stream;691}
692
693static void pkt_stream_replace_half(struct test_spec *test, u32 pkt_len, int offset)
694{
695 __pkt_stream_replace_half(test->ifobj_tx, pkt_len, offset);
696 __pkt_stream_replace_half(test->ifobj_rx, pkt_len, offset);
619}697}
620 698
621static void pkt_stream_receive_half(struct test_spec *test)699static void pkt_stream_receive_half(struct test_spec *test)
@@ -657,7 +735,8 @@ static struct pkt *pkt_generate(struct ifobject *ifobject, u32 pkt_nb) · 35 unmodified lines
657 return pkt;735 return pkt;
658}736}
659 737
660static void pkt_stream_generate_custom(struct test_spec *test, struct pkt *pkts, u32 nb_pkts)738static void __pkt_stream_generate_custom(struct ifobject *ifobj,
739 struct pkt *pkts, u32 nb_pkts)
661{740{
662 struct pkt_stream *pkt_stream;741 struct pkt_stream *pkt_stream;
663 u32 i;742 u32 i;
@@ -666,15 +745,20 @@ static void pkt_stream_generate_custom(struct test_spec *test, struct pkt *pkts, · 2 unmodified lines
666 if (!pkt_stream)745 if (!pkt_stream)
667 exit_with_error(ENOMEM);746 exit_with_error(ENOMEM);
668 747
669 test->ifobj_tx->pkt_stream = pkt_stream;
670 test->ifobj_rx->pkt_stream = pkt_stream;
671
672 for (i = 0; i < nb_pkts; i++) {748 for (i = 0; i < nb_pkts; i++) {
673 pkt_stream->pkts[i].addr = pkts[i].addr;749 pkt_stream->pkts[i].addr = pkts[i].addr + ifobj->umem->base_addr;
674 pkt_stream->pkts[i].len = pkts[i].len;750 pkt_stream->pkts[i].len = pkts[i].len;
675 pkt_stream->pkts[i].payload = i;751 pkt_stream->pkts[i].payload = i;
676 pkt_stream->pkts[i].valid = pkts[i].valid;752 pkt_stream->pkts[i].valid = pkts[i].valid;
677 }753 }
754
755 ifobj->pkt_stream = pkt_stream;
756}
757
758static void pkt_stream_generate_custom(struct test_spec *test, struct pkt *pkts, u32 nb_pkts)
759{
760 __pkt_stream_generate_custom(test->ifobj_tx, pkts, nb_pkts);
761 __pkt_stream_generate_custom(test->ifobj_rx, pkts, nb_pkts);
678}762}
679 763
680static void pkt_dump(void *pkt, u32 len)764static void pkt_dump(void *pkt, u32 len)
@@ -1126,6 +1210,70 @@ static int validate_tx_invalid_descs(struct ifobject *ifobject) · 445 unmodified lines
1126 return TEST_PASS;1210 return TEST_PASS;
1127}1211}
1128 1212
1213static void xsk_configure_socket(struct test_spec *test, struct ifobject *ifobject,
1214 struct xsk_umem_info *umem, bool tx)
1215{
1216 int i, ret;
1217
1218 for (i = 0; i < test->nb_sockets; i++) {
1219 bool shared = (ifobject->shared_umem && tx) ? true : !!i;
1220 u32 ctr = 0;
1221
1222 while (ctr++ < SOCK_RECONF_CTR) {
1223 ret = __xsk_configure_socket(&ifobject->xsk_arr[i], umem,
1224 ifobject, shared);
1225 if (!ret)
1226 break;
1227
1228 /* Retry if it fails as xsk_socket__create() is asynchronous */
1229 if (ctr >= SOCK_RECONF_CTR)
1230 exit_with_error(-ret);
1231 usleep(USLEEP_MAX);
1232 }
1233 if (ifobject->busy_poll)
1234 enable_busy_poll(&ifobject->xsk_arr[i]);
1235 }
1236}
1237
1238static void thread_common_ops_tx(struct test_spec *test, struct ifobject *ifobject)
1239{
1240 xsk_configure_socket(test, ifobject, test->ifobj_rx->umem, true);
1241 ifobject->xsk = &ifobject->xsk_arr[0];
1242 ifobject->xsk_map_fd = test->ifobj_rx->xsk_map_fd;
1243 memcpy(ifobject->umem, test->ifobj_rx->umem, sizeof(struct xsk_umem_info));
1244}
1245
1246static void xsk_populate_fill_ring(struct xsk_umem_info *umem, struct pkt_stream *pkt_stream)
1247{
1248 u32 idx = 0, i, buffers_to_fill;
1249 int ret;
1250
1251 if (umem->num_frames < XSK_RING_PROD__DEFAULT_NUM_DESCS)
1252 buffers_to_fill = umem->num_frames;
1253 else
1254 buffers_to_fill = XSK_RING_PROD__DEFAULT_NUM_DESCS;
1255
1256 ret = xsk_ring_prod__reserve(&umem->fq, buffers_to_fill, &idx);
1257 if (ret != buffers_to_fill)
1258 exit_with_error(ENOSPC);
1259 for (i = 0; i < buffers_to_fill; i++) {
1260 u64 addr;
1261
1262 if (pkt_stream->use_addr_for_fill) {
1263 struct pkt *pkt = pkt_stream_get_pkt(pkt_stream, i);
1264
1265 if (!pkt)
1266 break;
1267 addr = pkt->addr;
1268 } else {
1269 addr = i * umem->frame_size;
1270 }
1271
1272 *xsk_ring_prod__fill_addr(&umem->fq, idx++) = addr;
1273 }
1274 xsk_ring_prod__submit(&umem->fq, buffers_to_fill);
1275}
1276
1129static void thread_common_ops(struct test_spec *test, struct ifobject *ifobject)1277static void thread_common_ops(struct test_spec *test, struct ifobject *ifobject)
1130{1278{
1131 u64 umem_sz = ifobject->umem->num_frames * ifobject->umem->frame_size;1279 u64 umem_sz = ifobject->umem->num_frames * ifobject->umem->frame_size;
@@ -1133,13 +1281,15 @@ static void thread_common_ops(struct test_spec *test, struct ifobject *ifobject) · 1 unmodified line
1133 LIBBPF_OPTS(bpf_xdp_query_opts, opts);1281 LIBBPF_OPTS(bpf_xdp_query_opts, opts);
1134 int ret, ifindex;1282 int ret, ifindex;
1135 void *bufs;1283 void *bufs;
1136 u32 i;
1137 1284
1138 ifobject->ns_fd = switch_namespace(ifobject->nsname);1285 ifobject->ns_fd = switch_namespace(ifobject->nsname);
1139 1286
1140 if (ifobject->umem->unaligned_mode)1287 if (ifobject->umem->unaligned_mode)
1141 mmap_flags |= MAP_HUGETLB;1288 mmap_flags |= MAP_HUGETLB;
1142 1289
1290 if (ifobject->shared_umem)
1291 umem_sz *= 2;
1292
1143 bufs = mmap(NULL, umem_sz, PROT_READ | PROT_WRITE, mmap_flags, -1, 0);1293 bufs = mmap(NULL, umem_sz, PROT_READ | PROT_WRITE, mmap_flags, -1, 0);
1144 if (bufs == MAP_FAILED)1294 if (bufs == MAP_FAILED)
1145 exit_with_error(errno);1295 exit_with_error(errno);
@@ -1148,24 +1298,9 @@ static void thread_common_ops(struct test_spec *test, struct ifobject *ifobject) · 2 unmodified lines
1148 if (ret)1298 if (ret)
1149 exit_with_error(-ret);1299 exit_with_error(-ret);
1150 1300
1151 for (i = 0; i < test->nb_sockets; i++) {1301 xsk_populate_fill_ring(ifobject->umem, ifobject->pkt_stream);
1152 u32 ctr = 0;
1153
1154 while (ctr++ < SOCK_RECONF_CTR) {
1155 ret = xsk_configure_socket(&ifobject->xsk_arr[i], ifobject->umem,
1156 ifobject, !!i);
1157 if (!ret)
1158 break;
1159
1160 /* Retry if it fails as xsk_socket__create() is asynchronous */
1161 if (ctr >= SOCK_RECONF_CTR)
1162 exit_with_error(-ret);
1163 usleep(USLEEP_MAX);
1164 }
1165 1302
1166 if (ifobject->busy_poll)1303 xsk_configure_socket(test, ifobject, ifobject->umem, false);
1167 enable_busy_poll(&ifobject->xsk_arr[i]);
1168 }
1169 1304
1170 ifobject->xsk = &ifobject->xsk_arr[0];1305 ifobject->xsk = &ifobject->xsk_arr[0];
1171 1306
@@ -1201,22 +1336,18 @@ static void thread_common_ops(struct test_spec *test, struct ifobject *ifobject) · 29 unmodified lines
1201 exit_with_error(-ret);1336 exit_with_error(-ret);
1202}1337}
1203 1338
1204static void testapp_cleanup_xsk_res(struct ifobject *ifobj)
1205{
1206 print_verbose("Destroying socket\n");
1207 xsk_socket__delete(ifobj->xsk->xsk);
1208 munmap(ifobj->umem->buffer, ifobj->umem->num_frames * ifobj->umem->frame_size);
1209 xsk_umem__delete(ifobj->umem->umem);
1210}
1211
1212static void *worker_testapp_validate_tx(void *arg)1339static void *worker_testapp_validate_tx(void *arg)
1213{1340{
1214 struct test_spec *test = (struct test_spec *)arg;1341 struct test_spec *test = (struct test_spec *)arg;
1215 struct ifobject *ifobject = test->ifobj_tx;1342 struct ifobject *ifobject = test->ifobj_tx;
1216 int err;1343 int err;
1217 1344
1218 if (test->current_step == 1)1345 if (test->current_step == 1) {
1219 thread_common_ops(test, ifobject);1346 if (!ifobject->shared_umem)
1347 thread_common_ops(test, ifobject);
1348 else
1349 thread_common_ops_tx(test, ifobject);
1350 }
1220 1351
1221 print_verbose("Sending %d packets on interface %s\n", ifobject->pkt_stream->nb_pkts,1352 print_verbose("Sending %d packets on interface %s\n", ifobject->pkt_stream->nb_pkts,
1222 ifobject->ifname);1353 ifobject->ifname);
@@ -1227,53 +1358,23 @@ static void *worker_testapp_validate_tx(void *arg) · 4 unmodified lines
1227 if (err)1358 if (err)
1228 report_failure(test);1359 report_failure(test);
1229 1360
1230 if (test->total_steps == test->current_step || err)
1231 testapp_cleanup_xsk_res(ifobject);
1232 pthread_exit(NULL);1361 pthread_exit(NULL);
1233}1362}
1234 1363
1235static void xsk_populate_fill_ring(struct xsk_umem_info *umem, struct pkt_stream *pkt_stream)
1236{
1237 u32 idx = 0, i, buffers_to_fill;
1238 int ret;
1239
1240 if (umem->num_frames < XSK_RING_PROD__DEFAULT_NUM_DESCS)
1241 buffers_to_fill = umem->num_frames;
1242 else
1243 buffers_to_fill = XSK_RING_PROD__DEFAULT_NUM_DESCS;
1244
1245 ret = xsk_ring_prod__reserve(&umem->fq, buffers_to_fill, &idx);
1246 if (ret != buffers_to_fill)
1247 exit_with_error(ENOSPC);
1248 for (i = 0; i < buffers_to_fill; i++) {
1249 u64 addr;
1250
1251 if (pkt_stream->use_addr_for_fill) {
1252 struct pkt *pkt = pkt_stream_get_pkt(pkt_stream, i);
1253
1254 if (!pkt)
1255 break;
1256 addr = pkt->addr;
1257 } else {
1258 addr = i * umem->frame_size;
1259 }
1260
1261 *xsk_ring_prod__fill_addr(&umem->fq, idx++) = addr;
1262 }
1263 xsk_ring_prod__submit(&umem->fq, buffers_to_fill);
1264}
1265
1266static void *worker_testapp_validate_rx(void *arg)1364static void *worker_testapp_validate_rx(void *arg)
1267{1365{
1268 struct test_spec *test = (struct test_spec *)arg;1366 struct test_spec *test = (struct test_spec *)arg;
1269 struct ifobject *ifobject = test->ifobj_rx;1367 struct ifobject *ifobject = test->ifobj_rx;
1270 struct pollfd fds = { };1368 struct pollfd fds = { };
1369 int id = 0;
1271 int err;1370 int err;
1272 1371
1273 if (test->current_step == 1)1372 if (test->current_step == 1) {
1274 thread_common_ops(test, ifobject);1373 thread_common_ops(test, ifobject);
1275 1374 } else {
1276 xsk_populate_fill_ring(ifobject->umem, ifobject->pkt_stream);1375 bpf_map_delete_elem(ifobject->xsk_map_fd, &id);
1376 xsk_socket__update_xskmap(ifobject->xsk->xsk, ifobject->xsk_map_fd);
1377 }
1277 1378
1278 fds.fd = xsk_socket__fd(ifobject->xsk->xsk);1379 fds.fd = xsk_socket__fd(ifobject->xsk->xsk);
1279 fds.events = POLLIN;1380 fds.events = POLLIN;
@@ -1291,25 +1392,44 @@ static void *worker_testapp_validate_rx(void *arg) · 11 unmodified lines
1291 pthread_mutex_unlock(&pacing_mutex);1392 pthread_mutex_unlock(&pacing_mutex);
1292 }1393 }
1293 1394
1294 if (test->total_steps == test->current_step || err)1395 pthread_exit(NULL);
1295 testapp_cleanup_xsk_res(ifobject);1396}
1397
1398static void testapp_clean_xsk_umem(struct ifobject *ifobj)
1399{
1400 u64 umem_sz = ifobj->umem->num_frames * ifobj->umem->frame_size;
1401
1402 if (ifobj->shared_umem)
1403 umem_sz *= 2;
1404
1405 xsk_umem__delete(ifobj->umem->umem);
1406 munmap(ifobj->umem->buffer, umem_sz);
1407}
1408
1409static void handler(int signum)
1410{
1296 pthread_exit(NULL);1411 pthread_exit(NULL);
1297}1412}
1298 1413
1299static int testapp_validate_traffic_single_thread(struct test_spec *test, struct ifobject *ifobj,1414static int testapp_validate_traffic_single_thread(struct test_spec *test, struct ifobject *ifobj,
1300 enum test_type type)1415 enum test_type type)
1301{1416{
1417 bool old_shared_umem = ifobj->shared_umem;
1302 pthread_t t0;1418 pthread_t t0;
1303 1419
1304 if (pthread_barrier_init(&barr, NULL, 2))1420 if (pthread_barrier_init(&barr, NULL, 2))
1305 exit_with_error(errno);1421 exit_with_error(errno);
1306 1422
1307 test->current_step++;1423 test->current_step++;
1308 if (type == TEST_TYPE_POLL_RXQ_TMOUT)1424 if (type == TEST_TYPE_POLL_RXQ_TMOUT)
1309 pkt_stream_reset(ifobj->pkt_stream);1425 pkt_stream_reset(ifobj->pkt_stream);
1310 pkts_in_flight = 0;1426 pkts_in_flight = 0;
1311 1427
1312 /*Spawn thread */1428 test->ifobj_rx->shared_umem = false;
1429 test->ifobj_tx->shared_umem = false;
1430
1431 signal(SIGUSR1, handler);
1432 /* Spawn thread */
1313 pthread_create(&t0, NULL, ifobj->func_ptr, test);1433 pthread_create(&t0, NULL, ifobj->func_ptr, test);
1314 1434
1315 if (type != TEST_TYPE_POLL_TXQ_TMOUT)1435 if (type != TEST_TYPE_POLL_TXQ_TMOUT)
@@ -1318,8 +1438,17 @@ static int testapp_validate_traffic_single_thread(struct test_spec *test, struct · 2 unmodified lines
1318 if (pthread_barrier_destroy(&barr))1438 if (pthread_barrier_destroy(&barr))
1319 exit_with_error(errno);1439 exit_with_error(errno);
1320 1440
1441 pthread_kill(t0, SIGUSR1);
1321 pthread_join(t0, NULL);1442 pthread_join(t0, NULL);
1322 1443
1444 if (test->total_steps == test->current_step || test->fail) {
1445 xsk_socket__delete(ifobj->xsk->xsk);
1446 testapp_clean_xsk_umem(ifobj);
1447 }
1448
1449 test->ifobj_rx->shared_umem = old_shared_umem;
1450 test->ifobj_tx->shared_umem = old_shared_umem;
1451
1323 return !!test->fail;1452 return !!test->fail;
1324}1453}
1325 1454
@@ -1349,6 +1478,14 @@ static int testapp_validate_traffic(struct test_spec *test) · 23 unmodified lines
1349 pthread_join(t1, NULL);1478 pthread_join(t1, NULL);
1350 pthread_join(t0, NULL);1479 pthread_join(t0, NULL);
1351 1480
1481 if (test->total_steps == test->current_step || test->fail) {
1482 xsk_socket__delete(ifobj_tx->xsk->xsk);
1483 xsk_socket__delete(ifobj_rx->xsk->xsk);
1484 testapp_clean_xsk_umem(ifobj_rx);
1485 if (!ifobj_tx->shared_umem)
1486 testapp_clean_xsk_umem(ifobj_tx);
1487 }
1488
1352 return !!test->fail;1489 return !!test->fail;
1353}1490}
1354 1491
@@ -1428,9 +1565,9 @@ static void testapp_headroom(struct test_spec *test) · 73 unmodified lines
1428static void testapp_stats_rx_dropped(struct test_spec *test)1565static void testapp_stats_rx_dropped(struct test_spec *test)
1429{1566{
1430 test_spec_set_name(test, "STAT_RX_DROPPED");1567 test_spec_set_name(test, "STAT_RX_DROPPED");
1568 pkt_stream_replace_half(test, MIN_PKT_SIZE * 4, 0);
1431 test->ifobj_rx->umem->frame_headroom = test->ifobj_rx->umem->frame_size -1569 test->ifobj_rx->umem->frame_headroom = test->ifobj_rx->umem->frame_size -
1432 XDP_PACKET_HEADROOM - MIN_PKT_SIZE * 3;1570 XDP_PACKET_HEADROOM - MIN_PKT_SIZE * 3;
1433 pkt_stream_replace_half(test, MIN_PKT_SIZE * 4, 0);
1434 pkt_stream_receive_half(test);1571 pkt_stream_receive_half(test);
1435 test->ifobj_rx->validation_func = validate_rx_dropped;1572 test->ifobj_rx->validation_func = validate_rx_dropped;
1436 testapp_validate_traffic(test);1573 testapp_validate_traffic(test);
@@ -1553,6 +1690,11 @@ static void testapp_invalid_desc(struct test_spec *test) · 116 unmodified lines
1553 pkts[7].valid = false;1690 pkts[7].valid = false;
1554 }1691 }
1555 1692
1693 if (test->ifobj_tx->shared_umem) {
1694 pkts[4].addr += UMEM_SIZE;
1695 pkts[5].addr += UMEM_SIZE;
1696 }
1697
1556 pkt_stream_generate_custom(test, pkts, ARRAY_SIZE(pkts));1698 pkt_stream_generate_custom(test, pkts, ARRAY_SIZE(pkts));
1557 testapp_validate_traffic(test);1699 testapp_validate_traffic(test);
1558 pkt_stream_restore_default(test);1700 pkt_stream_restore_default(test);
@@ -1583,6 +1725,10 @@ static void run_pkt_test(struct test_spec *test, enum test_mode mode, enum test_ · 24 unmodified lines
1583{1725{
1584 switch (type) {1726 switch (type) {
1585 case TEST_TYPE_STATS_RX_DROPPED:1727 case TEST_TYPE_STATS_RX_DROPPED:
1728 if (mode == TEST_MODE_ZC) {
1729 ksft_test_result_skip("Can not run RX_DROPPED test for ZC mode\n");
1730 return;
1731 }
1586 testapp_stats_rx_dropped(test);1732 testapp_stats_rx_dropped(test);
1587 break;1733 break;
1588 case TEST_TYPE_STATS_TX_INVALID_DESCS:1734 case TEST_TYPE_STATS_TX_INVALID_DESCS:
@@ -1712,12 +1858,44 @@ static void ifobject_delete(struct ifobject *ifobj) · 123 unmodified lines
1712 free(ifobj);1858 free(ifobj);
1713}1859}
1714 1860
1861static bool is_xdp_supported(struct ifobject *ifobject)
1862{
1863 int flags = XDP_FLAGS_DRV_MODE;
1864
1865 LIBBPF_OPTS(bpf_link_create_opts, opts, .flags = flags);
1866 struct bpf_insn insns[2] = {
1867 BPF_MOV64_IMM(BPF_REG_0, XDP_PASS),
1868 BPF_EXIT_INSN()
1869 };
1870 int ifindex = if_nametoindex(ifobject->ifname);
1871 int prog_fd, insn_cnt = ARRAY_SIZE(insns);
1872 int err;
1873
1874 prog_fd = bpf_prog_load(BPF_PROG_TYPE_XDP, NULL, "GPL", insns, insn_cnt, NULL);
1875 if (prog_fd < 0)
1876 return false;
1877
1878 err = bpf_xdp_attach(ifindex, prog_fd, flags, NULL);
1879 if (err) {
1880 close(prog_fd);
1881 return false;
1882 }
1883
1884 bpf_xdp_detach(ifindex, flags, NULL);
1885 close(prog_fd);
1886
1887 return true;
1888}
1889
1715int main(int argc, char **argv)1890int main(int argc, char **argv)
1716{1891{
1717 struct pkt_stream *pkt_stream_default;1892 struct pkt_stream *rx_pkt_stream_default;
1893 struct pkt_stream *tx_pkt_stream_default;
1718 struct ifobject *ifobj_tx, *ifobj_rx;1894 struct ifobject *ifobj_tx, *ifobj_rx;
1895 int modes = TEST_MODE_SKB + 1;
1719 u32 i, j, failed_tests = 0;1896 u32 i, j, failed_tests = 0;
1720 struct test_spec test;1897 struct test_spec test;
1898 bool shared_umem;
1721 1899
1722 /* Use libbpf 1.0 API mode */1900 /* Use libbpf 1.0 API mode */
1723 libbpf_set_strict_mode(LIBBPF_STRICT_ALL);1901 libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
@@ -1732,6 +1910,10 @@ int main(int argc, char **argv) · 8 unmodified lines
1732 setlocale(LC_ALL, "");1910 setlocale(LC_ALL, "");
1733 1911
1734 parse_command_line(ifobj_tx, ifobj_rx, argc, argv);1912 parse_command_line(ifobj_tx, ifobj_rx, argc, argv);
1913 shared_umem = !strcmp(ifobj_tx->ifname, ifobj_rx->ifname);
1914
1915 ifobj_tx->shared_umem = shared_umem;
1916 ifobj_rx->shared_umem = shared_umem;
1735 1917
1736 if (!validate_interface(ifobj_tx) || !validate_interface(ifobj_rx)) {1918 if (!validate_interface(ifobj_tx) || !validate_interface(ifobj_rx)) {
1737 usage(basename(argv[0]));1919 usage(basename(argv[0]));
@@ -1743,15 +1925,23 @@ int main(int argc, char **argv) · 5 unmodified lines
1743 init_iface(ifobj_rx, MAC2, MAC1, IP2, IP1, UDP_PORT2, UDP_PORT1,1925 init_iface(ifobj_rx, MAC2, MAC1, IP2, IP1, UDP_PORT2, UDP_PORT1,
1744 worker_testapp_validate_rx);1926 worker_testapp_validate_rx);
1745 1927
1928 if (is_xdp_supported(ifobj_tx)) {
1929 modes++;
1930 if (ifobj_zc_avail(ifobj_tx))
1931 modes++;
1932 }
1933
1746 test_spec_init(&test, ifobj_tx, ifobj_rx, 0);1934 test_spec_init(&test, ifobj_tx, ifobj_rx, 0);
1747 pkt_stream_default = pkt_stream_generate(ifobj_tx->umem, DEFAULT_PKT_CNT, PKT_SIZE);1935 tx_pkt_stream_default = pkt_stream_generate(ifobj_tx->umem, DEFAULT_PKT_CNT, PKT_SIZE);
1748 if (!pkt_stream_default)1936 rx_pkt_stream_default = pkt_stream_generate(ifobj_rx->umem, DEFAULT_PKT_CNT, PKT_SIZE);
1937 if (!tx_pkt_stream_default || !rx_pkt_stream_default)
1749 exit_with_error(ENOMEM);1938 exit_with_error(ENOMEM);
1750 test.pkt_stream_default = pkt_stream_default;1939 test.tx_pkt_stream_default = tx_pkt_stream_default;
1940 test.rx_pkt_stream_default = rx_pkt_stream_default;
1751 1941
1752 ksft_set_plan(TEST_MODE_MAX * TEST_TYPE_MAX);1942 ksft_set_plan(modes * TEST_TYPE_MAX);
1753 1943
1754 for (i = 0; i < TEST_MODE_MAX; i++)1944 for (i = 0; i < modes; i++)
1755 for (j = 0; j < TEST_TYPE_MAX; j++) {1945 for (j = 0; j < TEST_TYPE_MAX; j++) {
1756 test_spec_init(&test, ifobj_tx, ifobj_rx, i);1946 test_spec_init(&test, ifobj_tx, ifobj_rx, i);
1757 run_pkt_test(&test, i, j);1947 run_pkt_test(&test, i, j);
@@ -1761,7 +1951,11 @@ int main(int argc, char **argv) · 3 unmodified lines
1761 failed_tests++;1951 failed_tests++;
1762 }1952 }
1763 1953
1764 pkt_stream_delete(pkt_stream_default);1954 pkt_stream_delete(tx_pkt_stream_default);
1955 pkt_stream_delete(rx_pkt_stream_default);
1956 free(ifobj_rx->umem);
1957 if (!ifobj_tx->shared_umem)
1958 free(ifobj_tx->umem);
1765 ifobject_delete(ifobj_tx);1959 ifobject_delete(ifobj_tx);
1766 ifobject_delete(ifobj_rx);1960 ifobject_delete(ifobj_rx);
1767 1961
tools/testing/selftests/bpf/xskxceiver.h+8−3
@@ -29,8 +29,8 @@ · 28 unmodified lines
29#define TEST_FAILURE -129#define TEST_FAILURE -1
30#define TEST_CONTINUE 130#define TEST_CONTINUE 1
31#define MAX_INTERFACES 231#define MAX_INTERFACES 2
32#define MAX_INTERFACE_NAME_CHARS 732#define MAX_INTERFACE_NAME_CHARS 16
33#define MAX_INTERFACES_NAMESPACE_CHARS 1033#define MAX_INTERFACES_NAMESPACE_CHARS 16
34#define MAX_SOCKETS 234#define MAX_SOCKETS 2
35#define MAX_TEST_NAME_SIZE 3235#define MAX_TEST_NAME_SIZE 32
36#define MAX_TEARDOWN_ITER 1036#define MAX_TEARDOWN_ITER 10
@@ -62,6 +62,7 @@ · 25 unmodified lines
62enum test_mode {62enum test_mode {
63 TEST_MODE_SKB,63 TEST_MODE_SKB,
64 TEST_MODE_DRV,64 TEST_MODE_DRV,
65 TEST_MODE_ZC,
65 TEST_MODE_MAX66 TEST_MODE_MAX
66};67};
67 68
@@ -99,6 +100,7 @@ struct xsk_umem_info { · 31 unmodified lines
99 u32 frame_headroom;100 u32 frame_headroom;
100 void *buffer;101 void *buffer;
101 u32 frame_size;102 u32 frame_size;
103 u32 base_addr;
102 bool unaligned_mode;104 bool unaligned_mode;
103};105};
104 106
@@ -152,6 +154,7 @@ struct ifobject { · 47 unmodified lines
152 bool busy_poll;154 bool busy_poll;
153 bool use_fill_ring;155 bool use_fill_ring;
154 bool release_rx;156 bool release_rx;
157 bool shared_umem;
155 u8 dst_mac[ETH_ALEN];158 u8 dst_mac[ETH_ALEN];
156 u8 src_mac[ETH_ALEN];159 u8 src_mac[ETH_ALEN];
157};160};
@@ -159,11 +162,13 @@ struct ifobject { · 1 unmodified line
159struct test_spec {162struct test_spec {
160 struct ifobject *ifobj_tx;163 struct ifobject *ifobj_tx;
161 struct ifobject *ifobj_rx;164 struct ifobject *ifobj_rx;
162 struct pkt_stream *pkt_stream_default;165 struct pkt_stream *tx_pkt_stream_default;
166 struct pkt_stream *rx_pkt_stream_default;
163 u16 total_steps;167 u16 total_steps;
164 u16 current_step;168 u16 current_step;
165 u16 nb_sockets;169 u16 nb_sockets;
166 bool fail;170 bool fail;
171 enum test_mode mode;
167 char name[MAX_TEST_NAME_SIZE];172 char name[MAX_TEST_NAME_SIZE];
168};173};
169 174