IP协议
IP协议是TCP/IP协议族的动力,它为上层协议提供无状态、无连接、不可靠的服务。
IP协议根据数据包的目的IP地址来决定如何投递它。如果数据包不能直接发送给目标主机,那么IP协议就为它寻找一个合适的下一跳(next hop)路由器,并将数据包交付给该路由器来转发。多次重复这一过程,数据包最终到达目标主机,或者由于发送失败而被丢弃。IP协议使用逐跳(hop by hop)的方式确定通信路径。
无状态(stateless)是指IP通信双方不同步传输数据的状态信息,因此所有IP数据报的发送、传输和接收都是相互独立、没有上下文关系的。这种服务最大的缺点是无法处理乱序和重复的IP数据报。比如发送端发送出的第N个IP数据报可能比第N+1个IP数据报后到达接收端,而同一个IP数据报也可能经过不同的路径多次到达接收端。在这两种情况下,接收端的IP模块无法检测到乱序和重复,因为这些IP数据报之间没有任何上下文关系。接收端的IP模块只要收到了完整的IP数据报(如果是IP分片的话,IP模块将先执行重组),就将其数据部分(TCP报文段、UDP数据报或者ICMP报文)上交给上层协议。那么从上层协议来看,这些数据就可能是乱序的、重复的。面向连接的协议,比如TCP协议,则能够自己处理乱序的、重复的报文段,它递交给上层协议的内容绝对是有序的、正确的。
虽然IP数据报头部提供了一个标识字段(见后文)用以唯一标识一个IP数据报,但它是被用来处理IP分片和重组的,而不是用来指示接收顺序的。
无状态服务的优点也很明显:简单、高效。我们无须为保持通信的状态而分配一些内核资源,也无须每次传输数据时都携带状态信息。在网络协议中,无状态是很常见的,比如UDP协议和HTTP协议都是无状态协议。以HTTP协议为例,一个浏览器的连续两次网页请求之间没有任何关联,它们将被Web服务器独立地处理。
无连接(connectionless)是指IP通信双方都不长久地维持对方的任何信息。这样,上层协议每次发送数据的时候,都必须明确指定对方的IP地址。
不可靠是指IP协议不能保证IP数据报准确地到达接收端,它只是承诺尽最大努力(best effort)。很多种情况都能导致IP数据报发送失败。比如,某个中转路由器发现IP数据报在网络上存活的时间太长(根据IP数据报头部字段TTL判断),那么它将丢弃之,并返回一个ICMP错误消息(超时错误)给发送端。又比如,接收端发现收到的IP数据报不正确(通过校验机制),它也将丢弃之,并返回一个ICMP错误消息(IP头部参数错误)给发送端。无论哪种情况,发送端的IP模块一旦检测到IP数据报发送失败,就通知上层协议发送失败,而不会试图重传。因此,使用IP服务的上层协议(比如TCP协议)需要自己实现数据确认、超时重传等机制以达到可靠传输的目的。
IPV4
IPv4头部结构
- 4位版本号(version)指定IP协议的版本。对IPv4来说,其值是4。
- 4位头部长度(header length)标识该IP头部有多少个32 bit字(4字节)。因为4位最大能表示15,所以IP头部最长是60字节。
- 8位服务类型(Type Of Service,TOS),4位的TOS字段和1位保留字段(必须置0)。4位的TOS字段分别表示:最小延时,最大吞吐量,最高可靠性和最小费用。其中最多有一个能置为1,应用程序应该根据实际需要来设置它。比如像ssh和telnet这样的登录程序需要的是最小延时的服务,而文件传输程序ftp则需要最大吞吐量的服务。
- 16位总长度(total length)是指整个IP数据报的长度,以字节为单位,因此IP数据报的最大长度为65 535字节。但由于MTU的限制,长度超过MTU的数据报都将被分片传输,所以实际传输的IP数据报(或分片)的长度都远远没有达到最大值。
接下来的3个字段则描述了如何实现分片。
- 16位标识(identification)唯一地标识主机发送的每一个数据报。其初始值由系统随机生成;每发送一个数据报,其值就加1。该值在数据报分片时被复制到每个分片中,因此同一个数据报的所有分片都具有相同的标识值。
- 3位标志字段的第一位保留。第二位(Don’t Fragment,DF)表示“禁止分片”。如果设置了这个位,IP模块将不对数据报进行分片。在这种情况下,如果IP数据报长度超过MTU的话,IP模块将丢弃该数据报并返回一个ICMP差错报文。第三位(More Fragment,MF)表示“更多分片”。除了数据报的最后一个分片外,其他分片都要把它置1。
- 13位分片偏移(fragmentation offset)是分片相对原始IP数据报开始处(仅指数据部分)的偏移。实际的偏移值是该值左移3位(乘8)后得到的。由于这个原因,除了最后一个IP分片外,每个IP分片的数据部分的长度必须是8的整数倍(这样才能保证后面的IP分片拥有一个合适的偏移值)。
- 8位生存时间(Time To Live,TTL)是数据报到达目的地之前允许经过的路由器跳数。TTL值被发送端设置(常见的值是64)。数据报在转发过程中每经过一个路由,该值就被路由器减1。当TTL值减为0时,路由器将丢弃数据报,并向源端发送一个ICMP差错报文。TTL值可以防止数据报陷入路由循环。
- 8位协议(protocol)用来区分上层协议,如ICMP是1,TCP是6,UDP是17。
- 6位头部校验和(header checksum)由发送端填充,接收端对其使用CRC算法以检验IP数据报头部(注意,仅检验头部)在传输过程中是否损坏。
- 32位的源端IP地址和目的端IP地址用来标识数据报的发送端和接收端。
IPv4最后一个选项字段(option)是可变长的可选信息。参考IP协议的标准文档RFC 791.
IP分片
当IP数据报的长度超过帧的MTU时,它将被分片传输。分片可能发生在发送端,也可能发生在中转路由器上,而且可能在传输过程中被多次分片,但只有在最终的目标机器上,这些分片才会被内核中的IP模块重新组装。
IP头部中的如下三个字段给IP的分片和重组提供了足够的信息:数据报标识、标志和片偏移。一个IP数据报的每个分片都具有自己的IP头部,它们具有相同的标识值,但具有不同的片偏移。并且除了最后一个分片外,其他分片都将设置MF标志。此外,每个分片的IP头部的总长度字段将被设置为该分片的长度。
以太网帧的MTU是1500字节(可以通过ifconfig命令或者netstat命令查看),因此它携带的IP数据报的数据部分最多是1480字节(IP头部占用20字节)。考虑用IP数据报封装一个长度为1481字节的ICMP报文(包括8字节的ICMP头部,所以其数据部分长度为1473字节),则该数据报在使用以太网帧传输时必须被分片
长度为1501字节的IP数据报被拆分成两个IP分片,第一个IP分片长度为1500字节,第二个IP分片的长度为21字节。每个IP分片都包含自己的IP头部(20字节),且第一个IP分片的IP头部设置了MF标志,而第二个IP分片的IP头部则没有设置该标志,因为它已经是最后一个分片了。
原始IP数据报中的ICMP头部内容被完整地复制到了第一个IP分片中。第二个IP分片不包含ICMP头部信息,因为IP模块重组该ICMP报文的时候只需要一份ICMP头部信息。1473字节的ICMP报文数据的前1472字节被IP模块复制到第一个IP分片中,使其总长度为1500字节,从而满足MTU的要求;而多出的最后1字节则被复制到第二个IP分片中。
IP 地址编址方式
1. 分类
由两部分组成,网络号和主机号,其中不同分类具有不同的网络号长度,并且是固定的。
IP 地址 ::= {< 网络号 >, < 主机号 >}
IP地址根据网络号和主机号来分,分为A、B、C三类及特殊地址D、E。 全0和全1的都保留不用。
A类:(1.0.0.0-126.0.0.0)(默认子网掩码:255.0.0.0或 0xFF000000)第一个字节为网络号,后三个字节为主机号。该类IP地址的最前面为“0”,所以地址的网络号取值于1~126之间。一般用于大型网络。
B类:(128.0.0.0-191.255.0.0)(默认子网掩码:255.255.0.0或0xFFFF0000)前两个字节为网络号,后两个字节为主机号。该类IP地址的最前面为“10”,所以地址的网络号取值于128~191之间。一般用于中等规模网络。
C类:(192.0.0.0-223.255.255.0)(子网掩码:255.255.255.0或 0xFFFFFF00)前三个字节为网络号,最后一个字节为主机号。该类IP地址的最前面为“110”,所以地址的网络号取值于192~223之间。一般用于小型网络。
在IP地址3种主要类型里,各保留了3个区域作为私有地址,其地址范围如下: A类地址:10.0.0.0~10.255.255.255 B类地址:172.16.0.0~172.31.255.255 C类地址:192.168.0.0~192.168.255.255
回送地址:127.0.0.1。 也是本机地址,等效于localhost或本机IP。一般用于测试使用。
2. 子网划分
通过在主机号字段中拿一部分作为子网号,把两级 IP 地址划分为三级 IP 地址。
IP 地址 ::= {< 网络号 >, < 子网号 >, < 主机号 >}
要使用子网,必须配置子网掩码。一个 B 类地址的默认子网掩码为 255.255.0.0,如果 B 类地址的子网占两个比特,那么子网掩码为 11111111 11111111 11000000 00000000,也就是 255.255.192.0。
注意,外部网络看不到子网的存在。
3. 无分类
无分类编址 CIDR 消除了传统 A 类、B 类和 C 类地址以及划分子网的概念,使用网络前缀和主机号来对 IP 地址进行编码,网络前缀的长度可以根据需要变化。
IP 地址 ::= {< 网络前缀号 >, < 主机号 >}
CIDR 的记法上采用在 IP 地址后面加上网络前缀长度的方法,例如 128.14.35.7/20 表示前 20 位为网络前缀。
CIDR 的地址掩码可以继续称为子网掩码,子网掩码首 1 长度为网络前缀的长度。
一个 CIDR 地址块中有很多地址,一个 CIDR 表示的网络就可以表示原来的很多个网络,并且在路由表中只需要一个路由就可以代替原来的多个路由,减少了路由表项的数量。把这种通过使用网络前缀来减少路由表项的方式称为路由聚合,也称为 构成超网 。
在路由表中的项目由“网络前缀”和“下一跳地址”组成,在查找时可能会得到不止一个匹配结果,应当采用最长前缀匹配来确定应该匹配哪一个。
IP路由
IP路由决定发送数据报到目标机器的路径
当IP模块接收到来自数据链路层的IP数据报时,它首先对该数据报的头部做CRC校验,确认无误之后就分析其头部的具体信息。
如果该IP数据报的头部设置了源站选路选项(松散源路由选择或严格源路由选择),则IP模块调用数据报转发子模块来处理该数据报。如果该IP数据报的头部中目标IP地址是本机的某个IP地址,或者是广播地址,即该数据报是发送给本机的,则IP模块就根据数据报头部中的协议字段来决定将它派发给哪个上层应用(分用)。如果IP模块发现这个数据报不是发送给本机的,则也调用数据报转发子模块来处理该数据报。
数据报转发子模块将首先检测系统是否允许转发,如果不允许,IP模块就将数据报丢弃。如果允许,数据报转发子模块将对该数据报执行一些操作,然后将它交给IP数据报输出子模块。
IP数据报应该发送至哪个下一跳路由(或者目标机器),以及经过哪个网卡来发送,就是IP路由过程,即“计算下一跳路由”子模块。IP模块实现数据报路由的核心数据结构是路由表。这个表按照数据报的目标IP地址分类,同一类型的IP数据报将被发往相同的下一跳路由器(或者目标机器)。
IP输出队列中存放的是所有等待发送的IP数据报,其中除了需要转发的IP数据报外,还包括封装了本机上层数据(ICMP报文、TCP报文段和UDP数据报)的IP数据报。
路由机制
可以使用route命令或netstat命令查看路由表。
路由器分组转发流程
- 从数据报的首部提取目的主机的 IP 地址 D,得到目的网络地址 N。
- 若 N 就是与此路由器直接相连的某个网络地址,则进行直接交付;
- 若路由表中有目的地址为 D 的特定主机路由,则把数据报传送给表中所指明的下一跳路由器;
- 若路由表中有到达网络 N 的路由,则把数据报传送给路由表中所指明的下一跳路由器;
- 若路由表中有一个默认路由,则把数据报传送给路由表中所指明的默认路由器;
- 报告转发分组出错。
内容来源
linux高性能服务器编程.游双