7

我目前正在尝试调试在以太网之上运行的 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 将块放入我维护的重组缓冲区之前,在以太网数据包中的任意偏移处查看几个字节。我应该用什么来做到这一点?

4

1 回答 1

10

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

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

bool skb_is_nonlinear(const struct sk_buff *skb)定义在/include/linux/skbuff.h用于测试这一点。

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

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 代码和其他以太网驱动程序中可以看到使用示例。

了解更多信息

于 2012-11-27T17:46:49.637 回答