参与网络通信的各种主体可以抽象成一张 图 ( graph ),每个主体是图的 节点 ( node ),连接关系则是图的 边 ( edge )。
环 ( cycle ),一种首尾相连的特殊路径,是图论中重点研究的对象。那么,IP 包有没有可能陷入环形的路径,在回路中空转呢?如果这样的话,它不就永远无法到达目的地了吗?
在特殊的路由规则下,IP 包确实会陷入回路,下面是一个简单的例子:
请注意 3 台路由器中,关于 10.0.10.0/24 这个网段的路由规则:R1 上的规则说,应该发给 R2 来转发;R2 上的规则说,应该发给 R3 来转发;R3 上的规则说,应该发给 R1 来转发。
这 3 台路由器,就像三个挑水和尚,互相推诿。一个去往 10.0.10.0/24 网段的 IP 包进来后,傻转了一圈又回到入口处。此后,该包将不停打转,永远无法逃逸出去,更别说到达目的地。
IP 包无法达到目的地事小,拖垮路由事大。如果陷入环路的包无法清理,最终将耗尽线路的带宽和路由器的处理资源,影响正常数据的传输,造成大量丢包。
那么,有什么办法可以解决这个问题吗?
第一个思路是从根源解决问题,减少路由规则因缺陷形成回路的可能。由于网络拓扑通常很复杂,我们很难完全避免路由环路。以配置静态路由规则为例,很难保证配置规则的人不会犯错。
因此,我们还需要第二个思路,降低路由环路的影响。
还记得 IP 包的 TTL 字段吗?TTL 是 time to live 缩写,表示 IP 包的存活时间。一旦 IP 包存活时间超过 TTL ,路由便将它丢弃。这样一来,就算 IP 包陷入环路,经过一小段时间后,它也会从网络中消失,不会造成更大的影响。
网络中路由器数量巨大,很难做到时间同步。因此,在实际工程实现中,TTL 并不是直接保存存活时间,而是保存 IP 包失效前可以经过的路由跳数。IP 包每经过一跳路由,TTL 都会减一;当 TTL 减到 0 ,路由便将它丢弃。
有了 TTL 机制后,就算 IP 包陷入路由环路,循环若干次后,最终将自行消失,不会造成更大的影响:
回到 TTL 字段,它的长度是 8 比特。因此,一个 IP 包失效前最多可以经过 255 跳路由。你可能会有点诧异,区区 255 跳就可以将 IP 包送达目的地吗?
现行的 IP 网络看似非常庞大,但得益于骨干网络优化,任意两点的最短路径并不长。笔者在大洋彼岸的美国加州有一台 VPS 服务器,如果从广州家中出发,只需大约 13 跳即可达到。如此看来,TTL 最大值为 255 ,其实绰绰有余。
实际上,在很多系统协议栈中, IP 包默认 TTL 都不会有 255 跳之多;而且因系统不同还略有差异:
- Windows 系统,IP 包默认 TTL 为 128 ;
- Linux 系统,IP 包默认 TTL 为 64 ;
当然了,我们可以根据实际情况调整系统的默认 TTL 。以 Linux 为例,默认 TTL 是一个内核参数,可以通过 procfs 来访问,路径是 /proc/sys/net/ipv4/ip_default_ttl
。
执行 cat 命令,将该 procfs 文件内容输出即可查看当前配置:
|
|
将新值写入该 procfs 文件即可完成设置,例如将它改成 128 :
|
|
再次查看配置,可以确认它已经生效了:
|
|
【小菜学网络】系列文章首发于公众号【小菜学编程】,敬请关注: