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 tools/include/uapi/linux (1 of 7 files). Show all
Unified · Split
| @@ -994,6 +994,8 @@ enum bpf_attach_type { · 993 unmodified lines | |||
| 994 | BPF_SK_LOOKUP, | 994 | BPF_SK_LOOKUP, |
| 995 | BPF_XDP, | 995 | BPF_XDP, |
| 996 | BPF_SK_SKB_VERDICT, | 996 | BPF_SK_SKB_VERDICT, |
| 997 | BPF_SK_REUSEPORT_SELECT, | ||
| 998 | BPF_SK_REUSEPORT_SELECT_OR_MIGRATE, | ||
| 997 | __MAX_BPF_ATTACH_TYPE | 999 | __MAX_BPF_ATTACH_TYPE |
| 998 | }; | 1000 | }; |
| 999 | 1001 | ||
| @@ -5416,7 +5418,20 @@ struct sk_reuseport_md { · 4416 unmodified lines | |||
| 5416 | __u32 ip_protocol; /* IP protocol. e.g. IPPROTO_TCP, IPPROTO_UDP */ | 5418 | __u32 ip_protocol; /* IP protocol. e.g. IPPROTO_TCP, IPPROTO_UDP */ |
| 5417 | __u32 bind_inany; /* Is sock bound to an INANY address? */ | 5419 | __u32 bind_inany; /* Is sock bound to an INANY address? */ |
| 5418 | __u32 hash; /* A hash of the packet 4 tuples */ | 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 | __bpf_md_ptr(struct bpf_sock *, sk); | 5433 | __bpf_md_ptr(struct bpf_sock *, sk); |
| 5434 | __bpf_md_ptr(struct bpf_sock *, migrating_sk); | ||
| 5420 | }; | 5435 | }; |
| 5421 | 5436 | ||
| 5422 | #define BPF_TAG_SIZE 8 | 5437 | #define BPF_TAG_SIZE 8 |