一个数据包的奇幻旅程(下)【译文】

2021-09-02
翻译

主机与主机的通信

在讨论了OSI模型的组成和几个关键的网络设备在网络传输中的作用之后,我们终于可以讨论下主机之间通信的具体细节。
互联的核心思想是两台计算机可以互相通信,尽管两台计算机直接相连的场景很罕见,但是理解两台直连计算机相互通信时发生的事情,对于理解通过交换机或者路由器连接的多台计算机的通信也是至关重要的。接下来我们将关注主机与之际之间通信的细节。

下图演示中没有路由器,即所有的通信都发生在同一个网络内,因此主机A和主机B配置的IP地址属于同一个网络。
image1.png

每台主机都有唯一的IP地址和MAC地址,由于主机也是网络层的设备,所以他们各自的内部也维护有ARP表。不过此时他们的ARP表还是空的。
当主机A向主机B发送数据时,主机A数据的目标IP地址是10.10.10.20,即主机B。主机A当然也知道它自己的IP地址(10.10.10.10),因此主机A可以用源IP地址和目标IP地址创建网络层数据包头。

但是,就像我们之前学到的,数据包的传输是数据链路层的工作,所以尽管两台计算机是直接相连接的,数据链路层数据包头仍然是必须的。
数据链路层数据包头的源MAC地址就是主机A的MAC地址,即aaaa.aaaa.aaa。目标MAC地址应该是主机B的MAC地址,但在此时,主机A的ARP表还没有对应的记录,即它还不能通过主机B的IP地址知道主机B的MAC地址,结果主机A还不能创建数据链路层数据包头,并把数据传输给主机B的网卡。但是主机A会发送一个ARP请求来获取它需要的信息:
image2.png
ARP请求是一个单独的数据包,这个过程本质上就好比在问:IP为10.10.10.20的主机,请把你的MAC地址发送给我。但是记住一点,此时主机A还不知道主机B是否存在,事实上,主机A根本没法知道它已经直接跟主机B相连。因此,这个请求会发送给已连接的所有主机。即ARP请求是以广播的形式发送,所有连接的主机都会收到这个请求。而且主机A会把自己的MAC地址放到这个ARP请求中,这使得主机B能够很容易的把自己的MAC地址直接返回给主机A。
image3.png

接收到ARP的请求后,主机B知道了主机A的IP地址为10.10.10.10,其对应的MAC地址为aaaa.aaaa.aaaa,此时该记录就被添加到了主机B的ARP表。主机B可以利用新的记录直接响应主机A的请求,所以主ARP请求的响应是一条单播消息,直接返回给主机A,连接的其他主机并不会收到这个ARP响应。ARP响应包含了主机A的请求:即IP地址为10.10.10.20的主机B的网卡的MAC地址bbbb.bbbb.bbbb。主机A在收到响应后将该ARP记录包存到自己的ARP表中:
image4.png

主机A有了这条ARP记录,便可以成功的拼装出所需要的数据链路层数据包头,并把数据发送给主机B。主机B一旦接收到数据,能够立即作出响应,因为在主机B的ARP表中已经有了主机A的ARP映射。

需要再次强调的是,主机直接相连的场景是很罕见的,但是理解他们之间的数据传输对于理解后面要讲到的更复杂的场景是很关键的。如通过交换机连接的多台主机的场景和通过路由器相连的多个网络的场景,后面我们会讨论这两种场景。而且需要注意的是,一个主机并不知道它是否被连接到一个交换机或者其他主机,但是不论哪种方式,当主机需要和其他主机的通信时,都会遵循上述所罗列的过程。

通过交换机连接的主机之间的通信

前面的文章我们讨论了两台直连计算机通信时的细节,接下来我们会加入一个常见的设备——交换机。我们会讨论通过交换机连接的主机在通信时的具体细节。之前我们已经讨论过交换机在通信中扮演的关键角色,接下来我们从实际应用的角度再来详细谈论交换机在数据传输中的作用,如果还有不明白的地方,你可以再回顾一下之前的章节。我们会先从单个路由器的功能讲起,然后再通过一个动画看一下多个交换机是如何协作的。

交换机的功能

一个交换机主要有四个功能:学习(Learning)、泛洪(Flooding)、转发(Forwarding)和过滤(Filtering)

学习(Learning)

作为一个数据链路层设备,交换机主要依赖于数据链路层数据包头工作,具体地说,交换机利用源MAC地址和目标MAC地址转发数据包。交换机的目标之一是创建MAC地址表,这个表存储了所连接设备的MAC地址和交换机端口之间的映射。MAC地址表一开始是空的,在每次收到数据时,它会查看数据帧的源MAC地址字段,然后利用源MAC地址和收到数据帧的交换机端口填充MAC地址表。所有连接到交换机的设备迟早都会向交换机发送数据,所以交换机最终能够知道所有连接到它的设备的MAC地址。交换机可以用MAC地址表将数据帧转发到目标设备。

泛洪(Flooding)

然而,尽管交换机有学习功能,但是它仍然可能收到一个未知端口的数据帧,即它不知道将包含了某个MAC地址的数据帧应改被转发到哪个端口。在这种情况下,交换机会简单的把这个数据帧复制,然后发送到所有交换机端口。这种行为即被称为泛洪。
泛洪能够确认目标设备是否存在并已连接到交换机,也保证已连接的目标设备能够最终收到数据帧。当然,其他已连接到交换机的设备也能收到这个数据帧。每个已连接到交换机的设备的网卡会查看数据帧的目标MAC地址字段,如果数据帧不是发给自己的,网卡会丢弃这个数据帧。如果这个数据帧是发给自己的,交换机能够知道数据帧已成功发送给目标设备,因为目标设备收到数据帧后会返回一个响应,交换机收到响应后通过学习的方式记录下这个设备的MAC地址和交换机端口之间的映射。

转发(Forwarding)

理想情况下,交换机知道所有它收到的数据帧的MAC地址的交换机端口,此时交换机只需要将数据帧转发给正确的端口即可。具体地,交换机的转发功能有三种方式,以下是他们的大致区别:

  • 存储转发——交换机复制整个数据帧(包含数据包头和数据)并存储到内存中,然后在转发之前检查数据帧是否包含错误。这种方式是最慢的,但是能够实现错误检查和其他功能,比如为某些特定类型的数据设置不同处理优先级。
  • 直通转发——交换机不保存任何数据,只读取所需要的目标MAC地址并转发数据帧,这种方式是最快的,但是不提供错误检查和其他功能。
  • 无碎片转发——这种方式是前两种的合并,交换机只会在转发之前检查数据帧的前64字节。因为错误的发生通常只出现前64字节。这种方式既能够检查数据帧错误,同时也能兼顾速度和效率,并避免在转发之前将整个数据帧存储到内存中。

需要指出的是,这三种方式在交换机技术发展的初期是很重要的,他们会引起不同程度的数据延迟。但是在现代,线速转发型的交换机已经可以忽略这三种方式间的差异,大多数现代交换机都是以存储转发的模式工作。

过滤(Filtering)

交换机的最后一个功能是过滤,过滤的含义是交换机不会将数据转发到它收到数据的端口。大多数时候,过滤行为发生在泛洪数据帧的时候,此时,交换机会将复制出的数据帧发送给除了接收端口以外的所有交换机端口。一个比较罕见的场景下,主机会将数据帧发给他自己,此时主机要么发生了某种错误,要么受到了恶意攻击。不论哪种情况,交换机都会丢弃这些数据帧。

交换机工作原理

现在我们已经知道了交换机的各种功能,下面通过动画的方式演示四种功能具体过程。通常,主机需要执行ARP请求,但是为了演示交换机的功能,我们省略了这个过程,并假设所有的主机已经知道了IP地址和对应的MAC地址。
image5.gif

主机A有数据需要发送给主机B,数据的内容不重要,只要他的数据帧的头部包含有源MAC地址和目标MAC地址。刚开始时,交换机的MAC地址表是空的,因为它只会在收到一些数据后才有记录。
主机A向交换机发送的数据帧包含他自己的源MAC地址aaaa.aaaa.aaaa。这个数据帧使得交换机通过学习的方式记录下端口1对应的MAC地址是aaaa.aaaa.aaaa。交换机收到数据后要决定它需要将这个数据帧转发到哪个端口,但是交换机意识到他没有MAC地址为bbbb.bbbb.bbbb的端口映射,所以交换机就只剩下一个选择:将数据复制并以泛洪的形式发送给所有端口,当然,除了端口1之外。这主要依赖于交换机的过滤功能。
结果,主机C和主机B都能收到这个数据帧,通过检查数据链路层包头,主机C知道这个数据帧不是发送给他的,所以会丢弃这个数据帧。按照约定,主机B收到这个数据帧时,意识到他是这个数据帧的收件人,它会接收这个数据帧并生成一个响应。
当响应到达交换机,交换机可以学习另外一个MAC地址映射:端口2——MAC地址bbbb.bbbb.bbbb。然后交换机查看响应的目标MAC地址aaaa.aaaa.aaaa,知道这个响应数据帧应该发送到端口1。
上面的动画演示单个交换机的四种功能,如果你想了解多个交换机的处理过程,可以看这篇文章

广播

关于交换机,很多人搞不清楚广播和交换机泛洪行为之间的区别,这很正常,因为这两个概念产生的结果是相同的,但是理解他们之间的区别还是很重要的。
广播说的通常是一个数据帧,这个数据帧的地址是网络中的所有主机。这个数据帧的以太网数据包头跟我们之前讨论的数据包头是一样的,所不一样的是他的目标MAC地址是一个特殊的MAC地址ffff.ffff.ffff。这种特殊的全是f的地址,是一个专门用于广播的保留地址。
根据规范,如果交换机收到了目标地址是ffff.ffff.ffff的数据帧,它应该以泛洪的形式将数据帧发送给所有的端口。(当时,是在学习了源MAC地址之后)从另一个角度看,ffff.ffff.ffff是一个保留地址,交换机不能学习这个MAC地址的映射,因此,包含这种MAC地址的数据帧会以泛洪的形式发送。
总结一下,广播指的是包含了特殊地址ffff.ffff.ffff的数据帧。泛洪是交换机的一种行为。按照规范,交换机会将广播帧会以泛洪的形式发送。但是交换机不会广播一个数据帧,因为广播不是交换的功能。

需要再次声明的是,上面的动画为了演示交换机的功能,省略了地址解析协议的过程(ARP),ARP是客户端的功能,交换机不执行这个过程。上面动画中。我们假设了客户端主机已经知道了每个IP地址对应的MAC地址。ARP的过程,可以这里查看

路由器连接的主机间的通信

前面我们已经了解了两台直连主机的通信,也了解了通过路由器连接的两台主机之间的通信,接下来我们来谈论一下通过路由器连接的主机之间的通信。
我们之前讨论过路由器的作用,接下来我们用一个更加实际的应用来解释路由器的功能。如果对路由器的功能有不理解的,可以回顾之前的章节。
我们以路由器的两个主要功能开始,然后看一下他们在路由器中是怎么工作的。为了能充分讲清楚这些概念,我们利用下面的演示图。我们主要关注R1,它将把数据从主机A发送到主机B和主机C。
image6.png

为了简单起见,每个网卡的MAC地址被简化成一个四位的十六进制数。

路由器功能

之前我们提到过路由器的主要功能是负责网络与网络之间的数据传输。为此,每个路由器会在两个网络之间创建一个边界,他的主要角色是将数据包从一个网络转发到另一个网络。
你可以看到在上面的图片中,R1路由器在网络11.11.11.x和网络22.22.22.x之间创建了一个边界。R2在22.22.22.x和33.33.33.x网络之间创建了一个边界。两个路由器都连接到22.22.22.x网络。为了在网络之间转发数据包,路由器必须要执行两个功能:维护路由表,维护ARP表。

维护路由表

从路由器起的角度来说,路由表存储了指向所有网络的路径。路由表初始时是空的,通过路由学习的方式学习每个网络的路径并将数据填充到路由表。路由器学习每个网络的路径的方式有多种,我们来谈论下两种常见的方式。
最简单的方式就是我们所熟知的直连路由,本质上,当一个路由器配置了一个特定的IP地址,路由器就会知道与他直接相连的网络。例如上图中,R1左边配置的IP地址为11.11.11.1。R1就会知道网络11.11.11.x存在。相同的方式,R1也能通过学习知道网络22.22.22.x存在。
当然,一个路由器不可能直接连接所有的网络,注意上图中,R1没有直接与网络33.33.33.x相连,但是总要一天,R1需要转发网络数据到这个网络,因此,路由器必须依靠另外一种方式学习网络地址,而不仅仅是只通过直连的方式学习。
另外一种方式称之为静态路由,静态路由的路径是网络管理员手动配置的,他就好像告诉R1网络33.33.33.x在R2后边,想要把数据传输到这个网络,就必须先把网络数据包转发给R2。
image7.png

最终,R1学了两个直连路径,加上手动配置的静态路由,R1会有一个类似上图所示的路由表。路由表通常包含很多路由,每个路由包含其他网络或下一跳网络的路径。路由器没收到一个网络数据包,它通过查询查询路由表,来决定将数据转发到哪里。
需要再次强调的是,路由表是每个网络是否存在的映射路径(从每个路由器的角度看)。如果一个路由器收到一个数据包,它的目标地址在路由表中不存在,路由器会认为该网络不存在,并丢弃这个数据包。
最后一种路由学习的方式称之为动态路由,这种方式通过探测和通信的方式学习网络路由,为了做到这一点,动态路由需要用到各种个样的网络协议,不同的协议代表的不同的策略,但是讲述他们的区别远远超出本文的主题,读者可自行研究。
总的来说,路由表告诉路由器应该将数据转发到哪个IP地址。但是就像我们之前学习的,网络数据包的转发永远是数据链路层的工作,路由器为了能将数据包传输到下一个网络地址,就要创建数据链路层数据包头,因为路由器还必须维护一个ARP表。

维护ARP表

地址解析协议(Address Resolution Protocol,ARP)是网络层和数据链路层的桥梁,设备利用ARP协议来维护ARP表,或者有时候称为ARP缓存,他存储了IP地址和MAC地址的映射关系。路由器通过查询路由表得知需要将数据转发到下一个网络的IP地址,如果该路由是直连网络,那么“下一个网络”即最终的目标网络。
不论哪种方式,路由器都会以数据链路层数据帧的方式将网络数据包传输至正确的网卡。与路由表不同,ARP表是按需维护,如上图所示的R1在收到发往主机B的数据包之前,不会发送ARP请求获取主机B的MAC地址。
但是就像我们之前讨论的,ARP表存储的是IP地址到MAC地址的简单映射关系,当R1的ARP表被填满时,他看起来如下图所。
image8.png

需要再次说明的是,为了简单起见,以上所有的演示图利用4位的十六进制数来表示MAC地址,现实中,MAC地址是一个12位的十六进制数,简单的将4位十六进制数重复三次即可得到正确的MAC地址,如R2左侧的真实MAC地址是bb22.bb22.bb22。

路由器职责

理解路由器是如何维护路由表和ARP表之后,我们来看一下路由器是如何利用这两个表来完成两个网络的通信的。在上面的R1的路由表中,可以看到两种类型的路由:一种指向一个网络接口,另一种指向下一跳的IP地址,我们讨论的路由器的职责将会限定在这两种情况之内。但是首先,我们先讨论下主机A如何将网络数据包传输至默认网关R1,然后我们会看一下R1在将数据包从主机A传递到主机B或从主机A到主机C的过程中做了什么。

主机A将数据传输至R1

image9.png

在上面的两种例子中,主机A都是与外部网络的主机进行通信,因此主机A需要先将数据包传输至默认网关R1.
主机A利用自己的源IP地址11.11.11.77和主机B的目标IP地址22.22.22.88(或主机C的目标IP地址33.33.33.99)来封装网络层数据包头,网络层数据包头负责端到端的数据传输。但是只有网络层数据包头还不足以使网络数据包传输至R1,必须要有额外的机制来做到这一点。
主机A会利用源MAC地址aaaa.aaaa.aaaa和目标MAC地址aa11.aa11.aa11——R1网卡的MAC地址封装数据链路层数据包头,并把网络层数据包头封装到数据链路层数据体中。数据链路层数据包头负责将网络数据包传输至下一跳。
通常情况下主机A已经配置了默认网关的IP地址,并且我们可以理想的认为主机A层将和外部网络的主机发生过网络通讯,所以主机A很可能已经可以通过ARP表知道R1的MAC地址。相反的,如果主机A是第一次与外网主机通信,则之前一步的数据链路层数据包头需要执行一次ARP请求来获取R1的MAC地址才能完成封装。当R1拿到网络数据包,数据包的目标是发往IP地址为22.22.22.88的主机B或者IP地址为33.33.33.99的主机C,这两个IP地址在R1的路由表中都存在,区别是一个路由是指向一个网络接口的,一个是指向下一跳的。

指向网络接口的路由

指向网络接口的路由通常是通过路由学习的方式获得的,因为该网络是与路由器直接相连的,如果网络数据包的目标IP地址是与路由器直接相连的,那么路由器知道它正把数据包传输给最终目标网络(跳)。
过程与之前讨论的有些相似,路由器利用网络层数据包的信息决定下一步将网络数据包发往哪里,然后创建数据链路层包头将网络数据包传输到那里。
image10.png

在传输的过程中,网络层数据包头保持不变,即,由主机A创建的网络层包头是相同的。所不同的是数据链路层包头。注意源MAC地址是bb11.bb11.bb11——R1的右侧接口MAC地址。主机A创建的老的数据链路层包头在传输到R1后被剥离,R1生成了新的数据链路层包头,使得网络数据包可以被传输至下一个网卡。当然,下一个网卡的MAC地址bbbb.bbbb.bbbb是目标主机B的MAC地址。

指向下一跳的路由

对于从主机A发送到主机C的网络数据包来说,目标的IP地址是33.33.33.99,R1查询自己的路由表得知下一跳网络33.33.33.x存在于IP地址为22.22.22.2的路由器R2的左边。
这相当于告诉R1,需要利用数据链路层数据包头将网络数据包发送至R2,以便数据包能被继续向下转发。由于当前“跳”在R1和R2之间,他们的MAC地址即为源MAC地址和目标MAC地址。
image11.png

并且网络层包头的信息是不变的,他的源IP地址和目标IP地址还是最初由主机A设置的。这两个IP地址代表的是两个通信的终端。如果R1没有R2的MAC地址,它会向IP地址为22.22.22.2的设备发送ARP请求,之后R1就能够利用这两个MAC地址创建数据链路层包头。
上面的过程之后,R2最终会收到这个网络数据包,此时R2的情况和上面R1的情况是一样的。整个过程可以按需要不断的重复,如主机A和主机X通信的路径上有十个路由器,这个过程是相同的。每个中转的路由器都有主机X的网络到下一跳网络IP的映射,知道路由器发现主机X的网络是直连的,最终的路由器会负责将数据发送给主机X。