SKB中的各种长度、数据指针和操作函数

skb结构体中的长度和数据指针

len: 线性区和分片区域的总长度
data_len:分片区域frag page中的数据长度
len-data_len: 当前协议层中的线性区长度

head:线性区的起始地址
data:数据的起始地址
tail:数据的结束地址
end:线性区的结束地址

headroom:从head到data之间的空间
tailroom:从tail到end之间的空间

除了上面的几个成员,特别指出一个truesize,它表示一个skb所消耗的内存,包括了skb结构体本身,skb shared info结构体和对应的数据区总占用内存大小。对于truesize来说,内核的定义如下:

#define SKB_TRUESIZE(X) ((X) +                      \                                                                                                                                           
           SKB_DATA_ALIGN(sizeof(struct sk_buff)) +   \
          SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))

SKB中的各种长度、数据指针和操作函数_第1张图片

skb操作函数

对于只有线性区的skb来说,有如下一些操作函数:

skb_put(): 向后扩大数据区空间。headroom空间不变,tailroom空间降低,skb->data指针不变,skb->tail指针下移;
skb_push(): 向前扩大数据区空间。headroom空间降低,tailroom空间不变。skb->tail指针不变,skb->data指针上移;
skb_pull(): 缩小数据区空间.headroom空间增大,tailroom空间不变,skb->data指针下移,skb->tail指针不变;
skb_reserve(): 数据区空间大小不变,headroom空间增大,tailroom空间降低,skb->data和skb->tail同时下移;

skb_reserve()只能用于空的SKB,通常会在分配SKB之后就调用该函数,此时data和tail指针还一同指向数据区的起始位置。例如,某个以太网设备驱动的接收函数,在分配SKB之后,向数据缓存区填充数据之前,会有这样的一条语句skb_reserve(skb, 2),这是因为以太网头长度为14B,再加上2B就正好16字节边界对齐,所以大多数以太网设备都会在数据包之前保留2B。

如果该skb存在分片的frag page,那么不能使用上面的函数了,必须使用:

SKB中的各种长度、数据指针和操作函数_第2张图片

pskb_pull():
对于带有frag page的分片skb来说,data指针往下移动,可能会导致线性区越界,因此需要判断是否线性区有足够的空间用来pull操作,如果空间不够,那么需要执行linearize,重构线性区,把一部分frags中的数据移动到线性区中来操作。
pskb_may_pull():
主要在使用skb_pull之前来检查线性区buffer有没有足够的数据用于 pull。
pskb_copy():
参考上图(a)只skb拷贝线性区的数据,对于分片的skb来说它的shared_info会拷贝过来,但是指向的frag page是共享的。所以使用该函数拷贝生成的新的skb只能修改线性区中的数据。
skb_copy():
参考上图(b)拷贝线性区和分片区的所有数据,一个分片的skb经过拷贝后会生成一个完全线性的skb。对于只想修改header的操作,建议不要使用该函数,而应该使用pskb_copy()。

skb_clone():
参考本文第一张图,只拷贝skb结构体,对应的head/data/tail/end指针指向的线性区还是共享的,所以clone的skb是不能修改其中的数据的。


https://www.cnblogs.com/zfyouxi/p/4560841.html

你可能感兴趣的:(网络子系统)