TCP IP详解卷2之mbuf宏与函数
2014-04-07 12:12
162 查看
mbuf的介绍在上一篇文章中已经介绍了.
查看介绍请移步:/article/11191063.html
mbuf全称即memory buffer,即存储器缓存,在内核中属于全局支持的范畴。这里有超过两打的宏和函数来处理mbuf。
函数:
1:m_get 函数,分配mbuf的函数,是宏MGET的展开
![](http://img.blog.csdn.net/20140407103549796?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvU2hpbmljaFI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
1.1
当插口层请求分配一个mbuf来存储sendto系统调用的目标地址时,nowait指定M_WAIT,因此会在这里阻塞,如果是请求分配一个mbuf来保存接收的帧时,nowait需指向M_DONTWAIT,便是不阻塞。
2:m_pullup函数,用来保证指定数目的字节(协议首部大小等)在链表的第一个buf中紧挨着存放。即这些字节被复制到一个新的mbuf并紧挨着存放。这里需要介绍下该函数用到的宏mtod和dtom,还有函数m_devget。
当接收到一个以太网帧时,调用m_devget来创建一个mbuf链表,并把设备中的帧复制进去,根据帧的长度会产生四种链表
![](http://img.blog.csdn.net/20140407110355390?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvU2hpbmljaFI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
图2-14的左边用于数据的长度在0-84字节之间的情况,右边的是85-100的情况
![](http://img.blog.csdn.net/20140407110408625?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvU2hpbmljaFI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
图2-15是数据在101-207字节之间的情况。这里有两个mbuf,前100字节存放在第一个mbuf中(有分组首部),剩下的在第二个。
![](http://img.blog.csdn.net/20140407110416734?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvU2hpbmljaFI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
当数据>=208字节时,就要用到cluster了。
m_pullup使用总结:
1:大多数设备驱动程序不把一个IP数据报的第一部分的分割到几个mbuf中,假设协议首部都紧挨着存放,则在每个协议(ICMP,IGMP,TCP,UDP)中调用m_pullup的可能性小,如果调用它,通常是因为数据报太小。
![](http://img.blog.csdn.net/20140407113452281?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvU2hpbmljaFI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
2::对于接收到的IP分片,当IP数据报被放在一个cluster中时,调用m'_pullup,几乎对于接受到的每一个分片都要调用,因为大多数分片的长度大于208字节。
这里因为指向IP首部的指针(即指向cluster起始的pointer)不能转换成指向mbuf的指针(因为m_data指向一个cluster时不能使用dtom,因为没有从cluster指向mbuf的指针,IP分片不能把链指针存储在cluster 中)
![](http://img.blog.csdn.net/20140407113954390?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvU2hpbmljaFI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
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宏
![](http://img.blog.csdn.net/20140407104119437?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvU2hpbmljaFI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
1.2
![](http://img.blog.csdn.net/20140407104437609?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvU2hpbmljaFI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
1.3
MGET调用的MALLOC是内核宏,它是通用存储器分配器进行的。数组mbtypes把mbuf的MT_xxx值转换成M_xxx(如图1.3)。
MBUFLOCK(mbuf锁,保护函数和宏不被中断) 做的是全局量mbstat的跟踪统计。当分配失败时,调用m_retry函数。
![](http://img.blog.csdn.net/20140407104930968?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvU2hpbmljaFI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
1.4
被m_retry调用的第一个函数是m_reclaim,这里不对该函数做细致分析,调用m_reclaim后,可能 会有更多的存储器,所以再次调用了MGET
注意这里如果不#define m_retry(i,t) (struct mbuf *)0,把m_retry定义为一个空指针,再次进入MGET后如果分配失败又会调用m_retry,就可能会出现无休止的循环。当然这个定义在MGET展开之后就取消了。
书中的介绍:
![](http://img.blog.csdn.net/20140407120438500?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvU2hpbmljaFI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
查看介绍请移步:/article/11191063.html
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展开之后就取消了。
书中的介绍:
相关文章推荐
- C系统函数库些许
- oracle 函数(一)
- Mysql数学函数不求人
- 为List添加排序的函数 处理并列排名情况(上篇)
- javaScript eval()函数用法
- 函数调用栈(Function call stack)
- C字符串处理函数的实现(Linux)
- php file_put_contents() 函数(转)
- C/C++时间函数使用方法
- C字符串处理函数
- 汇编中函数返回结构体的方法
- 关于opengl的几个函数
- bs_t结构及其相关函数的定义
- PHP基础,字符串处理函数
- 转大写函数MoneyCn
- PHP循环函数使用介绍之PHP基础入门教程
- C++中内存分配、函数调用和返回值问题
- clrscr() -- 等等辅助小函数 未完
- 技术中的小函数之道
- c++实现字符串复制函数strcpy()