【问题标题】:XDP program ipheader, data, nh_off confusionXDP程序ipheader、data、nh_off混淆
【发布时间】:2019-10-06 09:14:52
【问题描述】:

我现在正在研究 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]

    到底是做什么的?几天前,我试图猜测这行代码的作用,但我仍然没有任何线索。

如果我的问题太集中或含糊不清,我很抱歉。这件事困扰了我一段时间,如果有人能与我分享他们的知识,我将不胜感激。非常感谢您。

【问题讨论】:

    标签: bpf ebpf


    【解决方案1】:

    这完全取决于您的代码,因为我看不出在您的情况下如何定义 nh_off。但大多数时候,它确实指向下一个标题,所以我们会:

    1. nh_offnext header在以太网头被解析后的偏移量,即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
    

    【讨论】:

    • 非常感谢您的友好解释!它真的帮了我很多忙!我想我现在终于明白这些代码的含义了:D
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多