在Linux中处理sk_buff数据包的所有有效负载的正确方法是什么

sts*_*uad 6 c networking linux-kernel skb

我目前正在尝试调试在以太网上运行的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);
Run Code Online (Sandbox Code Playgroud)

然后进一步说:

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

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

我应该用什么来获取基础数据.理想情况下,我希望在memcpy将块存入我维护的重组缓冲区之前,将任意偏移量的几个字节查看到以太网数据包中.我该怎么用呢?

App*_*234 8

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

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

了解更多信息