我目前正在尝试调试在以太网上运行的ATM封装层。基本上ATM信元在以太网报头之后按顺序存储。但是我怀疑司机天真接近sk_buffs的方法已经破裂了。
驱动程序盲目地假设skb->数据可以迭代但查看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->数据访问。
我应该使用什么来获取基础数据。理想情况下,我想在memcpy将块存入我维护的重组缓冲区之前,将任意偏移量的几个字节窥视到以太网数据包中。我该怎么做才能做到这一点?
答案 0 :(得分:7)
套接字缓冲区的实现由线性数据缓冲区和一个或多个页面缓冲区组成。
套接字缓冲区中分页数据的存在由skb->data_len
成员非零表示。
bool skb_is_nonlinear(const struct sk_buff *skb)
中定义的 /include/linux/skbuff.h
用于测试此内容。
skb->数据的非分页数据量可以计算为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代码和其他以太网驱动程序中可以看到使用示例。
了解更多信息