History

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

Alexei Starovoitov says: ==================== pull-request: bpf-next 2020-10-12 The main changes are: 1) The BPF verifier improvements to track register allocation pattern, from Alexei and Yonghong. 2) libbpf relocation support for different size load/store, from Andrii. 3) bpf_redirect_peer() helper and support for inner map array with different max_entries, from Daniel. 4) BPF support for per-cpu variables, form Hao. 5) sockmap improvements, from John. ====================

Jakub Kicinski committed 6 years ago

Commit ccdf7fa2 parents a308283 376dcfe73 files · +4339 −772Browse files

Unified · Split

73 files
  1. Documentation/bpf/bpf_devel_QA.rst +2 −2
  2. MAINTAINERS +1 −1
  3. drivers/net/veth.c +9 −0
  4. include/linux/bpf.h +7 −1
  5. include/linux/bpf_verifier.h +7 −0
  6. include/linux/btf.h +26 −0
  7. include/linux/netdevice.h +4 −0
  8. include/linux/skmsg.h +2 −0
  9. include/net/tcp.h +0 −33
  10. include/uapi/linux/bpf.h +87 −14
  11. kernel/bpf/arraymap.c +11 −6
  12. kernel/bpf/btf.c +0 −25
  13. kernel/bpf/hashtab.c +3 −3
  14. kernel/bpf/helpers.c +32 −0
  15. kernel/bpf/percpu_freelist.c +96 −5
  16. kernel/bpf/percpu_freelist.h +1 −0
  17. kernel/bpf/syscall.c +3 −1
  18. kernel/bpf/verifier.c +251 −19
  19. kernel/trace/bpf_trace.c +6 −0
  20. net/core/dev.c +12 −3
  21. net/core/filter.c +99 −8
  22. net/core/skmsg.c +123 −38
  23. net/core/sock_map.c +23 −14
  24. net/ipv4/tcp_minisocks.c +0 −1
  25. net/xdp/xsk_buff_pool.c +0 −3
  26. net/xdp/xsk_queue.h +4 −0
  27. net/xdp/xskmap.c +1 −1
  28. samples/bpf/Makefile +12 −3
  29. samples/bpf/hbm.c +2 −1
  30. samples/bpf/xdp_monitor_kern.c +30 −30
  31. samples/bpf/xdp_monitor_user.c +120 −39
  32. samples/bpf/xdp_redirect_cpu_user.c +72 −81
  33. samples/bpf/xdp_sample_pkts_kern.c +6 −8
  34. samples/bpf/xdp_sample_pkts_user.c +0 −1
  35. samples/bpf/xdpsock_user.c +290 −64
  36. tools/include/uapi/linux/bpf.h +87 −14
  37. tools/lib/bpf/libbpf.c +289 −59
  38. tools/lib/bpf/xsk.c +6 −1
  39. tools/testing/selftests/bpf/README.rst +38 −0
  40. tools/testing/selftests/bpf/prog_tests/align.c +8 −8
  41. tools/testing/selftests/bpf/prog_tests/btf_map_in_map.c +29 −10
  42. tools/testing/selftests/bpf/prog_tests/core_autosize.c +225 −0
  43. tools/testing/selftests/bpf/prog_tests/ksyms.c +13 −25
  44. tools/testing/selftests/bpf/prog_tests/ksyms_btf.c +88 −0
  45. tools/testing/selftests/bpf/prog_tests/pinning.c +48 −1
  46. tools/testing/selftests/bpf/prog_tests/sockmap_basic.c +1 −1
  47. tools/testing/selftests/bpf/prog_tests/tcp_hdr_options.c +12 −0
  48. tools/testing/selftests/bpf/prog_tests/test_profiler.c +72 −0
  49. tools/testing/selftests/bpf/prog_tests/xdp_noinline.c +1 −1
  50. tools/testing/selftests/bpf/progs/connect4_prog.c +19 −0
  51. tools/testing/selftests/bpf/progs/profiler.h +177 −0
  52. tools/testing/selftests/bpf/progs/profiler.inc.h +969 −0
  53. tools/testing/selftests/bpf/progs/profiler1.c +6 −0
  54. tools/testing/selftests/bpf/progs/profiler2.c +6 −0
  55. tools/testing/selftests/bpf/progs/profiler3.c +6 −0
  56. tools/testing/selftests/bpf/progs/test_btf_map_in_map.c +43 −0
  57. tools/testing/selftests/bpf/progs/test_core_autosize.c +172 −0
  58. tools/testing/selftests/bpf/progs/test_ksyms_btf.c +55 −0
  59. tools/testing/selftests/bpf/progs/test_misc_tcp_hdr_options.c +2 −2
  60. tools/testing/selftests/bpf/progs/test_sockmap_kern.h +25 −9
  61. tools/testing/selftests/bpf/progs/test_tc_neigh.c +22 −18
  62. tools/testing/selftests/bpf/progs/test_tc_peer.c +45 −0
  63. tools/testing/selftests/bpf/progs/test_tcp_hdr_options.c +5 −2
  64. tools/testing/selftests/bpf/test_sockmap.c +45 −36
  65. tools/testing/selftests/bpf/test_tc_neigh.sh +0 −168
  66. tools/testing/selftests/bpf/test_tc_redirect.sh +204 −0
  67. tools/testing/selftests/bpf/test_tcp_hdr_options.h +3 −2
  68. tools/testing/selftests/bpf/trace_helpers.c +27 −0
  69. tools/testing/selftests/bpf/trace_helpers.h +4 −0
  70. tools/testing/selftests/bpf/verifier/basic.c +1 −1
  71. tools/testing/selftests/bpf/verifier/direct_packet_access.c +1 −1
  72. tools/testing/selftests/bpf/verifier/ld_imm64.c +0 −8
  73. tools/testing/selftests/bpf/verifier/regalloc.c +243 −0
Documentation/bpf/bpf_devel_QA.rst+2−2
@@ -60,13 +60,13 @@ Q: Where can I find patches currently under discussion for BPF subsystem? · 59 unmodified lines
6060 A: All patches that are Cc'ed to netdev are queued for review under netdev
6161 patchwork project:
6262
63− http://patchwork.ozlabs.org/project/netdev/list/
63+ https://patchwork.kernel.org/project/netdevbpf/list/
6464
6565 Those patches which target BPF, are assigned to a 'bpf' delegate for
6666 further processing from BPF maintainers. The current queue with
6767 patches under review can be found at:
6868
69− https://patchwork.ozlabs.org/project/netdev/list/?delegate=77147
69+ https://patchwork.kernel.org/project/netdevbpf/list/?delegate=121173
7070
7171 Once the patches have been reviewed by the BPF community as a whole
7272 and approved by the BPF maintainers, their status in patchwork will be
MAINTAINERS+1−1
@@ -3263,7 +3263,7 @@ M: Daniel Borkmann <daniel@iogearbox.net> · 3262 unmodified lines
32633263 R: Martin KaFai Lau <kafai@fb.com>
32643264 R: Song Liu <songliubraving@fb.com>
32653265 R: Yonghong Song <yhs@fb.com>
3266−R: Andrii Nakryiko <andriin@fb.com>
3266+R: Andrii Nakryiko <andrii@kernel.org>
32673267 R: John Fastabend <john.fastabend@gmail.com>
32683268 R: KP Singh <kpsingh@chromium.org>
32693269 L: netdev@vger.kernel.org
drivers/net/veth.c+9−0
@@ -420,6 +420,14 @@ static int veth_select_rxq(struct net_device *dev) · 419 unmodified lines
420420 return smp_processor_id() % dev->real_num_rx_queues;
421421 }
422422
423+static struct net_device *veth_peer_dev(struct net_device *dev)
424+{
425+ struct veth_priv *priv = netdev_priv(dev);
426+
427+ /* Callers must be under RCU read side. */
428+ return rcu_dereference(priv->peer);
429+}
430+
423431 static int veth_xdp_xmit(struct net_device *dev, int n,
424432 struct xdp_frame **frames,
425433 u32 flags, bool ndo_xmit)
@@ -1224,6 +1232,7 @@ static const struct net_device_ops veth_netdev_ops = { · 798 unmodified lines
12241232 .ndo_set_rx_headroom = veth_set_rx_headroom,
12251233 .ndo_bpf = veth_xdp,
12261234 .ndo_xdp_xmit = veth_ndo_xdp_xmit,
1235+ .ndo_get_peer_dev = veth_peer_dev,
12271236 };
12281237
12291238 #define VETH_FEATURES (NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HW_CSUM | \
include/linux/bpf.h+7−1
@@ -82,7 +82,7 @@ struct bpf_map_ops { · 81 unmodified lines
8282 void *(*map_fd_get_ptr)(struct bpf_map *map, struct file *map_file,
8383 int fd);
8484 void (*map_fd_put_ptr)(void *ptr);
85− u32 (*map_gen_lookup)(struct bpf_map *map, struct bpf_insn *insn_buf);
85+ int (*map_gen_lookup)(struct bpf_map *map, struct bpf_insn *insn_buf);
8686 u32 (*map_fd_sys_lookup_elem)(void *ptr);
8787 void (*map_seq_show_elem)(struct bpf_map *map, void *key,
8888 struct seq_file *m);
@@ -293,6 +293,7 @@ enum bpf_arg_type { · 204 unmodified lines
293293 ARG_PTR_TO_ALLOC_MEM_OR_NULL, /* pointer to dynamically allocated memory or NULL */
294294 ARG_CONST_ALLOC_SIZE_OR_ZERO, /* number of allocated bytes requested */
295295 ARG_PTR_TO_BTF_ID_SOCK_COMMON, /* pointer to in-kernel sock_common or bpf-mirrored bpf_sock */
296+ ARG_PTR_TO_PERCPU_BTF_ID, /* pointer to in-kernel percpu type */
296297 __BPF_ARG_TYPE_MAX,
297298 };
298299
@@ -307,6 +308,8 @@ enum bpf_return_type { · 8 unmodified lines
307308 RET_PTR_TO_SOCK_COMMON_OR_NULL, /* returns a pointer to a sock_common or NULL */
308309 RET_PTR_TO_ALLOC_MEM_OR_NULL, /* returns a pointer to dynamically allocated memory or NULL */
309310 RET_PTR_TO_BTF_ID_OR_NULL, /* returns a pointer to a btf_id or NULL */
311+ RET_PTR_TO_MEM_OR_BTF_ID_OR_NULL, /* returns a pointer to a valid memory or a btf_id or NULL */
312+ RET_PTR_TO_MEM_OR_BTF_ID, /* returns a pointer to a valid memory or a btf_id */
310313 };
311314
312315 /* eBPF function prototype used by verifier to allow BPF_CALLs from eBPF programs
@@ -405,6 +408,7 @@ enum bpf_reg_type { · 92 unmodified lines
405408 PTR_TO_RDONLY_BUF_OR_NULL, /* reg points to a readonly buffer or NULL */
406409 PTR_TO_RDWR_BUF, /* reg points to a read/write buffer */
407410 PTR_TO_RDWR_BUF_OR_NULL, /* reg points to a read/write buffer or NULL */
411+ PTR_TO_PERCPU_BTF_ID, /* reg points to a percpu kernel variable */
408412 };
409413
410414 /* The information passed from prog-specific *_is_valid_access
@@ -1828,6 +1832,8 @@ extern const struct bpf_func_proto bpf_skc_to_tcp_request_sock_proto; · 1417 unmodified lines
18281832 extern const struct bpf_func_proto bpf_skc_to_udp6_sock_proto;
18291833 extern const struct bpf_func_proto bpf_copy_from_user_proto;
18301834 extern const struct bpf_func_proto bpf_snprintf_btf_proto;
1835+extern const struct bpf_func_proto bpf_per_cpu_ptr_proto;
1836+extern const struct bpf_func_proto bpf_this_cpu_ptr_proto;
18311837
18321838 const struct bpf_func_proto *bpf_tracing_func_proto(
18331839 enum bpf_func_id func_id, const struct bpf_prog *prog);
include/linux/bpf_verifier.h+7−0
@@ -308,6 +308,13 @@ struct bpf_insn_aux_data { · 307 unmodified lines
308308 u32 map_index; /* index into used_maps[] */
309309 u32 map_off; /* offset from value base address */
310310 };
311+ struct {
312+ enum bpf_reg_type reg_type; /* type of pseudo_btf_id */
313+ union {
314+ u32 btf_id; /* btf_id for struct typed var */
315+ u32 mem_size; /* mem_size for non-struct typed var */
316+ };
317+ } btf_var;
311318 };
312319 u64 map_key_state; /* constant (32 bit) key tracking for maps */
313320 int ctx_field_size; /* the ctx field size for load insn, maybe 0 */
include/linux/btf.h+26−0
@@ -110,6 +110,11 @@ btf_resolve_size(const struct btf *btf, const struct btf_type *type, · 109 unmodified lines
110110 i < btf_type_vlen(struct_type); \
111111 i++, member++)
112112
113+#define for_each_vsi(i, datasec_type, member) \
114+ for (i = 0, member = btf_type_var_secinfo(datasec_type); \
115+ i < btf_type_vlen(datasec_type); \
116+ i++, member++)
117+
113118 static inline bool btf_type_is_ptr(const struct btf_type *t)
114119 {
115120 return BTF_INFO_KIND(t->info) == BTF_KIND_PTR;
@@ -145,6 +150,21 @@ static inline bool btf_type_is_func_proto(const struct btf_type *t) · 29 unmodified lines
145150 return BTF_INFO_KIND(t->info) == BTF_KIND_FUNC_PROTO;
146151 }
147152
153+static inline bool btf_type_is_var(const struct btf_type *t)
154+{
155+ return BTF_INFO_KIND(t->info) == BTF_KIND_VAR;
156+}
157+
158+/* union is only a special case of struct:
159+ * all its offsetof(member) == 0
160+ */
161+static inline bool btf_type_is_struct(const struct btf_type *t)
162+{
163+ u8 kind = BTF_INFO_KIND(t->info);
164+
165+ return kind == BTF_KIND_STRUCT || kind == BTF_KIND_UNION;
166+}
167+
148168 static inline u16 btf_type_vlen(const struct btf_type *t)
149169 {
150170 return BTF_INFO_VLEN(t->info);
@@ -179,6 +199,12 @@ static inline const struct btf_member *btf_type_member(const struct btf_type *t) · 28 unmodified lines
179199 return (const struct btf_member *)(t + 1);
180200 }
181201
202+static inline const struct btf_var_secinfo *btf_type_var_secinfo(
203+ const struct btf_type *t)
204+{
205+ return (const struct btf_var_secinfo *)(t + 1);
206+}
207+
182208 #ifdef CONFIG_BPF_SYSCALL
183209 const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id);
184210 const char *btf_name_by_offset(const struct btf *btf, u32 offset);
include/linux/netdevice.h+4−0
@@ -1276,6 +1276,9 @@ struct netdev_net_notifier { · 1275 unmodified lines
12761276 * int (*ndo_tunnel_ctl)(struct net_device *dev, struct ip_tunnel_parm *p,
12771277 * int cmd);
12781278 * Add, change, delete or get information on an IPv4 tunnel.
1279+ * struct net_device *(*ndo_get_peer_dev)(struct net_device *dev);
1280+ * If a device is paired with a peer device, return the peer instance.
1281+ * The caller must be under RCU read context.
12791282 */
12801283 struct net_device_ops {
12811284 int (*ndo_init)(struct net_device *dev);
@@ -1483,6 +1486,7 @@ struct net_device_ops { · 201 unmodified lines
14831486 struct devlink_port * (*ndo_get_devlink_port)(struct net_device *dev);
14841487 int (*ndo_tunnel_ctl)(struct net_device *dev,
14851488 struct ip_tunnel_parm *p, int cmd);
1489+ struct net_device * (*ndo_get_peer_dev)(struct net_device *dev);
14861490 };
14871491
14881492 /**
include/linux/skmsg.h+2−0
@@ -308,6 +308,8 @@ struct sk_psock *sk_psock_init(struct sock *sk, int node); · 307 unmodified lines
308308 int sk_psock_init_strp(struct sock *sk, struct sk_psock *psock);
309309 void sk_psock_start_strp(struct sock *sk, struct sk_psock *psock);
310310 void sk_psock_stop_strp(struct sock *sk, struct sk_psock *psock);
311+void sk_psock_start_verdict(struct sock *sk, struct sk_psock *psock);
312+void sk_psock_stop_verdict(struct sock *sk, struct sk_psock *psock);
311313
312314 int sk_psock_msg_verdict(struct sock *sk, struct sk_psock *psock,
313315 struct sk_msg *msg);
include/net/tcp.h+0−33
@@ -2228,34 +2228,6 @@ int __tcp_bpf_recvmsg(struct sock *sk, struct sk_psock *psock, · 2227 unmodified lines
22282228 #endif /* CONFIG_NET_SOCK_MSG */
22292229
22302230 #ifdef CONFIG_CGROUP_BPF
2231−/* Copy the listen sk's HDR_OPT_CB flags to its child.
2232− *
2233− * During 3-Way-HandShake, the synack is usually sent from
2234− * the listen sk with the HDR_OPT_CB flags set so that
2235− * bpf-prog will be called to write the BPF hdr option.
2236− *
2237− * In fastopen, the child sk is used to send synack instead
2238− * of the listen sk. Thus, inheriting the HDR_OPT_CB flags
2239− * from the listen sk gives the bpf-prog a chance to write
2240− * BPF hdr option in the synack pkt during fastopen.
2241− *
2242− * Both fastopen and non-fastopen child will inherit the
2243− * HDR_OPT_CB flags to keep the bpf-prog having a consistent
2244− * behavior when deciding to clear this cb flags (or not)
2245− * during the PASSIVE_ESTABLISHED_CB.
2246− *
2247− * In the future, other cb flags could be inherited here also.
2248− */
2249−static inline void bpf_skops_init_child(const struct sock *sk,
2250− struct sock *child)
2251−{
2252− tcp_sk(child)->bpf_sock_ops_cb_flags =
2253− tcp_sk(sk)->bpf_sock_ops_cb_flags &
2254− (BPF_SOCK_OPS_PARSE_ALL_HDR_OPT_CB_FLAG |
2255− BPF_SOCK_OPS_PARSE_UNKNOWN_HDR_OPT_CB_FLAG |
2256− BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG);
2257−}
2258−
22592231 static inline void bpf_skops_init_skb(struct bpf_sock_ops_kern *skops,
22602232 struct sk_buff *skb,
22612233 unsigned int end_offset)
@@ -2264,11 +2236,6 @@ static inline void bpf_skops_init_skb(struct bpf_sock_ops_kern *skops, · 2 unmodified lines
22642236 skops->skb_data_end = skb->data + end_offset;
22652237 }
22662238 #else
2267−static inline void bpf_skops_init_child(const struct sock *sk,
2268− struct sock *child)
2269−{
2270−}
2271−
22722239 static inline void bpf_skops_init_skb(struct bpf_sock_ops_kern *skops,
22732240 struct sk_buff *skb,
22742241 unsigned int end_offset)
include/uapi/linux/bpf.h+87−14
@@ -356,18 +356,36 @@ enum bpf_link_type { · 355 unmodified lines
356356 #define BPF_F_SLEEPABLE (1U << 4)
357357
358358 /* When BPF ldimm64's insn[0].src_reg != 0 then this can have
359− * two extensions:
360− *
361− * insn[0].src_reg: BPF_PSEUDO_MAP_FD BPF_PSEUDO_MAP_VALUE
362− * insn[0].imm: map fd map fd
363− * insn[1].imm: 0 offset into value
364− * insn[0].off: 0 0
365− * insn[1].off: 0 0
366− * ldimm64 rewrite: address of map address of map[0]+offset
367− * verifier type: CONST_PTR_TO_MAP PTR_TO_MAP_VALUE
359+ * the following extensions:
360+ *
361+ * insn[0].src_reg: BPF_PSEUDO_MAP_FD
362+ * insn[0].imm: map fd
363+ * insn[1].imm: 0
364+ * insn[0].off: 0
365+ * insn[1].off: 0
366+ * ldimm64 rewrite: address of map
367+ * verifier type: CONST_PTR_TO_MAP
368368 */
369369 #define BPF_PSEUDO_MAP_FD 1
370+/* insn[0].src_reg: BPF_PSEUDO_MAP_VALUE
371+ * insn[0].imm: map fd
372+ * insn[1].imm: offset into value
373+ * insn[0].off: 0
374+ * insn[1].off: 0
375+ * ldimm64 rewrite: address of map[0]+offset
376+ * verifier type: PTR_TO_MAP_VALUE
377+ */
370378 #define BPF_PSEUDO_MAP_VALUE 2
379+/* insn[0].src_reg: BPF_PSEUDO_BTF_ID
380+ * insn[0].imm: kernel btd id of VAR
381+ * insn[1].imm: 0
382+ * insn[0].off: 0
383+ * insn[1].off: 0
384+ * ldimm64 rewrite: address of the kernel variable
385+ * verifier type: PTR_TO_BTF_ID or PTR_TO_MEM, depending on whether the var
386+ * is struct/union.
387+ */
388+#define BPF_PSEUDO_BTF_ID 3
371389
372390 /* when bpf_call->src_reg == BPF_PSEUDO_CALL, bpf_call->imm == pc-relative
373391 * offset to another bpf function
@@ -417,6 +435,9 @@ enum { · 43 unmodified lines
417435
418436 /* Share perf_event among processes */
419437 BPF_F_PRESERVE_ELEMS = (1U << 11),
438+
439+/* Create a map that is suitable to be an inner map with dynamic max entries */
440+ BPF_F_INNER_MAP = (1U << 12),
420441 };
421442
422443 /* Flags for BPF_PROG_QUERY. */
@@ -1680,7 +1701,7 @@ union bpf_attr { · 1257 unmodified lines
16801701 * **TCP_CONGESTION**, **TCP_BPF_IW**,
16811702 * **TCP_BPF_SNDCWND_CLAMP**, **TCP_SAVE_SYN**,
16821703 * **TCP_KEEPIDLE**, **TCP_KEEPINTVL**, **TCP_KEEPCNT**,
1683− * **TCP_SYNCNT**, **TCP_USER_TIMEOUT**.
1704+ * **TCP_SYNCNT**, **TCP_USER_TIMEOUT**, **TCP_NOTSENT_LOWAT**.
16841705 * * **IPPROTO_IP**, which supports *optname* **IP_TOS**.
16851706 * * **IPPROTO_IPV6**, which supports *optname* **IPV6_TCLASS**.
16861707 * Return
@@ -2235,7 +2256,7 @@ union bpf_attr { · 548 unmodified lines
22352256 * Description
22362257 * This helper is used in programs implementing policies at the
22372258 * skb socket level. If the sk_buff *skb* is allowed to pass (i.e.
2238− * if the verdeict eBPF program returns **SK_PASS**), redirect it
2259+ * if the verdict eBPF program returns **SK_PASS**), redirect it
22392260 * to the socket referenced by *map* (of type
22402261 * **BPF_MAP_TYPE_SOCKHASH**) using hash *key*. Both ingress and
22412262 * egress interfaces can be used for redirection. The
@@ -3661,10 +3682,59 @@ union bpf_attr { · 1419 unmodified lines
36613682 * Redirect the packet to another net device of index *ifindex*
36623683 * and fill in L2 addresses from neighboring subsystem. This helper
36633684 * is somewhat similar to **bpf_redirect**\ (), except that it
3664− * fills in e.g. MAC addresses based on the L3 information from
3665− * the packet. This helper is supported for IPv4 and IPv6 protocols.
3685+ * populates L2 addresses as well, meaning, internally, the helper
3686+ * performs a FIB lookup based on the skb's networking header to
3687+ * get the address of the next hop and then relies on the neighbor
3688+ * lookup for the L2 address of the nexthop.
3689+ *
3690+ * The *flags* argument is reserved and must be 0. The helper is
3691+ * currently only supported for tc BPF program types, and enabled
3692+ * for IPv4 and IPv6 protocols.
3693+ * Return
3694+ * The helper returns **TC_ACT_REDIRECT** on success or
3695+ * **TC_ACT_SHOT** on error.
3696+ *
3697+ * void *bpf_per_cpu_ptr(const void *percpu_ptr, u32 cpu)
3698+ * Description
3699+ * Take a pointer to a percpu ksym, *percpu_ptr*, and return a
3700+ * pointer to the percpu kernel variable on *cpu*. A ksym is an
3701+ * extern variable decorated with '__ksym'. For ksym, there is a
3702+ * global var (either static or global) defined of the same name
3703+ * in the kernel. The ksym is percpu if the global var is percpu.
3704+ * The returned pointer points to the global percpu var on *cpu*.
3705+ *
3706+ * bpf_per_cpu_ptr() has the same semantic as per_cpu_ptr() in the
3707+ * kernel, except that bpf_per_cpu_ptr() may return NULL. This
3708+ * happens if *cpu* is larger than nr_cpu_ids. The caller of
3709+ * bpf_per_cpu_ptr() must check the returned value.
3710+ * Return
3711+ * A pointer pointing to the kernel percpu variable on *cpu*, or
3712+ * NULL, if *cpu* is invalid.
3713+ *
3714+ * void *bpf_this_cpu_ptr(const void *percpu_ptr)
3715+ * Description
3716+ * Take a pointer to a percpu ksym, *percpu_ptr*, and return a
3717+ * pointer to the percpu kernel variable on this cpu. See the
3718+ * description of 'ksym' in **bpf_per_cpu_ptr**\ ().
3719+ *
3720+ * bpf_this_cpu_ptr() has the same semantic as this_cpu_ptr() in
3721+ * the kernel. Different from **bpf_per_cpu_ptr**\ (), it would
3722+ * never return NULL.
3723+ * Return
3724+ * A pointer pointing to the kernel percpu variable on this cpu.
3725+ *
3726+ * long bpf_redirect_peer(u32 ifindex, u64 flags)
3727+ * Description
3728+ * Redirect the packet to another net device of index *ifindex*.
3729+ * This helper is somewhat similar to **bpf_redirect**\ (), except
3730+ * that the redirection happens to the *ifindex*' peer device and
3731+ * the netns switch takes place from ingress to ingress without
3732+ * going through the CPU's backlog queue.
3733+ *
36663734 * The *flags* argument is reserved and must be 0. The helper is
3667− * currently only supported for tc BPF program types.
3735+ * currently only supported for tc BPF program types at the ingress
3736+ * hook and for veth device types. The peer device must reside in a
3737+ * different network namespace.
36683738 * Return
36693739 * The helper returns **TC_ACT_REDIRECT** on success or
36703740 * **TC_ACT_SHOT** on error.
@@ -3823,6 +3893,9 @@ union bpf_attr { · 152 unmodified lines
38233893 FN(seq_printf_btf), \
38243894 FN(skb_cgroup_classid), \
38253895 FN(redirect_neigh), \
3896+ FN(bpf_per_cpu_ptr), \
3897+ FN(bpf_this_cpu_ptr), \
3898+ FN(redirect_peer), \
38263899 /* */
38273900
38283901 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
kernel/bpf/arraymap.c+11−6
@@ -16,7 +16,7 @@ · 15 unmodified lines
1616
1717 #define ARRAY_CREATE_FLAG_MASK \
1818 (BPF_F_NUMA_NODE | BPF_F_MMAPABLE | BPF_F_ACCESS_MASK | \
19− BPF_F_PRESERVE_ELEMS)
19+ BPF_F_PRESERVE_ELEMS | BPF_F_INNER_MAP)
2020
2121 static void bpf_array_free_percpu(struct bpf_array *array)
2222 {
@@ -62,7 +62,7 @@ int array_map_alloc_check(union bpf_attr *attr) · 39 unmodified lines
6262 return -EINVAL;
6363
6464 if (attr->map_type != BPF_MAP_TYPE_ARRAY &&
65− attr->map_flags & BPF_F_MMAPABLE)
65+ attr->map_flags & (BPF_F_MMAPABLE | BPF_F_INNER_MAP))
6666 return -EINVAL;
6767
6868 if (attr->map_type != BPF_MAP_TYPE_PERF_EVENT_ARRAY &&
@@ -214,7 +214,7 @@ static int array_map_direct_value_meta(const struct bpf_map *map, u64 imm, · 145 unmodified lines
214214 }
215215
216216 /* emit BPF instructions equivalent to C code of array_map_lookup_elem() */
217−static u32 array_map_gen_lookup(struct bpf_map *map, struct bpf_insn *insn_buf)
217+static int array_map_gen_lookup(struct bpf_map *map, struct bpf_insn *insn_buf)
218218 {
219219 struct bpf_array *array = container_of(map, struct bpf_array, map);
220220 struct bpf_insn *insn = insn_buf;
@@ -223,6 +223,9 @@ static u32 array_map_gen_lookup(struct bpf_map *map, struct bpf_insn *insn_buf) · 2 unmodified lines
223223 const int map_ptr = BPF_REG_1;
224224 const int index = BPF_REG_2;
225225
226+ if (map->map_flags & BPF_F_INNER_MAP)
227+ return -EOPNOTSUPP;
228+
226229 *insn++ = BPF_ALU64_IMM(BPF_ADD, map_ptr, offsetof(struct bpf_array, value));
227230 *insn++ = BPF_LDX_MEM(BPF_W, ret, index, 0);
228231 if (!map->bypass_spec_v1) {
@@ -496,8 +499,10 @@ static int array_map_mmap(struct bpf_map *map, struct vm_area_struct *vma) · 267 unmodified lines
496499 static bool array_map_meta_equal(const struct bpf_map *meta0,
497500 const struct bpf_map *meta1)
498501 {
499− return meta0->max_entries == meta1->max_entries &&
500− bpf_map_meta_equal(meta0, meta1);
502+ if (!bpf_map_meta_equal(meta0, meta1))
503+ return false;
504+ return meta0->map_flags & BPF_F_INNER_MAP ? true :
505+ meta0->max_entries == meta1->max_entries;
501506 }
502507
503508 struct bpf_iter_seq_array_map_info {
@@ -1251,7 +1256,7 @@ static void *array_of_map_lookup_elem(struct bpf_map *map, void *key) · 747 unmodified lines
12511256 return READ_ONCE(*inner_map);
12521257 }
12531258
1254−static u32 array_of_map_gen_lookup(struct bpf_map *map,
1259+static int array_of_map_gen_lookup(struct bpf_map *map,
12551260 struct bpf_insn *insn_buf)
12561261 {
12571262 struct bpf_array *array = container_of(map, struct bpf_array, map);
kernel/bpf/btf.c+0−25
@@ -188,11 +188,6 @@ · 187 unmodified lines
188188 i < btf_type_vlen(struct_type); \
189189 i++, member++)
190190
191−#define for_each_vsi(i, struct_type, member) \
192− for (i = 0, member = btf_type_var_secinfo(struct_type); \
193− i < btf_type_vlen(struct_type); \
194− i++, member++)
195−
196191 #define for_each_vsi_from(i, from, struct_type, member) \
197192 for (i = from, member = btf_type_var_secinfo(struct_type) + from; \
198193 i < btf_type_vlen(struct_type); \
@@ -440,16 +435,6 @@ static bool btf_type_nosize_or_null(const struct btf_type *t) · 241 unmodified lines
440435 return !t || btf_type_nosize(t);
441436 }
442437
443−/* union is only a special case of struct:
444− * all its offsetof(member) == 0
445− */
446−static bool btf_type_is_struct(const struct btf_type *t)
447−{
448− u8 kind = BTF_INFO_KIND(t->info);
449−
450− return kind == BTF_KIND_STRUCT || kind == BTF_KIND_UNION;
451−}
452−
453438 static bool __btf_type_is_struct(const struct btf_type *t)
454439 {
455440 return BTF_INFO_KIND(t->info) == BTF_KIND_STRUCT;
@@ -460,11 +445,6 @@ static bool btf_type_is_array(const struct btf_type *t) · 4 unmodified lines
460445 return BTF_INFO_KIND(t->info) == BTF_KIND_ARRAY;
461446 }
462447
463−static bool btf_type_is_var(const struct btf_type *t)
464−{
465− return BTF_INFO_KIND(t->info) == BTF_KIND_VAR;
466−}
467−
468448 static bool btf_type_is_datasec(const struct btf_type *t)
469449 {
470450 return BTF_INFO_KIND(t->info) == BTF_KIND_DATASEC;
@@ -613,11 +593,6 @@ static const struct btf_var *btf_type_var(const struct btf_type *t) · 142 unmodified lines
613593 return (const struct btf_var *)(t + 1);
614594 }
615595
616−static const struct btf_var_secinfo *btf_type_var_secinfo(const struct btf_type *t)
617−{
618− return (const struct btf_var_secinfo *)(t + 1);
619−}
620−
621596 static const struct btf_kind_operations *btf_type_ops(const struct btf_type *t)
622597 {
623598 return kind_ops[BTF_INFO_KIND(t->info)];
kernel/bpf/hashtab.c+3−3
@@ -612,7 +612,7 @@ static void *htab_map_lookup_elem(struct bpf_map *map, void *key) · 611 unmodified lines
612612 * bpf_prog
613613 * __htab_map_lookup_elem
614614 */
615−static u32 htab_map_gen_lookup(struct bpf_map *map, struct bpf_insn *insn_buf)
615+static int htab_map_gen_lookup(struct bpf_map *map, struct bpf_insn *insn_buf)
616616 {
617617 struct bpf_insn *insn = insn_buf;
618618 const int ret = BPF_REG_0;
@@ -651,7 +651,7 @@ static void *htab_lru_map_lookup_elem_sys(struct bpf_map *map, void *key) · 32 unmodified lines
651651 return __htab_lru_map_lookup_elem(map, key, false);
652652 }
653653
654−static u32 htab_lru_map_gen_lookup(struct bpf_map *map,
654+static int htab_lru_map_gen_lookup(struct bpf_map *map,
655655 struct bpf_insn *insn_buf)
656656 {
657657 struct bpf_insn *insn = insn_buf;
@@ -2070,7 +2070,7 @@ static void *htab_of_map_lookup_elem(struct bpf_map *map, void *key) · 1412 unmodified lines
20702070 return READ_ONCE(*inner_map);
20712071 }
20722072
2073−static u32 htab_of_map_gen_lookup(struct bpf_map *map,
2073+static int htab_of_map_gen_lookup(struct bpf_map *map,
20742074 struct bpf_insn *insn_buf)
20752075 {
20762076 struct bpf_insn *insn = insn_buf;
kernel/bpf/helpers.c+32−0
@@ -623,6 +623,34 @@ const struct bpf_func_proto bpf_copy_from_user_proto = { · 622 unmodified lines
623623 .arg3_type = ARG_ANYTHING,
624624 };
625625
626+BPF_CALL_2(bpf_per_cpu_ptr, const void *, ptr, u32, cpu)
627+{
628+ if (cpu >= nr_cpu_ids)
629+ return (unsigned long)NULL;
630+
631+ return (unsigned long)per_cpu_ptr((const void __percpu *)ptr, cpu);
632+}
633+
634+const struct bpf_func_proto bpf_per_cpu_ptr_proto = {
635+ .func = bpf_per_cpu_ptr,
636+ .gpl_only = false,
637+ .ret_type = RET_PTR_TO_MEM_OR_BTF_ID_OR_NULL,
638+ .arg1_type = ARG_PTR_TO_PERCPU_BTF_ID,
639+ .arg2_type = ARG_ANYTHING,
640+};
641+
642+BPF_CALL_1(bpf_this_cpu_ptr, const void *, percpu_ptr)
643+{
644+ return (unsigned long)this_cpu_ptr((const void __percpu *)percpu_ptr);
645+}
646+
647+const struct bpf_func_proto bpf_this_cpu_ptr_proto = {
648+ .func = bpf_this_cpu_ptr,
649+ .gpl_only = false,
650+ .ret_type = RET_PTR_TO_MEM_OR_BTF_ID,
651+ .arg1_type = ARG_PTR_TO_PERCPU_BTF_ID,
652+};
653+
626654 const struct bpf_func_proto bpf_get_current_task_proto __weak;
627655 const struct bpf_func_proto bpf_probe_read_user_proto __weak;
628656 const struct bpf_func_proto bpf_probe_read_user_str_proto __weak;
@@ -689,6 +717,10 @@ bpf_base_func_proto(enum bpf_func_id func_id) · 60 unmodified lines
689717 return &bpf_snprintf_btf_proto;
690718 case BPF_FUNC_jiffies64:
691719 return &bpf_jiffies64_proto;
720+ case BPF_FUNC_bpf_per_cpu_ptr:
721+ return &bpf_per_cpu_ptr_proto;
722+ case BPF_FUNC_bpf_this_cpu_ptr:
723+ return &bpf_this_cpu_ptr_proto;
692724 default:
693725 break;
694726 }
kernel/bpf/percpu_freelist.c+96−5
@@ -17,6 +17,8 @@ int pcpu_freelist_init(struct pcpu_freelist *s) · 16 unmodified lines
1717 raw_spin_lock_init(&head->lock);
1818 head->first = NULL;
1919 }
20+ raw_spin_lock_init(&s->extralist.lock);
21+ s->extralist.first = NULL;
2022 return 0;
2123 }
2224
@@ -40,12 +42,50 @@ static inline void ___pcpu_freelist_push(struct pcpu_freelist_head *head, · 17 unmodified lines
4042 raw_spin_unlock(&head->lock);
4143 }
4244
45+static inline bool pcpu_freelist_try_push_extra(struct pcpu_freelist *s,
46+ struct pcpu_freelist_node *node)
47+{
48+ if (!raw_spin_trylock(&s->extralist.lock))
49+ return false;
50+
51+ pcpu_freelist_push_node(&s->extralist, node);
52+ raw_spin_unlock(&s->extralist.lock);
53+ return true;
54+}
55+
56+static inline void ___pcpu_freelist_push_nmi(struct pcpu_freelist *s,
57+ struct pcpu_freelist_node *node)
58+{
59+ int cpu, orig_cpu;
60+
61+ orig_cpu = cpu = raw_smp_processor_id();
62+ while (1) {
63+ struct pcpu_freelist_head *head;
64+
65+ head = per_cpu_ptr(s->freelist, cpu);
66+ if (raw_spin_trylock(&head->lock)) {
67+ pcpu_freelist_push_node(head, node);
68+ raw_spin_unlock(&head->lock);
69+ return;
70+ }
71+ cpu = cpumask_next(cpu, cpu_possible_mask);
72+ if (cpu >= nr_cpu_ids)
73+ cpu = 0;
74+
75+ /* cannot lock any per cpu lock, try extralist */
76+ if (cpu == orig_cpu &&
77+ pcpu_freelist_try_push_extra(s, node))
78+ return;
79+ }
80+}
81+
4382 void __pcpu_freelist_push(struct pcpu_freelist *s,
4483 struct pcpu_freelist_node *node)
4584 {
46− struct pcpu_freelist_head *head = this_cpu_ptr(s->freelist);
47−
48− ___pcpu_freelist_push(head, node);
85+ if (in_nmi())
86+ ___pcpu_freelist_push_nmi(s, node);
87+ else
88+ ___pcpu_freelist_push(this_cpu_ptr(s->freelist), node);
4989 }
5090
5191 void pcpu_freelist_push(struct pcpu_freelist *s,
@@ -81,7 +121,7 @@ again: · 29 unmodified lines
81121 }
82122 }
83123
84−struct pcpu_freelist_node *__pcpu_freelist_pop(struct pcpu_freelist *s)
124+static struct pcpu_freelist_node *___pcpu_freelist_pop(struct pcpu_freelist *s)
85125 {
86126 struct pcpu_freelist_head *head;
87127 struct pcpu_freelist_node *node;
@@ -102,8 +142,59 @@ struct pcpu_freelist_node *__pcpu_freelist_pop(struct pcpu_freelist *s) · 14 unmodified lines
102142 if (cpu >= nr_cpu_ids)
103143 cpu = 0;
104144 if (cpu == orig_cpu)
105− return NULL;
145+ break;
146+ }
147+
148+ /* per cpu lists are all empty, try extralist */
149+ raw_spin_lock(&s->extralist.lock);
150+ node = s->extralist.first;
151+ if (node)
152+ s->extralist.first = node->next;
153+ raw_spin_unlock(&s->extralist.lock);
154+ return node;
155+}
156+
157+static struct pcpu_freelist_node *
158+___pcpu_freelist_pop_nmi(struct pcpu_freelist *s)
159+{
160+ struct pcpu_freelist_head *head;
161+ struct pcpu_freelist_node *node;
162+ int orig_cpu, cpu;
163+
164+ orig_cpu = cpu = raw_smp_processor_id();
165+ while (1) {
166+ head = per_cpu_ptr(s->freelist, cpu);
167+ if (raw_spin_trylock(&head->lock)) {
168+ node = head->first;
169+ if (node) {
170+ head->first = node->next;
171+ raw_spin_unlock(&head->lock);
172+ return node;
173+ }
174+ raw_spin_unlock(&head->lock);
175+ }
176+ cpu = cpumask_next(cpu, cpu_possible_mask);
177+ if (cpu >= nr_cpu_ids)
178+ cpu = 0;
179+ if (cpu == orig_cpu)
180+ break;
106181 }
182+
183+ /* cannot pop from per cpu lists, try extralist */
184+ if (!raw_spin_trylock(&s->extralist.lock))
185+ return NULL;
186+ node = s->extralist.first;
187+ if (node)
188+ s->extralist.first = node->next;
189+ raw_spin_unlock(&s->extralist.lock);
190+ return node;
191+}
192+
193+struct pcpu_freelist_node *__pcpu_freelist_pop(struct pcpu_freelist *s)
194+{
195+ if (in_nmi())
196+ return ___pcpu_freelist_pop_nmi(s);
197+ return ___pcpu_freelist_pop(s);
107198 }
108199
109200 struct pcpu_freelist_node *pcpu_freelist_pop(struct pcpu_freelist *s)
kernel/bpf/percpu_freelist.h+1−0
@@ -13,6 +13,7 @@ struct pcpu_freelist_head { · 12 unmodified lines
1313
1414 struct pcpu_freelist {
1515 struct pcpu_freelist_head __percpu *freelist;
16+ struct pcpu_freelist_head extralist;
1617 };
1718
1819 struct pcpu_freelist_node {
kernel/bpf/syscall.c+3−1
@@ -4323,8 +4323,10 @@ static int bpf_prog_bind_map(union bpf_attr *attr) · 4322 unmodified lines
43234323 used_maps_old = prog->aux->used_maps;
43244324
43254325 for (i = 0; i < prog->aux->used_map_cnt; i++)
4326− if (used_maps_old[i] == map)
4326+ if (used_maps_old[i] == map) {
4327+ bpf_map_put(map);
43274328 goto out_unlock;
4329+ }
43284330
43294331 used_maps_new = kmalloc_array(prog->aux->used_map_cnt + 1,
43304332 sizeof(used_maps_new[0]),
kernel/bpf/verifier.c+251−19
@@ -238,6 +238,8 @@ struct bpf_call_arg_meta { · 237 unmodified lines
238238 u64 msize_max_value;
239239 int ref_obj_id;
240240 int func_id;
241+ u32 btf_id;
242+ u32 ret_btf_id;
241243 };
242244
243245 struct btf *btf_vmlinux;
@@ -517,6 +519,7 @@ static const char * const reg_type_str[] = { · 273 unmodified lines
517519 [PTR_TO_XDP_SOCK] = "xdp_sock",
518520 [PTR_TO_BTF_ID] = "ptr_",
519521 [PTR_TO_BTF_ID_OR_NULL] = "ptr_or_null_",
522+ [PTR_TO_PERCPU_BTF_ID] = "percpu_ptr_",
520523 [PTR_TO_MEM] = "mem",
521524 [PTR_TO_MEM_OR_NULL] = "mem_or_null",
522525 [PTR_TO_RDONLY_BUF] = "rdonly_buf",
@@ -583,7 +586,9 @@ static void print_verifier_state(struct bpf_verifier_env *env, · 60 unmodified lines
583586 /* reg->off should be 0 for SCALAR_VALUE */
584587 verbose(env, "%lld", reg->var_off.value + reg->off);
585588 } else {
586− if (t == PTR_TO_BTF_ID || t == PTR_TO_BTF_ID_OR_NULL)
589+ if (t == PTR_TO_BTF_ID ||
590+ t == PTR_TO_BTF_ID_OR_NULL ||
591+ t == PTR_TO_PERCPU_BTF_ID)
587592 verbose(env, "%s", kernel_type_name(reg->btf_id));
588593 verbose(env, "(id=%d", reg->id);
589594 if (reg_type_may_be_refcounted_or_null(t))
@@ -2204,6 +2209,7 @@ static bool is_spillable_regtype(enum bpf_reg_type type) · 1614 unmodified lines
22042209 case PTR_TO_RDONLY_BUF_OR_NULL:
22052210 case PTR_TO_RDWR_BUF:
22062211 case PTR_TO_RDWR_BUF_OR_NULL:
2212+ case PTR_TO_PERCPU_BTF_ID:
22072213 return true;
22082214 default:
22092215 return false;
@@ -2221,6 +2227,20 @@ static bool register_is_const(struct bpf_reg_state *reg) · 11 unmodified lines
22212227 return reg->type == SCALAR_VALUE && tnum_is_const(reg->var_off);
22222228 }
22232229
2230+static bool __is_scalar_unbounded(struct bpf_reg_state *reg)
2231+{
2232+ return tnum_is_unknown(reg->var_off) &&
2233+ reg->smin_value == S64_MIN && reg->smax_value == S64_MAX &&
2234+ reg->umin_value == 0 && reg->umax_value == U64_MAX &&
2235+ reg->s32_min_value == S32_MIN && reg->s32_max_value == S32_MAX &&
2236+ reg->u32_min_value == 0 && reg->u32_max_value == U32_MAX;
2237+}
2238+
2239+static bool register_is_bounded(struct bpf_reg_state *reg)
2240+{
2241+ return reg->type == SCALAR_VALUE && !__is_scalar_unbounded(reg);
2242+}
2243+
22242244 static bool __is_pointer_value(bool allow_ptr_leaks,
22252245 const struct bpf_reg_state *reg)
22262246 {
@@ -2272,7 +2292,7 @@ static int check_stack_write(struct bpf_verifier_env *env, · 45 unmodified lines
22722292 if (value_regno >= 0)
22732293 reg = &cur->regs[value_regno];
22742294
2275− if (reg && size == BPF_REG_SIZE && register_is_const(reg) &&
2295+ if (reg && size == BPF_REG_SIZE && register_is_bounded(reg) &&
22762296 !register_is_null(reg) && env->bpf_capable) {
22772297 if (dst_reg != BPF_REG_FP) {
22782298 /* The backtracking logic can only recognize explicit
@@ -2667,7 +2687,7 @@ static bool may_access_direct_pkt_data(struct bpf_verifier_env *env, · 388 unmodified lines
26672687 case BPF_PROG_TYPE_CGROUP_SKB:
26682688 if (t == BPF_WRITE)
26692689 return false;
2670− /* fallthrough */
2690+ fallthrough;
26712691
26722692 /* Program types with direct read + write access go here! */
26732693 case BPF_PROG_TYPE_SCHED_CLS:
@@ -3978,6 +3998,7 @@ static const struct bpf_reg_types sock_types = { · 1304 unmodified lines
39783998 },
39793999 };
39804000
4001+#ifdef CONFIG_NET
39814002 static const struct bpf_reg_types btf_id_sock_common_types = {
39824003 .types = {
39834004 PTR_TO_SOCK_COMMON,
@@ -3988,6 +4009,7 @@ static const struct bpf_reg_types btf_id_sock_common_types = { · 4 unmodified lines
39884009 },
39894010 .btf_id = &btf_sock_ids[BTF_SOCK_TYPE_SOCK_COMMON],
39904011 };
4012+#endif
39914013
39924014 static const struct bpf_reg_types mem_types = {
39934015 .types = {
@@ -4017,6 +4039,7 @@ static const struct bpf_reg_types alloc_mem_types = { .types = { PTR_TO_MEM } }; · 23 unmodified lines
40174039 static const struct bpf_reg_types const_map_ptr_types = { .types = { CONST_PTR_TO_MAP } };
40184040 static const struct bpf_reg_types btf_ptr_types = { .types = { PTR_TO_BTF_ID } };
40194041 static const struct bpf_reg_types spin_lock_types = { .types = { PTR_TO_MAP_VALUE } };
4042+static const struct bpf_reg_types percpu_btf_ptr_types = { .types = { PTR_TO_PERCPU_BTF_ID } };
40204043
40214044 static const struct bpf_reg_types *compatible_reg_types[__BPF_ARG_TYPE_MAX] = {
40224045 [ARG_PTR_TO_MAP_KEY] = &map_key_value_types,
@@ -4030,7 +4053,9 @@ static const struct bpf_reg_types *compatible_reg_types[__BPF_ARG_TYPE_MAX] = { · 7 unmodified lines
40304053 [ARG_PTR_TO_CTX] = &context_types,
40314054 [ARG_PTR_TO_CTX_OR_NULL] = &context_types,
40324055 [ARG_PTR_TO_SOCK_COMMON] = &sock_types,
4056+#ifdef CONFIG_NET
40334057 [ARG_PTR_TO_BTF_ID_SOCK_COMMON] = &btf_id_sock_common_types,
4058+#endif
40344059 [ARG_PTR_TO_SOCKET] = &fullsock_types,
40354060 [ARG_PTR_TO_SOCKET_OR_NULL] = &fullsock_types,
40364061 [ARG_PTR_TO_BTF_ID] = &btf_ptr_types,
@@ -4042,6 +4067,7 @@ static const struct bpf_reg_types *compatible_reg_types[__BPF_ARG_TYPE_MAX] = { · 5 unmodified lines
40424067 [ARG_PTR_TO_ALLOC_MEM_OR_NULL] = &alloc_mem_types,
40434068 [ARG_PTR_TO_INT] = &int_ptr_types,
40444069 [ARG_PTR_TO_LONG] = &int_ptr_types,
4070+ [ARG_PTR_TO_PERCPU_BTF_ID] = &percpu_btf_ptr_types,
40454071 };
40464072
40474073 static int check_reg_type(struct bpf_verifier_env *env, u32 regno,
@@ -4205,6 +4231,12 @@ skip_type_check: · 157 unmodified lines
42054231 err = check_helper_mem_access(env, regno,
42064232 meta->map_ptr->value_size, false,
42074233 meta);
4234+ } else if (arg_type == ARG_PTR_TO_PERCPU_BTF_ID) {
4235+ if (!reg->btf_id) {
4236+ verbose(env, "Helper has invalid btf_id in R%d\n", regno);
4237+ return -EACCES;
4238+ }
4239+ meta->ret_btf_id = reg->btf_id;
42084240 } else if (arg_type == ARG_PTR_TO_SPIN_LOCK) {
42094241 if (meta->func_id == BPF_FUNC_spin_lock) {
42104242 if (process_spin_lock(env, regno, true))
@@ -5114,6 +5146,35 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn · 903 unmodified lines
51145146 regs[BPF_REG_0].type = PTR_TO_MEM_OR_NULL;
51155147 regs[BPF_REG_0].id = ++env->id_gen;
51165148 regs[BPF_REG_0].mem_size = meta.mem_size;
5149+ } else if (fn->ret_type == RET_PTR_TO_MEM_OR_BTF_ID_OR_NULL ||
5150+ fn->ret_type == RET_PTR_TO_MEM_OR_BTF_ID) {
5151+ const struct btf_type *t;
5152+
5153+ mark_reg_known_zero(env, regs, BPF_REG_0);
5154+ t = btf_type_skip_modifiers(btf_vmlinux, meta.ret_btf_id, NULL);
5155+ if (!btf_type_is_struct(t)) {
5156+ u32 tsize;
5157+ const struct btf_type *ret;
5158+ const char *tname;
5159+
5160+ /* resolve the type size of ksym. */
5161+ ret = btf_resolve_size(btf_vmlinux, t, &tsize);
5162+ if (IS_ERR(ret)) {
5163+ tname = btf_name_by_offset(btf_vmlinux, t->name_off);
5164+ verbose(env, "unable to resolve the size of type '%s': %ld\n",
5165+ tname, PTR_ERR(ret));
5166+ return -EINVAL;
5167+ }
5168+ regs[BPF_REG_0].type =
5169+ fn->ret_type == RET_PTR_TO_MEM_OR_BTF_ID ?
5170+ PTR_TO_MEM : PTR_TO_MEM_OR_NULL;
5171+ regs[BPF_REG_0].mem_size = tsize;
5172+ } else {
5173+ regs[BPF_REG_0].type =
5174+ fn->ret_type == RET_PTR_TO_MEM_OR_BTF_ID ?
5175+ PTR_TO_BTF_ID : PTR_TO_BTF_ID_OR_NULL;
5176+ regs[BPF_REG_0].btf_id = meta.ret_btf_id;
5177+ }
51175178 } else if (fn->ret_type == RET_PTR_TO_BTF_ID_OR_NULL) {
51185179 int ret_btf_id;
51195180
@@ -5432,7 +5493,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, · 312 unmodified lines
54325493 /* smin_val represents the known value */
54335494 if (known && smin_val == 0 && opcode == BPF_ADD)
54345495 break;
5435− /* fall-through */
5496+ fallthrough;
54365497 case PTR_TO_PACKET_END:
54375498 case PTR_TO_SOCKET:
54385499 case PTR_TO_SOCKET_OR_NULL:
@@ -6389,6 +6450,11 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env, · 950 unmodified lines
63896450 src_reg = NULL;
63906451 if (dst_reg->type != SCALAR_VALUE)
63916452 ptr_reg = dst_reg;
6453+ else
6454+ /* Make sure ID is cleared otherwise dst_reg min/max could be
6455+ * incorrectly propagated into other registers by find_equal_scalars()
6456+ */
6457+ dst_reg->id = 0;
63926458 if (BPF_SRC(insn->code) == BPF_X) {
63936459 src_reg = &regs[insn->src_reg];
63946460 if (src_reg->type != SCALAR_VALUE) {
@@ -6522,6 +6588,12 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn) · 127 unmodified lines
65226588 /* case: R1 = R2
65236589 * copy register state to dest reg
65246590 */
6591+ if (src_reg->type == SCALAR_VALUE && !src_reg->id)
6592+ /* Assign src and dst registers the same ID
6593+ * that will be used by find_equal_scalars()
6594+ * to propagate min/max range.
6595+ */
6596+ src_reg->id = ++env->id_gen;
65256597 *dst_reg = *src_reg;
65266598 dst_reg->live |= REG_LIVE_WRITTEN;
65276599 dst_reg->subreg_def = DEF_NOT_SUBREG;
@@ -6534,6 +6606,11 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn) · 6 unmodified lines
65346606 return -EACCES;
65356607 } else if (src_reg->type == SCALAR_VALUE) {
65366608 *dst_reg = *src_reg;
6609+ /* Make sure ID is cleared otherwise
6610+ * dst_reg min/max could be incorrectly
6611+ * propagated into src_reg by find_equal_scalars()
6612+ */
6613+ dst_reg->id = 0;
65376614 dst_reg->live |= REG_LIVE_WRITTEN;
65386615 dst_reg->subreg_def = env->insn_idx + 1;
65396616 } else {
@@ -7322,6 +7399,30 @@ static bool try_match_pkt_pointers(const struct bpf_insn *insn, · 782 unmodified lines
73227399 return true;
73237400 }
73247401
7402+static void find_equal_scalars(struct bpf_verifier_state *vstate,
7403+ struct bpf_reg_state *known_reg)
7404+{
7405+ struct bpf_func_state *state;
7406+ struct bpf_reg_state *reg;
7407+ int i, j;
7408+
7409+ for (i = 0; i <= vstate->curframe; i++) {
7410+ state = vstate->frame[i];
7411+ for (j = 0; j < MAX_BPF_REG; j++) {
7412+ reg = &state->regs[j];
7413+ if (reg->type == SCALAR_VALUE && reg->id == known_reg->id)
7414+ *reg = *known_reg;
7415+ }
7416+
7417+ bpf_for_each_spilled_reg(j, state, reg) {
7418+ if (!reg)
7419+ continue;
7420+ if (reg->type == SCALAR_VALUE && reg->id == known_reg->id)
7421+ *reg = *known_reg;
7422+ }
7423+ }
7424+}
7425+
73257426 static int check_cond_jmp_op(struct bpf_verifier_env *env,
73267427 struct bpf_insn *insn, int *insn_idx)
73277428 {
@@ -7450,6 +7551,11 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env, · 122 unmodified lines
74507551 reg_combine_min_max(&other_branch_regs[insn->src_reg],
74517552 &other_branch_regs[insn->dst_reg],
74527553 src_reg, dst_reg, opcode);
7554+ if (src_reg->id) {
7555+ find_equal_scalars(this_branch, src_reg);
7556+ find_equal_scalars(other_branch, &other_branch_regs[insn->src_reg]);
7557+ }
7558+
74537559 }
74547560 } else if (dst_reg->type == SCALAR_VALUE) {
74557561 reg_set_min_max(&other_branch_regs[insn->dst_reg],
@@ -7457,6 +7563,11 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env, · 1 unmodified line
74577563 opcode, is_jmp32);
74587564 }
74597565
7566+ if (dst_reg->type == SCALAR_VALUE && dst_reg->id) {
7567+ find_equal_scalars(this_branch, dst_reg);
7568+ find_equal_scalars(other_branch, &other_branch_regs[insn->dst_reg]);
7569+ }
7570+
74607571 /* detect if R == 0 where R is returned from bpf_map_lookup_elem().
74617572 * NOTE: these optimizations below are related with pointer comparison
74627573 * which will never be JMP32.
@@ -7488,6 +7599,7 @@ static int check_ld_imm(struct bpf_verifier_env *env, struct bpf_insn *insn) · 25 unmodified lines
74887599 {
74897600 struct bpf_insn_aux_data *aux = cur_aux(env);
74907601 struct bpf_reg_state *regs = cur_regs(env);
7602+ struct bpf_reg_state *dst_reg;
74917603 struct bpf_map *map;
74927604 int err;
74937605
@@ -7504,25 +7616,45 @@ static int check_ld_imm(struct bpf_verifier_env *env, struct bpf_insn *insn) · 10 unmodified lines
75047616 if (err)
75057617 return err;
75067618
7619+ dst_reg = &regs[insn->dst_reg];
75077620 if (insn->src_reg == 0) {
75087621 u64 imm = ((u64)(insn + 1)->imm << 32) | (u32)insn->imm;
75097622
7510− regs[insn->dst_reg].type = SCALAR_VALUE;
7623+ dst_reg->type = SCALAR_VALUE;
75117624 __mark_reg_known(&regs[insn->dst_reg], imm);
75127625 return 0;
75137626 }
75147627
7628+ if (insn->src_reg == BPF_PSEUDO_BTF_ID) {
7629+ mark_reg_known_zero(env, regs, insn->dst_reg);
7630+
7631+ dst_reg->type = aux->btf_var.reg_type;
7632+ switch (dst_reg->type) {
7633+ case PTR_TO_MEM:
7634+ dst_reg->mem_size = aux->btf_var.mem_size;
7635+ break;
7636+ case PTR_TO_BTF_ID:
7637+ case PTR_TO_PERCPU_BTF_ID:
7638+ dst_reg->btf_id = aux->btf_var.btf_id;
7639+ break;
7640+ default:
7641+ verbose(env, "bpf verifier is misconfigured\n");
7642+ return -EFAULT;
7643+ }
7644+ return 0;
7645+ }
7646+
75157647 map = env->used_maps[aux->map_index];
75167648 mark_reg_known_zero(env, regs, insn->dst_reg);
7517− regs[insn->dst_reg].map_ptr = map;
7649+ dst_reg->map_ptr = map;
75187650
75197651 if (insn->src_reg == BPF_PSEUDO_MAP_VALUE) {
7520− regs[insn->dst_reg].type = PTR_TO_MAP_VALUE;
7521− regs[insn->dst_reg].off = aux->map_off;
7652+ dst_reg->type = PTR_TO_MAP_VALUE;
7653+ dst_reg->off = aux->map_off;
75227654 if (map_value_has_spin_lock(map))
7523− regs[insn->dst_reg].id = ++env->id_gen;
7655+ dst_reg->id = ++env->id_gen;
75247656 } else if (insn->src_reg == BPF_PSEUDO_MAP_FD) {
7525− regs[insn->dst_reg].type = CONST_PTR_TO_MAP;
7657+ dst_reg->type = CONST_PTR_TO_MAP;
75267658 } else {
75277659 verbose(env, "bpf verifier is misconfigured\n");
75287660 return -EINVAL;
@@ -9424,6 +9556,92 @@ process_bpf_exit: · 1895 unmodified lines
94249556 return 0;
94259557 }
94269558
9559+/* replace pseudo btf_id with kernel symbol address */
9560+static int check_pseudo_btf_id(struct bpf_verifier_env *env,
9561+ struct bpf_insn *insn,
9562+ struct bpf_insn_aux_data *aux)
9563+{
9564+ u32 datasec_id, type, id = insn->imm;
9565+ const struct btf_var_secinfo *vsi;
9566+ const struct btf_type *datasec;
9567+ const struct btf_type *t;
9568+ const char *sym_name;
9569+ bool percpu = false;
9570+ u64 addr;
9571+ int i;
9572+
9573+ if (!btf_vmlinux) {
9574+ verbose(env, "kernel is missing BTF, make sure CONFIG_DEBUG_INFO_BTF=y is specified in Kconfig.\n");
9575+ return -EINVAL;
9576+ }
9577+
9578+ if (insn[1].imm != 0) {
9579+ verbose(env, "reserved field (insn[1].imm) is used in pseudo_btf_id ldimm64 insn.\n");
9580+ return -EINVAL;
9581+ }
9582+
9583+ t = btf_type_by_id(btf_vmlinux, id);
9584+ if (!t) {
9585+ verbose(env, "ldimm64 insn specifies invalid btf_id %d.\n", id);
9586+ return -ENOENT;
9587+ }
9588+
9589+ if (!btf_type_is_var(t)) {
9590+ verbose(env, "pseudo btf_id %d in ldimm64 isn't KIND_VAR.\n",
9591+ id);
9592+ return -EINVAL;
9593+ }
9594+
9595+ sym_name = btf_name_by_offset(btf_vmlinux, t->name_off);
9596+ addr = kallsyms_lookup_name(sym_name);
9597+ if (!addr) {
9598+ verbose(env, "ldimm64 failed to find the address for kernel symbol '%s'.\n",
9599+ sym_name);
9600+ return -ENOENT;
9601+ }
9602+
9603+ datasec_id = btf_find_by_name_kind(btf_vmlinux, ".data..percpu",
9604+ BTF_KIND_DATASEC);
9605+ if (datasec_id > 0) {
9606+ datasec = btf_type_by_id(btf_vmlinux, datasec_id);
9607+ for_each_vsi(i, datasec, vsi) {
9608+ if (vsi->type == id) {
9609+ percpu = true;
9610+ break;
9611+ }
9612+ }
9613+ }
9614+
9615+ insn[0].imm = (u32)addr;
9616+ insn[1].imm = addr >> 32;
9617+
9618+ type = t->type;
9619+ t = btf_type_skip_modifiers(btf_vmlinux, type, NULL);
9620+ if (percpu) {
9621+ aux->btf_var.reg_type = PTR_TO_PERCPU_BTF_ID;
9622+ aux->btf_var.btf_id = type;
9623+ } else if (!btf_type_is_struct(t)) {
9624+ const struct btf_type *ret;
9625+ const char *tname;
9626+ u32 tsize;
9627+
9628+ /* resolve the type size of ksym. */
9629+ ret = btf_resolve_size(btf_vmlinux, t, &tsize);
9630+ if (IS_ERR(ret)) {
9631+ tname = btf_name_by_offset(btf_vmlinux, t->name_off);
9632+ verbose(env, "ldimm64 unable to resolve the size of type '%s': %ld\n",
9633+ tname, PTR_ERR(ret));
9634+ return -EINVAL;
9635+ }
9636+ aux->btf_var.reg_type = PTR_TO_MEM;
9637+ aux->btf_var.mem_size = tsize;
9638+ } else {
9639+ aux->btf_var.reg_type = PTR_TO_BTF_ID;
9640+ aux->btf_var.btf_id = type;
9641+ }
9642+ return 0;
9643+}
9644+
94279645 static int check_map_prealloc(struct bpf_map *map)
94289646 {
94299647 return (map->map_type != BPF_MAP_TYPE_HASH &&
@@ -9534,10 +9752,14 @@ static bool bpf_map_is_cgroup_storage(struct bpf_map *map) · 104 unmodified lines
95349752 map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE);
95359753 }
95369754
9537−/* look for pseudo eBPF instructions that access map FDs and
9538− * replace them with actual map pointers
9755+/* find and rewrite pseudo imm in ld_imm64 instructions:
9756+ *
9757+ * 1. if it accesses map FD, replace it with actual map pointer.
9758+ * 2. if it accesses btf_id of a VAR, replace it with pointer to the var.
9759+ *
9760+ * NOTE: btf_vmlinux is required for converting pseudo btf_id.
95399761 */
9540−static int replace_map_fd_with_map_ptr(struct bpf_verifier_env *env)
9762+static int resolve_pseudo_ldimm64(struct bpf_verifier_env *env)
95419763 {
95429764 struct bpf_insn *insn = env->prog->insnsi;
95439765 int insn_cnt = env->prog->len;
@@ -9578,6 +9800,14 @@ static int replace_map_fd_with_map_ptr(struct bpf_verifier_env *env) · 34 unmodified lines
95789800 /* valid generic load 64-bit imm */
95799801 goto next_insn;
95809802
9803+ if (insn[0].src_reg == BPF_PSEUDO_BTF_ID) {
9804+ aux = &env->insn_aux_data[i];
9805+ err = check_pseudo_btf_id(env, insn, aux);
9806+ if (err)
9807+ return err;
9808+ goto next_insn;
9809+ }
9810+
95819811 /* In final convert_pseudo_ld_imm64() step, this is
95829812 * converted into regular 64-bit imm load insn.
95839813 */
@@ -10819,7 +11049,9 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env) · 1235 unmodified lines
1081911049 if (insn->imm == BPF_FUNC_map_lookup_elem &&
1082011050 ops->map_gen_lookup) {
1082111051 cnt = ops->map_gen_lookup(map_ptr, insn_buf);
10822− if (cnt == 0 || cnt >= ARRAY_SIZE(insn_buf)) {
11052+ if (cnt == -EOPNOTSUPP)
11053+ goto patch_map_ops_generic;
11054+ if (cnt <= 0 || cnt >= ARRAY_SIZE(insn_buf)) {
1082311055 verbose(env, "bpf verifier is misconfigured\n");
1082411056 return -EINVAL;
1082511057 }
@@ -10849,7 +11081,7 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env) · 23 unmodified lines
1084911081 (int (*)(struct bpf_map *map, void *value))NULL));
1085011082 BUILD_BUG_ON(!__same_type(ops->map_peek_elem,
1085111083 (int (*)(struct bpf_map *map, void *value))NULL));
10852−
11084+patch_map_ops_generic:
1085311085 switch (insn->imm) {
1085411086 case BPF_FUNC_map_lookup_elem:
1085511087 insn->imm = BPF_CAST_CALL(ops->map_lookup_elem) -
@@ -11633,10 +11865,6 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, · 777 unmodified lines
1163311865 if (is_priv)
1163411866 env->test_state_freq = attr->prog_flags & BPF_F_TEST_STATE_FREQ;
1163511867
11636− ret = replace_map_fd_with_map_ptr(env);
11637− if (ret < 0)
11638− goto skip_full_check;
11639−
1164011868 if (bpf_prog_is_dev_bound(env->prog->aux)) {
1164111869 ret = bpf_prog_offload_verifier_prep(env->prog);
1164211870 if (ret)
@@ -11662,6 +11890,10 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, · 19 unmodified lines
1166211890 if (ret)
1166311891 goto skip_full_check;
1166411892
11893+ ret = resolve_pseudo_ldimm64(env);
11894+ if (ret < 0)
11895+ goto skip_full_check;
11896+
1166511897 ret = check_cfg(env);
1166611898 if (ret < 0)
1166711899 goto skip_full_check;
kernel/trace/bpf_trace.c+6−0
@@ -1327,6 +1327,10 @@ bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) · 1326 unmodified lines
13271327 return prog->aux->sleepable ? &bpf_copy_from_user_proto : NULL;
13281328 case BPF_FUNC_snprintf_btf:
13291329 return &bpf_snprintf_btf_proto;
1330+ case BPF_FUNC_bpf_per_cpu_ptr:
1331+ return &bpf_per_cpu_ptr_proto;
1332+ case BPF_FUNC_bpf_this_cpu_ptr:
1333+ return &bpf_this_cpu_ptr_proto;
13301334 default:
13311335 return NULL;
13321336 }
@@ -1776,7 +1780,9 @@ const struct bpf_verifier_ops raw_tracepoint_verifier_ops = { · 443 unmodified lines
17761780 };
17771781
17781782 const struct bpf_prog_ops raw_tracepoint_prog_ops = {
1783+#ifdef CONFIG_NET
17791784 .test_run = bpf_prog_test_run_raw_tp,
1785+#endif
17801786 };
17811787
17821788 const struct bpf_verifier_ops tracing_verifier_ops = {
net/core/dev.c+12−3
@@ -4930,7 +4930,7 @@ EXPORT_SYMBOL_GPL(br_fdb_test_addr_hook); · 4929 unmodified lines
49304930
49314931 static inline struct sk_buff *
49324932 sch_handle_ingress(struct sk_buff *skb, struct packet_type **pt_prev, int *ret,
4933− struct net_device *orig_dev)
4933+ struct net_device *orig_dev, bool *another)
49344934 {
49354935 #ifdef CONFIG_NET_CLS_ACT
49364936 struct mini_Qdisc *miniq = rcu_dereference_bh(skb->dev->miniq_ingress);
@@ -4974,7 +4974,11 @@ sch_handle_ingress(struct sk_buff *skb, struct packet_type **pt_prev, int *ret, · 37 unmodified lines
49744974 * redirecting to another netdev
49754975 */
49764976 __skb_push(skb, skb->mac_len);
4977− skb_do_redirect(skb);
4977+ if (skb_do_redirect(skb) == -EAGAIN) {
4978+ __skb_pull(skb, skb->mac_len);
4979+ *another = true;
4980+ break;
4981+ }
49784982 return NULL;
49794983 case TC_ACT_CONSUMED:
49804984 return NULL;
@@ -5163,7 +5167,12 @@ another_round: · 182 unmodified lines
51635167 skip_taps:
51645168 #ifdef CONFIG_NET_INGRESS
51655169 if (static_branch_unlikely(&ingress_needed_key)) {
5166− skb = sch_handle_ingress(skb, &pt_prev, &ret, orig_dev);
5170+ bool another = false;
5171+
5172+ skb = sch_handle_ingress(skb, &pt_prev, &ret, orig_dev,
5173+ &another);
5174+ if (another)
5175+ goto another_round;
51675176 if (!skb)
51685177 goto out;
51695178
net/core/filter.c+99−8
@@ -76,6 +76,7 @@ · 75 unmodified lines
7676 #include <net/bpf_sk_storage.h>
7777 #include <net/transp_v6.h>
7878 #include <linux/btf_ids.h>
79+#include <net/tls.h>
7980
8081 static const struct bpf_func_proto *
8182 bpf_sk_base_func_proto(enum bpf_func_id func_id);
@@ -2379,8 +2380,9 @@ out: · 2297 unmodified lines
23792380
23802381 /* Internal, non-exposed redirect flags. */
23812382 enum {
2382− BPF_F_NEIGH = (1ULL << 1),
2383−#define BPF_F_REDIRECT_INTERNAL (BPF_F_NEIGH)
2383+ BPF_F_NEIGH = (1ULL << 1),
2384+ BPF_F_PEER = (1ULL << 2),
2385+#define BPF_F_REDIRECT_INTERNAL (BPF_F_NEIGH | BPF_F_PEER)
23842386 };
23852387
23862388 BPF_CALL_3(bpf_clone_redirect, struct sk_buff *, skb, u32, ifindex, u64, flags)
@@ -2429,19 +2431,35 @@ EXPORT_PER_CPU_SYMBOL_GPL(bpf_redirect_info); · 42 unmodified lines
24292431 int skb_do_redirect(struct sk_buff *skb)
24302432 {
24312433 struct bpf_redirect_info *ri = this_cpu_ptr(&bpf_redirect_info);
2434+ struct net *net = dev_net(skb->dev);
24322435 struct net_device *dev;
24332436 u32 flags = ri->flags;
24342437
2435− dev = dev_get_by_index_rcu(dev_net(skb->dev), ri->tgt_index);
2438+ dev = dev_get_by_index_rcu(net, ri->tgt_index);
24362439 ri->tgt_index = 0;
2437− if (unlikely(!dev)) {
2438− kfree_skb(skb);
2439− return -EINVAL;
2440+ ri->flags = 0;
2441+ if (unlikely(!dev))
2442+ goto out_drop;
2443+ if (flags & BPF_F_PEER) {
2444+ const struct net_device_ops *ops = dev->netdev_ops;
2445+
2446+ if (unlikely(!ops->ndo_get_peer_dev ||
2447+ !skb_at_tc_ingress(skb)))
2448+ goto out_drop;
2449+ dev = ops->ndo_get_peer_dev(dev);
2450+ if (unlikely(!dev ||
2451+ !is_skb_forwardable(dev, skb) ||
2452+ net_eq(net, dev_net(dev))))
2453+ goto out_drop;
2454+ skb->dev = dev;
2455+ return -EAGAIN;
24402456 }
2441−
24422457 return flags & BPF_F_NEIGH ?
24432458 __bpf_redirect_neigh(skb, dev) :
24442459 __bpf_redirect(skb, dev, flags);
2460+out_drop:
2461+ kfree_skb(skb);
2462+ return -EINVAL;
24452463 }
24462464
24472465 BPF_CALL_2(bpf_redirect, u32, ifindex, u64, flags)
@@ -2465,6 +2483,27 @@ static const struct bpf_func_proto bpf_redirect_proto = { · 17 unmodified lines
24652483 .arg2_type = ARG_ANYTHING,
24662484 };
24672485
2486+BPF_CALL_2(bpf_redirect_peer, u32, ifindex, u64, flags)
2487+{
2488+ struct bpf_redirect_info *ri = this_cpu_ptr(&bpf_redirect_info);
2489+
2490+ if (unlikely(flags))
2491+ return TC_ACT_SHOT;
2492+
2493+ ri->flags = BPF_F_PEER;
2494+ ri->tgt_index = ifindex;
2495+
2496+ return TC_ACT_REDIRECT;
2497+}
2498+
2499+static const struct bpf_func_proto bpf_redirect_peer_proto = {
2500+ .func = bpf_redirect_peer,
2501+ .gpl_only = false,
2502+ .ret_type = RET_INTEGER,
2503+ .arg1_type = ARG_ANYTHING,
2504+ .arg2_type = ARG_ANYTHING,
2505+};
2506+
24682507 BPF_CALL_2(bpf_redirect_neigh, u32, ifindex, u64, flags)
24692508 {
24702509 struct bpf_redirect_info *ri = this_cpu_ptr(&bpf_redirect_info);
@@ -3479,6 +3518,48 @@ static u32 __bpf_skb_max_len(const struct sk_buff *skb) · 1008 unmodified lines
34793518 SKB_MAX_ALLOC;
34803519 }
34813520
3521+BPF_CALL_4(sk_skb_adjust_room, struct sk_buff *, skb, s32, len_diff,
3522+ u32, mode, u64, flags)
3523+{
3524+ u32 len_diff_abs = abs(len_diff);
3525+ bool shrink = len_diff < 0;
3526+ int ret = 0;
3527+
3528+ if (unlikely(flags || mode))
3529+ return -EINVAL;
3530+ if (unlikely(len_diff_abs > 0xfffU))
3531+ return -EFAULT;
3532+
3533+ if (!shrink) {
3534+ ret = skb_cow(skb, len_diff);
3535+ if (unlikely(ret < 0))
3536+ return ret;
3537+ __skb_push(skb, len_diff_abs);
3538+ memset(skb->data, 0, len_diff_abs);
3539+ } else {
3540+ if (unlikely(!pskb_may_pull(skb, len_diff_abs)))
3541+ return -ENOMEM;
3542+ __skb_pull(skb, len_diff_abs);
3543+ }
3544+ bpf_compute_data_end_sk_skb(skb);
3545+ if (tls_sw_has_ctx_rx(skb->sk)) {
3546+ struct strp_msg *rxm = strp_msg(skb);
3547+
3548+ rxm->full_len += len_diff;
3549+ }
3550+ return ret;
3551+}
3552+
3553+static const struct bpf_func_proto sk_skb_adjust_room_proto = {
3554+ .func = sk_skb_adjust_room,
3555+ .gpl_only = false,
3556+ .ret_type = RET_INTEGER,
3557+ .arg1_type = ARG_PTR_TO_CTX,
3558+ .arg2_type = ARG_ANYTHING,
3559+ .arg3_type = ARG_ANYTHING,
3560+ .arg4_type = ARG_ANYTHING,
3561+};
3562+
34823563 BPF_CALL_4(bpf_skb_adjust_room, struct sk_buff *, skb, s32, len_diff,
34833564 u32, mode, u64, flags)
34843565 {
@@ -4784,6 +4865,10 @@ static int _bpf_setsockopt(struct sock *sk, int level, int optname, · 1299 unmodified lines
47844865 else
47854866 icsk->icsk_user_timeout = val;
47864867 break;
4868+ case TCP_NOTSENT_LOWAT:
4869+ tp->notsent_lowat = val;
4870+ sk->sk_write_space(sk);
4871+ break;
47874872 default:
47884873 ret = -EINVAL;
47894874 }
@@ -5149,7 +5234,6 @@ static int bpf_fib_set_fwd_params(struct bpf_fib_lookup *params, · 359 unmodified lines
51495234 memcpy(params->smac, dev->dev_addr, ETH_ALEN);
51505235 params->h_vlan_TCI = 0;
51515236 params->h_vlan_proto = 0;
5152− params->ifindex = dev->ifindex;
51535237
51545238 return 0;
51555239 }
@@ -5246,6 +5330,7 @@ static int bpf_ipv4_fib_lookup(struct net *net, struct bpf_fib_lookup *params, · 90 unmodified lines
52465330 dev = nhc->nhc_dev;
52475331
52485332 params->rt_metric = res.fi->fib_priority;
5333+ params->ifindex = dev->ifindex;
52495334
52505335 /* xdp and cls_bpf programs are run in RCU-bh so
52515336 * rcu_read_lock_bh is not needed here
@@ -5371,6 +5456,7 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params, · 119 unmodified lines
53715456
53725457 dev = res.nh->fib_nh_dev;
53735458 params->rt_metric = res.f6i->fib6_metric;
5459+ params->ifindex = dev->ifindex;
53745460
53755461 /* xdp and cls_bpf programs are run in RCU-bh so rcu_read_lock_bh is
53765462 * not needed here.
@@ -6745,6 +6831,7 @@ bool bpf_helper_changes_pkt_data(void *func) · 1368 unmodified lines
67456831 func == bpf_skb_change_tail ||
67466832 func == sk_skb_change_tail ||
67476833 func == bpf_skb_adjust_room ||
6834+ func == sk_skb_adjust_room ||
67486835 func == bpf_skb_pull_data ||
67496836 func == sk_skb_pull_data ||
67506837 func == bpf_clone_redirect ||
@@ -7005,6 +7092,8 @@ tc_cls_act_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) · 254 unmodified lines
70057092 return &bpf_redirect_proto;
70067093 case BPF_FUNC_redirect_neigh:
70077094 return &bpf_redirect_neigh_proto;
7095+ case BPF_FUNC_redirect_peer:
7096+ return &bpf_redirect_peer_proto;
70087097 case BPF_FUNC_get_route_realm:
70097098 return &bpf_get_route_realm_proto;
70107099 case BPF_FUNC_get_hash_recalc:
@@ -7218,6 +7307,8 @@ sk_skb_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) · 207 unmodified lines
72187307 return &sk_skb_change_tail_proto;
72197308 case BPF_FUNC_skb_change_head:
72207309 return &sk_skb_change_head_proto;
7310+ case BPF_FUNC_skb_adjust_room:
7311+ return &sk_skb_adjust_room_proto;
72217312 case BPF_FUNC_get_socket_cookie:
72227313 return &bpf_get_socket_cookie_proto;
72237314 case BPF_FUNC_get_socket_uid:
net/core/skmsg.c+123−38
@@ -433,10 +433,12 @@ static int sk_psock_skb_ingress(struct sk_psock *psock, struct sk_buff *skb) · 432 unmodified lines
433433 static int sk_psock_handle_skb(struct sk_psock *psock, struct sk_buff *skb,
434434 u32 off, u32 len, bool ingress)
435435 {
436− if (ingress)
437− return sk_psock_skb_ingress(psock, skb);
438− else
436+ if (!ingress) {
437+ if (!sock_writeable(psock->sk))
438+ return -EAGAIN;
439439 return skb_send_sock_locked(psock->sk, skb, off, len);
440+ }
441+ return sk_psock_skb_ingress(psock, skb);
440442 }
441443
442444 static void sk_psock_backlog(struct work_struct *work)
@@ -625,6 +627,8 @@ void sk_psock_drop(struct sock *sk, struct sk_psock *psock) · 182 unmodified lines
625627 rcu_assign_sk_user_data(sk, NULL);
626628 if (psock->progs.skb_parser)
627629 sk_psock_stop_strp(sk, psock);
630+ else if (psock->progs.skb_verdict)
631+ sk_psock_stop_verdict(sk, psock);
628632 write_unlock_bh(&sk->sk_callback_lock);
629633 sk_psock_clear_state(psock, SK_PSOCK_TX_ENABLED);
630634
@@ -682,19 +686,8 @@ EXPORT_SYMBOL_GPL(sk_psock_msg_verdict); · 51 unmodified lines
682686 static int sk_psock_bpf_run(struct sk_psock *psock, struct bpf_prog *prog,
683687 struct sk_buff *skb)
684688 {
685− int ret;
686−
687− skb->sk = psock->sk;
688689 bpf_compute_data_end_sk_skb(skb);
689− ret = bpf_prog_run_pin_on_cpu(prog, skb);
690− /* strparser clones the skb before handing it to a upper layer,
691− * meaning skb_orphan has been called. We NULL sk on the way out
692− * to ensure we don't trigger a BUG_ON() in skb/sk operations
693− * later and because we are not charging the memory of this skb
694− * to any socket yet.
695− */
696− skb->sk = NULL;
697− return ret;
690+ return bpf_prog_run_pin_on_cpu(prog, skb);
698691 }
699692
700693 static struct sk_psock *sk_psock_from_strp(struct strparser *strp)
@@ -709,38 +702,35 @@ static void sk_psock_skb_redirect(struct sk_buff *skb) · 8 unmodified lines
709702 {
710703 struct sk_psock *psock_other;
711704 struct sock *sk_other;
712− bool ingress;
713705
714706 sk_other = tcp_skb_bpf_redirect_fetch(skb);
707+ /* This error is a buggy BPF program, it returned a redirect
708+ * return code, but then didn't set a redirect interface.
709+ */
715710 if (unlikely(!sk_other)) {
716711 kfree_skb(skb);
717712 return;
718713 }
719714 psock_other = sk_psock(sk_other);
715+ /* This error indicates the socket is being torn down or had another
716+ * error that caused the pipe to break. We can't send a packet on
717+ * a socket that is in this state so we drop the skb.
718+ */
720719 if (!psock_other || sock_flag(sk_other, SOCK_DEAD) ||
721720 !sk_psock_test_state(psock_other, SK_PSOCK_TX_ENABLED)) {
722721 kfree_skb(skb);
723722 return;
724723 }
725724
726− ingress = tcp_skb_bpf_ingress(skb);
727− if ((!ingress && sock_writeable(sk_other)) ||
728− (ingress &&
729− atomic_read(&sk_other->sk_rmem_alloc) <=
730− sk_other->sk_rcvbuf)) {
731− if (!ingress)
732− skb_set_owner_w(skb, sk_other);
733− skb_queue_tail(&psock_other->ingress_skb, skb);
734− schedule_work(&psock_other->work);
735− } else {
736− kfree_skb(skb);
737− }
725+ skb_queue_tail(&psock_other->ingress_skb, skb);
726+ schedule_work(&psock_other->work);
738727 }
739728
740−static void sk_psock_tls_verdict_apply(struct sk_buff *skb, int verdict)
729+static void sk_psock_tls_verdict_apply(struct sk_buff *skb, struct sock *sk, int verdict)
741730 {
742731 switch (verdict) {
743732 case __SK_REDIRECT:
733+ skb_set_owner_r(skb, sk);
744734 sk_psock_skb_redirect(skb);
745735 break;
746736 case __SK_PASS:
@@ -758,11 +748,17 @@ int sk_psock_tls_strp_read(struct sk_psock *psock, struct sk_buff *skb) · 11 unmodified lines
758748 rcu_read_lock();
759749 prog = READ_ONCE(psock->progs.skb_verdict);
760750 if (likely(prog)) {
751+ /* We skip full set_owner_r here because if we do a SK_PASS
752+ * or SK_DROP we can skip skb memory accounting and use the
753+ * TLS context.
754+ */
755+ skb->sk = psock->sk;
761756 tcp_skb_bpf_redirect_clear(skb);
762757 ret = sk_psock_bpf_run(psock, prog, skb);
763758 ret = sk_psock_map_verd(ret, tcp_skb_bpf_redirect_fetch(skb));
759+ skb->sk = NULL;
764760 }
765− sk_psock_tls_verdict_apply(skb, ret);
761+ sk_psock_tls_verdict_apply(skb, psock->sk, ret);
766762 rcu_read_unlock();
767763 return ret;
768764 }
@@ -771,7 +767,9 @@ EXPORT_SYMBOL_GPL(sk_psock_tls_strp_read); · 2 unmodified lines
771767 static void sk_psock_verdict_apply(struct sk_psock *psock,
772768 struct sk_buff *skb, int verdict)
773769 {
770+ struct tcp_skb_cb *tcp;
774771 struct sock *sk_other;
772+ int err = -EIO;
775773
776774 switch (verdict) {
777775 case __SK_PASS:
@@ -780,16 +778,24 @@ static void sk_psock_verdict_apply(struct sk_psock *psock, · 2 unmodified lines
780778 !sk_psock_test_state(psock, SK_PSOCK_TX_ENABLED)) {
781779 goto out_free;
782780 }
783− if (atomic_read(&sk_other->sk_rmem_alloc) <=
784− sk_other->sk_rcvbuf) {
785− struct tcp_skb_cb *tcp = TCP_SKB_CB(skb);
786781
787− tcp->bpf.flags |= BPF_F_INGRESS;
782+ tcp = TCP_SKB_CB(skb);
783+ tcp->bpf.flags |= BPF_F_INGRESS;
784+
785+ /* If the queue is empty then we can submit directly
786+ * into the msg queue. If its not empty we have to
787+ * queue work otherwise we may get OOO data. Otherwise,
788+ * if sk_psock_skb_ingress errors will be handled by
789+ * retrying later from workqueue.
790+ */
791+ if (skb_queue_empty(&psock->ingress_skb)) {
792+ err = sk_psock_skb_ingress(psock, skb);
793+ }
794+ if (err < 0) {
788795 skb_queue_tail(&psock->ingress_skb, skb);
789796 schedule_work(&psock->work);
790− break;
791797 }
792− goto out_free;
798+ break;
793799 case __SK_REDIRECT:
794800 sk_psock_skb_redirect(skb);
795801 break;
@@ -814,9 +820,9 @@ static void sk_psock_strp_read(struct strparser *strp, struct sk_buff *skb) · 18 unmodified lines
814820 kfree_skb(skb);
815821 goto out;
816822 }
823+ skb_set_owner_r(skb, sk);
817824 prog = READ_ONCE(psock->progs.skb_verdict);
818825 if (likely(prog)) {
819− skb_orphan(skb);
820826 tcp_skb_bpf_redirect_clear(skb);
821827 ret = sk_psock_bpf_run(psock, prog, skb);
822828 ret = sk_psock_map_verd(ret, tcp_skb_bpf_redirect_fetch(skb));
@@ -839,8 +845,11 @@ static int sk_psock_strp_parse(struct strparser *strp, struct sk_buff *skb) · 16 unmodified lines
839845
840846 rcu_read_lock();
841847 prog = READ_ONCE(psock->progs.skb_parser);
842− if (likely(prog))
848+ if (likely(prog)) {
849+ skb->sk = psock->sk;
843850 ret = sk_psock_bpf_run(psock, prog, skb);
851+ skb->sk = NULL;
852+ }
844853 rcu_read_unlock();
845854 return ret;
846855 }
@@ -864,6 +873,57 @@ static void sk_psock_strp_data_ready(struct sock *sk) · 17 unmodified lines
864873 rcu_read_unlock();
865874 }
866875
876+static int sk_psock_verdict_recv(read_descriptor_t *desc, struct sk_buff *skb,
877+ unsigned int offset, size_t orig_len)
878+{
879+ struct sock *sk = (struct sock *)desc->arg.data;
880+ struct sk_psock *psock;
881+ struct bpf_prog *prog;
882+ int ret = __SK_DROP;
883+ int len = skb->len;
884+
885+ /* clone here so sk_eat_skb() in tcp_read_sock does not drop our data */
886+ skb = skb_clone(skb, GFP_ATOMIC);
887+ if (!skb) {
888+ desc->error = -ENOMEM;
889+ return 0;
890+ }
891+
892+ rcu_read_lock();
893+ psock = sk_psock(sk);
894+ if (unlikely(!psock)) {
895+ len = 0;
896+ kfree_skb(skb);
897+ goto out;
898+ }
899+ skb_set_owner_r(skb, sk);
900+ prog = READ_ONCE(psock->progs.skb_verdict);
901+ if (likely(prog)) {
902+ tcp_skb_bpf_redirect_clear(skb);
903+ ret = sk_psock_bpf_run(psock, prog, skb);
904+ ret = sk_psock_map_verd(ret, tcp_skb_bpf_redirect_fetch(skb));
905+ }
906+ sk_psock_verdict_apply(psock, skb, ret);
907+out:
908+ rcu_read_unlock();
909+ return len;
910+}
911+
912+static void sk_psock_verdict_data_ready(struct sock *sk)
913+{
914+ struct socket *sock = sk->sk_socket;
915+ read_descriptor_t desc;
916+
917+ if (unlikely(!sock || !sock->ops || !sock->ops->read_sock))
918+ return;
919+
920+ desc.arg.data = sk;
921+ desc.error = 0;
922+ desc.count = 1;
923+
924+ sock->ops->read_sock(sk, &desc, sk_psock_verdict_recv);
925+}
926+
867927 static void sk_psock_write_space(struct sock *sk)
868928 {
869929 struct sk_psock *psock;
@@ -893,6 +953,19 @@ int sk_psock_init_strp(struct sock *sk, struct sk_psock *psock) · 23 unmodified lines
893953 return strp_init(&psock->parser.strp, sk, &cb);
894954 }
895955
956+void sk_psock_start_verdict(struct sock *sk, struct sk_psock *psock)
957+{
958+ struct sk_psock_parser *parser = &psock->parser;
959+
960+ if (parser->enabled)
961+ return;
962+
963+ parser->saved_data_ready = sk->sk_data_ready;
964+ sk->sk_data_ready = sk_psock_verdict_data_ready;
965+ sk->sk_write_space = sk_psock_write_space;
966+ parser->enabled = true;
967+}
968+
896969 void sk_psock_start_strp(struct sock *sk, struct sk_psock *psock)
897970 {
898971 struct sk_psock_parser *parser = &psock->parser;
@@ -918,3 +991,15 @@ void sk_psock_stop_strp(struct sock *sk, struct sk_psock *psock) · 19 unmodified lines
918991 strp_stop(&parser->strp);
919992 parser->enabled = false;
920993 }
994+
995+void sk_psock_stop_verdict(struct sock *sk, struct sk_psock *psock)
996+{
997+ struct sk_psock_parser *parser = &psock->parser;
998+
999+ if (!parser->enabled)
1000+ return;
1001+
1002+ sk->sk_data_ready = parser->saved_data_ready;
1003+ parser->saved_data_ready = NULL;
1004+ parser->enabled = false;
1005+}
net/core/sock_map.c+23−14
@@ -148,8 +148,8 @@ static void sock_map_add_link(struct sk_psock *psock, · 147 unmodified lines
148148 static void sock_map_del_link(struct sock *sk,
149149 struct sk_psock *psock, void *link_raw)
150150 {
151+ bool strp_stop = false, verdict_stop = false;
151152 struct sk_psock_link *link, *tmp;
152− bool strp_stop = false;
153153
154154 spin_lock_bh(&psock->link_lock);
155155 list_for_each_entry_safe(link, tmp, &psock->link, list) {
@@ -159,14 +159,19 @@ static void sock_map_del_link(struct sock *sk, · 3 unmodified lines
159159 map);
160160 if (psock->parser.enabled && stab->progs.skb_parser)
161161 strp_stop = true;
162+ if (psock->parser.enabled && stab->progs.skb_verdict)
163+ verdict_stop = true;
162164 list_del(&link->list);
163165 sk_psock_free_link(link);
164166 }
165167 }
166168 spin_unlock_bh(&psock->link_lock);
167− if (strp_stop) {
169+ if (strp_stop || verdict_stop) {
168170 write_lock_bh(&sk->sk_callback_lock);
169− sk_psock_stop_strp(sk, psock);
171+ if (strp_stop)
172+ sk_psock_stop_strp(sk, psock);
173+ else
174+ sk_psock_stop_verdict(sk, psock);
170175 write_unlock_bh(&sk->sk_callback_lock);
171176 }
172177 }
@@ -230,16 +235,16 @@ static int sock_map_link(struct bpf_map *map, struct sk_psock_progs *progs, · 57 unmodified lines
230235 {
231236 struct bpf_prog *msg_parser, *skb_parser, *skb_verdict;
232237 struct sk_psock *psock;
233− bool skb_progs;
234238 int ret;
235239
236240 skb_verdict = READ_ONCE(progs->skb_verdict);
237241 skb_parser = READ_ONCE(progs->skb_parser);
238− skb_progs = skb_parser && skb_verdict;
239− if (skb_progs) {
242+ if (skb_verdict) {
240243 skb_verdict = bpf_prog_inc_not_zero(skb_verdict);
241244 if (IS_ERR(skb_verdict))
242245 return PTR_ERR(skb_verdict);
246+ }
247+ if (skb_parser) {
243248 skb_parser = bpf_prog_inc_not_zero(skb_parser);
244249 if (IS_ERR(skb_parser)) {
245250 bpf_prog_put(skb_verdict);
@@ -264,7 +269,8 @@ static int sock_map_link(struct bpf_map *map, struct sk_psock_progs *progs, · 18 unmodified lines
264269
265270 if (psock) {
266271 if ((msg_parser && READ_ONCE(psock->progs.msg_parser)) ||
267− (skb_progs && READ_ONCE(psock->progs.skb_parser))) {
272+ (skb_parser && READ_ONCE(psock->progs.skb_parser)) ||
273+ (skb_verdict && READ_ONCE(psock->progs.skb_verdict))) {
268274 sk_psock_put(sk, psock);
269275 ret = -EBUSY;
270276 goto out_progs;
@@ -285,28 +291,31 @@ static int sock_map_link(struct bpf_map *map, struct sk_psock_progs *progs, · 14 unmodified lines
285291 goto out_drop;
286292
287293 write_lock_bh(&sk->sk_callback_lock);
288− if (skb_progs && !psock->parser.enabled) {
294+ if (skb_parser && skb_verdict && !psock->parser.enabled) {
289295 ret = sk_psock_init_strp(sk, psock);
290− if (ret) {
291− write_unlock_bh(&sk->sk_callback_lock);
292− goto out_drop;
293− }
296+ if (ret)
297+ goto out_unlock_drop;
294298 psock_set_prog(&psock->progs.skb_verdict, skb_verdict);
295299 psock_set_prog(&psock->progs.skb_parser, skb_parser);
296300 sk_psock_start_strp(sk, psock);
301+ } else if (!skb_parser && skb_verdict && !psock->parser.enabled) {
302+ psock_set_prog(&psock->progs.skb_verdict, skb_verdict);
303+ sk_psock_start_verdict(sk,psock);
297304 }
298305 write_unlock_bh(&sk->sk_callback_lock);
299306 return 0;
307+out_unlock_drop:
308+ write_unlock_bh(&sk->sk_callback_lock);
300309 out_drop:
301310 sk_psock_put(sk, psock);
302311 out_progs:
303312 if (msg_parser)
304313 bpf_prog_put(msg_parser);
305314 out:
306− if (skb_progs) {
315+ if (skb_verdict)
307316 bpf_prog_put(skb_verdict);
317+ if (skb_parser)
308318 bpf_prog_put(skb_parser);
309− }
310319 return ret;
311320 }
312321
net/ipv4/tcp_minisocks.c+0−1
@@ -548,7 +548,6 @@ struct sock *tcp_create_openreq_child(const struct sock *sk, · 547 unmodified lines
548548 newtp->fastopen_req = NULL;
549549 RCU_INIT_POINTER(newtp->fastopen_rsk, NULL);
550550
551− bpf_skops_init_child(sk, newsk);
552551 tcp_bpf_clone(sk, newsk);
553552
554553 __TCP_INC_STATS(sock_net(sk), TCP_MIB_PASSIVEOPENS);
net/xdp/xsk_buff_pool.c+0−3
@@ -3,9 +3,6 @@ · 2 unmodified lines
33 #include <net/xsk_buff_pool.h>
44 #include <net/xdp_sock.h>
55 #include <net/xdp_sock_drv.h>
6−#include <linux/dma-direct.h>
7−#include <linux/dma-noncoherent.h>
8−#include <linux/swiotlb.h>
96
107 #include "xsk_queue.h"
118 #include "xdp_umem.h"
net/xdp/xsk_queue.h+4−0
@@ -15,6 +15,10 @@ · 14 unmodified lines
1515
1616 struct xdp_ring {
1717 u32 producer ____cacheline_aligned_in_smp;
18+ /* Hinder the adjacent cache prefetcher to prefetch the consumer
19+ * pointer if the producer pointer is touched and vice versa.
20+ */
21+ u32 pad ____cacheline_aligned_in_smp;
1822 u32 consumer ____cacheline_aligned_in_smp;
1923 u32 flags;
2024 };
net/xdp/xskmap.c+1−1
@@ -132,7 +132,7 @@ static int xsk_map_get_next_key(struct bpf_map *map, void *key, void *next_key) · 131 unmodified lines
132132 return 0;
133133 }
134134
135−static u32 xsk_map_gen_lookup(struct bpf_map *map, struct bpf_insn *insn_buf)
135+static int xsk_map_gen_lookup(struct bpf_map *map, struct bpf_insn *insn_buf)
136136 {
137137 const int ret = BPF_REG_0, mp = BPF_REG_1, index = BPF_REG_2;
138138 struct bpf_insn *insn = insn_buf;
samples/bpf/Makefile+12−3
@@ -98,8 +98,8 @@ test_map_in_map-objs := test_map_in_map_user.o · 97 unmodified lines
9898 per_socket_stats_example-objs := cookie_uid_helper_example.o
9999 xdp_redirect-objs := xdp_redirect_user.o
100100 xdp_redirect_map-objs := xdp_redirect_map_user.o
101−xdp_redirect_cpu-objs := bpf_load.o xdp_redirect_cpu_user.o
102−xdp_monitor-objs := bpf_load.o xdp_monitor_user.o
101+xdp_redirect_cpu-objs := xdp_redirect_cpu_user.o
102+xdp_monitor-objs := xdp_monitor_user.o
103103 xdp_rxq_info-objs := xdp_rxq_info_user.o
104104 syscall_tp-objs := syscall_tp_user.o
105105 cpustat-objs := cpustat_user.o
@@ -211,6 +211,8 @@ TPROGLDLIBS_xsk_fwd += -pthread · 105 unmodified lines
211211 # make M=samples/bpf/ LLC=~/git/llvm/build/bin/llc CLANG=~/git/llvm/build/bin/clang
212212 LLC ?= llc
213213 CLANG ?= clang
214+OPT ?= opt
215+LLVM_DIS ?= llvm-dis
214216 LLVM_OBJCOPY ?= llvm-objcopy
215217 BTF_PAHOLE ?= pahole
216218
@@ -303,6 +305,11 @@ $(obj)/hbm_edt_kern.o: $(src)/hbm.h $(src)/hbm_kern.h · 86 unmodified lines
303305 # asm/sysreg.h - inline assembly used by it is incompatible with llvm.
304306 # But, there is no easy way to fix it, so just exclude it since it is
305307 # useless for BPF samples.
308+# below we use long chain of commands, clang | opt | llvm-dis | llc,
309+# to generate final object file. 'clang' compiles the source into IR
310+# with native target, e.g., x64, arm64, etc. 'opt' does bpf CORE IR builtin
311+# processing (llvm12) and IR optimizations. 'llvm-dis' converts
312+# 'opt' output to IR, and finally 'llc' generates bpf byte code.
306313 $(obj)/%.o: $(src)/%.c
307314 @echo " CLANG-bpf " $@
308315 $(Q)$(CLANG) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) $(BPF_EXTRA_CFLAGS) \
@@ -314,7 +321,9 @@ $(obj)/%.o: $(src)/%.c · 5 unmodified lines
314321 -Wno-address-of-packed-member -Wno-tautological-compare \
315322 -Wno-unknown-warning-option $(CLANG_ARCH_ARGS) \
316323 -I$(srctree)/samples/bpf/ -include asm_goto_workaround.h \
317− -O2 -emit-llvm -c $< -o -| $(LLC) -march=bpf $(LLC_FLAGS) -filetype=obj -o $@
324+ -O2 -emit-llvm -Xclang -disable-llvm-passes -c $< -o - | \
325+ $(OPT) -O2 -mtriple=bpf-pc-linux | $(LLVM_DIS) | \
326+ $(LLC) -march=bpf $(LLC_FLAGS) -filetype=obj -o $@
318327 ifeq ($(DWARF2BTF),y)
319328 $(BTF_PAHOLE) -J $@
320329 endif
samples/bpf/hbm.c+2−1
@@ -40,6 +40,7 @@ · 39 unmodified lines
4040 #include <errno.h>
4141 #include <fcntl.h>
4242 #include <linux/unistd.h>
43+#include <linux/compiler.h>
4344
4445 #include <linux/bpf.h>
4546 #include <bpf/bpf.h>
@@ -483,7 +484,7 @@ int main(int argc, char **argv) · 437 unmodified lines
483484 "Option -%c requires an argument.\n\n",
484485 optopt);
485486 case 'h':
486− fallthrough;
487+ __fallthrough;
487488 default:
488489 Usage();
489490 return 0;
samples/bpf/xdp_monitor_kern.c+30−30
@@ -6,21 +6,21 @@ · 5 unmodified lines
66 #include <uapi/linux/bpf.h>
77 #include <bpf/bpf_helpers.h>
88
9−struct bpf_map_def SEC("maps") redirect_err_cnt = {
10− .type = BPF_MAP_TYPE_PERCPU_ARRAY,
11− .key_size = sizeof(u32),
12− .value_size = sizeof(u64),
13− .max_entries = 2,
9+struct {
10+ __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
11+ __type(key, u32);
12+ __type(value, u64);
13+ __uint(max_entries, 2);
1414 /* TODO: have entries for all possible errno's */
15−};
15+} redirect_err_cnt SEC(".maps");
1616
1717 #define XDP_UNKNOWN XDP_REDIRECT + 1
18−struct bpf_map_def SEC("maps") exception_cnt = {
19− .type = BPF_MAP_TYPE_PERCPU_ARRAY,
20− .key_size = sizeof(u32),
21− .value_size = sizeof(u64),
22− .max_entries = XDP_UNKNOWN + 1,
23−};
18+struct {
19+ __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
20+ __type(key, u32);
21+ __type(value, u64);
22+ __uint(max_entries, XDP_UNKNOWN + 1);
23+} exception_cnt SEC(".maps");
2424
2525 /* Tracepoint format: /sys/kernel/debug/tracing/events/xdp/xdp_redirect/format
2626 * Code in: kernel/include/trace/events/xdp.h
@@ -129,19 +129,19 @@ struct datarec { · 102 unmodified lines
129129 };
130130 #define MAX_CPUS 64
131131
132−struct bpf_map_def SEC("maps") cpumap_enqueue_cnt = {
133− .type = BPF_MAP_TYPE_PERCPU_ARRAY,
134− .key_size = sizeof(u32),
135− .value_size = sizeof(struct datarec),
136− .max_entries = MAX_CPUS,
137−};
132+struct {
133+ __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
134+ __type(key, u32);
135+ __type(value, struct datarec);
136+ __uint(max_entries, MAX_CPUS);
137+} cpumap_enqueue_cnt SEC(".maps");
138138
139−struct bpf_map_def SEC("maps") cpumap_kthread_cnt = {
140− .type = BPF_MAP_TYPE_PERCPU_ARRAY,
141− .key_size = sizeof(u32),
142− .value_size = sizeof(struct datarec),
143− .max_entries = 1,
144−};
139+struct {
140+ __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
141+ __type(key, u32);
142+ __type(value, struct datarec);
143+ __uint(max_entries, 1);
144+} cpumap_kthread_cnt SEC(".maps");
145145
146146 /* Tracepoint: /sys/kernel/debug/tracing/events/xdp/xdp_cpumap_enqueue/format
147147 * Code in: kernel/include/trace/events/xdp.h
@@ -210,12 +210,12 @@ int trace_xdp_cpumap_kthread(struct cpumap_kthread_ctx *ctx) · 62 unmodified lines
210210 return 0;
211211 }
212212
213−struct bpf_map_def SEC("maps") devmap_xmit_cnt = {
214− .type = BPF_MAP_TYPE_PERCPU_ARRAY,
215− .key_size = sizeof(u32),
216− .value_size = sizeof(struct datarec),
217− .max_entries = 1,
218−};
213+struct {
214+ __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
215+ __type(key, u32);
216+ __type(value, struct datarec);
217+ __uint(max_entries, 1);
218+} devmap_xmit_cnt SEC(".maps");
219219
220220 /* Tracepoint: /sys/kernel/debug/tracing/events/xdp/xdp_devmap_xmit/format
221221 * Code in: kernel/include/trace/events/xdp.h
samples/bpf/xdp_monitor_user.c+120−39
@@ -26,12 +26,37 @@ static const char *__doc_err_only__= · 25 unmodified lines
2626 #include <net/if.h>
2727 #include <time.h>
2828
29+#include <signal.h>
2930 #include <bpf/bpf.h>
30−#include "bpf_load.h"
31+#include <bpf/libbpf.h>
3132 #include "bpf_util.h"
3233
34+enum map_type {
35+ REDIRECT_ERR_CNT,
36+ EXCEPTION_CNT,
37+ CPUMAP_ENQUEUE_CNT,
38+ CPUMAP_KTHREAD_CNT,
39+ DEVMAP_XMIT_CNT,
40+};
41+
42+static const char *const map_type_strings[] = {
43+ [REDIRECT_ERR_CNT] = "redirect_err_cnt",
44+ [EXCEPTION_CNT] = "exception_cnt",
45+ [CPUMAP_ENQUEUE_CNT] = "cpumap_enqueue_cnt",
46+ [CPUMAP_KTHREAD_CNT] = "cpumap_kthread_cnt",
47+ [DEVMAP_XMIT_CNT] = "devmap_xmit_cnt",
48+};
49+
50+#define NUM_MAP 5
51+#define NUM_TP 8
52+
53+static int tp_cnt;
54+static int map_cnt;
3355 static int verbose = 1;
3456 static bool debug = false;
57+struct bpf_map *map_data[NUM_MAP] = {};
58+struct bpf_link *tp_links[NUM_TP] = {};
59+struct bpf_object *obj;
3560
3661 static const struct option long_options[] = {
3762 {"help", no_argument, NULL, 'h' },
@@ -41,6 +66,16 @@ static const struct option long_options[] = { · 3 unmodified lines
4166 {0, 0, NULL, 0 }
4267 };
4368
69+static void int_exit(int sig)
70+{
71+ /* Detach tracepoints */
72+ while (tp_cnt)
73+ bpf_link__destroy(tp_links[--tp_cnt]);
74+
75+ bpf_object__close(obj);
76+ exit(0);
77+}
78+
4479 /* C standard specifies two constants, EXIT_SUCCESS(0) and EXIT_FAILURE(1) */
4580 #define EXIT_FAIL_MEM 5
4681
@@ -483,23 +518,23 @@ static bool stats_collect(struct stats_record *rec) · 436 unmodified lines
483518 * this can happen by someone running perf-record -e
484519 */
485520
486− fd = map_data[0].fd; /* map0: redirect_err_cnt */
521+ fd = bpf_map__fd(map_data[REDIRECT_ERR_CNT]);
487522 for (i = 0; i < REDIR_RES_MAX; i++)
488523 map_collect_record_u64(fd, i, &rec->xdp_redirect[i]);
489524
490− fd = map_data[1].fd; /* map1: exception_cnt */
525+ fd = bpf_map__fd(map_data[EXCEPTION_CNT]);
491526 for (i = 0; i < XDP_ACTION_MAX; i++) {
492527 map_collect_record_u64(fd, i, &rec->xdp_exception[i]);
493528 }
494529
495− fd = map_data[2].fd; /* map2: cpumap_enqueue_cnt */
530+ fd = bpf_map__fd(map_data[CPUMAP_ENQUEUE_CNT]);
496531 for (i = 0; i < MAX_CPUS; i++)
497532 map_collect_record(fd, i, &rec->xdp_cpumap_enqueue[i]);
498533
499− fd = map_data[3].fd; /* map3: cpumap_kthread_cnt */
534+ fd = bpf_map__fd(map_data[CPUMAP_KTHREAD_CNT]);
500535 map_collect_record(fd, 0, &rec->xdp_cpumap_kthread);
501536
502− fd = map_data[4].fd; /* map4: devmap_xmit_cnt */
537+ fd = bpf_map__fd(map_data[DEVMAP_XMIT_CNT]);
503538 map_collect_record(fd, 0, &rec->xdp_devmap_xmit);
504539
505540 return true;
@@ -598,8 +633,8 @@ static void stats_poll(int interval, bool err_only) · 92 unmodified lines
598633
599634 /* TODO Need more advanced stats on error types */
600635 if (verbose) {
601− printf(" - Stats map0: %s\n", map_data[0].name);
602− printf(" - Stats map1: %s\n", map_data[1].name);
636+ printf(" - Stats map0: %s\n", bpf_map__name(map_data[0]));
637+ printf(" - Stats map1: %s\n", bpf_map__name(map_data[1]));
603638 printf("\n");
604639 }
605640 fflush(stdout);
@@ -618,44 +653,51 @@ static void stats_poll(int interval, bool err_only) · 12 unmodified lines
618653
619654 static void print_bpf_prog_info(void)
620655 {
621− int i;
656+ struct bpf_program *prog;
657+ struct bpf_map *map;
658+ int i = 0;
622659
623660 /* Prog info */
624− printf("Loaded BPF prog have %d bpf program(s)\n", prog_cnt);
625− for (i = 0; i < prog_cnt; i++) {
626− printf(" - prog_fd[%d] = fd(%d)\n", i, prog_fd[i]);
661+ printf("Loaded BPF prog have %d bpf program(s)\n", tp_cnt);
662+ bpf_object__for_each_program(prog, obj) {
663+ printf(" - prog_fd[%d] = fd(%d)\n", i, bpf_program__fd(prog));
664+ i++;
627665 }
628666
667+ i = 0;
629668 /* Maps info */
630− printf("Loaded BPF prog have %d map(s)\n", map_data_count);
631− for (i = 0; i < map_data_count; i++) {
632− char *name = map_data[i].name;
633− int fd = map_data[i].fd;
669+ printf("Loaded BPF prog have %d map(s)\n", map_cnt);
670+ bpf_object__for_each_map(map, obj) {
671+ const char *name = bpf_map__name(map);
672+ int fd = bpf_map__fd(map);
634673
635674 printf(" - map_data[%d] = fd(%d) name:%s\n", i, fd, name);
675+ i++;
636676 }
637677
638678 /* Event info */
639− printf("Searching for (max:%d) event file descriptor(s)\n", prog_cnt);
640− for (i = 0; i < prog_cnt; i++) {
641− if (event_fd[i] != -1)
642− printf(" - event_fd[%d] = fd(%d)\n", i, event_fd[i]);
679+ printf("Searching for (max:%d) event file descriptor(s)\n", tp_cnt);
680+ for (i = 0; i < tp_cnt; i++) {
681+ int fd = bpf_link__fd(tp_links[i]);
682+
683+ if (fd != -1)
684+ printf(" - event_fd[%d] = fd(%d)\n", i, fd);
643685 }
644686 }
645687
646688 int main(int argc, char **argv)
647689 {
648690 struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
691+ struct bpf_program *prog;
649692 int longindex = 0, opt;
650− int ret = EXIT_SUCCESS;
651− char bpf_obj_file[256];
693+ int ret = EXIT_FAILURE;
694+ enum map_type type;
695+ char filename[256];
652696
653697 /* Default settings: */
654698 bool errors_only = true;
655699 int interval = 2;
656700
657− snprintf(bpf_obj_file, sizeof(bpf_obj_file), "%s_kern.o", argv[0]);
658−
659701 /* Parse commands line args */
660702 while ((opt = getopt_long(argc, argv, "hDSs:",
661703 long_options, &longindex)) != -1) {
@@ -672,40 +714,79 @@ int main(int argc, char **argv) · 10 unmodified lines
672714 case 'h':
673715 default:
674716 usage(argv);
675− return EXIT_FAILURE;
717+ return ret;
676718 }
677719 }
678720
721+ snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
679722 if (setrlimit(RLIMIT_MEMLOCK, &r)) {
680723 perror("setrlimit(RLIMIT_MEMLOCK)");
681− return EXIT_FAILURE;
724+ return ret;
682725 }
683726
684− if (load_bpf_file(bpf_obj_file)) {
685− printf("ERROR - bpf_log_buf: %s", bpf_log_buf);
686− return EXIT_FAILURE;
727+ /* Remove tracepoint program when program is interrupted or killed */
728+ signal(SIGINT, int_exit);
729+ signal(SIGTERM, int_exit);
730+
731+ obj = bpf_object__open_file(filename, NULL);
732+ if (libbpf_get_error(obj)) {
733+ printf("ERROR: opening BPF object file failed\n");
734+ obj = NULL;
735+ goto cleanup;
736+ }
737+
738+ /* load BPF program */
739+ if (bpf_object__load(obj)) {
740+ printf("ERROR: loading BPF object file failed\n");
741+ goto cleanup;
742+ }
743+
744+ for (type = 0; type < NUM_MAP; type++) {
745+ map_data[type] =
746+ bpf_object__find_map_by_name(obj, map_type_strings[type]);
747+
748+ if (libbpf_get_error(map_data[type])) {
749+ printf("ERROR: finding a map in obj file failed\n");
750+ goto cleanup;
751+ }
752+ map_cnt++;
687753 }
688− if (!prog_fd[0]) {
689− printf("ERROR - load_bpf_file: %s\n", strerror(errno));
690− return EXIT_FAILURE;
754+
755+ bpf_object__for_each_program(prog, obj) {
756+ tp_links[tp_cnt] = bpf_program__attach(prog);
757+ if (libbpf_get_error(tp_links[tp_cnt])) {
758+ printf("ERROR: bpf_program__attach failed\n");
759+ tp_links[tp_cnt] = NULL;
760+ goto cleanup;
761+ }
762+ tp_cnt++;
691763 }
692764
693765 if (debug) {
694766 print_bpf_prog_info();
695767 }
696768
697− /* Unload/stop tracepoint event by closing fd's */
769+ /* Unload/stop tracepoint event by closing bpf_link's */
698770 if (errors_only) {
699− /* The prog_fd[i] and event_fd[i] depend on the
700− * order the functions was defined in _kern.c
771+ /* The bpf_link[i] depend on the order of
772+ * the functions was defined in _kern.c
701773 */
702− close(event_fd[2]); /* tracepoint/xdp/xdp_redirect */
703− close(prog_fd[2]); /* func: trace_xdp_redirect */
704− close(event_fd[3]); /* tracepoint/xdp/xdp_redirect_map */
705− close(prog_fd[3]); /* func: trace_xdp_redirect_map */
774+ bpf_link__destroy(tp_links[2]); /* tracepoint/xdp/xdp_redirect */
775+ tp_links[2] = NULL;
776+
777+ bpf_link__destroy(tp_links[3]); /* tracepoint/xdp/xdp_redirect_map */
778+ tp_links[3] = NULL;
706779 }
707780
708781 stats_poll(interval, errors_only);
709782
783+ ret = EXIT_SUCCESS;
784+
785+cleanup:
786+ /* Detach tracepoints */
787+ while (tp_cnt)
788+ bpf_link__destroy(tp_links[--tp_cnt]);
789+
790+ bpf_object__close(obj);
710791 return ret;
711792 }
samples/bpf/xdp_redirect_cpu_user.c+72−81
@@ -37,18 +37,35 @@ static __u32 prog_id; · 36 unmodified lines
3737
3838 static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
3939 static int n_cpus;
40−static int cpu_map_fd;
41−static int rx_cnt_map_fd;
42−static int redirect_err_cnt_map_fd;
43−static int cpumap_enqueue_cnt_map_fd;
44−static int cpumap_kthread_cnt_map_fd;
45−static int cpus_available_map_fd;
46−static int cpus_count_map_fd;
47−static int cpus_iterator_map_fd;
48−static int exception_cnt_map_fd;
40+
41+enum map_type {
42+ CPU_MAP,
43+ RX_CNT,
44+ REDIRECT_ERR_CNT,
45+ CPUMAP_ENQUEUE_CNT,
46+ CPUMAP_KTHREAD_CNT,
47+ CPUS_AVAILABLE,
48+ CPUS_COUNT,
49+ CPUS_ITERATOR,
50+ EXCEPTION_CNT,
51+};
52+
53+static const char *const map_type_strings[] = {
54+ [CPU_MAP] = "cpu_map",
55+ [RX_CNT] = "rx_cnt",
56+ [REDIRECT_ERR_CNT] = "redirect_err_cnt",
57+ [CPUMAP_ENQUEUE_CNT] = "cpumap_enqueue_cnt",
58+ [CPUMAP_KTHREAD_CNT] = "cpumap_kthread_cnt",
59+ [CPUS_AVAILABLE] = "cpus_available",
60+ [CPUS_COUNT] = "cpus_count",
61+ [CPUS_ITERATOR] = "cpus_iterator",
62+ [EXCEPTION_CNT] = "exception_cnt",
63+};
4964
5065 #define NUM_TP 5
51−struct bpf_link *tp_links[NUM_TP] = { 0 };
66+#define NUM_MAP 9
67+struct bpf_link *tp_links[NUM_TP] = {};
68+static int map_fds[NUM_MAP];
5269 static int tp_cnt = 0;
5370
5471 /* Exit return codes */
@@ -527,20 +544,20 @@ static void stats_collect(struct stats_record *rec) · 472 unmodified lines
527544 {
528545 int fd, i;
529546
530− fd = rx_cnt_map_fd;
547+ fd = map_fds[RX_CNT];
531548 map_collect_percpu(fd, 0, &rec->rx_cnt);
532549
533− fd = redirect_err_cnt_map_fd;
550+ fd = map_fds[REDIRECT_ERR_CNT];
534551 map_collect_percpu(fd, 1, &rec->redir_err);
535552
536− fd = cpumap_enqueue_cnt_map_fd;
553+ fd = map_fds[CPUMAP_ENQUEUE_CNT];
537554 for (i = 0; i < n_cpus; i++)
538555 map_collect_percpu(fd, i, &rec->enq[i]);
539556
540− fd = cpumap_kthread_cnt_map_fd;
557+ fd = map_fds[CPUMAP_KTHREAD_CNT];
541558 map_collect_percpu(fd, 0, &rec->kthread);
542559
543− fd = exception_cnt_map_fd;
560+ fd = map_fds[EXCEPTION_CNT];
544561 map_collect_percpu(fd, 0, &rec->exception);
545562 }
546563
@@ -565,7 +582,7 @@ static int create_cpu_entry(__u32 cpu, struct bpf_cpumap_val *value, · 18 unmodified lines
565582 /* Add a CPU entry to cpumap, as this allocate a cpu entry in
566583 * the kernel for the cpu.
567584 */
568− ret = bpf_map_update_elem(cpu_map_fd, &cpu, value, 0);
585+ ret = bpf_map_update_elem(map_fds[CPU_MAP], &cpu, value, 0);
569586 if (ret) {
570587 fprintf(stderr, "Create CPU entry failed (err:%d)\n", ret);
571588 exit(EXIT_FAIL_BPF);
@@ -574,21 +591,21 @@ static int create_cpu_entry(__u32 cpu, struct bpf_cpumap_val *value, · 2 unmodified lines
574591 /* Inform bpf_prog's that a new CPU is available to select
575592 * from via some control maps.
576593 */
577− ret = bpf_map_update_elem(cpus_available_map_fd, &avail_idx, &cpu, 0);
594+ ret = bpf_map_update_elem(map_fds[CPUS_AVAILABLE], &avail_idx, &cpu, 0);
578595 if (ret) {
579596 fprintf(stderr, "Add to avail CPUs failed\n");
580597 exit(EXIT_FAIL_BPF);
581598 }
582599
583600 /* When not replacing/updating existing entry, bump the count */
584− ret = bpf_map_lookup_elem(cpus_count_map_fd, &key, &curr_cpus_count);
601+ ret = bpf_map_lookup_elem(map_fds[CPUS_COUNT], &key, &curr_cpus_count);
585602 if (ret) {
586603 fprintf(stderr, "Failed reading curr cpus_count\n");
587604 exit(EXIT_FAIL_BPF);
588605 }
589606 if (new) {
590607 curr_cpus_count++;
591− ret = bpf_map_update_elem(cpus_count_map_fd, &key,
608+ ret = bpf_map_update_elem(map_fds[CPUS_COUNT], &key,
592609 &curr_cpus_count, 0);
593610 if (ret) {
594611 fprintf(stderr, "Failed write curr cpus_count\n");
@@ -612,7 +629,7 @@ static void mark_cpus_unavailable(void) · 17 unmodified lines
612629 int ret, i;
613630
614631 for (i = 0; i < n_cpus; i++) {
615− ret = bpf_map_update_elem(cpus_available_map_fd, &i,
632+ ret = bpf_map_update_elem(map_fds[CPUS_AVAILABLE], &i,
616633 &invalid_cpu, 0);
617634 if (ret) {
618635 fprintf(stderr, "Failed marking CPU unavailable\n");
@@ -665,68 +682,37 @@ static void stats_poll(int interval, bool use_separators, char *prog_name, · 46 unmodified lines
665682 free_stats_record(prev);
666683 }
667684
668−static struct bpf_link * attach_tp(struct bpf_object *obj,
669− const char *tp_category,
670− const char* tp_name)
685+static int init_tracepoints(struct bpf_object *obj)
671686 {
672687 struct bpf_program *prog;
673− struct bpf_link *link;
674− char sec_name[PATH_MAX];
675− int len;
676688
677− len = snprintf(sec_name, PATH_MAX, "tracepoint/%s/%s",
678− tp_category, tp_name);
679− if (len < 0)
680− exit(EXIT_FAIL);
689+ bpf_object__for_each_program(prog, obj) {
690+ if (bpf_program__is_tracepoint(prog) != true)
691+ continue;
681692
682− prog = bpf_object__find_program_by_title(obj, sec_name);
683− if (!prog) {
684− fprintf(stderr, "ERR: finding progsec: %s\n", sec_name);
685− exit(EXIT_FAIL_BPF);
693+ tp_links[tp_cnt] = bpf_program__attach(prog);
694+ if (libbpf_get_error(tp_links[tp_cnt])) {
695+ tp_links[tp_cnt] = NULL;
696+ return -EINVAL;
697+ }
698+ tp_cnt++;
686699 }
687700
688− link = bpf_program__attach_tracepoint(prog, tp_category, tp_name);
689− if (libbpf_get_error(link))
690− exit(EXIT_FAIL_BPF);
691−
692− return link;
693−}
694−
695−static void init_tracepoints(struct bpf_object *obj) {
696− tp_links[tp_cnt++] = attach_tp(obj, "xdp", "xdp_redirect_err");
697− tp_links[tp_cnt++] = attach_tp(obj, "xdp", "xdp_redirect_map_err");
698− tp_links[tp_cnt++] = attach_tp(obj, "xdp", "xdp_exception");
699− tp_links[tp_cnt++] = attach_tp(obj, "xdp", "xdp_cpumap_enqueue");
700− tp_links[tp_cnt++] = attach_tp(obj, "xdp", "xdp_cpumap_kthread");
701+ return 0;
701702 }
702703
703704 static int init_map_fds(struct bpf_object *obj)
704705 {
705− /* Maps updated by tracepoints */
706− redirect_err_cnt_map_fd =
707− bpf_object__find_map_fd_by_name(obj, "redirect_err_cnt");
708− exception_cnt_map_fd =
709− bpf_object__find_map_fd_by_name(obj, "exception_cnt");
710− cpumap_enqueue_cnt_map_fd =
711− bpf_object__find_map_fd_by_name(obj, "cpumap_enqueue_cnt");
712− cpumap_kthread_cnt_map_fd =
713− bpf_object__find_map_fd_by_name(obj, "cpumap_kthread_cnt");
714−
715− /* Maps used by XDP */
716− rx_cnt_map_fd = bpf_object__find_map_fd_by_name(obj, "rx_cnt");
717− cpu_map_fd = bpf_object__find_map_fd_by_name(obj, "cpu_map");
718− cpus_available_map_fd =
719− bpf_object__find_map_fd_by_name(obj, "cpus_available");
720− cpus_count_map_fd = bpf_object__find_map_fd_by_name(obj, "cpus_count");
721− cpus_iterator_map_fd =
722− bpf_object__find_map_fd_by_name(obj, "cpus_iterator");
723−
724− if (cpu_map_fd < 0 || rx_cnt_map_fd < 0 ||
725− redirect_err_cnt_map_fd < 0 || cpumap_enqueue_cnt_map_fd < 0 ||
726− cpumap_kthread_cnt_map_fd < 0 || cpus_available_map_fd < 0 ||
727− cpus_count_map_fd < 0 || cpus_iterator_map_fd < 0 ||
728− exception_cnt_map_fd < 0)
729− return -ENOENT;
706+ enum map_type type;
707+
708+ for (type = 0; type < NUM_MAP; type++) {
709+ map_fds[type] =
710+ bpf_object__find_map_fd_by_name(obj,
711+ map_type_strings[type]);
712+
713+ if (map_fds[type] < 0)
714+ return -ENOENT;
715+ }
730716
731717 return 0;
732718 }
@@ -795,13 +781,13 @@ int main(int argc, char **argv) · 62 unmodified lines
795781 bool stress_mode = false;
796782 struct bpf_program *prog;
797783 struct bpf_object *obj;
784+ int err = EXIT_FAIL;
798785 char filename[256];
799786 int added_cpus = 0;
800787 int longindex = 0;
801788 int interval = 2;
802789 int add_cpu = -1;
803− int opt, err;
804− int prog_fd;
790+ int opt, prog_fd;
805791 int *cpu, i;
806792 __u32 qsize;
807793
@@ -824,24 +810,29 @@ int main(int argc, char **argv) · 16 unmodified lines
824810 }
825811
826812 if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd))
827− return EXIT_FAIL;
813+ return err;
828814
829815 if (prog_fd < 0) {
830816 fprintf(stderr, "ERR: bpf_prog_load_xattr: %s\n",
831817 strerror(errno));
832− return EXIT_FAIL;
818+ return err;
833819 }
834− init_tracepoints(obj);
820+
821+ if (init_tracepoints(obj) < 0) {
822+ fprintf(stderr, "ERR: bpf_program__attach failed\n");
823+ return err;
824+ }
825+
835826 if (init_map_fds(obj) < 0) {
836827 fprintf(stderr, "bpf_object__find_map_fd_by_name failed\n");
837− return EXIT_FAIL;
828+ return err;
838829 }
839830 mark_cpus_unavailable();
840831
841832 cpu = malloc(n_cpus * sizeof(int));
842833 if (!cpu) {
843834 fprintf(stderr, "failed to allocate cpu array\n");
844− return EXIT_FAIL;
835+ return err;
845836 }
846837 memset(cpu, 0, n_cpus * sizeof(int));
847838
@@ -960,14 +951,12 @@ int main(int argc, char **argv) · 112 unmodified lines
960951 prog = bpf_object__find_program_by_title(obj, prog_name);
961952 if (!prog) {
962953 fprintf(stderr, "bpf_object__find_program_by_title failed\n");
963− err = EXIT_FAIL;
964954 goto out;
965955 }
966956
967957 prog_fd = bpf_program__fd(prog);
968958 if (prog_fd < 0) {
969959 fprintf(stderr, "bpf_program__fd failed\n");
970− err = EXIT_FAIL;
971960 goto out;
972961 }
973962
@@ -986,6 +975,8 @@ int main(int argc, char **argv) · 12 unmodified lines
986975
987976 stats_poll(interval, use_separators, prog_name, mprog_name,
988977 &value, stress_mode);
978+
979+ err = EXIT_OK;
989980 out:
990981 free(cpu);
991982 return err;
samples/bpf/xdp_sample_pkts_kern.c+6−8
@@ -5,14 +5,12 @@ · 4 unmodified lines
55 #include <bpf/bpf_helpers.h>
66
77 #define SAMPLE_SIZE 64ul
8−#define MAX_CPUS 128
9−
10−struct bpf_map_def SEC("maps") my_map = {
11− .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
12− .key_size = sizeof(int),
13− .value_size = sizeof(u32),
14− .max_entries = MAX_CPUS,
15−};
8+
9+struct {
10+ __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
11+ __uint(key_size, sizeof(int));
12+ __uint(value_size, sizeof(u32));
13+} my_map SEC(".maps");
1614
1715 SEC("xdp_sample")
1816 int xdp_sample_prog(struct xdp_md *ctx)
samples/bpf/xdp_sample_pkts_user.c+0−1
@@ -18,7 +18,6 @@ · 17 unmodified lines
1818
1919 #include "perf-sys.h"
2020
21−#define MAX_CPUS 128
2221 static int if_idx;
2322 static char *if_name;
2423 static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
samples/bpf/xdpsock_user.c+290−64
@@ -11,6 +11,7 @@ · 10 unmodified lines
1111 #include <linux/if_xdp.h>
1212 #include <linux/if_ether.h>
1313 #include <linux/ip.h>
14+#include <linux/limits.h>
1415 #include <linux/udp.h>
1516 #include <arpa/inet.h>
1617 #include <locale.h>
@@ -79,6 +80,10 @@ static u16 opt_pkt_size = MIN_PKT_SIZE; · 62 unmodified lines
7980 static u32 opt_pkt_fill_pattern = 0x12345678;
8081 static bool opt_extra_stats;
8182 static bool opt_quiet;
83+static bool opt_app_stats;
84+static const char *opt_irq_str = "";
85+static u32 irq_no;
86+static int irqs_at_init = -1;
8287 static int opt_poll;
8388 static int opt_interval = 1;
8489 static u32 opt_xdp_bind_flags = XDP_USE_NEED_WAKEUP;
@@ -91,18 +96,7 @@ static bool opt_need_wakeup = true; · 6 unmodified lines
9196 static u32 opt_num_xsks = 1;
9297 static u32 prog_id;
9398
94−struct xsk_umem_info {
95− struct xsk_ring_prod fq;
96− struct xsk_ring_cons cq;
97− struct xsk_umem *umem;
98− void *buffer;
99−};
100−
101−struct xsk_socket_info {
102− struct xsk_ring_cons rx;
103− struct xsk_ring_prod tx;
104− struct xsk_umem_info *umem;
105− struct xsk_socket *xsk;
99+struct xsk_ring_stats {
106100 unsigned long rx_npkts;
107101 unsigned long tx_npkts;
108102 unsigned long rx_dropped_npkts;
@@ -119,6 +113,41 @@ struct xsk_socket_info { · 10 unmodified lines
119113 unsigned long prev_rx_full_npkts;
120114 unsigned long prev_rx_fill_empty_npkts;
121115 unsigned long prev_tx_empty_npkts;
116+};
117+
118+struct xsk_driver_stats {
119+ unsigned long intrs;
120+ unsigned long prev_intrs;
121+};
122+
123+struct xsk_app_stats {
124+ unsigned long rx_empty_polls;
125+ unsigned long fill_fail_polls;
126+ unsigned long copy_tx_sendtos;
127+ unsigned long tx_wakeup_sendtos;
128+ unsigned long opt_polls;
129+ unsigned long prev_rx_empty_polls;
130+ unsigned long prev_fill_fail_polls;
131+ unsigned long prev_copy_tx_sendtos;
132+ unsigned long prev_tx_wakeup_sendtos;
133+ unsigned long prev_opt_polls;
134+};
135+
136+struct xsk_umem_info {
137+ struct xsk_ring_prod fq;
138+ struct xsk_ring_cons cq;
139+ struct xsk_umem *umem;
140+ void *buffer;
141+};
142+
143+struct xsk_socket_info {
144+ struct xsk_ring_cons rx;
145+ struct xsk_ring_prod tx;
146+ struct xsk_umem_info *umem;
147+ struct xsk_socket *xsk;
148+ struct xsk_ring_stats ring_stats;
149+ struct xsk_app_stats app_stats;
150+ struct xsk_driver_stats drv_stats;
122151 u32 outstanding_tx;
123152 };
124153
@@ -173,18 +202,151 @@ static int xsk_get_xdp_stats(int fd, struct xsk_socket_info *xsk) · 48 unmodified lines
173202 return err;
174203
175204 if (optlen == sizeof(struct xdp_statistics)) {
176− xsk->rx_dropped_npkts = stats.rx_dropped;
177− xsk->rx_invalid_npkts = stats.rx_invalid_descs;
178− xsk->tx_invalid_npkts = stats.tx_invalid_descs;
179− xsk->rx_full_npkts = stats.rx_ring_full;
180− xsk->rx_fill_empty_npkts = stats.rx_fill_ring_empty_descs;
181− xsk->tx_empty_npkts = stats.tx_ring_empty_descs;
205+ xsk->ring_stats.rx_dropped_npkts = stats.rx_dropped;
206+ xsk->ring_stats.rx_invalid_npkts = stats.rx_invalid_descs;
207+ xsk->ring_stats.tx_invalid_npkts = stats.tx_invalid_descs;
208+ xsk->ring_stats.rx_full_npkts = stats.rx_ring_full;
209+ xsk->ring_stats.rx_fill_empty_npkts = stats.rx_fill_ring_empty_descs;
210+ xsk->ring_stats.tx_empty_npkts = stats.tx_ring_empty_descs;
182211 return 0;
183212 }
184213
185214 return -EINVAL;
186215 }
187216
217+static void dump_app_stats(long dt)
218+{
219+ int i;
220+
221+ for (i = 0; i < num_socks && xsks[i]; i++) {
222+ char *fmt = "%-18s %'-14.0f %'-14lu\n";
223+ double rx_empty_polls_ps, fill_fail_polls_ps, copy_tx_sendtos_ps,
224+ tx_wakeup_sendtos_ps, opt_polls_ps;
225+
226+ rx_empty_polls_ps = (xsks[i]->app_stats.rx_empty_polls -
227+ xsks[i]->app_stats.prev_rx_empty_polls) * 1000000000. / dt;
228+ fill_fail_polls_ps = (xsks[i]->app_stats.fill_fail_polls -
229+ xsks[i]->app_stats.prev_fill_fail_polls) * 1000000000. / dt;
230+ copy_tx_sendtos_ps = (xsks[i]->app_stats.copy_tx_sendtos -
231+ xsks[i]->app_stats.prev_copy_tx_sendtos) * 1000000000. / dt;
232+ tx_wakeup_sendtos_ps = (xsks[i]->app_stats.tx_wakeup_sendtos -
233+ xsks[i]->app_stats.prev_tx_wakeup_sendtos)
234+ * 1000000000. / dt;
235+ opt_polls_ps = (xsks[i]->app_stats.opt_polls -
236+ xsks[i]->app_stats.prev_opt_polls) * 1000000000. / dt;
237+
238+ printf("\n%-18s %-14s %-14s\n", "", "calls/s", "count");
239+ printf(fmt, "rx empty polls", rx_empty_polls_ps, xsks[i]->app_stats.rx_empty_polls);
240+ printf(fmt, "fill fail polls", fill_fail_polls_ps,
241+ xsks[i]->app_stats.fill_fail_polls);
242+ printf(fmt, "copy tx sendtos", copy_tx_sendtos_ps,
243+ xsks[i]->app_stats.copy_tx_sendtos);
244+ printf(fmt, "tx wakeup sendtos", tx_wakeup_sendtos_ps,
245+ xsks[i]->app_stats.tx_wakeup_sendtos);
246+ printf(fmt, "opt polls", opt_polls_ps, xsks[i]->app_stats.opt_polls);
247+
248+ xsks[i]->app_stats.prev_rx_empty_polls = xsks[i]->app_stats.rx_empty_polls;
249+ xsks[i]->app_stats.prev_fill_fail_polls = xsks[i]->app_stats.fill_fail_polls;
250+ xsks[i]->app_stats.prev_copy_tx_sendtos = xsks[i]->app_stats.copy_tx_sendtos;
251+ xsks[i]->app_stats.prev_tx_wakeup_sendtos = xsks[i]->app_stats.tx_wakeup_sendtos;
252+ xsks[i]->app_stats.prev_opt_polls = xsks[i]->app_stats.opt_polls;
253+ }
254+}
255+
256+static bool get_interrupt_number(void)
257+{
258+ FILE *f_int_proc;
259+ char line[4096];
260+ bool found = false;
261+
262+ f_int_proc = fopen("/proc/interrupts", "r");
263+ if (f_int_proc == NULL) {
264+ printf("Failed to open /proc/interrupts.\n");
265+ return found;
266+ }
267+
268+ while (!feof(f_int_proc) && !found) {
269+ /* Make sure to read a full line at a time */
270+ if (fgets(line, sizeof(line), f_int_proc) == NULL ||
271+ line[strlen(line) - 1] != '\n') {
272+ printf("Error reading from interrupts file\n");
273+ break;
274+ }
275+
276+ /* Extract interrupt number from line */
277+ if (strstr(line, opt_irq_str) != NULL) {
278+ irq_no = atoi(line);
279+ found = true;
280+ break;
281+ }
282+ }
283+
284+ fclose(f_int_proc);
285+
286+ return found;
287+}
288+
289+static int get_irqs(void)
290+{
291+ char count_path[PATH_MAX];
292+ int total_intrs = -1;
293+ FILE *f_count_proc;
294+ char line[4096];
295+
296+ snprintf(count_path, sizeof(count_path),
297+ "/sys/kernel/irq/%i/per_cpu_count", irq_no);
298+ f_count_proc = fopen(count_path, "r");
299+ if (f_count_proc == NULL) {
300+ printf("Failed to open %s\n", count_path);
301+ return total_intrs;
302+ }
303+
304+ if (fgets(line, sizeof(line), f_count_proc) == NULL ||
305+ line[strlen(line) - 1] != '\n') {
306+ printf("Error reading from %s\n", count_path);
307+ } else {
308+ static const char com[2] = ",";
309+ char *token;
310+
311+ total_intrs = 0;
312+ token = strtok(line, com);
313+ while (token != NULL) {
314+ /* sum up interrupts across all cores */
315+ total_intrs += atoi(token);
316+ token = strtok(NULL, com);
317+ }
318+ }
319+
320+ fclose(f_count_proc);
321+
322+ return total_intrs;
323+}
324+
325+static void dump_driver_stats(long dt)
326+{
327+ int i;
328+
329+ for (i = 0; i < num_socks && xsks[i]; i++) {
330+ char *fmt = "%-18s %'-14.0f %'-14lu\n";
331+ double intrs_ps;
332+ int n_ints = get_irqs();
333+
334+ if (n_ints < 0) {
335+ printf("error getting intr info for intr %i\n", irq_no);
336+ return;
337+ }
338+ xsks[i]->drv_stats.intrs = n_ints - irqs_at_init;
339+
340+ intrs_ps = (xsks[i]->drv_stats.intrs - xsks[i]->drv_stats.prev_intrs) *
341+ 1000000000. / dt;
342+
343+ printf("\n%-18s %-14s %-14s\n", "", "intrs/s", "count");
344+ printf(fmt, "irqs", intrs_ps, xsks[i]->drv_stats.intrs);
345+
346+ xsks[i]->drv_stats.prev_intrs = xsks[i]->drv_stats.intrs;
347+ }
348+}
349+
188350 static void dump_stats(void)
189351 {
190352 unsigned long now = get_nsecs();
@@ -194,67 +356,83 @@ static void dump_stats(void) · 3 unmodified lines
194356 prev_time = now;
195357
196358 for (i = 0; i < num_socks && xsks[i]; i++) {
197− char *fmt = "%-15s %'-11.0f %'-11lu\n";
359+ char *fmt = "%-18s %'-14.0f %'-14lu\n";
198360 double rx_pps, tx_pps, dropped_pps, rx_invalid_pps, full_pps, fill_empty_pps,
199361 tx_invalid_pps, tx_empty_pps;
200362
201− rx_pps = (xsks[i]->rx_npkts - xsks[i]->prev_rx_npkts) *
363+ rx_pps = (xsks[i]->ring_stats.rx_npkts - xsks[i]->ring_stats.prev_rx_npkts) *
202364 1000000000. / dt;
203− tx_pps = (xsks[i]->tx_npkts - xsks[i]->prev_tx_npkts) *
365+ tx_pps = (xsks[i]->ring_stats.tx_npkts - xsks[i]->ring_stats.prev_tx_npkts) *
204366 1000000000. / dt;
205367
206368 printf("\n sock%d@", i);
207369 print_benchmark(false);
208370 printf("\n");
209371
210− printf("%-15s %-11s %-11s %-11.2f\n", "", "pps", "pkts",
372+ printf("%-18s %-14s %-14s %-14.2f\n", "", "pps", "pkts",
211373 dt / 1000000000.);
212− printf(fmt, "rx", rx_pps, xsks[i]->rx_npkts);
213− printf(fmt, "tx", tx_pps, xsks[i]->tx_npkts);
374+ printf(fmt, "rx", rx_pps, xsks[i]->ring_stats.rx_npkts);
375+ printf(fmt, "tx", tx_pps, xsks[i]->ring_stats.tx_npkts);
214376
215− xsks[i]->prev_rx_npkts = xsks[i]->rx_npkts;
216− xsks[i]->prev_tx_npkts = xsks[i]->tx_npkts;
377+ xsks[i]->ring_stats.prev_rx_npkts = xsks[i]->ring_stats.rx_npkts;
378+ xsks[i]->ring_stats.prev_tx_npkts = xsks[i]->ring_stats.tx_npkts;
217379
218380 if (opt_extra_stats) {
219381 if (!xsk_get_xdp_stats(xsk_socket__fd(xsks[i]->xsk), xsks[i])) {
220− dropped_pps = (xsks[i]->rx_dropped_npkts -
221− xsks[i]->prev_rx_dropped_npkts) * 1000000000. / dt;
222− rx_invalid_pps = (xsks[i]->rx_invalid_npkts -
223− xsks[i]->prev_rx_invalid_npkts) * 1000000000. / dt;
224− tx_invalid_pps = (xsks[i]->tx_invalid_npkts -
225− xsks[i]->prev_tx_invalid_npkts) * 1000000000. / dt;
226− full_pps = (xsks[i]->rx_full_npkts -
227− xsks[i]->prev_rx_full_npkts) * 1000000000. / dt;
228− fill_empty_pps = (xsks[i]->rx_fill_empty_npkts -
229− xsks[i]->prev_rx_fill_empty_npkts)
230− * 1000000000. / dt;
231− tx_empty_pps = (xsks[i]->tx_empty_npkts -
232− xsks[i]->prev_tx_empty_npkts) * 1000000000. / dt;
382+ dropped_pps = (xsks[i]->ring_stats.rx_dropped_npkts -
383+ xsks[i]->ring_stats.prev_rx_dropped_npkts) *
384+ 1000000000. / dt;
385+ rx_invalid_pps = (xsks[i]->ring_stats.rx_invalid_npkts -
386+ xsks[i]->ring_stats.prev_rx_invalid_npkts) *
387+ 1000000000. / dt;
388+ tx_invalid_pps = (xsks[i]->ring_stats.tx_invalid_npkts -
389+ xsks[i]->ring_stats.prev_tx_invalid_npkts) *
390+ 1000000000. / dt;
391+ full_pps = (xsks[i]->ring_stats.rx_full_npkts -
392+ xsks[i]->ring_stats.prev_rx_full_npkts) *
393+ 1000000000. / dt;
394+ fill_empty_pps = (xsks[i]->ring_stats.rx_fill_empty_npkts -
395+ xsks[i]->ring_stats.prev_rx_fill_empty_npkts) *
396+ 1000000000. / dt;
397+ tx_empty_pps = (xsks[i]->ring_stats.tx_empty_npkts -
398+ xsks[i]->ring_stats.prev_tx_empty_npkts) *
399+ 1000000000. / dt;
233400
234401 printf(fmt, "rx dropped", dropped_pps,
235− xsks[i]->rx_dropped_npkts);
402+ xsks[i]->ring_stats.rx_dropped_npkts);
236403 printf(fmt, "rx invalid", rx_invalid_pps,
237− xsks[i]->rx_invalid_npkts);
404+ xsks[i]->ring_stats.rx_invalid_npkts);
238405 printf(fmt, "tx invalid", tx_invalid_pps,
239− xsks[i]->tx_invalid_npkts);
406+ xsks[i]->ring_stats.tx_invalid_npkts);
240407 printf(fmt, "rx queue full", full_pps,
241− xsks[i]->rx_full_npkts);
408+ xsks[i]->ring_stats.rx_full_npkts);
242409 printf(fmt, "fill ring empty", fill_empty_pps,
243− xsks[i]->rx_fill_empty_npkts);
410+ xsks[i]->ring_stats.rx_fill_empty_npkts);
244411 printf(fmt, "tx ring empty", tx_empty_pps,
245− xsks[i]->tx_empty_npkts);
246−
247− xsks[i]->prev_rx_dropped_npkts = xsks[i]->rx_dropped_npkts;
248− xsks[i]->prev_rx_invalid_npkts = xsks[i]->rx_invalid_npkts;
249− xsks[i]->prev_tx_invalid_npkts = xsks[i]->tx_invalid_npkts;
250− xsks[i]->prev_rx_full_npkts = xsks[i]->rx_full_npkts;
251− xsks[i]->prev_rx_fill_empty_npkts = xsks[i]->rx_fill_empty_npkts;
252− xsks[i]->prev_tx_empty_npkts = xsks[i]->tx_empty_npkts;
412+ xsks[i]->ring_stats.tx_empty_npkts);
413+
414+ xsks[i]->ring_stats.prev_rx_dropped_npkts =
415+ xsks[i]->ring_stats.rx_dropped_npkts;
416+ xsks[i]->ring_stats.prev_rx_invalid_npkts =
417+ xsks[i]->ring_stats.rx_invalid_npkts;
418+ xsks[i]->ring_stats.prev_tx_invalid_npkts =
419+ xsks[i]->ring_stats.tx_invalid_npkts;
420+ xsks[i]->ring_stats.prev_rx_full_npkts =
421+ xsks[i]->ring_stats.rx_full_npkts;
422+ xsks[i]->ring_stats.prev_rx_fill_empty_npkts =
423+ xsks[i]->ring_stats.rx_fill_empty_npkts;
424+ xsks[i]->ring_stats.prev_tx_empty_npkts =
425+ xsks[i]->ring_stats.tx_empty_npkts;
253426 } else {
254427 printf("%-15s\n", "Error retrieving extra stats");
255428 }
256429 }
257430 }
431+
432+ if (opt_app_stats)
433+ dump_app_stats(dt);
434+ if (irq_no)
435+ dump_driver_stats(dt);
258436 }
259437
260438 static bool is_benchmark_done(void)
@@ -693,6 +871,17 @@ static struct xsk_socket_info *xsk_configure_socket(struct xsk_umem_info *umem, · 432 unmodified lines
693871 if (ret)
694872 exit_with_error(-ret);
695873
874+ xsk->app_stats.rx_empty_polls = 0;
875+ xsk->app_stats.fill_fail_polls = 0;
876+ xsk->app_stats.copy_tx_sendtos = 0;
877+ xsk->app_stats.tx_wakeup_sendtos = 0;
878+ xsk->app_stats.opt_polls = 0;
879+ xsk->app_stats.prev_rx_empty_polls = 0;
880+ xsk->app_stats.prev_fill_fail_polls = 0;
881+ xsk->app_stats.prev_copy_tx_sendtos = 0;
882+ xsk->app_stats.prev_tx_wakeup_sendtos = 0;
883+ xsk->app_stats.prev_opt_polls = 0;
884+
696885 return xsk;
697886 }
698887
@@ -720,6 +909,8 @@ static struct option long_options[] = { · 21 unmodified lines
720909 {"tx-pkt-pattern", required_argument, 0, 'P'},
721910 {"extra-stats", no_argument, 0, 'x'},
722911 {"quiet", no_argument, 0, 'Q'},
912+ {"app-stats", no_argument, 0, 'a'},
913+ {"irq-string", no_argument, 0, 'I'},
723914 {0, 0, 0, 0}
724915 };
725916
@@ -756,6 +947,8 @@ static void usage(const char *prog) · 30 unmodified lines
756947 " -P, --tx-pkt-pattern=nPacket fill pattern. Default: 0x%x\n"
757948 " -x, --extra-stats Display extra statistics.\n"
758949 " -Q, --quiet Do not display any stats.\n"
950+ " -a, --app-stats Display application (syscall) statistics.\n"
951+ " -I, --irq-string Display driver interrupt statistics for interface associated with irq-string.\n"
759952 "\n";
760953 fprintf(stderr, str, prog, XSK_UMEM__DEFAULT_FRAME_SIZE,
761954 opt_batch_size, MIN_PKT_SIZE, MIN_PKT_SIZE,
@@ -771,7 +964,7 @@ static void parse_command_line(int argc, char **argv) · 9 unmodified lines
771964 opterr = 0;
772965
773966 for (;;) {
774− c = getopt_long(argc, argv, "Frtli:q:pSNn:czf:muMd:b:C:s:P:xQ",
967+ c = getopt_long(argc, argv, "Frtli:q:pSNn:czf:muMd:b:C:s:P:xQaI:",
775968 long_options, &option_index);
776969 if (c == -1)
777970 break;
@@ -857,6 +1050,19 @@ static void parse_command_line(int argc, char **argv) · 79 unmodified lines
8571050 break;
8581051 case 'Q':
8591052 opt_quiet = 1;
1053+ break;
1054+ case 'a':
1055+ opt_app_stats = 1;
1056+ break;
1057+ case 'I':
1058+ opt_irq_str = optarg;
1059+ if (get_interrupt_number())
1060+ irqs_at_init = get_irqs();
1061+ if (irqs_at_init < 0) {
1062+ fprintf(stderr, "ERROR: Failed to get irqs for %s\n", opt_irq_str);
1063+ usage(basename(argv[0]));
1064+ }
1065+
8601066 break;
8611067 default:
8621068 usage(basename(argv[0]));
@@ -908,8 +1114,10 @@ static inline void complete_tx_l2fwd(struct xsk_socket_info *xsk, · 45 unmodified lines
9081114 * is driven by the NAPI loop. So as an optimization, we do not have to call
9091115 * sendto() all the time in zero-copy mode for l2fwd.
9101116 */
911− if (opt_xdp_bind_flags & XDP_COPY)
1117+ if (opt_xdp_bind_flags & XDP_COPY) {
1118+ xsk->app_stats.copy_tx_sendtos++;
9121119 kick_tx(xsk);
1120+ }
9131121
9141122 ndescs = (xsk->outstanding_tx > opt_batch_size) ? opt_batch_size :
9151123 xsk->outstanding_tx;
@@ -924,8 +1132,10 @@ static inline void complete_tx_l2fwd(struct xsk_socket_info *xsk, · 8 unmodified lines
9241132 while (ret != rcvd) {
9251133 if (ret < 0)
9261134 exit_with_error(-ret);
927− if (xsk_ring_prod__needs_wakeup(&umem->fq))
1135+ if (xsk_ring_prod__needs_wakeup(&umem->fq)) {
1136+ xsk->app_stats.fill_fail_polls++;
9281137 ret = poll(fds, num_socks, opt_timeout);
1138+ }
9291139 ret = xsk_ring_prod__reserve(&umem->fq, rcvd, &idx_fq);
9301140 }
9311141
@@ -936,7 +1146,7 @@ static inline void complete_tx_l2fwd(struct xsk_socket_info *xsk, · 4 unmodified lines
9361146 xsk_ring_prod__submit(&xsk->umem->fq, rcvd);
9371147 xsk_ring_cons__release(&xsk->umem->cq, rcvd);
9381148 xsk->outstanding_tx -= rcvd;
939− xsk->tx_npkts += rcvd;
1149+ xsk->ring_stats.tx_npkts += rcvd;
9401150 }
9411151 }
9421152
@@ -949,14 +1159,16 @@ static inline void complete_tx_only(struct xsk_socket_info *xsk, · 6 unmodified lines
9491159 if (!xsk->outstanding_tx)
9501160 return;
9511161
952− if (!opt_need_wakeup || xsk_ring_prod__needs_wakeup(&xsk->tx))
1162+ if (!opt_need_wakeup || xsk_ring_prod__needs_wakeup(&xsk->tx)) {
1163+ xsk->app_stats.tx_wakeup_sendtos++;
9531164 kick_tx(xsk);
1165+ }
9541166
9551167 rcvd = xsk_ring_cons__peek(&xsk->umem->cq, batch_size, &idx);
9561168 if (rcvd > 0) {
9571169 xsk_ring_cons__release(&xsk->umem->cq, rcvd);
9581170 xsk->outstanding_tx -= rcvd;
959− xsk->tx_npkts += rcvd;
1171+ xsk->ring_stats.tx_npkts += rcvd;
9601172 }
9611173 }
9621174
@@ -968,8 +1180,10 @@ static void rx_drop(struct xsk_socket_info *xsk, struct pollfd *fds) · 5 unmodified lines
9681180
9691181 rcvd = xsk_ring_cons__peek(&xsk->rx, opt_batch_size, &idx_rx);
9701182 if (!rcvd) {
971− if (xsk_ring_prod__needs_wakeup(&xsk->umem->fq))
1183+ if (xsk_ring_prod__needs_wakeup(&xsk->umem->fq)) {
1184+ xsk->app_stats.rx_empty_polls++;
9721185 ret = poll(fds, num_socks, opt_timeout);
1186+ }
9731187 return;
9741188 }
9751189
@@ -977,8 +1191,10 @@ static void rx_drop(struct xsk_socket_info *xsk, struct pollfd *fds) · 1 unmodified line
9771191 while (ret != rcvd) {
9781192 if (ret < 0)
9791193 exit_with_error(-ret);
980− if (xsk_ring_prod__needs_wakeup(&xsk->umem->fq))
1194+ if (xsk_ring_prod__needs_wakeup(&xsk->umem->fq)) {
1195+ xsk->app_stats.fill_fail_polls++;
9811196 ret = poll(fds, num_socks, opt_timeout);
1197+ }
9821198 ret = xsk_ring_prod__reserve(&xsk->umem->fq, rcvd, &idx_fq);
9831199 }
9841200
@@ -996,7 +1212,7 @@ static void rx_drop(struct xsk_socket_info *xsk, struct pollfd *fds) · 11 unmodified lines
9961212
9971213 xsk_ring_prod__submit(&xsk->umem->fq, rcvd);
9981214 xsk_ring_cons__release(&xsk->rx, rcvd);
999− xsk->rx_npkts += rcvd;
1215+ xsk->ring_stats.rx_npkts += rcvd;
10001216 }
10011217
10021218 static void rx_drop_all(void)
@@ -1011,6 +1227,8 @@ static void rx_drop_all(void) · 8 unmodified lines
10111227
10121228 for (;;) {
10131229 if (opt_poll) {
1230+ for (i = 0; i < num_socks; i++)
1231+ xsks[i]->app_stats.opt_polls++;
10141232 ret = poll(fds, num_socks, opt_timeout);
10151233 if (ret <= 0)
10161234 continue;
@@ -1091,6 +1309,8 @@ static void tx_only_all(void) · 74 unmodified lines
10911309 int batch_size = get_batch_size(pkt_cnt);
10921310
10931311 if (opt_poll) {
1312+ for (i = 0; i < num_socks; i++)
1313+ xsks[i]->app_stats.opt_polls++;
10941314 ret = poll(fds, num_socks, opt_timeout);
10951315 if (ret <= 0)
10961316 continue;
@@ -1122,8 +1342,10 @@ static void l2fwd(struct xsk_socket_info *xsk, struct pollfd *fds) · 25 unmodified lines
11221342
11231343 rcvd = xsk_ring_cons__peek(&xsk->rx, opt_batch_size, &idx_rx);
11241344 if (!rcvd) {
1125− if (xsk_ring_prod__needs_wakeup(&xsk->umem->fq))
1345+ if (xsk_ring_prod__needs_wakeup(&xsk->umem->fq)) {
1346+ xsk->app_stats.rx_empty_polls++;
11261347 ret = poll(fds, num_socks, opt_timeout);
1348+ }
11271349 return;
11281350 }
11291351
@@ -1132,8 +1354,10 @@ static void l2fwd(struct xsk_socket_info *xsk, struct pollfd *fds) · 2 unmodified lines
11321354 if (ret < 0)
11331355 exit_with_error(-ret);
11341356 complete_tx_l2fwd(xsk, fds);
1135− if (xsk_ring_prod__needs_wakeup(&xsk->tx))
1357+ if (xsk_ring_prod__needs_wakeup(&xsk->tx)) {
1358+ xsk->app_stats.tx_wakeup_sendtos++;
11361359 kick_tx(xsk);
1360+ }
11371361 ret = xsk_ring_prod__reserve(&xsk->tx, rcvd, &idx_tx);
11381362 }
11391363
@@ -1155,7 +1379,7 @@ static void l2fwd(struct xsk_socket_info *xsk, struct pollfd *fds) · 15 unmodified lines
11551379 xsk_ring_prod__submit(&xsk->tx, rcvd);
11561380 xsk_ring_cons__release(&xsk->rx, rcvd);
11571381
1158− xsk->rx_npkts += rcvd;
1382+ xsk->ring_stats.rx_npkts += rcvd;
11591383 xsk->outstanding_tx += rcvd;
11601384 }
11611385
@@ -1171,6 +1395,8 @@ static void l2fwd_all(void) · 9 unmodified lines
11711395
11721396 for (;;) {
11731397 if (opt_poll) {
1398+ for (i = 0; i < num_socks; i++)
1399+ xsks[i]->app_stats.opt_polls++;
11741400 ret = poll(fds, num_socks, opt_timeout);
11751401 if (ret <= 0)
11761402 continue;
tools/include/uapi/linux/bpf.h+87−14
@@ -356,18 +356,36 @@ enum bpf_link_type { · 355 unmodified lines
356356 #define BPF_F_SLEEPABLE (1U << 4)
357357
358358 /* When BPF ldimm64's insn[0].src_reg != 0 then this can have
359− * two extensions:
360− *
361− * insn[0].src_reg: BPF_PSEUDO_MAP_FD BPF_PSEUDO_MAP_VALUE
362− * insn[0].imm: map fd map fd
363− * insn[1].imm: 0 offset into value
364− * insn[0].off: 0 0
365− * insn[1].off: 0 0
366− * ldimm64 rewrite: address of map address of map[0]+offset
367− * verifier type: CONST_PTR_TO_MAP PTR_TO_MAP_VALUE
359+ * the following extensions:
360+ *
361+ * insn[0].src_reg: BPF_PSEUDO_MAP_FD
362+ * insn[0].imm: map fd
363+ * insn[1].imm: 0
364+ * insn[0].off: 0
365+ * insn[1].off: 0
366+ * ldimm64 rewrite: address of map
367+ * verifier type: CONST_PTR_TO_MAP
368368 */
369369 #define BPF_PSEUDO_MAP_FD 1
370+/* insn[0].src_reg: BPF_PSEUDO_MAP_VALUE
371+ * insn[0].imm: map fd
372+ * insn[1].imm: offset into value
373+ * insn[0].off: 0
374+ * insn[1].off: 0
375+ * ldimm64 rewrite: address of map[0]+offset
376+ * verifier type: PTR_TO_MAP_VALUE
377+ */
370378 #define BPF_PSEUDO_MAP_VALUE 2
379+/* insn[0].src_reg: BPF_PSEUDO_BTF_ID
380+ * insn[0].imm: kernel btd id of VAR
381+ * insn[1].imm: 0
382+ * insn[0].off: 0
383+ * insn[1].off: 0
384+ * ldimm64 rewrite: address of the kernel variable
385+ * verifier type: PTR_TO_BTF_ID or PTR_TO_MEM, depending on whether the var
386+ * is struct/union.
387+ */
388+#define BPF_PSEUDO_BTF_ID 3
371389
372390 /* when bpf_call->src_reg == BPF_PSEUDO_CALL, bpf_call->imm == pc-relative
373391 * offset to another bpf function
@@ -417,6 +435,9 @@ enum { · 43 unmodified lines
417435
418436 /* Share perf_event among processes */
419437 BPF_F_PRESERVE_ELEMS = (1U << 11),
438+
439+/* Create a map that is suitable to be an inner map with dynamic max entries */
440+ BPF_F_INNER_MAP = (1U << 12),
420441 };
421442
422443 /* Flags for BPF_PROG_QUERY. */
@@ -1680,7 +1701,7 @@ union bpf_attr { · 1257 unmodified lines
16801701 * **TCP_CONGESTION**, **TCP_BPF_IW**,
16811702 * **TCP_BPF_SNDCWND_CLAMP**, **TCP_SAVE_SYN**,
16821703 * **TCP_KEEPIDLE**, **TCP_KEEPINTVL**, **TCP_KEEPCNT**,
1683− * **TCP_SYNCNT**, **TCP_USER_TIMEOUT**.
1704+ * **TCP_SYNCNT**, **TCP_USER_TIMEOUT**, **TCP_NOTSENT_LOWAT**.
16841705 * * **IPPROTO_IP**, which supports *optname* **IP_TOS**.
16851706 * * **IPPROTO_IPV6**, which supports *optname* **IPV6_TCLASS**.
16861707 * Return
@@ -2235,7 +2256,7 @@ union bpf_attr { · 548 unmodified lines
22352256 * Description
22362257 * This helper is used in programs implementing policies at the
22372258 * skb socket level. If the sk_buff *skb* is allowed to pass (i.e.
2238− * if the verdeict eBPF program returns **SK_PASS**), redirect it
2259+ * if the verdict eBPF program returns **SK_PASS**), redirect it
22392260 * to the socket referenced by *map* (of type
22402261 * **BPF_MAP_TYPE_SOCKHASH**) using hash *key*. Both ingress and
22412262 * egress interfaces can be used for redirection. The
@@ -3661,10 +3682,59 @@ union bpf_attr { · 1419 unmodified lines
36613682 * Redirect the packet to another net device of index *ifindex*
36623683 * and fill in L2 addresses from neighboring subsystem. This helper
36633684 * is somewhat similar to **bpf_redirect**\ (), except that it
3664− * fills in e.g. MAC addresses based on the L3 information from
3665− * the packet. This helper is supported for IPv4 and IPv6 protocols.
3685+ * populates L2 addresses as well, meaning, internally, the helper
3686+ * performs a FIB lookup based on the skb's networking header to
3687+ * get the address of the next hop and then relies on the neighbor
3688+ * lookup for the L2 address of the nexthop.
3689+ *
3690+ * The *flags* argument is reserved and must be 0. The helper is
3691+ * currently only supported for tc BPF program types, and enabled
3692+ * for IPv4 and IPv6 protocols.
3693+ * Return
3694+ * The helper returns **TC_ACT_REDIRECT** on success or
3695+ * **TC_ACT_SHOT** on error.
3696+ *
3697+ * void *bpf_per_cpu_ptr(const void *percpu_ptr, u32 cpu)
3698+ * Description
3699+ * Take a pointer to a percpu ksym, *percpu_ptr*, and return a
3700+ * pointer to the percpu kernel variable on *cpu*. A ksym is an
3701+ * extern variable decorated with '__ksym'. For ksym, there is a
3702+ * global var (either static or global) defined of the same name
3703+ * in the kernel. The ksym is percpu if the global var is percpu.
3704+ * The returned pointer points to the global percpu var on *cpu*.
3705+ *
3706+ * bpf_per_cpu_ptr() has the same semantic as per_cpu_ptr() in the
3707+ * kernel, except that bpf_per_cpu_ptr() may return NULL. This
3708+ * happens if *cpu* is larger than nr_cpu_ids. The caller of
3709+ * bpf_per_cpu_ptr() must check the returned value.
3710+ * Return
3711+ * A pointer pointing to the kernel percpu variable on *cpu*, or
3712+ * NULL, if *cpu* is invalid.
3713+ *
3714+ * void *bpf_this_cpu_ptr(const void *percpu_ptr)
3715+ * Description
3716+ * Take a pointer to a percpu ksym, *percpu_ptr*, and return a
3717+ * pointer to the percpu kernel variable on this cpu. See the
3718+ * description of 'ksym' in **bpf_per_cpu_ptr**\ ().
3719+ *
3720+ * bpf_this_cpu_ptr() has the same semantic as this_cpu_ptr() in
3721+ * the kernel. Different from **bpf_per_cpu_ptr**\ (), it would
3722+ * never return NULL.
3723+ * Return
3724+ * A pointer pointing to the kernel percpu variable on this cpu.
3725+ *
3726+ * long bpf_redirect_peer(u32 ifindex, u64 flags)
3727+ * Description
3728+ * Redirect the packet to another net device of index *ifindex*.
3729+ * This helper is somewhat similar to **bpf_redirect**\ (), except
3730+ * that the redirection happens to the *ifindex*' peer device and
3731+ * the netns switch takes place from ingress to ingress without
3732+ * going through the CPU's backlog queue.
3733+ *
36663734 * The *flags* argument is reserved and must be 0. The helper is
3667− * currently only supported for tc BPF program types.
3735+ * currently only supported for tc BPF program types at the ingress
3736+ * hook and for veth device types. The peer device must reside in a
3737+ * different network namespace.
36683738 * Return
36693739 * The helper returns **TC_ACT_REDIRECT** on success or
36703740 * **TC_ACT_SHOT** on error.
@@ -3823,6 +3893,9 @@ union bpf_attr { · 152 unmodified lines
38233893 FN(seq_printf_btf), \
38243894 FN(skb_cgroup_classid), \
38253895 FN(redirect_neigh), \
3896+ FN(bpf_per_cpu_ptr), \
3897+ FN(bpf_this_cpu_ptr), \
3898+ FN(redirect_peer), \
38263899 /* */
38273900
38283901 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
tools/lib/bpf/libbpf.c+289−59
@@ -390,6 +390,12 @@ struct extern_desc { · 389 unmodified lines
390390 } kcfg;
391391 struct {
392392 unsigned long long addr;
393+
394+ /* target btf_id of the corresponding kernel var. */
395+ int vmlinux_btf_id;
396+
397+ /* local btf_id of the ksym extern's type. */
398+ __u32 type_id;
393399 } ksym;
394400 };
395401 };
@@ -2522,12 +2528,23 @@ static int bpf_object__load_vmlinux_btf(struct bpf_object *obj) · 2126 unmodified lines
25222528 {
25232529 bool need_vmlinux_btf = false;
25242530 struct bpf_program *prog;
2525− int err;
2531+ int i, err;
25262532
25272533 /* CO-RE relocations need kernel BTF */
25282534 if (obj->btf_ext && obj->btf_ext->core_relo_info.len)
25292535 need_vmlinux_btf = true;
25302536
2537+ /* Support for typed ksyms needs kernel BTF */
2538+ for (i = 0; i < obj->nr_extern; i++) {
2539+ const struct extern_desc *ext;
2540+
2541+ ext = &obj->externs[i];
2542+ if (ext->type == EXT_KSYM && ext->ksym.type_id) {
2543+ need_vmlinux_btf = true;
2544+ break;
2545+ }
2546+ }
2547+
25312548 bpf_object__for_each_program(prog, obj) {
25322549 if (!prog->load)
25332550 continue;
@@ -3156,16 +3173,10 @@ static int bpf_object__collect_externs(struct bpf_object *obj) · 622 unmodified lines
31563173 return -ENOTSUP;
31573174 }
31583175 } else if (strcmp(sec_name, KSYMS_SEC) == 0) {
3159− const struct btf_type *vt;
3160−
31613176 ksym_sec = sec;
31623177 ext->type = EXT_KSYM;
3163−
3164− vt = skip_mods_and_typedefs(obj->btf, t->type, NULL);
3165− if (!btf_is_void(vt)) {
3166− pr_warn("extern (ksym) '%s' is not typeless (void)\n", ext_name);
3167− return -ENOTSUP;
3168− }
3178+ skip_mods_and_typedefs(obj->btf, t->type,
3179+ &ext->ksym.type_id);
31693180 } else {
31703181 pr_warn("unrecognized extern section '%s'\n", sec_name);
31713182 return -ENOTSUP;
@@ -4192,6 +4203,36 @@ static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map) · 1020 unmodified lines
41924203 return 0;
41934204 }
41944205
4206+static int init_map_slots(struct bpf_map *map)
4207+{
4208+ const struct bpf_map *targ_map;
4209+ unsigned int i;
4210+ int fd, err;
4211+
4212+ for (i = 0; i < map->init_slots_sz; i++) {
4213+ if (!map->init_slots[i])
4214+ continue;
4215+
4216+ targ_map = map->init_slots[i];
4217+ fd = bpf_map__fd(targ_map);
4218+ err = bpf_map_update_elem(map->fd, &i, &fd, 0);
4219+ if (err) {
4220+ err = -errno;
4221+ pr_warn("map '%s': failed to initialize slot [%d] to map '%s' fd=%d: %d\n",
4222+ map->name, i, targ_map->name,
4223+ fd, err);
4224+ return err;
4225+ }
4226+ pr_debug("map '%s': slot [%d] set to map '%s' fd=%d\n",
4227+ map->name, i, targ_map->name, fd);
4228+ }
4229+
4230+ zfree(&map->init_slots);
4231+ map->init_slots_sz = 0;
4232+
4233+ return 0;
4234+}
4235+
41954236 static int
41964237 bpf_object__create_maps(struct bpf_object *obj)
41974238 {
@@ -4215,47 +4256,29 @@ bpf_object__create_maps(struct bpf_object *obj) · 17 unmodified lines
42154256 if (map->fd >= 0) {
42164257 pr_debug("map '%s': skipping creation (preset fd=%d)\n",
42174258 map->name, map->fd);
4218− continue;
4219− }
4220−
4221− err = bpf_object__create_map(obj, map);
4222− if (err)
4223− goto err_out;
4224−
4225− pr_debug("map '%s': created successfully, fd=%d\n", map->name,
4226− map->fd);
4227−
4228− if (bpf_map__is_internal(map)) {
4229− err = bpf_object__populate_internal_map(obj, map);
4230− if (err < 0) {
4231− zclose(map->fd);
4259+ } else {
4260+ err = bpf_object__create_map(obj, map);
4261+ if (err)
42324262 goto err_out;
4233− }
4234− }
42354263
4236− if (map->init_slots_sz) {
4237− for (j = 0; j < map->init_slots_sz; j++) {
4238− const struct bpf_map *targ_map;
4239− int fd;
4264+ pr_debug("map '%s': created successfully, fd=%d\n",
4265+ map->name, map->fd);
42404266
4241− if (!map->init_slots[j])
4242− continue;
4267+ if (bpf_map__is_internal(map)) {
4268+ err = bpf_object__populate_internal_map(obj, map);
4269+ if (err < 0) {
4270+ zclose(map->fd);
4271+ goto err_out;
4272+ }
4273+ }
42434274
4244− targ_map = map->init_slots[j];
4245− fd = bpf_map__fd(targ_map);
4246− err = bpf_map_update_elem(map->fd, &j, &fd, 0);
4247− if (err) {
4248− err = -errno;
4249− pr_warn("map '%s': failed to initialize slot [%d] to map '%s' fd=%d: %d\n",
4250− map->name, j, targ_map->name,
4251− fd, err);
4275+ if (map->init_slots_sz) {
4276+ err = init_map_slots(map);
4277+ if (err < 0) {
4278+ zclose(map->fd);
42524279 goto err_out;
42534280 }
4254− pr_debug("map '%s': slot [%d] set to map '%s' fd=%d\n",
4255− map->name, j, targ_map->name, fd);
42564281 }
4257− zfree(&map->init_slots);
4258− map->init_slots_sz = 0;
42594282 }
42604283
42614284 if (map->pin_path && !map->pinned) {
@@ -5017,16 +5040,19 @@ static int bpf_core_spec_match(struct bpf_core_spec *local_spec, · 755 unmodified lines
50175040 static int bpf_core_calc_field_relo(const struct bpf_program *prog,
50185041 const struct bpf_core_relo *relo,
50195042 const struct bpf_core_spec *spec,
5020− __u32 *val, bool *validate)
5043+ __u32 *val, __u32 *field_sz, __u32 *type_id,
5044+ bool *validate)
50215045 {
50225046 const struct bpf_core_accessor *acc;
50235047 const struct btf_type *t;
5024− __u32 byte_off, byte_sz, bit_off, bit_sz;
5048+ __u32 byte_off, byte_sz, bit_off, bit_sz, field_type_id;
50255049 const struct btf_member *m;
50265050 const struct btf_type *mt;
50275051 bool bitfield;
50285052 __s64 sz;
50295053
5054+ *field_sz = 0;
5055+
50305056 if (relo->kind == BPF_FIELD_EXISTS) {
50315057 *val = spec ? 1 : 0;
50325058 return 0;
@@ -5042,6 +5068,12 @@ static int bpf_core_calc_field_relo(const struct bpf_program *prog, · 9 unmodified lines
50425068 if (!acc->name) {
50435069 if (relo->kind == BPF_FIELD_BYTE_OFFSET) {
50445070 *val = spec->bit_offset / 8;
5071+ /* remember field size for load/store mem size */
5072+ sz = btf__resolve_size(spec->btf, acc->type_id);
5073+ if (sz < 0)
5074+ return -EINVAL;
5075+ *field_sz = sz;
5076+ *type_id = acc->type_id;
50455077 } else if (relo->kind == BPF_FIELD_BYTE_SIZE) {
50465078 sz = btf__resolve_size(spec->btf, acc->type_id);
50475079 if (sz < 0)
@@ -5058,7 +5090,7 @@ static int bpf_core_calc_field_relo(const struct bpf_program *prog, · 10 unmodified lines
50585090 }
50595091
50605092 m = btf_members(t) + acc->idx;
5061− mt = skip_mods_and_typedefs(spec->btf, m->type, NULL);
5093+ mt = skip_mods_and_typedefs(spec->btf, m->type, &field_type_id);
50625094 bit_off = spec->bit_offset;
50635095 bit_sz = btf_member_bitfield_size(t, acc->idx);
50645096
@@ -5078,7 +5110,7 @@ static int bpf_core_calc_field_relo(const struct bpf_program *prog, · 13 unmodified lines
50785110 byte_off = bit_off / 8 / byte_sz * byte_sz;
50795111 }
50805112 } else {
5081− sz = btf__resolve_size(spec->btf, m->type);
5113+ sz = btf__resolve_size(spec->btf, field_type_id);
50825114 if (sz < 0)
50835115 return -EINVAL;
50845116 byte_sz = sz;
@@ -5096,6 +5128,10 @@ static int bpf_core_calc_field_relo(const struct bpf_program *prog, · 11 unmodified lines
50965128 switch (relo->kind) {
50975129 case BPF_FIELD_BYTE_OFFSET:
50985130 *val = byte_off;
5131+ if (!bitfield) {
5132+ *field_sz = byte_sz;
5133+ *type_id = field_type_id;
5134+ }
50995135 break;
51005136 case BPF_FIELD_BYTE_SIZE:
51015137 *val = byte_sz;
@@ -5196,6 +5232,19 @@ struct bpf_core_relo_res · 94 unmodified lines
51965232 bool poison;
51975233 /* some relocations can't be validated against orig_val */
51985234 bool validate;
5235+ /* for field byte offset relocations or the forms:
5236+ * *(T *)(rX + <off>) = rY
5237+ * rX = *(T *)(rY + <off>),
5238+ * we remember original and resolved field size to adjust direct
5239+ * memory loads of pointers and integers; this is necessary for 32-bit
5240+ * host kernel architectures, but also allows to automatically
5241+ * relocate fields that were resized from, e.g., u32 to u64, etc.
5242+ */
5243+ bool fail_memsz_adjust;
5244+ __u32 orig_sz;
5245+ __u32 orig_type_id;
5246+ __u32 new_sz;
5247+ __u32 new_type_id;
51995248 };
52005249
52015250 /* Calculate original and target relocation values, given local and target
@@ -5217,10 +5266,56 @@ static int bpf_core_calc_relo(const struct bpf_program *prog, · 15 unmodified lines
52175266 res->new_val = 0;
52185267 res->poison = false;
52195268 res->validate = true;
5269+ res->fail_memsz_adjust = false;
5270+ res->orig_sz = res->new_sz = 0;
5271+ res->orig_type_id = res->new_type_id = 0;
52205272
52215273 if (core_relo_is_field_based(relo->kind)) {
5222− err = bpf_core_calc_field_relo(prog, relo, local_spec, &res->orig_val, &res->validate);
5223− err = err ?: bpf_core_calc_field_relo(prog, relo, targ_spec, &res->new_val, NULL);
5274+ err = bpf_core_calc_field_relo(prog, relo, local_spec,
5275+ &res->orig_val, &res->orig_sz,
5276+ &res->orig_type_id, &res->validate);
5277+ err = err ?: bpf_core_calc_field_relo(prog, relo, targ_spec,
5278+ &res->new_val, &res->new_sz,
5279+ &res->new_type_id, NULL);
5280+ if (err)
5281+ goto done;
5282+ /* Validate if it's safe to adjust load/store memory size.
5283+ * Adjustments are performed only if original and new memory
5284+ * sizes differ.
5285+ */
5286+ res->fail_memsz_adjust = false;
5287+ if (res->orig_sz != res->new_sz) {
5288+ const struct btf_type *orig_t, *new_t;
5289+
5290+ orig_t = btf__type_by_id(local_spec->btf, res->orig_type_id);
5291+ new_t = btf__type_by_id(targ_spec->btf, res->new_type_id);
5292+
5293+ /* There are two use cases in which it's safe to
5294+ * adjust load/store's mem size:
5295+ * - reading a 32-bit kernel pointer, while on BPF
5296+ * size pointers are always 64-bit; in this case
5297+ * it's safe to "downsize" instruction size due to
5298+ * pointer being treated as unsigned integer with
5299+ * zero-extended upper 32-bits;
5300+ * - reading unsigned integers, again due to
5301+ * zero-extension is preserving the value correctly.
5302+ *
5303+ * In all other cases it's incorrect to attempt to
5304+ * load/store field because read value will be
5305+ * incorrect, so we poison relocated instruction.
5306+ */
5307+ if (btf_is_ptr(orig_t) && btf_is_ptr(new_t))
5308+ goto done;
5309+ if (btf_is_int(orig_t) && btf_is_int(new_t) &&
5310+ btf_int_encoding(orig_t) != BTF_INT_SIGNED &&
5311+ btf_int_encoding(new_t) != BTF_INT_SIGNED)
5312+ goto done;
5313+
5314+ /* mark as invalid mem size adjustment, but this will
5315+ * only be checked for LDX/STX/ST insns
5316+ */
5317+ res->fail_memsz_adjust = true;
5318+ }
52245319 } else if (core_relo_is_type_based(relo->kind)) {
52255320 err = bpf_core_calc_type_relo(relo, local_spec, &res->orig_val);
52265321 err = err ?: bpf_core_calc_type_relo(relo, targ_spec, &res->new_val);
@@ -5229,6 +5324,7 @@ static int bpf_core_calc_relo(const struct bpf_program *prog, · 2 unmodified lines
52295324 err = err ?: bpf_core_calc_enumval_relo(relo, targ_spec, &res->new_val);
52305325 }
52315326
5327+done:
52325328 if (err == -EUCLEAN) {
52335329 /* EUCLEAN is used to signal instruction poisoning request */
52345330 res->poison = true;
@@ -5268,6 +5364,28 @@ static bool is_ldimm64(struct bpf_insn *insn) · 33 unmodified lines
52685364 return insn->code == (BPF_LD | BPF_IMM | BPF_DW);
52695365 }
52705366
5367+static int insn_bpf_size_to_bytes(struct bpf_insn *insn)
5368+{
5369+ switch (BPF_SIZE(insn->code)) {
5370+ case BPF_DW: return 8;
5371+ case BPF_W: return 4;
5372+ case BPF_H: return 2;
5373+ case BPF_B: return 1;
5374+ default: return -1;
5375+ }
5376+}
5377+
5378+static int insn_bytes_to_bpf_size(__u32 sz)
5379+{
5380+ switch (sz) {
5381+ case 8: return BPF_DW;
5382+ case 4: return BPF_W;
5383+ case 2: return BPF_H;
5384+ case 1: return BPF_B;
5385+ default: return -1;
5386+ }
5387+}
5388+
52715389 /*
52725390 * Patch relocatable BPF instruction.
52735391 *
@@ -5277,10 +5395,13 @@ static bool is_ldimm64(struct bpf_insn *insn) · 3 unmodified lines
52775395 * spec, and is checked before patching instruction. If actual insn->imm value
52785396 * is wrong, bail out with error.
52795397 *
5280− * Currently three kinds of BPF instructions are supported:
5398+ * Currently supported classes of BPF instruction are:
52815399 * 1. rX = <imm> (assignment with immediate operand);
52825400 * 2. rX += <imm> (arithmetic operations with immediate operand);
5283− * 3. rX = <imm64> (load with 64-bit immediate value).
5401+ * 3. rX = <imm64> (load with 64-bit immediate value);
5402+ * 4. rX = *(T *)(rY + <off>), where T is one of {u8, u16, u32, u64};
5403+ * 5. *(T *)(rX + <off>) = rY, where T is one of {u8, u16, u32, u64};
5404+ * 6. *(T *)(rX + <off>) = <imm>, where T is one of {u8, u16, u32, u64}.
52845405 */
52855406 static int bpf_core_patch_insn(struct bpf_program *prog,
52865407 const struct bpf_core_relo *relo,
@@ -5304,6 +5425,7 @@ static int bpf_core_patch_insn(struct bpf_program *prog, · 17 unmodified lines
53045425 class = BPF_CLASS(insn->code);
53055426
53065427 if (res->poison) {
5428+poison:
53075429 /* poison second part of ldimm64 to avoid confusing error from
53085430 * verifier about "unknown opcode 00"
53095431 */
@@ -5346,10 +5468,39 @@ static int bpf_core_patch_insn(struct bpf_program *prog, · 36 unmodified lines
53465468 prog->name, relo_idx, insn_idx, new_val);
53475469 return -ERANGE;
53485470 }
5471+ if (res->fail_memsz_adjust) {
5472+ pr_warn("prog '%s': relo #%d: insn #%d (LDX/ST/STX) accesses field incorrectly. "
5473+ "Make sure you are accessing pointers, unsigned integers, or fields of matching type and size.\n",
5474+ prog->name, relo_idx, insn_idx);
5475+ goto poison;
5476+ }
5477+
53495478 orig_val = insn->off;
53505479 insn->off = new_val;
53515480 pr_debug("prog '%s': relo #%d: patched insn #%d (LDX/ST/STX) off %u -> %u\n",
53525481 prog->name, relo_idx, insn_idx, orig_val, new_val);
5482+
5483+ if (res->new_sz != res->orig_sz) {
5484+ int insn_bytes_sz, insn_bpf_sz;
5485+
5486+ insn_bytes_sz = insn_bpf_size_to_bytes(insn);
5487+ if (insn_bytes_sz != res->orig_sz) {
5488+ pr_warn("prog '%s': relo #%d: insn #%d (LDX/ST/STX) unexpected mem size: got %d, exp %u\n",
5489+ prog->name, relo_idx, insn_idx, insn_bytes_sz, res->orig_sz);
5490+ return -EINVAL;
5491+ }
5492+
5493+ insn_bpf_sz = insn_bytes_to_bpf_size(res->new_sz);
5494+ if (insn_bpf_sz < 0) {
5495+ pr_warn("prog '%s': relo #%d: insn #%d (LDX/ST/STX) invalid new mem size: %u\n",
5496+ prog->name, relo_idx, insn_idx, res->new_sz);
5497+ return -EINVAL;
5498+ }
5499+
5500+ insn->code = BPF_MODE(insn->code) | insn_bpf_sz | BPF_CLASS(insn->code);
5501+ pr_debug("prog '%s': relo #%d: patched insn #%d (LDX/ST/STX) mem_sz %u -> %u\n",
5502+ prog->name, relo_idx, insn_idx, res->orig_sz, res->new_sz);
5503+ }
53535504 break;
53545505 case BPF_LD: {
53555506 __u64 imm;
@@ -5691,7 +5842,7 @@ bpf_object__relocate_core(struct bpf_object *obj, const char *targ_btf_path) · 335 unmodified lines
56915842 return 0;
56925843
56935844 if (targ_btf_path)
5694− targ_btf = btf__parse_elf(targ_btf_path, NULL);
5845+ targ_btf = btf__parse(targ_btf_path, NULL);
56955846 else
56965847 targ_btf = obj->btf_vmlinux;
56975848 if (IS_ERR_OR_NULL(targ_btf)) {
@@ -5742,6 +5893,11 @@ bpf_object__relocate_core(struct bpf_object *obj, const char *targ_btf_path) · 44 unmodified lines
57425893 err = -EINVAL;
57435894 goto out;
57445895 }
5896+ /* no need to apply CO-RE relocation if the program is
5897+ * not going to be loaded
5898+ */
5899+ if (!prog->load)
5900+ continue;
57455901
57465902 err = bpf_core_apply_relo(prog, rec, i, obj->btf,
57475903 targ_btf, cand_cache);
@@ -5800,8 +5956,13 @@ bpf_object__relocate_data(struct bpf_object *obj, struct bpf_program *prog) · 52 unmodified lines
58005956 insn[0].imm = obj->maps[obj->kconfig_map_idx].fd;
58015957 insn[1].imm = ext->kcfg.data_off;
58025958 } else /* EXT_KSYM */ {
5803− insn[0].imm = (__u32)ext->ksym.addr;
5804− insn[1].imm = ext->ksym.addr >> 32;
5959+ if (ext->ksym.type_id) { /* typed ksyms */
5960+ insn[0].src_reg = BPF_PSEUDO_BTF_ID;
5961+ insn[0].imm = ext->ksym.vmlinux_btf_id;
5962+ } else { /* typeless ksyms */
5963+ insn[0].imm = (__u32)ext->ksym.addr;
5964+ insn[1].imm = ext->ksym.addr >> 32;
5965+ }
58055966 }
58065967 relo->processed = true;
58075968 break;
@@ -6933,10 +7094,72 @@ out: · 1125 unmodified lines
69337094 return err;
69347095 }
69357096
7097+static int bpf_object__resolve_ksyms_btf_id(struct bpf_object *obj)
7098+{
7099+ struct extern_desc *ext;
7100+ int i, id;
7101+
7102+ for (i = 0; i < obj->nr_extern; i++) {
7103+ const struct btf_type *targ_var, *targ_type;
7104+ __u32 targ_type_id, local_type_id;
7105+ const char *targ_var_name;
7106+ int ret;
7107+
7108+ ext = &obj->externs[i];
7109+ if (ext->type != EXT_KSYM || !ext->ksym.type_id)
7110+ continue;
7111+
7112+ id = btf__find_by_name_kind(obj->btf_vmlinux, ext->name,
7113+ BTF_KIND_VAR);
7114+ if (id <= 0) {
7115+ pr_warn("extern (ksym) '%s': failed to find BTF ID in vmlinux BTF.\n",
7116+ ext->name);
7117+ return -ESRCH;
7118+ }
7119+
7120+ /* find local type_id */
7121+ local_type_id = ext->ksym.type_id;
7122+
7123+ /* find target type_id */
7124+ targ_var = btf__type_by_id(obj->btf_vmlinux, id);
7125+ targ_var_name = btf__name_by_offset(obj->btf_vmlinux,
7126+ targ_var->name_off);
7127+ targ_type = skip_mods_and_typedefs(obj->btf_vmlinux,
7128+ targ_var->type,
7129+ &targ_type_id);
7130+
7131+ ret = bpf_core_types_are_compat(obj->btf, local_type_id,
7132+ obj->btf_vmlinux, targ_type_id);
7133+ if (ret <= 0) {
7134+ const struct btf_type *local_type;
7135+ const char *targ_name, *local_name;
7136+
7137+ local_type = btf__type_by_id(obj->btf, local_type_id);
7138+ local_name = btf__name_by_offset(obj->btf,
7139+ local_type->name_off);
7140+ targ_name = btf__name_by_offset(obj->btf_vmlinux,
7141+ targ_type->name_off);
7142+
7143+ pr_warn("extern (ksym) '%s': incompatible types, expected [%d] %s %s, but kernel has [%d] %s %s\n",
7144+ ext->name, local_type_id,
7145+ btf_kind_str(local_type), local_name, targ_type_id,
7146+ btf_kind_str(targ_type), targ_name);
7147+ return -EINVAL;
7148+ }
7149+
7150+ ext->is_set = true;
7151+ ext->ksym.vmlinux_btf_id = id;
7152+ pr_debug("extern (ksym) '%s': resolved to [%d] %s %s\n",
7153+ ext->name, id, btf_kind_str(targ_var), targ_var_name);
7154+ }
7155+ return 0;
7156+}
7157+
69367158 static int bpf_object__resolve_externs(struct bpf_object *obj,
69377159 const char *extra_kconfig)
69387160 {
69397161 bool need_config = false, need_kallsyms = false;
7162+ bool need_vmlinux_btf = false;
69407163 struct extern_desc *ext;
69417164 void *kcfg_data = NULL;
69427165 int err, i;
@@ -6967,7 +7190,10 @@ static int bpf_object__resolve_externs(struct bpf_object *obj, · 24 unmodified lines
69677190 strncmp(ext->name, "CONFIG_", 7) == 0) {
69687191 need_config = true;
69697192 } else if (ext->type == EXT_KSYM) {
6970− need_kallsyms = true;
7193+ if (ext->ksym.type_id)
7194+ need_vmlinux_btf = true;
7195+ else
7196+ need_kallsyms = true;
69717197 } else {
69727198 pr_warn("unrecognized extern '%s'\n", ext->name);
69737199 return -EINVAL;
@@ -6996,6 +7222,11 @@ static int bpf_object__resolve_externs(struct bpf_object *obj, · 22 unmodified lines
69967222 if (err)
69977223 return -EINVAL;
69987224 }
7225+ if (need_vmlinux_btf) {
7226+ err = bpf_object__resolve_ksyms_btf_id(obj);
7227+ if (err)
7228+ return -EINVAL;
7229+ }
69997230 for (i = 0; i < obj->nr_extern; i++) {
70007231 ext = &obj->externs[i];
70017232
@@ -7028,10 +7259,10 @@ int bpf_object__load_xattr(struct bpf_object_load_attr *attr) · 26 unmodified lines
70287259 }
70297260
70307261 err = bpf_object__probe_loading(obj);
7262+ err = err ? : bpf_object__load_vmlinux_btf(obj);
70317263 err = err ? : bpf_object__resolve_externs(obj, obj->kconfig);
70327264 err = err ? : bpf_object__sanitize_and_load_btf(obj);
70337265 err = err ? : bpf_object__sanitize_maps(obj);
7034− err = err ? : bpf_object__load_vmlinux_btf(obj);
70357266 err = err ? : bpf_object__init_kern_struct_ops_maps(obj);
70367267 err = err ? : bpf_object__create_maps(obj);
70377268 err = err ? : bpf_object__relocate(obj, attr->target_btf_path);
@@ -10353,9 +10584,8 @@ int bpf_program__set_attach_target(struct bpf_program *prog, · 3315 unmodified lines
1035310584 btf_id = libbpf_find_prog_btf_id(attach_func_name,
1035410585 attach_prog_fd);
1035510586 else
10356− btf_id = __find_vmlinux_btf_id(prog->obj->btf_vmlinux,
10357− attach_func_name,
10358− prog->expected_attach_type);
10587+ btf_id = libbpf_find_vmlinux_btf_id(attach_func_name,
10588+ prog->expected_attach_type);
1035910589
1036010590 if (btf_id < 0)
1036110591 return btf_id;
tools/lib/bpf/xsk.c+6−1
@@ -705,7 +705,7 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr, · 704 unmodified lines
705705 struct xsk_ctx *ctx;
706706 int err, ifindex;
707707
708− if (!umem || !xsk_ptr || !(rx || tx) || !fill || !comp)
708+ if (!umem || !xsk_ptr || !(rx || tx))
709709 return -EFAULT;
710710
711711 xsk = calloc(1, sizeof(*xsk));
@@ -735,6 +735,11 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr, · 23 unmodified lines
735735
736736 ctx = xsk_get_ctx(umem, ifindex, queue_id);
737737 if (!ctx) {
738+ if (!fill || !comp) {
739+ err = -EFAULT;
740+ goto out_socket;
741+ }
742+
738743 ctx = xsk_create_ctx(xsk, umem, ifindex, ifname, queue_id,
739744 fill, comp);
740745 if (!ctx) {
tools/testing/selftests/bpf/README.rst+38−0
@@ -7,6 +7,44 @@ General instructions on running selftests can be found in · 6 unmodified lines
77 Additional information about selftest failures are
88 documented here.
99
10+profiler[23] test failures with clang/llvm <12.0.0
11+==================================================
12+
13+With clang/llvm <12.0.0, the profiler[23] test may fail.
14+The symptom looks like
15+
16+.. code-block:: c
17+
18+ // r9 is a pointer to map_value
19+ // r7 is a scalar
20+ 17: bf 96 00 00 00 00 00 00 r6 = r9
21+ 18: 0f 76 00 00 00 00 00 00 r6 += r7
22+ math between map_value pointer and register with unbounded min value is not allowed
23+
24+ // the instructions below will not be seen in the verifier log
25+ 19: a5 07 01 00 01 01 00 00 if r7 < 257 goto +1
26+ 20: bf 96 00 00 00 00 00 00 r6 = r9
27+ // r6 is used here
28+
29+The verifier will reject such code with above error.
30+At insn 18 the r7 is indeed unbounded. The later insn 19 checks the bounds and
31+the insn 20 undoes map_value addition. It is currently impossible for the
32+verifier to understand such speculative pointer arithmetic.
33+Hence
34+ https://reviews.llvm.org/D85570
35+addresses it on the compiler side. It was committed on llvm 12.
36+
37+The corresponding C code
38+.. code-block:: c
39+
40+ for (int i = 0; i < MAX_CGROUPS_PATH_DEPTH; i++) {
41+ filepart_length = bpf_probe_read_str(payload, ...);
42+ if (filepart_length <= MAX_PATH) {
43+ barrier_var(filepart_length); // workaround
44+ payload += filepart_length;
45+ }
46+ }
47+
1048 bpf_iter test failures with clang/llvm 10.0.0
1149 =============================================
1250
tools/testing/selftests/bpf/prog_tests/align.c+8−8
@@ -195,13 +195,13 @@ static struct bpf_align_test tests[] = { · 194 unmodified lines
195195 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
196196 .matches = {
197197 {7, "R3_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"},
198− {8, "R4_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"},
198+ {8, "R4_w=inv(id=1,umax_value=255,var_off=(0x0; 0xff))"},
199199 {9, "R4_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"},
200− {10, "R4_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"},
200+ {10, "R4_w=inv(id=1,umax_value=255,var_off=(0x0; 0xff))"},
201201 {11, "R4_w=inv(id=0,umax_value=510,var_off=(0x0; 0x1fe))"},
202− {12, "R4_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"},
202+ {12, "R4_w=inv(id=1,umax_value=255,var_off=(0x0; 0xff))"},
203203 {13, "R4_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
204− {14, "R4_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"},
204+ {14, "R4_w=inv(id=1,umax_value=255,var_off=(0x0; 0xff))"},
205205 {15, "R4_w=inv(id=0,umax_value=2040,var_off=(0x0; 0x7f8))"},
206206 {16, "R4_w=inv(id=0,umax_value=4080,var_off=(0x0; 0xff0))"},
207207 },
@@ -518,7 +518,7 @@ static struct bpf_align_test tests[] = { · 310 unmodified lines
518518 * the total offset is 4-byte aligned and meets the
519519 * load's requirements.
520520 */
521− {20, "R5=pkt(id=1,off=0,r=4,umin_value=2,umax_value=1034,var_off=(0x2; 0x7fc)"},
521+ {20, "R5=pkt(id=2,off=0,r=4,umin_value=2,umax_value=1034,var_off=(0x2; 0x7fc)"},
522522
523523 },
524524 },
@@ -561,18 +561,18 @@ static struct bpf_align_test tests[] = { · 36 unmodified lines
561561 /* Adding 14 makes R6 be (4n+2) */
562562 {11, "R6_w=inv(id=0,umin_value=14,umax_value=74,var_off=(0x2; 0x7c))"},
563563 /* Subtracting from packet pointer overflows ubounds */
564− {13, "R5_w=pkt(id=1,off=0,r=8,umin_value=18446744073709551542,umax_value=18446744073709551602,var_off=(0xffffffffffffff82; 0x7c)"},
564+ {13, "R5_w=pkt(id=2,off=0,r=8,umin_value=18446744073709551542,umax_value=18446744073709551602,var_off=(0xffffffffffffff82; 0x7c)"},
565565 /* New unknown value in R7 is (4n), >= 76 */
566566 {15, "R7_w=inv(id=0,umin_value=76,umax_value=1096,var_off=(0x0; 0x7fc))"},
567567 /* Adding it to packet pointer gives nice bounds again */
568− {16, "R5_w=pkt(id=2,off=0,r=0,umin_value=2,umax_value=1082,var_off=(0x2; 0xfffffffc)"},
568+ {16, "R5_w=pkt(id=3,off=0,r=0,umin_value=2,umax_value=1082,var_off=(0x2; 0xfffffffc)"},
569569 /* At the time the word size load is performed from R5,
570570 * its total fixed offset is NET_IP_ALIGN + reg->off (0)
571571 * which is 2. Then the variable offset is (4n+2), so
572572 * the total offset is 4-byte aligned and meets the
573573 * load's requirements.
574574 */
575− {20, "R5=pkt(id=2,off=0,r=4,umin_value=2,umax_value=1082,var_off=(0x2; 0xfffffffc)"},
575+ {20, "R5=pkt(id=3,off=0,r=4,umin_value=2,umax_value=1082,var_off=(0x2; 0xfffffffc)"},
576576 },
577577 },
578578 };
tools/testing/selftests/bpf/prog_tests/btf_map_in_map.c+29−10
@@ -55,10 +55,10 @@ static int kern_sync_rcu(void) · 54 unmodified lines
5555
5656 static void test_lookup_update(void)
5757 {
58− int err, key = 0, val, i;
58+ int map1_fd, map2_fd, map3_fd, map4_fd, map5_fd, map1_id, map2_id;
59+ int outer_arr_fd, outer_hash_fd, outer_arr_dyn_fd;
5960 struct test_btf_map_in_map *skel;
60− int outer_arr_fd, outer_hash_fd;
61− int fd, map1_fd, map2_fd, map1_id, map2_id;
61+ int err, key = 0, val, i, fd;
6262
6363 skel = test_btf_map_in_map__open_and_load();
6464 if (CHECK(!skel, "skel_open", "failed to open&load skeleton\n"))
@@ -70,32 +70,45 @@ static void test_lookup_update(void) · 5 unmodified lines
7070
7171 map1_fd = bpf_map__fd(skel->maps.inner_map1);
7272 map2_fd = bpf_map__fd(skel->maps.inner_map2);
73+ map3_fd = bpf_map__fd(skel->maps.inner_map3);
74+ map4_fd = bpf_map__fd(skel->maps.inner_map4);
75+ map5_fd = bpf_map__fd(skel->maps.inner_map5);
76+ outer_arr_dyn_fd = bpf_map__fd(skel->maps.outer_arr_dyn);
7377 outer_arr_fd = bpf_map__fd(skel->maps.outer_arr);
7478 outer_hash_fd = bpf_map__fd(skel->maps.outer_hash);
7579
76− /* inner1 = input, inner2 = input + 1 */
77− map1_fd = bpf_map__fd(skel->maps.inner_map1);
80+ /* inner1 = input, inner2 = input + 1, inner3 = input + 2 */
7881 bpf_map_update_elem(outer_arr_fd, &key, &map1_fd, 0);
79− map2_fd = bpf_map__fd(skel->maps.inner_map2);
8082 bpf_map_update_elem(outer_hash_fd, &key, &map2_fd, 0);
83+ bpf_map_update_elem(outer_arr_dyn_fd, &key, &map3_fd, 0);
8184 skel->bss->input = 1;
8285 usleep(1);
83−
8486 bpf_map_lookup_elem(map1_fd, &key, &val);
8587 CHECK(val != 1, "inner1", "got %d != exp %d\n", val, 1);
8688 bpf_map_lookup_elem(map2_fd, &key, &val);
8789 CHECK(val != 2, "inner2", "got %d != exp %d\n", val, 2);
90+ bpf_map_lookup_elem(map3_fd, &key, &val);
91+ CHECK(val != 3, "inner3", "got %d != exp %d\n", val, 3);
8892
89− /* inner1 = input + 1, inner2 = input */
93+ /* inner2 = input, inner1 = input + 1, inner4 = input + 2 */
9094 bpf_map_update_elem(outer_arr_fd, &key, &map2_fd, 0);
9195 bpf_map_update_elem(outer_hash_fd, &key, &map1_fd, 0);
96+ bpf_map_update_elem(outer_arr_dyn_fd, &key, &map4_fd, 0);
9297 skel->bss->input = 3;
9398 usleep(1);
94−
9599 bpf_map_lookup_elem(map1_fd, &key, &val);
96100 CHECK(val != 4, "inner1", "got %d != exp %d\n", val, 4);
97101 bpf_map_lookup_elem(map2_fd, &key, &val);
98102 CHECK(val != 3, "inner2", "got %d != exp %d\n", val, 3);
103+ bpf_map_lookup_elem(map4_fd, &key, &val);
104+ CHECK(val != 5, "inner4", "got %d != exp %d\n", val, 5);
105+
106+ /* inner5 = input + 2 */
107+ bpf_map_update_elem(outer_arr_dyn_fd, &key, &map5_fd, 0);
108+ skel->bss->input = 5;
109+ usleep(1);
110+ bpf_map_lookup_elem(map5_fd, &key, &val);
111+ CHECK(val != 7, "inner5", "got %d != exp %d\n", val, 7);
99112
100113 for (i = 0; i < 5; i++) {
101114 val = i % 2 ? map1_fd : map2_fd;
@@ -106,7 +119,13 @@ static void test_lookup_update(void) · 4 unmodified lines
106119 }
107120 err = bpf_map_update_elem(outer_arr_fd, &key, &val, 0);
108121 if (CHECK_FAIL(err)) {
109− printf("failed to update hash_of_maps on iter #%d\n", i);
122+ printf("failed to update array_of_maps on iter #%d\n", i);
123+ goto cleanup;
124+ }
125+ val = i % 2 ? map4_fd : map5_fd;
126+ err = bpf_map_update_elem(outer_arr_dyn_fd, &key, &val, 0);
127+ if (CHECK_FAIL(err)) {
128+ printf("failed to update array_of_maps (dyn) on iter #%d\n", i);
110129 goto cleanup;
111130 }
112131 }
tools/testing/selftests/bpf/prog_tests/core_autosize.c+225−0
@@ -0,0 +1,225 @@
1+// SPDX-License-Identifier: GPL-2.0
2+/* Copyright (c) 2020 Facebook */
3+
4+#include <test_progs.h>
5+#include <bpf/btf.h>
6+
7+/* real layout and sizes according to test's (32-bit) BTF
8+ * needs to be defined before skeleton is included */
9+struct test_struct___real {
10+ unsigned int ptr; /* can't use `void *`, it is always 8 byte in BPF target */
11+ unsigned int val2;
12+ unsigned long long val1;
13+ unsigned short val3;
14+ unsigned char val4;
15+ unsigned char _pad;
16+};
17+
18+#include "test_core_autosize.skel.h"
19+
20+static int duration = 0;
21+
22+static struct {
23+ unsigned long long ptr_samesized;
24+ unsigned long long val1_samesized;
25+ unsigned long long val2_samesized;
26+ unsigned long long val3_samesized;
27+ unsigned long long val4_samesized;
28+ struct test_struct___real output_samesized;
29+
30+ unsigned long long ptr_downsized;
31+ unsigned long long val1_downsized;
32+ unsigned long long val2_downsized;
33+ unsigned long long val3_downsized;
34+ unsigned long long val4_downsized;
35+ struct test_struct___real output_downsized;
36+
37+ unsigned long long ptr_probed;
38+ unsigned long long val1_probed;
39+ unsigned long long val2_probed;
40+ unsigned long long val3_probed;
41+ unsigned long long val4_probed;
42+
43+ unsigned long long ptr_signed;
44+ unsigned long long val1_signed;
45+ unsigned long long val2_signed;
46+ unsigned long long val3_signed;
47+ unsigned long long val4_signed;
48+ struct test_struct___real output_signed;
49+} out;
50+
51+void test_core_autosize(void)
52+{
53+ char btf_file[] = "/tmp/core_autosize.btf.XXXXXX";
54+ int err, fd = -1, zero = 0;
55+ int char_id, short_id, int_id, long_long_id, void_ptr_id, id;
56+ struct test_core_autosize* skel = NULL;
57+ struct bpf_object_load_attr load_attr = {};
58+ struct bpf_program *prog;
59+ struct bpf_map *bss_map;
60+ struct btf *btf = NULL;
61+ size_t written;
62+ const void *raw_data;
63+ __u32 raw_sz;
64+ FILE *f = NULL;
65+
66+ btf = btf__new_empty();
67+ if (!ASSERT_OK_PTR(btf, "empty_btf"))
68+ return;
69+ /* Emit the following struct with 32-bit pointer size:
70+ *
71+ * struct test_struct {
72+ * void *ptr;
73+ * unsigned long val2;
74+ * unsigned long long val1;
75+ * unsigned short val3;
76+ * unsigned char val4;
77+ * char: 8;
78+ * };
79+ *
80+ * This struct is going to be used as the "kernel BTF" for this test.
81+ * It's equivalent memory-layout-wise to test_struct__real above.
82+ */
83+
84+ /* force 32-bit pointer size */
85+ btf__set_pointer_size(btf, 4);
86+
87+ char_id = btf__add_int(btf, "unsigned char", 1, 0);
88+ ASSERT_EQ(char_id, 1, "char_id");
89+ short_id = btf__add_int(btf, "unsigned short", 2, 0);
90+ ASSERT_EQ(short_id, 2, "short_id");
91+ /* "long unsigned int" of 4 byte size tells BTF that sizeof(void *) == 4 */
92+ int_id = btf__add_int(btf, "long unsigned int", 4, 0);
93+ ASSERT_EQ(int_id, 3, "int_id");
94+ long_long_id = btf__add_int(btf, "unsigned long long", 8, 0);
95+ ASSERT_EQ(long_long_id, 4, "long_long_id");
96+ void_ptr_id = btf__add_ptr(btf, 0);
97+ ASSERT_EQ(void_ptr_id, 5, "void_ptr_id");
98+
99+ id = btf__add_struct(btf, "test_struct", 20 /* bytes */);
100+ ASSERT_EQ(id, 6, "struct_id");
101+ err = btf__add_field(btf, "ptr", void_ptr_id, 0, 0);
102+ err = err ?: btf__add_field(btf, "val2", int_id, 32, 0);
103+ err = err ?: btf__add_field(btf, "val1", long_long_id, 64, 0);
104+ err = err ?: btf__add_field(btf, "val3", short_id, 128, 0);
105+ err = err ?: btf__add_field(btf, "val4", char_id, 144, 0);
106+ ASSERT_OK(err, "struct_fields");
107+
108+ fd = mkstemp(btf_file);
109+ if (CHECK(fd < 0, "btf_tmp", "failed to create file: %d\n", fd))
110+ goto cleanup;
111+ f = fdopen(fd, "w");
112+ if (!ASSERT_OK_PTR(f, "btf_fdopen"))
113+ goto cleanup;
114+
115+ raw_data = btf__get_raw_data(btf, &raw_sz);
116+ if (!ASSERT_OK_PTR(raw_data, "raw_data"))
117+ goto cleanup;
118+ written = fwrite(raw_data, 1, raw_sz, f);
119+ if (CHECK(written != raw_sz, "btf_write", "written: %zu, errno: %d\n", written, errno))
120+ goto cleanup;
121+ fflush(f);
122+ fclose(f);
123+ f = NULL;
124+ close(fd);
125+ fd = -1;
126+
127+ /* open and load BPF program with custom BTF as the kernel BTF */
128+ skel = test_core_autosize__open();
129+ if (!ASSERT_OK_PTR(skel, "skel_open"))
130+ return;
131+
132+ /* disable handle_signed() for now */
133+ prog = bpf_object__find_program_by_name(skel->obj, "handle_signed");
134+ if (!ASSERT_OK_PTR(prog, "prog_find"))
135+ goto cleanup;
136+ bpf_program__set_autoload(prog, false);
137+
138+ load_attr.obj = skel->obj;
139+ load_attr.target_btf_path = btf_file;
140+ err = bpf_object__load_xattr(&load_attr);
141+ if (!ASSERT_OK(err, "prog_load"))
142+ goto cleanup;
143+
144+ prog = bpf_object__find_program_by_name(skel->obj, "handle_samesize");
145+ if (!ASSERT_OK_PTR(prog, "prog_find"))
146+ goto cleanup;
147+ skel->links.handle_samesize = bpf_program__attach(prog);
148+ if (!ASSERT_OK_PTR(skel->links.handle_samesize, "prog_attach"))
149+ goto cleanup;
150+
151+ prog = bpf_object__find_program_by_name(skel->obj, "handle_downsize");
152+ if (!ASSERT_OK_PTR(prog, "prog_find"))
153+ goto cleanup;
154+ skel->links.handle_downsize = bpf_program__attach(prog);
155+ if (!ASSERT_OK_PTR(skel->links.handle_downsize, "prog_attach"))
156+ goto cleanup;
157+
158+ prog = bpf_object__find_program_by_name(skel->obj, "handle_probed");
159+ if (!ASSERT_OK_PTR(prog, "prog_find"))
160+ goto cleanup;
161+ skel->links.handle_probed = bpf_program__attach(prog);
162+ if (!ASSERT_OK_PTR(skel->links.handle_probed, "prog_attach"))
163+ goto cleanup;
164+
165+ usleep(1);
166+
167+ bss_map = bpf_object__find_map_by_name(skel->obj, "test_cor.bss");
168+ if (!ASSERT_OK_PTR(bss_map, "bss_map_find"))
169+ goto cleanup;
170+
171+ err = bpf_map_lookup_elem(bpf_map__fd(bss_map), &zero, (void *)&out);
172+ if (!ASSERT_OK(err, "bss_lookup"))
173+ goto cleanup;
174+
175+ ASSERT_EQ(out.ptr_samesized, 0x01020304, "ptr_samesized");
176+ ASSERT_EQ(out.val1_samesized, 0x1020304050607080, "val1_samesized");
177+ ASSERT_EQ(out.val2_samesized, 0x0a0b0c0d, "val2_samesized");
178+ ASSERT_EQ(out.val3_samesized, 0xfeed, "val3_samesized");
179+ ASSERT_EQ(out.val4_samesized, 0xb9, "val4_samesized");
180+ ASSERT_EQ(out.output_samesized.ptr, 0x01020304, "ptr_samesized");
181+ ASSERT_EQ(out.output_samesized.val1, 0x1020304050607080, "val1_samesized");
182+ ASSERT_EQ(out.output_samesized.val2, 0x0a0b0c0d, "val2_samesized");
183+ ASSERT_EQ(out.output_samesized.val3, 0xfeed, "val3_samesized");
184+ ASSERT_EQ(out.output_samesized.val4, 0xb9, "val4_samesized");
185+
186+ ASSERT_EQ(out.ptr_downsized, 0x01020304, "ptr_downsized");
187+ ASSERT_EQ(out.val1_downsized, 0x1020304050607080, "val1_downsized");
188+ ASSERT_EQ(out.val2_downsized, 0x0a0b0c0d, "val2_downsized");
189+ ASSERT_EQ(out.val3_downsized, 0xfeed, "val3_downsized");
190+ ASSERT_EQ(out.val4_downsized, 0xb9, "val4_downsized");
191+ ASSERT_EQ(out.output_downsized.ptr, 0x01020304, "ptr_downsized");
192+ ASSERT_EQ(out.output_downsized.val1, 0x1020304050607080, "val1_downsized");
193+ ASSERT_EQ(out.output_downsized.val2, 0x0a0b0c0d, "val2_downsized");
194+ ASSERT_EQ(out.output_downsized.val3, 0xfeed, "val3_downsized");
195+ ASSERT_EQ(out.output_downsized.val4, 0xb9, "val4_downsized");
196+
197+ ASSERT_EQ(out.ptr_probed, 0x01020304, "ptr_probed");
198+ ASSERT_EQ(out.val1_probed, 0x1020304050607080, "val1_probed");
199+ ASSERT_EQ(out.val2_probed, 0x0a0b0c0d, "val2_probed");
200+ ASSERT_EQ(out.val3_probed, 0xfeed, "val3_probed");
201+ ASSERT_EQ(out.val4_probed, 0xb9, "val4_probed");
202+
203+ test_core_autosize__destroy(skel);
204+ skel = NULL;
205+
206+ /* now re-load with handle_signed() enabled, it should fail loading */
207+ skel = test_core_autosize__open();
208+ if (!ASSERT_OK_PTR(skel, "skel_open"))
209+ return;
210+
211+ load_attr.obj = skel->obj;
212+ load_attr.target_btf_path = btf_file;
213+ err = bpf_object__load_xattr(&load_attr);
214+ if (!ASSERT_ERR(err, "bad_prog_load"))
215+ goto cleanup;
216+
217+cleanup:
218+ if (f)
219+ fclose(f);
220+ if (fd >= 0)
221+ close(fd);
222+ remove(btf_file);
223+ btf__free(btf);
224+ test_core_autosize__destroy(skel);
225+}
tools/testing/selftests/bpf/prog_tests/ksyms.c+13−25
@@ -7,40 +7,28 @@ · 6 unmodified lines
77
88 static int duration;
99
10−static __u64 kallsyms_find(const char *sym)
11−{
12− char type, name[500];
13− __u64 addr, res = 0;
14− FILE *f;
15−
16− f = fopen("/proc/kallsyms", "r");
17− if (CHECK(!f, "kallsyms_fopen", "failed to open: %d\n", errno))
18− return 0;
19−
20− while (fscanf(f, "%llx %c %499s%*[^\n]\n", &addr, &type, name) > 0) {
21− if (strcmp(name, sym) == 0) {
22− res = addr;
23− goto out;
24− }
25− }
26−
27− CHECK(false, "not_found", "symbol %s not found\n", sym);
28−out:
29− fclose(f);
30− return res;
31−}
32−
3310 void test_ksyms(void)
3411 {
35− __u64 per_cpu_start_addr = kallsyms_find("__per_cpu_start");
36− __u64 link_fops_addr = kallsyms_find("bpf_link_fops");
3712 const char *btf_path = "/sys/kernel/btf/vmlinux";
3813 struct test_ksyms *skel;
3914 struct test_ksyms__data *data;
15+ __u64 link_fops_addr, per_cpu_start_addr;
4016 struct stat st;
4117 __u64 btf_size;
4218 int err;
4319
20+ err = kallsyms_find("bpf_link_fops", &link_fops_addr);
21+ if (CHECK(err == -EINVAL, "kallsyms_fopen", "failed to open: %d\n", errno))
22+ return;
23+ if (CHECK(err == -ENOENT, "ksym_find", "symbol 'bpf_link_fops' not found\n"))
24+ return;
25+
26+ err = kallsyms_find("__per_cpu_start", &per_cpu_start_addr);
27+ if (CHECK(err == -EINVAL, "kallsyms_fopen", "failed to open: %d\n", errno))
28+ return;
29+ if (CHECK(err == -ENOENT, "ksym_find", "symbol 'per_cpu_start' not found\n"))
30+ return;
31+
4432 if (CHECK(stat(btf_path, &st), "stat_btf", "err %d\n", errno))
4533 return;
4634 btf_size = st.st_size;
tools/testing/selftests/bpf/prog_tests/ksyms_btf.c+88−0
@@ -0,0 +1,88 @@
1+// SPDX-License-Identifier: GPL-2.0
2+/* Copyright (c) 2020 Google */
3+
4+#include <test_progs.h>
5+#include <bpf/libbpf.h>
6+#include <bpf/btf.h>
7+#include "test_ksyms_btf.skel.h"
8+
9+static int duration;
10+
11+void test_ksyms_btf(void)
12+{
13+ __u64 runqueues_addr, bpf_prog_active_addr;
14+ __u32 this_rq_cpu;
15+ int this_bpf_prog_active;
16+ struct test_ksyms_btf *skel = NULL;
17+ struct test_ksyms_btf__data *data;
18+ struct btf *btf;
19+ int percpu_datasec;
20+ int err;
21+
22+ err = kallsyms_find("runqueues", &runqueues_addr);
23+ if (CHECK(err == -EINVAL, "kallsyms_fopen", "failed to open: %d\n", errno))
24+ return;
25+ if (CHECK(err == -ENOENT, "ksym_find", "symbol 'runqueues' not found\n"))
26+ return;
27+
28+ err = kallsyms_find("bpf_prog_active", &bpf_prog_active_addr);
29+ if (CHECK(err == -EINVAL, "kallsyms_fopen", "failed to open: %d\n", errno))
30+ return;
31+ if (CHECK(err == -ENOENT, "ksym_find", "symbol 'bpf_prog_active' not found\n"))
32+ return;
33+
34+ btf = libbpf_find_kernel_btf();
35+ if (CHECK(IS_ERR(btf), "btf_exists", "failed to load kernel BTF: %ld\n",
36+ PTR_ERR(btf)))
37+ return;
38+
39+ percpu_datasec = btf__find_by_name_kind(btf, ".data..percpu",
40+ BTF_KIND_DATASEC);
41+ if (percpu_datasec < 0) {
42+ printf("%s:SKIP:no PERCPU DATASEC in kernel btf\n",
43+ __func__);
44+ test__skip();
45+ goto cleanup;
46+ }
47+
48+ skel = test_ksyms_btf__open_and_load();
49+ if (CHECK(!skel, "skel_open", "failed to open and load skeleton\n"))
50+ goto cleanup;
51+
52+ err = test_ksyms_btf__attach(skel);
53+ if (CHECK(err, "skel_attach", "skeleton attach failed: %d\n", err))
54+ goto cleanup;
55+
56+ /* trigger tracepoint */
57+ usleep(1);
58+
59+ data = skel->data;
60+ CHECK(data->out__runqueues_addr != runqueues_addr, "runqueues_addr",
61+ "got %llu, exp %llu\n",
62+ (unsigned long long)data->out__runqueues_addr,
63+ (unsigned long long)runqueues_addr);
64+ CHECK(data->out__bpf_prog_active_addr != bpf_prog_active_addr, "bpf_prog_active_addr",
65+ "got %llu, exp %llu\n",
66+ (unsigned long long)data->out__bpf_prog_active_addr,
67+ (unsigned long long)bpf_prog_active_addr);
68+
69+ CHECK(data->out__rq_cpu == -1, "rq_cpu",
70+ "got %u, exp != -1\n", data->out__rq_cpu);
71+ CHECK(data->out__bpf_prog_active < 0, "bpf_prog_active",
72+ "got %d, exp >= 0\n", data->out__bpf_prog_active);
73+ CHECK(data->out__cpu_0_rq_cpu != 0, "cpu_rq(0)->cpu",
74+ "got %u, exp 0\n", data->out__cpu_0_rq_cpu);
75+
76+ this_rq_cpu = data->out__this_rq_cpu;
77+ CHECK(this_rq_cpu != data->out__rq_cpu, "this_rq_cpu",
78+ "got %u, exp %u\n", this_rq_cpu, data->out__rq_cpu);
79+
80+ this_bpf_prog_active = data->out__this_bpf_prog_active;
81+ CHECK(this_bpf_prog_active != data->out__bpf_prog_active, "this_bpf_prog_active",
82+ "got %d, exp %d\n", this_bpf_prog_active,
83+ data->out__bpf_prog_active);
84+
85+cleanup:
86+ btf__free(btf);
87+ test_ksyms_btf__destroy(skel);
88+}
tools/testing/selftests/bpf/prog_tests/pinning.c+48−1
@@ -37,7 +37,7 @@ void test_pinning(void) · 36 unmodified lines
3737 struct stat statbuf = {};
3838 struct bpf_object *obj;
3939 struct bpf_map *map;
40− int err;
40+ int err, map_fd;
4141 DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts,
4242 .pin_root_path = custpath,
4343 );
@@ -213,6 +213,53 @@ void test_pinning(void) · 169 unmodified lines
213213 if (CHECK(err, "stat custpinpath", "err %d errno %d\n", err, errno))
214214 goto out;
215215
216+ /* remove the custom pin path to re-test it with reuse fd below */
217+ err = unlink(custpinpath);
218+ if (CHECK(err, "unlink custpinpath", "err %d errno %d\n", err, errno))
219+ goto out;
220+
221+ err = rmdir(custpath);
222+ if (CHECK(err, "rmdir custpindir", "err %d errno %d\n", err, errno))
223+ goto out;
224+
225+ bpf_object__close(obj);
226+
227+ /* test pinning at custom path with reuse fd */
228+ obj = bpf_object__open_file(file, NULL);
229+ err = libbpf_get_error(obj);
230+ if (CHECK(err, "default open", "err %d errno %d\n", err, errno)) {
231+ obj = NULL;
232+ goto out;
233+ }
234+
235+ map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(__u32),
236+ sizeof(__u64), 1, 0);
237+ if (CHECK(map_fd < 0, "create pinmap manually", "fd %d\n", map_fd))
238+ goto out;
239+
240+ map = bpf_object__find_map_by_name(obj, "pinmap");
241+ if (CHECK(!map, "find map", "NULL map"))
242+ goto close_map_fd;
243+
244+ err = bpf_map__reuse_fd(map, map_fd);
245+ if (CHECK(err, "reuse pinmap fd", "err %d errno %d\n", err, errno))
246+ goto close_map_fd;
247+
248+ err = bpf_map__set_pin_path(map, custpinpath);
249+ if (CHECK(err, "set pin path", "err %d errno %d\n", err, errno))
250+ goto close_map_fd;
251+
252+ err = bpf_object__load(obj);
253+ if (CHECK(err, "custom load", "err %d errno %d\n", err, errno))
254+ goto close_map_fd;
255+
256+ /* check that pinmap was pinned at the custom path */
257+ err = stat(custpinpath, &statbuf);
258+ if (CHECK(err, "stat custpinpath", "err %d errno %d\n", err, errno))
259+ goto close_map_fd;
260+
261+close_map_fd:
262+ close(map_fd);
216263 out:
217264 unlink(pinpath);
218265 unlink(nopinpath);
tools/testing/selftests/bpf/prog_tests/sockmap_basic.c+1−1
@@ -198,7 +198,7 @@ static void test_sockmap_copy(enum bpf_map_type map_type) · 197 unmodified lines
198198 {
199199 DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
200200 int err, len, src_fd, iter_fd, duration = 0;
201− union bpf_iter_link_info linfo = {0};
201+ union bpf_iter_link_info linfo = {};
202202 __u32 i, num_sockets, num_elems;
203203 struct bpf_iter_sockmap *skel;
204204 __s64 *sock_fd = NULL;
tools/testing/selftests/bpf/prog_tests/tcp_hdr_options.c+12−0
@@ -264,9 +264,19 @@ static int check_error_linum(const struct sk_fds *sk_fds) · 263 unmodified lines
264264
265265 static void check_hdr_and_close_fds(struct sk_fds *sk_fds)
266266 {
267+ const __u32 expected_inherit_cb_flags =
268+ BPF_SOCK_OPS_PARSE_UNKNOWN_HDR_OPT_CB_FLAG |
269+ BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG |
270+ BPF_SOCK_OPS_STATE_CB_FLAG;
271+
267272 if (sk_fds_shutdown(sk_fds))
268273 goto check_linum;
269274
275+ if (CHECK(expected_inherit_cb_flags != skel->bss->inherit_cb_flags,
276+ "Unexpected inherit_cb_flags", "0x%x != 0x%x\n",
277+ skel->bss->inherit_cb_flags, expected_inherit_cb_flags))
278+ goto check_linum;
279+
270280 if (check_hdr_stg(&exp_passive_hdr_stg, sk_fds->passive_fd,
271281 "passive_hdr_stg"))
272282 goto check_linum;
@@ -321,6 +331,8 @@ static void reset_test(void) · 48 unmodified lines
321331 memset(&skel->bss->active_estab_in, 0, optsize);
322332 memset(&skel->bss->active_fin_in, 0, optsize);
323333
334+ skel->bss->inherit_cb_flags = 0;
335+
324336 skel->data->test_kind = TCPOPT_EXP;
325337 skel->data->test_magic = 0xeB9F;
326338
tools/testing/selftests/bpf/prog_tests/test_profiler.c+72−0
@@ -0,0 +1,72 @@
1+// SPDX-License-Identifier: GPL-2.0
2+/* Copyright (c) 2020 Facebook */
3+#include <test_progs.h>
4+#include "progs/profiler.h"
5+#include "profiler1.skel.h"
6+#include "profiler2.skel.h"
7+#include "profiler3.skel.h"
8+
9+static int sanity_run(struct bpf_program *prog)
10+{
11+ struct bpf_prog_test_run_attr test_attr = {};
12+ __u64 args[] = {1, 2, 3};
13+ __u32 duration = 0;
14+ int err, prog_fd;
15+
16+ prog_fd = bpf_program__fd(prog);
17+ test_attr.prog_fd = prog_fd;
18+ test_attr.ctx_in = args;
19+ test_attr.ctx_size_in = sizeof(args);
20+ err = bpf_prog_test_run_xattr(&test_attr);
21+ if (CHECK(err || test_attr.retval, "test_run",
22+ "err %d errno %d retval %d duration %d\n",
23+ err, errno, test_attr.retval, duration))
24+ return -1;
25+ return 0;
26+}
27+
28+void test_test_profiler(void)
29+{
30+ struct profiler1 *profiler1_skel = NULL;
31+ struct profiler2 *profiler2_skel = NULL;
32+ struct profiler3 *profiler3_skel = NULL;
33+ __u32 duration = 0;
34+ int err;
35+
36+ profiler1_skel = profiler1__open_and_load();
37+ if (CHECK(!profiler1_skel, "profiler1_skel_load", "profiler1 skeleton failed\n"))
38+ goto cleanup;
39+
40+ err = profiler1__attach(profiler1_skel);
41+ if (CHECK(err, "profiler1_attach", "profiler1 attach failed: %d\n", err))
42+ goto cleanup;
43+
44+ if (sanity_run(profiler1_skel->progs.raw_tracepoint__sched_process_exec))
45+ goto cleanup;
46+
47+ profiler2_skel = profiler2__open_and_load();
48+ if (CHECK(!profiler2_skel, "profiler2_skel_load", "profiler2 skeleton failed\n"))
49+ goto cleanup;
50+
51+ err = profiler2__attach(profiler2_skel);
52+ if (CHECK(err, "profiler2_attach", "profiler2 attach failed: %d\n", err))
53+ goto cleanup;
54+
55+ if (sanity_run(profiler2_skel->progs.raw_tracepoint__sched_process_exec))
56+ goto cleanup;
57+
58+ profiler3_skel = profiler3__open_and_load();
59+ if (CHECK(!profiler3_skel, "profiler3_skel_load", "profiler3 skeleton failed\n"))
60+ goto cleanup;
61+
62+ err = profiler3__attach(profiler3_skel);
63+ if (CHECK(err, "profiler3_attach", "profiler3 attach failed: %d\n", err))
64+ goto cleanup;
65+
66+ if (sanity_run(profiler3_skel->progs.raw_tracepoint__sched_process_exec))
67+ goto cleanup;
68+cleanup:
69+ profiler1__destroy(profiler1_skel);
70+ profiler2__destroy(profiler2_skel);
71+ profiler3__destroy(profiler3_skel);
72+}
tools/testing/selftests/bpf/prog_tests/xdp_noinline.c+1−1
@@ -25,7 +25,7 @@ void test_xdp_noinline(void) · 24 unmodified lines
2525 __u8 flags;
2626 } real_def = {.dst = MAGIC_VAL};
2727 __u32 ch_key = 11, real_num = 3;
28− __u32 duration, retval, size;
28+ __u32 duration = 0, retval, size;
2929 int err, i;
3030 __u64 bytes = 0, pkts = 0;
3131 char buf[128];
tools/testing/selftests/bpf/progs/connect4_prog.c+19−0
@@ -23,6 +23,10 @@ · 22 unmodified lines
2323 #define TCP_CA_NAME_MAX 16
2424 #endif
2525
26+#ifndef TCP_NOTSENT_LOWAT
27+#define TCP_NOTSENT_LOWAT 25
28+#endif
29+
2630 #ifndef IFNAMSIZ
2731 #define IFNAMSIZ 16
2832 #endif
@@ -128,6 +132,18 @@ static __inline int set_keepalive(struct bpf_sock_addr *ctx) · 99 unmodified lines
128132 return 0;
129133 }
130134
135+static __inline int set_notsent_lowat(struct bpf_sock_addr *ctx)
136+{
137+ int lowat = 65535;
138+
139+ if (ctx->type == SOCK_STREAM) {
140+ if (bpf_setsockopt(ctx, SOL_TCP, TCP_NOTSENT_LOWAT, &lowat, sizeof(lowat)))
141+ return 1;
142+ }
143+
144+ return 0;
145+}
146+
131147 SEC("cgroup/connect4")
132148 int connect_v4_prog(struct bpf_sock_addr *ctx)
133149 {
@@ -148,6 +164,9 @@ int connect_v4_prog(struct bpf_sock_addr *ctx) · 14 unmodified lines
148164 if (set_keepalive(ctx))
149165 return 0;
150166
167+ if (set_notsent_lowat(ctx))
168+ return 0;
169+
151170 if (ctx->type != SOCK_STREAM && ctx->type != SOCK_DGRAM)
152171 return 0;
153172 else if (ctx->type == SOCK_STREAM)
tools/testing/selftests/bpf/progs/profiler.h+177−0
@@ -0,0 +1,177 @@
1+// SPDX-License-Identifier: GPL-2.0
2+/* Copyright (c) 2020 Facebook */
3+#pragma once
4+
5+#define TASK_COMM_LEN 16
6+#define MAX_ANCESTORS 4
7+#define MAX_PATH 256
8+#define KILL_TARGET_LEN 64
9+#define CTL_MAXNAME 10
10+#define MAX_ARGS_LEN 4096
11+#define MAX_FILENAME_LEN 512
12+#define MAX_ENVIRON_LEN 8192
13+#define MAX_PATH_DEPTH 32
14+#define MAX_FILEPATH_LENGTH (MAX_PATH_DEPTH * MAX_PATH)
15+#define MAX_CGROUPS_PATH_DEPTH 8
16+
17+#define MAX_METADATA_PAYLOAD_LEN TASK_COMM_LEN
18+
19+#define MAX_CGROUP_PAYLOAD_LEN \
20+ (MAX_PATH * 2 + (MAX_PATH * MAX_CGROUPS_PATH_DEPTH))
21+
22+#define MAX_CAP_PAYLOAD_LEN (MAX_METADATA_PAYLOAD_LEN + MAX_CGROUP_PAYLOAD_LEN)
23+
24+#define MAX_SYSCTL_PAYLOAD_LEN \
25+ (MAX_METADATA_PAYLOAD_LEN + MAX_CGROUP_PAYLOAD_LEN + CTL_MAXNAME + MAX_PATH)
26+
27+#define MAX_KILL_PAYLOAD_LEN \
28+ (MAX_METADATA_PAYLOAD_LEN + MAX_CGROUP_PAYLOAD_LEN + TASK_COMM_LEN + \
29+ KILL_TARGET_LEN)
30+
31+#define MAX_EXEC_PAYLOAD_LEN \
32+ (MAX_METADATA_PAYLOAD_LEN + MAX_CGROUP_PAYLOAD_LEN + MAX_FILENAME_LEN + \
33+ MAX_ARGS_LEN + MAX_ENVIRON_LEN)
34+
35+#define MAX_FILEMOD_PAYLOAD_LEN \
36+ (MAX_METADATA_PAYLOAD_LEN + MAX_CGROUP_PAYLOAD_LEN + MAX_FILEPATH_LENGTH + \
37+ MAX_FILEPATH_LENGTH)
38+
39+enum data_type {
40+ INVALID_EVENT,
41+ EXEC_EVENT,
42+ FORK_EVENT,
43+ KILL_EVENT,
44+ SYSCTL_EVENT,
45+ FILEMOD_EVENT,
46+ MAX_DATA_TYPE_EVENT
47+};
48+
49+enum filemod_type {
50+ FMOD_OPEN,
51+ FMOD_LINK,
52+ FMOD_SYMLINK,
53+};
54+
55+struct ancestors_data_t {
56+ pid_t ancestor_pids[MAX_ANCESTORS];
57+ uint32_t ancestor_exec_ids[MAX_ANCESTORS];
58+ uint64_t ancestor_start_times[MAX_ANCESTORS];
59+ uint32_t num_ancestors;
60+};
61+
62+struct var_metadata_t {
63+ enum data_type type;
64+ pid_t pid;
65+ uint32_t exec_id;
66+ uid_t uid;
67+ gid_t gid;
68+ uint64_t start_time;
69+ uint32_t cpu_id;
70+ uint64_t bpf_stats_num_perf_events;
71+ uint64_t bpf_stats_start_ktime_ns;
72+ uint8_t comm_length;
73+};
74+
75+struct cgroup_data_t {
76+ ino_t cgroup_root_inode;
77+ ino_t cgroup_proc_inode;
78+ uint64_t cgroup_root_mtime;
79+ uint64_t cgroup_proc_mtime;
80+ uint16_t cgroup_root_length;
81+ uint16_t cgroup_proc_length;
82+ uint16_t cgroup_full_length;
83+ int cgroup_full_path_root_pos;
84+};
85+
86+struct var_sysctl_data_t {
87+ struct var_metadata_t meta;
88+ struct cgroup_data_t cgroup_data;
89+ struct ancestors_data_t ancestors_info;
90+ uint8_t sysctl_val_length;
91+ uint16_t sysctl_path_length;
92+ char payload[MAX_SYSCTL_PAYLOAD_LEN];
93+};
94+
95+struct var_kill_data_t {
96+ struct var_metadata_t meta;
97+ struct cgroup_data_t cgroup_data;
98+ struct ancestors_data_t ancestors_info;
99+ pid_t kill_target_pid;
100+ int kill_sig;
101+ uint32_t kill_count;
102+ uint64_t last_kill_time;
103+ uint8_t kill_target_name_length;
104+ uint8_t kill_target_cgroup_proc_length;
105+ char payload[MAX_KILL_PAYLOAD_LEN];
106+ size_t payload_length;
107+};
108+
109+struct var_exec_data_t {
110+ struct var_metadata_t meta;
111+ struct cgroup_data_t cgroup_data;
112+ pid_t parent_pid;
113+ uint32_t parent_exec_id;
114+ uid_t parent_uid;
115+ uint64_t parent_start_time;
116+ uint16_t bin_path_length;
117+ uint16_t cmdline_length;
118+ uint16_t environment_length;
119+ char payload[MAX_EXEC_PAYLOAD_LEN];
120+};
121+
122+struct var_fork_data_t {
123+ struct var_metadata_t meta;
124+ pid_t parent_pid;
125+ uint32_t parent_exec_id;
126+ uint64_t parent_start_time;
127+ char payload[MAX_METADATA_PAYLOAD_LEN];
128+};
129+
130+struct var_filemod_data_t {
131+ struct var_metadata_t meta;
132+ struct cgroup_data_t cgroup_data;
133+ enum filemod_type fmod_type;
134+ unsigned int dst_flags;
135+ uint32_t src_device_id;
136+ uint32_t dst_device_id;
137+ ino_t src_inode;
138+ ino_t dst_inode;
139+ uint16_t src_filepath_length;
140+ uint16_t dst_filepath_length;
141+ char payload[MAX_FILEMOD_PAYLOAD_LEN];
142+};
143+
144+struct profiler_config_struct {
145+ bool fetch_cgroups_from_bpf;
146+ ino_t cgroup_fs_inode;
147+ ino_t cgroup_login_session_inode;
148+ uint64_t kill_signals_mask;
149+ ino_t inode_filter;
150+ uint32_t stale_info_secs;
151+ bool use_variable_buffers;
152+ bool read_environ_from_exec;
153+ bool enable_cgroup_v1_resolver;
154+};
155+
156+struct bpf_func_stats_data {
157+ uint64_t time_elapsed_ns;
158+ uint64_t num_executions;
159+ uint64_t num_perf_events;
160+};
161+
162+struct bpf_func_stats_ctx {
163+ uint64_t start_time_ns;
164+ struct bpf_func_stats_data* bpf_func_stats_data_val;
165+};
166+
167+enum bpf_function_id {
168+ profiler_bpf_proc_sys_write,
169+ profiler_bpf_sched_process_exec,
170+ profiler_bpf_sched_process_exit,
171+ profiler_bpf_sys_enter_kill,
172+ profiler_bpf_do_filp_open_ret,
173+ profiler_bpf_sched_process_fork,
174+ profiler_bpf_vfs_link,
175+ profiler_bpf_vfs_symlink,
176+ profiler_bpf_max_function_id
177+};
tools/testing/selftests/bpf/progs/profiler.inc.h+969−0
@@ -0,0 +1,969 @@
1+// SPDX-License-Identifier: GPL-2.0
2+/* Copyright (c) 2020 Facebook */
3+#include <vmlinux.h>
4+#include <bpf/bpf_core_read.h>
5+#include <bpf/bpf_helpers.h>
6+#include <bpf/bpf_tracing.h>
7+
8+#include "profiler.h"
9+
10+#ifndef NULL
11+#define NULL 0
12+#endif
13+
14+#define O_WRONLY 00000001
15+#define O_RDWR 00000002
16+#define O_DIRECTORY 00200000
17+#define __O_TMPFILE 020000000
18+#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY)
19+#define MAX_ERRNO 4095
20+#define S_IFMT 00170000
21+#define S_IFSOCK 0140000
22+#define S_IFLNK 0120000
23+#define S_IFREG 0100000
24+#define S_IFBLK 0060000
25+#define S_IFDIR 0040000
26+#define S_IFCHR 0020000
27+#define S_IFIFO 0010000
28+#define S_ISUID 0004000
29+#define S_ISGID 0002000
30+#define S_ISVTX 0001000
31+#define S_ISLNK(m) (((m)&S_IFMT) == S_IFLNK)
32+#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
33+#define S_ISCHR(m) (((m)&S_IFMT) == S_IFCHR)
34+#define S_ISBLK(m) (((m)&S_IFMT) == S_IFBLK)
35+#define S_ISFIFO(m) (((m)&S_IFMT) == S_IFIFO)
36+#define S_ISSOCK(m) (((m)&S_IFMT) == S_IFSOCK)
37+#define IS_ERR_VALUE(x) (unsigned long)(void*)(x) >= (unsigned long)-MAX_ERRNO
38+
39+#define KILL_DATA_ARRAY_SIZE 8
40+
41+struct var_kill_data_arr_t {
42+ struct var_kill_data_t array[KILL_DATA_ARRAY_SIZE];
43+};
44+
45+union any_profiler_data_t {
46+ struct var_exec_data_t var_exec;
47+ struct var_kill_data_t var_kill;
48+ struct var_sysctl_data_t var_sysctl;
49+ struct var_filemod_data_t var_filemod;
50+ struct var_fork_data_t var_fork;
51+ struct var_kill_data_arr_t var_kill_data_arr;
52+};
53+
54+volatile struct profiler_config_struct bpf_config = {};
55+
56+#define FETCH_CGROUPS_FROM_BPF (bpf_config.fetch_cgroups_from_bpf)
57+#define CGROUP_FS_INODE (bpf_config.cgroup_fs_inode)
58+#define CGROUP_LOGIN_SESSION_INODE \
59+ (bpf_config.cgroup_login_session_inode)
60+#define KILL_SIGNALS (bpf_config.kill_signals_mask)
61+#define STALE_INFO (bpf_config.stale_info_secs)
62+#define INODE_FILTER (bpf_config.inode_filter)
63+#define READ_ENVIRON_FROM_EXEC (bpf_config.read_environ_from_exec)
64+#define ENABLE_CGROUP_V1_RESOLVER (bpf_config.enable_cgroup_v1_resolver)
65+
66+struct kernfs_iattrs___52 {
67+ struct iattr ia_iattr;
68+};
69+
70+struct kernfs_node___52 {
71+ union /* kernfs_node_id */ {
72+ struct {
73+ u32 ino;
74+ u32 generation;
75+ };
76+ u64 id;
77+ } id;
78+};
79+
80+struct {
81+ __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
82+ __uint(max_entries, 1);
83+ __type(key, u32);
84+ __type(value, union any_profiler_data_t);
85+} data_heap SEC(".maps");
86+
87+struct {
88+ __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
89+ __uint(key_size, sizeof(int));
90+ __uint(value_size, sizeof(int));
91+} events SEC(".maps");
92+
93+struct {
94+ __uint(type, BPF_MAP_TYPE_HASH);
95+ __uint(max_entries, KILL_DATA_ARRAY_SIZE);
96+ __type(key, u32);
97+ __type(value, struct var_kill_data_arr_t);
98+} var_tpid_to_data SEC(".maps");
99+
100+struct {
101+ __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
102+ __uint(max_entries, profiler_bpf_max_function_id);
103+ __type(key, u32);
104+ __type(value, struct bpf_func_stats_data);
105+} bpf_func_stats SEC(".maps");
106+
107+struct {
108+ __uint(type, BPF_MAP_TYPE_HASH);
109+ __type(key, u32);
110+ __type(value, bool);
111+ __uint(max_entries, 16);
112+} allowed_devices SEC(".maps");
113+
114+struct {
115+ __uint(type, BPF_MAP_TYPE_HASH);
116+ __type(key, u64);
117+ __type(value, bool);
118+ __uint(max_entries, 1024);
119+} allowed_file_inodes SEC(".maps");
120+
121+struct {
122+ __uint(type, BPF_MAP_TYPE_HASH);
123+ __type(key, u64);
124+ __type(value, bool);
125+ __uint(max_entries, 1024);
126+} allowed_directory_inodes SEC(".maps");
127+
128+struct {
129+ __uint(type, BPF_MAP_TYPE_HASH);
130+ __type(key, u32);
131+ __type(value, bool);
132+ __uint(max_entries, 16);
133+} disallowed_exec_inodes SEC(".maps");
134+
135+#ifndef ARRAY_SIZE
136+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
137+#endif
138+
139+static INLINE bool IS_ERR(const void* ptr)
140+{
141+ return IS_ERR_VALUE((unsigned long)ptr);
142+}
143+
144+static INLINE u32 get_userspace_pid()
145+{
146+ return bpf_get_current_pid_tgid() >> 32;
147+}
148+
149+static INLINE bool is_init_process(u32 tgid)
150+{
151+ return tgid == 1 || tgid == 0;
152+}
153+
154+static INLINE unsigned long
155+probe_read_lim(void* dst, void* src, unsigned long len, unsigned long max)
156+{
157+ len = len < max ? len : max;
158+ if (len > 1) {
159+ if (bpf_probe_read(dst, len, src))
160+ return 0;
161+ } else if (len == 1) {
162+ if (bpf_probe_read(dst, 1, src))
163+ return 0;
164+ }
165+ return len;
166+}
167+
168+static INLINE int get_var_spid_index(struct var_kill_data_arr_t* arr_struct,
169+ int spid)
170+{
171+#ifdef UNROLL
172+#pragma unroll
173+#endif
174+ for (int i = 0; i < ARRAY_SIZE(arr_struct->array); i++)
175+ if (arr_struct->array[i].meta.pid == spid)
176+ return i;
177+ return -1;
178+}
179+
180+static INLINE void populate_ancestors(struct task_struct* task,
181+ struct ancestors_data_t* ancestors_data)
182+{
183+ struct task_struct* parent = task;
184+ u32 num_ancestors, ppid;
185+
186+ ancestors_data->num_ancestors = 0;
187+#ifdef UNROLL
188+#pragma unroll
189+#endif
190+ for (num_ancestors = 0; num_ancestors < MAX_ANCESTORS; num_ancestors++) {
191+ parent = BPF_CORE_READ(parent, real_parent);
192+ if (parent == NULL)
193+ break;
194+ ppid = BPF_CORE_READ(parent, tgid);
195+ if (is_init_process(ppid))
196+ break;
197+ ancestors_data->ancestor_pids[num_ancestors] = ppid;
198+ ancestors_data->ancestor_exec_ids[num_ancestors] =
199+ BPF_CORE_READ(parent, self_exec_id);
200+ ancestors_data->ancestor_start_times[num_ancestors] =
201+ BPF_CORE_READ(parent, start_time);
202+ ancestors_data->num_ancestors = num_ancestors;
203+ }
204+}
205+
206+static INLINE void* read_full_cgroup_path(struct kernfs_node* cgroup_node,
207+ struct kernfs_node* cgroup_root_node,
208+ void* payload,
209+ int* root_pos)
210+{
211+ void* payload_start = payload;
212+ size_t filepart_length;
213+
214+#ifdef UNROLL
215+#pragma unroll
216+#endif
217+ for (int i = 0; i < MAX_CGROUPS_PATH_DEPTH; i++) {
218+ filepart_length =
219+ bpf_probe_read_str(payload, MAX_PATH, BPF_CORE_READ(cgroup_node, name));
220+ if (!cgroup_node)
221+ return payload;
222+ if (cgroup_node == cgroup_root_node)
223+ *root_pos = payload - payload_start;
224+ if (filepart_length <= MAX_PATH) {
225+ barrier_var(filepart_length);
226+ payload += filepart_length;
227+ }
228+ cgroup_node = BPF_CORE_READ(cgroup_node, parent);
229+ }
230+ return payload;
231+}
232+
233+static ino_t get_inode_from_kernfs(struct kernfs_node* node)
234+{
235+ struct kernfs_node___52* node52 = (void*)node;
236+
237+ if (bpf_core_field_exists(node52->id.ino)) {
238+ barrier_var(node52);
239+ return BPF_CORE_READ(node52, id.ino);
240+ } else {
241+ barrier_var(node);
242+ return (u64)BPF_CORE_READ(node, id);
243+ }
244+}
245+
246+int pids_cgrp_id = 1;
247+
248+static INLINE void* populate_cgroup_info(struct cgroup_data_t* cgroup_data,
249+ struct task_struct* task,
250+ void* payload)
251+{
252+ struct kernfs_node* root_kernfs =
253+ BPF_CORE_READ(task, nsproxy, cgroup_ns, root_cset, dfl_cgrp, kn);
254+ struct kernfs_node* proc_kernfs = BPF_CORE_READ(task, cgroups, dfl_cgrp, kn);
255+
256+ if (ENABLE_CGROUP_V1_RESOLVER) {
257+#ifdef UNROLL
258+#pragma unroll
259+#endif
260+ for (int i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
261+ struct cgroup_subsys_state* subsys =
262+ BPF_CORE_READ(task, cgroups, subsys[i]);
263+ if (subsys != NULL) {
264+ int subsys_id = BPF_CORE_READ(subsys, ss, id);
265+ if (subsys_id == pids_cgrp_id) {
266+ proc_kernfs = BPF_CORE_READ(subsys, cgroup, kn);
267+ root_kernfs = BPF_CORE_READ(subsys, ss, root, kf_root, kn);
268+ break;
269+ }
270+ }
271+ }
272+ }
273+
274+ cgroup_data->cgroup_root_inode = get_inode_from_kernfs(root_kernfs);
275+ cgroup_data->cgroup_proc_inode = get_inode_from_kernfs(proc_kernfs);
276+
277+ if (bpf_core_field_exists(root_kernfs->iattr->ia_mtime)) {
278+ cgroup_data->cgroup_root_mtime =
279+ BPF_CORE_READ(root_kernfs, iattr, ia_mtime.tv_nsec);
280+ cgroup_data->cgroup_proc_mtime =
281+ BPF_CORE_READ(proc_kernfs, iattr, ia_mtime.tv_nsec);
282+ } else {
283+ struct kernfs_iattrs___52* root_iattr =
284+ (struct kernfs_iattrs___52*)BPF_CORE_READ(root_kernfs, iattr);
285+ cgroup_data->cgroup_root_mtime =
286+ BPF_CORE_READ(root_iattr, ia_iattr.ia_mtime.tv_nsec);
287+
288+ struct kernfs_iattrs___52* proc_iattr =
289+ (struct kernfs_iattrs___52*)BPF_CORE_READ(proc_kernfs, iattr);
290+ cgroup_data->cgroup_proc_mtime =
291+ BPF_CORE_READ(proc_iattr, ia_iattr.ia_mtime.tv_nsec);
292+ }
293+
294+ cgroup_data->cgroup_root_length = 0;
295+ cgroup_data->cgroup_proc_length = 0;
296+ cgroup_data->cgroup_full_length = 0;
297+
298+ size_t cgroup_root_length =
299+ bpf_probe_read_str(payload, MAX_PATH, BPF_CORE_READ(root_kernfs, name));
300+ barrier_var(cgroup_root_length);
301+ if (cgroup_root_length <= MAX_PATH) {
302+ barrier_var(cgroup_root_length);
303+ cgroup_data->cgroup_root_length = cgroup_root_length;
304+ payload += cgroup_root_length;
305+ }
306+
307+ size_t cgroup_proc_length =
308+ bpf_probe_read_str(payload, MAX_PATH, BPF_CORE_READ(proc_kernfs, name));
309+ barrier_var(cgroup_proc_length);
310+ if (cgroup_proc_length <= MAX_PATH) {
311+ barrier_var(cgroup_proc_length);
312+ cgroup_data->cgroup_proc_length = cgroup_proc_length;
313+ payload += cgroup_proc_length;
314+ }
315+
316+ if (FETCH_CGROUPS_FROM_BPF) {
317+ cgroup_data->cgroup_full_path_root_pos = -1;
318+ void* payload_end_pos = read_full_cgroup_path(proc_kernfs, root_kernfs, payload,
319+ &cgroup_data->cgroup_full_path_root_pos);
320+ cgroup_data->cgroup_full_length = payload_end_pos - payload;
321+ payload = payload_end_pos;
322+ }
323+
324+ return (void*)payload;
325+}
326+
327+static INLINE void* populate_var_metadata(struct var_metadata_t* metadata,
328+ struct task_struct* task,
329+ u32 pid, void* payload)
330+{
331+ u64 uid_gid = bpf_get_current_uid_gid();
332+
333+ metadata->uid = (u32)uid_gid;
334+ metadata->gid = uid_gid >> 32;
335+ metadata->pid = pid;
336+ metadata->exec_id = BPF_CORE_READ(task, self_exec_id);
337+ metadata->start_time = BPF_CORE_READ(task, start_time);
338+ metadata->comm_length = 0;
339+
340+ size_t comm_length = bpf_core_read_str(payload, TASK_COMM_LEN, &task->comm);
341+ barrier_var(comm_length);
342+ if (comm_length <= TASK_COMM_LEN) {
343+ barrier_var(comm_length);
344+ metadata->comm_length = comm_length;
345+ payload += comm_length;
346+ }
347+
348+ return (void*)payload;
349+}
350+
351+static INLINE struct var_kill_data_t*
352+get_var_kill_data(struct pt_regs* ctx, int spid, int tpid, int sig)
353+{
354+ int zero = 0;
355+ struct var_kill_data_t* kill_data = bpf_map_lookup_elem(&data_heap, &zero);
356+
357+ if (kill_data == NULL)
358+ return NULL;
359+ struct task_struct* task = (struct task_struct*)bpf_get_current_task();
360+
361+ void* payload = populate_var_metadata(&kill_data->meta, task, spid, kill_data->payload);
362+ payload = populate_cgroup_info(&kill_data->cgroup_data, task, payload);
363+ size_t payload_length = payload - (void*)kill_data->payload;
364+ kill_data->payload_length = payload_length;
365+ populate_ancestors(task, &kill_data->ancestors_info);
366+ kill_data->meta.type = KILL_EVENT;
367+ kill_data->kill_target_pid = tpid;
368+ kill_data->kill_sig = sig;
369+ kill_data->kill_count = 1;
370+ kill_data->last_kill_time = bpf_ktime_get_ns();
371+ return kill_data;
372+}
373+
374+static INLINE int trace_var_sys_kill(void* ctx, int tpid, int sig)
375+{
376+ if ((KILL_SIGNALS & (1ULL << sig)) == 0)
377+ return 0;
378+
379+ u32 spid = get_userspace_pid();
380+ struct var_kill_data_arr_t* arr_struct = bpf_map_lookup_elem(&var_tpid_to_data, &tpid);
381+
382+ if (arr_struct == NULL) {
383+ struct var_kill_data_t* kill_data = get_var_kill_data(ctx, spid, tpid, sig);
384+ int zero = 0;
385+
386+ if (kill_data == NULL)
387+ return 0;
388+ arr_struct = bpf_map_lookup_elem(&data_heap, &zero);
389+ if (arr_struct == NULL)
390+ return 0;
391+ bpf_probe_read(&arr_struct->array[0], sizeof(arr_struct->array[0]), kill_data);
392+ } else {
393+ int index = get_var_spid_index(arr_struct, spid);
394+
395+ if (index == -1) {
396+ struct var_kill_data_t* kill_data =
397+ get_var_kill_data(ctx, spid, tpid, sig);
398+ if (kill_data == NULL)
399+ return 0;
400+#ifdef UNROLL
401+#pragma unroll
402+#endif
403+ for (int i = 0; i < ARRAY_SIZE(arr_struct->array); i++)
404+ if (arr_struct->array[i].meta.pid == 0) {
405+ bpf_probe_read(&arr_struct->array[i],
406+ sizeof(arr_struct->array[i]), kill_data);
407+ bpf_map_update_elem(&var_tpid_to_data, &tpid,
408+ arr_struct, 0);
409+
410+ return 0;
411+ }
412+ return 0;
413+ }
414+
415+ struct var_kill_data_t* kill_data = &arr_struct->array[index];
416+
417+ u64 delta_sec =
418+ (bpf_ktime_get_ns() - kill_data->last_kill_time) / 1000000000;
419+
420+ if (delta_sec < STALE_INFO) {
421+ kill_data->kill_count++;
422+ kill_data->last_kill_time = bpf_ktime_get_ns();
423+ bpf_probe_read(&arr_struct->array[index],
424+ sizeof(arr_struct->array[index]),
425+ kill_data);
426+ } else {
427+ struct var_kill_data_t* kill_data =
428+ get_var_kill_data(ctx, spid, tpid, sig);
429+ if (kill_data == NULL)
430+ return 0;
431+ bpf_probe_read(&arr_struct->array[index],
432+ sizeof(arr_struct->array[index]),
433+ kill_data);
434+ }
435+ }
436+ bpf_map_update_elem(&var_tpid_to_data, &tpid, arr_struct, 0);
437+ return 0;
438+}
439+
440+static INLINE void bpf_stats_enter(struct bpf_func_stats_ctx* bpf_stat_ctx,
441+ enum bpf_function_id func_id)
442+{
443+ int func_id_key = func_id;
444+
445+ bpf_stat_ctx->start_time_ns = bpf_ktime_get_ns();
446+ bpf_stat_ctx->bpf_func_stats_data_val =
447+ bpf_map_lookup_elem(&bpf_func_stats, &func_id_key);
448+ if (bpf_stat_ctx->bpf_func_stats_data_val)
449+ bpf_stat_ctx->bpf_func_stats_data_val->num_executions++;
450+}
451+
452+static INLINE void bpf_stats_exit(struct bpf_func_stats_ctx* bpf_stat_ctx)
453+{
454+ if (bpf_stat_ctx->bpf_func_stats_data_val)
455+ bpf_stat_ctx->bpf_func_stats_data_val->time_elapsed_ns +=
456+ bpf_ktime_get_ns() - bpf_stat_ctx->start_time_ns;
457+}
458+
459+static INLINE void
460+bpf_stats_pre_submit_var_perf_event(struct bpf_func_stats_ctx* bpf_stat_ctx,
461+ struct var_metadata_t* meta)
462+{
463+ if (bpf_stat_ctx->bpf_func_stats_data_val) {
464+ bpf_stat_ctx->bpf_func_stats_data_val->num_perf_events++;
465+ meta->bpf_stats_num_perf_events =
466+ bpf_stat_ctx->bpf_func_stats_data_val->num_perf_events;
467+ }
468+ meta->bpf_stats_start_ktime_ns = bpf_stat_ctx->start_time_ns;
469+ meta->cpu_id = bpf_get_smp_processor_id();
470+}
471+
472+static INLINE size_t
473+read_absolute_file_path_from_dentry(struct dentry* filp_dentry, void* payload)
474+{
475+ size_t length = 0;
476+ size_t filepart_length;
477+ struct dentry* parent_dentry;
478+
479+#ifdef UNROLL
480+#pragma unroll
481+#endif
482+ for (int i = 0; i < MAX_PATH_DEPTH; i++) {
483+ filepart_length = bpf_probe_read_str(payload, MAX_PATH,
484+ BPF_CORE_READ(filp_dentry, d_name.name));
485+ barrier_var(filepart_length);
486+ if (filepart_length > MAX_PATH)
487+ break;
488+ barrier_var(filepart_length);
489+ payload += filepart_length;
490+ length += filepart_length;
491+
492+ parent_dentry = BPF_CORE_READ(filp_dentry, d_parent);
493+ if (filp_dentry == parent_dentry)
494+ break;
495+ filp_dentry = parent_dentry;
496+ }
497+
498+ return length;
499+}
500+
501+static INLINE bool
502+is_ancestor_in_allowed_inodes(struct dentry* filp_dentry)
503+{
504+ struct dentry* parent_dentry;
505+#ifdef UNROLL
506+#pragma unroll
507+#endif
508+ for (int i = 0; i < MAX_PATH_DEPTH; i++) {
509+ u64 dir_ino = BPF_CORE_READ(filp_dentry, d_inode, i_ino);
510+ bool* allowed_dir = bpf_map_lookup_elem(&allowed_directory_inodes, &dir_ino);
511+
512+ if (allowed_dir != NULL)
513+ return true;
514+ parent_dentry = BPF_CORE_READ(filp_dentry, d_parent);
515+ if (filp_dentry == parent_dentry)
516+ break;
517+ filp_dentry = parent_dentry;
518+ }
519+ return false;
520+}
521+
522+static INLINE bool is_dentry_allowed_for_filemod(struct dentry* file_dentry,
523+ u32* device_id,
524+ u64* file_ino)
525+{
526+ u32 dev_id = BPF_CORE_READ(file_dentry, d_sb, s_dev);
527+ *device_id = dev_id;
528+ bool* allowed_device = bpf_map_lookup_elem(&allowed_devices, &dev_id);
529+
530+ if (allowed_device == NULL)
531+ return false;
532+
533+ u64 ino = BPF_CORE_READ(file_dentry, d_inode, i_ino);
534+ *file_ino = ino;
535+ bool* allowed_file = bpf_map_lookup_elem(&allowed_file_inodes, &ino);
536+
537+ if (allowed_file == NULL)
538+ if (!is_ancestor_in_allowed_inodes(BPF_CORE_READ(file_dentry, d_parent)))
539+ return false;
540+ return true;
541+}
542+
543+SEC("kprobe/proc_sys_write")
544+ssize_t BPF_KPROBE(kprobe__proc_sys_write,
545+ struct file* filp, const char* buf,
546+ size_t count, loff_t* ppos)
547+{
548+ struct bpf_func_stats_ctx stats_ctx;
549+ bpf_stats_enter(&stats_ctx, profiler_bpf_proc_sys_write);
550+
551+ u32 pid = get_userspace_pid();
552+ int zero = 0;
553+ struct var_sysctl_data_t* sysctl_data =
554+ bpf_map_lookup_elem(&data_heap, &zero);
555+ if (!sysctl_data)
556+ goto out;
557+
558+ struct task_struct* task = (struct task_struct*)bpf_get_current_task();
559+ sysctl_data->meta.type = SYSCTL_EVENT;
560+ void* payload = populate_var_metadata(&sysctl_data->meta, task, pid, sysctl_data->payload);
561+ payload = populate_cgroup_info(&sysctl_data->cgroup_data, task, payload);
562+
563+ populate_ancestors(task, &sysctl_data->ancestors_info);
564+
565+ sysctl_data->sysctl_val_length = 0;
566+ sysctl_data->sysctl_path_length = 0;
567+
568+ size_t sysctl_val_length = bpf_probe_read_str(payload, CTL_MAXNAME, buf);
569+ barrier_var(sysctl_val_length);
570+ if (sysctl_val_length <= CTL_MAXNAME) {
571+ barrier_var(sysctl_val_length);
572+ sysctl_data->sysctl_val_length = sysctl_val_length;
573+ payload += sysctl_val_length;
574+ }
575+
576+ size_t sysctl_path_length = bpf_probe_read_str(payload, MAX_PATH,
577+ BPF_CORE_READ(filp, f_path.dentry, d_name.name));
578+ barrier_var(sysctl_path_length);
579+ if (sysctl_path_length <= MAX_PATH) {
580+ barrier_var(sysctl_path_length);
581+ sysctl_data->sysctl_path_length = sysctl_path_length;
582+ payload += sysctl_path_length;
583+ }
584+
585+ bpf_stats_pre_submit_var_perf_event(&stats_ctx, &sysctl_data->meta);
586+ unsigned long data_len = payload - (void*)sysctl_data;
587+ data_len = data_len > sizeof(struct var_sysctl_data_t)
588+ ? sizeof(struct var_sysctl_data_t)
589+ : data_len;
590+ bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, sysctl_data, data_len);
591+out:
592+ bpf_stats_exit(&stats_ctx);
593+ return 0;
594+}
595+
596+SEC("tracepoint/syscalls/sys_enter_kill")
597+int tracepoint__syscalls__sys_enter_kill(struct trace_event_raw_sys_enter* ctx)
598+{
599+ struct bpf_func_stats_ctx stats_ctx;
600+
601+ bpf_stats_enter(&stats_ctx, profiler_bpf_sys_enter_kill);
602+ int pid = ctx->args[0];
603+ int sig = ctx->args[1];
604+ int ret = trace_var_sys_kill(ctx, pid, sig);
605+ bpf_stats_exit(&stats_ctx);
606+ return ret;
607+};
608+
609+SEC("raw_tracepoint/sched_process_exit")
610+int raw_tracepoint__sched_process_exit(void* ctx)
611+{
612+ int zero = 0;
613+ struct bpf_func_stats_ctx stats_ctx;
614+ bpf_stats_enter(&stats_ctx, profiler_bpf_sched_process_exit);
615+
616+ u32 tpid = get_userspace_pid();
617+
618+ struct var_kill_data_arr_t* arr_struct = bpf_map_lookup_elem(&var_tpid_to_data, &tpid);
619+ struct var_kill_data_t* kill_data = bpf_map_lookup_elem(&data_heap, &zero);
620+
621+ if (arr_struct == NULL || kill_data == NULL)
622+ goto out;
623+
624+ struct task_struct* task = (struct task_struct*)bpf_get_current_task();
625+ struct kernfs_node* proc_kernfs = BPF_CORE_READ(task, cgroups, dfl_cgrp, kn);
626+
627+#ifdef UNROLL
628+#pragma unroll
629+#endif
630+ for (int i = 0; i < ARRAY_SIZE(arr_struct->array); i++) {
631+ struct var_kill_data_t* past_kill_data = &arr_struct->array[i];
632+
633+ if (past_kill_data != NULL && past_kill_data->kill_target_pid == tpid) {
634+ bpf_probe_read(kill_data, sizeof(*past_kill_data), past_kill_data);
635+ void* payload = kill_data->payload;
636+ size_t offset = kill_data->payload_length;
637+ if (offset >= MAX_METADATA_PAYLOAD_LEN + MAX_CGROUP_PAYLOAD_LEN)
638+ return 0;
639+ payload += offset;
640+
641+ kill_data->kill_target_name_length = 0;
642+ kill_data->kill_target_cgroup_proc_length = 0;
643+
644+ size_t comm_length = bpf_core_read_str(payload, TASK_COMM_LEN, &task->comm);
645+ barrier_var(comm_length);
646+ if (comm_length <= TASK_COMM_LEN) {
647+ barrier_var(comm_length);
648+ kill_data->kill_target_name_length = comm_length;
649+ payload += comm_length;
650+ }
651+
652+ size_t cgroup_proc_length = bpf_probe_read_str(payload, KILL_TARGET_LEN,
653+ BPF_CORE_READ(proc_kernfs, name));
654+ barrier_var(cgroup_proc_length);
655+ if (cgroup_proc_length <= KILL_TARGET_LEN) {
656+ barrier_var(cgroup_proc_length);
657+ kill_data->kill_target_cgroup_proc_length = cgroup_proc_length;
658+ payload += cgroup_proc_length;
659+ }
660+
661+ bpf_stats_pre_submit_var_perf_event(&stats_ctx, &kill_data->meta);
662+ unsigned long data_len = (void*)payload - (void*)kill_data;
663+ data_len = data_len > sizeof(struct var_kill_data_t)
664+ ? sizeof(struct var_kill_data_t)
665+ : data_len;
666+ bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, kill_data, data_len);
667+ }
668+ }
669+ bpf_map_delete_elem(&var_tpid_to_data, &tpid);
670+out:
671+ bpf_stats_exit(&stats_ctx);
672+ return 0;
673+}
674+
675+SEC("raw_tracepoint/sched_process_exec")
676+int raw_tracepoint__sched_process_exec(struct bpf_raw_tracepoint_args* ctx)
677+{
678+ struct bpf_func_stats_ctx stats_ctx;
679+ bpf_stats_enter(&stats_ctx, profiler_bpf_sched_process_exec);
680+
681+ struct linux_binprm* bprm = (struct linux_binprm*)ctx->args[2];
682+ u64 inode = BPF_CORE_READ(bprm, file, f_inode, i_ino);
683+
684+ bool* should_filter_binprm = bpf_map_lookup_elem(&disallowed_exec_inodes, &inode);
685+ if (should_filter_binprm != NULL)
686+ goto out;
687+
688+ int zero = 0;
689+ struct var_exec_data_t* proc_exec_data = bpf_map_lookup_elem(&data_heap, &zero);
690+ if (!proc_exec_data)
691+ goto out;
692+
693+ if (INODE_FILTER && inode != INODE_FILTER)
694+ return 0;
695+
696+ u32 pid = get_userspace_pid();
697+ struct task_struct* task = (struct task_struct*)bpf_get_current_task();
698+
699+ proc_exec_data->meta.type = EXEC_EVENT;
700+ proc_exec_data->bin_path_length = 0;
701+ proc_exec_data->cmdline_length = 0;
702+ proc_exec_data->environment_length = 0;
703+ void* payload = populate_var_metadata(&proc_exec_data->meta, task, pid,
704+ proc_exec_data->payload);
705+ payload = populate_cgroup_info(&proc_exec_data->cgroup_data, task, payload);
706+
707+ struct task_struct* parent_task = BPF_CORE_READ(task, real_parent);
708+ proc_exec_data->parent_pid = BPF_CORE_READ(parent_task, tgid);
709+ proc_exec_data->parent_uid = BPF_CORE_READ(parent_task, real_cred, uid.val);
710+ proc_exec_data->parent_exec_id = BPF_CORE_READ(parent_task, self_exec_id);
711+ proc_exec_data->parent_start_time = BPF_CORE_READ(parent_task, start_time);
712+
713+ const char* filename = BPF_CORE_READ(bprm, filename);
714+ size_t bin_path_length = bpf_probe_read_str(payload, MAX_FILENAME_LEN, filename);
715+ barrier_var(bin_path_length);
716+ if (bin_path_length <= MAX_FILENAME_LEN) {
717+ barrier_var(bin_path_length);
718+ proc_exec_data->bin_path_length = bin_path_length;
719+ payload += bin_path_length;
720+ }
721+
722+ void* arg_start = (void*)BPF_CORE_READ(task, mm, arg_start);
723+ void* arg_end = (void*)BPF_CORE_READ(task, mm, arg_end);
724+ unsigned int cmdline_length = probe_read_lim(payload, arg_start,
725+ arg_end - arg_start, MAX_ARGS_LEN);
726+
727+ if (cmdline_length <= MAX_ARGS_LEN) {
728+ barrier_var(cmdline_length);
729+ proc_exec_data->cmdline_length = cmdline_length;
730+ payload += cmdline_length;
731+ }
732+
733+ if (READ_ENVIRON_FROM_EXEC) {
734+ void* env_start = (void*)BPF_CORE_READ(task, mm, env_start);
735+ void* env_end = (void*)BPF_CORE_READ(task, mm, env_end);
736+ unsigned long env_len = probe_read_lim(payload, env_start,
737+ env_end - env_start, MAX_ENVIRON_LEN);
738+ if (cmdline_length <= MAX_ENVIRON_LEN) {
739+ proc_exec_data->environment_length = env_len;
740+ payload += env_len;
741+ }
742+ }
743+
744+ bpf_stats_pre_submit_var_perf_event(&stats_ctx, &proc_exec_data->meta);
745+ unsigned long data_len = payload - (void*)proc_exec_data;
746+ data_len = data_len > sizeof(struct var_exec_data_t)
747+ ? sizeof(struct var_exec_data_t)
748+ : data_len;
749+ bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, proc_exec_data, data_len);
750+out:
751+ bpf_stats_exit(&stats_ctx);
752+ return 0;
753+}
754+
755+SEC("kretprobe/do_filp_open")
756+int kprobe_ret__do_filp_open(struct pt_regs* ctx)
757+{
758+ struct bpf_func_stats_ctx stats_ctx;
759+ bpf_stats_enter(&stats_ctx, profiler_bpf_do_filp_open_ret);
760+
761+ struct file* filp = (struct file*)PT_REGS_RC_CORE(ctx);
762+
763+ if (filp == NULL || IS_ERR(filp))
764+ goto out;
765+ unsigned int flags = BPF_CORE_READ(filp, f_flags);
766+ if ((flags & (O_RDWR | O_WRONLY)) == 0)
767+ goto out;
768+ if ((flags & O_TMPFILE) > 0)
769+ goto out;
770+ struct inode* file_inode = BPF_CORE_READ(filp, f_inode);
771+ umode_t mode = BPF_CORE_READ(file_inode, i_mode);
772+ if (S_ISDIR(mode) || S_ISCHR(mode) || S_ISBLK(mode) || S_ISFIFO(mode) ||
773+ S_ISSOCK(mode))
774+ goto out;
775+
776+ struct dentry* filp_dentry = BPF_CORE_READ(filp, f_path.dentry);
777+ u32 device_id = 0;
778+ u64 file_ino = 0;
779+ if (!is_dentry_allowed_for_filemod(filp_dentry, &device_id, &file_ino))
780+ goto out;
781+
782+ int zero = 0;
783+ struct var_filemod_data_t* filemod_data = bpf_map_lookup_elem(&data_heap, &zero);
784+ if (!filemod_data)
785+ goto out;
786+
787+ u32 pid = get_userspace_pid();
788+ struct task_struct* task = (struct task_struct*)bpf_get_current_task();
789+
790+ filemod_data->meta.type = FILEMOD_EVENT;
791+ filemod_data->fmod_type = FMOD_OPEN;
792+ filemod_data->dst_flags = flags;
793+ filemod_data->src_inode = 0;
794+ filemod_data->dst_inode = file_ino;
795+ filemod_data->src_device_id = 0;
796+ filemod_data->dst_device_id = device_id;
797+ filemod_data->src_filepath_length = 0;
798+ filemod_data->dst_filepath_length = 0;
799+
800+ void* payload = populate_var_metadata(&filemod_data->meta, task, pid,
801+ filemod_data->payload);
802+ payload = populate_cgroup_info(&filemod_data->cgroup_data, task, payload);
803+
804+ size_t len = read_absolute_file_path_from_dentry(filp_dentry, payload);
805+ barrier_var(len);
806+ if (len <= MAX_FILEPATH_LENGTH) {
807+ barrier_var(len);
808+ payload += len;
809+ filemod_data->dst_filepath_length = len;
810+ }
811+ bpf_stats_pre_submit_var_perf_event(&stats_ctx, &filemod_data->meta);
812+ unsigned long data_len = payload - (void*)filemod_data;
813+ data_len = data_len > sizeof(*filemod_data) ? sizeof(*filemod_data) : data_len;
814+ bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, filemod_data, data_len);
815+out:
816+ bpf_stats_exit(&stats_ctx);
817+ return 0;
818+}
819+
820+SEC("kprobe/vfs_link")
821+int BPF_KPROBE(kprobe__vfs_link,
822+ struct dentry* old_dentry, struct inode* dir,
823+ struct dentry* new_dentry, struct inode** delegated_inode)
824+{
825+ struct bpf_func_stats_ctx stats_ctx;
826+ bpf_stats_enter(&stats_ctx, profiler_bpf_vfs_link);
827+
828+ u32 src_device_id = 0;
829+ u64 src_file_ino = 0;
830+ u32 dst_device_id = 0;
831+ u64 dst_file_ino = 0;
832+ if (!is_dentry_allowed_for_filemod(old_dentry, &src_device_id, &src_file_ino) &&
833+ !is_dentry_allowed_for_filemod(new_dentry, &dst_device_id, &dst_file_ino))
834+ goto out;
835+
836+ int zero = 0;
837+ struct var_filemod_data_t* filemod_data = bpf_map_lookup_elem(&data_heap, &zero);
838+ if (!filemod_data)
839+ goto out;
840+
841+ u32 pid = get_userspace_pid();
842+ struct task_struct* task = (struct task_struct*)bpf_get_current_task();
843+
844+ filemod_data->meta.type = FILEMOD_EVENT;
845+ filemod_data->fmod_type = FMOD_LINK;
846+ filemod_data->dst_flags = 0;
847+ filemod_data->src_inode = src_file_ino;
848+ filemod_data->dst_inode = dst_file_ino;
849+ filemod_data->src_device_id = src_device_id;
850+ filemod_data->dst_device_id = dst_device_id;
851+ filemod_data->src_filepath_length = 0;
852+ filemod_data->dst_filepath_length = 0;
853+
854+ void* payload = populate_var_metadata(&filemod_data->meta, task, pid,
855+ filemod_data->payload);
856+ payload = populate_cgroup_info(&filemod_data->cgroup_data, task, payload);
857+
858+ size_t len = read_absolute_file_path_from_dentry(old_dentry, payload);
859+ barrier_var(len);
860+ if (len <= MAX_FILEPATH_LENGTH) {
861+ barrier_var(len);
862+ payload += len;
863+ filemod_data->src_filepath_length = len;
864+ }
865+
866+ len = read_absolute_file_path_from_dentry(new_dentry, payload);
867+ barrier_var(len);
868+ if (len <= MAX_FILEPATH_LENGTH) {
869+ barrier_var(len);
870+ payload += len;
871+ filemod_data->dst_filepath_length = len;
872+ }
873+
874+ bpf_stats_pre_submit_var_perf_event(&stats_ctx, &filemod_data->meta);
875+ unsigned long data_len = payload - (void*)filemod_data;
876+ data_len = data_len > sizeof(*filemod_data) ? sizeof(*filemod_data) : data_len;
877+ bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, filemod_data, data_len);
878+out:
879+ bpf_stats_exit(&stats_ctx);
880+ return 0;
881+}
882+
883+SEC("kprobe/vfs_symlink")
884+int BPF_KPROBE(kprobe__vfs_symlink, struct inode* dir, struct dentry* dentry,
885+ const char* oldname)
886+{
887+ struct bpf_func_stats_ctx stats_ctx;
888+ bpf_stats_enter(&stats_ctx, profiler_bpf_vfs_symlink);
889+
890+ u32 dst_device_id = 0;
891+ u64 dst_file_ino = 0;
892+ if (!is_dentry_allowed_for_filemod(dentry, &dst_device_id, &dst_file_ino))
893+ goto out;
894+
895+ int zero = 0;
896+ struct var_filemod_data_t* filemod_data = bpf_map_lookup_elem(&data_heap, &zero);
897+ if (!filemod_data)
898+ goto out;
899+
900+ u32 pid = get_userspace_pid();
901+ struct task_struct* task = (struct task_struct*)bpf_get_current_task();
902+
903+ filemod_data->meta.type = FILEMOD_EVENT;
904+ filemod_data->fmod_type = FMOD_SYMLINK;
905+ filemod_data->dst_flags = 0;
906+ filemod_data->src_inode = 0;
907+ filemod_data->dst_inode = dst_file_ino;
908+ filemod_data->src_device_id = 0;
909+ filemod_data->dst_device_id = dst_device_id;
910+ filemod_data->src_filepath_length = 0;
911+ filemod_data->dst_filepath_length = 0;
912+
913+ void* payload = populate_var_metadata(&filemod_data->meta, task, pid,
914+ filemod_data->payload);
915+ payload = populate_cgroup_info(&filemod_data->cgroup_data, task, payload);
916+
917+ size_t len = bpf_probe_read_str(payload, MAX_FILEPATH_LENGTH, oldname);
918+ barrier_var(len);
919+ if (len <= MAX_FILEPATH_LENGTH) {
920+ barrier_var(len);
921+ payload += len;
922+ filemod_data->src_filepath_length = len;
923+ }
924+ len = read_absolute_file_path_from_dentry(dentry, payload);
925+ barrier_var(len);
926+ if (len <= MAX_FILEPATH_LENGTH) {
927+ barrier_var(len);
928+ payload += len;
929+ filemod_data->dst_filepath_length = len;
930+ }
931+ bpf_stats_pre_submit_var_perf_event(&stats_ctx, &filemod_data->meta);
932+ unsigned long data_len = payload - (void*)filemod_data;
933+ data_len = data_len > sizeof(*filemod_data) ? sizeof(*filemod_data) : data_len;
934+ bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, filemod_data, data_len);
935+out:
936+ bpf_stats_exit(&stats_ctx);
937+ return 0;
938+}
939+
940+SEC("raw_tracepoint/sched_process_fork")
941+int raw_tracepoint__sched_process_fork(struct bpf_raw_tracepoint_args* ctx)
942+{
943+ struct bpf_func_stats_ctx stats_ctx;
944+ bpf_stats_enter(&stats_ctx, profiler_bpf_sched_process_fork);
945+
946+ int zero = 0;
947+ struct var_fork_data_t* fork_data = bpf_map_lookup_elem(&data_heap, &zero);
948+ if (!fork_data)
949+ goto out;
950+
951+ struct task_struct* parent = (struct task_struct*)ctx->args[0];
952+ struct task_struct* child = (struct task_struct*)ctx->args[1];
953+ fork_data->meta.type = FORK_EVENT;
954+
955+ void* payload = populate_var_metadata(&fork_data->meta, child,
956+ BPF_CORE_READ(child, pid), fork_data->payload);
957+ fork_data->parent_pid = BPF_CORE_READ(parent, pid);
958+ fork_data->parent_exec_id = BPF_CORE_READ(parent, self_exec_id);
959+ fork_data->parent_start_time = BPF_CORE_READ(parent, start_time);
960+ bpf_stats_pre_submit_var_perf_event(&stats_ctx, &fork_data->meta);
961+
962+ unsigned long data_len = payload - (void*)fork_data;
963+ data_len = data_len > sizeof(*fork_data) ? sizeof(*fork_data) : data_len;
964+ bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, fork_data, data_len);
965+out:
966+ bpf_stats_exit(&stats_ctx);
967+ return 0;
968+}
969+char _license[] SEC("license") = "GPL";
tools/testing/selftests/bpf/progs/profiler1.c+6−0
@@ -0,0 +1,6 @@
1+// SPDX-License-Identifier: GPL-2.0
2+/* Copyright (c) 2020 Facebook */
3+#define barrier_var(var) asm volatile("" : "=r"(var) : "0"(var))
4+#define UNROLL
5+#define INLINE __always_inline
6+#include "profiler.inc.h"
tools/testing/selftests/bpf/progs/profiler2.c+6−0
@@ -0,0 +1,6 @@
1+// SPDX-License-Identifier: GPL-2.0
2+/* Copyright (c) 2020 Facebook */
3+#define barrier_var(var) /**/
4+/* undef #define UNROLL */
5+#define INLINE /**/
6+#include "profiler.inc.h"
tools/testing/selftests/bpf/progs/profiler3.c+6−0
@@ -0,0 +1,6 @@
1+// SPDX-License-Identifier: GPL-2.0
2+/* Copyright (c) 2020 Facebook */
3+#define barrier_var(var) /**/
4+#define UNROLL
5+#define INLINE __noinline
6+#include "profiler.inc.h"
tools/testing/selftests/bpf/progs/test_btf_map_in_map.c+43−0
@@ -41,6 +41,43 @@ struct outer_arr { · 40 unmodified lines
4141 .values = { (void *)&inner_map1, 0, (void *)&inner_map2 },
4242 };
4343
44+struct inner_map_sz3 {
45+ __uint(type, BPF_MAP_TYPE_ARRAY);
46+ __uint(map_flags, BPF_F_INNER_MAP);
47+ __uint(max_entries, 3);
48+ __type(key, int);
49+ __type(value, int);
50+} inner_map3 SEC(".maps"),
51+ inner_map4 SEC(".maps");
52+
53+struct inner_map_sz4 {
54+ __uint(type, BPF_MAP_TYPE_ARRAY);
55+ __uint(map_flags, BPF_F_INNER_MAP);
56+ __uint(max_entries, 5);
57+ __type(key, int);
58+ __type(value, int);
59+} inner_map5 SEC(".maps");
60+
61+struct outer_arr_dyn {
62+ __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
63+ __uint(max_entries, 3);
64+ __uint(key_size, sizeof(int));
65+ __uint(value_size, sizeof(int));
66+ __array(values, struct {
67+ __uint(type, BPF_MAP_TYPE_ARRAY);
68+ __uint(map_flags, BPF_F_INNER_MAP);
69+ __uint(max_entries, 1);
70+ __type(key, int);
71+ __type(value, int);
72+ });
73+} outer_arr_dyn SEC(".maps") = {
74+ .values = {
75+ [0] = (void *)&inner_map3,
76+ [1] = (void *)&inner_map4,
77+ [2] = (void *)&inner_map5,
78+ },
79+};
80+
4481 struct outer_hash {
4582 __uint(type, BPF_MAP_TYPE_HASH_OF_MAPS);
4683 __uint(max_entries, 5);
@@ -101,6 +138,12 @@ int handle__sys_enter(void *ctx) · 54 unmodified lines
101138 val = input + 1;
102139 bpf_map_update_elem(inner_map, &key, &val, 0);
103140
141+ inner_map = bpf_map_lookup_elem(&outer_arr_dyn, &key);
142+ if (!inner_map)
143+ return 1;
144+ val = input + 2;
145+ bpf_map_update_elem(inner_map, &key, &val, 0);
146+
104147 return 0;
105148 }
106149
tools/testing/selftests/bpf/progs/test_core_autosize.c+172−0
@@ -0,0 +1,172 @@
1+// SPDX-License-Identifier: GPL-2.0
2+/* Copyright (c) 2020 Facebook */
3+
4+#include <linux/bpf.h>
5+#include <stdint.h>
6+#include <bpf/bpf_helpers.h>
7+#include <bpf/bpf_core_read.h>
8+
9+char _license[] SEC("license") = "GPL";
10+
11+/* fields of exactly the same size */
12+struct test_struct___samesize {
13+ void *ptr;
14+ unsigned long long val1;
15+ unsigned int val2;
16+ unsigned short val3;
17+ unsigned char val4;
18+} __attribute((preserve_access_index));
19+
20+/* unsigned fields that have to be downsized by libbpf */
21+struct test_struct___downsize {
22+ void *ptr;
23+ unsigned long val1;
24+ unsigned long val2;
25+ unsigned long val3;
26+ unsigned long val4;
27+ /* total sz: 40 */
28+} __attribute__((preserve_access_index));
29+
30+/* fields with signed integers of wrong size, should be rejected */
31+struct test_struct___signed {
32+ void *ptr;
33+ long val1;
34+ long val2;
35+ long val3;
36+ long val4;
37+} __attribute((preserve_access_index));
38+
39+/* real layout and sizes according to test's (32-bit) BTF */
40+struct test_struct___real {
41+ unsigned int ptr; /* can't use `void *`, it is always 8 byte in BPF target */
42+ unsigned int val2;
43+ unsigned long long val1;
44+ unsigned short val3;
45+ unsigned char val4;
46+ unsigned char _pad;
47+ /* total sz: 20 */
48+};
49+
50+struct test_struct___real input = {
51+ .ptr = 0x01020304,
52+ .val1 = 0x1020304050607080,
53+ .val2 = 0x0a0b0c0d,
54+ .val3 = 0xfeed,
55+ .val4 = 0xb9,
56+ ._pad = 0xff, /* make sure no accidental zeros are present */
57+};
58+
59+unsigned long long ptr_samesized = 0;
60+unsigned long long val1_samesized = 0;
61+unsigned long long val2_samesized = 0;
62+unsigned long long val3_samesized = 0;
63+unsigned long long val4_samesized = 0;
64+struct test_struct___real output_samesized = {};
65+
66+unsigned long long ptr_downsized = 0;
67+unsigned long long val1_downsized = 0;
68+unsigned long long val2_downsized = 0;
69+unsigned long long val3_downsized = 0;
70+unsigned long long val4_downsized = 0;
71+struct test_struct___real output_downsized = {};
72+
73+unsigned long long ptr_probed = 0;
74+unsigned long long val1_probed = 0;
75+unsigned long long val2_probed = 0;
76+unsigned long long val3_probed = 0;
77+unsigned long long val4_probed = 0;
78+
79+unsigned long long ptr_signed = 0;
80+unsigned long long val1_signed = 0;
81+unsigned long long val2_signed = 0;
82+unsigned long long val3_signed = 0;
83+unsigned long long val4_signed = 0;
84+struct test_struct___real output_signed = {};
85+
86+SEC("raw_tp/sys_exit")
87+int handle_samesize(void *ctx)
88+{
89+ struct test_struct___samesize *in = (void *)&input;
90+ struct test_struct___samesize *out = (void *)&output_samesized;
91+
92+ ptr_samesized = (unsigned long long)in->ptr;
93+ val1_samesized = in->val1;
94+ val2_samesized = in->val2;
95+ val3_samesized = in->val3;
96+ val4_samesized = in->val4;
97+
98+ out->ptr = in->ptr;
99+ out->val1 = in->val1;
100+ out->val2 = in->val2;
101+ out->val3 = in->val3;
102+ out->val4 = in->val4;
103+
104+ return 0;
105+}
106+
107+SEC("raw_tp/sys_exit")
108+int handle_downsize(void *ctx)
109+{
110+ struct test_struct___downsize *in = (void *)&input;
111+ struct test_struct___downsize *out = (void *)&output_downsized;
112+
113+ ptr_downsized = (unsigned long long)in->ptr;
114+ val1_downsized = in->val1;
115+ val2_downsized = in->val2;
116+ val3_downsized = in->val3;
117+ val4_downsized = in->val4;
118+
119+ out->ptr = in->ptr;
120+ out->val1 = in->val1;
121+ out->val2 = in->val2;
122+ out->val3 = in->val3;
123+ out->val4 = in->val4;
124+
125+ return 0;
126+}
127+
128+SEC("raw_tp/sys_enter")
129+int handle_probed(void *ctx)
130+{
131+ struct test_struct___downsize *in = (void *)&input;
132+ __u64 tmp;
133+
134+ tmp = 0;
135+ bpf_core_read(&tmp, bpf_core_field_size(in->ptr), &in->ptr);
136+ ptr_probed = tmp;
137+
138+ tmp = 0;
139+ bpf_core_read(&tmp, bpf_core_field_size(in->val1), &in->val1);
140+ val1_probed = tmp;
141+
142+ tmp = 0;
143+ bpf_core_read(&tmp, bpf_core_field_size(in->val2), &in->val2);
144+ val2_probed = tmp;
145+
146+ tmp = 0;
147+ bpf_core_read(&tmp, bpf_core_field_size(in->val3), &in->val3);
148+ val3_probed = tmp;
149+
150+ tmp = 0;
151+ bpf_core_read(&tmp, bpf_core_field_size(in->val4), &in->val4);
152+ val4_probed = tmp;
153+
154+ return 0;
155+}
156+
157+SEC("raw_tp/sys_enter")
158+int handle_signed(void *ctx)
159+{
160+ struct test_struct___signed *in = (void *)&input;
161+ struct test_struct___signed *out = (void *)&output_signed;
162+
163+ val2_signed = in->val2;
164+ val3_signed = in->val3;
165+ val4_signed = in->val4;
166+
167+ out->val2= in->val2;
168+ out->val3= in->val3;
169+ out->val4= in->val4;
170+
171+ return 0;
172+}
tools/testing/selftests/bpf/progs/test_ksyms_btf.c+55−0
@@ -0,0 +1,55 @@
1+// SPDX-License-Identifier: GPL-2.0
2+/* Copyright (c) 2020 Google */
3+
4+#include "vmlinux.h"
5+
6+#include <bpf/bpf_helpers.h>
7+
8+__u64 out__runqueues_addr = -1;
9+__u64 out__bpf_prog_active_addr = -1;
10+
11+__u32 out__rq_cpu = -1; /* percpu struct fields */
12+int out__bpf_prog_active = -1; /* percpu int */
13+
14+__u32 out__this_rq_cpu = -1;
15+int out__this_bpf_prog_active = -1;
16+
17+__u32 out__cpu_0_rq_cpu = -1; /* cpu_rq(0)->cpu */
18+
19+extern const struct rq runqueues __ksym; /* struct type global var. */
20+extern const int bpf_prog_active __ksym; /* int type global var. */
21+
22+SEC("raw_tp/sys_enter")
23+int handler(const void *ctx)
24+{
25+ struct rq *rq;
26+ int *active;
27+ __u32 cpu;
28+
29+ out__runqueues_addr = (__u64)&runqueues;
30+ out__bpf_prog_active_addr = (__u64)&bpf_prog_active;
31+
32+ cpu = bpf_get_smp_processor_id();
33+
34+ /* test bpf_per_cpu_ptr() */
35+ rq = (struct rq *)bpf_per_cpu_ptr(&runqueues, cpu);
36+ if (rq)
37+ out__rq_cpu = rq->cpu;
38+ active = (int *)bpf_per_cpu_ptr(&bpf_prog_active, cpu);
39+ if (active)
40+ out__bpf_prog_active = *active;
41+
42+ rq = (struct rq *)bpf_per_cpu_ptr(&runqueues, 0);
43+ if (rq) /* should always be valid, but we can't spare the check. */
44+ out__cpu_0_rq_cpu = rq->cpu;
45+
46+ /* test bpf_this_cpu_ptr */
47+ rq = (struct rq *)bpf_this_cpu_ptr(&runqueues);
48+ out__this_rq_cpu = rq->cpu;
49+ active = (int *)bpf_this_cpu_ptr(&bpf_prog_active);
50+ out__this_bpf_prog_active = *active;
51+
52+ return 0;
53+}
54+
55+char _license[] SEC("license") = "GPL";
tools/testing/selftests/bpf/progs/test_misc_tcp_hdr_options.c+2−2
@@ -304,10 +304,10 @@ int misc_estab(struct bpf_sock_ops *skops) · 303 unmodified lines
304304 passive_lport_n = __bpf_htons(passive_lport_h);
305305 bpf_setsockopt(skops, SOL_TCP, TCP_SAVE_SYN,
306306 &true_val, sizeof(true_val));
307− set_hdr_cb_flags(skops);
307+ set_hdr_cb_flags(skops, 0);
308308 break;
309309 case BPF_SOCK_OPS_TCP_CONNECT_CB:
310− set_hdr_cb_flags(skops);
310+ set_hdr_cb_flags(skops, 0);
311311 break;
312312 case BPF_SOCK_OPS_PARSE_HDR_OPT_CB:
313313 return handle_parse_hdr(skops);
tools/testing/selftests/bpf/progs/test_sockmap_kern.h+25−9
@@ -131,39 +131,55 @@ int bpf_prog2(struct __sk_buff *skb) · 130 unmodified lines
131131
132132 }
133133
134−SEC("sk_skb3")
135−int bpf_prog3(struct __sk_buff *skb)
134+static inline void bpf_write_pass(struct __sk_buff *skb, int offset)
136135 {
137− const int one = 1;
138− int err, *f, ret = SK_PASS;
136+ int err = bpf_skb_pull_data(skb, 6 + offset);
139137 void *data_end;
140138 char *c;
141139
142− err = bpf_skb_pull_data(skb, 19);
143140 if (err)
144− goto tls_out;
141+ return;
145142
146143 c = (char *)(long)skb->data;
147144 data_end = (void *)(long)skb->data_end;
148145
149− if (c + 18 < data_end)
150− memcpy(&c[13], "PASS", 4);
146+ if (c + 5 + offset < data_end)
147+ memcpy(c + offset, "PASS", 4);
148+}
149+
150+SEC("sk_skb3")
151+int bpf_prog3(struct __sk_buff *skb)
152+{
153+ int err, *f, ret = SK_PASS;
154+ const int one = 1;
155+
151156 f = bpf_map_lookup_elem(&sock_skb_opts, &one);
152157 if (f && *f) {
153158 __u64 flags = 0;
154159
155160 ret = 0;
156161 flags = *f;
162+
163+ err = bpf_skb_adjust_room(skb, -13, 0, 0);
164+ if (err)
165+ return SK_DROP;
166+ err = bpf_skb_adjust_room(skb, 4, 0, 0);
167+ if (err)
168+ return SK_DROP;
169+ bpf_write_pass(skb, 0);
157170 #ifdef SOCKMAP
158171 return bpf_sk_redirect_map(skb, &tls_sock_map, ret, flags);
159172 #else
160173 return bpf_sk_redirect_hash(skb, &tls_sock_map, &ret, flags);
161174 #endif
162175 }
163−
164176 f = bpf_map_lookup_elem(&sock_skb_opts, &one);
165177 if (f && *f)
166178 ret = SK_DROP;
179+ err = bpf_skb_adjust_room(skb, 4, 0, 0);
180+ if (err)
181+ return SK_DROP;
182+ bpf_write_pass(skb, 13);
167183 tls_out:
168184 return ret;
169185 }
tools/testing/selftests/bpf/progs/test_tc_neigh.c+22−18
@@ -13,17 +13,10 @@ · 12 unmodified lines
1313 #include <bpf/bpf_helpers.h>
1414 #include <bpf/bpf_endian.h>
1515
16−#ifndef barrier_data
17−# define barrier_data(ptr) asm volatile("": :"r"(ptr) :"memory")
18−#endif
19−
2016 #ifndef ctx_ptr
2117 # define ctx_ptr(field) (void *)(long)(field)
2218 #endif
2319
24−#define dst_to_src_tmp 0xeeddddeeU
25−#define src_to_dst_tmp 0xeeffffeeU
26−
2720 #define ip4_src 0xac100164 /* 172.16.1.100 */
2821 #define ip4_dst 0xac100264 /* 172.16.2.100 */
2922
@@ -39,6 +32,18 @@ · 9 unmodified lines
3932 a.s6_addr32[3] == b.s6_addr32[3])
4033 #endif
4134
35+enum {
36+ dev_src,
37+ dev_dst,
38+};
39+
40+struct bpf_map_def SEC("maps") ifindex_map = {
41+ .type = BPF_MAP_TYPE_ARRAY,
42+ .key_size = sizeof(int),
43+ .value_size = sizeof(int),
44+ .max_entries = 2,
45+};
46+
4247 static __always_inline bool is_remote_ep_v4(struct __sk_buff *skb,
4348 __be32 addr)
4449 {
@@ -73,7 +78,14 @@ static __always_inline bool is_remote_ep_v6(struct __sk_buff *skb, · 28 unmodified lines
7378 return v6_equal(ip6h->daddr, addr);
7479 }
7580
76−SEC("chk_neigh") int tc_chk(struct __sk_buff *skb)
81+static __always_inline int get_dev_ifindex(int which)
82+{
83+ int *ifindex = bpf_map_lookup_elem(&ifindex_map, &which);
84+
85+ return ifindex ? *ifindex : 0;
86+}
87+
88+SEC("chk_egress") int tc_chk(struct __sk_buff *skb)
7789 {
7890 void *data_end = ctx_ptr(skb->data_end);
7991 void *data = ctx_ptr(skb->data);
@@ -87,7 +99,6 @@ SEC("chk_neigh") int tc_chk(struct __sk_buff *skb) · 7 unmodified lines
8799
88100 SEC("dst_ingress") int tc_dst(struct __sk_buff *skb)
89101 {
90− int idx = dst_to_src_tmp;
91102 __u8 zero[ETH_ALEN * 2];
92103 bool redirect = false;
93104
@@ -103,19 +114,15 @@ SEC("dst_ingress") int tc_dst(struct __sk_buff *skb) · 9 unmodified lines
103114 if (!redirect)
104115 return TC_ACT_OK;
105116
106− barrier_data(&idx);
107− idx = bpf_ntohl(idx);
108−
109117 __builtin_memset(&zero, 0, sizeof(zero));
110118 if (bpf_skb_store_bytes(skb, 0, &zero, sizeof(zero), 0) < 0)
111119 return TC_ACT_SHOT;
112120
113− return bpf_redirect_neigh(idx, 0);
121+ return bpf_redirect_neigh(get_dev_ifindex(dev_src), 0);
114122 }
115123
116124 SEC("src_ingress") int tc_src(struct __sk_buff *skb)
117125 {
118− int idx = src_to_dst_tmp;
119126 __u8 zero[ETH_ALEN * 2];
120127 bool redirect = false;
121128
@@ -131,14 +138,11 @@ SEC("src_ingress") int tc_src(struct __sk_buff *skb) · 9 unmodified lines
131138 if (!redirect)
132139 return TC_ACT_OK;
133140
134− barrier_data(&idx);
135− idx = bpf_ntohl(idx);
136−
137141 __builtin_memset(&zero, 0, sizeof(zero));
138142 if (bpf_skb_store_bytes(skb, 0, &zero, sizeof(zero), 0) < 0)
139143 return TC_ACT_SHOT;
140144
141− return bpf_redirect_neigh(idx, 0);
145+ return bpf_redirect_neigh(get_dev_ifindex(dev_dst), 0);
142146 }
143147
144148 char __license[] SEC("license") = "GPL";
tools/testing/selftests/bpf/progs/test_tc_peer.c+45−0
@@ -0,0 +1,45 @@
1+// SPDX-License-Identifier: GPL-2.0
2+#include <stdint.h>
3+#include <stdbool.h>
4+
5+#include <linux/bpf.h>
6+#include <linux/stddef.h>
7+#include <linux/pkt_cls.h>
8+
9+#include <bpf/bpf_helpers.h>
10+
11+enum {
12+ dev_src,
13+ dev_dst,
14+};
15+
16+struct bpf_map_def SEC("maps") ifindex_map = {
17+ .type = BPF_MAP_TYPE_ARRAY,
18+ .key_size = sizeof(int),
19+ .value_size = sizeof(int),
20+ .max_entries = 2,
21+};
22+
23+static __always_inline int get_dev_ifindex(int which)
24+{
25+ int *ifindex = bpf_map_lookup_elem(&ifindex_map, &which);
26+
27+ return ifindex ? *ifindex : 0;
28+}
29+
30+SEC("chk_egress") int tc_chk(struct __sk_buff *skb)
31+{
32+ return TC_ACT_SHOT;
33+}
34+
35+SEC("dst_ingress") int tc_dst(struct __sk_buff *skb)
36+{
37+ return bpf_redirect_peer(get_dev_ifindex(dev_src), 0);
38+}
39+
40+SEC("src_ingress") int tc_src(struct __sk_buff *skb)
41+{
42+ return bpf_redirect_peer(get_dev_ifindex(dev_dst), 0);
43+}
44+
45+char __license[] SEC("license") = "GPL";
tools/testing/selftests/bpf/progs/test_tcp_hdr_options.c+5−2
@@ -21,6 +21,7 @@ · 20 unmodified lines
2121
2222 __u8 test_kind = TCPOPT_EXP;
2323 __u16 test_magic = 0xeB9F;
24+__u32 inherit_cb_flags = 0;
2425
2526 struct bpf_test_option passive_synack_out = {};
2627 struct bpf_test_option passive_fin_out = {};
@@ -467,6 +468,8 @@ static int handle_passive_estab(struct bpf_sock_ops *skops) · 440 unmodified lines
467468 struct tcphdr *th;
468469 int err;
469470
471+ inherit_cb_flags = skops->bpf_sock_ops_cb_flags;
472+
470473 err = load_option(skops, &passive_estab_in, true);
471474 if (err == -ENOENT) {
472475 /* saved_syn is not found. It was in syncookie mode.
@@ -600,10 +603,10 @@ int estab(struct bpf_sock_ops *skops) · 127 unmodified lines
600603 case BPF_SOCK_OPS_TCP_LISTEN_CB:
601604 bpf_setsockopt(skops, SOL_TCP, TCP_SAVE_SYN,
602605 &true_val, sizeof(true_val));
603− set_hdr_cb_flags(skops);
606+ set_hdr_cb_flags(skops, BPF_SOCK_OPS_STATE_CB_FLAG);
604607 break;
605608 case BPF_SOCK_OPS_TCP_CONNECT_CB:
606− set_hdr_cb_flags(skops);
609+ set_hdr_cb_flags(skops, 0);
607610 break;
608611 case BPF_SOCK_OPS_PARSE_HDR_OPT_CB:
609612 return handle_parse_hdr(skops);
tools/testing/selftests/bpf/test_sockmap.c+45−36
@@ -86,6 +86,7 @@ int txmsg_ktls_skb_redir; · 85 unmodified lines
8686 int ktls;
8787 int peek_flag;
8888 int skb_use_parser;
89+int txmsg_omit_skb_parser;
8990
9091 static const struct option long_options[] = {
9192 {"help", no_argument, NULL, 'h' },
@@ -111,6 +112,7 @@ static const struct option long_options[] = { · 19 unmodified lines
111112 {"txmsg_redir_skb", no_argument, &txmsg_redir_skb, 1 },
112113 {"ktls", no_argument, &ktls, 1 },
113114 {"peek", no_argument, &peek_flag, 1 },
115+ {"txmsg_omit_skb_parser", no_argument, &txmsg_omit_skb_parser, 1},
114116 {"whitelist", required_argument, NULL, 'n' },
115117 {"blacklist", required_argument, NULL, 'b' },
116118 {0, 0, NULL, 0 }
@@ -175,6 +177,7 @@ static void test_reset(void) · 58 unmodified lines
175177 txmsg_apply = txmsg_cork = 0;
176178 txmsg_ingress = txmsg_redir_skb = 0;
177179 txmsg_ktls_skb = txmsg_ktls_skb_drop = txmsg_ktls_skb_redir = 0;
180+ txmsg_omit_skb_parser = 0;
178181 skb_use_parser = 0;
179182 }
180183
@@ -518,28 +521,13 @@ static int msg_verify_data(struct msghdr *msg, int size, int chunk_sz) · 337 unmodified lines
518521 if (i == 0 && txmsg_ktls_skb) {
519522 if (msg->msg_iov[i].iov_len < 4)
520523 return -EIO;
521− if (txmsg_ktls_skb_redir) {
522− if (memcmp(&d[13], "PASS", 4) != 0) {
523− fprintf(stderr,
524− "detected redirect ktls_skb data error with skb ingress update @iov[%i]:%i \"%02x %02x %02x %02x\" != \"PASS\"\n", i, 0, d[13], d[14], d[15], d[16]);
525− return -EIO;
526− }
527− d[13] = 0;
528− d[14] = 1;
529− d[15] = 2;
530− d[16] = 3;
531− j = 13;
532− } else if (txmsg_ktls_skb) {
533− if (memcmp(d, "PASS", 4) != 0) {
534− fprintf(stderr,
535− "detected ktls_skb data error with skb ingress update @iov[%i]:%i \"%02x %02x %02x %02x\" != \"PASS\"\n", i, 0, d[0], d[1], d[2], d[3]);
536− return -EIO;
537− }
538− d[0] = 0;
539− d[1] = 1;
540− d[2] = 2;
541− d[3] = 3;
524+ if (memcmp(d, "PASS", 4) != 0) {
525+ fprintf(stderr,
526+ "detected skb data error with skb ingress update @iov[%i]:%i \"%02x %02x %02x %02x\" != \"PASS\"\n",
527+ i, 0, d[0], d[1], d[2], d[3]);
528+ return -EIO;
542529 }
530+ j = 4; /* advance index past PASS header */
543531 }
544532
545533 for (; j < msg->msg_iov[i].iov_len && size; j++) {
@@ -927,13 +915,15 @@ static int run_options(struct sockmap_options *options, int cg_fd, int test) · 381 unmodified lines
927915 goto run;
928916
929917 /* Attach programs to sockmap */
930− err = bpf_prog_attach(prog_fd[0], map_fd[0],
931− BPF_SK_SKB_STREAM_PARSER, 0);
932− if (err) {
933− fprintf(stderr,
934− "ERROR: bpf_prog_attach (sockmap %i->%i): %d (%s)\n",
935− prog_fd[0], map_fd[0], err, strerror(errno));
936− return err;
918+ if (!txmsg_omit_skb_parser) {
919+ err = bpf_prog_attach(prog_fd[0], map_fd[0],
920+ BPF_SK_SKB_STREAM_PARSER, 0);
921+ if (err) {
922+ fprintf(stderr,
923+ "ERROR: bpf_prog_attach (sockmap %i->%i): %d (%s)\n",
924+ prog_fd[0], map_fd[0], err, strerror(errno));
925+ return err;
926+ }
937927 }
938928
939929 err = bpf_prog_attach(prog_fd[1], map_fd[0],
@@ -946,13 +936,15 @@ static int run_options(struct sockmap_options *options, int cg_fd, int test) · 6 unmodified lines
946936
947937 /* Attach programs to TLS sockmap */
948938 if (txmsg_ktls_skb) {
949− err = bpf_prog_attach(prog_fd[0], map_fd[8],
950− BPF_SK_SKB_STREAM_PARSER, 0);
951− if (err) {
952− fprintf(stderr,
953− "ERROR: bpf_prog_attach (TLS sockmap %i->%i): %d (%s)\n",
954− prog_fd[0], map_fd[8], err, strerror(errno));
955− return err;
939+ if (!txmsg_omit_skb_parser) {
940+ err = bpf_prog_attach(prog_fd[0], map_fd[8],
941+ BPF_SK_SKB_STREAM_PARSER, 0);
942+ if (err) {
943+ fprintf(stderr,
944+ "ERROR: bpf_prog_attach (TLS sockmap %i->%i): %d (%s)\n",
945+ prog_fd[0], map_fd[8], err, strerror(errno));
946+ return err;
947+ }
956948 }
957949
958950 err = bpf_prog_attach(prog_fd[2], map_fd[8],
@@ -1480,12 +1472,29 @@ static void test_txmsg_skb(int cgrp, struct sockmap_options *opt) · 521 unmodified lines
14801472 txmsg_ktls_skb_drop = 0;
14811473 txmsg_ktls_skb_redir = 1;
14821474 test_exec(cgrp, opt);
1475+ txmsg_ktls_skb_redir = 0;
1476+
1477+ /* Tests that omit skb_parser */
1478+ txmsg_omit_skb_parser = 1;
1479+ ktls = 0;
1480+ txmsg_ktls_skb = 0;
1481+ test_exec(cgrp, opt);
1482+
1483+ txmsg_ktls_skb_drop = 1;
1484+ test_exec(cgrp, opt);
1485+ txmsg_ktls_skb_drop = 0;
1486+
1487+ txmsg_ktls_skb_redir = 1;
1488+ test_exec(cgrp, opt);
1489+
1490+ ktls = 1;
1491+ test_exec(cgrp, opt);
1492+ txmsg_omit_skb_parser = 0;
14831493
14841494 opt->data_test = data;
14851495 ktls = k;
14861496 }
14871497
1488−
14891498 /* Test cork with hung data. This tests poor usage patterns where
14901499 * cork can leave data on the ring if user program is buggy and
14911500 * doesn't flush them somehow. They do take some time however
tools/testing/selftests/bpf/test_tc_neigh.sh+0−168
@@ -1,168 +0,0 @@
1−#!/bin/bash
2−# SPDX-License-Identifier: GPL-2.0
3−#
4−# This test sets up 3 netns (src <-> fwd <-> dst). There is no direct veth link
5−# between src and dst. The netns fwd has veth links to each src and dst. The
6−# client is in src and server in dst. The test installs a TC BPF program to each
7−# host facing veth in fwd which calls into bpf_redirect_peer() to perform the
8−# neigh addr population and redirect; it also installs a dropper prog on the
9−# egress side to drop skbs if neigh addrs were not populated.
10−
11−if [[ $EUID -ne 0 ]]; then
12− echo "This script must be run as root"
13− echo "FAIL"
14− exit 1
15−fi
16−
17−# check that nc, dd, ping, ping6 and timeout are present
18−command -v nc >/dev/null 2>&1 || \
19− { echo >&2 "nc is not available"; exit 1; }
20−command -v dd >/dev/null 2>&1 || \
21− { echo >&2 "dd is not available"; exit 1; }
22−command -v timeout >/dev/null 2>&1 || \
23− { echo >&2 "timeout is not available"; exit 1; }
24−command -v ping >/dev/null 2>&1 || \
25− { echo >&2 "ping is not available"; exit 1; }
26−command -v ping6 >/dev/null 2>&1 || \
27− { echo >&2 "ping6 is not available"; exit 1; }
28−
29−readonly GREEN='\033[0;92m'
30−readonly RED='\033[0;31m'
31−readonly NC='\033[0m' # No Color
32−
33−readonly PING_ARG="-c 3 -w 10 -q"
34−
35−readonly TIMEOUT=10
36−
37−readonly NS_SRC="ns-src-$(mktemp -u XXXXXX)"
38−readonly NS_FWD="ns-fwd-$(mktemp -u XXXXXX)"
39−readonly NS_DST="ns-dst-$(mktemp -u XXXXXX)"
40−
41−readonly IP4_SRC="172.16.1.100"
42−readonly IP4_DST="172.16.2.100"
43−
44−readonly IP6_SRC="::1:dead:beef:cafe"
45−readonly IP6_DST="::2:dead:beef:cafe"
46−
47−readonly IP4_SLL="169.254.0.1"
48−readonly IP4_DLL="169.254.0.2"
49−readonly IP4_NET="169.254.0.0"
50−
51−cleanup()
52−{
53− ip netns del ${NS_SRC}
54− ip netns del ${NS_FWD}
55− ip netns del ${NS_DST}
56−}
57−
58−trap cleanup EXIT
59−
60−set -e
61−
62−ip netns add "${NS_SRC}"
63−ip netns add "${NS_FWD}"
64−ip netns add "${NS_DST}"
65−
66−ip link add veth_src type veth peer name veth_src_fwd
67−ip link add veth_dst type veth peer name veth_dst_fwd
68−
69−ip link set veth_src netns ${NS_SRC}
70−ip link set veth_src_fwd netns ${NS_FWD}
71−
72−ip link set veth_dst netns ${NS_DST}
73−ip link set veth_dst_fwd netns ${NS_FWD}
74−
75−ip -netns ${NS_SRC} addr add ${IP4_SRC}/32 dev veth_src
76−ip -netns ${NS_DST} addr add ${IP4_DST}/32 dev veth_dst
77−
78−# The fwd netns automatically get a v6 LL address / routes, but also needs v4
79−# one in order to start ARP probing. IP4_NET route is added to the endpoints
80−# so that the ARP processing will reply.
81−
82−ip -netns ${NS_FWD} addr add ${IP4_SLL}/32 dev veth_src_fwd
83−ip -netns ${NS_FWD} addr add ${IP4_DLL}/32 dev veth_dst_fwd
84−
85−ip -netns ${NS_SRC} addr add ${IP6_SRC}/128 dev veth_src nodad
86−ip -netns ${NS_DST} addr add ${IP6_DST}/128 dev veth_dst nodad
87−
88−ip -netns ${NS_SRC} link set dev veth_src up
89−ip -netns ${NS_FWD} link set dev veth_src_fwd up
90−
91−ip -netns ${NS_DST} link set dev veth_dst up
92−ip -netns ${NS_FWD} link set dev veth_dst_fwd up
93−
94−ip -netns ${NS_SRC} route add ${IP4_DST}/32 dev veth_src scope global
95−ip -netns ${NS_SRC} route add ${IP4_NET}/16 dev veth_src scope global
96−ip -netns ${NS_FWD} route add ${IP4_SRC}/32 dev veth_src_fwd scope global
97−
98−ip -netns ${NS_SRC} route add ${IP6_DST}/128 dev veth_src scope global
99−ip -netns ${NS_FWD} route add ${IP6_SRC}/128 dev veth_src_fwd scope global
100−
101−ip -netns ${NS_DST} route add ${IP4_SRC}/32 dev veth_dst scope global
102−ip -netns ${NS_DST} route add ${IP4_NET}/16 dev veth_dst scope global
103−ip -netns ${NS_FWD} route add ${IP4_DST}/32 dev veth_dst_fwd scope global
104−
105−ip -netns ${NS_DST} route add ${IP6_SRC}/128 dev veth_dst scope global
106−ip -netns ${NS_FWD} route add ${IP6_DST}/128 dev veth_dst_fwd scope global
107−
108−fmac_src=$(ip netns exec ${NS_FWD} cat /sys/class/net/veth_src_fwd/address)
109−fmac_dst=$(ip netns exec ${NS_FWD} cat /sys/class/net/veth_dst_fwd/address)
110−
111−ip -netns ${NS_SRC} neigh add ${IP4_DST} dev veth_src lladdr $fmac_src
112−ip -netns ${NS_DST} neigh add ${IP4_SRC} dev veth_dst lladdr $fmac_dst
113−
114−ip -netns ${NS_SRC} neigh add ${IP6_DST} dev veth_src lladdr $fmac_src
115−ip -netns ${NS_DST} neigh add ${IP6_SRC} dev veth_dst lladdr $fmac_dst
116−
117−veth_dst=$(ip netns exec ${NS_FWD} cat /sys/class/net/veth_dst_fwd/ifindex | awk '{printf "%08x\n", $1}')
118−veth_src=$(ip netns exec ${NS_FWD} cat /sys/class/net/veth_src_fwd/ifindex | awk '{printf "%08x\n", $1}')
119−
120−xxd -p < test_tc_neigh.o | sed "s/eeddddee/$veth_src/g" | xxd -r -p > test_tc_neigh.x.o
121−xxd -p < test_tc_neigh.x.o | sed "s/eeffffee/$veth_dst/g" | xxd -r -p > test_tc_neigh.y.o
122−
123−ip netns exec ${NS_FWD} tc qdisc add dev veth_src_fwd clsact
124−ip netns exec ${NS_FWD} tc filter add dev veth_src_fwd ingress bpf da obj test_tc_neigh.y.o sec src_ingress
125−ip netns exec ${NS_FWD} tc filter add dev veth_src_fwd egress bpf da obj test_tc_neigh.y.o sec chk_neigh
126−
127−ip netns exec ${NS_FWD} tc qdisc add dev veth_dst_fwd clsact
128−ip netns exec ${NS_FWD} tc filter add dev veth_dst_fwd ingress bpf da obj test_tc_neigh.y.o sec dst_ingress
129−ip netns exec ${NS_FWD} tc filter add dev veth_dst_fwd egress bpf da obj test_tc_neigh.y.o sec chk_neigh
130−
131−rm -f test_tc_neigh.x.o test_tc_neigh.y.o
132−
133−ip netns exec ${NS_DST} bash -c "nc -4 -l -p 9004 &"
134−ip netns exec ${NS_DST} bash -c "nc -6 -l -p 9006 &"
135−
136−set +e
137−
138−TEST="TCPv4 connectivity test"
139−ip netns exec ${NS_SRC} bash -c "timeout ${TIMEOUT} dd if=/dev/zero bs=1000 count=100 > /dev/tcp/${IP4_DST}/9004"
140−if [ $? -ne 0 ]; then
141− echo -e "${TEST}: ${RED}FAIL${NC}"
142− exit 1
143−fi
144−echo -e "${TEST}: ${GREEN}PASS${NC}"
145−
146−TEST="TCPv6 connectivity test"
147−ip netns exec ${NS_SRC} bash -c "timeout ${TIMEOUT} dd if=/dev/zero bs=1000 count=100 > /dev/tcp/${IP6_DST}/9006"
148−if [ $? -ne 0 ]; then
149− echo -e "${TEST}: ${RED}FAIL${NC}"
150− exit 1
151−fi
152−echo -e "${TEST}: ${GREEN}PASS${NC}"
153−
154−TEST="ICMPv4 connectivity test"
155−ip netns exec ${NS_SRC} ping $PING_ARG ${IP4_DST}
156−if [ $? -ne 0 ]; then
157− echo -e "${TEST}: ${RED}FAIL${NC}"
158− exit 1
159−fi
160−echo -e "${TEST}: ${GREEN}PASS${NC}"
161−
162−TEST="ICMPv6 connectivity test"
163−ip netns exec ${NS_SRC} ping6 $PING_ARG ${IP6_DST}
164−if [ $? -ne 0 ]; then
165− echo -e "${TEST}: ${RED}FAIL${NC}"
166− exit 1
167−fi
168−echo -e "${TEST}: ${GREEN}PASS${NC}"
tools/testing/selftests/bpf/test_tc_redirect.sh+204−0
@@ -0,0 +1,204 @@
1+#!/bin/bash
2+# SPDX-License-Identifier: GPL-2.0
3+#
4+# This test sets up 3 netns (src <-> fwd <-> dst). There is no direct veth link
5+# between src and dst. The netns fwd has veth links to each src and dst. The
6+# client is in src and server in dst. The test installs a TC BPF program to each
7+# host facing veth in fwd which calls into i) bpf_redirect_neigh() to perform the
8+# neigh addr population and redirect or ii) bpf_redirect_peer() for namespace
9+# switch from ingress side; it also installs a checker prog on the egress side
10+# to drop unexpected traffic.
11+
12+if [[ $EUID -ne 0 ]]; then
13+ echo "This script must be run as root"
14+ echo "FAIL"
15+ exit 1
16+fi
17+
18+# check that needed tools are present
19+command -v nc >/dev/null 2>&1 || \
20+ { echo >&2 "nc is not available"; exit 1; }
21+command -v dd >/dev/null 2>&1 || \
22+ { echo >&2 "dd is not available"; exit 1; }
23+command -v timeout >/dev/null 2>&1 || \
24+ { echo >&2 "timeout is not available"; exit 1; }
25+command -v ping >/dev/null 2>&1 || \
26+ { echo >&2 "ping is not available"; exit 1; }
27+command -v ping6 >/dev/null 2>&1 || \
28+ { echo >&2 "ping6 is not available"; exit 1; }
29+command -v perl >/dev/null 2>&1 || \
30+ { echo >&2 "perl is not available"; exit 1; }
31+command -v jq >/dev/null 2>&1 || \
32+ { echo >&2 "jq is not available"; exit 1; }
33+command -v bpftool >/dev/null 2>&1 || \
34+ { echo >&2 "bpftool is not available"; exit 1; }
35+
36+readonly GREEN='\033[0;92m'
37+readonly RED='\033[0;31m'
38+readonly NC='\033[0m' # No Color
39+
40+readonly PING_ARG="-c 3 -w 10 -q"
41+
42+readonly TIMEOUT=10
43+
44+readonly NS_SRC="ns-src-$(mktemp -u XXXXXX)"
45+readonly NS_FWD="ns-fwd-$(mktemp -u XXXXXX)"
46+readonly NS_DST="ns-dst-$(mktemp -u XXXXXX)"
47+
48+readonly IP4_SRC="172.16.1.100"
49+readonly IP4_DST="172.16.2.100"
50+
51+readonly IP6_SRC="::1:dead:beef:cafe"
52+readonly IP6_DST="::2:dead:beef:cafe"
53+
54+readonly IP4_SLL="169.254.0.1"
55+readonly IP4_DLL="169.254.0.2"
56+readonly IP4_NET="169.254.0.0"
57+
58+netns_cleanup()
59+{
60+ ip netns del ${NS_SRC}
61+ ip netns del ${NS_FWD}
62+ ip netns del ${NS_DST}
63+}
64+
65+netns_setup()
66+{
67+ ip netns add "${NS_SRC}"
68+ ip netns add "${NS_FWD}"
69+ ip netns add "${NS_DST}"
70+
71+ ip link add veth_src type veth peer name veth_src_fwd
72+ ip link add veth_dst type veth peer name veth_dst_fwd
73+
74+ ip link set veth_src netns ${NS_SRC}
75+ ip link set veth_src_fwd netns ${NS_FWD}
76+
77+ ip link set veth_dst netns ${NS_DST}
78+ ip link set veth_dst_fwd netns ${NS_FWD}
79+
80+ ip -netns ${NS_SRC} addr add ${IP4_SRC}/32 dev veth_src
81+ ip -netns ${NS_DST} addr add ${IP4_DST}/32 dev veth_dst
82+
83+ # The fwd netns automatically get a v6 LL address / routes, but also
84+ # needs v4 one in order to start ARP probing. IP4_NET route is added
85+ # to the endpoints so that the ARP processing will reply.
86+
87+ ip -netns ${NS_FWD} addr add ${IP4_SLL}/32 dev veth_src_fwd
88+ ip -netns ${NS_FWD} addr add ${IP4_DLL}/32 dev veth_dst_fwd
89+
90+ ip -netns ${NS_SRC} addr add ${IP6_SRC}/128 dev veth_src nodad
91+ ip -netns ${NS_DST} addr add ${IP6_DST}/128 dev veth_dst nodad
92+
93+ ip -netns ${NS_SRC} link set dev veth_src up
94+ ip -netns ${NS_FWD} link set dev veth_src_fwd up
95+
96+ ip -netns ${NS_DST} link set dev veth_dst up
97+ ip -netns ${NS_FWD} link set dev veth_dst_fwd up
98+
99+ ip -netns ${NS_SRC} route add ${IP4_DST}/32 dev veth_src scope global
100+ ip -netns ${NS_SRC} route add ${IP4_NET}/16 dev veth_src scope global
101+ ip -netns ${NS_FWD} route add ${IP4_SRC}/32 dev veth_src_fwd scope global
102+
103+ ip -netns ${NS_SRC} route add ${IP6_DST}/128 dev veth_src scope global
104+ ip -netns ${NS_FWD} route add ${IP6_SRC}/128 dev veth_src_fwd scope global
105+
106+ ip -netns ${NS_DST} route add ${IP4_SRC}/32 dev veth_dst scope global
107+ ip -netns ${NS_DST} route add ${IP4_NET}/16 dev veth_dst scope global
108+ ip -netns ${NS_FWD} route add ${IP4_DST}/32 dev veth_dst_fwd scope global
109+
110+ ip -netns ${NS_DST} route add ${IP6_SRC}/128 dev veth_dst scope global
111+ ip -netns ${NS_FWD} route add ${IP6_DST}/128 dev veth_dst_fwd scope global
112+
113+ fmac_src=$(ip netns exec ${NS_FWD} cat /sys/class/net/veth_src_fwd/address)
114+ fmac_dst=$(ip netns exec ${NS_FWD} cat /sys/class/net/veth_dst_fwd/address)
115+
116+ ip -netns ${NS_SRC} neigh add ${IP4_DST} dev veth_src lladdr $fmac_src
117+ ip -netns ${NS_DST} neigh add ${IP4_SRC} dev veth_dst lladdr $fmac_dst
118+
119+ ip -netns ${NS_SRC} neigh add ${IP6_DST} dev veth_src lladdr $fmac_src
120+ ip -netns ${NS_DST} neigh add ${IP6_SRC} dev veth_dst lladdr $fmac_dst
121+}
122+
123+netns_test_connectivity()
124+{
125+ set +e
126+
127+ ip netns exec ${NS_DST} bash -c "nc -4 -l -p 9004 &"
128+ ip netns exec ${NS_DST} bash -c "nc -6 -l -p 9006 &"
129+
130+ TEST="TCPv4 connectivity test"
131+ ip netns exec ${NS_SRC} bash -c "timeout ${TIMEOUT} dd if=/dev/zero bs=1000 count=100 > /dev/tcp/${IP4_DST}/9004"
132+ if [ $? -ne 0 ]; then
133+ echo -e "${TEST}: ${RED}FAIL${NC}"
134+ exit 1
135+ fi
136+ echo -e "${TEST}: ${GREEN}PASS${NC}"
137+
138+ TEST="TCPv6 connectivity test"
139+ ip netns exec ${NS_SRC} bash -c "timeout ${TIMEOUT} dd if=/dev/zero bs=1000 count=100 > /dev/tcp/${IP6_DST}/9006"
140+ if [ $? -ne 0 ]; then
141+ echo -e "${TEST}: ${RED}FAIL${NC}"
142+ exit 1
143+ fi
144+ echo -e "${TEST}: ${GREEN}PASS${NC}"
145+
146+ TEST="ICMPv4 connectivity test"
147+ ip netns exec ${NS_SRC} ping $PING_ARG ${IP4_DST}
148+ if [ $? -ne 0 ]; then
149+ echo -e "${TEST}: ${RED}FAIL${NC}"
150+ exit 1
151+ fi
152+ echo -e "${TEST}: ${GREEN}PASS${NC}"
153+
154+ TEST="ICMPv6 connectivity test"
155+ ip netns exec ${NS_SRC} ping6 $PING_ARG ${IP6_DST}
156+ if [ $? -ne 0 ]; then
157+ echo -e "${TEST}: ${RED}FAIL${NC}"
158+ exit 1
159+ fi
160+ echo -e "${TEST}: ${GREEN}PASS${NC}"
161+
162+ set -e
163+}
164+
165+hex_mem_str()
166+{
167+ perl -e 'print join(" ", unpack("(H2)8", pack("L", @ARGV)))' $1
168+}
169+
170+netns_setup_bpf()
171+{
172+ local obj=$1
173+
174+ ip netns exec ${NS_FWD} tc qdisc add dev veth_src_fwd clsact
175+ ip netns exec ${NS_FWD} tc filter add dev veth_src_fwd ingress bpf da obj $obj sec src_ingress
176+ ip netns exec ${NS_FWD} tc filter add dev veth_src_fwd egress bpf da obj $obj sec chk_egress
177+
178+ ip netns exec ${NS_FWD} tc qdisc add dev veth_dst_fwd clsact
179+ ip netns exec ${NS_FWD} tc filter add dev veth_dst_fwd ingress bpf da obj $obj sec dst_ingress
180+ ip netns exec ${NS_FWD} tc filter add dev veth_dst_fwd egress bpf da obj $obj sec chk_egress
181+
182+ veth_src=$(ip netns exec ${NS_FWD} cat /sys/class/net/veth_src_fwd/ifindex)
183+ veth_dst=$(ip netns exec ${NS_FWD} cat /sys/class/net/veth_dst_fwd/ifindex)
184+
185+ progs=$(ip netns exec ${NS_FWD} bpftool net --json | jq -r '.[] | .tc | map(.id) | .[]')
186+ for prog in $progs; do
187+ map=$(bpftool prog show id $prog --json | jq -r '.map_ids | .? | .[]')
188+ if [ ! -z "$map" ]; then
189+ bpftool map update id $map key hex $(hex_mem_str 0) value hex $(hex_mem_str $veth_src)
190+ bpftool map update id $map key hex $(hex_mem_str 1) value hex $(hex_mem_str $veth_dst)
191+ fi
192+ done
193+}
194+
195+trap netns_cleanup EXIT
196+set -e
197+
198+netns_setup
199+netns_setup_bpf test_tc_neigh.o
200+netns_test_connectivity
201+netns_cleanup
202+netns_setup
203+netns_setup_bpf test_tc_peer.o
204+netns_test_connectivity
tools/testing/selftests/bpf/test_tcp_hdr_options.h+3−2
@@ -110,12 +110,13 @@ static inline void clear_hdr_cb_flags(struct bpf_sock_ops *skops) · 109 unmodified lines
110110 BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG));
111111 }
112112
113−static inline void set_hdr_cb_flags(struct bpf_sock_ops *skops)
113+static inline void set_hdr_cb_flags(struct bpf_sock_ops *skops, __u32 extra)
114114 {
115115 bpf_sock_ops_cb_flags_set(skops,
116116 skops->bpf_sock_ops_cb_flags |
117117 BPF_SOCK_OPS_PARSE_UNKNOWN_HDR_OPT_CB_FLAG |
118− BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG);
118+ BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG |
119+ extra);
119120 }
120121 static inline void
121122 clear_parse_all_hdr_cb_flags(struct bpf_sock_ops *skops)
tools/testing/selftests/bpf/trace_helpers.c+27−0
@@ -90,6 +90,33 @@ long ksym_get_addr(const char *name) · 89 unmodified lines
9090 return 0;
9191 }
9292
93+/* open kallsyms and read symbol addresses on the fly. Without caching all symbols,
94+ * this is faster than load + find.
95+ */
96+int kallsyms_find(const char *sym, unsigned long long *addr)
97+{
98+ char type, name[500];
99+ unsigned long long value;
100+ int err = 0;
101+ FILE *f;
102+
103+ f = fopen("/proc/kallsyms", "r");
104+ if (!f)
105+ return -EINVAL;
106+
107+ while (fscanf(f, "%llx %c %499s%*[^\n]\n", &value, &type, name) > 0) {
108+ if (strcmp(name, sym) == 0) {
109+ *addr = value;
110+ goto out;
111+ }
112+ }
113+ err = -ENOENT;
114+
115+out:
116+ fclose(f);
117+ return err;
118+}
119+
93120 void read_trace_pipe(void)
94121 {
95122 int trace_fd;
tools/testing/selftests/bpf/trace_helpers.h+4−0
@@ -12,6 +12,10 @@ struct ksym { · 11 unmodified lines
1212 int load_kallsyms(void);
1313 struct ksym *ksym_search(long key);
1414 long ksym_get_addr(const char *name);
15+
16+/* open kallsyms and find addresses on the fly, faster than load + search. */
17+int kallsyms_find(const char *sym, unsigned long long *addr);
18+
1519 void read_trace_pipe(void);
1620
1721 #endif
tools/testing/selftests/bpf/verifier/basic.c+1−1
@@ -2,7 +2,7 @@ · 1 unmodified line
22 "empty prog",
33 .insns = {
44 },
5− .errstr = "unknown opcode 00",
5+ .errstr = "last insn is not an exit or jmp",
66 .result = REJECT,
77 },
88 {
tools/testing/selftests/bpf/verifier/direct_packet_access.c+1−1
@@ -529,7 +529,7 @@ · 528 unmodified lines
529529 },
530530 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
531531 .result = REJECT,
532− .errstr = "invalid access to packet, off=0 size=8, R5(id=1,off=0,r=0)",
532+ .errstr = "invalid access to packet, off=0 size=8, R5(id=2,off=0,r=0)",
533533 .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
534534 },
535535 {
tools/testing/selftests/bpf/verifier/ld_imm64.c+0−8
@@ -50,14 +50,6 @@ · 49 unmodified lines
5050 .errstr = "invalid bpf_ld_imm64 insn",
5151 .result = REJECT,
5252 },
53−{
54− "test5 ld_imm64",
55− .insns = {
56− BPF_RAW_INSN(BPF_LD | BPF_IMM | BPF_DW, 0, 0, 0, 0),
57− },
58− .errstr = "invalid bpf_ld_imm64 insn",
59− .result = REJECT,
60−},
6153 {
6254 "test6 ld_imm64",
6355 .insns = {
tools/testing/selftests/bpf/verifier/regalloc.c+243−0
@@ -0,0 +1,243 @@
1+{
2+ "regalloc basic",
3+ .insns = {
4+ BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
5+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
6+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
7+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
8+ BPF_LD_MAP_FD(BPF_REG_1, 0),
9+ BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
10+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 8),
11+ BPF_MOV64_REG(BPF_REG_7, BPF_REG_0),
12+ BPF_EMIT_CALL(BPF_FUNC_get_prandom_u32),
13+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
14+ BPF_JMP_IMM(BPF_JSGT, BPF_REG_0, 20, 4),
15+ BPF_JMP_IMM(BPF_JSLT, BPF_REG_2, 0, 3),
16+ BPF_ALU64_REG(BPF_ADD, BPF_REG_7, BPF_REG_0),
17+ BPF_ALU64_REG(BPF_ADD, BPF_REG_7, BPF_REG_2),
18+ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_7, 0),
19+ BPF_EXIT_INSN(),
20+ },
21+ .fixup_map_hash_48b = { 4 },
22+ .result = ACCEPT,
23+ .prog_type = BPF_PROG_TYPE_TRACEPOINT,
24+},
25+{
26+ "regalloc negative",
27+ .insns = {
28+ BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
29+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
30+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
31+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
32+ BPF_LD_MAP_FD(BPF_REG_1, 0),
33+ BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
34+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 8),
35+ BPF_MOV64_REG(BPF_REG_7, BPF_REG_0),
36+ BPF_EMIT_CALL(BPF_FUNC_get_prandom_u32),
37+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
38+ BPF_JMP_IMM(BPF_JSGT, BPF_REG_0, 24, 4),
39+ BPF_JMP_IMM(BPF_JSLT, BPF_REG_2, 0, 3),
40+ BPF_ALU64_REG(BPF_ADD, BPF_REG_7, BPF_REG_0),
41+ BPF_ALU64_REG(BPF_ADD, BPF_REG_7, BPF_REG_2),
42+ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_7, 0),
43+ BPF_EXIT_INSN(),
44+ },
45+ .fixup_map_hash_48b = { 4 },
46+ .result = REJECT,
47+ .errstr = "invalid access to map value, value_size=48 off=48 size=1",
48+ .prog_type = BPF_PROG_TYPE_TRACEPOINT,
49+},
50+{
51+ "regalloc src_reg mark",
52+ .insns = {
53+ BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
54+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
55+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
56+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
57+ BPF_LD_MAP_FD(BPF_REG_1, 0),
58+ BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
59+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 9),
60+ BPF_MOV64_REG(BPF_REG_7, BPF_REG_0),
61+ BPF_EMIT_CALL(BPF_FUNC_get_prandom_u32),
62+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
63+ BPF_JMP_IMM(BPF_JSGT, BPF_REG_0, 20, 5),
64+ BPF_MOV64_IMM(BPF_REG_3, 0),
65+ BPF_JMP_REG(BPF_JSGE, BPF_REG_3, BPF_REG_2, 3),
66+ BPF_ALU64_REG(BPF_ADD, BPF_REG_7, BPF_REG_0),
67+ BPF_ALU64_REG(BPF_ADD, BPF_REG_7, BPF_REG_2),
68+ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_7, 0),
69+ BPF_EXIT_INSN(),
70+ },
71+ .fixup_map_hash_48b = { 4 },
72+ .result = ACCEPT,
73+ .prog_type = BPF_PROG_TYPE_TRACEPOINT,
74+},
75+{
76+ "regalloc src_reg negative",
77+ .insns = {
78+ BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
79+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
80+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
81+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
82+ BPF_LD_MAP_FD(BPF_REG_1, 0),
83+ BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
84+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 9),
85+ BPF_MOV64_REG(BPF_REG_7, BPF_REG_0),
86+ BPF_EMIT_CALL(BPF_FUNC_get_prandom_u32),
87+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
88+ BPF_JMP_IMM(BPF_JSGT, BPF_REG_0, 22, 5),
89+ BPF_MOV64_IMM(BPF_REG_3, 0),
90+ BPF_JMP_REG(BPF_JSGE, BPF_REG_3, BPF_REG_2, 3),
91+ BPF_ALU64_REG(BPF_ADD, BPF_REG_7, BPF_REG_0),
92+ BPF_ALU64_REG(BPF_ADD, BPF_REG_7, BPF_REG_2),
93+ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_7, 0),
94+ BPF_EXIT_INSN(),
95+ },
96+ .fixup_map_hash_48b = { 4 },
97+ .result = REJECT,
98+ .errstr = "invalid access to map value, value_size=48 off=44 size=8",
99+ .prog_type = BPF_PROG_TYPE_TRACEPOINT,
100+},
101+{
102+ "regalloc and spill",
103+ .insns = {
104+ BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
105+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
106+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
107+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
108+ BPF_LD_MAP_FD(BPF_REG_1, 0),
109+ BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
110+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 11),
111+ BPF_MOV64_REG(BPF_REG_7, BPF_REG_0),
112+ BPF_EMIT_CALL(BPF_FUNC_get_prandom_u32),
113+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
114+ BPF_JMP_IMM(BPF_JSGT, BPF_REG_0, 20, 7),
115+ /* r0 has upper bound that should propagate into r2 */
116+ BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -8), /* spill r2 */
117+ BPF_MOV64_IMM(BPF_REG_0, 0),
118+ BPF_MOV64_IMM(BPF_REG_2, 0), /* clear r0 and r2 */
119+ BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_10, -8), /* fill r3 */
120+ BPF_JMP_REG(BPF_JSGE, BPF_REG_0, BPF_REG_3, 2),
121+ /* r3 has lower and upper bounds */
122+ BPF_ALU64_REG(BPF_ADD, BPF_REG_7, BPF_REG_3),
123+ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_7, 0),
124+ BPF_EXIT_INSN(),
125+ },
126+ .fixup_map_hash_48b = { 4 },
127+ .result = ACCEPT,
128+ .prog_type = BPF_PROG_TYPE_TRACEPOINT,
129+},
130+{
131+ "regalloc and spill negative",
132+ .insns = {
133+ BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
134+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
135+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
136+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
137+ BPF_LD_MAP_FD(BPF_REG_1, 0),
138+ BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
139+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 11),
140+ BPF_MOV64_REG(BPF_REG_7, BPF_REG_0),
141+ BPF_EMIT_CALL(BPF_FUNC_get_prandom_u32),
142+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
143+ BPF_JMP_IMM(BPF_JSGT, BPF_REG_0, 48, 7),
144+ /* r0 has upper bound that should propagate into r2 */
145+ BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -8), /* spill r2 */
146+ BPF_MOV64_IMM(BPF_REG_0, 0),
147+ BPF_MOV64_IMM(BPF_REG_2, 0), /* clear r0 and r2 */
148+ BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_10, -8), /* fill r3 */
149+ BPF_JMP_REG(BPF_JSGE, BPF_REG_0, BPF_REG_3, 2),
150+ /* r3 has lower and upper bounds */
151+ BPF_ALU64_REG(BPF_ADD, BPF_REG_7, BPF_REG_3),
152+ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_7, 0),
153+ BPF_EXIT_INSN(),
154+ },
155+ .fixup_map_hash_48b = { 4 },
156+ .result = REJECT,
157+ .errstr = "invalid access to map value, value_size=48 off=48 size=8",
158+ .prog_type = BPF_PROG_TYPE_TRACEPOINT,
159+},
160+{
161+ "regalloc three regs",
162+ .insns = {
163+ BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
164+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
165+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
166+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
167+ BPF_LD_MAP_FD(BPF_REG_1, 0),
168+ BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
169+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 10),
170+ BPF_MOV64_REG(BPF_REG_7, BPF_REG_0),
171+ BPF_EMIT_CALL(BPF_FUNC_get_prandom_u32),
172+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
173+ BPF_MOV64_REG(BPF_REG_4, BPF_REG_2),
174+ BPF_JMP_IMM(BPF_JSGT, BPF_REG_0, 12, 5),
175+ BPF_JMP_IMM(BPF_JSLT, BPF_REG_2, 0, 4),
176+ BPF_ALU64_REG(BPF_ADD, BPF_REG_7, BPF_REG_0),
177+ BPF_ALU64_REG(BPF_ADD, BPF_REG_7, BPF_REG_2),
178+ BPF_ALU64_REG(BPF_ADD, BPF_REG_7, BPF_REG_4),
179+ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_7, 0),
180+ BPF_EXIT_INSN(),
181+ },
182+ .fixup_map_hash_48b = { 4 },
183+ .result = ACCEPT,
184+ .prog_type = BPF_PROG_TYPE_TRACEPOINT,
185+},
186+{
187+ "regalloc after call",
188+ .insns = {
189+ BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
190+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
191+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
192+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
193+ BPF_LD_MAP_FD(BPF_REG_1, 0),
194+ BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
195+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 10),
196+ BPF_MOV64_REG(BPF_REG_7, BPF_REG_0),
197+ BPF_EMIT_CALL(BPF_FUNC_get_prandom_u32),
198+ BPF_MOV64_REG(BPF_REG_8, BPF_REG_0),
199+ BPF_MOV64_REG(BPF_REG_9, BPF_REG_0),
200+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 6),
201+ BPF_JMP_IMM(BPF_JSGT, BPF_REG_8, 20, 4),
202+ BPF_JMP_IMM(BPF_JSLT, BPF_REG_9, 0, 3),
203+ BPF_ALU64_REG(BPF_ADD, BPF_REG_7, BPF_REG_8),
204+ BPF_ALU64_REG(BPF_ADD, BPF_REG_7, BPF_REG_9),
205+ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_7, 0),
206+ BPF_EXIT_INSN(),
207+ BPF_MOV64_IMM(BPF_REG_0, 0),
208+ BPF_EXIT_INSN(),
209+ },
210+ .fixup_map_hash_48b = { 4 },
211+ .result = ACCEPT,
212+ .prog_type = BPF_PROG_TYPE_TRACEPOINT,
213+},
214+{
215+ "regalloc in callee",
216+ .insns = {
217+ BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
218+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
219+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
220+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
221+ BPF_LD_MAP_FD(BPF_REG_1, 0),
222+ BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
223+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6),
224+ BPF_MOV64_REG(BPF_REG_7, BPF_REG_0),
225+ BPF_EMIT_CALL(BPF_FUNC_get_prandom_u32),
226+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
227+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
228+ BPF_MOV64_REG(BPF_REG_3, BPF_REG_7),
229+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 1),
230+ BPF_EXIT_INSN(),
231+ BPF_JMP_IMM(BPF_JSGT, BPF_REG_1, 20, 5),
232+ BPF_JMP_IMM(BPF_JSLT, BPF_REG_2, 0, 4),
233+ BPF_ALU64_REG(BPF_ADD, BPF_REG_3, BPF_REG_1),
234+ BPF_ALU64_REG(BPF_ADD, BPF_REG_3, BPF_REG_2),
235+ BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_3, 0),
236+ BPF_EXIT_INSN(),
237+ BPF_MOV64_IMM(BPF_REG_0, 0),
238+ BPF_EXIT_INSN(),
239+ },
240+ .fixup_map_hash_48b = { 4 },
241+ .result = ACCEPT,
242+ .prog_type = BPF_PROG_TYPE_TRACEPOINT,
243+},