《TCP/IP详解 卷2:实现》 —2.6 m_devget和m_pullup函数
2.6 m_devget和m_pullup函数
我们在讨论IP、ICMP、IGMP、UDP和TCP的代码时会遇到函数m_pullup。它用来保证指定数目的字节(相应协议首部的大小)在链表的第一个mbuf中紧挨着存放,即这些指定数目的字节被复制到一个新的mbuf并紧接着存放。为了理解m_pullup的用法,必须查看它的实现及相关的函数m_devget和宏mtod与dtom。在分析这些问题的同时我们还可以再次领会Net/3中mbuf的用法。
2.6.1 m_devget函数
当接收到一个以太网帧时,设备驱动程序调用函数m_devget来创建一个mbuf链表,并把设备中的帧复制到这个链表中。根据所接收的帧的长度(不包括以太网首部),可能导致4种不同的mbuf链表。图2-14所示的是前两种。
图2-14 m_devget创建的前两种类型的mbuf
1) 图2-14左边的mbuf用于数据的长度在0~84字节之间的情况。在这个图中,我们假定有52字节的数据:一个20字节的IP首部和一个32字节的TCP首部(标准的20字节的TCP首部加上12字节的TCP选项),但不包括TCP数据。既然m_devget返回的mbuf数据从IP首部开始,m_len的实际最小值是28:20字节的IP首部,8字节的UDP首部和一个0长度的UDP数据报。
m_devget在这个mbuf的开始保留了16字节未用。虽然14字节的以太网首部不存放在这里,但还是分配了一个14字节的用于输出的以太网首部,这是同一个mbuf,用于输出。我们会遇到函数icmp_reflect和tcp_respond,它们通过把接收到的mbuf作为输出mbuf来产生一个应答。在这两种情况中,接收的数据报应该少于84字节,因此很容易在前面保留16字节的空间,这样在建立输出数据报时可以节省时间。分配16字节而不是14字节是为了在mbuf中用长字对准方式存储IP首部。
2) 如果数据在85~100字节之间,就仍然存放在一个分组首部mbuf中,但在开始没有16字节的空间。数据存储在数组m_pktdat的开始,并且任何未用的空间放在这个数组的后面。例如在图2-14右边的mbuf显示的就是这个例子,假设有85字节数据。
3) 图2-15所示的是m_devget创建的第3种mbuf。当数据在101~207字节之间时,要求有两个mbuf。前100字节存放在第一个mbuf中(有分组首部的mbuf),而剩下的存放在第二个mbuf中。在此例中,我们显示的是一个104字节的数据报。在第一个mbuf的开始没有保留16字节的空间。
图2-15 m_devget创建的第3种mbuf
4) 图2-16所示的是m_devget创建的第4种mbuf。如果数据超过或等于208 字节(MINCLBYTES),要用一个或多个簇。图中的例子假设了一个1500字节的以太网帧。如果使用1024字节的簇,本例子需要两个mbuf,每个mbuf都有标志M_EXT,以及指向一个簇的指针。
- 点赞
- 收藏
- 关注作者
评论(0)