ebpf 程序中常用的 load_byte/load_half/load_word 功能介绍

前言

大家在阅读一些网络相关的 ebpf 程序源码时可能会发现部分程序会使用 load_byte, load_half 以及 load_word 这几个函数来辅助解析网络数据包。

那么这几个函数的功能究竟是啥?以及它们各自的使用场景是啥,怎么知道究竟该用哪个函数? 本文将记录这几个函数各种的功能以及使用场景。

load_byte

函数定义

load_byte 函数的定义如下:

unsigned long long load_byte(void *skb,
                          unsigned long long off) asm("llvm.bpf.load.byte");

函数功能

它的功能是:从 skb 指向的数据包指针中读取 8-bits 的数据。 跟 gcc 里的 __builtin_bpf_load_byte 函数的功能是一样的。

使用场景

当想要从 struct __sk_buff *skb 中读取数据类型大小为 8-bits(1个字节) 的字段的值的时候, 可以使用 load_byte 直接从指针中读取对应的数据。

例子:

__u8 protocol = load_byte(skb, ETH_HLEN + offsetof(struct iphdr, protocol));

load_half

函数定义

load_half 函数的定义如下:

unsigned long long load_half(void *skb,
                         unsigned long long off) asm("llvm.bpf.load.half");

函数功能

它的功能是:从 skb 指向的数据包指针中读取 16-bits 的数据。 跟 gcc 里的 __builtin_bpf_load_half 函数的功能是一样的。

使用场景

当想要从 struct __sk_buff *skb 中读取数据类型大小为 16-bits(2个字节)的字段的值的时候, 可以使用 load_byte 直接从指针中读取对应的数据。

例子:

__u16 h_proto = load_half(skb, offsetof(struct ethhdr, h_proto));

load_word

函数定义

load_word 函数的定义如下:

unsigned long long load_word(void *skb,
                         unsigned long long off) asm("llvm.bpf.load.word");

函数功能

它的功能是:从 skb 指向的数据包指针中读取 32-bits 的数据。 跟 gcc 里的 __builtin_bpf_load_word 函数的功能是一样的。

使用场景

当想要从 struct __sk_buff *skb 中读取数据类型大小为 32-bits(4个字节)的字段的值的时候, 可以使用 load_byte 直接从指针中读取对应的数据。

例子:

__u32 saddr = load_word(skb, ETH_HLEN + offsetof(struct iphdr, saddr));

替代函数

如果不想依赖 llvm 实现这几个函数所提供的功能的话,可以使用 bpf-helpers 中提供的 bpf_skb_load_bytes 函数实现类似的功能。

比如前面的那几个例子可以改写为:

// __u8 protocol = load_byte(skb, ETH_HLEN + offsetof(struct iphdr, protocol));
struct iphdr ip_hdr;
if (bpf_skb_load_bytes(skb, ETH_HLEN, &ip_hdr, sizeof(ip_hdr)) < 0)
    return 0;
__u8 protocol = ip_hdr.protocol;


// __u16 h_proto = load_half(skb, offsetof(struct ethhdr, h_proto));
struct ethhdr eth_hdr;
if (bpf_skb_load_bytes(skb, 0, &eth_hdr, sizeof(eth_hdr)) < 0)
    return 0;
__u16 h_proto = bpf_ntohs(eth_hdr.h_proto);


// __u32 saddr = load_word(skb, ETH_HLEN + offsetof(struct iphdr, saddr));
struct iphdr ip_hdr;
if (bpf_skb_load_bytes(skb, ETH_HLEN, &ip_hdr, sizeof(ip_hdr)) < 0)
    return 0;
__u32 saddr = ip_hdr.saddr;

Comments

comments powered by Disqus