《TCP/IP详解:实现》: mbuf 详解一

一、mbuf 介绍

在BSD TCP/IP协议栈代码设计中的一个基本概念就是存储器缓存,称作一个mbuf全称为"memory buffer",用于存储各种信息。mbuf的主要用途是保存在进程和网络接口间互相传递的用户数据。但mbuf也用于保存其他各种数据:源与目标地址、插口选项等等。mbuf相当于Linux内核中的skb。

mbuf的相关定义在文件/4.4BSD-Lite/usr/src/sys/sys/Mbuf.h

二、mbuf 结构体


/*每个mbuf的大小*/
#define	MSIZE		128	
/*一个mbuf簇(外部缓存)的大小*/
#define	MCLBYTES	2048
/*128-20=108,正常mbuf中的最大数据量*/
#define	MLEN		(MSIZE - sizeof(struct m_hdr))	/* normal data len */  
/*108-8=100,带分组首部的mbuf的最大数据量*/
#define	MHLEN		(MLEN - sizeof(struct pkthdr))	/* data len w/pkthdr */ 
/*208,存储到簇中的最小数据量*/
#define	MINCLSIZE	(MHLEN + MLEN)

/* mbuf的头部信息 */
这个结构用来描述mbuf跟具体的内容无关
struct m_hdr {
       struct  mbuf *mh_next;        /* 指向链中下一个mbuf的指针 */
       struct  mbuf *mh_nextpkt;     /* 指向下一个链的指针 */
       int     mh_len;               /* mbuf中数据的长度(不包括头部) */
       char    *mh_data;             /* 指向数据区的指针 */
       short   mh_type;              /* mbuf的数据类型,如MT_DATA*/
       short   mh_flags;             /* mbuf标识,具体定义见下 */
};


/ *记录/包头在链的第一个mbuf中; M_PKTHDR设置有效* / 
struct pkthdr {
       int      len;                 /* 整个mbuf链表包含数据的总长度,在链表的第一个mbuf中维
                                     护一个带有总长度的分组首部的原因是,当需要总长度时可以避
                                     免查看所有mbuf中的mh_len来求和*/
       struct   ifnet *rcvif;        /* 指向接收分组的接收接口结构的指针*/
};


/ *描述外部存储映射到mbuf,M_EXT设置有效* /
struct m_ext {
	caddr_t	ext_buf;		/* 缓冲区的开始 */
	void	(*ext_free)();		/* free routine if not the usual */
	u_int	ext_size;		/* 缓冲区大小,对于ext_free */
};


这个就是mbuf的描述,设计的比较巧妙
struct mbuf {
       struct       m_hdr m_hdr;
       union {
              struct {
                     struct       pkthdr MH_pkthdr;    /* M_PKTHDR set */
                     union {
                            struct     m_ext MH_ext;   /* M_EXT set */
                            char       MH_databuf[MHLEN];
                     } MH_dat;
              } MH;
              char       M_databuf[MLEN];              /* !M_PKTHDR, !M_EXT */
       } M_dat;
};

// 为了便于访问,这里定义了很多宏
#define	m_next		m_hdr.mh_next
#define	m_len		m_hdr.mh_len
#define	m_data		m_hdr.mh_data
#define	m_type		m_hdr.mh_type
#define	m_flags		m_hdr.mh_flags
#define	m_nextpkt	m_hdr.mh_nextpkt
#define	m_act		m_nextpkt
#define	m_pkthdr	M_dat.MH.MH_pkthdr
#define	m_ext		M_dat.MH.MH_dat.MH_ext
#define	m_pktdat	M_dat.MH.MH_dat.MH_databuf
#define	m_dat		M_dat.M_databuf

mbuf的总长为128个字节,前20个字节是首部struct m_hdr),mbuf可以用成员mh_next和mh_nextpkt链接起来。(m_next指向链中下一个mbuf,而m_nextpkt指向下一个链)

        +-----------+        +-----------+        +-----------+
        | m_next    |------->| m_next    |------->| m_next    |-------> ...
        +-----------+        +-----------+        +-----------+
    ----| m_nextpkt |        |   ...     |        |   ...     |
    |   +-----------+        |           |        |           |
    |   |   ...     |        |           |        |           |
    |   +-----------+        +-----------+        +-----------+
    |
    |   +-----------+        +-----------+
    |-->| m_next    |------->| m_next    |-------> ...
        +-----------+        +-----------+
    --- | m_nextpkt |        |   ...     |
    |   +-----------+        |           |
    |   |   ...     |        |           |
    |   +-----------+        +-----------+
    |
    |--> ...

三、mbuf 四种类型

可以看到mbuf大体由两部分组成,m_hdr和M_dat。

M_dat是个联合体,使用其中哪个成员是由m_hdr.mh_flags来决定的。

1.如果mh_flags里没有M_EXT与M_PKTHDR,则此mbuf完全是用来存放数据的。总共可以存放MLEN(108)字节的数据

2.如果mh_flags里有M_EXT则此mbuf使用外部簇(外部存储空间(cluster))来存放数据

3.如果mh_flags里有M_PKTHDR,则此mbuf是一个记录的起始mbuf(某个packet的一串mbuf中的第一个),由于MH_pkthdr占用了部分空间,总共只能存放MHLEN(100)字节的数据;

4.如果mh_flags里既有M_PKTHDR又有M_EXT(注意: 一个mbuf可以同时设置上述两个标志)则此mbuf是起始mbuf,但是使用外部簇来存放数据。

/* mbuf mh_flags*/

#define       M_EXT        0x0001    /* 一个mbuf的大小是128字节,是一个相对比较小的缓存。如果数
                                        据比较多,就需要多个mbuf连起来或者用一个叫簇的东西来存储
                                        数据。M_EXT就是这个标志 */

#define       M_PKTHDR     0x0002    /* 表明分组的第一个mbuf,在数据区中有pkthdr */
#define       M_EOR        0x0004    /* 表明记录的尾部,TCP是一个字节流,不设置这个标志 */

m_hdr.mh_type 介绍

/* mbuf types */
#define	MT_FREE		0	/* should be on free list */
#define	MT_DATA		1	/* dynamic (data) allocation */ 数据就是这个类型
#define	MT_HEADER	2	/* packet header */
#define	MT_SOCKET	3	/* socket structure */
#define	MT_PCB		4	/* protocol control block */
#define	MT_RTABLE	5	/* routing tables */
#define	MT_HTABLE	6	/* IMP host tables */
#define	MT_ATABLE	7	/* address resolution tables */
#define	MT_SONAME	8	/* socket name */
#define	MT_SOOPTS	10	/* socket options */
#define	MT_FTABLE	11	/* fragment reassembly header */
#define	MT_RIGHTS	12	/* access rights */
#define	MT_IFADDR	13	/* interface address */
#define MT_CONTROL	14	/* extra-data protocol message */
#define MT_OOBDATA	15	/* expedited data  */

当mh_flags设置为M_PKTHDR时,一般与下面的类型进行或操作 如 mh_flags |= M_MCAST

/* mbuf pkthdr flags, also in m_flags */

#define M_BCAST 0x0100 /* send/received as link-level broadcast */

#define M_MCAST 0x0200 /* send/received as link-level multicast */

/* flags copied when copying m_pkthdr */
这个具体干嘛用的不懂。。。
#define	M_COPYFLAGS	(M_PKTHDR|M_EOR|M_BCAST|M_MCAST)

判断类型

(m_flags & M_PKTHDR) == 1

(m_flags & M_EXT) == 1

mbuf大小固定的理由:

1. 可以最大限度地避免内存碎片的产生

2. 可在不重新分配和拷贝的前提下完成协议对数据区的操作。

3. 如果mbuf不是固定长度,dtom()函数的开销将会非常大。

4. mbuf中的pakcet头中的tags用于携带一些关于packet的但又不能放在packet内部的信息。

四、以图说明mbuf 四种类型

把图中分为四个部分:从左到右依次叫 图-1,图-2,图-3,图-4

1.  m_flags的值为0图-1 表示此mbuf只包含数据。在mbuf中有108字节的数据空间(m_dat数组,详情见mbuf结构定义),指针m_data指向这108字节缓存中的某个位置。图中m_data指向缓存数据的起始位置,但它可以指向缓存中的任意位置。m_len指示了从m_data开始的数据字节数。

2.  m_flags的值为M_PKTHDR图-2 M_PKTHDR表示此mbuf是一个分组首部,而且是一个分组数据的第一个mbuf。数据仍然保存在这个mbuf中,但是由于分组首部占用8个字节,所以只有100字节的数据可以存储在这个mbuf中(m_pktdat数组,详情见mbuf结构定义)。

m_pkthdr.len的值是这个分组的mbuf链中所有数据的总长度即所有通过m_next指针链接的mbuf的m_len值的和。输出分组的m_pkthdr.rcvif为空,但是对于输入分组,m_pkthdr.rcvif是一个指向接收接口的ifnet结构的指针。

3.  m_flags的值为M_EXT图-3 这种mbuf没有分组首部(没有设置M_PKTHDR),但是包含超过208字节的数据(MINCLSIZE),此时用到一个叫“簇”的外部缓存(设置M_EXT)。此mbuf中仍然为分组首部分配了空间,但是没用图-3 中用阴影表示出来。

一般来说,我们希望这种类型的mbuf的m_len的值最小为209,即至少存储的数据大小为209字节(而不应该是图-3 中的208,图中有误)。208字节数据可以存放到两个mbuf中,第一个存放100字节,第二个存放108字节。

4. m_flags的值为M_PKTHDR|M_EXT图-4 此类mbuf包含一个分组首部,并且数据超过208字节。

关于mbuf的几点说明:

1. mbuf结构的大小总是128字节。这意味着图-3、图-4两个mbuf在结构m_ext后面的未用空间为88字节(128-20-8-12)。

2. 既然有些协议(例如UDP)允许零长记录,当然就可以有m_len为0的缓存。

3. 在每个mbuf中的成员m_data指向相应缓存数据的开始(mbuf本身或者一个簇)。这个指针能指向相应缓存的任意位置,不一定是开始。

4. 带有簇的mbuf总是包含缓存的起始地址(m_ext.ext_buf)以及缓存大小(m_ext.ext_size)。注意m_data和m_ext.ext_buf的不同含义,m_data是指向缓存数据的起始地址,m_ext.ext_buf是指向缓存(簇)的起始地址,只有当m_data也只指向缓存(簇)的第一个字节时,两者的值是一样的。

5. 指针m_next是把多个mbuf链接在一起,把一个分组形成一条mbuf链表。指针m_nextpkt把多个分组链接成一个mbuf队列。在队列中的每个分组可以是一个单独的mbuf,也可以是一个mbuf链表。每个分组的第一个mbuf包含一个分组首部。如果分组是一个mbuf链表,只有第一个mbuf的m_nextpktp被使用,其它mbuf的m_nextpkt为空指针。

上图是包含两个分组的mbuf队列,第一个分组UDP数据报已经放到接口输出队列中(14字节的以太网商务部已经添加到链表中第一个mbuf的IP首部前面);第二个分组TCP报文段(1460字节数据)也被添加到队列中,TCP数据包含在一个簇中,并且第一个mbuf中包含了以太网、IP与TCP首部,在这个簇中可以看到指向簇中缓存数据的指针m_data并没有指向簇的起始位置(注意理解)。

上图所示的是m_flags的五个独立的值。M_EXT和M_PKTHDR前文已经介绍过,如果数据流有记录边界,那么对于记录尾的mbuf其m_flags应该设置M_EOR,TCP从来不需要设置,因为它提供的是无记录边界的字节流服务。OSI和XNS运输层要使用到这个标志。M_BCAST和M_MCAST主要用于链接层广播或者多播数据的接收和发送。

m_type指示存储在mbuf中的数据类型。mbuf除了可以存放要发送或者接收的用户数据,还可以存储各种不同类型的数据结构,具体如上图所示。

  • 8
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
第1章概述 1.1引言 1.2源代码表示 1.2.1将拥塞窗口设置为 1.2.2印刷约定 1.3历史 1.4应用编程接口 1.5程序示例 1.6系统调用和库函数 1.7网络实现概述 1.8描述符 1.9mbuf与输出处理 1.9.1包含插口地址结构的mbuf 1.9.2包含数据的mbuf 1.9.3添力口IP和UDP首部 1.9.4IP输出 1.9.5以太网输出 1.9.6UDP输出小结 1.10输入处理 1.10.1以太网输入 1.10.2IP输入 1.10.3UDP输入 1.10.4进程输入 1.11网络实现概述(续) 1.12中断级别与并发 1.13源代码组织 1.14测试网络 1.15小结 第2章mbuf:存储器缓存 2.1引言 2.2代码介绍 2.2.1全局变量 2.2.2统计 2.2.3内核统计 2.3mbuf的定义 2.4mbuf结构 2.5简单的mbuf宏和函数 2.5.1m_get函数 2.5.2MGET宏 2.5.3m_retry函数 2.5.4mbuf锁 2.6m_devget和m_pullup函数 2.6.1m_devget函数 2.6.2mtod和dtom宏 2.6.3m_pullup函数和连续的协议首部 2.6.4m_pullup和IP的分片与重组 2.6.5TCP重组避免调用m_pullup 2.6.6m_pullup使用总结 2.7mbuf宏和函数的小结 2.8Net/3联网数据结构小结 2.9m_copy和簇引用计数 2.10其他选择 2.11小结 第3章接口层 3.1引言 3.2代码介绍 3.2.1全局变量 3.2.2SNMP变量 3.3ifnet结构 3.4ifaddr结构 3.5sockaddr结构 3.6ifnet与ifaddr的专用化 3.7网络初始化概述 3.8以太网初始化 3.9SLIP初始化 3.10环回初始化 …… 第4章接口:以太网 第5章接口:SLIP和环回 第6章IP编址 第7章域和协议 第8章IP:网际协议 第9章IP选项处理 第10章IP的分片与重装 第11章ICMP:Internet控制报文协议 第12章IP多播 第13章ICMP:Internet组管理协议 第14章IP多播选路 第15章插口层 第16章插口I/O 第17章插口选项 第18章Radix树路由表 第19章选路请求和选路消息 第20章选路插口书摘插图第1章概述
编辑推荐 “我在全国各地教授Cisc0联网课程.每本新的有名的数据通信的书我都听说了,因为我的学生们拿它们作为课程的参考书。Stevens的《TCP/IP详解卷1 协议》的到来如同一枚炸弹的爆炸……学生们被这本书所倾倒。我刚读完《TCP/IP详解卷2:实现》。如果说卷1像一枚炸弹,则卷2就是一枚重磅炸弹!” “在读完Stevens的《TCP/IP详解卷1协议》后,我认为很难再有另一本如此有用的书了,但卷2就是这样一本书。有些人可能会问,如果你不是一个专职的网络程序员,如何让这本书适合于你。因为在我最初使用UNIX的日子里,回答‘这到底是如何工作的?’的标准答案是‘看源代 码’。用这本书,你不仅能看源代码,还有一个最清晰的解释:它们是如何互相配合起来的。” 《TCP/IP详解》系列覆盖了TCP/IP的许多方面.提供了一个高效直观的方法来学习联网协议族。 《TCP/IP详解卷2:实现》详尽地说明了TCP/IP协议是如何实现的。目前还没有更多的 书——此卷是唯一一本书,本书全面讲解了来源于44BSD—Lite版本的事实上的标准实现.这个 实现是运行在世界上成千上万个系统上的TCP/IP实现的基础。 500个示例总共15000行代码都是真正正在使用的代码,《TCP/IP详解卷2:实现》使用一种举例说明的方法来帮助你精通TCP/IP实现。你会掌握以下问题:插口API和协议族之间的关系,一个主机实现和一个路由器实现之间的区别等。另外本书覆盖了4.4BSD—Lite版本的最新特性,包括多播,长肥管道支持、窗口缩放、时间戳选项、防止序列号环绕及很多其他主题。 本书覆盖范围广,它基于一个当前正使用的标准,并且有详尽的示例,因此它是任何使用TCP/IP的人员一个不可缺少的资源。 内容简介 本书完整而详细地介绍了TCP/IP协议是如何实现的。书中给出了约500个图例,15000行实际操作的C代码,采用举例教学的方法帮助你掌握TCP/IP实现。本书不仅说明了插口API和协议族的关系以及主机实现与路由器实现的差别。还介绍了4.4BSD-Lite版的新的特点。本书适用于希望理解TCP/IP协议如何实现的人,包括编写网络应用程序的程序员以及利用TCP/IP维护计算机网络的系统管理员。 作者简介 Gary R.Wright 研究TCP/IP多年。他是Connix公司的董事长,这个公司的基地在康涅狄格州,它提供Internet接入和咨询服务。 W.Richard Stevens(1951-1999)是一位非常受人尊敬的专家,除了《TCP/IP详解》三卷本外,他还有其他两部最为畅销的作品;《UNIX环境高级编程》和《UNIX网络编程》(两卷本)。 目录 译者序 前言 第1章 概述  1.1 引言 1.2 源代码表示  1.2.1 将拥塞窗口设置为  1.2.2 印刷约定 1.3 历史 1.4 应用编程接口 1.5 程序示例 1.6 系统调用和库函数 1.7 网络实现概述 1.8 描述符 1.9 mbuf与输出处理 1.9.1 包含插口地址结构的mbuf 1.9.2 包含数据的mbuf 1.9.3 添力口IP和UDP首部 1.9.4 IP输出 1.9.5 以太网输出 1.9.6 UDP输出小结 1.10 输入处理 1.10.1 以太网输入 1.10.2 IP输入 1.10.3 UDP输入 1.10.4 进程输入 1.11 网络实现概述(续) 1.12 中断级别与并发 1.13 源代码组织 1.14 测试网络 1.15 小结 第2章 mbuf:存储器缓存 2.1 引言 2.2 代码介绍 2.2.1 全局变量  2.2.2 统计  2.2.3 内核统计  2.3 mbuf的定义  2.4 mbuf结构  2.5 简单的mbuf宏和函数  2.5.1 m_get函数  2.5.2 MGET宏  2.5.3 m_retry函数  2.5.4 mbuf锁  2.6 m_devget和m_pullup函数  2.6.1 m_devget函数  2.6.2 mtod和dtom宏  2.6.3 m_pullup函数和连续的协议首部  2.6.4 m_pullup和IP的分片与重组  2.6.5 TCP重组避免调用m_pul lup  2.6.6 m_pullup使用总结  2.7 mbuf宏和函数的小结  2.8 Net/3联网数据结构小结  2.9 m_copy和簇引用计数  2.10 其他选择  2.11 小结 第3章 接口层 3.1 引言 3.2 代码介绍  3.2.1 全局变量   3.2.2 SNMP变量 3.3 ifnet结构 3.4 ifaddr结构 3.5 sockaddr结构 3.6 ifnet与ifaddr的专用化 3.7 网络初始化概述 3.8 以太网初始化 3.9 SLIP初始化 3.10 环回初始化  …… 第4章 接口:以太网 第5章 接口:SLIP和环回 第6章 IP编址 第7章 域和协议 第8章 IP:网际协议 第9章 IP选项处理 第10章 IP的分片与重装 第11章 ICMP:Internet控制报文协议 第12章 IP多播 第13章 ICMP:Internet组管理协议 第14章 IP多播选路 第15章 插口层 第16章 插口I/O 第17章 插口选项 第18章 Radix树路由表 第19章 选路请求和选路消息 第20章 选路插口 书摘插图 第1章 概述  1.1 引言   本章介绍伯克利(Berkeley)联网程序代码。开始我们先看一段源代码并介绍一些通篇要用的印刷约定。对各种不同代码版本的简单历史回顾让我们可以看到本书中的源代码处于什么位置。接下来介绍了两种主要的编程接口,它们在Unix与非Unix系统中用于编写TCP/IP协议。   然后我们介绍一个简单的用户程序,它发送一个UDP数据报给一个位于另一主机上的日期,时间服务器,服务器返回一个UDP数据报,其中包含服务器上日期和时间的ASCIl码字符串。这个进程发送的数据报经过所有的协议栈到达设备驱动器,来自服务器的应答从下向上经过所有协议栈到达这个进程。通过这个例子的这些细节介绍了很多核心数据结构和概念,这些数据结构和概念在后面的章节中还要详细说明。 本章的最后介绍了在本书中各源代码的组织,并显示了联网代码在整个组织中的位置。  1.2 源代码表示   1.2.1 将拥塞窗口设置为1   这是文件tcp—subr.c中的函数tcp—quench。这些源文件名引用4.4BSD-Lite发布的文件。4.4BSD在1.13节中讨论。每个非空白行都有编号。正文所描述的代码的起始和结束位置的行号记于行开始处,如本段所示。有时在段前有一个简短的描述性题头,对所描述的代码提供一个概述。   这些源代码同4.4BSD—Lite发行版一样,偶尔也包含一些错误,在遇到时我们会提出来并加以讨论,偶尔还包括一些原作者的编者评论。这些代码已通过了GNU缩进程序的运行,使它们从版面上看起来具有一致性。制表符的位置被设置成4个栏的界线使得这些行在一个页面中显示得很合适。在定义常量时,有些#ifdef语句和它们的对应语句#endif被删去(如:GATEWAY和MROUTING,因为我们假设系统被作为一个路由器或多播路由器)。   ……
TCP/IP详解·卷2:实现》完整而详细地介绍了TCP/IP协议是如何实现的。书中给出了约500个图例,15000行实际操作的C代码,采用举例教学的方法帮助你掌握TCP/IP实现。《TCP/IP详解·卷2:实现》不仅说明了插口API和协议族的关系以及主机实现与路由器实现的差别。还介绍了4.4BSD-Lite版的新的特点。《TCP/IP详解·卷2:实现》适用于希望理解TCP/IP协议如何实现的人,包括编写网络应用程序的程序员以及利用TCP/IP维护计算机网络的系统管理员。 目录 · · · · · · 第一章 概述 1.1 引言 1.2 源代码表示 1.3 历史 1.4 应用编程接口 1.5 程序示例 1.6 系统调用和库函数 1.7 描述符 1.8 网络实现概述 1.9 mbuf与输出处理 1.10 输入处理 1.11 网络实现概述 1.12 中断级别与并发 1.13 源代码组织 1.14 测试网络 1.15 小结 第二章 mduf:存储器缓存 2.1 引言 2.2 代码介绍 2.3 mduf的定义 2.4 mduf结构 2.5 简单的mduf宏和函数 2.6 m_devget和m_pullup函数 2.7 mduf宏和函数的小结 2.8 Net/3联网数据结构小结 2.9 m_copy和簇引用记数 2.10 其他选择 2.11 小结 第三章 接口层 3.1 引言 3.2 代码介绍 3.3 ifnet结构 3.4 ifaddr结构 3.5 sockaddr结构 3.6 ifnet与ifaddr的专用化 3.7 网络初始化概述 3.8 以太网初始化 3.9 SLIP初始化 3.10 环回初始化 3.11 if_attach函数 3.12 ifinit函数 3.13 小结 第四章 接口:以太网 4.1 引言 4.2 代码介绍 4.3 以太网接口 4.4 ioctl系统调用 4.5 小结 第五章 接口:SLIP和环回 5.1 引言 5.2 代码介绍 5.3 SLIP接口 5.4 环回接口 5.5 小结 第六章 IP编址 6.1 引言 6.2 代码介绍 6.3 接口和地址小结 6.4 sockaddr_in结构 6.5 in_ifaddr结构 6.6 地址指派 6.7 接口ioctl处理 6.8 internet实用函数 6.9 ifnet实用函数 6.10 小结 第七章 域和协议 7.1 引言 7.2 代码介绍 7.3 domain结构 7.4 protosw结构 7.5 IP的domain和protosw结构 7.6 pffindproto和pffindtype函数 7.7 pfctlinput函数 7.8 IP初始化 7.9 sysctl系统调用 7.10 小结 第八章 IP:网际协议 8.1 引言 8.2 代码介绍 8.3 IP分组 8.4 输入处理:ipintr函数 8.5 转发:ip_forward函数 8.6 输出处理:ip_output函数 8.7 Internet检验和:in_cksum函数 8.8 setsockopt和getsockopt系统调用 8.9 ip_sysctl函数 8.10 小结 第九章 IP选项处理 9.1 引言 9.2 代码介绍 9.3 选项格式 9.4 ip_dooptions函数 9.5 记录路由选项 9.6 源站和记录路由选项 9.7 时间戳选项 9.8 ip_insertoptions函数 9.9 ip_pcbopts函数 9.10 一些限制 9.11 小结 第十章 IP的分片与重装 10.1 引言 10.2 代码介绍 10.3 分片 10.4 ip_optcopy函数 10.5 重装 10.6 ip_optcopy函数 10.7 ip_slowtimo函数 10.8 小结 第十一章 ICMP:Internet控制报文协议 第十二章 IP多播 第十三章 IGMP:Internet组管理协议 第十四章 IP多播选路 第十五章 插口层 第十六章 插口I/O 第十七章 插口选项 第十八章 Radix树路由表 第十九章 选路请求和选路消息 第二十章 选路接口 第二十一章 ARP:地址解析协议 第二十二章 协议控制块 第二十三章 UDP:用户数据报协议 第二十四章 TCP:传输控制协议 第二十五章 TCP的定时器 第二十六章 TCP输出 第二十七章 TCP的函数 第二十八章 TCP的输入 第二十九章 TCP的输入(续) 第三十章 TCP的用户需求 第三十一章 BPF:BSD分组过滤程序 第三十二章 原始IP 结束语 附录A 部分习题的解答 附录B 源代码的获取 附录C RFC 1122的有关内容 参考文献
目 录 译者序 前言 第1章 概述 1 1.1 引言 1 1.2 源代码表示 1 1.2.1 将拥塞窗口设置为1 1 1.2.2 印刷约定 2 1.3 历史 2 1.4 应用编程接口 3 1.5 程序示例 4 1.6 系统调用和库函数 6 1.7 网络实现概述 6 1.8 描述符 7 1.9 mbuf与输出处理 11 1.9.1 包含插口地址结构的mbuf 11 1.9.2 包含数据的mbuf 12 1.9.3 添加IP和UDP首部 13 1.9.4 IP输出 14 1.9.5 以太网输出 14 1.9.6 UDP输出小结 14 1.10 输入处理 15 1.10.1 以太网输入 15 1.10.2 IP输入 15 1.10.3 UDP输入 16 1.10.4 进程输入 17 1.11 网络实现概述(续) 17 1.12 中断级别与并发 18 1.13 源代码组织 20 1.14 测试网络 21 1.15 小结 22 第2章 mbuf:存储器缓存 24 2.1 引言 24 2.2 代码介绍 27 2.2.1 全局变量 27 2.2.2 统计 28 2.2.3 内核统计 28 2.3 mbuf的定义 29 2.4 mbuf结构 29 2.5 简单的mbuf宏和函数 31 2.5.1 m_get函数 32 2.5.2 MGET宏 32 2.5.3 m_retry函数 33 2.5.4 mbuf锁 34 2.6 m_devget和m_pullup函数 34 2.6.1 m_devget函数 34 2.6.2 mtod和dtom宏 36 2.6.3 m_pullup函数和连续的协议首部 36 2.6.4 m_pullup和IP的分片与重组 37 2.6.5 TCP重组避免调用m_pullup 39 2.6.6 m_pullup使用总结 40 2.7 mbuf宏和函数的小结 40 2.8 Net/3联网数据结构小结 42 2.9 m_copy和簇引用计数 43 2.10 其他选择 47 2.11 小结 47 第3章 接口层 49 3.1 引言 49 3.2 代码介绍 49 3.2.1 全局变量 49 3.2.2 SNMP变量 50 3.3 ifnet结构 51 3.4 ifaddr结构 57 3.5 sockaddr结构 58 3.6 ifnet与ifaddr的专用化 59 3.7 网络初始化概述 60 3.8 以太网初始化 61 3.9 SLIP初始化 64 3.10 环回初始化 65 3.11 if_attach函数 66 3.12 ifinit函数 72 3.13 小结 73 第4章 接口:以太网 74 4.1 引言 74 4.2 代码介绍 75 4.2.1 全局变量 75 4.2.2 统计量 75 4.2.3 SNMP变量 76 4.3 以太网接口 77 4.3.1 leintr函数 79 4.3.2 leread函数 79 4.3.3 ether_input函数 81 4.3.4 ether_output函数 84 4.3.5 lestart函数 87 4.4 ioctl系统调用 89 4.4.1 ifioctl函数 90 4.4.2 ifconf函数 91 4.4.3 举例 94 4.4.4 通用接口ioctl命令 95 4.4.5 if_down和if_up函数 96 4.4.6 以太网、SLIP和环回 97 4.5 小结 98 第5章 接口:SLIP和环回 100 5.1 引言 100 5.2 代码介绍 100 5.2.1 全局变量 100 5.2.2 统计量 101 5.3 SLIP接口 101 5.3.1 SLIP线路规程:SLIPDISC 101 5.3.2 SLIP初始化:slopen和slinit 103 5.3.3 SLIP输入处理:slinput 105 5.3.4 SLIP输出处理:sloutput 109 5.3.5 slstart函数 111 5.3.6 SLIP分组丢失 116 5.3.7 SLIP性能考虑 117 5.3.8 slclose函数 117 5.3.9 sltioctl函数 118 5.4 环回接口 119 5.5 小结 121 第6章 IP编址 123 6.1 引言 123 6.1.1 IP地址 123 6.1.2 IP地址的印刷规定 123 6.1.3 主机和路由器 124 6.2 代码介绍 125 6.3 接口和地址小结 125 6.4 sockaddr_in结构 126 6.5 in_ifaddr结构 127 6.6 地址指派 128 6.6.1 ifioctl函数 130 6.6.2 in_control函数 130 6.6.3 前提条件:SIOCSIFADDR、 SIOCSIFNETMASK和 SIOCSIFDSTADDR 132 6.6.4 地址指派:SIOCSIFADDR 133 6.6.5 in_ifinit函数 133 6.6.6 网络掩码指派:SIOCSIFNETMASK 136 6.6.7 目的地址指派:SIOCSIFDSTADDR 137 6.6.8 获取接口信息 137 6.6.9 每个接口多个IP地址 138 6.6.10 附加IP地址:SIOCAIFADDR 139 6.6.11 删除IP地址:SIOCDIFADDR 140 6.7 接口ioctl处理 141 6.7.1 leioctl函数 141 6.7.2 slioctl函数 142 6.7.3 loioctl函数 143 6.8 Internet实用函数 144 6.9 ifnet实用函数 144 6.10 小结 145 第7章 域和协议 146 7.1 引言 146 7.2 代码介绍 146 7.2.1 全局变量 147 7.2.2 统计量 147 7.3 domain结构 147 7.4 protosw结构 148 7.5 IP 的domain和protosw结构 150 7.6 pffindproto和pffindtype函数 155 7.7 pfctlinput函数 157 7.8 IP初始化 157 7.8.1 Internet传输分用 157 7.8.2 ip_init函数 158 7.9 sysctl系统调用 159 7.10 小结 161 第8章 IP:网际协议 162 8.1 引言 162 8.2 代码介绍 163 8.2.1 全局变量 163 8.2.2 统计量 163 8.2.3 SNMP变量 164 8.3 IP分组 165 8.4 输入处理:ipintr函数 167 8.4.1 ipintr概观 167 8.4.2 验证 168 8.4.3 转发或不转发 171 8.4.4 重装和分用 173 8.5 转发:ip_forward函数 174 8.6 输出处理:ip_output函数 180 8.6.1 首部初始化 181 8.6.2 路由选择 182 8.6.3 源地址选择和分片 184 8.7 Internet检验和:in_cksum函数 186 8.8 setsockopt和getsockopt系统调用 190 8.8.1 PRCO_SETOPT的处理 192 8.8.2 PRCO_GETOPT的处理 193 8.9 ip_sysctl函数 193 8.10 小结 194 第9章 IP选项处理 196 9.1 引言 196 9.2 代码介绍 196 9.2.1 全局变量 196 9.2.2 统计量 197 9.3 选项格式 197 9.4 ip_dooptions函数 198 9.5 记录路由选项 200 9.6 源站和记录路由选项 202 9.6.1 save_rte函数 205 9.6.2 ip_srcroute函数 206 9.7 时间戳选项 207 9.8 ip_insertoptions函数 210 9.9 ip_pcbopts函数 214 9.10 一些限制 217 9.11 小结 217 第10章 IP的分片与重装 218 10.1 引言 218 10.2 代码介绍 219 10.2.1 全局变量 220 10.2.2 统计量 220 10.3 分片 220 10.4 ip_optcopy函数 223 10.5 重装 224 10.6 ip_reass函数 227 10.7 ip_slowtimo函数 237 10.8 小结 238 第11章 ICMP:Internet控制报文协议 239 11.1 引言 239 11.2 代码介绍 242 11.2.1 全局变量 242 11.2.2 统计量 242 11.2.3 SNMP变量 243 11.3 icmp结构 244 11.4 ICMP 的protosw结构 245 11.5 输入处理:icmp_input函数 246 11.6 差错处理 249 11.7 请求处理 251 11.7.1 回显询问:ICMP_ECHO和 ICMP_ECHOREPLY 252 11.7.2 时间戳询问:ICMP_TSTAMP和 ICMP_TSTAMPREPLY 253 11.7.3 地址掩码询问:ICMP_MASKREQ和 ICMP_MASKREPLY 253 11.7.4 信息询问:ICMP_IREQ和ICMP_ IREQREPLY 255 11.7.5 路由器发现:ICMP_ROUTERADVERT 和ICMP_ROUTERSOLICIT 255 11.8 重定向处理 255 11.9 回答处理 257 11.10 输出处理 257 11.11 icmp_error函数 258 11.12 icmp_reflect函数 261 11.13 icmp_send函数 265 11.14 icmp_sysctl函数 266 11.15 小结 266 第12章 IP多播 268 12.1 引言 268 12.2 代码介绍 269 12.2.1 全局变量 270 12.2.2 统计量 270 12.3 以太网多播地址 270 12.4 ether_multi结构 271 12.5 以太网多播接收 273 12.6 in_multi结构 273 12.7 ip_moptions结构 275 12.8 多播的插口选项 276 12.9 多播的TTL值 277 12.9.1 MBONE 278 12.9.2 扩展环搜索 278 12.10 ip_setmoptions函数 278 12.10.1 选择一个明确的多播接口:IP_ MULTICAST_IF 280 12.10.2 选择明确的多播TTL: IP_ MULTICAST_TTL 281 12.10.3 选择多播环回:IP_MULTICAST_ LOOP 281 12.11 加入一个IP多播组 282 12.11.1 in_addmulti函数 285 12.11.2 slioctl和loioctl函数:SIOCADDMULTI和SIOCDELMULTI 287 12.11.3 leioctl函数:SIOCADDMULTI和 SIOCDELMULTI 288 12.11.4 ether_addmulti函数 288 12.12 离开一个IP多播组 291 12.12.1 in_delmulti函数 292 12.12.2 ether_delmulti函数 293 12.13 ip_getmoptions函数 295 12.14 多播输入处理:ipintr函数 296 12.15 多播输出处理:ip_output函数 298 12.16 性能的考虑 301 12.17 小结 301 第13章 IGMP:Internet组管理协议 303 13.1 引言 303 13.2 代码介绍 304 13.2.1 全局变量 304 13.2.2 统计量 304 13.2.3 SNMP变量 305 13.3 igmp结构 305 13.4 IGMP的protosw的结构 306 13.5 加入一个组:igmp_joingroup函数 306 13.6 igmp_fasttimo函数 308 13.7 输入处理:igmp_input函数 311 13.7.1 成员关系查询:IGMP_HOST_ MEMBERSHIP_QUERY 312 13.7.2 成员关系报告:IGMP_HOST_ MEMBERSHIP_REPORT 313 13.8 离开一个组:igmp_leavegroup函数 314 13.9 小结 315 第14章 IP多播选路 316 14.1 引言 316 14.2 代码介绍 316 14.2.1 全局变量 316 14.2.2 统计量 317 14.2.3 SNMP变量 317 14.3 多播输出处理(续) 317 14.4 mrouted守护程序 318 14.5 虚拟接口 321 14.5.1 虚拟接口表 322 14.5.2 add_vif函数 324 14.5.3 del_vif函数 326 14.6 IGMP(续) 327 14.6.1 add_lgrp函数 328 14.6.2 del_lgrp函数 329 14.6.3 grplst_member函数 330 14.7 多播选路 331 14.7.1 多播选路表 334 14.7.2 del_mrt函数 335 14.7.3 add_mrt函数 336 14.7.4 mrtfind函数 337 14.8 多播转发:ip_mforward函数 338 14.8.1 phyint_send函数 343 14.8.2 tunnel_send函数 344 14.9 清理:ip_mrouter_done函数 345 14.10 小结 346 第15章 插口层 348 15.1 引言 348 15.2 代码介绍 349 15.3 socket结构 349 15.4 系统调用 354 15.4.1 举例 355 15.4.2 系统调用小结 355 15.5 进程、描述符和插口 357 15.6 socket系统调用 358 15.6.1 socreate函数 359 15.6.2 超级用户特权 361 15.7 getsock和sockargs函数 361 15.8 bind系统调用 363 15.9 listen系统调用 364 15.10 tsleep和wakeup函数 365 15.11 accept系统调用 366 15.12 sonewconn和soisconnected 函数 369 15.13 connect系统调用 372 15.13.1 soconnect函数 374 15.13.2 切断无连接插口和外部地址的 关联 375 15.14 shutdown系统调用 375 15.15 close系统调用 377 15.15.1 soo_close函数 377 15.15.2 soclose函数 378 15.16 小结 380 第16章 插口I/O 381 16.1 引言 381 16.2 代码介绍 381 16.3 插口缓存 381 16.4 write、writev、sendto和sendmsg 系统调用 384 16.5 sendmsg系统调用 387 16.6 sendit函数 388 16.6.1 uiomove函数 389 16.6.2 举例 390 16.6.3 sendit代码 391 16.7 sosend函数 392 16.7.1 可靠的协议缓存 393 16.7.2 不可靠的协议缓存 393 16.7.3 sosend函数小结 401 16.7.4 性能问题 401 16.8 read、readv、recvfrom和recvmsg 系统调用 401 16.9 recvmsg系统调用 402 16.10 recvit函数 403 16.11 soreceive函数 405 16.11.1 带外数据 406 16.11.2 举例 406 16.11.3 其他的接收操作选项 407 16.11.4 接收缓存的组织:报文边界 407 16.11.5 接收缓存的组织:没有报文边界 408 16.11.6 控制信息和带外数据 409 16.12 soreceive代码 410 16.13 select系统调用 421 16.13.1 selscan函数 425 16.13.2 soo_select函数 425 16.13.3 selrecord函数 427 16.13.4 selwakeup函数 428 16.14 小结 429 第17章 插口选项 431 17.1 引言 431 17.2 代码介绍 431 17.3 setsockopt系统调用 432 17.4 getsockopt系统调用 437 17.5 fcntl和ioctl系统调用 440 17.5.1 fcntl代码 441 17.5.2 ioctl代码 443 17.6 getsockname系统调用 444 17.7 getpeername系统调用 445 17.8 小结 447 第18章 Radix树路由表 448 18.1 引言 448 18.2 路由表结构 448 18.3 选路插口 456 18.4 代码介绍 456 18.4.1 全局变量 458 18.4.2 统计量 458 18.4.3 SNMP变量 459 18.5 Radix结点数据结构 460 18.6 选路结构 463 18.7 初始化:route_init和rtable_init 函数 465 18.8 初始化:rn_init和rn_inithead 函数 468 18.9 重复键和掩码列表 471 18.10 rn_match函数 473 18.11 rn_search函数 480 18.12 小结 481 第19章 选路请求和选路消息 482 19.1 引言 482 19.2 rtalloc和rtalloc1函数 482 19.3 宏RTFREE和rtfree函数 484 19.4 rtrequest函数 486 19.5 rt_setgate函数 491 19.6 rtinit函数 493 19.7 rtredirect函数 495 19.8 选路消息的结构 498 19.9 rt_missmsg函数 501 19.10 rt_ifmsg函数 503 19.11 rt_newaddrmsg函数 504 19.12 rt_msg1函数 505 19.13 rt_msg2函数 507 19.14 sysctl_rtable函数 510 19.15 sysctl_dumpentry函数 514 19.16 sysctl_iflist函数 515 19.17 小结 517 第20章 选路插口 518 20.1 引言 518 20.2 routedomain和protosw结构 518 20.3 选路控制块 519 20.4 raw_init函数 520 20.5 route_output函数 520 20.6 rt_xaddrs函数 530 20.7 rt_setmetrics函数 531 20.8 raw_input函数 532 20.9 route_usrreq函数 534 20.10 raw_usrreq函数 535 20.11 raw_attach、raw_detach和raw_disconnect函数 539 20.12 小结 540 第21章 ARP:地址解析协议 542 21.1 介绍 542 21.2 ARP和路由表 542 21.3 代码介绍 544 21.3.1 全局变量 544 21.3.2 统计量 544 21.3.3 SNMP变量 546 21.4 ARP结构 546 21.5 arpwhohas函数 548 21.6 arprequest函数 548 21.7 arpintr函数 551 21.8 in_arpinput函数 552 21.9 ARP定时器函数 557 21.9.1 arptimer函数 557 21.9.2 arptfree函数 557 21.10 arpresolve函数 558 21.11 arplookup函数 562 21.12 代理ARP 563 21.13 arp_rtrequest函数 564 21.14 ARP和多播 569 21.15 小结 570 第22章 协议控制块 572 22.1 引言 572 22.2 代码介绍 573 22.2.1 全局变量 574 22.2.2 统计量 574 22.3 inpcb的结构 574 22.4 in_pcballoc和in_pcbdetach函数 575 22.5 绑定、连接和分用 577 22.6 in_pcblookup函数 581 22.7 in_pcbbind函数 584 22.8 in_pcbconnect函数 589 22.9 in_pcbdisconnect函数 594 22.10 in_setsockaddr和in_setpeeraddr 函数 595 22.11 in_pcbnotify、in_rtchange和in_losing函数 595 22.11.1 in_rtchange函数 598 22.11.2 重定向和原始插口 599 22.11.3 ICMP差错和UDP插口 600 22.11.4 in_losing函数 601 22.12 实现求精 602 22.13 小结 602 第23章 UDP:用户数据报协议 605 23.1 引言 605 23.2 代码介绍 605 23.2.1 全局变量 606 23.2.2 统计量 606 23.2.3 SNMP变量 607 23.3 UDP 的protosw结构 607 23.4 UDP的首部 608 23.5 udp_init函数 609 23.6 udp_output函数 609 23.6.1 在前面加上IP/UDP首部和mbuf簇 612 23.6.2 UDP检验和计算和伪首部 612 23.7 udp_input函数 616 23.7.1 对收到的UDP数据报的一般确认 616 23.7.2 分用单播数据报 619 23.7.3 分用多播和广播数据报 622 23.7.4 连接上的UDP插口和多接口主机 625 23.8 udp_saveopt函数 625 23.9 udp_ctlinput函数 627 23.10 udp_usrreq函数 628 23.11 udp_sysctl函数 633 23.12 实现求精 633 23.12.1 UDP PCB高速缓存 633 23.12.2 UDP检验和 634 23.13 小结 635 第24章 TCP:传输控制协议 636 24.1 引言 636 24.2 代码介绍 636 24.2.1 全局变量 636 24.2.2 统计量 637 24.2.3 SNMP变量 640 24.3 TCP 的protosw结构 641 24.4 TCP的首部 641 24.5 TCP的控制块 643 24.6 TCP的状态变迁图 645 24.7 TCP的序号 646 24.8 tcp_init函数 650 24.9 小结 652 第25章 TCP的定时器 654 25.1 引言 654 25.2 代码介绍 655 25.3 tcp_canceltimers函数 657 25.4 tcp_fasttimo函数 657 25.5 tcp_slowtimo函数 658 25.6 tcp_timers函数 659 25.6.1 FIN_WAIT_2和2MSL定时器 660 25.6.2 持续定时器 662 25.6.3 连接建立定时器和保活定时器 662 25.7 重传定时器的计算 665 25.8 tcp_newtcpcb算法 666 25.9 tcp_setpersist函数 668 25.10 tcp_xmit_timer函数 669 25.11 重传超时:tcp_timers函数 673 25.11.1 慢起动和避免拥塞 675 25.11.2 精确性 677 25.12 一个RTT的例子 677 25.13 小结 679 第26章 TCP输出 680 26.1 引言 680 26.2 tcp_output概述 680 26.3 决定是否应发送一个报文段 682 26.4 TCP选项 691 26.5 窗口大小选项 692 26.6 时间戳选项 692 26.6.1 哪个时间戳需要回显,RFC1323 算法 694 26.6.2 哪个时间戳需要回显,正确的 算法 695 26.6.3 时间戳与延迟ACK 695 26.7 发送一个报文段 696 26.8 tcp_template函数 707 26.9 tcp_respond函数 708 26.10 小结 710 第27章 TCP的函数 712 27.1 引言 712 27.2 tcp_drain函数 712 27.3 tcp_drop函数 712 27.4 tcp_close函数 713 27.4.1 路由特性 713 27.4.2 资源释放 716 27.5 tcp_mss函数 717 27.6 tcp_ctlinput函数 722 27.7 tcp_notify函数 723 27.8 tcp_quench函数 724 27.9 TCP_REASS宏和tcp_reass函数 724 27.9.1 TCP_REASS宏 725 27.9.2 tcp_reass函数 727 27.10 tcp_trace函数 732 27.11 小结 736 第28章 TCP的输入 737 28.1 引言 737 28.2 预处理 739 28.3 tcp_dooptions函数 745 28.4 首部预测 747 28.5 TCP输入:缓慢的执行路径 752 28.6 完成被动打开或主动打开 752 28.6.1 完成被动打开 753 28.6.2 完成主动打开 756 28.7 PAWS:防止序号回绕 760 28.8 裁剪报文段使数据在窗口内 762 28.9 自连接和同时打开 768 28.10 记录时间戳 770 28.11 RST处理 770 28.12 小结 772 第29章 TCP的输入(续) 773 29.1 引言 773 29.2 ACK处理概述 773 29.3 完成被动打开和同时打开 774 29.4 快速重传和快速恢复的算法 775 29.5 ACK处理 778 29.6 更新窗口信息 784 29.7 紧急方式处理 786 29.8 tcp_pulloutofband函数 788 29.9 处理已接收的数据 789 29.10 FIN处理 791 29.11 最后的处理 793 29.12 实现求精 795 29.13 首部压缩 795 29.13.1 引言 796 29.13.2 首部字段的压缩 799 29.13.3 特殊情况 801 29.13.4 实例 802 29.13.5 配置 803 29.14 小结 803 第30章 TCP的用户需求 805 30.1 引言 805 30.2 tcp_usrreq函数 805 30.3 tcp_attach函数 814 30.4 tcp_disconnect函数 815 30.5 tcp_usrclosed函数 816 30.6 tcp_ctloutput函数 817 30.7 小结 820 第31章 BPF:BSD 分组过滤程序 821 31.1 引言 821 31.2 代码介绍 821 31.2.1 全局变量 821 31.2.2 统计量 822 31.3 bpf_if结构 822 31.4 bpf_d结构 825 31.4.1 bpfopen函数 826 31.4.2 bpfioctl函数 827 31.4.3 bpf_setif函数 830 31.4.4 bpf_attachd函数 831 31.5 BPF的输入 832 31.5.1 bpf_tap函数 832 31.5.2 catchpacket函数 833 31.5.3 bpfread函数 835 31.6 BPF的输出 837 31.7 小结 838 第32章 原始IP 839 32.1 引言 839 32.2 代码介绍 839 32.2.1 全局变量 839 32.2.2 统计量 840 32.3 原始 IP的protosw结构 840 32.4 rip_init函数 842 32.5 rip_input函数 842 32.6 rip_output函数 844 32.7 rip_usrreq函数 846 32.8 rip_ctloutput函数 850 32.9 小结 852 结束语 853 附录A 部分习题的解答 854 附录B 源代码的获取 872 附录C RFC 1122 的有关内容 874 参考文献 895

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HarkerYX

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值