History

bpf: Support socket migration by eBPF.

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.

Kuniyuki Iwashima committed 5 years ago

Commit d5e4dda1 parent e0610477 files · +88 −5Browse files

Showing the changes to include/uapi (1 of 7 files). Show all

Unified · Split

include/uapi/linux/bpf.h+15−0
@@ -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_TYPE999 __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 85437#define BPF_TAG_SIZE 8