Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1381557
  • 博文数量: 436
  • 博客积分: 7854
  • 博客等级: 少将
  • 技术积分: 3225
  • 用 户 组: 普通用户
  • 注册时间: 2007-12-18 16:30
文章分类

全部博文(436)

文章存档

2013年(2)

2012年(56)

2011年(70)

2010年(308)

分类: 网络与安全

2010-01-15 13:07:26

应用策略路由,可以使多链路下的路由表管理更为清晰,而且能满足未来更为复杂的需求。

 

本文简单介绍策略路由,然后分析如何通过策略路由来管理多链路下的路由表。

 

1.   策略路由

 1.1.                    简介

传统的路由算法可以描述为:

根据数据包的目的地址,通过最长匹配算法,选择一条路由规则;路由的结果是找到下一跳地址以及对应的输出接口。

但是在复杂情况下,我们希望不仅仅根据目的地址,还能根据源地址,IP 协议,端口,TOS,甚至 packet payload 来进行路由选择,这就是策略路由。

Linux 从 2.1 内核就开始支持策略路由.

 策略路由使用多张路由表,查找路由过程分为两个阶段:

1.       首先根据策略来确定路由表。策略主要包括源地址、目的地址、TOS 和 incoming interface。例如凡是从某个源地址来的数据包都要从某个路由表中查找路由。

2.       然后在这个选定的路由表中,根据源地址、目的地址、TOS 等来选定路由规则,这个过程和我们通常了解的路由查找过程是一致的。

 1.2.                    Linux 对策略路由的支持

 1.2.1.              内置的路由表

 Linux 最多可以支持 255 张路由表,其中有 3 张表是内置的,不能删除。

表255 本地路由表(Local table):本地接口地址,广播地址,已及NAT地址都放在这个表。该路由表由系统自动维护,管理员不能直接修改。

表254 主路由表(Main table) :如果没有指明路由所属的表,所有的路由都默认都放在这个表里。旧的路由工具(如route)所添加的路由都会加到这个表。

表253 默认路由表 (Default table):这个表的作用不清楚,一般也用不到

表 0 保留

1.2.2.              增加一个路由表

Linux 通过 /etc/iproute2/rt_tables 文件来管理路由表

要增加一个新的路由表 GPRS_TBL, 可以这样:

echo “100  GPRS_TBL”     >>  /etc/iproute2/rt_tables

其中  100 是表的索引号, GPRS_TBL 是表的名称



1.2.3.              默认的路由策略

通过  ip rule ls 可以看到 Linux 默认的路由策略:

0:                            from all lookup local

32766:                   from all lookup main

32767:                   from all lookup default

可以看到:

1.       有三条策略,它们的优先级分别是  0,32766 和 32767;

2.       这些策略都是根据源地址来选择路由表,它们适用于任何源地址的情况(from all);

3.       0 级的策略优先级最高,它选定 local 表,这适应于目的地址是本机地址或者广播地址的情况。

4.       32766 级的策略选定 main 表,它适用于目的地址为普通地址的情况,这张表也就是通过工具 ‘route’ 看到的那张路由表。

 

2.   应用策略路由

 2.1.                    多链路的需求


多链路情况下,通常有如下需求:

 1.       应用能指定从某个链路发送数据

2.       应用不指定链路的情况下,可从默认链路发送数据

3.       对于从某个链路上进入的数据包的响应,应仍从这个链路发送出去


单张路由表也可以满足这些需求,但缺点是理解起来不清晰,管理起来也有点混乱,而且可能无法满足将来更多的需求。

 

2.2.                    应用策略路由来满足多链路的需求

2.2.1.              多链路的典型场景

假设手机上同时存在两条链路:

1、  GPRS 链路: 网络接口 gprs0,IP 地址  10.0.0.2,网关地址 10.0.0.1

2、  WiFi 链路:  网络接口 eth0,IP 地址 20.0.0.2,网关地址 20.0.0.1

3、  WiFi 链路是默认链路

再假设某个应用有如下多个 socket:

1、  Client socket S1,指定从 GPRS 链路收发数据

2、  Client socket S2,指定从 WiFi 链路收发数据

3、  Client socket S3,不指定链路,希望从默认链路收发数据

4、  Server socket S4,它要求能接收从所有网络接口来的请求

2.2.2.              配置策略路由

思路是:

¨       为每条链路单独维护一张路由表

¨       同时维护默认的 main 表

¨       根据数据包的源地址作为选择路由表的依据:

¨       源地址是某条链路的地址时,选择链路所对应的路由表;

¨       其它的源地址,选择默认的 main 表

 下面针对这个场景,看看如何具体配置路由:

 1、  添加两张路由表 GPRS_TBL 和 WIFI_TBL

echo  100  GPRS_TBL >>  /etc/iproute2/rt_tables

echo  101  WIFI_TBL  >>  /etc/iproute2/rt_tables

 

2、  为 GPRS 表设置路由,包括网段路由和默认路由

ip route add 10.0.0.0/24  dev gprs0 src 10.0.0.2 table GPRS_TBL

ip route add  default via  10.0.0.1 table GPRS_TBL

 

3、  为 WiFi 表设置路由,包括网段路由和默认路由

ip route add 20.0.0.0/24  dev gprs0 src 20.0.0.2 table WIFI_TBL

ip route add  default via  20.0.0.1 table WIFI_TBL

 

4、  为 main 表设置路由,包括网段路由和默认路由

ip route add 10.0.0.0/24  dev gprs0 src 10.0.0.2

ip route add 20.0.0.0/24  dev gprs0 src 20.0.0.2

ip route add default via 20.0.0.1

 

5、  根据源地址来设置选择路由表的策略,也就是源地址路由策略

ip rule add from 10.0.0.2 table GPRS_TBL

ip rule add from 20.0.0.2 table WIFI_TBL

 

2.3.                    满足需求:应用指定从某个链路收发数据

这要求应用显示调用  bind(), 将 socket  的源地址绑定到指定网络接口的 IP 地址上

在这个场景中,应用需要把 S1 绑定到 10.0.0.2 上,把 S2 绑定到 20.0.0.2 上

在路由过程中,由于源地址已经确定,因此可以选择到对应的路由表,进而选择到正确的路由规则。

 

2.4.                    满足需求:应用不指定链路时,从默认链路收发数据

 对于很多 open source 或者第三方的应用,很可能不会调用 bind() 来指定源地址,而是交给内核选择源地址。

在这个场景中, S3 socket 没有调用绑定,它的源地址是 0.0.0.0,因此在路由过程中,会选择到 main 路由表。

在 main 表中查找路由时,主要有三种情况:

 1.       如果目的地址是  10.0.0.0/24 网段的,则选择第一条路由

2.       如果目的地址是  20.0.0.0/24 网段的,则选择第二条路由

3.       对于其它的目的地址,选择默认路由

 

2.5.                    满足需求:对于从某个链路上进入的数据包的响应,应仍从这个链路发送出去

 如果手机上存在某个 server,能为外部应用提供服务,就会有这种需求。对于 P2P 应用,以及将来可能出现的新的应用,这种情况是存在的。

 在这个场景中的 S4 socket 就是这样的 server,它要求对于从 GPRS 链路上来的请求,响应数据应从 GPRS 链路上发送,而不至于从 WiFi 链路上发送;同样,对于从 WiFi 链路来的请求,响应应从 WiFi 链路发送。

 对于这种响应包,因为是根据请求包来构造的,所以它的源地址是可以知道的,就是进入的网络接口的地址,因此这种响应包的路由过程和“应用指定链路”的情况是一样的。

 

 2.6.                    应用不指定链路,不允许收发数据

也可能会有这样的需求,对于不指定链路的应用,不允许收发数据。可以通过清空 main 表来在一定程度上满足这种需求。

 

3.  应用策略路由可能存在的问题

3.1   应用能否不调用 bind() ?

 应用必须显式调用 bind(),能否省略这一步?例如根据 socket 所属的应用,找到对应的链路?

我认为这个 bind() 是无法避免的。

首先,一个应用可以有多个 socket,而不同的 socket 又可能希望从不同的链路发送数据,因此无法根据一个 socket 属于的应用程序来决定这个 socket 上的数据应该从哪个链路发送。

其次,应用必须通过一个显式的手段来指定 socket 对应的链路,不用 bind() 也必须有其它方式。通过 bind() 指定源地址,从而指定链路,只是一种方式而已。

 

3.2   两个链路具有相同的源地址怎么办?

在这个场景中,我们仅仅根据源地址作为策略来选择路由表,这要求不同的链路必须具有不同的源地址。但在一些特殊情况下,例如 GPRS 的 primary PDP 和second PDP,两个网络接口具有相同的地址,这时候无法仅仅通过源地址来区分不同的链路,怎么办?

因为 Primary PDP 和 Secondary PDP 具有不同的 TOS,因此可以将 TOS 作为一个策略加进来。

 

阅读(880) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~