Linux内核-从sk_buff{}结构学习“双循环双链表”的实现

【他引】

代码:linux-2.4 Kernel

图一 : Linux TCP IP 协议栈分析.pdf

【背景】

sk_buff{}结构是linux 网络协议栈的重要结构体,本结构描述的数据包(package)穿梭于运输层~链路层之间。每个数据包都有对应的sk_buff进行描述,而系统对这么多的sk_buff的处理时以循环双链表的形式组织的。见如下图:

Linux内核-从sk_buff{}结构学习“双循环双链表”的实现_第1张图片

                                                       图一

【数据结构】

//链表表头,维护一个表,作为一个链表的标杆,不做具体数据的存储
struct sk_buff_head {
	struct sk_buff	* next;
	struct sk_buff	* prev;
	__u32		qlen;

	spinlock_t	lock;
};

//链表数据节点
struct sk_buff {
	/* 链表结构参数*/
	struct sk_buff	* next;			/* Next buffer in list 				*/
	struct sk_buff	* prev;			/* Previous buffer in list 			*/
	struct sk_buff_head * list;		/* List we are on				*/

	/*...
	data
	...*/
}

【List init】

链表的初始化...

//链表的表头的初始化
static inline void skb_queue_head_init(struct sk_buff_head *list)
{
	spin_lock_init(&list->lock);
	list->prev = (struct sk_buff *)list;
	list->next = (struct sk_buff *)list;
	list->qlen = 0;
}

【Operations】

链表的每个操作有两个函数构成,形如__fun(),fun()。而且都是在fun()中调用__fun()。
主要原因是__fun()是非原子操作,在fun()中添加锁机制,确保__fun()操作的原子性。
比如:__skb_quque_head()和skb_queue_head();

static inline void __skb_queue_head(struct sk_buff_head *list, struct sk_buff *newsk)
{
	struct sk_buff *prev, *next;

	newsk->list = list;
	list->qlen++;
	prev = (struct sk_buff *)list;
	next = prev->next;
	newsk->next = next;
	newsk->prev = prev;
	next->prev = newsk;
	prev->next = newsk;
}

/**
 *	skb_queue_head - queue a buffer at the list head
 *	@list: list to use
 *	@newsk: buffer to queue
 *
 *	Queue a buffer at the start of the list. This function takes the
 *	list lock and can be used safely with other locking &sk_buff functions
 *	safely.
 */	
 //头部添加
static inline void skb_queue_head(struct sk_buff_head *list, struct sk_buff *newsk)
{
	unsigned long flags;

	spin_lock_irqsave(&list->lock, flags);
	__skb_queue_head(list, newsk);
	spin_unlock_irqrestore(&list->lock, flags);
}

其他函数的fun()基本显示,下面就主要贴出每个链表操作的具体实现的函数__fun().

/**
 *	__skb_queue_tail - queue a buffer at the list tail
 *	@list: list to use
 *	@newsk: buffer to queue
 *
 *	Queue a buffer at the end of a list. This function takes no locks
 *	and you must therefore hold required locks before calling it.
 *
 *	A buffer cannot be placed on two lists at the same time.
 */
//尾部添加
static inline void __skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk)
{
	struct sk_buff *prev, *next;

	newsk->list = list;
	list->qlen++;
	next = (struct sk_buff *)list;
	prev = next->prev;
	newsk->next = next;
	newsk->prev = prev;
	next->prev = newsk;
	prev->next = newsk;
}

/**
 *	__skb_dequeue - remove from the head of the queue
 *	@list: list to dequeue from
 *
 *	Remove the head of the list. This function does not take any locks
 *	so must be used with appropriate locks held only. The head item is
 *	returned or %NULL if the list is empty.
 */
//删除第一个数据节点
static inline struct sk_buff *__skb_dequeue(struct sk_buff_head *list)
{
	struct sk_buff *next, *prev, *result;

	prev = (struct sk_buff *) list;
	next = prev->next;
	result = NULL;
	if (next != prev) {
		result = next;
		next = next->next;
		list->qlen--;
		next->prev = prev;
		prev->next = next;
		result->next = NULL;
		result->prev = NULL;
		result->list = NULL;
	}
	return result;
}


/**
 *	__skb_dequeue_tail - remove from the tail of the queue
 *	@list: list to dequeue from
 *
 *	Remove the tail of the list. This function does not take any locks
 *	so must be used with appropriate locks held only. The tail item is
 *	returned or %NULL if the list is empty.
 */
//删除最后一个数据节点
static inline struct sk_buff *__skb_dequeue_tail(struct sk_buff_head *list)
{
	struct sk_buff *skb = skb_peek_tail(list); 
	if (skb)
		__skb_unlink(skb, list);
	return skb;
}


/*
 *	Insert a packet on a list.
 */
static inline void __skb_insert(struct sk_buff *newsk,
	struct sk_buff * prev, struct sk_buff *next,
	struct sk_buff_head * list)
{
	newsk->next = next;
	newsk->prev = prev;
	next->prev = newsk;
	prev->next = newsk;
	newsk->list = list;
	list->qlen++;
}


/*
 *	Place a packet after a given packet in a list.
 */

static inline void __skb_append(struct sk_buff *old, struct sk_buff *newsk)
{
	__skb_insert(newsk, old, old->next, old->list);
}


/*
 * remove sk_buff from list. _Must_ be called atomically, and with
 * the list known..
 */
 
static inline void __skb_unlink(struct sk_buff *skb, struct sk_buff_head *list)
{
	struct sk_buff * next, * prev;

	list->qlen--;
	next = skb->next;
	prev = skb->prev;
	skb->next = NULL;
	skb->prev = NULL;
	skb->list = NULL;
	next->prev = prev;
	prev->next = next;
}


你可能感兴趣的:(C语言,sk_buff,双循环链表)