linux igmp数据内核分析,skb解析_老张的技术博客的技术博客_51CTO博客

skb(Struct sk_buffer)是TCP/IP堆栈中用于收发包的缓冲区域。它在接收数据的时候会进行2次拷贝,以提升性能:数据包进入网卡驱动后拷贝一次,从内核空间递交给用户空间的应用时再拷贝一次。网络中所有数据包的封装及解封都是通过这个结构进行的。struct sk_buff {

struct sk_buff                       *next;

struct sk_buff                       *prev;

struct sock                            *sk;

struct skb_timeval               tstamp;

struct net_device           *dev;

struct net_device           *input_dev;

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;

struct  dst_entry                   *dst;

struct       sec_path                *sp;

char                                         cb[40];

unsigned int                           len,

data_len,

mac_len,

csum;

__u32                                      priority;

__u8                                         local_df:1,

cloned:1,

ip_summed:2,

nohdr:1,

nfctinfo:3;

__u8                                         pkt_type:3,

fclone:2;

__be16                                    protocol;

void                                          (*destructor)(struct sk_buff *skb);

/* These elements must be at the end, see alloc_skb() for details.  */

unsigned int                           truesize;

atomic_t                                 users;

unsigned char                       *head,

*data,

*tail,

*end;

};

一、成员变量解析

tstamp可通过调用net_enable_timestamp(),用于记录数据包send/recv时间。但是这个计算会消耗一些时间。

*dev、*input_dev这两个值都是用来区分不同的设备,input_dev通常用来指向接收数据包优先级最高的网络输入设备。

cb[40]skb的控制块, 用来保存重传状态或数据包的序列号等信息。

len表示skb中数据缓冲的总长度

priority定义数据包的优先级, 传输控制模块根据这个值来实现对数据包的分类,以决定调度策略

cloned当对一个已存在的skb进行复制后,新skb会共享已有的skb数据区,这时这两个skb的clone值都会被设置成1

truesize就是skb所消耗的内存(skb本身+databuffer)

rcvbuf接收数据包的总大小

sndbuf发送数据包的总大小

[*head, *data, *tail, *end]

这四个指正用来实现对databuffer的管理。head和end用于指向buffer, data和tail用来指向实际的数据。这四个指正将buffer划分为三个区packet data:用来保存真正的数据

head room:packetdata上面的空闲空间,用于给协议头分配内存

tail room: packetdata下面的空闲空间, 用于给数据分配内存

e48f1059abfb69db4075cf74a725ecde.png

划分了三个区,这样当数据包需要增加协议头的时候就只需要从上层空间拿一块内存,当需要增加数据的时候就只需要从下层空间拿一块内存。这样skb就只需要申请一次内存,之后的处理只需通过指正就可完成。

二、关于skb的一些操作创建一个skb结构static inline struct sk_buff *alloc_skb( unsigned int size, gfp_t priority)

{

return  __alloc_skb(size, priority, 0, -1) //fclone位,1表对当前skb克隆, 0表不克隆

}

size : 为将要分配的缓存区的大小;

priority : 取值为GFP_ATOMIC, GFP_KERNEL等(指对内存抢占的优先级);

0257d68ff4512226eee1912ca44de052.png释放skb结构

void kfree_skb(struct sk_buff *skb);这里会进行一个判断,如果skb->users > 1,则只进行atomic_dec(&skb->user)操作,然后返回。如果skb->users = 1,则才会将struct sk_buff结构体所占的内存还给系统。

这里应该是判断是否存在共享,没咋搞懂。。。

三、内核接收数据包方式中断方式

2.4之前都是用中断方式接收的。数据包到达网卡后产生一个中断,中断服务程序将接收的数据拷贝到skb,然后将skb挂入软中断队列上,同时将设备poll_list加入软中断的poll_list列表并标记,然后等待软中断处理。发生软中断的时候将skb从软中断队列中取出,发送给网络上层(netif_receive_skb())。轮询方式

2.6中增加了轮询机制。当中断来临时,它首先直接将设备poll_list挂入软中断的poll_list,打上软中断标记,先不对数据包进行接收,把接收数据包的任务给软中断了。发生软中断时直接把网卡数据poll给skb, 然后交给上层(netif_receive_skb())。

netif_receive_skb()得到skb包之后就处理该数据包, 检查正确性,打印时间戳。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值