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

查看:26
本文介绍了在 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.

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

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) 定义在/include/linux/skbuff.h 中用于测试.

bool skb_is_nonlinear(const struct sk_buff *skb) defined in /include/linux/skbuff.h is used to test this.

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.

了解更多信息

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

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