linux网络协议之 sk_buff 结构分析

【推荐阅读】

浅谈linux 内核网络 sk_buff 之克隆与复制

深入linux内核架构--进程&线程

了解Docker 依赖的linux内核技术

想要了解网络是怎么进行部署和运行的,首先要做的就是对数据结构进行分析。首先我们对最重要的sk_buff这个数据结构的一些内容查看分析。

一、布局字段

1.表头数据结构

skbuff.h

struct sk_buff_head {/* These two members must be first. */// 双向链表指针 前驱指针和后继指针struct sk_buff	*next;struct sk_buff	*prev;// 表中元素的数目__u32		qlen;// 用于防止对表的并发访问spinlock_t	lock;
};

2.sk_buff中的布局字段

本数据结构过于庞大,只挑出部分尽心分析

skbuff.h

union {struct {/* These two members must be first. */// 双向链表指struct sk_buff		*next;struct sk_buff		*prev;union {// 指向网络设备的指针struct net_device	*dev;/* Some protocols might use this space to store information,* while device pointer would be NULL.* UDP receive path is one user.*/unsigned long		dev_scratch;};};struct rb_node		rbnode; /* used in netem, ip4 defrag, and tcp stack */// 指向表头的指针struct list_head	list;
};
union {// 指向拥有此缓冲区的套接字的sock数据结构。只有数据再本地产生或者接受的时候才有用,如果只是被转发,则为NULLstruct sock		*sk;int			ip_defrag_offset;
};
// 缓冲区数据块的大小,包括报头
unsigned int		len,
// 只表示数据大小data_len;
// MAC报头的大小__u16			mac_len,

/* private: */__u32			headers_end[0];/* public: *//* These elements must be at the end, see alloc_skb() for details.  */// 指向数据尾部的指针sk_buff_data_t		tail;、// 指向缓冲区尾部的指针sk_buff_data_t		end;// 指向缓冲区头部的指针unsigned char		*head,// 指向数据头部的指针*data;// 缓冲区总大小,包括sk_buff结构本身unsigned int		truesize;// 引用计数,表示使用这个sk_buff缓冲区的实例的数目。避免在某人依然使用此sk_buff的时候,吧这个结构释放掉。缓冲区的每个用户都要递增递减这个字段refcount_t		users;

二、通用字段

union {// 时间戳,表示封包何时被接收ktime_t		tstamp;u64		skb_mstamp_ns; /* earliest departure time */};
/** This is the control buffer. It is free to use for every* layer. Please put your private variables there. If you* want to keep them across layers you have to do a skb_clone()* first. This is owned by whoever has the skb queued ATM.*/控制缓冲区,为每一层内部使用起维护作用,在每一层的代码都是通过宏进行访问。char			cb[48] __aligned(8);
/*根据真的L2目的地址进行类型划分接收帧的目的地址#define PACKET_HOST		0已接收的真的目的地址是该接口的广播地址#define PACKET_BROADCAST	1已接收的真的目的地址是该接口的多播地址#define PACKET_MULTICAST	2已接收的真的目的地址不属于与该接口相匹配的地址。如果转发机制使能,就会转发,否则将丢弃封包正在被发送#define PACKET_OTHERHOST	3		封包正传送至环回设备#define PACKET_LOOPBACK		5		*/__u8			pkt_type:3;__u8			ignore_df:1;__u8			nf_trace:1;__u8			ip_summed:2;__u8			ooo_okay:1;union {// 校验和__wsum		csum;struct {__u16	csum_start;__u16	csum_offset;};};// 正被转发或传输的封包的QoS等级__u32			priority;

管理函数

skbuff.c

注:会发现文件中几乎所有的函数都有两个版本。do_something和__do_something。第一个是包裹函数,增加了额外的合理性检查或者在调用第二个函数前后加入上锁机制。__do_something一般不会被直接调用。

// 分配缓冲区的主要函数
struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,int flags, int node)
{struct kmem_cache *cache;struct skb_shared_info *shinfo;struct sk_buff *skb;u8 *data;bool pfmemalloc;cache = (flags & SKB_ALLOC_FCLONE)? skbuff_fclone_cache : skbuff_head_cache;if (sk_memalloc_socks() && (flags & SKB_ALLOC_RX))gfp_mask |= __GFP_MEMALLOC;/* Get the HEAD */skb = kmem_cache_alloc_node(cache, gfp_mask & ~__GFP_DMA, node);if (!skb)goto out;prefetchw(skb);/* We do our best to align skb_shared_info on a separate cache* line. It usually works because kmalloc(X > SMP_CACHE_BYTES) gives* aligned memory blocks, unless SLUB/SLAB debug is enabled.* Both skb->head and skb_shared_info are cache line aligned.*/size = SKB_DATA_ALIGN(size);size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info));data = kmalloc_reserve(size, gfp_mask, node, &pfmemalloc);if (!data)goto nodata;/* kmalloc(size) might give us more room than requested.* Put skb_shared_info exactly at the end of allocated zone,* to allow max possible filling before reallocation.*/size = SKB_WITH_OVERHEAD(ksize(data));prefetchw(data + size);/** Only clear those fields we need to clear, not those that we will* actually initialise below. Hence, don't put any more fields after* the tail pointer in struct sk_buff!*/memset(skb, 0, offsetof(struct sk_buff, tail));/* Account for allocated memory : skb + skb->head */skb->truesize = SKB_TRUESIZE(size);skb->pfmemalloc = pfmemalloc;refcount_set(&skb->users, 1);skb->head = data;skb->data = data;skb_reset_tail_pointer(skb);skb->end = skb->tail + size;skb->mac_header = (typeof(skb->mac_header))~0U;skb->transport_header = (typeof(skb->transport_header))~0U;/* make sure we initialize shinfo sequentially */shinfo = skb_shinfo(skb);memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));atomic_set(&shinfo->dataref, 1);if (flags & SKB_ALLOC_FCLONE) {struct sk_buff_fclones *fclones;fclones = container_of(skb, struct sk_buff_fclones, skb1);skb->fclone = SKB_FCLONE_ORIG;refcount_set(&fclones->fclone_ref, 1);fclones->skb2.fclone = SKB_FCLONE_CLONE;}
out:return skb;
nodata:kmem_cache_free(cache, skb);skb = NULL;goto out;
}

释放内存

/***	__kfree_skb - private function*	@skb: buffer**	Free an sk_buff. Release anything attached to the buffer.*	Clean the state. This is an internal helper function. Users should*	always call kfree_skb*/void __kfree_skb(struct sk_buff *skb)
{skb_release_all(skb);kfree_skbmem(skb);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值