Linux内核-从sk_buff{}结构学习“双循环双链表”的实现
2013-09-14 14:19
459 查看
【他引】
代码:linux-2.4 Kernel
图一 :Linux TCP IP 协议栈分析.pdf【背景】
sk_buff{}结构是linux 网络协议栈的重要结构体,本结构描述的数据包(package)穿梭于运输层~链路层之间。每个数据包都有对应的sk_buff进行描述,而系统对这么多的sk_buff的处理时以循环双链表的形式组织的。见如下图:图一
【数据结构】
//链表表头,维护一个表,作为一个链表的标杆,不做具体数据的存储 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; }
相关文章推荐
- 【Linux 内核网络协议栈源码剖析】网络栈主要结构介绍(socket、sock、sk_buff,etc)
- 学习Linux-4.12内核网路协议栈(1.2)——协议栈的初始化(sk_buff)
- 【Linux 内核网络协议栈源码剖析】网络栈主要结构介绍(socket、sock、sk_buff,etc)
- 【Linux 内核网络协议栈源码剖析】网络栈主要结构介绍(socket、sock、sk_buff,etc)
- Linux2.6.39内核sk_buff的结构分析
- linux2.6.24内核源代码分析(1)——扒一扒sk_buff
- php学习之 循环结构实现代码
- Linux内核设计与实现 学习笔记(7)设备与模块
- linux系统编程之文件与I/O(五):文件的内核结构file和dup实现重定向
- Linux 内核设计与实现学习笔记之第一章Linux内核简介和第二张从内核出发
- linux路由内核实现分析(二)---FIB相关数据结构
- 数据结构之循环双链表的结构和实现
- linux系统编程之文件与I/O(五):文件的内核结构file和dup实现重定向
- linux路由内核实现分析(二)---FIB相关数据结构(2)
- 内核中struct sk_buff结构分析
- linux路由内核实现分析(二)---FIB相关数据结构(3)
- Linux内核--网络协议栈深入分析(一)--与sk_buff有关的几个重要的数据结构
- 数据结构学习----线性表的链式表示之循环双链表(Java实现)
- linux路由内核实现分析(二)---FIB相关数据结构(4)