1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2020 Facebook */
8 #include <sys/socket.h>
10 #include <linux/socket.h>
11 #include <linux/bpf.h>
12 #include <linux/types.h>
13 #include <bpf/bpf_helpers.h>
14 #include <bpf/bpf_endian.h>
15 #define BPF_PROG_TEST_TCP_HDR_OPTIONS
16 #include "test_tcp_hdr_options.h"
19 #define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER))
22 __u8 test_kind
= TCPOPT_EXP
;
23 __u16 test_magic
= 0xeB9F;
24 __u32 inherit_cb_flags
= 0;
26 struct bpf_test_option passive_synack_out
= {};
27 struct bpf_test_option passive_fin_out
= {};
29 struct bpf_test_option passive_estab_in
= {};
30 struct bpf_test_option passive_fin_in
= {};
32 struct bpf_test_option active_syn_out
= {};
33 struct bpf_test_option active_fin_out
= {};
35 struct bpf_test_option active_estab_in
= {};
36 struct bpf_test_option active_fin_in
= {};
39 __uint(type
, BPF_MAP_TYPE_SK_STORAGE
);
40 __uint(map_flags
, BPF_F_NO_PREALLOC
);
42 __type(value
, struct hdr_stg
);
43 } hdr_stg_map
SEC(".maps");
45 static bool skops_want_cookie(const struct bpf_sock_ops
*skops
)
47 return skops
->args
[0] == BPF_WRITE_HDR_TCP_SYNACK_COOKIE
;
50 static bool skops_current_mss(const struct bpf_sock_ops
*skops
)
52 return skops
->args
[0] == BPF_WRITE_HDR_TCP_CURRENT_MSS
;
55 static __u8
option_total_len(__u8 flags
)
57 __u8 i
, len
= 1; /* +1 for flags */
62 /* RESEND bit does not use a byte */
63 for (i
= OPTION_RESEND
+ 1; i
< __NR_OPTION_FLAGS
; i
++)
64 len
+= !!TEST_OPTION_FLAGS(flags
, i
);
66 if (test_kind
== TCPOPT_EXP
)
67 return len
+ TCP_BPF_EXPOPT_BASE_LEN
;
69 return len
+ 2; /* +1 kind, +1 kind-len */
72 static void write_test_option(const struct bpf_test_option
*test_opt
,
77 data
[offset
++] = test_opt
->flags
;
78 if (TEST_OPTION_FLAGS(test_opt
->flags
, OPTION_MAX_DELACK_MS
))
79 data
[offset
++] = test_opt
->max_delack_ms
;
81 if (TEST_OPTION_FLAGS(test_opt
->flags
, OPTION_RAND
))
82 data
[offset
++] = test_opt
->rand
;
85 static int store_option(struct bpf_sock_ops
*skops
,
86 const struct bpf_test_option
*test_opt
)
89 struct tcp_exprm_opt exprm
;
90 struct tcp_opt regular
;
94 if (test_kind
== TCPOPT_EXP
) {
95 write_opt
.exprm
.kind
= TCPOPT_EXP
;
96 write_opt
.exprm
.len
= option_total_len(test_opt
->flags
);
97 write_opt
.exprm
.magic
= __bpf_htons(test_magic
);
98 write_opt
.exprm
.data32
= 0;
99 write_test_option(test_opt
, write_opt
.exprm
.data
);
100 err
= bpf_store_hdr_opt(skops
, &write_opt
.exprm
,
101 sizeof(write_opt
.exprm
), 0);
103 write_opt
.regular
.kind
= test_kind
;
104 write_opt
.regular
.len
= option_total_len(test_opt
->flags
);
105 write_opt
.regular
.data32
= 0;
106 write_test_option(test_opt
, write_opt
.regular
.data
);
107 err
= bpf_store_hdr_opt(skops
, &write_opt
.regular
,
108 sizeof(write_opt
.regular
), 0);
117 static int parse_test_option(struct bpf_test_option
*opt
, const __u8
*start
)
119 opt
->flags
= *start
++;
121 if (TEST_OPTION_FLAGS(opt
->flags
, OPTION_MAX_DELACK_MS
))
122 opt
->max_delack_ms
= *start
++;
124 if (TEST_OPTION_FLAGS(opt
->flags
, OPTION_RAND
))
125 opt
->rand
= *start
++;
130 static int load_option(struct bpf_sock_ops
*skops
,
131 struct bpf_test_option
*test_opt
, bool from_syn
)
134 struct tcp_exprm_opt exprm
;
135 struct tcp_opt regular
;
137 int ret
, load_flags
= from_syn
? BPF_LOAD_HDR_OPT_TCP_SYN
: 0;
139 if (test_kind
== TCPOPT_EXP
) {
140 search_opt
.exprm
.kind
= TCPOPT_EXP
;
141 search_opt
.exprm
.len
= 4;
142 search_opt
.exprm
.magic
= __bpf_htons(test_magic
);
143 search_opt
.exprm
.data32
= 0;
144 ret
= bpf_load_hdr_opt(skops
, &search_opt
.exprm
,
145 sizeof(search_opt
.exprm
), load_flags
);
148 return parse_test_option(test_opt
, search_opt
.exprm
.data
);
150 search_opt
.regular
.kind
= test_kind
;
151 search_opt
.regular
.len
= 0;
152 search_opt
.regular
.data32
= 0;
153 ret
= bpf_load_hdr_opt(skops
, &search_opt
.regular
,
154 sizeof(search_opt
.regular
), load_flags
);
157 return parse_test_option(test_opt
, search_opt
.regular
.data
);
161 static int synack_opt_len(struct bpf_sock_ops
*skops
)
163 struct bpf_test_option test_opt
= {};
167 if (!passive_synack_out
.flags
)
170 err
= load_option(skops
, &test_opt
, true);
172 /* bpf_test_option is not found */
179 optlen
= option_total_len(passive_synack_out
.flags
);
181 err
= bpf_reserve_hdr_opt(skops
, optlen
, 0);
189 static int write_synack_opt(struct bpf_sock_ops
*skops
)
191 struct bpf_test_option opt
;
193 if (!passive_synack_out
.flags
)
194 /* We should not even be called since no header
195 * space has been reserved.
199 opt
= passive_synack_out
;
200 if (skops_want_cookie(skops
))
201 SET_OPTION_FLAGS(opt
.flags
, OPTION_RESEND
);
203 return store_option(skops
, &opt
);
206 static int syn_opt_len(struct bpf_sock_ops
*skops
)
211 if (!active_syn_out
.flags
)
214 optlen
= option_total_len(active_syn_out
.flags
);
216 err
= bpf_reserve_hdr_opt(skops
, optlen
, 0);
224 static int write_syn_opt(struct bpf_sock_ops
*skops
)
226 if (!active_syn_out
.flags
)
229 return store_option(skops
, &active_syn_out
);
232 static int fin_opt_len(struct bpf_sock_ops
*skops
)
234 struct bpf_test_option
*opt
;
235 struct hdr_stg
*hdr_stg
;
242 hdr_stg
= bpf_sk_storage_get(&hdr_stg_map
, skops
->sk
, NULL
, 0);
247 opt
= &active_fin_out
;
249 opt
= &passive_fin_out
;
251 optlen
= option_total_len(opt
->flags
);
253 err
= bpf_reserve_hdr_opt(skops
, optlen
, 0);
261 static int write_fin_opt(struct bpf_sock_ops
*skops
)
263 struct bpf_test_option
*opt
;
264 struct hdr_stg
*hdr_stg
;
269 hdr_stg
= bpf_sk_storage_get(&hdr_stg_map
, skops
->sk
, NULL
, 0);
274 opt
= &active_fin_out
;
276 opt
= &passive_fin_out
;
281 return store_option(skops
, opt
);
284 static int resend_in_ack(struct bpf_sock_ops
*skops
)
286 struct hdr_stg
*hdr_stg
;
291 hdr_stg
= bpf_sk_storage_get(&hdr_stg_map
, skops
->sk
, NULL
, 0);
295 return !!hdr_stg
->resend_syn
;
298 static int nodata_opt_len(struct bpf_sock_ops
*skops
)
302 resend
= resend_in_ack(skops
);
307 return syn_opt_len(skops
);
312 static int write_nodata_opt(struct bpf_sock_ops
*skops
)
316 resend
= resend_in_ack(skops
);
321 return write_syn_opt(skops
);
326 static int data_opt_len(struct bpf_sock_ops
*skops
)
328 /* Same as the nodata version. Mostly to show
329 * an example usage on skops->skb_len.
331 return nodata_opt_len(skops
);
334 static int write_data_opt(struct bpf_sock_ops
*skops
)
336 return write_nodata_opt(skops
);
339 static int current_mss_opt_len(struct bpf_sock_ops
*skops
)
341 /* Reserve maximum that may be needed */
344 err
= bpf_reserve_hdr_opt(skops
, option_total_len(OPTION_MASK
), 0);
351 static int handle_hdr_opt_len(struct bpf_sock_ops
*skops
)
353 __u8 tcp_flags
= skops_tcp_flags(skops
);
355 if ((tcp_flags
& TCPHDR_SYNACK
) == TCPHDR_SYNACK
)
356 return synack_opt_len(skops
);
358 if (tcp_flags
& TCPHDR_SYN
)
359 return syn_opt_len(skops
);
361 if (tcp_flags
& TCPHDR_FIN
)
362 return fin_opt_len(skops
);
364 if (skops_current_mss(skops
))
365 /* The kernel is calculating the MSS */
366 return current_mss_opt_len(skops
);
369 return data_opt_len(skops
);
371 return nodata_opt_len(skops
);
374 static int handle_write_hdr_opt(struct bpf_sock_ops
*skops
)
376 __u8 tcp_flags
= skops_tcp_flags(skops
);
379 if ((tcp_flags
& TCPHDR_SYNACK
) == TCPHDR_SYNACK
)
380 return write_synack_opt(skops
);
382 if (tcp_flags
& TCPHDR_SYN
)
383 return write_syn_opt(skops
);
385 if (tcp_flags
& TCPHDR_FIN
)
386 return write_fin_opt(skops
);
388 th
= skops
->skb_data
;
389 if (th
+ 1 > skops
->skb_data_end
)
392 if (skops
->skb_len
> tcp_hdrlen(th
))
393 return write_data_opt(skops
);
395 return write_nodata_opt(skops
);
398 static int set_delack_max(struct bpf_sock_ops
*skops
, __u8 max_delack_ms
)
400 __u32 max_delack_us
= max_delack_ms
* 1000;
402 return bpf_setsockopt(skops
, SOL_TCP
, TCP_BPF_DELACK_MAX
,
403 &max_delack_us
, sizeof(max_delack_us
));
406 static int set_rto_min(struct bpf_sock_ops
*skops
, __u8 peer_max_delack_ms
)
408 __u32 min_rto_us
= peer_max_delack_ms
* 1000;
410 return bpf_setsockopt(skops
, SOL_TCP
, TCP_BPF_RTO_MIN
, &min_rto_us
,
414 static int handle_active_estab(struct bpf_sock_ops
*skops
)
416 struct hdr_stg init_stg
= {
421 err
= load_option(skops
, &active_estab_in
, false);
422 if (err
&& err
!= -ENOMSG
)
425 init_stg
.resend_syn
= TEST_OPTION_FLAGS(active_estab_in
.flags
,
427 if (!skops
->sk
|| !bpf_sk_storage_get(&hdr_stg_map
, skops
->sk
,
429 BPF_SK_STORAGE_GET_F_CREATE
))
432 if (init_stg
.resend_syn
)
433 /* Don't clear the write_hdr cb now because
434 * the ACK may get lost and retransmit may
437 * PARSE_ALL_HDR cb flag is set to learn if this
438 * resend_syn option has received by the peer.
440 * The header option will be resent until a valid
441 * packet is received at handle_parse_hdr()
442 * and all hdr cb flags will be cleared in
443 * handle_parse_hdr().
445 set_parse_all_hdr_cb_flags(skops
);
446 else if (!active_fin_out
.flags
)
447 /* No options will be written from now */
448 clear_hdr_cb_flags(skops
);
450 if (active_syn_out
.max_delack_ms
) {
451 err
= set_delack_max(skops
, active_syn_out
.max_delack_ms
);
456 if (active_estab_in
.max_delack_ms
) {
457 err
= set_rto_min(skops
, active_estab_in
.max_delack_ms
);
465 static int handle_passive_estab(struct bpf_sock_ops
*skops
)
467 struct hdr_stg init_stg
= {};
471 inherit_cb_flags
= skops
->bpf_sock_ops_cb_flags
;
473 err
= load_option(skops
, &passive_estab_in
, true);
474 if (err
== -ENOENT
) {
475 /* saved_syn is not found. It was in syncookie mode.
476 * We have asked the active side to resend the options
477 * in ACK, so try to find the bpf_test_option from ACK now.
479 err
= load_option(skops
, &passive_estab_in
, false);
480 init_stg
.syncookie
= true;
483 /* ENOMSG: The bpf_test_option is not found which is fine.
484 * Bail out now for all other errors.
486 if (err
&& err
!= -ENOMSG
)
489 th
= skops
->skb_data
;
490 if (th
+ 1 > skops
->skb_data_end
)
496 /* Cannot clear cb_flags to stop write_hdr cb.
497 * synack is not sent yet for fast open.
498 * Even it was, the synack may need to be retransmitted.
500 * PARSE_ALL_HDR cb flag is set to learn
501 * if synack has reached the peer.
502 * All cb_flags will be cleared in handle_parse_hdr().
504 set_parse_all_hdr_cb_flags(skops
);
505 init_stg
.fastopen
= true;
506 } else if (!passive_fin_out
.flags
) {
507 /* No options will be written from now */
508 clear_hdr_cb_flags(skops
);
512 !bpf_sk_storage_get(&hdr_stg_map
, skops
->sk
, &init_stg
,
513 BPF_SK_STORAGE_GET_F_CREATE
))
516 if (passive_synack_out
.max_delack_ms
) {
517 err
= set_delack_max(skops
, passive_synack_out
.max_delack_ms
);
522 if (passive_estab_in
.max_delack_ms
) {
523 err
= set_rto_min(skops
, passive_estab_in
.max_delack_ms
);
531 static int handle_parse_hdr(struct bpf_sock_ops
*skops
)
533 struct hdr_stg
*hdr_stg
;
539 th
= skops
->skb_data
;
540 if (th
+ 1 > skops
->skb_data_end
)
543 hdr_stg
= bpf_sk_storage_get(&hdr_stg_map
, skops
->sk
, NULL
, 0);
547 if (hdr_stg
->resend_syn
|| hdr_stg
->fastopen
)
548 /* The PARSE_ALL_HDR cb flag was turned on
549 * to ensure that the previously written
550 * options have reached the peer.
551 * Those previously written option includes:
552 * - Active side: resend_syn in ACK during syncookie
554 * - Passive side: SYNACK during fastopen
556 * A valid packet has been received here after
557 * the 3WHS, so the PARSE_ALL_HDR cb flag
558 * can be cleared now.
560 clear_parse_all_hdr_cb_flags(skops
);
562 if (hdr_stg
->resend_syn
&& !active_fin_out
.flags
)
563 /* Active side resent the syn option in ACK
564 * because the server was in syncookie mode.
565 * A valid packet has been received, so
566 * clear header cb flags if there is no
567 * more option to send.
569 clear_hdr_cb_flags(skops
);
571 if (hdr_stg
->fastopen
&& !passive_fin_out
.flags
)
572 /* Passive side was in fastopen.
573 * A valid packet has been received, so
574 * the SYNACK has reached the peer.
575 * Clear header cb flags if there is no more
578 clear_hdr_cb_flags(skops
);
581 struct bpf_test_option
*fin_opt
;
585 fin_opt
= &active_fin_in
;
587 fin_opt
= &passive_fin_in
;
589 err
= load_option(skops
, fin_opt
, false);
590 if (err
&& err
!= -ENOMSG
)
598 int estab(struct bpf_sock_ops
*skops
)
603 case BPF_SOCK_OPS_TCP_LISTEN_CB
:
604 bpf_setsockopt(skops
, SOL_TCP
, TCP_SAVE_SYN
,
605 &true_val
, sizeof(true_val
));
606 set_hdr_cb_flags(skops
, BPF_SOCK_OPS_STATE_CB_FLAG
);
608 case BPF_SOCK_OPS_TCP_CONNECT_CB
:
609 set_hdr_cb_flags(skops
, 0);
611 case BPF_SOCK_OPS_PARSE_HDR_OPT_CB
:
612 return handle_parse_hdr(skops
);
613 case BPF_SOCK_OPS_HDR_OPT_LEN_CB
:
614 return handle_hdr_opt_len(skops
);
615 case BPF_SOCK_OPS_WRITE_HDR_OPT_CB
:
616 return handle_write_hdr_opt(skops
);
617 case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB
:
618 return handle_passive_estab(skops
);
619 case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB
:
620 return handle_active_estab(skops
);
626 char _license
[] SEC("license") = "GPL";