Merge branch 'master' of git://github.com/plusjade/jekyll-bootstrap
[GalaxyBlog.git] / _posts / 2012-04-25-zt-use-iproute2-to-multihoming.md
blob257013025ca3bdb23afe2fefd9d439f12e2835d8
1 ---
2 layout: post
3 slug: zt-use-iproute2-to-multihoming
4 title: "[ZT]使用 iproute2 进行 MultiHoming 设置"
5 description: ""
6 category: Linux
7 tags: [ZT, Tips, TCP/IP, net]
8 ---
9 {% include JB/setup %}
11 http://wangxu.me/blog/p/675<br>
12 April 21st, 2012 by gnawux
14 <font color="navy">有机会用的话,是很有用的……<br>博客应该是北邮某人的,内容不错。</font>
15 * * *
17 iproute2,也就是ip(8)这个命令的功能是非常强大的,之前就曾经用它建隧道之类的,但从来没涉及过路由,毕竟找不到什么不用 route(8) 命令的理由。不过,这次我们找到了一个——当你需要两个缺省路由的时候,该怎么配置?
19     按:这个是新研究出来的,有什么不对的地方敬请指出哈
21 ## iproute2 ##
23 iproute2 是一整套网络设置工具,涵盖从网口(link, address)、ARP(neigh)、路由(rule, route)、隧道(tunnel)等各个方面,是 Linux 2.2 (如果没记错的话,应该有十三四年了吧)以来的网络“新”特性的用户态工具,可以替代 arp、ifconfig、route 这些经典但不够完善的工具。
25 如果你要搭 ipip 或 gre 隧道,无疑要使用 iproute2 的 ip tunnel 命令了,除此之外,你还能想到第二个用 iproute2 的场景么?我就遇到了一个——
27 ## 问题背景:两张路由表 ##
29 如果你有一台服务器,有两张网卡,对应了两个网络出口,都能连到目标网络,这时,怎么设置下一跳路由呢?经典的 route 设置,只有一个缺省路由条目可以生效的。你当然可以设置,让一部分目标地址走一个路由,另一部分目标地址走另一个路由,但是有两个问题:
31 <ul>
32         <li>这样,流量很难均衡使用两个路由</li>
33         <li>包从哪个网口进来是无法通过自己的路由表选择的,所以,如果按照上面那种划分方法,只要进入的包没有按照我们的期待分区划分,那么就无法正确地回复,也可能会被 rp_filter 直接过滤掉。</li>
34 </ul>
36 嗯,那么,怎么同时用上两块网卡呢——
38     我们需要按照出发 IP 划分,使用源 IP1 的包,走第一块网卡,使用 IP2 的包,走第二块网卡。(先不考虑未指定的)
40 但是,IP路由的基本哲学是——按照目的地址,从路由表里查询,不可能按照源地址来整路由表,于是,问题就变成了这样——
42     我们需要为每个 src IP 建立一张路由表:从第一个IP出来的包,进第一张路由表,出第一块网卡;从第二个IP出来的包,进第二张路由表,出第二块网卡。
44 思路很简单,但是 route(8) 命令在这里就束手无策了,嗯,看 iproute2 的:
46 ## 多张路由表(rule) ##
48 好了,不卖关子了,iproute2 本来就支持多张路由表,配置文件位于这里:
49 {% highlight bash %}
50 root@swipe:~# cat /etc/iproute2/rt_tables
52 # reserved values
54 255 local
55 254 main
56 253 default
57 0   unspec
59 # local
61 #1  inr.ruhep
62 {% endhighlight %}
64 已经有三张表了:
65 {% highlight bash %}
66 root@swipe:~# ip rule ls
67 0:  from all lookup local
68 32766:  from all lookup main
69 32767:  from all lookup default
70 {% endhighlight %}
72 这三张表都对所有的IP来源生效(from all),这其中,main 就是我们通常设置的路由规则,
73 {% highlight bash %}
74 root@swipe:~# ip route ls table main
75 default via 192.168.12.1 dev eth0  proto static
76 169.254.0.0/16 dev eth0  scope link  metric 1000
77 192.168.12.0/24 dev eth0  proto kernel  scope link  src 192.168.12.104  metric 1
78 root@swipe:~# route
79 Kernel IP routing table
80 Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
81 default         localhost       0.0.0.0         UG    0      0        0 eth0
82 link-local      *               255.255.0.0     U     1000   0        0 eth0
83 192.168.12.0    *               255.255.255.0   U     1      0        0 eth0
84 {% endhighlight %}
86 default表是空的,而local表则是本机链路的设置。如果我们需要,可以人为加入新规则(路由表)
87 {% highlight bash %}
88 root@swipe:~# echo "200 rt2" >> /etc/iproute2/rt_tables
89 root@swipe:~# ip rule add from 192.168.12.111 table rt2
90 root@swipe:~# ip rule ls
91 0:  from all lookup local
92 32765:  from 192.168.12.111 lookup rt2
93 32766:  from all lookup main
94 32767:  from all lookup default
95 {% endhighlight %}
97 这样,来自 192.168.12.111 的包就可以先进入 rt2 这张表了
99 ## 路由设置 ##
101 现在要做的是为每张表设置路由
102 {% highlight bash %}
103 root@swipe:~# ip route add 192.168.12.0/24 dev eth1 table rt2
104 root@swipe:~# ip route add default via 192.168.12.254 dev eth1 table rt2
105 root@swipe:~# ip route flush cache
106 {% endhighlight %}
108 对于本机发出的包,应该可以以某种机会,比较均衡地选择任意路由出去
109 {% highlight bash %}
110 root@swipe:~# ip route add default scope global nexthop via XX.XX.XX.XX dev eth0 weight 1 \
111  nexthop via XX.XX.XX.XX dev eth1 weight 1
112 {% endhighlight %}
114 当然,这种基于路由表的负载均衡并不能做到完全均匀,毕竟路由表是可以被缓存的。
116 说明:上面的设置例子是在一台只有一块网卡的机器上码的,不过在写blog之前是在有两块网卡的机器上操作的,就是那个机器不方便写blog,所以看着细节上可能有点味道不太对,没关系哈
118 ## 参考 ##
120 下面是一些参考文献:
122 1.  Linux Advanced Routing & Traffic Control HOWTO : http://lartc.org/howto/index.html
123 2.  ip-cref : http://users.cis.fiu.edu/~esj/cnt4504/reading/ip-cref.pdf