深入理解Linux网络技术内幕_关键数据结构 sk_buff

关键数据结构

1. sk_buf

sk_buf{
	布局字段
	通用字段
	功能专用字段
	管理函数
}
1.1 布局字段

内核为了方便搜寻和组织数据结构,使用了双向链表来维护所有的sk_buf结构,但是该表的组织比传统的双向链表更为复杂。

struct sk_buf_head{
	struct sk_buf *next
	struct sk_buf *prev
	__u32		   qlen //元素的数目。
	spinloct_t     lock //防止对表的并发访问。
}
struct sk_buf {
	struct sk_buf *next
	struct sk_buf *prev
	struct sk_buf_head *list //指向专一的sk_buf_head数据结构。
	struct sock *sk	//指向缓冲区的套接字数据结构,当数据由进程接收时,就需要这个指针。T4以及用户程序使用。
	unsigned int len //缓冲区数据块的大小(含数据包的头)。
	unsigned int data_len //只计算片段中的数据大小。
	unsigned int mac_len //mac报头的大小。
	atomic users //引用计数,使用sk_buf实例的数目。
	unsigned int truesize //此缓冲区的总大小。
	unsigned char *head //缓冲区数据的开端。
	unsigned char *end  //缓冲区数据的尾端。
	unsigned char *data	//缓冲区实际数据的开端。
	unsigned char *tail //缓冲区实际数据的尾端。
	
	void (*destructor)(...) //函数指针可初始化为一个函数,但缓冲区被删除时,可完成某项工作。
}

在这里插入图片描述

1.2 通用字段
struct sk_buf {
	...
	struct timeval stamp //时间戳,表示封包何时被接收,或有时用于封包预定传输的时间。
	struct net_device *dev //用于描述一个网络设备。
	struct net_device *input_dev //已被接收封包来自的设备。
	struct net_device *real_dev //此字段只对虚拟设备有意义。
	
	union {...} h //h是针对L4(传输层)。
	union {...} nh //nh是针对L3(网络层)。
	union {...} mac //mac是针对L2(网络接口层)。
	
	struct dst_entry dst //这个结构由路由子系统使用。
	char cb[40] //“控制缓冲区”,为每一层内部起维护作用。
	unsigned int csum //校验和。
	unsigned char ip_summed //状态标识。
	unsigned char cloned //相当于一个boolean标识位,改结构是不是另一个sk_buf拷贝来的。
	unsigned char pkt_type //根据帧的L2目的地址进行划分。
	__u32 priority //标示真被传输或转发的封包QoS等级。
	unsigned short protocol //从L2层来看,用于下一层较高的协议。
	unsigned short security //封包的安全级别。
}
1.3 功能专用字段
struct sk_buf {
	...
	/**
		以下参数由防火墙使用。
	*/
	unsigned long mfmark
	__u32 nfcache
	__u32 nfctinfo
	struct nf_conntrack *nfct
	unsigned int nf debug
	struct nf_brudge_info *nf_bridge 
	
	union {...} private //这个联合由HIPPI(高性能并行串口)使用。
	
	/**
		以下参数由于流量控制使用。
	*/
	__u32 tc_index
	__u32 tc_verd
	__u32 tc_classid
	
	struct sec_path *sp //由IPsec协议组使用,已记录转换信息。
}
1.4 管理函数

分配内存:alloc_skb和dev_alloc_skb

​ alloc_skb是分配缓冲区的主要函数。alloc_skb通过调用kmem_cache_alloc函数,从一个缓存中渠道sk_buff数据结构,然后调用kmalloc以取得一个数据缓冲区。

skb = kmem_cache_alloc(...)
...
size = SKB_DATA_ALIGN(size)
data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask)

​ dev_alloc_skb是由设备驱动程序使用的缓冲区分配函数,应该在中断模式中执行。此函数只是包裹了alloc_skb的函数,为了优化的原因在申请之上加了16个字节。因为此函数是由中断事件处理的函数调用,所以要求原子操作(GFP_ATOMIC)。

释放内存:kfree_skb和dev_kfree_skb

​ 这两个函数会释放一个缓冲区,使其返回缓存池子。dev_kfree_skb不做任何的事情,只是简单的调用kfree_skb。只有当skb->users = 1的时候,这个函数才会释放缓冲区。否则,递减该计数器。

数据预留及对齐:skb_reserve、skb_put、skb_push以及skb_pull

​ skb_resever会在缓冲区头部预留一些空间,通常允许插入一些包头,或者强迫数据对齐某个边界。注意,sk_reserve并没有将任何东西移入数据缓冲区内,只是更新了两个指针。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zM2JdJBK-1671114839015)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20221215215515914.png)]

​ skb_push会把一个数据块添加到缓冲区的开端,而skb_put会把一个数据块添加到缓冲区的结尾。skb_pull是吧head指针向前移,吧一个数据块从缓冲区的头部删除。

skb_shared_info结构和skb_shinfo函数

​ skb_shared_info用以保持数据块区域的附加信息,此数据结构标记数据尾端的end指针后。

struct skb_shared_info {
	automic_t dataref //数据块的用户数目。
	/**
		以下字段用来处理IP片段。	
	*/
	unsigned int nr_frags 
	struct sk_buff *frag_list
	skb_frag_t frags[MAX_SKB_FRAGS]
	/**
		以下字段用来处理TCP节段卸载。	
	*/
    unsigned short tso_size
	unsigned short tso_seqs
}

​ skb_buff结构没有指向skb_shared_info的字段,为了访问该结构,必须使用返回end指针的skb_shinfo宏。

缓冲区的克隆和拷贝

​ 当一个缓冲区需要被不同消费者处理时,那些消费者可能需要sk_buf描述符的内容。skb_clone只克隆sk_buff结构,共享数据缓冲区。当一个缓冲区被克隆时,数据不能被修改。当程序员想要修改缓冲区的数据的时候可以使用pskb_copy和skb_copy。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q1BpzHsA-1671114839017)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20221215222933273.png)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值