Switch-Router

通俗理解IP路由

Published at 2019-01-13 | Last Update 2019-01-13

日常工作环境中,我们习惯于使用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添加路由表项了。

(完)