通俗理解IP路由

6次阅读

共计 6362 个字符,预计需要花费 16 分钟才能阅读完成。

日常工作环境中,我们习惯于使用 ping 去测试网络的连通性。如果 ping 不通,我们往往会去怀疑是不是路由配置错了。

路由是什么

我们知道,IP地址是网络世界里的门牌号。你可以通过 IP 地址访问远在天边的网站, 那么数据是如何到达网站的呢?靠的就是路径上每个节点的路由。
路由,简单的说就是指导 IP 报文该去哪的指示牌。

一般说来,主机会在以下两个时机进行路由查询

  1. 收到报文时,查询路由决定是上送本机(LOCAL IN),或者从哪个出接口转发(FORWARD)
  2. 本机发送报文时,查询报文出接口

注意,转发需要开启 net/ipv4/ip_forward

路由表长什么样

以一个典型的主机为例,tristan有一个外部网卡 eth0 和一个内部还回网卡lo

[root@tristan]# ifconfig
eth0      Link encap:Ethernet  HWaddr 00:80:C8:F8:4A:51  
          inet addr:192.168.99.35  Bcast:192.168.99.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:27849718 errors:1 dropped:0 overruns:0 frame:0
          TX packets:29968044 errors:5 dropped:0 overruns:2 carrier:3
          collisions:0 txqueuelen:100 
          RX bytes:943447653 (899.7 Mb)  TX bytes:2599122310 (2478.7 Mb)
          Interrupt:9 Base address:0x1000 

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:7028982 errors:0 dropped:0 overruns:0 frame:0
          TX packets:7028982 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:1206918001 (1151.0 Mb)  TX bytes:1206918001 (1151.0 Mb)

[root@tristan]# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
192.168.99.0    0.0.0.0         255.255.255.0   U     0      0        0 eth0
127.0.0.0       0.0.0.0         255.0.0.0       U     0      0        0 lo
0.0.0.0         192.168.99.254  0.0.0.0         UG    0      0        0 eth0

通过 route -n 我们可以看到主机上简要的路由表信息 (当然通过ip route 也可以),那么上面的路由信息中的每一表项代表什么意思呢?

  • 如果报文的目的 IP 地址在 192.168.99.0/24 这个网段,那么它应该从 eth0 进行转发。
  • 如果报文的目的 IP 地址在 127.0.0.1/8 这个网段,那么它应该从 lo 进行转发。
  • 其他情况下 (0.0.0.0/0),报文从eth0 转发,下一跳 IP 地址是192.168.99.254

第 1,2 条应该都很好理解,比较难以理解的是第 3 条,为什么它的 Gateway 不是全0.0.0.0, 这需要从网络拓扑说起

Gateway

上图左边是一幅典型的网络拓扑。主机之间通过交换机组成一个小型局域网,再通过一个路由器连接到更大的网络。

图中的路由器对于局域网内的主机来说,即可称为 Gateway,一般翻译为 网关 。他的地位如同一个国家的 海关 , 出了 海关 IP 报文就在另一个网络之中了。

回到前面的路由表的第 3 条,当主机发现报文的目的 IP 地址不满足其他表项时,就表示这个报文需要送到局域网外部,所以它会将报文发送或者转发给网关,也就是192.168.99.254。这种情况下,

192.168.99.254被称为 默认网关 ,这条表项也称为 默认路由 。与这个名字对应的,第 1,2 条路由表项也被称为 网段路由

局域网内部通信

当我们为网卡配置 IP 地址时或者由 DHCP 服务器分配 IP 地址,Linux内核会根据 IP 地址和掩码 自动 生成对应的网段路由。这相当于告诉系统,这个网段的主机在同一个局域网内部

举个例子,假设我们在 tristan 主机去 ping 局域网内的 susan 主机。那么这个 ICMP request 报文向下面这样组装就 OK 了。

如果 tristan还不知道 susan 主机上 eth0MAC地址,那么它首先要发送 ARP 广播报文去获得。

局域网外通信

与局域网外的主机通信就需要通过 (via) 网关了

相似的例子,假设我们在 tristan 主机去 ping 局域网外的 paul 主机的 eth0, 在查询路由后,内核选择默认网关,那么组装的ICMP request 的报文头将是下面这样:

设置静态路由

网段路由

有时,系统生成的默认路由并不能满足我们的要求,我们需要手动设置路由

[root@tristan]# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
192.168.99.0    0.0.0.0         255.255.255.0   U     0      0        0 eth0
127.0.0.0       0.0.0.0         255.0.0.0       U     0      0        0 lo
0.0.0.0         192.168.99.254  0.0.0.0         UG    0      0        0 eth0

比如刚才的拓扑,tristan主机要与 jerry 主机所在的网络通信,显然根据现有的路由表,显然是不行的。因此我们需要在 tristan 主机上配置额外的路由表项:

[root@tristan]# route add -net 192.168.98.0 netmask 255.255.255.0 gw 192.168.99.1
[root@tristan]# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
192.168.99.0    0.0.0.0         255.255.255.0   U     0      0        0 eth0
192.168.98.0    192.168.99.1    255.255.255.0   UG    0      0        0 eth0
127.0.0.0       0.0.0.0         255.0.0.0       U     0      0        0 lo
0.0.0.0         192.168.99.254  0.0.0.0         UG    0      0        0 eth0

新添加的路由表项表示本机与 192.168.98.0/24 范围内的主机主机通信,需要途径网关192.168.99.1

使用 ip route 命令也可以达到相同的效果, 通过 via 设置下一跳网关,本质上没有区别

[root@tristan]# ip route add 192.168.98.0/24 via 192.168.99.1

我们甚至可以添加或者删除默认路由

[root@tristan]# route del default gw 192.168.99.254
[root@tristan]# route add default gw 192.168.99.1

主机路由

除了设置整个网段,我们还可以仅为某个目的 IP 设置路由, 即 主机路由 ,主机路由实际上这是掩码为255.255.255.255 的网段路由的特殊形式

[root@tristan]# route add -host 192.168.98.42 gw 192.168.99.1

或者

[root@tristan]# route add -net 192.168.98.42 netmask 255.255.255.255 gw 192.168.99.1

都可以生成一条特定主机的路由,Flags字段中的 H 表示Host

[root@tristan]# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
192.168.99.0    0.0.0.0         255.255.255.0   U     0      0        0 eth0
192.168.98.42   192.168.99.1    255.255.255.255 UGH   0      0        0 eth0
127.0.0.0       0.0.0.0         255.0.0.0       U     0      0        0 lo
0.0.0.0         192.168.99.254  0.0.0.0         UG    0      0        0 eth0

等价路由

等价路由 (ECMP) 是指存在多条链路到达同一目的,链路之间可以起到负载均衡和链路备份的目的,比如下面的拓扑:

在主机 melo 设置的路由如下

[root@melo]# route show scope global
default via 203.0.113.5 dev eth0
192.0.2.0/25
        nexthop via 203.0.113.7  dev eth1 weight 1
        nexthop via 203.0.113.9  dev eth2 weight 1

表示如果报文目的地址是 192.0.2.0/25,那么它将等可能地选择out1 或者 out2 作为出接口。

策略路由

多张路由表

上面提到的所有路由选择都是根据目的 IP 找到对应的路由表项进行的。除此之外,Linux还提供了一种更高级灵活的方式可以完成更加复杂的路由选择策略,这就是 策略路由。它使得用户可以基于源 IP 等信息进行路由配置。

策略路由的基本原理是系统会根据 IP 报文的特征使用不同的路由表。它需要在内核编译时勾选CONFIG_IP_MULTIPLE_TABLES

Linux内核最多支持 256 张路由表, 其中有 4 张是系统默认保留的,用户可以新建 252 张表

/etc/iproute2/rt_tables 可以看到内核保留的 4 张表,其中有用的是local 表和 main

root@ubuntu-1:/home/user1# cat /etc/iproute2/rt_tables 
#
# reserved values
#
255    local
254    main
253    default
0    unspec

local表中存储的是内核自动生成 本机路由 广播路由

当我们使用 route 命令或者不指定路由表时的 ip route 时,操作的表是 main 表,所以我们需要使用额外的参数才能操作和查看 local

[root@real-server]# ip address show dev eth1
6: eth1: <BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast qlen 100
   link/ether 00:80:c8:e8:1e:fc brd ff:ff:ff:ff:ff:ff
   inet 10.10.20.89/24 brd 10.10.20.255 scope global eth1
[root@real-server]# ip route show dev eth1
10.10.20.0/24  proto kernel  scope link  src 10.10.20.89
[root@real-server]# ip route show dev eth1 table local
broadcast 10.10.20.0  proto kernel  scope link  src 10.10.20.89 
broadcast 10.10.20.255  proto kernel  scope link  src 10.10.20.89
local 10.10.20.89  proto kernel  scope host  src 10.10.20.89
[root@real-server]# ip address add 192.168.254.254/24 brd+ dev eth1
[root@real-server]# ip address show dev eth1
6: eth1: <BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast qlen 100
   link/ether 00:80:c8:e8:1e:fc brd ff:ff:ff:ff:ff:ff
   inet 10.10.20.89/24 brd 10.10.20.255 scope global eth1
   inet 192.168.254.254/24 brd 192.168.254.255 scope global eth1
[root@real-server]# ip route show dev eth1
10.10.20.0/24  proto kernel  scope link  src 10.10.20.89 
192.168.254.0/24  proto kernel  scope link  src 192.168.254.254
[root@real-server]# ip route show dev eth1 table local
broadcast 10.10.20.0  proto kernel  scope link  src 10.10.20.89 
broadcast 192.168.254.0  proto kernel  scope link  src 192.168.254.254          
broadcast 10.10.20.255  proto kernel  scope link  src 10.10.20.89               
local 192.168.254.254  proto kernel  scope host  src 192.168.254.254            
local 10.10.20.89  proto kernel  scope host  src 10.10.20.89                    
broadcast 192.168.254.255  proto kernel  scope link  src 192.168.254.254     

一般情况下,我们不应该也没必要操作 local 表,虽然内核并没有禁止用户对 local 表的操作

ip route add table local local 10.10.20.64 dev eth0 proto kernel scope host src 10.10.20.67
ip route add table local local 192.168.43.12 dev eth4 proto kernel scope host src 192.168.43.14

路由表的选择

使用 ip rule 命令,我们可以看到系统选择路由表的规则

[root@real-server]# ip rule show
0:    from all lookup local 
32766:    from all lookup main 
32767:    from all lookup default 

第一项表示默认查找的优先级,数字越小的优先级越高,所以系统默认会从 local 表进行查找。规则中的 from all 表示所有源地址。

我们可以 ip rule 命令添加自定义的规则,

ip rule add from 192.168.101.0/24 table 10  
ip rule add to 192.168.102.0/24 table 20 
ip rule add to 192.168.103.0/24 table 30 prio 123

上面的规则表示来自 192.168.101.0/24 网段的报文都查询 table 10, 目的地址为192.168.102.0/24 网段的报文查询 table 20,目的地址为192.168.103.0/24 网段的报文查询 table 30 且优先级为123

[root@real-server]# ip rule show
0:    from all lookup local 
123:    from all to 192.168.103.0/24 lookup 30 
32764:    from all to 192.168.102.0/24 lookup 20 
32765:    from 192.168.101.0/24 lookup 10 
32766:    from all lookup main 
32767:    from all lookup default 

之后,用户就可以通过 ip route 命令向具体的 table 添加路由表项了。

(完)

正文完
 0