Skip to content

Commit 91bc357

Browse files
Petar PenkovAlexei Starovoitov
authored andcommitted
selftests/bpf: add test for bpf_tcp_gen_syncookie
Modify the existing bpf_tcp_check_syncookie test to also generate a SYN cookie, pass the packet to the kernel, and verify that the two cookies are the same (and both valid). Since cloned SKBs are skipped during generic XDP, this test does not issue a SYN cookie when run in XDP mode. We therefore only check that a valid SYN cookie was issued at the TC hook. Additionally, verify that the MSS for that SYN cookie is within expected range. Signed-off-by: Petar Penkov <[email protected]> Reviewed-by: Lorenz Bauer <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent 637f71c commit 91bc357

File tree

3 files changed

+99
-13
lines changed

3 files changed

+99
-13
lines changed

tools/testing/selftests/bpf/progs/test_tcp_check_syncookie_kern.c

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,29 @@
1919
struct bpf_map_def SEC("maps") results = {
2020
.type = BPF_MAP_TYPE_ARRAY,
2121
.key_size = sizeof(__u32),
22-
.value_size = sizeof(__u64),
23-
.max_entries = 1,
22+
.value_size = sizeof(__u32),
23+
.max_entries = 3,
2424
};
2525

26+
static __always_inline __s64 gen_syncookie(void *data_end, struct bpf_sock *sk,
27+
void *iph, __u32 ip_size,
28+
struct tcphdr *tcph)
29+
{
30+
__u32 thlen = tcph->doff * 4;
31+
32+
if (tcph->syn && !tcph->ack) {
33+
// packet should only have an MSS option
34+
if (thlen != 24)
35+
return 0;
36+
37+
if ((void *)tcph + thlen > data_end)
38+
return 0;
39+
40+
return bpf_tcp_gen_syncookie(sk, iph, ip_size, tcph, thlen);
41+
}
42+
return 0;
43+
}
44+
2645
static __always_inline void check_syncookie(void *ctx, void *data,
2746
void *data_end)
2847
{
@@ -33,8 +52,10 @@ static __always_inline void check_syncookie(void *ctx, void *data,
3352
struct ipv6hdr *ipv6h;
3453
struct tcphdr *tcph;
3554
int ret;
55+
__u32 key_mss = 2;
56+
__u32 key_gen = 1;
3657
__u32 key = 0;
37-
__u64 value = 1;
58+
__s64 seq_mss;
3859

3960
ethh = data;
4061
if (ethh + 1 > data_end)
@@ -66,6 +87,9 @@ static __always_inline void check_syncookie(void *ctx, void *data,
6687
if (sk->state != BPF_TCP_LISTEN)
6788
goto release;
6889

90+
seq_mss = gen_syncookie(data_end, sk, ipv4h, sizeof(*ipv4h),
91+
tcph);
92+
6993
ret = bpf_tcp_check_syncookie(sk, ipv4h, sizeof(*ipv4h),
7094
tcph, sizeof(*tcph));
7195
break;
@@ -95,6 +119,9 @@ static __always_inline void check_syncookie(void *ctx, void *data,
95119
if (sk->state != BPF_TCP_LISTEN)
96120
goto release;
97121

122+
seq_mss = gen_syncookie(data_end, sk, ipv6h, sizeof(*ipv6h),
123+
tcph);
124+
98125
ret = bpf_tcp_check_syncookie(sk, ipv6h, sizeof(*ipv6h),
99126
tcph, sizeof(*tcph));
100127
break;
@@ -103,8 +130,19 @@ static __always_inline void check_syncookie(void *ctx, void *data,
103130
return;
104131
}
105132

106-
if (ret == 0)
107-
bpf_map_update_elem(&results, &key, &value, 0);
133+
if (seq_mss > 0) {
134+
__u32 cookie = (__u32)seq_mss;
135+
__u32 mss = seq_mss >> 32;
136+
137+
bpf_map_update_elem(&results, &key_gen, &cookie, 0);
138+
bpf_map_update_elem(&results, &key_mss, &mss, 0);
139+
}
140+
141+
if (ret == 0) {
142+
__u32 cookie = bpf_ntohl(tcph->ack_seq) - 1;
143+
144+
bpf_map_update_elem(&results, &key, &cookie, 0);
145+
}
108146

109147
release:
110148
bpf_sk_release(sk);

tools/testing/selftests/bpf/test_tcp_check_syncookie.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ setup()
3737
ns1_exec ip link set lo up
3838

3939
ns1_exec sysctl -w net.ipv4.tcp_syncookies=2
40+
ns1_exec sysctl -w net.ipv4.tcp_window_scaling=0
41+
ns1_exec sysctl -w net.ipv4.tcp_timestamps=0
42+
ns1_exec sysctl -w net.ipv4.tcp_sack=0
4043

4144
wait_for_ip 127.0.0.1
4245
wait_for_ip ::1

tools/testing/selftests/bpf/test_tcp_check_syncookie_user.c

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Copyright (c) 2018 Facebook
33
// Copyright (c) 2019 Cloudflare
44

5+
#include <limits.h>
56
#include <string.h>
67
#include <stdlib.h>
78
#include <unistd.h>
@@ -77,7 +78,7 @@ static int connect_to_server(int server_fd)
7778
return fd;
7879
}
7980

80-
static int get_map_fd_by_prog_id(int prog_id)
81+
static int get_map_fd_by_prog_id(int prog_id, bool *xdp)
8182
{
8283
struct bpf_prog_info info = {};
8384
__u32 info_len = sizeof(info);
@@ -104,6 +105,8 @@ static int get_map_fd_by_prog_id(int prog_id)
104105
goto err;
105106
}
106107

108+
*xdp = info.type == BPF_PROG_TYPE_XDP;
109+
107110
map_fd = bpf_map_get_fd_by_id(map_ids[0]);
108111
if (map_fd < 0)
109112
log_err("Failed to get fd by map id %d", map_ids[0]);
@@ -113,18 +116,32 @@ static int get_map_fd_by_prog_id(int prog_id)
113116
return map_fd;
114117
}
115118

116-
static int run_test(int server_fd, int results_fd)
119+
static int run_test(int server_fd, int results_fd, bool xdp)
117120
{
118121
int client = -1, srv_client = -1;
119122
int ret = 0;
120123
__u32 key = 0;
121-
__u64 value = 0;
124+
__u32 key_gen = 1;
125+
__u32 key_mss = 2;
126+
__u32 value = 0;
127+
__u32 value_gen = 0;
128+
__u32 value_mss = 0;
122129

123130
if (bpf_map_update_elem(results_fd, &key, &value, 0) < 0) {
124131
log_err("Can't clear results");
125132
goto err;
126133
}
127134

135+
if (bpf_map_update_elem(results_fd, &key_gen, &value_gen, 0) < 0) {
136+
log_err("Can't clear results");
137+
goto err;
138+
}
139+
140+
if (bpf_map_update_elem(results_fd, &key_mss, &value_mss, 0) < 0) {
141+
log_err("Can't clear results");
142+
goto err;
143+
}
144+
128145
client = connect_to_server(server_fd);
129146
if (client == -1)
130147
goto err;
@@ -140,8 +157,35 @@ static int run_test(int server_fd, int results_fd)
140157
goto err;
141158
}
142159

143-
if (value != 1) {
144-
log_err("Didn't match syncookie: %llu", value);
160+
if (value == 0) {
161+
log_err("Didn't match syncookie: %u", value);
162+
goto err;
163+
}
164+
165+
if (bpf_map_lookup_elem(results_fd, &key_gen, &value_gen) < 0) {
166+
log_err("Can't lookup result");
167+
goto err;
168+
}
169+
170+
if (xdp && value_gen == 0) {
171+
// SYN packets do not get passed through generic XDP, skip the
172+
// rest of the test.
173+
printf("Skipping XDP cookie check\n");
174+
goto out;
175+
}
176+
177+
if (bpf_map_lookup_elem(results_fd, &key_mss, &value_mss) < 0) {
178+
log_err("Can't lookup result");
179+
goto err;
180+
}
181+
182+
if (value != value_gen) {
183+
log_err("BPF generated cookie does not match kernel one");
184+
goto err;
185+
}
186+
187+
if (value_mss < 536 || value_mss > USHRT_MAX) {
188+
log_err("Unexpected MSS retrieved");
145189
goto err;
146190
}
147191

@@ -163,13 +207,14 @@ int main(int argc, char **argv)
163207
int server_v6 = -1;
164208
int results = -1;
165209
int err = 0;
210+
bool xdp;
166211

167212
if (argc < 2) {
168213
fprintf(stderr, "Usage: %s prog_id\n", argv[0]);
169214
exit(1);
170215
}
171216

172-
results = get_map_fd_by_prog_id(atoi(argv[1]));
217+
results = get_map_fd_by_prog_id(atoi(argv[1]), &xdp);
173218
if (results < 0) {
174219
log_err("Can't get map");
175220
goto err;
@@ -194,10 +239,10 @@ int main(int argc, char **argv)
194239
if (server_v6 == -1)
195240
goto err;
196241

197-
if (run_test(server, results))
242+
if (run_test(server, results, xdp))
198243
goto err;
199244

200-
if (run_test(server_v6, results))
245+
if (run_test(server_v6, results, xdp))
201246
goto err;
202247

203248
printf("ok\n");

0 commit comments

Comments
 (0)