数据链路层实现了链路接入功能,负责将数据从一个节点传输到相邻的节点。
数据链路层的协议很多,以太网是其中最为流行的一个。通过以太网通信的主机,需要连接到同一个以太网网络。不管采用何种设备,以何种方式连接,以太网从逻辑上都可以抽象成这样:
以太网中的主机都是邻居关系,任何主机都可以通过以太网帧与其他主机进行直接通信。
当然了,设备和连接方式会影响通信的效率,但不会改变通信逻辑。
单个以太网的规模是非常有限的,但我们可以用网络层设备—— 路由器 ,将多个以太网组织成更大的网络。大网络内的所有主机,都可以通过网络层协议—— IP协议 ,进行通信。
为了彻底理解网络层、IP协议以及路由器的工作原理,我们构建一个极简网络拓扑,深入研究:
图中有两个以太网络,分别是以太网①和以太网②。以太网①中有三台主机,分别是 ant 、bee 和 cicada ;以太网②中有两台主机,apple 和 banana ;中间的路由器,同时接入这两个以太网。
我们给以太网①中的通信实体,分配一个 192.168.1.x 段的 IP 地址:
通信实体 | 网卡 | MAC地址 | IP地址 |
---|---|---|---|
路由器 | eth1 | fa:1c:b2:d0:b0:01 | 192.168.1.1 |
ant | eth0 | 1e:1f:84:08:d2:aa | 192.168.1.2 |
bee | eth0 | e6:04:b1:10:f1:bb | 192.168.1.3 |
cicada | eth0 | ce:ba:ec:ff:fd:cc | 192.168.1.4 |
同样,给以太网②中的通信实体,分配一个 192.168.2.x 段的 IP 地址:
通信实体 | 网卡 | MAC地址 | IP地址 |
---|---|---|---|
路由器 | eth2 | ee:21:30:4a:5a:02 | 192.168.2.1 |
apple | eth0 | b6:f1:81:44:21:11 | 192.168.2.2 |
banana | eth0 | 22:5b:7c:b3:d6:22 | 192.168.2.3 |
此外,每个通信实体还需要配置路由表,我们列举几个例子:
通信实体 | 规则 |
---|---|
ant | 192.168.1.x 直接从eth0网卡发出去;192.168.2.x 先发给192.168.1.1,由它负责转发 |
bee | 192.168.1.x 直接从eth0网卡发出去;192.168.2.x 先发给192.168.1.1,由它负责转发 |
apple | 192.168.2.x 直接从eth0网卡发出去;192.168.1.x 先发给192.168.2.1,由它负责转发 |
路由器 | 192.168.1.x 直接从eth1网卡发出去;192.168.2.x 直接从eth2网卡发出去 |
路由表准备好后,主机就可以互相通信了,分为两种不同场景:
- 本地网通信,例如 ant-bee ;
- 网际通信,例如 ant-apple ;
本地网通信
主机 ant 和 bee 接入同一个以太网络,它们的 IP 地址也在同一段,这样与主机直接连接的网络称为 本地网 。同一网络内的主机可以直接通信,无须借助第三方。具体如何进行呢?
假设主机 ant 通过 IP 协议向主机 bee 发送数据,数据封装成 IP 包,其中:
- 源地址 是 ant 的 IP 地址,即: 192.168.1.2
- 目的地址 是 bee 的 IP 地址,即: 192.168.1.3
IP 包封装好后,主机查询路由表:去往 192.168.1.x 网段的 IP 包,可以直接从 eth0 网卡发出去。这表明:目标网络就是 eth0 网卡接入的本地网络,该 IP 包可以通过以太网帧直接发给目标主机。
接着,主机将 IP 包封装到以太网帧中,从 eth0 网卡发送出去,其中:
- 源地址 是 ant 主机 eth0 网卡的 MAC 地址,即: 1e:1f:84:08:d2:aa
- 目的地址 是 bee 主机 eth0 网卡的 MAC 地址, e6:04:b1:10:f1:bb
那么,主机 ant 怎么知道 192.168.1.3 这台主机( bee )的 MAC 地址呢?实际上,主机 ant 内部需要维护一张映射表,记录本地网主机 IP 到 MAC 地址的映射关系:
IP地址 | MAC地址 | 备注 |
---|---|---|
192.168.1.1 | fa:1c:b2:d0:b0:01 | 路由器 |
192.168.1.3 | e6:04:b1:10:f1:bb | bee |
192.168.1.4 | ce:ba:ec:ff:fd:cc | cicada |
至于这个映射表是如何获得的,谜底将在 ARP 协议一章揭晓。
主机 bee 接到以太网帧后,即可取出 IP 包,进而取出封装在其中的数据。
这就是本地网主机通过 IP 协议通信的全过程,请结合下图理解,重点体会 IP 包和以太网帧的地址:
网际通信
主机 ant 和 apple 位于不同的网络中,IP 地址也不在同一段,无法直接通信。这种跨网络通信称为 网际通信 ,需要借助 路由器 来实现。具体步骤又是怎样的呢?
假设主机 ant 通过 IP 协议向主机 apple 发送数据,数据封装成 IP 包,其中:
- 源地址 是 ant 的 IP 地址,即: 192.168.1.2
- 目的地址 是 apple 的 IP 地址,即: 192.168.2.2
IP 包封装好后,主机查询路由表:去往 192.168.2.x 网段的 IP 包,需要先发给路由器 192.168.1.1 ,由它负责转发。由于路由器 192.168.1.1 位于本地网,主机可以将 IP 包搭载在以太网帧中,通过 eth0 网卡发给它。
主机先根据路由 IP 地址从映射表中取出路由的 MAC 地址,然后完成以太网帧封装,其中:
- 源地址 是 ant 主机 eth0 网卡的 MAC 地址,即: 1e:1f:84:08:d2:aa
- 目的地址 是路由器 eth1 网卡的 MAC 地址, fa:1c:b2:d0:b0:01
当路由器接到以太网帧后,从中取出 IP 包,发现它是发往 192.168.2.2 的。路由器同样查询路由表,发现: 192.168.2.x 是个直连的本地网络,可以通过 eth2 网卡直接通信。
路由器从内部映射表中查到 192.168.2.2 对应的 MAC 地址,并将 IP 封装在以太网帧中从 eth2 网卡发出去:
- 源地址 是路由器 eth2 网卡的 MAC 地址,即: ee:21:30:4a:5a:02
- 目的地址 是 apple 主机 eth0 网卡的 MAC 地址,即 b6:f1:81:44:21:11
主机 apple 接到以太网帧后,即可取出 IP 包,进而得到 ant 发给它的数据。
这就是网际主机通过 IP 协议通信的全过程,请结合下图理解,重点体会 IP 包和以太网帧封装和转发步骤:
实验演示
本文讨论的网络拓扑环境,同样由 docker 提供,只需执行以下命令即可一键打开:
|
|
如果屏幕出现 press Ctrl-C to exit
说明实验环境已经成功启动,实验完毕后,输入 Ctrl-C
即可一键退出。
实验环境启动后,只需执行以下命令,即可进入主机 ant :
|
|
如果看到这个熟悉的命令行提示符,说明已经成功进入主机 ant :
|
|
先观察一下主机 ant 网卡 eth0 的情况,重点它的 MAC 地址和 IP 地址:
|
|
这里看到的信息跟前面的表格是一致的。
将上一个命令中的 ant 改成 router ,执行即可进入中间的路由器;同理,我们可以进入主机 bee :
|
|
同样先观察 eth0 网卡上的地址信息,跟前面的表格是一致的:
|
|
接下来我们观察路由表,可以用 route 命令或者 ip 命令,以主机 ant 为例:
|
|
route 命令输出两条路由规则,每条占一行,分别有目的地、网关、子网掩码、标志位以及出口设备等好几列。其中,目的地结合子网掩码确定目的网段,例如 192.168.1.0/255.255.255.0 表示 192.168.1.x 这个网段。
子网掩码将在后面章节详细介绍,这里只需有一个大概印象即可。
第一条路由记录(第 4 行)的意思是,去往 192.168.1.x 网段的 IP 包,都可以通过 eth0 直接发送出去。网关 0.0.0.0 表示 IP 包无须通过任何路由中介进行转发,也就是说 192.168.1.x 网段是一个本地网段,可以直接通信。
第二条路由记录(第 5 行)的意思是,去往 192.168.2.x 网段的 IP 包,需要先发给 192.168.1.1 ,由它负责转发;而网关 192.168.1.1 可以通过 eth0 网卡直接通信。
ip 是一个比较新的命令,更推荐使用。它输出的路由信息相对来说更紧凑:
|
|
192.168.1.0/24 是子网掩码的另一种表示法,代表 192.168.1.x 这个网段,具体细节将在后续章节展开介绍。
第一条路由的意思是,去往 192.168.1.x 网段的 IP 包,可以直接从 eth0 网卡中发送出去;第二条路由则表示,去往 192.168.2.x 也可以通过 eth0 网卡发送,但必须先发给 192.168.1.1 ,由它负责转发。
很显然,主机 ant 上的这两条路由,特征显著不同:
- 第一条属于 直接路由 ,目的网段是本地网,可以通过网卡直接发送出去,属于 本地网通信 场景;
- 第二条属于 间接路由 ,目的网段是其他网络,需要通过路由转发,属于 网际通信 场景;
路由种类 | 通信场景 | route命令特征 | ip命令特征 |
---|---|---|---|
直接路由 | 本地网通信 | 网关为空,即0.0.0.0;标志位不带G | 不带via |
间接路由 | 网际通信 | 网关非空;标志位带G | 带via |
现在,尝试在主机 ant 上,向主机 bee 发送 IP 包。我们使用 ping 命令,它可以向目标主机发送一个特殊的 IP 包;主机接到这样的包后,将返回另一个 IP 包作为响应,以此检查网络是否畅通。
开始之前,我们分别在主机 bee 和路由器 router 上运行 tcpdump 程序,观察可能达到的 IP 包:
|
|
|
|
tcpdump -e 参数用于显示以太网帧头部信息。
现在,回到主机 ant ,执行 ping 命令,向 bee 发出一个 IP 包:
|
|
命令输出显示,主机 ant 很快就收到 bee 响应的回包,往返时间在 0.2 毫秒左右。
主机 bee 上,tcpdump 观察到 ant 发来的 IP 包以及系统自动回复的响应包:
|
|
第一行是主机 bee 接到主机 ant 的来包,关键字 In
表示入站。该包是 1e:1f:84:08:d2:aa 发来的以太网帧,以太类型是 0x0800 ,数据承载着一个 IP 包;IP 包是由 192.168.1.2/ant 发到 192.168.1.3/bee 的。
IP 包中还承载着一个 ICMP 协议的包,用于探测主机连通性,我们先按下不表。
第二行是主机 bee 回复主机 ant 的响应包,关键字 OUT
表示出站,请结合上一个对照理解。
注意到,路由器 router 可能也会收到这个包,这是为什么呢?
|
|
我们知道,IP 包承载在以太网帧中从 1e:1f:84:08:d2:aa/ant 发往 e6:04:b1:10:f1:bb/bee 。还记得以太网协议中学到的内容吗?以太网交换机一开始可能还没有学习到主机 bee 的地址 e6:04:b1:10:f1:bb ,因此只能将该帧广播到所有端口。这就是路由器 router 也收到到这个包的原因,这种情况下其他主机 bee 和 cicada 也会收到。
注意到,路由器知道这个包不是发给自己的。关键字 P
表明,这是一个发往其他主机的帧,因网卡开启混杂模式而被嗅探到。路由器系统协议栈不会处理该包,因此也不会回复响应包。
回过头来执行 arp 命令查看主机 ant 上维护的本地网主机 IP 和 MAC 地址的映射表:
|
|
主机 ant 就是根据这个映射表,找到 192.168.1.3 对应的 MAC 地址,从而完成以太网帧的封装和发送的。至于这个映射表是如何获得的,同样先按下不表,等到介绍 ARP 协议时再揭晓。
最后,考察一下网际通信的场景。先进入路由器 router ,观察它的路由表:
|
|
router 只有两条直接路由,因为两个网络都与路由直接相连,它可以与图中任一台主机进行直接通信。
以主机 ant 向 主机 apple 发包为例,我们先在 router 和 apple 上执行 tcpdump 命令,观察网络流量:
|
|
|
|
回到主机 ant ,执行 ping 命令向主机 apple 发送一个 IP 包,它的 IP 地址是 192.168.2.2 :
|
|
主机 ant 路由规则显示,去往 192.168.2.x 网段的 IP 包,需要先发给本地网上的 192.168.1.1 ,由它转发。ant 从自己的映射表中找到 192.168.1.1 的 MAC 地址,并封装以太网帧,将 IP 包作为帧数据发送出去。
这时,我们可以在路由上观察到这个 IP 包:
|
|
第一行显示的是 eth1 网卡收到 ant 发来的帧, In
表示入站。帧的源地址是 ant 的 MAC 地址,以太类型表明该帧承载着一个 IP 包。IP 包是从 192.168.1.2/ant 发到 192.168.2.2/apple 的。
路由器查询本地路由表,知道 IP 包的目的网段 192.168.2.x 是一个本地网,可以通过 eth2 网卡直接通信。查询本地的 IP/MAC 地址映射表后,路由器知道 192.168.2.2 的 MAC 地址 ee:21:30:4a:5a:02 。
正如第二行显示的那样,路由器可以将 IP 包封装在以太网帧中,通过 eth2 网卡发给主机 apple 。其中, Out
表示出站,帧的目的地是 ee:21:30:4a:5a:02/apple ,帧中承载的是 ant 发给 apple 的 IP 包。
同样可以观察到主机 apple 接到 IP 包后,回复一个响应包,细节就不再赘述了:
|
|
根据 apple 的路由规则,响应包同样被发给路由器,从 eth2 网卡进入,正如路由器观察到的第三行。路由器则接力将响应包从 eth1 网卡转发给主机 ant ,正如第四行。
FAQ
Linux系统如何获取下一跳网关(路由)的IP地址?
我们知道,一个 IP 包下一跳应该发给谁是系统路由表决定的。因此我们只需查询路由表,即可获取下一跳网关的地址。执行 route 命令即可查询系统当前路由表:
|
|
这个例子中第 5 行是一条直接路由,本地直连网络可以通过网卡直接发给目的主机;第 4 行是一条默认路由,即发往其他 IP 地址的 IP 包,下一跳发给网关 10.0.8.1 。如果路由表比较复杂,配置了多个网卡,那么需要根据目的 IP 和网段,看匹配哪个网关。
执行 ip route 命令也可以查询系统当前的路由表,默认它会列出所有路由记录:
|
|
想要直接查询去往某个目的地的路由记录,可以这样查询:
|
|
这次我们直接取出了决定目的地址 8.8.8.8 的路由记录,这表明发给 8.8.8.8 的 IP 包需要发给网关 10.0.8.1 。
【小菜学网络】系列文章首发于公众号【小菜学编程】,敬请关注: