網路驅動移植之sk_buff結構體及其相關操作函式(下)
2、結構體相關操作函式
(1)、dev_alloc_skb
實際上,函式dev_alloc_skb最終是呼叫__alloc_skb函式來分配資料緩衝區和sk_buff結構體的,如下圖:
從dev_alloc_skb到__alloc_skb所涉及的原始碼如下:
/* linux-2.6.38.8/net/core/skbuff.c */ struct sk_buff *dev_alloc_skb(unsigned int length) { /* * There is more code here than it seems: * __dev_alloc_skb is an inline */ return __dev_alloc_skb(length, GFP_ATOMIC); } /* linux-2.6.38.8/include/linux/skbuff.h */ static inline struct sk_buff *__dev_alloc_skb(unsigned int length, gfp_t gfp_mask) { struct sk_buff *skb = alloc_skb(length + NET_SKB_PAD, gfp_mask); if (likely(skb)) skb_reserve(skb, NET_SKB_PAD); return skb; } /* linux-2.6.38.8/include/linux/skbuff.h */ static inline struct sk_buff *alloc_skb(unsigned int size, gfp_t priority) { return __alloc_skb(size, priority, 0, NUMA_NO_NODE); }
其中,NET_SKB_PAD的值在ARM體系架構上為32。
接下來,在__alloc_skb函式中,首先通過kmem_cache_alloc_node函式(在未配置CONFIG_NUMA和CONFIG_SLOB的情況下,它的實現就是直接呼叫kmem_cache_alloc函式)從skbuff_head_cache快取記憶體中申請一個sk_buff結構體物件。建立skbuff_head_cache快取記憶體的原始碼如下:
/* linux-2.6.38.8/net/socket.c */ static int __init sock_init(void) { ... /* Initialize skbuff SLAB cache */ skb_init(); ... } core_initcall(sock_init); /* early initcall */ /* linux-2.6.38.8/net/core/skbuff.c */ void __init skb_init(void) { skbuff_head_cache = kmem_cache_create("skbuff_head_cache", sizeof(struct sk_buff), 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); skbuff_fclone_cache = kmem_cache_create("skbuff_fclone_cache", (2*sizeof(struct sk_buff)) + sizeof(atomic_t), 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); }
申請sk_buff結構體物件的程式碼如下:
/* linux-2.6.38.8/net/core/skbuff.c */
skb = kmem_cache_alloc_node(cache, gfp_mask & ~__GFP_DMA, node);
if (!skb)
goto out;
prefetchw(skb);
對於S3C2410,prefetchw函式的實現是使用GCC的內建函式__builtin_prefetch,定義如下:
/* linux-2.6.38.8/include/linux/prefetch.h */ #ifndef ARCH_HAS_PREFETCHW #define prefetchw(x) __builtin_prefetch(x,1) #endif
__builtin_prefetch的函式原型為void __builtin_prefetch (const void *addr, ...),常用於最小化資料的存取時間。引數addr的值為將要預取的記憶體地址,另外,它還有兩個可選的引數rw 和 locality,rw的值只能為常量0或者1,1用於寫的預取,預設值0用於讀的預取。關於它的詳細使用說明請參考網址http://gcc.gnu.org/onlinedocs/gcc-4.6.2/gcc/Other-Builtins.html#Other-Builtins。
對於ARMv5,prefetchw函式使用另一種實現,而S3C2410是無法支援的。另外,對於S3C2410,__LINUX_ARM_ARCH__的值為4,在linux-2.6.38.8/arch/arm/Makefile檔案中被宣告。
__alloc_skb函式的另一個重要功能就是分配資料緩衝區,包括skb_shared_info結構體。先使用SKB_DATA_ALIGN巨集以SMP_CACHE_BYTES(對於ARM體系架構,它的值為32)位對齊資料緩衝區(這裡不包括skb_shared_info結構體)的大小,然後呼叫kmalloc_node_track_caller函式分配記憶體,程式碼如下:
/* linux-2.6.38.8/net/core/skbuff.c */
size = SKB_DATA_ALIGN(size);
data = kmalloc_node_track_caller(size + sizeof(struct skb_shared_info),
gfp_mask, node);
if (!data)
goto nodata;
prefetchw(data + size);
其中兩個主要函式的實現如下:
/* linux-2.6.38.8/include/linux/skbuff.h */
#define SKB_DATA_ALIGN(X) (((X) + (SMP_CACHE_BYTES - 1)) & \
~(SMP_CACHE_BYTES - 1))
/* linux-2.6.38.8/include/linux/slab.h */
#define kmalloc_node_track_caller(size, flags, node) \
kmalloc_track_caller(size, flags)
#define kmalloc_track_caller(size, flags) \
__kmalloc(size, flags)
/* linux-2.6.38.8/mm/slab.c */
void *__kmalloc(size_t size, gfp_t flags)
{
return __do_kmalloc(size, flags, NULL);
}
最後,__alloc_skb函式會完成對sk_buff和skb_shared_info兩個結構體變數部分成員的初始化。
/* linux-2.6.38.8/net/core/skbuff.c */
memset(skb, 0, offsetof(struct sk_buff, tail));
skb->truesize = size + sizeof(struct sk_buff);
atomic_set(&skb->users, 1);
skb->head = data;
skb->data = data;
skb_reset_tail_pointer(skb);
skb->end = skb->tail + size;
#ifdef NET_SKBUFF_DATA_USES_OFFSET
skb->mac_header = ~0U;
#endif
其中,當NET_SKBUFF_DATA_USES_OFFSET未定義時,skb_reset_tail_pointer函式的定義如下:
/* linux-2.6.38.8/include/linux/skbuff.h */
static inline void skb_reset_tail_pointer(struct sk_buff *skb)
{
skb->tail = skb->data;
}
/* linux-2.6.38.8/net/core/skbuff.c */
shinfo = skb_shinfo(skb);
memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));
atomic_set(&shinfo->dataref, 1);
kmemcheck_annotate_variable(shinfo->destructor_arg);
其中,skb_shinfo函式的定義如下:
/* linux-2.6.38.8/include/linux/skbuff.h */
#define skb_shinfo(SKB) ((struct skb_shared_info *)(skb_end_pointer(SKB)))
當NET_SKBUFF_DATA_USES_OFFSET未定義時,skb_end_pointer函式的定義如下:
/* linux-2.6.38.8/include/linux/skbuff.h */
static inline unsigned char *skb_end_pointer(const struct sk_buff *skb)
{
return skb->end;
}
__alloc_skb函式完成的工作大致如下圖(圖片來自《Understanding Linux Network Internals》):
另外,當NET_SKBUFF_DATA_USES_OFFSET未定義時,sk_buff_data_t的宣告如下:
/* linux-2.6.38.8/include/linux/skbuff.h */
typedef unsigned char *sk_buff_data_t;
(2)、skb_reserve
skb_reserve函式用於在緩衝區的頭部預留一些空間,其定義如下:
/* linux-2.6.38.8/include/linux/skbuff.h */
static inline void skb_reserve(struct sk_buff *skb, int len)
{
skb->data += len;
skb->tail += len;
}
skb_reserve函式只是簡單地更新data和tail兩個指標而已,如下圖(圖片來自《Understanding LinuxNetwork Internals》):
(3)、skb_put
skb_put函式會把一個數據塊新增到緩衝區的尾端。
/* linux-2.6.38.8/net/core/skbuff.c */
unsigned char *skb_put(struct sk_buff *skb, unsigned int len)
{
unsigned char *tmp = skb_tail_pointer(skb);
SKB_LINEAR_ASSERT(skb);
skb->tail += len;
skb->len += len;
if (unlikely(skb->tail > skb->end))
skb_over_panic(skb, len, __builtin_return_address(0));
return tmp;
}
其中,skb_tail_pointer函式在NET_SKBUFF_DATA_USES_OFFSET未定義時,其定義如下:
/* linux-2.6.38.8/include/linux/skbuff.h */
static inline unsigned char *skb_tail_pointer(const struct sk_buff *skb)
{
return skb->tail;
}
對於ARM體系結構,在CONFIG_BUG和CONFIG_DEBUG_BUGVERBOSE都配置的情況下,SKB_LINEAR_ASSERT的定義如下:
/* linux-2.6.38.8/include/linux/skbuff.h */
#define SKB_LINEAR_ASSERT(skb) BUG_ON(skb_is_nonlinear(skb))
/* linux-2.6.38.8/include/asm-generic/bug.h */
#ifndef HAVE_ARCH_BUG_ON
#define BUG_ON(condition) do { if (unlikely(condition)) BUG(); } while(0)
#endif
/* linux-2.6.38.8/arch/arm/include/asm/bug.h */
extern void __bug(const char *file, int line) __attribute__((noreturn));
#define BUG() __bug(__FILE__, __LINE__) /* give file/line information */
/* linux-2.6.38.8/arch/arm/kernel/traps.c */
void __attribute__((noreturn)) __bug(const char *file, int line)
{
printk(KERN_CRIT"kernel BUG at %s:%d!\n", file, line);
*(int *)0 = 0;
/* Avoid "noreturn function does return" */
for (;;);
}
當函式skb_is_nonlinear返回非零值(也就是skb->data_len的值不為0)時,SKB_LINEAR_ASSERT將產生一個oops訊息。skb_is_nonlinear的定義如下:
/* linux-2.6.38.8/include/linux/skbuff.h */
static inline int skb_is_nonlinear(const struct sk_buff *skb)
{
return skb->data_len;
}
skb_put函式其實也沒有真的把資料新增到緩衝區中,而只是簡單地更新了skb->tail和skb->len的值,如下圖(圖片來自《Understanding Linux Network Internals》):
(4)、skb_push
skb_push函式會把一個數據塊新增到緩衝區的開端。
/* linux-2.6.38.8/net/core/skbuff.c */
unsigned char *skb_push(struct sk_buff *skb, unsigned int len)
{
skb->data -= len;
skb->len += len;
if (unlikely(skb->data<skb->head))
skb_under_panic(skb, len, __builtin_return_address(0));
return skb->data;
}
skb_push函式其實也沒有真的把資料新增到緩衝區中,而只是簡單地更新了skb->data和skb->len的值,如下圖(圖片來自《Understanding Linux Network Internals》):
(5)、skb_pull
skb_pull函式會把一個數據塊從緩衝區中的頂端刪除。
/* linux-2.6.38.8/net/core/skbuff.c */
unsigned char *skb_pull(struct sk_buff *skb, unsigned int len)
{
return skb_pull_inline(skb, len);
}
/* linux-2.6.38.8/include/linux/skbuff.h */
static inline unsigned char *skb_pull_inline(struct sk_buff *skb, unsigned int len)
{
return unlikely(len > skb->len) ? NULL : __skb_pull(skb, len);
}
static inline unsigned char *__skb_pull(struct sk_buff *skb, unsigned int len)
{
skb->len -= len;
BUG_ON(skb->len < skb->data_len);
return skb->data += len;
}
skb_pull函式其實也沒有真的把資料從緩衝區中刪除,而只是簡單地更新了skb->data和skb->len的值,如下圖(圖片來自《Understanding Linux Network Internals》):
相關推薦
網路驅動移植之sk_buff結構體及其相關操作函式(下)
2、結構體相關操作函式 (1)、dev_alloc_skb 實際上,函式dev_alloc_skb最終是呼叫__alloc_skb函式來分配資料緩衝區和sk_buff結構體的,如下圖: 從dev_alloc_skb到__alloc_skb
net_device結構體及其相關的操作函式
在Linux系統中,網路裝置都被抽象為struct net_device結構體。它是網路裝置硬體與上層協議之間聯絡的介面,瞭解它對編寫網路驅動程式非常有益,所以本文將著手簡要介紹linux-2.6.38.8/include/linux/netdevice.h檔案中struc
cdev結構體及其相關函式 【轉】
1、在Linux2.6核心中一個字元裝置用cdev結構來描述,其定義如下: struct cdev { struct kobject kobj; struct module *owner; //所屬模組 cons
Go語言基礎(九)—— Go語言結構體、Go語言切片(Slice)、range遍歷、Go語言Map(集合)
Go語言結構體 Go 語言中陣列可以儲存同一型別的資料,但在結構體中我們可以為不同項定義不同的資料型別。 結構體是由一系列具有相同型別或不同型別的資料構成的資料集合。 結構體表示一項記錄,比如儲存圖書館的書籍記錄,每本書有以下屬性: Title :標題&nbs
c語言==兩個結構體之間的相互呼叫(17)
指向結構體型別變數的使用 首先讓我們定義結構體: struct stu { char name[20]; long number; float score[4]; } ; 再定義指向結構體型別變數的指標變數: struct stu *p1, *
c語言結構體計算罰時與成績(acm)
Judging a programming contest is hard work, with demanding contestants, tedious decisions,and monotonous work. Not to mention the nutritional problems of s
《Java從小白到大牛》之第10章 面向對象基礎(下)
ket 方法重載 imp isp 配套 一次 sub 類名 類的變量 《Java從小白到大牛》紙質版已經上架了!!! 封裝性與訪問控制 Java面向對象的封裝性是通過對成員變量和方法進行訪問控制實現的,訪問控制分為4個等級:私有、默認、保護和公有,具體規則如表10-1所示。
spring之我見--Controller註冊到DispatchServlet請求處理(下)
1 DispatcherServlet請求分發 1.1 DispatcherServlet的初始化 在web.xml檔案裡,跟ContextLoaderListener形影不離的應該就是DispatcherServlet了,它一般做如下定義: <servlet>
UVM暫存器篇之二:暫存器模型概覽(下)
本文轉自:http://www.eetop.cn/blog/html/28/1561828-6266219.html 暫存器模型構建 在構建UVM暫存器模型的過程中,讀者需要了解下面這些與模型構建相關的類和它們的功能: 簡化後的MCDF暫存器模
android影象處理系列之六--給圖片新增邊框(下)-圖片疊加
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
企業架構研究總結(9)——聯邦企業架構之CIO委員會的企業架構實施指南(下)
開發基線企業架構 在開發基線企業架構這一過程中,各個企業或組織需要根據已經確定的架構目標、範圍和所採用的架構框架對當前自身的狀態進行各種製品的開發,這既包括針對核心架構製品的開發,也包括對支援性架構製品的開發,同時還包括針對其他由於特定需求而單獨定義的架構製品(
sencha touch 擴充套件篇之將sencha touch打包成安裝程式(下)- 使用phonegap打包安裝程式
這講我們來講解下如何使用phonegapa建立專案環境並通過她們將sencha touch打包成app,這裡我們只講解打包android的apk,打包ios的過程有點類似,但是需要在mac環境下,最後通過xcode匯出成ipa安裝程式; 一、phonega
學不可以已--我一年Java之路的回顧,反思以及展望(下)
說到上個暑假,還有不得不提的事就是沉迷於CSDN的論壇中。早在暑假回家之前,除了那些學習計劃,我還有一個目標就是一定要在CSDN的Java板塊變成一個紅星,因為那個時候我覺得紅星就是技術水平高的代名詞(一般初學者才有這個想法^_^),所以那個假期在CSDN回答問題可以用一個瘋狂來形容,當時基本上事每一個帖子都
View的事件體系之三 android事件分發機制詳解(下)
接著上一篇來分析事件分發機制,在看了各位大牛的關於事件分發機制的分析後茅塞頓開,之前看過好幾遍郭霖,弘揚以及玉剛大神關於事件體系的講解,一直看不懂,比較模糊,最近複習時,看到一篇博文,寫的相當精彩,看完後,再回看各位大神的博文,收穫頗豐,記錄一下自己的理解和
資料結構-棧和佇列面試題(下)
面試題四:元素出棧、入棧順序的合法性。如入棧的序列(1,2,3,4,5),出棧序列為(4,5,3,2,1)。 思路: ①首先判斷出棧入棧序列長度是否一致,不一致直接返回false; ②借用一個臨時的棧,依次遍歷入棧序列的每一個元素,每次
資料結構入門---初始二叉樹(下)
這篇文章我們準備將二叉樹實現為具體的程式碼 首先我們要從二叉樹的遍歷說起。二叉樹的遍歷主要有四種形式 1. 前序遍歷 方法:如果二叉樹為空,則直接返回。如果二叉樹非空,則訪問根結點,再前序遍歷左子樹,然後前序遍歷右子樹 我們可以知道這樣的遍歷方式是以遞迴
資料結構基礎溫故-6.查詢(下):雜湊表
雜湊(雜湊)技術既是一種儲存方法,也是一種查詢方法。然而它與線性表、樹、圖等結構不同的是,前面幾種結構,資料元素之間都存在某種邏輯關係,可以用連線圖示表示出來,而雜湊技術的記錄之間不存在什麼邏輯關係,它只與關鍵字有關聯。因此,雜湊主要是面向查詢的儲存結構。雜湊技術最適合的求解問題是查詢與給定值相等的記錄。
資料結構基礎溫故-5.圖(下):最短路徑
圖的最重要的應用之一就是在交通運輸和通訊網路中尋找最短路徑。例如在交通網路中經常會遇到這樣的問題:兩地之間是否有公路可通;在有多條公路可通的情況下,哪一條路徑是最短的等等。這就是帶權圖中求最短路徑的問題,此時路徑的長度不再是路徑上邊的數目總和,而是路徑上的邊所帶權值的和。帶權圖分為無向帶權圖和有向帶權圖,但如
袁毓林 李強:怎樣用物性結構知識解決“網球問題”?(下)
“網球問題”指怎樣把racquet(網球拍)、ball(網球)和net(球網)之類具有情境聯想關係的詞彙概念聯絡起來、發現它們之間的語義和推理關係。這是一個自然語言處理和相關的語言知識資源建設的世界性難題。該文以求解“網球問題”為目標,對目前比較主流的幾種語言詞彙和概
獻給初學iOS的小盆友們——微博app專案開發之十八搭建傳送微博介面(下)
今天應該是這個專案最後一次更新啦,能堅持下來的小盆友真是棒棒噠。這節課我們將會完成傳送有圖片的微博,實現微博最後一個核心功能。因為微博的功能實在太多太多了,我們不可能把微博的每個功能都一一實現。小夥伴能從中學到最精髓的東西才是最主要的,萬變不離其宗,得到處理問題