26
2019
03

Linux的高级路由和流量控制:路由策略数据库

HQY

如果你有一个大规模的路由器,你可能不得不同时满足不同用户对于路由的不同需求。路由策略数据库可以帮助你通过多路由表技术来实现。

如果你想使用这个特性,请确认你的内核配置中带有 "IP: advanced router" 和 "IP: policy routing" 两项。

当内核需要做出路由选择时,它会找出应该参考哪一张路由表。除了 "ip" 命令之外,以前的 "route" 命令也能修改 main 和 local 表。

缺省规则:

[ahu@home ahu]$ ip rule list
0: from all lookup local
32766: from all lookup main
32767: from all lookup default

上面列出了规则的优先顺序。我们看到,所有的规则都应用到了所有的包上 (“from all”)。我们前面已经看到了 "main" 表,就是“ip route ls”命令的输出,但是“local”和“default”是初次见到。

如果我们想做点有趣的事情,就可以生成一些指向不同路由表的规则,取代系统中的路由规则。

对于内核如何处理一个IP包匹配多个规则的精确意义,请参见Alexey关于 ip-cref文档。

1. 简单的源策略路由

让我们再来一个真实的例子。我有两个Cable Modem,连接到了一个 Linux的NAT (“伪装”) 路由器上。这里的室友们向我付费使用 Internet。假如我其中的一个室友因为只想访问 hotmail 而希望少付一些钱。对我来说这没有问题, 他们肯定只能使用那个比较次的 Cable Modem。

那个比较快的cable modem 的IP地址是 212.64.94.251, PPP 链路,对端IP是212.64.94.1。而那个比较慢的cable modem 的IP 地址是212.64.78.148,对端是195.96.98.253。

local 表:

[ahu@home ahu]$ ip route list table local
broadcast 127.255.255.255 dev lo proto kernel scope link src 127.0.0.1
local 10.0.0.1 dev eth0 proto kernel scope host src 10.0.0.1
broadcast 10.0.0.0 dev eth0 proto kernel scope link src 10.0.0.1
local 212.64.94.251 dev ppp0 proto kernel scope host src 212.64.94.251
broadcast 10.255.255.255 dev eth0 proto kernel scope link src 10.0.0.1
broadcast 127.0.0.0 dev lo proto kernel scope link src 127.0.0.1
local 212.64.78.148 dev ppp2 proto kernel scope host src 212.64.78.148
local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1
local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1

有很多明显的事实,其实可能还需要进一步说明。好了,这样就行了。“default” 表为空。

让我们看看“main”路由表:

[ahu@home ahu]$ ip route list table main
195.96.98.253 dev ppp2 proto kernel scope link src 212.64.78.148
212.64.94.1 dev ppp0 proto kernel scope link src 212.64.94.251
10.0.0.0/8 dev eth0 proto kernel scope link src 10.0.0.1
127.0.0.0/8 dev lo scope link
default via 212.64.94.1 dev ppp0

我们现在为我们的朋友创建了一个叫做“John”的规则。其实我们完全可以使用纯数字表示规则,但是不方便。我们可以向 /etc/iproute2/rt_tables 文件中添加数字与名字的关联:

# echo 200 John >> /etc/iproute2/rt_tables
# ip rule add from 10.0.0.10 table John
# ip rule ls
0: from all lookup local
32765: from 10.0.0.10 lookup John
32766: from all lookup main
32767: from all lookup default

现在,剩下的事情就是为 John 的路由表创建路由项了。别忘了刷新路由缓存:

# ip route add default via 195.96.98.253 dev ppp2 table John
# ip route flush cache

这样就做好了。至于如何在 ip-up 阶段实现就留给读者自己去研究吧。

2. 多重上连ISP的路由

下图是很常见的配置,同一个局域网(甚至是同一台计算机)通过两个ISP连接到互联网上。

Linux的高级路由和流量控制:路由策略数据库

这种情况下通常会出现两个问题。

2.1. 流量分割

首先是如何保证:回应来自某一个ISP的数据包时,仍然使用相同的ISP。

让我们先定义一些符号。 令第一块网卡(上图的if1)的名字叫 $IF1,而第二块网卡叫做 $IF2 。然后设置 $IF1 的IP地址为 $IP1,$IF2 的IP地址为 $IP2。并且,令ISP1 的网关地址为 $P1,ISP2 的网关地址为 $P2。最后,令$P1的网络地址为 $P1_NET ,令$P2的网络地址为 $P2_NET。

额外创建两个路由表, T1 和 T2。 加入到 /etc/iproute2/rt_tables 中。然后如下设置两个路由表中的路由:

ip route add $P1_NET dev $IF1 src $IP1 table T1
ip route add default via $P1 table T1
ip route add $P2_NET dev $IF2 src $IP2 table T2
ip route add default via $P2 table T2

没什么大不了的,不过是建立了通向该网关的一条路由,并使之成为默认网关,分别负责一个单独的上行流,并且为这两个ISP都作这样的配置。要指出的是,那条网络路由是必要条件,因为它能够让我们找到那个子网内的主机,也包括上述那台网关。

下一步,我们设置“main”路由表。把包通过网卡直接路由到与网卡相连的局域网上不失为一个好办法。要注意“src” 参数,他们能够保证选择正确的出口IP地址。

ip route add $P1_NET dev $IF1 src $IP1
ip route add $P2_NET dev $IF2 src $IP2

然后,设置你的缺省路由:

ip route add default via $P1

接着,设置路由规则。这实际上在选择用什么路由表进行路由。你需要确认当你从一个给定接口路由出数据包时,是否已经有了相应的源地址:你需要保证的就是如果你已经有了相应的源地址,就应该把数据包从相应的网卡路由出去:

ip rule add from $IP1 table T1
ip rule add from $IP2 table T2

以上命令保证了所有的回应数据都会从他们来的那块网卡原路返回。

现在,完成了非常基本的配置。这将对于所有运行在路由器上所有的进程起作用,实现IP伪装以后,对本地局域网也将起作用。如果不进行伪装,那么你要么拥有两个ISP的地址空间,要么你想对两个ISP中的一个进行伪装。无论哪种情况,你都要添加规则,基于发包的主机在局域网内的IP地址,选择从哪个ISP路由出去。

2.2. 负载均衡

第二个问题是如何对于通过两个ISP流出的数据进行负载均衡。如果你已经成功地实现了流量分割,这件事并不难。

与选择两个ISP中的一个作为缺省路由不同,这次是设置缺省路由为多路路由。在缺省内核中,这会均衡两个ISP的路由。象下面这样做(基于前面的流量分割实验):

ip route add default scope global nexthop via $P1 dev $IF1 weight 1 \
nexthop via $P2 dev $IF2 weight 1

这样就可以均衡两个ISP的路由。通过调整“weight”参数我们可以指定其中一个ISP的优先权高于另一个。

应该指出,由于均衡是基于路由进行的,而路由是经过缓冲的,所以这样的均衡并不是100%精确。也就是说,对于一个经常访问的站点,总是会使用同一个ISP。

进而,如果你对此不满意,你可能需要参考以下Julian Anastasov的内核补丁:

http://www.linuxvirtualserver.org/~julian/#routes

Julian的路由补丁会弥补上述缺陷。


HQY
« 上一篇 下一篇 »

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。