sk_buff相关资料

1.sk_buff
sk_buff是linux内核TCP/IP协议栈最重要的结构,它是网络数据报在内核中的表现形式。sk_buff的定义在$KERN_DIR/incude/linux/skbuff.h中。
1.1 sk_buff最重要的几个成员:


1.sk_buff
sk_buff是linux内核TCP/IP协议栈最重要的结构,它是网络数据报在内核中的表现形式。sk_buff的定义在$KERN_DIR/incude/linux/skbuff.h中。
1.1 sk_buff最重要的几个成员:
union {
struct tcphdr *th;
struct udphdr *uh;
struct icmphdr *icmph;
struct igmphdr *igmph;
struct iphdr *ipiph;
struct ipv6hdr *ipv6h;
unsigned char *raw;
} h;

union {
struct iphdr *iph;
struct ipv6hdr *ipv6h;
struct arphdr *arph;
unsigned char *raw;
} nh;

union {
unsigned char *raw;
} mac;
这几个成员定义了各个层协议的头部,h是传输层头部,他是tcp/udp/icmp/igmp/ipip(ip over ip)/ipv6几个协议头部中的一种。nh是网络层协议的头部,他是ip/ipv6/arp几个协议头部中的一个。需要指出的是,Linux 2.6内核对mac层头部做了变动,在以前的sk_buff定义中,mac层头部中还有一个struct ethhdr *ethernet成员。目前还不清楚为什么要做这样的改变(兼容不同的标准?)。
unsigned int len,
data_len,
mac_len,
csum;
这几个成员定义了几个长度,len指的是不同层的数据报长度,包括头部和数据。在不同的层,len的值是不同的。也就是说,如果处在网络层,len指的是ip包的长度,如果包已经到了应用层,则len是应用层头部和数据载荷的长度。
data_len用在当数据包被分片存储时(不同于ip分片,只是在内存中用不连续的空间存储数据包)指定frags和frag_list所指空间的大小,一般为0。由于mac头部取消了ethernet成员,因此增加了mac_len来描述mac头部的长度。csum是以太网校验和。
unsigned int truesize;
atomic_t users;
unsigned char *head,
*data,
*tail,
*end;
truesize指报文的存储区长度,为16字节对齐。users为控制结构(sk_buff结构本身占据的内存)的引用技术。head指针指向存储空间的起始地址,end指针指向存储空间的结束地,data指针指向网络报文的起始地址,tail指针指向网络报文的结束地址,也就是说end-head=存储空间大小,tail-data=网络报文大小。网络报文不一定要填满整个存储空间,它可以在head和data之间,tail和end之间留下一些空间,这些空间可以做优化用,也可以为继续扩展网络报文提供空间。网络报文在存储空间里的存放的顺序依次是:链路层的头部,网络层的头部,传输层的头部,传输层的数据。


1.2 sk_buf的memory layout
________
| head     |--------->_______________
|-----------|             |                              |
| data      |--------->|______________|
|-----------|              |                             |
| tail        |              |          数据报         |
|-----------|---------->|______________|
| end       |            |                             |
--------------------->|____ __________|
sk_buff
在alloc_skb时,开辟两个内存区间,第一个存放sk_buff结构本身,第二个存放数据网络数据报。使用alloc_skb函数分配一个skb时,初始data,tail均和head一起,指向存储空间的开始出。如果使用dev_alloc_skb,则自动会在head和data之间保留一点空间,做优化用。
2. sk_buff相关的系列函数
1). struct sk_buff *alloc_skb(unsigned int size, int gfp_mask)
前面已经介绍过了,分配一个sk_buff。size指网络数据报的存储空间大小,sk_buff结构本身需要的内存空间不需要指定。因此在谈论sk_buff大小时,指的均是网络数据报的存储空间大小。最终分配出来的存储空间大小可能比size要大,因为在alloc_skb内部还要对size进行字节对齐处理size = SKB_DATA_ALIGN(size)。gfp_mask为内存分配优先级,常见的有GFP_ATOMIC和GFP_KERNEL.
2).struct sk_buff *dev_alloc_skb(unsigned int length)
内部以GFP_ATOMIC调用alloc_skb并在head和data之间保留16个字节(headroom)
3).struct sk_buff *skb_clone(struct sk_buff *skb, int gfp_mask)
克隆一个skb新的控制结构,克隆出来的skb中的cloned标记被置位并且增加网络报文的引用计数。
atomic_inc(&(skb_shinfo(skb)->dataref));
4). struct sk_buff *skb_copy(struct sk_buff *skb, int gfp_mask)
复制一个skb,包括控制结构和存储区域。复制成功后,新skb和原来的skb相对独立,cloned为0,并且引用计数为1。因此,我们可以修改存储区域中的数据报。
5). void kfree_skb(struct sk_buff *skb)
释放一个skb,当引用计数为1时,同时释放控制结构和存储区域。否则,只释放控制结构。
6). unsigned char *skb_put(struct sk_buff *skb, unsigned int len)
同时增加len和tail。用于向数据报尾部追加数据。返回原来tail所在位置。例如:对于一个新分配的skb,要增加mac,ip,tcp三个头部,就可以使用skb_put函数。
memcpy(skb_put(skb, ETH_HLEN),ethhd, ETH_HLEN);
memcpy(skb_put(skb, sizeof(struct iphdr), iphd, sizeof(struct iphdr));
memcpy(skb_put(skb, sizeof(struct tcphdr), tcph, sizeof(struct tcphdr));
7).unsigned char *skb_push(struct sk_buff *skb, unsigned int len)
将data指针上移(即往head方向移动)并增加len长度。这个函数用来向头部添加一些数据。当然前提是有足够的headroom。
8). unsigned char * skb_pull(struct sk_buff *skb, unsigned int len)
将data指针下移(往tail方向移动),并减小len的值。这个函数一般用来除去某个头部,将data指针指向上一层头部,或者数据。
9). void skb_reserve(struct sk_buff *skb, unsigned int len)
将data指针和tail指针同时下移。这个操作在存储空间的头部预留len长度的空隙(headroom)。
10). void skb_trim(struct sk_buff *skb, unsigned int len)
将网络报文的长度缩减到len。这个操作丢弃了网络报文尾部的填充值。
11). int skb_cloned(struct sk_buff *skb)
判断skb是否是一个clone的控制结构。如果是clone的,它的cloned标记是1,而且它指向的存储空间的引用计数大于1。

3.总结
sk_buff是linux网络协议栈中最重要的数据结构,理解它对于理解整个网络协议栈非常有帮助。需要注意的是,一个网络数据包存储于一片存储区域中,而该片存储区域可能同时被许多sk_buff控制结构所共享。该共享信息存储与end指针之后,可以通过(&(skb_shinfo(skb)->dataref来查看其引用状态。只有当引用为1的时候,我们才能修改数据区域。否则将造成不可预料的后果,包括内核崩溃。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值