sk_buff内存空间布局情况与相关操作(三)

描述

2、非线性区域

在1、中,可以看到每张sk_buff的图: 在end指针紧挨着一个非线性区域

在struct sk_buff中没有指向skb_shared_info结构的指针,利用end指针,,可以用skb_shinfo宏来访问:

#define skb_shinfo(SKB) ((struct skb_shared_info *)(skb_end_pointer(SKB)))

其中skb_end_pointer函数如下,返回end指针

static inline unsigned char *skb_end_pointer(const struct sk_buff *skb)
{
 return skb- >end;
}

具体地,struct skb_shared_info如下:

struct skb_shared_info {
 __u8  __unused;
 __u8  meta_len;

    //数组frags包含的元素个数
 __u8  nr_frags;
 __u8  tx_flags;
 unsigned short gso_size;
 /* Warning: this field is not always filled in (UFO)! */
 unsigned short gso_segs;
 struct sk_buff *frag_list;
 struct skb_shared_hwtstamps hwtstamps;
 unsigned int gso_type;
 u32  tskey;

 /*
  * Warning : all fields before dataref are cleared in __alloc_skb()
  */
 
    //结构skb_shared_info 的引用计数器
 atomic_t dataref;

 /* Intermediate layers must ensure that destructor_arg
  * remains valid until skb destructor */
 void *  destructor_arg;

 /* must be last field, see pskb_expand_head() */
 skb_frag_t frags[MAX_SKB_FRAGS];
};

其中skb_frag_t如下:

typedef struct skb_frag_struct skb_frag_t;

struct skb_frag_struct {
 struct {

    //指向文件系统缓存页的指针
  struct page *p;
 } page;
#if (BITS_PER_LONG > 32) || (PAGE_SIZE >= 65536)

  //数据起始地址在文件系统缓存页中的偏移
 __u32 page_offset;
  //数据在文件系统缓存页中使用的长度
 __u32 size;
#else
 __u16 page_offset;
 __u16 size;
#endif
};

nr_frags,frags,frag_list与IP分片存储有关。

frag_list的用法:

  • 用于在接收分组后链接多个分片,组成一个完整的IP数据报
  • 在UDP数据报输出中,将待分片的SKB链接到第一个SKB中,然后在输出过程中能够快速的分片
  • 用于存放FRAGLIST类型的聚合分散I/O数据包

判断是否存在非线性缓冲区:

  • 先说明struct sk_buff中关于长度的两个字段
  1. len字段:无分片的报文,数据报文的大小
  2. data_len字段:存在分散报文,data_len表示分片的部分大小

如下所示,没有开启分片的报文len = x,data_len = 0:

Linux

如下所示在Linux内核中,使用skb_is_nonlinear函数判断是否存在分片,即通过判断data_len的大小是否为0:

static inline bool skb_is_nonlinear(const struct sk_buff *skb)
{
 return skb- >data_len;
}
  • 在没有开启分片的报文中,数据包长度在struct sk_buff中为len字段的大小,即data到tail的长度,nf_frags为0,frag_list为NULL。

普通聚合分散I/O的报文:

采用聚合分散I/O的报文, frag_list为 NULL,nf_frags不等于0 ,说明这不是一个普通的分片,而是聚合分散I/O的报文。

如下所示:

nr_frags为2,而frag_list为NULL,说明这不是普通的分片,而是聚合分散I/O分片,数量为2,这两个分片指向同一物理分页,各自在分页中的偏移和长度分别是0/S1和S1/S2。

Linux

FRAGLIST类型的分散聚合I/O的报文:

采用FRAGLIST类型的分散聚合I/O报文, ** frag_list不为NULL,nf_frags等于0 ,** 数据长度len为x+S1,data_len为S1,

Linux

以上从struct sk_buff的四大指针以及操作、非线性区域对套接字缓存(socket buffer)进行分析,更多sk_buff的分析、实操等将在以后的文章中梳理。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分