1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2020 Cloudflare
3 
4 #include <errno.h>
5 #include <stdbool.h>
6 #include <linux/bpf.h>
7 
8 #include <bpf/bpf_helpers.h>
9 
10 struct {
11 	__uint(type, BPF_MAP_TYPE_SOCKMAP);
12 	__uint(max_entries, 2);
13 	__type(key, __u32);
14 	__type(value, __u64);
15 } sock_map SEC(".maps");
16 
17 struct {
18 	__uint(type, BPF_MAP_TYPE_SOCKHASH);
19 	__uint(max_entries, 2);
20 	__type(key, __u32);
21 	__type(value, __u64);
22 } sock_hash SEC(".maps");
23 
24 struct {
25 	__uint(type, BPF_MAP_TYPE_ARRAY);
26 	__uint(max_entries, 2);
27 	__type(key, int);
28 	__type(value, unsigned int);
29 } verdict_map SEC(".maps");
30 
31 struct {
32 	__uint(type, BPF_MAP_TYPE_ARRAY);
33 	__uint(max_entries, 1);
34 	__type(key, int);
35 	__type(value, int);
36 } parser_map SEC(".maps");
37 
38 bool test_sockmap = false; /* toggled by user-space */
39 bool test_ingress = false; /* toggled by user-space */
40 
41 SEC("sk_skb/stream_parser")
42 int prog_stream_parser(struct __sk_buff *skb)
43 {
44 	int *value;
45 	__u32 key = 0;
46 
47 	value = bpf_map_lookup_elem(&parser_map, &key);
48 	if (value && *value)
49 		return *value;
50 
51 	return skb->len;
52 }
53 
54 SEC("sk_skb/stream_verdict")
55 int prog_stream_verdict(struct __sk_buff *skb)
56 {
57 	unsigned int *count;
58 	__u32 zero = 0;
59 	int verdict;
60 
61 	if (test_sockmap)
62 		verdict = bpf_sk_redirect_map(skb, &sock_map, zero, 0);
63 	else
64 		verdict = bpf_sk_redirect_hash(skb, &sock_hash, &zero, 0);
65 
66 	count = bpf_map_lookup_elem(&verdict_map, &verdict);
67 	if (count)
68 		(*count)++;
69 
70 	return verdict;
71 }
72 
73 SEC("sk_skb")
74 int prog_skb_verdict(struct __sk_buff *skb)
75 {
76 	unsigned int *count;
77 	__u32 zero = 0;
78 	int verdict;
79 
80 	if (test_sockmap)
81 		verdict = bpf_sk_redirect_map(skb, &sock_map, zero,
82 					      test_ingress ? BPF_F_INGRESS : 0);
83 	else
84 		verdict = bpf_sk_redirect_hash(skb, &sock_hash, &zero,
85 					       test_ingress ? BPF_F_INGRESS : 0);
86 
87 	count = bpf_map_lookup_elem(&verdict_map, &verdict);
88 	if (count)
89 		(*count)++;
90 
91 	return verdict;
92 }
93 
94 SEC("sk_msg")
95 int prog_msg_verdict(struct sk_msg_md *msg)
96 {
97 	unsigned int *count;
98 	__u32 zero = 0;
99 	int verdict;
100 
101 	if (test_sockmap)
102 		verdict = bpf_msg_redirect_map(msg, &sock_map, zero, 0);
103 	else
104 		verdict = bpf_msg_redirect_hash(msg, &sock_hash, &zero, 0);
105 
106 	count = bpf_map_lookup_elem(&verdict_map, &verdict);
107 	if (count)
108 		(*count)++;
109 
110 	return verdict;
111 }
112 
113 SEC("sk_reuseport")
114 int prog_reuseport(struct sk_reuseport_md *reuse)
115 {
116 	unsigned int *count;
117 	int err, verdict;
118 	__u32 zero = 0;
119 
120 	if (test_sockmap)
121 		err = bpf_sk_select_reuseport(reuse, &sock_map, &zero, 0);
122 	else
123 		err = bpf_sk_select_reuseport(reuse, &sock_hash, &zero, 0);
124 	verdict = err ? SK_DROP : SK_PASS;
125 
126 	count = bpf_map_lookup_elem(&verdict_map, &verdict);
127 	if (count)
128 		(*count)++;
129 
130 	return verdict;
131 }
132 
133 char _license[] SEC("license") = "GPL";
134