在过去的十几年中,Linux已经成为网络领域中服务器技术、嵌入式系统、研究工作的常用选择。它首先引起了学生团体的兴趣,并逐渐进入研究人员和公司的视野。网络一旦与Linux结合,就在很多方面诞生了一系列具有创新性的产品,如高端通信设备、数据中心、嵌入式系统等。 1996年,我第一次进行TCP/IP套接字编程,从此开始了解Linux。那时,我对客户端-服务器知之甚少,不明白服务器程序使用唯一端口号在系统中注册自身,而客户端则根据该端口号与服务器通信。我也不了解客户端程序用以标识主机的IP地址,然后我强迫自己去学习和了解它们的工作原理。 很多知识都需要从头开始学习,如系统调用、协议、Linux内核、驱动器、支持协议栈的内核框架等。慢慢地,我逐步了解了Linux内核,了解到用户区程序通过编写新的系统调用和内核模块来实现与内核的交互。 这个学习过程首先从著名的Richard Stevens所编写的TCP/IP Illustrated, Volume 1开始,但是,由于很少有探讨这些协议在Linux实现的相关文档和书籍,因此,我决定自己深入学习来了解协议栈的实现。最后,我开始明白了套接层如何链接到VFS层,然后又逐渐了解TCP层以及TCP协议发送数据的第一个接口例程。接下来,不断地对TCP/IP协议栈的实现进行总结和实验。当总结了很多学习经验时,我产生了将这些资料介绍给Linux社区的想法。编写一本书超出了我的能力,这将需要大量的工作,并会花费大量的时间和精力。但是,我仍然下定决心将这个复杂的话题引入Linux社区,尽我所能地对其进行介绍。不过由于缺乏相关详细、系统的文档或者书籍介绍,因此,理解这些问题显得比较困难,于是我开始考虑是否可能写一本这方面的书籍。当我从IEEE计算机协会和John Wiley & Sons收到邀请时,我下定决心要完成编写这样一本书。 在工作的同时还要编写本书使我倍感困难,因此,我想应当寻找一个合著者,以负责某些内容的编写工作。经过长时间努力,M. Ajaykumar Venkatesulu成为我的合著者,他从事庞大且最为复杂的路由子系统和QoS方面的工作。 本书试图介绍TCP/IP协议栈和内核支持框架的各个方面,其思想是尽可能地弱化其复杂性,以便于理解的方式呈现给读者。理解任何操作系统上的TCP/IP实现,首先需要理解支持该协议栈的内核框架。在Linux中,这些支持框架有VFS层、套接字框架、协议层、定时器、内存管理、中断处理、软中断、内核线程、内核同步机制等,这是内核实现协议栈所需的。除此之外,还需要了解打开TCP通信套接字和客户端-服务器程序所需的通信协议以及应用程序接口(系统调用)。这些知识对于希望学习和了解该主题,并希望为Linux做贡献的学生和经验丰富的专业人员来说,都很有帮助。 在编写本书时是基于Linux内核2.4.20,而最新版本的2.6内核在TCP/IP协议栈方面并没有很大变化,并且在Linux应用中,2.4内核是接受最为广泛的版本。2.6版内核在TCP/IP方面的变化将在本书的下一版本中讨论。 读者对象 本书面向各个方面的读者: 全世界研究机构的研究人员:从事TCP/IP协议栈方面工作的研究人员发现,BSD是最为适合的网络操作系统。但在企业界,BSD并不是常用的一种选择。因此,研究人员最常用的选择是Linux操作系统,研究如何提高TCP/IP协议栈在该操作系统上的性能。网络是当前最为广泛的研究领域,其原因是Internet在社会生活中的地位日益提高。一般来说,研究人员喜欢比较简单的商业化操作系统,这些操作系统能够运行在廉价的硬件上。 学术研究人员:高级学术研究项目更喜欢使用Linux,如MS、M. Tech、B. Tech、PG等,其原因在于Linux是第一个类Unix的操作系统,它文档丰富并且运行稳定。在网络领域,学生通常选择Linux上的TCP/IP来开展项目研究。这些项目的需求有修改路由器或者TCP性能、实现一些新的TCP/IP RFC、网络驱动器、实现安全IP层、提高处理网络流量的可扩展性。 公司:从很大程度上来说,企业界一般都选择Linux作为开发其网络产品的操作系统。很多公司在开发网络产品(如IP安全、服务质量(基于类的路由)、路由器开发、带宽管理产品、集群服务器等)时,都要修改TCP/IP协议栈,或者编写新的模块集成到Linux TCP/IP协议栈中。Linux不仅是开放式系统的常用选择,也是嵌入式产品和实时操作系统的主流选择。这些嵌入式产品主要用于网络领域,如路由器、嵌入式Web服务器、Web浏览器等。 企业:新思想不断涌现,不过需要转化为产品。随着Internet的应用日益广泛,开发网络产品方面出现了很多新思想,Linux再次成为企业界开发的首选。 开源组织:由于Linux和Internet技术的使用日益广泛,很多新毕业的大学生,甚至软件业人员都希望能够为提高Linux的网络能力做贡献。他们的目标是使Linux更加强大、稳定、安全,互联功能更加完善,以满足企业界的各个方面要求。很多专业人员希望能够为Linux网络能力做贡献,但是,没有足够的时间来熟悉网络协议栈和内核框架。 国防机构:Linux作为一种网络操作系统,在国防机构的应用也日益广泛,尤其是在军事领域,对Linux IPSec进行一定的修改后,可以应用于安全军事网络事务。 所有这些人员都需要对Linux TCP/IP协议栈和内核网络协议栈框架有较为全面、细致的了解。而理解TCP、IP、BSD套接字、防火墙、IPSec、IP转发、路由器网络驱动,都需要对网络协议栈的实现和设计有比较全面的了解。如果要实现IPSec或者防火墙,就需要了解在Linux中如何实现报文,报文如何以及从何处传递给IP层,IP层如何处理报文并添加协议头,最后还需要了解IP层如何将报文传递给设备驱动器来最后传输出去。类似地,如果要实现QoS,或者对现有实现做一些修改,就需要了解Linux路由表实现、报文结构、报文调度、内核帧的处理过程(如网络软中断等)。因此,任何需要修改现有Linux网络协议栈或者向协议栈添加新特性的工作,都需要全面理解Linux TCP/IP协议栈的设计与实现。 本书的组织结构 本书全面阐述了Linux TCP/IP协议及其设计和实现。首先以简单的客户端-服务器套接字程序开始,最后探讨了Linux中较为复杂的TCP/IP协议和设计与实现,其间则逐步阐述套接字编程的各个方面以及主要的TCP/IP相关算法。包括: Linux内核和TCP/IP应用接口:第1章介绍了Linux内核的基本知识,以及使用TCP/IP协议栈进行通信的内核接口(系统调用)。 协议:第2章讲述了TCP/IP协议以及相关支持协议,如ARP和ICMP等。本章使用图示阐述了一些主要的RFC,以使读者熟悉这些协议,从而便于在后面的章节中将Linux及其对协议栈的实现联系起来。 套接字:第3章讲述了BSD套接字在Linux内核中的实现,本章详细讨论了套接字层如何挂接到VFS层,以及各种协议如何挂接到BSD套接字。 连接设置的内核实现:第4章使用C语言阐述了客户端-服务器应用程序。本章都使用tcp dump输出来讲解连接设置的完整过程。本章还讨论了系统调用的内核实现,应用程序使用这些系统调用来实现客户端-服务器的交互,从中可以了解服务器如何接受连接,同时,服务器程序如何将特定的监听端口注册到内核并绑定。 Linux网络报文实现:第5章讨论了Linux中表示网络报文的数据结构sk_buff,本章讲述了处理sk_buff的主要例程。 报文的各层处理:第6章完整地介绍了TCP/IP内核协议栈框架,讨论了如何生成报文,以及报文在发出系统之前的向下处理过程。类似地,本章还讨论了设备接收的报文到达宿主套接字的完整处理路径,同时也阐述了Linux中实现TCP/IP协议栈的完整内核框架。 TCP接收/发送:第7章和第8章阐述了TCP接收和发送的实现,以及与TCP接收数据和发送数据相关的各个方面。同时,说明了当TCP接收到ICMP错误消息(路由器的MSS发生变化)时,TCP分段单元的处理过程。还简要说明了紧急数据的处理。 TCP套接字定时器和内存管理:内核在套接字层记录了每个连接所消耗的内存,因此,不良应用程序使用单个套接字连接无法耗尽全部的系统内存。当应用程序读取数据的速度不够快并且套接字耗尽其缓冲区配额时,需要按一定的顺序来释放接收队列中的缓冲区。第9章阐述了内存管理方面的内容。TCP是一个事件驱动的协议,TCP实现了跟踪数据丢失的定时器、发送延时ACK的定时器、发送零窗口探测的定时器等,第10章阐述了这些定时器。 TCP状态机:第11章阐述了TCP核心处理过程,如报文接收、ACK发送、滑动窗口、Nagle算法、延时ACK的调度、乱序分段的处理、SACK的处理、D-SACK等。tcp_opt对象表示Linux中状态机实现的。第12章讨论了拥塞控制算法的实现。 netlink套接字:用户区应用程序(如netstat和iproute,路由协议守护程序等)使用特殊的netlink套接字来更新/读取路由,并配置内核QoS。第13章讨论了netlink套接字。 IP层和路由表实现:第14章讨论了Linux路由表(FIB)的实现,同时说明了与路由相关的各个方面,如多路径、策略路由等,本章也阐述了更新内核路由表的各个内核控制路径,以及路由缓存管理。 IP服务质量:IP网络不断演进,公网提供的服务也各种各样,Linux完全实现了QoS,第15章讨论了PFIFO和CBQ排队规则实现。 netfilter框架:Linux通过netfilter框架来实现对TCP/IP协议栈的扩展,这些扩展可能是防火墙、伪装、IPSec等。第16章讨论了协议栈不同层次的netfilter钩子以及netfilter实现。 支持可扩展性的软中断(SoftIRQ)实现:网络数据帧通过中断处理程序编码接收到内核内存中,但是中断处理程序不可能完全处理报文。Linux实现了软中断,用于每个报文的接收和传输处理。第17章使用图示阐述了网络软中断框架。本章完整地阐述了Linux在SMP体系结构中处理网络流的高可扩展性。 链路层和DMA环缓冲区:第18章阐述了链路层(设备驱动)对报文的处理,同时还阐述了DMA环缓冲区在报文接收和传输方面的设计原理及工作过程,并利用设备驱动器和真实设备的中断例程对其进行了详解。 调试TCP/IP协议栈:第19章讨论了对TCP/IP协议栈的调试,本章举例说明了lkcd(Linux内核崩溃转储)调试技术,以深入了解TCP/IP协议栈的各个内核数据结构。 特别说明 前面已经提过,本书简要涉及了理解核心TCP/IP协议栈和内核框架的关键部分实现。每一章都有概述和总结,阐述相应章节的重点内容,还使用源码和图示阐述了相关的处理过程,并逐行说明重要例程,所有例程代码段的前面都标有行号,不过有些例程比较大,我们将其分为多个小的代码段,从主例程调用的例程则在不同的章节说明。如果调用的例程只有几行,就不会在独立的章节中说明。在解释这些例程时,还标记了代码段号和行号以便于理解。当例程非常大时,会在章节的开头标记“除非特别说明,参见源码”,其含义是所提及的行号都是指本章节开头所指出的代码段。 当遇到一些已在其他章节解释过程的概念时,会提供一些章节的交叉引用,如“参考某节”,提供交叉引用的原因是某些主题是相关的,例如,在解释传入TCP报文的排队处理时,需要参考套接字接收缓冲区`。如果耗尽了套接字接收缓冲区,就需要调用例程来释放接收队列中的某些缓冲区,为新的TCP数据段留出空间。为此可能需要参考TCP内存管理的相关章节。主要的数据结构则在独立章节中阐述,如果没有在独立章节中阐述,那么出现在例程中的数据结构及其相应域则会逐一解释。 本书还在需要的地方提供例程和图示以帮助读者理解这些内容。例如,在阐述SYN队列中的连接请求时,就描述了各种内核数据结构,然后使用图示描述了三步握手结束时,连接请求从SYN队列移动到accept队列的过程。所有这些图示能够将复杂的数据结构和场景以可视化的形式呈现给读者,便于读者理解。 Sameer Seth 班加罗尔,印度