在学习了IP数据包的构造之后,接下来要学习IP数据包是怎么被路由器处理并转发的。内容涉及到路由表的概念、存储转发的概念以及数据在网络层和数据链路层被转发时的区别。


路由的逻辑

在以前的章节中,我们知道了路由器是用来连接多个不同网络(或子网),工作在TCP/IP体系的网络层,负责处理IP数据包。现在我们从整体宏观的视角来看就是:既然一个路由器能连接多个不同的网络(或子网),那么很多个路由器用通信线路连接起来,就组成了更大范围的网络互联。同样的道理再扩大范围,也就不难理解:因特网上存在着大量的数以万计的路由器,再加上通信线路以及其它的网络设备就组成了全世界最大的广域网。

其实这就像日常生活中的交通一样,在我们生活的某个城市(无论是大城市还是县城、乡镇),都有为我们出行提供服务的公路,比如从当地的一所学校到一家大型超市,通过查地图我们能知道到达某个路口之后应该怎么走,最终到达目的地。类比到计算机网络中也是一样的,路口就相当于路由器,公路就相当于通信线路,人就相当于数据包。

但是,现实中的人是灵活的,去往一个陌生地方可以查地图、用导航,如果途中实在迷路还可以询问一下别人。那么网络中的数据包怎么办呢,它们不像人这么智能,这时候就需要路由器为它指明路径了。

路由表

路由器是怎么为数据包指明路径的?路由器知道整个网络的“地图”吗?其实,在路由器内部会记录着一张表格,称为“路由表”,就类似于“MAC地址表”那样的表格,当收到一个数据包的时候,查看数据包的目的IP地址,再检索自己的路由表,就知道应该把此数据包转交给谁。

路由表也不是路由器本身自带的,它也是像“MAC地址表”一样通过某种手段自己建立起来的。建立路由表的方法有两种:一种是人工为它建立(称为静态路由),另一种是通过一定的路由选择协议让路由器自己去学习并自动建立(称为动态路由)。

关于路由选择协议,比如OSPF、IS-IS、BGP这些,但这些协议内部原理太复杂、太庞大,在学习基本网络原理的时候,不需要深入了解,只要知道它们是路由器可以运行的动态路由协议,能够帮助路由器自动建立路由表,让路由器能够知道自己所处的网络的拓扑图是什么样子的,就可以了。

路由表的一般格式:(目的网络,下一跳),当然这只是理论上的一般格式,在实际情况中,路由表可能会更复杂,比如会有网关地址、接口等表项,如果是划分了子网的环境下,还必须要有子网掩码的表项。借用谢希仁教授编著的教材上的例图展示一下:

lua 实现路由转发 路由转发原理_IP

谢老师的例图中展示的是路由器R2的路由表,对于R2本身来说,它同时连接着网2和网3,所以当R2收到一个目的IP地址在网2或网3的数据包时,通过查自己的路由表得知是直接交付,所以应该从本身的接口0和接口1转发。

当R2收到一个目的IP地址在网1的数据包时,查自己路由表得知下一跳地址是20.0.0.7,而20.0.0.7是路由器R1的接口1地址,所以R2就会从自己的接口0把此数据包扔给R1。R1得到后,同样也是查自身的路由表,因为网1和路由器R1直接相连,所以R1就知道应该直接交付到网1。(网4同理)。

这就是IP数据包在网络中传送的样子,路由器就是根据IP数据包里面的目的IP地址,然后匹配自己路由表的条目,决定应该把数据包转发给某个其它的路由器或者直接是目的主机,IP数据包就是这样在多个路由器之间一跳一跳的接力传输,直到到达目的主机。


存储转发机制

在实际网络中传输的数据包,并不是像模拟环境那样只有少量的数据包,实际网络上会有大量的数据包要传输,并且要求速度快。当路由器收到数据包的时候,查看目的IP地址,然后查路由表……总要经历这个过程。如果路由器每次只能处理一个数据包,那么正在处理这个包的时候,又来了一个新的包,就只能丢弃,这样效率就会很低。

解决的办法是,使用存储转发机制。在路由器的输入端口和输出端口上开辟一小块缓冲区来暂存数据包,当路由器正在处理一个数据包的时候,如果在这期间后面又来了第二个、第三个以及更多数据包,那么就先暂存在缓冲区中,排队等待处理(这其实是运用了数据结构中队列的先进先出的原理),如果缓冲区满了,实在接收不下了,那就只能把数据包丢弃了。

这就是存储转发,来不及处理的数据包,先暂存下来,然后再进行转发的工作。


特殊路由

1、特定主机路由:一般是由网络管理人员设定的,目的是方便进行网络测试方面的工作。特定主机路由就是为路由器指定一个非常明确的路由,单独指向某台主机。

比如某台主机的IP地址是10.0.0.1,它所在的网络的掩码是:255.0.0.0,在与该网络相连的路由器上单独设置一条专门到达该主机的特定路由:目的网络地址是10.0.0.1,掩码是255.255.255.255,下一跳是直接交付。

上面这个例子说明的是:特定主机路由,目的网络地址不再是某个网络,而是一台特定主机的具体IP地址,掩码也不再是网络的掩码255.0.0.0,而是255.255.255.255。任何特定主机路由的掩码都是255.255.255.255,无论是A/B/C哪一类。

2、默认路由:也叫缺省路由,默认路由在实际应用中作用非常大。如果路由器收到一个IP数据包,查看目的IP地址,然后查自己路由表,直到把所有条目都查找完了,也没有发现合适的下一跳,这时候就会按照默认路由指出的接口把该数据包转发出去。任何匹配不到合适条目的数据包都将走默认路由转发。(但是如果没有设置默认路由,那么路由器只能丢弃该数据包)。

默认路由的写法为:0.0.0.0,0.0.0.0。即目的网络地址和掩码都是全0,即为默认路由。


目的地址的变化

现在我们抛开NAT的概念,只当是没有公网和私网之分。再次应用一下上面谢老师教材上那个例图。

lua 实现路由转发 路由转发原理_lua 实现路由转发_02

假设处于网1的一台主机A,IP地址是10.0.0.1,现在要给处于网3的一台主机B(IP为30.0.0.3)发送数据:

首先主机A把自己的数据准备好,经过网络层封装成数据包,再经过链路层封装成帧。那么现在这个帧要发给谁呢,很明显主机B在网3,而主机A在网1,它们不在同一个网络,所以主机A要去找网关地址,也就是路由器R1的左边接口的地址10.0.0.4(路由器R1其实就相当于是网1的出口路由器,只要是发往除了网1的所有其他网络,那都要通过路由器R1发出去)。

发出去的数据包的源IP地址是主机A本机的10.0.0.1,目的IP地址是30.0.0.3,封装成帧后,源MAC地址是主机A的MAC地址,目的MAC地址是路由器R1的MAC地址(如果你不知道为什么目的MAC地址是R1的MAC地址,而不是主机B的MAC地址,那么请重新回顾一下前面的两个知识点:第一,数据链路层是在相邻两个节点之间的链路上传送帧的;第二,有关ARP代理的内容)。

数据到达R1之后,R1通过数据包里面的IP地址与自己路由表条目匹配,发现应该交给下一跳路由器R2。

当R1要把数据包交给R2的时候,R1要把数据包封装成帧才能在链路上传送,这时候数据包里面的源IP地址10.0.0.1和目的IP地址30.0.0.3不会变,而封装之后的帧:源MAC地址会变成R1自己的MAC地址,目的MAC地址会变成R2的MAC地址。

R2收到后,查看数据包的目的IP地址,通过匹配自己的路由表,得知应该把此数据包从自己的右边接口转交给网3的主机B,此时R2向主机B转发的数据是这样的:数据包中的源IP地址和目的IP地址仍不会变(还是10.0.0.1和30.0.0.3),R2把它封装成帧后,数据帧的源MAC地址就变成了R2自己的MAC地址,目的MAC地址会变成主机B的MAC地址。

通过上面这个过程,我们不难发现这个结论:数据从主机A到主机B的路途中,源IP地址和目的IP地址永远不变,而封装成帧之后的MAC地址是每一跳会变化一次的。