TCP IP詳解卷2之mbuf宏與函數

mbuf的介紹在上一篇文章中已經介紹了.

查看介紹請移步:http://blog.csdn.net/shinichr/article/details/23044999

mbuf全稱即memory buffer,即存儲器緩存,在內核中屬於全局支持的範疇。這裏有超過兩打的宏和函數來處理mbuf。

函數:

1:m_get 函數,分配mbuf的函數,是宏MGET的展開

1.1

插口層請求分配一個mbuf來存儲sendto系統調用的目標地址時,nowait指定M_WAIT,因此會在這裏阻塞,如果是請求分配一個mbuf來保存接收的幀時,nowait需指向M_DONTWAIT,便是不阻塞。


2:m_pullup函數,用來保證指定數目的字節(協議首部大小等)在鏈表的第一個buf中緊挨着存放。即這些字節被複制到一個新的mbuf並緊挨着存放。這裏需要介紹下該函數用到的宏mtod和dtom,還有函數m_devget。

當接收到一個以太網幀時,調用m_devget來創建一個mbuf鏈表,並把設備中的幀複製進去,根據幀的長度會產生四種鏈表

2-14的左邊用於數據的長度在0-84字節之間的情況,右邊的是85-100的情況


圖2-15是數據在101-207字節之間的情況。這裏有兩個mbuf,前100字節存放在第一個mbuf中(有分組首部),剩下的在第二個。

數據>=208字節時,就要用到cluster了。

m_pullup使用總結:

1:大多數設備驅動程序不把一個IP數據報的第一部分的分割到幾個mbuf中,假設協議首部都緊挨着存放,則在每個協議(ICMP,IGMP,TCP,UDP)中調用m_pullup的可能性小,如果調用它,通常是因爲數據報太小。


      2::對於接收到的IP分片,當IP數據報被放在一個cluster中時,調用m'_pullup,幾乎對於接受到的每一個分片都要調用,因爲大多數分片的長度大於208字節。

這裏因爲指向IP首部的指針(即指向cluster起始的pointer)不能轉換成指向mbuf的指針(因爲m_data指向一個cluster時不能使用dtom,因爲沒有從cluster指向mbuf的指針,IP分片不能把鏈指針存儲在cluster 中)

3:只要TCP報文段不被IP分片,接收到一個報文段,不論是否失序,都不需要調用m_pullup

3:宏mtod和dtom。

#define mtod(m,t)    ((t)((m)->m_data))

#define dtom(x)   ((struct mbuf *)((int)(x) & ~(MSIZE-1)))

mtod返回指向一個mbuf數據的指針,並把指針聲明爲指定類型

dtom取得一個存放在mbuf任意位置的數據的指針,並返回這個mbuf結構本身的一個指針。這裏MSIZE是128(10000000),dtom僅僅是爲了清除參數中指針的低位來獲取mbuf的起始位置。


m_copy函數:

cluster的好處就是當有大量數據時可以減少mbuf,還有就是可以多個mbuf共享一個cluster,共享的cluster避免了內核將數據從一個mbuf複製到另一個mbuf中,這裏用到了引用計數,當另一個buf指向這個cluster時,相應的計數+1,當最後計數變成0時,才清除它。


宏:

1:MGET宏

                1.2

1.3

MGET調用的MALLOC是內核宏,它是通用存儲器分配器進行的。數組mbtypes把mbuf的MT_xxx值轉換成M_xxx(如圖1.3)。

MBUFLOCK(mbuf鎖,保護函數和宏不被中斷) 做的是全局量mbstat的跟蹤統計。當分配失敗時,調用m_retry函數。


1.4

m_retry調用的第一個函數是m_reclaim,這裏不對該函數做細緻分析,調用m_reclaim後,可能 會有更多的存儲器,所以再次調用了MGET

注意這裏如果不#define m_retry(i,t) (struct mbuf *)0,把m_retry定義爲一個空指針,再次進入MGET後如果分配失敗又會調用m_retry,就可能會出現無休止的循環。當然這個定義在MGET展開之後就取消了。


書中的介紹:



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章