1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2019 Facebook */
3 #include <linux/stddef.h>
4 #include <linux/if_ether.h>
5 #include <linux/ipv6.h>
8 #include <bpf/bpf_helpers.h>
9 #include <bpf/bpf_endian.h>
10 #include <bpf/bpf_tracing.h>
16 __u64 test_result
= 0;
17 SEC("fexit/test_pkt_access")
18 int BPF_PROG(test_main
, struct sk_buff
*skb
, int ret
)
22 __builtin_preserve_access_index(({
25 if (len
!= 74 || ret
!= 0)
31 __u64 test_result_subprog1
= 0;
32 SEC("fexit/test_pkt_access_subprog1")
33 int BPF_PROG(test_subprog1
, struct sk_buff
*skb
, int ret
)
37 __builtin_preserve_access_index(({
40 if (len
!= 74 || ret
!= 148)
42 test_result_subprog1
= 1;
46 /* Though test_pkt_access_subprog2() is defined in C as:
47 * static __attribute__ ((noinline))
48 * int test_pkt_access_subprog2(int val, volatile struct __sk_buff *skb)
50 * return skb->len * val;
52 * llvm optimizations remove 'int val' argument and generate BPF assembly:
53 * r0 = *(u32 *)(r1 + 0)
56 * In such case the verifier falls back to conservative and
57 * tracing program can access arguments and return value as u64
58 * instead of accurate types.
60 struct args_subprog2
{
64 __u64 test_result_subprog2
= 0;
65 SEC("fexit/test_pkt_access_subprog2")
66 int test_subprog2(struct args_subprog2
*ctx
)
68 struct sk_buff
*skb
= (void *)ctx
->args
[0];
72 bpf_probe_read_kernel(&len
, sizeof(len
),
73 __builtin_preserve_access_index(&skb
->len
));
76 /* bpf_prog_load() loads "test_pkt_access.o" with BPF_F_TEST_RND_HI32
77 * which randomizes upper 32 bits after BPF_ALU32 insns.
78 * Hence after 'w0 <<= 1' upper bits of $rax are random.
79 * That is expected and correct. Trim them.
82 if (len
!= 74 || ret
!= 148)
84 test_result_subprog2
= 1;
88 __u64 test_result_subprog3
= 0;
89 SEC("fexit/test_pkt_access_subprog3")
90 int BPF_PROG(test_subprog3
, int val
, struct sk_buff
*skb
, int ret
)
94 __builtin_preserve_access_index(({
97 if (len
!= 74 || ret
!= 74 * val
|| val
!= 3)
99 test_result_subprog3
= 1;
103 __u64 test_get_skb_len
= 0;
104 SEC("freplace/get_skb_len")
105 int new_get_skb_len(struct __sk_buff
*skb
)
111 test_get_skb_len
= 1;
112 return 74; /* original get_skb_len() returns skb->len */
115 __u64 test_get_skb_ifindex
= 0;
116 SEC("freplace/get_skb_ifindex")
117 int new_get_skb_ifindex(int val
, struct __sk_buff
*skb
, int var
)
119 void *data_end
= (void *)(long)skb
->data_end
;
120 void *data
= (void *)(long)skb
->data
;
121 struct ipv6hdr ip6
, *ip6p
;
122 int ifindex
= skb
->ifindex
;
126 /* check that BPF extension can read packet via direct packet access */
127 if (data
+ 14 + sizeof(ip6
) > data_end
)
131 if (ip6p
->nexthdr
!= 6 || ip6p
->payload_len
!= __bpf_constant_htons(123))
134 /* check that legacy packet access helper works too */
135 if (bpf_skb_load_bytes(skb
, 14, &ip6
, sizeof(ip6
)) < 0)
138 if (ip6p
->nexthdr
!= 6 || ip6p
->payload_len
!= __bpf_constant_htons(123))
141 if (ifindex
!= 1 || val
!= 3 || var
!= 1)
143 test_get_skb_ifindex
= 1;
144 return 3; /* original get_skb_ifindex() returns val * ifindex * var */
147 volatile __u64 test_get_constant
= 0;
148 SEC("freplace/get_constant")
149 int new_get_constant(long val
)
153 test_get_constant
= 1;
154 return test_get_constant
; /* original get_constant() returns val - 122 */
157 __u64 test_pkt_write_access_subprog
= 0;
158 SEC("freplace/test_pkt_write_access_subprog")
159 int new_test_pkt_write_access_subprog(struct __sk_buff
*skb
, __u32 off
)
162 void *data
= (void *)(long)skb
->data
;
163 void *data_end
= (void *)(long)skb
->data_end
;
166 if (off
> sizeof(struct ethhdr
) + sizeof(struct ipv6hdr
))
170 if (tcp
+ 1 > data_end
)
173 /* make modifications to the packet data */
177 test_pkt_write_access_subprog
= 1;
181 char _license
[] SEC("license") = "GPL";