我正在研究不同类型的BPF
程序,并注意到对于不同的程序类型,上下文的传递方式不同。
Example:
对于节目类型BPF_PROG_TYPE_SOCK_OPS
,类型的对象struct bpf_sock_ops_kern https://elixir.bootlin.com/linux/latest/source/include/net/tcp.h#L2009已通过。然而,这种类型的 BPF 程序引用了struct bpf_sock_ops https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/bpf.h#L931。为什么这样做,“翻译”出自哪里bpf_sock_ops_kern
to bpf_sock_ops
?
对于节目类型BPF_PROG_TYPE_CGROUP_SKB
,类型的对象struct sk_buff https://elixir.bootlin.com/linux/latest/source/include/linux/skbuff.h#L658已通过(例如,在__cgroup_bpf_run_filter_skb https://elixir.bootlin.com/linux/latest/source/kernel/bpf/cgroup.c#L446),但 BPF 程序需要最小化版本,struct __sk_buff https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/bpf.h#L799.
所以我看了看the struct bpf_verifier_ops函数回调 https://elixir.bootlin.com/linux/latest/source/net/core/filter.c#L4195,但它们似乎只调整 BPF 指令中的偏移量,因为它们是由 BPF 验证器调用的。
如果有人能够阐明 BPF 上下文是如何定义的,我会很高兴。谢谢。
镜像对象(例如,struct bpf_sock_ops https://elixir.bootlin.com/linux/v4.15.7/source/include/uapi/linux/bpf.h#L931)作为参数传递,将原始对象字段的子集公开给 BPF 程序。镜像结构还可以具有来自多个不同原始结构的场;在这种情况下,镜像对象充当聚合。将原始对象传递给 BPF 程序也会产生误导,因为用户可能认为他们可以访问所有字段。例如,他们可能认为自己有权访问bpf_sock_ops_kern.sk https://elixir.bootlin.com/linux/v4.15.7/source/include/linux/filter.h#L982但事实并非如此。
然后,在程序第一次执行之前,验证器将对镜像对象的访问转换为对原始对象的访问。每种类型的镜像对象都有一个转换函数(例如,sock_ops_convert_ctx_access https://elixir.bootlin.com/linux/v4.15.7/source/net/core/filter.c#L4313用于将访问转换为struct bpf_sock_ops https://elixir.bootlin.com/linux/v4.15.7/source/include/uapi/linux/bpf.h#L931)。然后,对于镜像对象的每个字段(即,对于每个偏移量),转换函数使用原始字段的偏移量重写加载或存储指令。
请注意,所有原始字段可能不在同一个对象中。例如,在镜像对象中struct bpf_sock_ops https://elixir.bootlin.com/linux/v4.15.7/source/include/uapi/linux/bpf.h#L931, 田野op
and family
被检索到bpf_sock_ops_kern.op https://elixir.bootlin.com/linux/v4.15.7/source/net/core/filter.c#L4333 and bpf_sock_ops_kern.sk->skc_family https://elixir.bootlin.com/linux/v4.15.7/source/net/core/filter.c#L4345分别。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)