本来想等再从新看一遍书来整理下的,不过公司以后有个讨论会,先发上来,大家看到的提提意见呀!
开源是众多程序员们进步的一大阶梯,仅仅一个月来了解TCP/IP的实现,就越发感到自己的不足。对于整体协议的把握,任务的划分,内核与用户之间的转换,锁的设定都需要艺术的解决,甚至一个宏,一个联合都是自己以前万万想不到的。
再次从头开始阅读,带着敬意,走进大师的代码。
在BSD4.4版的TCP/IP实现,数据之间的传输的缓冲区命名为mbuf,这一结构需要完成的功能有
1. 各个层次的首部信息,并且要方便的添加。
2. 完成大容量内容的保存。传
3. 递插口信息
4. 标示分组首部等等。
同时,这一缓冲区的生成、删除、修改的层次不定,例如可以是以太网驱动调用m_devget来缓存一个帧,也可能是sendto请求缓存来将插口层将发送的内容保存。需要仔细的设计处理器的优先级。
首先看一下标准的结构:
每一个mbuf都是标准的128字节,这样对于不同用途、不同类型的mbuf都可以用统一的眼光来看待,而具体区别使用联合的结构,通过flags来解读特定位置的数据。
mbuf总共可以分成 个部分:
[1] 首部结构 m_hdr ,这是一个所有类型mbuf(由mh_flags标识) 都统一拥有的类型。
包括 指向下一个不相干的mbuf链的指针mh_nextpkt 指向属于同一分组的下一块缓存mh_next 自身数据长度 自身数据指针 mbuf的用途 mbuf的类型
[2] 分组首部结构 pkthdr ,当mbuf用于存储分组首部时,利用此结构找到特定位置存储的分组总长度与接受接口的ifnet结构
[3] 簇结构 - 簇的起始地址 一个未使用的指针 及簇的总大小
有了[2]和[3],就可以完成mbuf的主要四种类型——
纯数据内容:flags = 0 联合M_dat中的 M_databuf[MLEN]
短数据报的分组首部: M_PKTHDR 联合M_dat 中的 MH_pkthdr和联合MH_dat中的MH_databuf[MHLEN]
不含首部的大数据: M_EXT
含较多数据的分组首部: M_EXT / M_PKTHDR 联合M_dat 中的 MH_pkthdr和联合MH_dat中的MH_databuf[MHLEN]
同时对于宏定义的使用,这里有非常好的一个实例,由于把通用结构抽象出去作为一个公用的结构体,传统的使用就会变为m.m_hdr.mh_next
统一的,使用了简化技术:"我们会看到这种技术普遍应用于Net/3源代码中,只要是一个结构包含其他结构或联合这种情况"
#define m_pkthdr M_dat.MH.MH_pkthdr
......
到了令我大开眼界的地方:
MGET是一个宏,用于分配一个缓存区,如果分配失败,则调用下面这段代码——调用协议的drain函数,可能会产生新的可供分配的空间,从而再次尝试分配缓存区。
struct mbuf *
m_retry(i,t)
int i,t;
{
struct mbuf *m;
m_reclaim();
#define m_retry(i, t) (struct mbuf *)0
MGET(m, i, t);
#undef m_retry
return (m);
}
在这里,再次使用了MGET宏来申请缓冲区。防止新的展开又再次调用m_retry。将m_retry这个函数定义为空指针,调用MGET,并在下一语句恢复。