ebpf开发问题汇总

不同Programs之间通信

用bpf_obj_get来获取MAP的描述符,然后用bpf_map_reuse_fd函数来在不同program之间复用

kernel 与 user space之间

需要pin the BPF MAP to the BPF Virtual File System (VFS),来持久化存储,否则如果map用不到会被destory

引用:B. Yang, D. Shen, J. Zhang, F. Dong, J. Luo and J. C. S. Lui, “Towards the Full Extensibility of Multipath TCP with eMPTCP,” 2022 IEEE 30th International Conference on Network Protocols (ICNP), Lexington, KY, USA, 2022, pp. 1-11, doi: 10.1109/ICNP55882.2022.9940354.第7页

BPF_CORE_READ和BPF_CORE_READ_INFO的作用?在哪里定义的?

BPF_CORE_READBPF_CORE_READ_INFO 是用于 BPF(Berkeley Packet Filter)程序的特定操作码(opcode),用于从内核中访问核心数据结构的信息。

  • BPF_CORE_READ:它允许 BPF 程序读取核心数据结构的内容。通过将目标内存区域的指针和大小传递给这个操作码,BPF 程序可以读取内核数据结构的特定字段值。

  • BPF_CORE_READ_INFO:它在 BPF_CORE_READ 的基础上提供了更详细的信息。除了允许读取指定字段的值外,它还提供有关该字段的元数据,如字段名称、偏移量、大小等。

这两个操作码通常与 bpf_probe_read() 函数结合使用,该函数提供了从内核空间读取字节的能力。

这些操作码是作为 BPF 架构的一部分在内核中定义的。它们通常在 include/uapi/linux/bpf.h 或类似的头文件中可以找到。

BPF_PROG是什么意思,在哪里定义的?

BPF_PROG 是 Linux 内核中表示 BPF(Berkeley Packet Filter)程序的结构体类型。它在内核中定义了 BPF 程序的相关属性和信息。

BPF_PROG 结构体的定义通常在 include/uapi/linux/bpf.h 或类似的头文件中可以找到。下面是一个简化的 BPF_PROG 结构体的示例定义:

struct bpf_prog {
    __u32    id;           /* Program ID */
    __u32    len;          /* Program length */
    __u32    type;         /* Program type */
    /* ... 其他字段和属性 ... */
};

BPF_PROG 结构体包含了表示 BPF 程序的信息,例如程序的 ID、长度、类型等。它还可以包含其他与 BPF 程序相关的字段和属性,具体取决于内核的版本和配置。

通过使用 BPF_PROG 结构体,内核可以管理和操作 BPF 程序,并将其加载到合适的位置,以便在特定的协议层或事件处理中应用 BPF 程序的逻辑。

long bpf_skb_adjust_room(struct sk_buff *skb, s32 len_diff, u32 mode, u64 flags)

当你调用 bpf_skb_adjust_room 函数时,它会根据指定的参数来增加或减少数据包中的数据空间。具体的操作取决于 len_diffmode 参数。

  1. len_diff 参数是一个有符号整数,表示要增加或减少的数据空间的大小。如果 len_diff 是正数,数据空间将增加;如果 len_diff 是负数,数据空间将减少。

  2. mode 参数是一个无符号整数,用于指定调整的模式。目前有两种支持的模式:

    • BPF_ADJ_ROOM_MAC:在 MAC 层进行数据空间的调整,即在第二层和第三层头之间增加或减少空间。
    • BPF_ADJ_ROOM_NET:在网络层进行数据空间的调整,即在第三层和第四层头之间增加或减少空间。
  3. flags 参数是一个64位无符号整数,用于指定额外的标志和选项。这些标志和选项可以控制调整的行为:

    • BPF_F_ADJ_ROOM_NO_CSUM_RESET:不重置数据包的校验和,即保留原始的校验和设置。
    • BPF_F_ADJ_ROOM_FIXED_GSO:不调整 GSO(Generic Segmentation Offload)大小。对于数据报,不允许调整 MSS(Maximum Segment Size)。
    • BPF_F_ADJ_ROOM_ENCAP_L3_IPV4BPF_F_ADJ_ROOM_ENCAP_L3_IPV6:为隧道头部预留空间,并相应地配置 skb 的偏移量和其他字段。
    • BPF_F_ADJ_ROOM_ENCAP_L4_GREBPF_F_ADJ_ROOM_ENCAP_L4_UDP:与 BPF_F_ADJ_ROOM_ENCAP_L3 标志一起使用,用于进一步指定隧道类型。
    • BPF_F_ADJ_ROOM_ENCAP_L2(len):与 BPF_F_ADJ_ROOM_ENCAP_L3 / BPF_F_ADJ_ROOM_ENCAP_L4 标志一起使用,用于进一步指定隧道类型;len 是内部 MAC 头部的长度。
    • BPF_F_ADJ_ROOM_ENCAP_L2_ETH:与 BPF_F_ADJ_ROOM_ENCAP_L2 标志一起使用,进一步指定 L2 类型为以太网。

请注意,由于调用 bpf_skb_adjust_room 函数可能会改变底层的数据包缓冲区,因此在加载时,之前由验证器执行的指针检查将无效。如果你在程序中使用直接数据包访问,你需要重新执行这些检查来确保指针的有效性。

函数的返回值为整数,如果调整操作成功,则返回 0。如果出现错误,则返回一个负数错误码,表示调整操作失败。

long bpf_fib_lookup(void *ctx, struct bpf_fib_lookup *params, int plen, u32 flags)

bpf_fib_lookup 函数用于在内核表中进行 FIB(Forwarding Information Base)查找,使用传入的参数 params 进行查找。如果查找成功并且结果显示要转发数据包,则会在邻居表中查找下一跳。如果成功(即 FIB 查找显示转发并解析了下一跳),则会将下一跳地址返回到 ipv4_dstipv6_dst 字段中,smac 设置为出口设备的 MAC 地址,dmac 设置为下一跳的 MAC 地址,rt_metric 设置为来自路由的度量值(仅适用于 IPv4/IPv6),并将 ifindex 设置为 FIB 查找得到的下一跳对应的设备索引。

plen 参数是传入的结构体的大小。

flags 参数可以是以下值的组合:

  • BPF_FIB_LOOKUP_DIRECT:执行直接的表查找,而不是使用 FIB 规则进行完整查找。
  • BPF_FIB_LOOKUP_OUTPUT:从出口的角度进行查找(默认是从入口方向)。

ctx 参数可以是 struct xdp_md(用于 XDP 程序)或 struct sk_buff(用于 tc cls_act 程序)。

函数的返回值可能为:

  • 小于 0:表示任何输入参数无效。
  • 0:查找成功(数据包被转发,下一跳邻居存在)。
  • 大于 0:其中一个 BPF_FIB_LKUP_RET_ 开头的代码,解释为什么数据包未被转发或需要完整协议栈的辅助。

如果查找失败并且返回值为 BPF_FIB_LKUP_RET_FRAG_NEEDED,则 MTU(最大传输单元)超过了,并且输出参数的 mtu_result 字段包含 MTU 值。

long bpf_redirect_neigh(u32 ifindex, struct bpf_redir_neigh *params, int plen, u64 flags)

描述:
将数据包重定向到索引为ifindex的另一个网络设备,并从邻居子系统中填充L2地址。该辅助函数与bpf_redirect()类似,但它还会填充L2地址,也就是说,内部实现中,这个辅助函数依赖于邻居查找来获取下一跳的L2地址。

如果调用者在params参数中没有提供地址,辅助函数将基于skb的网络头进行FIB查找,以获取下一跳地址。参数plen表示params的长度,如果params为NULL,应将plen设置为0。

flags参数是保留字段,必须为0。该辅助函数目前仅支持tc BPF程序类型,并对IPv4和IPv6协议启用。

返回:辅助函数在成功时返回TC_ACT_REDIRECT,错误时返回TC_ACT_SHOT。

s64 bpf_csum_diff(__be32 *from, u32 from_size, __be32 *to, u32 to_size, __wsum seed)

描述:
计算从指向由from指针指向的原始缓冲区开始,长度为from_size(必须是4的倍数),到指向由to指针指向的原始缓冲区的大小为to_size(同样的要求)的校验和差异。可选的seed可以添加到此值中(可以级联使用,seed可以来自对此辅助函数的先前调用)。

这个辅助函数的灵活性使其可以有多种用途:

  • 当from_size == 0,to_size > 0,并且seed设置为校验和时,它可用于推送新数据。
  • 当from_size > 0,to_size == 0,并且seed设置为校验和时,它可用于从数据包中删除数据。
  • 当from_size > 0,to_size > 0,并且seed设置为0时,它可用于计算差异。请注意,from_size和to_size不需要相等。

此辅助函数可以与bpf_l3_csum_replace()和bpf_l4_csum_replace()组合使用,可以使用bpf_csum_diff()计算的差异来提供给它们。

返回:校验和结果,或者在失败的情况下返回负数错误代码。

sk_buff的结构就是head,data,tail,end

SEC("socket")
int socket_handler(struct __sk_buff *skb)
{
        struct so_event *e;
        __u8 verlen;
        __u16 proto;
        __u32 nhoff = ETH_HLEN;

        bpf_skb_load_bytes(skb, 12, &proto, 2);
        proto = __bpf_ntohs(proto);
        if (proto != ETH_P_IP)
                return 0;

bpf_skb_load_bytes(skb, 12, &prote, 2); prote就指向的是IP层的协议字段了
链路层包头是的12个字节偏移取2字节在以太网里表示的是包类型

bpf_get_current_pid_tgid()

bpf_get_current_pid_tgid() 是一种用于在 BPF 程序中获取当前进程的函数。它返回一个 pid_t 类型的值,该值包含当前进程的 PID(进程 ID)和 TGID(任务组 ID)。

在 Linux 中,每个进程都有一个唯一的 PID,用于标识该进程。而 TGID 是一个与 PID 相关联的概念,表示进程所属的任务组(Thread Group)。在单线程的情况下,PID 和 TGID 是相等的,但在多线程的情况下,一个任务组可以包含多个线程,每个线程拥有不同的 PID,但共享相同的 TGID。

bpf_get_current_pid_tgid() 函数允许 BPF 程序在执行过程中获取当前进程的 PID 和 TGID,以便根据需要进行进一步的处理或决策。例如,可以根据 PID 或 TGID 进行访问权限控制、进程过滤或统计等操作。

需要注意的是,bpf_get_current_pid_tgid() 函数只能在内核中的 BPF 程序中使用,而不能在用户态应用程序中调用。

SEC(“fentry/tcp_v6_connect”)

int BPF_PROG(fentry_tcp_v6_connect, struct sock *sk)
{
return trace_connect(sk);
}

SEC(“fentry/tcp_rcv_state_process”)
int BPF_PROG(fentry_tcp_rcv_state_process, struct sock *sk)
{
return handle_tcp_rcv_state_process(ctx, sk);
}中的fentry_tcp_rcv_state_process是什么意思

fentry_tcp_v6_connect 是一个函数入口点,用于 BPF (Berkeley Packet Filter) 程序在 Linux 内核中的网络栈中拦截和监视 IPv6 TCP 连接操作,这个名称表示该 BPF 程序是在 TCP 接收状态处理阶段插入的。

该函数入口点的定义通过 BPF 宏 BPF_PROG(fentry_tcp_v6_connect, struct sock *sk) 进行了定义,它指示了一个 BPF 程序入口函数名为 fentry_tcp_v6_connect,接受一个指向 struct sock 类型的指针 sk 作为参数。

在 fentry_tcp_v6_connect 函数中,我们可以进行一些自定义的操作,例如记录连接的信息、监视连接请求的参数等。该函数在 TCP IPv6 连接建立的阶段被调用,允许我们在连接建立之前或之后执行特定的操作。

bpf_current_task_under_cgroup

long bpf_current_task_under_cgroup(struct bpf_map *map, u32 index)
请检查是否在给定的cgroup2层次结构的子集上运行了探针。要测试的cgroup2由类型为BPF_MAP_TYPE_CGROUP_ARRAY的映射在索引位置上保存。

struct sk_buff ,struct sock ,struct bpf_sock_ops,struct bpf_sock_addr的区别

struct sk_buffstruct sockstruct bpf_sock_opsstruct bpf_sock_addr是Linux内核中用于网络编程的不同数据结构。

  • struct sk_buff是Linux内核中用于表示网络数据包的缓冲区的数据结构。它包含了数据包的元数据(如协议头、接口信息等)以及数据包的实际内容。struct sk_buff在Linux内核网络协议栈中扮演着重要的角色,用于在网络协议层之间传递数据包。

  • struct sock代表Linux内核中的网络套接字(socket)。套接字是网络通信的接口,它提供了应用程序和网络协议栈之间的通信机制。struct sock存储了套接字相关的状态信息、配置参数和与网络层交互的功能。

  • struct bpf_sock_ops是eBPF程序执行期间与套接字相关的操作的上下文数据结构。它提供了执行eBPF程序时访问套接字信息的接口,比如套接字的协议号、源/目的IP地址、端口号等。eBPF程序可以使用struct bpf_sock_ops中的字段来获取和设置套接字相关的属性。

  • struct bpf_sock_addr包含关于套接字的地址信息,用于在eBPF程序中访问和操作套接字地址。它提供了套接字地址的各个部分的访问接口,比如IP地址、端口号等。struct bpf_sock_addr通常与struct bpf_sock_ops一起使用,以便在eBPF程序中处理套接字的地址信息。

综上所述,这些数据结构在Linux内核网络编程中扮演不同的角色,用于处理网络数据包、管理套接字状态和提供与套接字相关的操作和地址访问。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值