This patch introduces a new bpf_attach_type for BPF_PROG_TYPE_SK_REUSEPORT to check if the attached eBPF program is capable of migrating sockets. When the eBPF program is attached, we run it for socket migration if the expected_attach_type is BPF_SK_REUSEPORT_SELECT_OR_MIGRATE or net.ipv4.tcp_migrate_req is enabled. Currently, the expected_attach_type is not enforced for the BPF_PROG_TYPE_SK_REUSEPORT type of program. Thus, this commit follows the earlier idea in the commit aac3fc320d94 ("bpf: Post-hooks for sys_bind") to fix up the zero expected_attach_type in bpf_prog_load_fixup_attach_type(). Moreover, this patch adds a new field (migrating_sk) to sk_reuseport_md to select a new listener based on the child socket. migrating_sk varies depending on if it is migrating a request in the accept queue or during 3WHS. - accept_queue : sock (ESTABLISHED/SYN_RECV) - 3WHS : request_sock (NEW_SYN_RECV) In the eBPF program, we can select a new listener by BPF_FUNC_sk_select_reuseport(). Also, we can cancel migration by returning SK_DROP. This feature is useful when listeners have different settings at the socket API level or when we want to free resources as soon as possible. - SK_PASS with selected_sk, select it as a new listener - SK_PASS with selected_sk NULL, fallbacks to the random selection - SK_DROP, cancel the migration. There is a noteworthy point. We select a listening socket in three places, but we do not have struct skb at closing a listener or retransmitting a SYN+ACK. On the other hand, some helper functions do not expect skb is NULL (e.g. skb_header_pointer() in BPF_FUNC_skb_load_bytes(), skb_tail_pointer() in BPF_FUNC_skb_load_bytes_relative()). So we allocate an empty skb temporarily before running the eBPF program.
Showing the changes to include/uapi (1 of 7 files). Show all
Unified · Split
| @@ -994,6 +994,8 @@ enum bpf_attach_type { · 993 unmodified lines | ||
| 994 | 994 | BPF_SK_LOOKUP, |
| 995 | 995 | BPF_XDP, |
| 996 | 996 | BPF_SK_SKB_VERDICT, |
| 997 | + BPF_SK_REUSEPORT_SELECT, | |
| 998 | + BPF_SK_REUSEPORT_SELECT_OR_MIGRATE, | |
| 997 | 999 | __MAX_BPF_ATTACH_TYPE |
| 998 | 1000 | }; |
| 999 | 1001 | |
| @@ -5416,7 +5418,20 @@ struct sk_reuseport_md { · 4416 unmodified lines | ||
| 5416 | 5418 | __u32 ip_protocol; /* IP protocol. e.g. IPPROTO_TCP, IPPROTO_UDP */ |
| 5417 | 5419 | __u32 bind_inany; /* Is sock bound to an INANY address? */ |
| 5418 | 5420 | __u32 hash; /* A hash of the packet 4 tuples */ |
| 5421 | + /* When reuse->migrating_sk is NULL, it is selecting a sk for the | |
| 5422 | + * new incoming connection request (e.g. selecting a listen sk for | |
| 5423 | + * the received SYN in the TCP case). reuse->sk is one of the sk | |
| 5424 | + * in the reuseport group. The bpf prog can use reuse->sk to learn | |
| 5425 | + * the local listening ip/port without looking into the skb. | |
| 5426 | + * | |
| 5427 | + * When reuse->migrating_sk is not NULL, reuse->sk is closed and | |
| 5428 | + * reuse->migrating_sk is the socket that needs to be migrated | |
| 5429 | + * to another listening socket. migrating_sk could be a fullsock | |
| 5430 | + * sk that is fully established or a reqsk that is in-the-middle | |
| 5431 | + * of 3-way handshake. | |
| 5432 | + */ | |
| 5419 | 5433 | __bpf_md_ptr(struct bpf_sock *, sk); |
| 5434 | + __bpf_md_ptr(struct bpf_sock *, migrating_sk); | |
| 5420 | 5435 | }; |
| 5421 | 5436 | |
| 5422 | 5437 | #define BPF_TAG_SIZE 8 |