使用 iproute2 进行 MultiHoming 设置
iproute2,也就是ip(8)这个命令的功能是非常强大的,之前就曾经用它建隧道之类的,但从来没涉及过路由,毕竟找不到什么不用 route(8) 命令的理由。不过,这次我们找到了一个——当你需要两个缺省路由的时候,该怎么配置?
按:这个是新研究出来的,有什么不对的地方敬请指出哈
iproute2
iproute2 是一整套网络设置工具,涵盖从网口(link, address)、ARP(neigh)、路由(rule, route)、隧道(tunnel)等各个方面,是 Linux 2.2 (如果没记错的话,应该有十三四年了吧)以来的网络“新”特性的用户态工具,可以替代 arp、ifconfig、route 这些经典但不够完善的工具。
如果你要搭 ipip 或 gre 隧道,无疑要使用 iproute2 的 ip tunnel 命令了,除此之外,你还能想到第二个用 iproute2 的场景么?我就遇到了一个——
问题背景:两张路由表
如果你有一台服务器,有两张网卡,对应了两个网络出口,都能连到目标网络,这时,怎么设置下一跳路由呢?经典的 route 设置,只有一个缺省路由条目可以生效的。你当然可以设置,让一部分目标地址走一个路由,另一部分目标地址走另一个路由,但是有两个问题:
- 这样,流量很难均衡使用两个路由
- 包从哪个网口进来是无法通过自己的路由表选择的,所以,如果按照上面那种划分方法,只要进入的包没有按照我们的期待分区划分,那么就无法正确地回复,也可能会被 rp_filter 直接过滤掉。
嗯,那么,怎么同时用上两块网卡呢——
我们需要按照出发 IP 划分,使用源 IP1 的包,走第一块网卡,使用 IP2 的包,走第二块网卡。(先不考虑未指定的)
但是,IP路由的基本哲学是——按照目的地址,从路由表里查询,不可能按照源地址来整路由表,于是,问题就变成了这样——
我们需要为每个 src IP 建立一张路由表:从第一个IP出来的包,进第一张路由表,出第一块网卡;从第二个IP出来的包,进第二张路由表,出第二块网卡。
思路很简单,但是 route(8) 命令在这里就束手无策了,嗯,看 iproute2 的:
多张路由表(rule)
好了,不卖关子了,iproute2 本来就支持多张路由表,配置文件位于这里:
root@swipe:~# cat /etc/iproute2/rt_tables # # reserved values # 255 local 254 main 253 default 0 unspec # # local # #1 inr.ruhep
已经有三张表了:
root@swipe:~# ip rule ls 0: from all lookup local 32766: from all lookup main 32767: from all lookup default
这三张表都对所有的IP来源生效(from all),这其中,main 就是我们通常设置的路由规则,
root@swipe:~# ip route ls table main default via 192.168.12.1 dev eth0 proto static 169.254.0.0/16 dev eth0 scope link metric 1000 192.168.12.0/24 dev eth0 proto kernel scope link src 192.168.12.104 metric 1 root@swipe:~# route Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface default localhost 0.0.0.0 UG 0 0 0 eth0 link-local * 255.255.0.0 U 1000 0 0 eth0 192.168.12.0 * 255.255.255.0 U 1 0 0 eth0
default表是空的,而local表则是本机链路的设置。如果我们需要,可以人为加入新规则(路由表)
root@swipe:~# echo "200 rt2" >> /etc/iproute2/rt_tables root@swipe:~# ip rule add from 192.168.12.111 table rt2 root@swipe:~# ip rule ls 0: from all lookup local 32765: from 192.168.12.111 lookup rt2 32766: from all lookup main 32767: from all lookup default
这样,来自 192.168.12.111 的包就可以先进入 rt2 这张表了
路由设置
现在要做的是为每张表设置路由
root@swipe:~# ip route add 192.168.12.0/24 dev eth1 table rt2 root@swipe:~# ip route add default via 192.168.12.254 dev eth1 table rt2 root@swipe:~# ip route flush cache
对于本机发出的包,应该可以以某种机会,比较均衡地选择任意路由出去
root@swipe:~# ip route add default scope global nexthop via XX.XX.XX.XX dev eth0 weight 1 \ nexthop via XX.XX.XX.XX dev eth1 weight 1
当然,这种基于路由表的负载均衡并不能做到完全均匀,毕竟路由表是可以被缓存的。
说明:上面的设置例子是在一台只有一块网卡的机器上码的,不过在写blog之前是在有两块网卡的机器上操作的,就是那个机器不方便写blog,所以看着细节上可能有点味道不太对,没关系哈
参考
下面是一些参考文献:
- Linux Advanced Routing & Traffic Control HOWTO : http://lartc.org/howto/index.html
- ip-cref : http://users.cis.fiu.edu/~esj/cnt4504/reading/ip-cref.pdf