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中关于长度的两个字段
- len字段:无分片的报文,数据报文的大小
- data_len字段:存在分散报文,data_len表示分片的部分大小
如下所示,没有开启分片的报文len = x,data_len = 0:
如下所示在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。
FRAGLIST类型的分散聚合I/O的报文:
采用FRAGLIST类型的分散聚合I/O报文, ** frag_list不为NULL,nf_frags等于0 ,** 数据长度len为x+S1,data_len为S1,
以上从struct sk_buff的四大指针以及操作、非线性区域对套接字缓存(socket buffer)进行分析,更多sk_buff的分析、实操等将在以后的文章中梳理。
-
嵌入式
+关注
关注
5068文章
19008浏览量
302995 -
Linux
+关注
关注
87文章
11219浏览量
208879 -
内存
+关注
关注
8文章
2996浏览量
73870
发布评论请先 登录
相关推荐
评论