您的位置:首页 > 理论基础 > 计算机网络

《TCP-IP详解 卷2:实现》学习笔记—mbuf的深入解析

2013-11-26 18:55 916 查看
1、下面将要经常会的遇到的四种不同类型的mbuf,它们依据在成员mh_flags中填写的不同标志M_PKTHDR和M_EXT而不同。
mbuf的固定大小是128字节
1)  第一类mbuf的mh_flags等于0,mbuf只包含数据,在mbuf中有108字节的数据空间,指针mh_data指向这108字节缓存中的某个位置。
2)  第二类mbuf的mh_flags值是M_PKTHDR,它指示这是一个分组首部,描述一个分组数据的第一个mbuf。数据仍然保存在这个mbuf中,但是由于分组首部占用了8字节,只有100字节的数据可存储在这个mbuf中。
3)  当分组数据超过208字节的数据时,如果采用前面提到的1/2类mbuf,需要3个或更多的mbuf,这时我们就要使用一种称之为簇的mbuf,就是我们下面讲到的mbuf。第3类m
b u f不包含分组首部(没有设置M_PKTHDR),但包含超过208字节的数据,这时用到一个叫“簇”的外部缓存(设置M_EXT)。在此mbuf中仍然为分组首部结构分配了空间,但没有用。在这个mbuf中,指针mh_data指向这个簇中的某个位置。
4)  第四类mbuf包含一个分组首部,包含超过208字节的数据,同时设置了标志M_PKTHDR和M_EXT
2、Mbstat是一个全局变量

下面是全局结构mbstat中维护的各种统计

struct mbstat {
u_long	m_mbufs;	/* mbufs obtained from page pool */ 从页池(未用)中获得mbuf数
u_long	m_clusters;	/* clusters obtained from page pool */从页池中获得簇
u_long	m_spare;	/* spare field */剩余空间(未用)
u_long	m_clfree;	/* free clusters */自由簇
u_long	m_drops;	/* times failed to find space */寻找空间(未用)失败的次数
u_long	m_wait;		/* times waited for space */等待空间(未用)的次数
u_long	m_drain;	/* times drained protocols for space */调用协议的drain函数来回收空
/间的次数
u_short	m_mtypes[256];	/* type specific mbuf allocations */当前mbuf的分配数:
/MT_XXX索引
};


 

3、获取一个mbuf

MGET宏。例如调用MGET来分配系统sendto系统调用的目标地址的mbuf如下所示:

MGET(m, M_WAIT, MT_SONAME);
If ( m == NULL)
Return (ENOBUFS);


MGET函数的原型如下:MBUFLOCK来保护函数和宏不被中断 
#define	MGET(m, how, type) {
MALLOC((m), struct mbuf *, MSIZE, mbtypes[type], (how));
if (m) {
(m)->m_type = (type);
MBUFLOCK(mbstat.m_mtypes[type]++;)
(m)->m_next = (struct mbuf *)NULL;
(m)->m_nextpkt = (struct mbuf *)NULL;
(m)->m_data = (m)->m_dat;
(m)->m_flags = 0;
} else
(m) = m_retry((how), (type));
}


MBUFLOCK用于跟踪统计每种mbuf类型的内核结构加1(mbstat)。当执行这句时,宏MBUFLOCK把它作为参数来改变处理器优先级,然后把优先级恢复为原值。这防止在执行语句mbstat.m_mtypes[type]++时被网络设备中断,因为mbuf可能在内核中的各层中被分配。考虑这样一个系统,它用三步来实现一个c中的++运算:(1)把当前值装入到一个寄存器;(2)寄存器加1;(3)把寄存器值存入到存储器。假设计数器值为77并且MGET在插口层执行。假设执行了步骤1和2(寄存器值为78),并且一个设备中断发生。若设备驱动也执行MGET来获得同种类型的mbuf,在存储器中取值(77),加1(78),并存回在存储器。当被中断执行的MGET的步骤3继续执行时,它将寄存器的值(78)存入存储器。但是计数器应为79,而不是78,这样计数器就被破坏了。
4、分配一个mbuf
struct mbuf *
m_get(nowait, type)
int nowait, type;
{
register struct mbuf *m;

MGET(m, nowait, type);
return (m);
}


这个调用表明参数nowait的值为M_WAIT或M_DONTWAIT,它取决于在存储器不可用时是否需要等待。例如,当插口层请求分配一个mbuf来存储sendto系统调用的目标地址时,它指定M_WAIT,因为在此阻塞是没有问题的。但是当以太网设备驱动程序请求分配一个mbuf来存储一个接收的帧时,它指定M_DONTWAIT,因为它是作为一个设备中断处理来执行的,不能进入睡眠状态来等待一个mbuf。在这种情况下,若存储器不可用,设备驱动程序丢弃这个帧比较好。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息