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
994994 BPF_SK_LOOKUP,
995995 BPF_XDP,
996996 BPF_SK_SKB_VERDICT,
997+ BPF_SK_REUSEPORT_SELECT,
998+ BPF_SK_REUSEPORT_SELECT_OR_MIGRATE,
997999 __MAX_BPF_ATTACH_TYPE
9981000 };
9991001
@@ -5416,7 +5418,20 @@ struct sk_reuseport_md { · 4416 unmodified lines
54165418 __u32 ip_protocol; /* IP protocol. e.g. IPPROTO_TCP, IPPROTO_UDP */
54175419 __u32 bind_inany; /* Is sock bound to an INANY address? */
54185420 __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+ */
54195433 __bpf_md_ptr(struct bpf_sock *, sk);
5434+ __bpf_md_ptr(struct bpf_sock *, migrating_sk);
54205435 };
54215436
54225437 #define BPF_TAG_SIZE 8