【问题标题】:What's the correct way to process all the payload of a sk_buff packet in Linux在 Linux 中处理 sk_buff 数据包的所有有效负载的正确方法是什么
【发布时间】:2012-11-27 16:26:19
【问题描述】:

我目前正在尝试调试在以太网之上运行的 ATM 封装层。基本上,ATM 信元在以太网标头之后按顺序存储。但是我怀疑司机对 sk_buffs 的天真方法被打破了。

驱动程序盲目地假设 skb->data 可以迭代,但查看 virtio_net.c:page_to_skb 的内核代码我看到以下行为:

memcpy(hdr, p, hdr_len);
len -= hdr_len;
p += offset;
copy = len;

if (copy > skb_tailroom(skb))
        copy = skb_tailroom(skb);

memcpy(skb_put(skb, copy), p, copy);

然后继续:

while (len) {
        set_skb_frag(skb, page, offset, &len);
    page = (struct page *)page->private;
    offset = 0;
}

这似乎表明缓冲区是碎片化的,只有第一部分可以从 skb->data 直接访问。

我应该使用什么来获取基础数据。理想情况下,我想在 memcpy 将块放入我维护的重组缓冲区之前,在以太网数据包中的任意偏移处查看几个字节。我应该用什么来做到这一点?

【问题讨论】:

    标签: c networking linux-kernel skb


    【解决方案1】:

    套接字缓冲区的实现由一个线性数据缓冲区和一个或多个页面缓冲区组成。

    skb->data_len 成员非零表示套接字缓冲区中存在分页数据。

    /include/linux/skbuff.h 中定义的bool skb_is_nonlinear(const struct sk_buff *skb) 用于测试。

    skb->data处的非分页数据量可以计算为skb->len - skb->data_len。 /include/linux/skbuff.h 中定义的 unsigned int skb_headlen(const struct sk_buff *skb) 用于测试。

    skb->data 指针仅指向非分页数据,您描述的驱动程序可能依赖于该数据。

    void *skb_header_pointer(const struct sk_buff *skb, int offset, int len, void *buffer)/include/linux/skbuff.h 中定义。它需要您想要的套接字缓冲区、字节偏移量和字节长度 和一个本地数据缓冲区,仅当数据位于其中一个页面缓冲区中时才使用。

    它返回一个指针,指向来自skb->data 的线性数据缓冲区中的数据或指向提供的本地数据缓冲区的指针, 如果您的偏移量和长度不正确,则为 NULL。

    对于大于协议标头的数据,您可以使用

    int skb_copy_bits(const struct sk_buff *skb, int offset,void *to, int len);

    从给定的套接字缓冲区、字节偏移量和字节长度复制到给定的内核缓冲区。

    int skb_copy_datagram_iovec(const struct sk_buff *from, int offset, struct iovec *to, int size);

    从给定的套接字缓冲区、字节偏移量和字节长度复制到用户空间中的给定iovec结构。

    可以在 netfilter 代码和其他以太网驱动程序中看到使用示例。

    更多信息

    【讨论】:

      猜你喜欢
      • 2021-03-04
      • 1970-01-01
      • 1970-01-01
      • 2012-01-05
      • 2012-11-01
      • 2021-02-10
      • 1970-01-01
      • 1970-01-01
      • 2014-10-23
      相关资源
      最近更新 更多