BPF sk_lookup 程序¶
BPF sk_lookup 程序类型 (BPF_PROG_TYPE_SK_LOOKUP
) 将可编程性引入到传输层执行的套接字查找中,当数据包需要在本地交付时。
当调用 BPF sk_lookup 程序时,可以通过调用 bpf_sk_assign()
BPF 辅助函数来选择将接收传入数据包的套接字。
TCP 和 UDP 都存在用于常见连接点 (BPF_SK_LOOKUP
) 的钩子。
动机¶
引入 BPF sk_lookup 程序类型是为了解决在某些设置场景中,使用 bind()
套接字调用将套接字绑定到地址是不切实际的,例如
在一定 IP 地址范围内接收连接,例如 192.0.2.0/24,当由于端口冲突而无法绑定到通配符地址
INADRR_ANY
时,接收所有或很大范围的端口上的连接,即 L7 代理用例。
这样的设置将需要创建并将一个套接字 bind()
到范围内的每个 IP 地址/端口,导致资源消耗和套接字查找期间潜在的延迟峰值。
附件¶
可以使用 bpf(BPF_LINK_CREATE, ...)
系统调用,使用 BPF_SK_LOOKUP
附加类型和 netns FD 作为附件 target_fd
,将 BPF sk_lookup 程序附加到网络命名空间。
可以将多个程序附加到一个网络命名空间。 程序将按照附加的顺序调用。
钩子¶
每当传输层需要为传入数据包找到一个侦听(TCP)或未连接(UDP)套接字时,都会运行附加的 BPF sk_lookup 程序。
到已建立(TCP)和已连接(UDP)套接字的传入流量将像往常一样传送,而不会触发 BPF sk_lookup 钩子。
附加的 BPF 程序必须以 SK_PASS
或 SK_DROP
判决代码返回。 对于其他作为网络过滤器的 BPF 程序类型,SK_PASS
表示套接字查找应继续到常规的基于哈希表的查找,而 SK_DROP
导致传输层丢弃数据包。
BPF sk_lookup 程序还可以通过调用 bpf_sk_assign()
BPF 辅助函数来选择一个套接字来接收数据包。 通常,该程序在保存套接字的映射中查找套接字,例如 SOCKMAP
或 SOCKHASH
,并将 struct bpf_sock *
传递给 bpf_sk_assign()
辅助函数以记录选择。 仅当程序以 SK_PASS
代码终止时,选择套接字才会生效。
当附加多个程序时,最终结果由所有程序的返回代码根据以下规则确定
如果任何程序返回
SK_PASS
并选择了一个有效的套接字,则该套接字将用作套接字查找的结果。如果多个程序返回
SK_PASS
并选择了一个套接字,则最后一个选择生效。如果任何程序返回
SK_DROP
,并且没有程序返回SK_PASS
并选择了一个套接字,则套接字查找失败。如果所有程序都返回
SK_PASS
并且没有程序选择套接字,则套接字查找继续。
API¶
在其上下文中,struct bpf_sk_lookup
的实例,BPF sk_lookup 程序接收有关触发套接字查找的数据包的信息。 即
IP 版本 (
AF_INET
或AF_INET6
),L4 协议标识符 (
IPPROTO_TCP
或IPPROTO_UDP
),源和目标 IP 地址,
源和目标 L4 端口,
已使用
bpf_sk_assign()
选择的套接字。
有关详细信息,请参阅 linux/bpf.h
用户 API 标头中的 struct bpf_sk_lookup
声明,以及 bpf-helpers(7) 手册页中的 bpf_sk_assign()
部分。
示例¶
有关参考实现,请参阅 tools/testing/selftests/bpf/prog_tests/sk_lookup.c
。