XDP程序ipheader,数据,nh_off混淆

时间:2019-10-06 09:14:52

标签: bpf ebpf

我现在正在研究XDP代码,关于程序如何处理数据包头的某些部分,我有些困惑。 所以!当我查看获取数据包IP地址的代码时,它看起来像:

static inline int parse_ipv4(void *data, u64 nh_off, void *data_end) {
struct iphdr *iph = data + nh_off;

if ((void*)&iph[1] > data_end)
    return 0;
    return iph->protocol;
}

现在这让我有些困惑:

struct iphdr *iph = data + nh_off;
  1. 我认为nh_off是下一个标头的偏移量,所以如果添加data + nh_off,那不应该带您到下一个数据包吗? 因为据我了解,如果您向数据添加下一个标头偏移,那么应该有一个下一个数据包等待处理!

  2. 做什么

    (void*)&iph[1]

    是吗?我试图猜测这行代码几天后会做什么,但是我还是一无所知。

如果我的问题太过吸收或模糊不清,我感到非常抱歉。这件事困扰了我一段时间,如果有人可以与我分享他们的知识,我将不胜感激。提前非常感谢您。

1 个答案:

答案 0 :(得分:3)

这完全取决于您的代码,因为我看不到您的情况下nh_off的定义。但是大多数时候,它确实指向下一个标头,因此我们将:

  1. nh_off是解析以太网报头后的下一报头的偏移量,即nh_off是数据包中IP报头的偏移量(通常是,则在此阶段将其设置为14,如果不使用VLAN / encap,则为以太网头中的字节数。

    设置struct iphdr *iph = data + nh_off;会将iph声明并初始化为struct iphdr指针,因此我们以后可以重用它来轻松地从IPv4标头访问每个字段。它指向data + nh_off,即数据包的开头加上IPv4标头在数据包中开始的偏移量。

    无法从您的eBPF程序中访问下一个要处理的数据包;当使用新的BPF程序调用处理 新数据包时,您将获得一个带有ctx指针的新data指针,但是您只会看到一个数据包一次。

  2. 因此iph指向IPv4标头的开头。我们可以使用该指针轻松访问各个字段(例如iph->protocol以获得L4协议)。但是在我们这样做之前,我们必须确保数据包足够长并且实际上包含那些字段。否则,我们可以进行越界访问(因此,验证者将首先拒绝该程序)。这是我们在此处执行的检查:if ((void*)&iph[1] > data_end) return 0;

    在该验证中,(void*)&iph[1]表示:i)考虑一个struct iphdr *数组(&iph,它是指向struct iphdr的指针的指针)。 ii)取得该阵列的第二个单元格,例如第二个struct iphdr *指向的结构的地址,例如从数据包中第一个struct iphdr开始的字节的地址。 iii)将其转换为void *,以便我们可以将其与data_end进行比较。换句话说,这是一种比较data_end(包中最后一个字节之后的内存中的地址)和IPv4标头之后紧接着的字节的地址(因此L4的第一个字节是包长)的一种方式足够)。如果(void*)&iph[1]大于data_end,则我们考虑的IPv4标头比我们得到的实际数据包长,因此我们无法取消引用iph来尝试到达例如protocol字段。

使用图表,也许:

Packet data

| Ethernet     | IPv4               | IPv4 data (e.g. L4, data)       |
+--------------+--------------------+------ ... ----------------------+
^              ^                    ^                                 ^
data           data + nh_off        |                                 data_end
               iph                  |
               &iph[0]              &iph[1]

如果我们有以下内容,则访问iph->protocol会遇到问题(这就是为什么return 0如果比较成功的原因):

Packet data

| Ethernet     | <something>   | End of packet
+--------------+----------------    +
^              ^               ^    ^
data           data + nh_off   |    |
               iph             |    |
               &iph[0]         |    &iph[1]
                               data_end