在Linux中处理sk_buff数据包的所有有效载荷的正确方法是什么 [英] What's the correct way to process all the payload of a sk_buff packet in Linux

查看:612
本文介绍了在Linux中处理sk_buff数据包的所有有效载荷的正确方法是什么的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在尝试调试在以太网顶部运行的ATM封装层.基本上,ATM信元按顺序存储在以太网头之后.但是我怀疑驱动程序对sk_buffs的幼稚方法已被破坏.

I'm currently trying to debug an ATM encapsulation layer that runs on-top of Ethernet. Basically the ATM cells are stored in order after the ethernet header. However I suspect the drivers naive approach to the sk_buffs is broken.

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

The driver blindly assumes that skb->data can be iterated through but looking at the kernel code for virtio_net.c:page_to_skb I see the following behaviour:

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直接访问.

Which seems to show the buffer is fragmented with only the first portion being directly accessible from skb->data.

我应该使用什么来获取基础数据.理想情况下,我想先将任意大小的字节偷看到以太网数据包中,然后再将大块存入我维护的重组缓冲区中.我该怎么用呢?

What should I be using to get at the underlying data. Ideally I want to peek a few bytes at arbitrary offsets into the ethernet packet before memcpy'ing chunks into a reassembly buffer I maintain. What should I be using to do this?

推荐答案

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

The implementation of socket buffers are comprised of a linear data buffer and one or more page buffers.

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

The existence of paged data in a socket buffer is indicated by skb->data_len member being non-zero.

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)用于对此进行测试.

The amount of non-paged data at skb->data can be calculated as skb->len - skb->data_len. unsigned int skb_headlen(const struct sk_buff *skb) defined in /include/linux/skbuff.h is used to test this.

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

The skb->data pointer only points to the non paged data, which what the driver you described possibly relies on.

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

void *skb_header_pointer(const struct sk_buff *skb, int offset, int len, void *buffer) is defined in /include/linux/skbuff.h . It takes the socket buffer, byte offset and byte length your want and a local data buffer which is only used if the data is in one of the page buffers.

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

It returns a pointer to either the data in the linear data buffer from skb->data or the pointer to the local data buffer supplied, or NULL if your offset and length were incorrect.

对于大于协议头的数据,您要么要使用

For pieces of data larger than protocol headers you either want to use

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

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

to copy from a given socket buffer ,byte offset and byte length to a given kernel buffer.

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

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

to to copy from a given socket buffer ,byte offset and byte length to a given iovec structure in user space.

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

Examples of usage can been seen in netfilter code and in other Ethernet drivers.

了解更多信息

  • Socket Buffer Introduction by David S. Miller
  • Socket Buffer Data Layout by David S. Miller
  • Socket Buffer Tutorial by Roberto Innocente, O.S.Adewale

这篇关于在Linux中处理sk_buff数据包的所有有效载荷的正确方法是什么的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆