Chinaunix首页 | 论坛 | 博客
  • 博客访问: 603080
  • 博文数量: 204
  • 博客积分: 5172
  • 博客等级: 上校
  • 技术积分: 2092
  • 用 户 组: 普通用户
  • 注册时间: 2009-12-08 21:48
个人简介

一个毫无毅力之人的自勉

文章分类

全部博文(204)

文章存档

2014年(1)

2013年(54)

2012年(50)

2011年(94)

2010年(3)

2009年(3)

分类: LINUX

2011-08-13 17:20:58

===============================================================================

linux 路由表维护

使用下面的 route 命令可以查看 Linux 内核路由表

# route Destination Gateway Genmask Flags Metric Ref Use Iface
192.168.0.0 * 255.255.255.0 U 0 0 0 eth0
169.254.0.0 * 255.255.0.0 U 0 0 0 eth0
default 192.168.0.1 0.0.0.0 UG 0 0 0 eth0

route 命令的输出项说明

输出项 说明
Destination 目标网段或者主机
Gateway 网关地址,”*” 表示目标是本主机所属的网络,不需要路由
Genmask 网络掩码
Flags 标记。一些可能的标记如下:

U — 路由是活动的

H — 目标是一个主机

G — 路由指向网关

R — 恢复动态路由产生的表项

D — 由路由的后台程序动态地安装

M — 由路由的后台程序修改

! — 拒绝路由
Metric 路由距离,到达指定网络所需的中转数(linux 内核中没有使用)
Ref 路由项引用次数(linux 内核中没有使用)
Use 此路由项被路由软件查找的次数
Iface 路由表项对应的输出接口

主机路由是路由选择表中指向单个IP地址或主机名的路由记录。主机路由的Flags字段为H。例如,在下面的示例中,本地主机通过IP地址192.168.1.1的路由器到达IP地址为10.0.0.10的主机。

Destination Gateway Genmask Flags Metric Ref Use Iface
----------- ------- ------- ----- ------ --- --- -----
10.0.0.10 192.168.1.1 255.255.255.255 UH 0 0 0 eth0

网络路由是代表主机可以到达的网络。网络路由的Flags字段为N。例如,在下面的示例中,本地主机将发送到网络192.19.12的数据包转发到IP地址为192.168.1.1的路由器。

Destination Gateway Genmask Flags Metric Ref Use Iface
----------- ------- ------- ----- ----- --- --- -----
192.19.12 192.168.1.1 255.255.255.0 UN 0 0 0 eth0

当主机不能在路由表中查找到目标主机的IP地址或网络路由时,数据包就被发送到默认路由(默认网关)上。默认路由的Flags字段为G。例如,在下面的示例中,默认路由是IP地址为192.168.1.1的路由器。

Destination Gateway Genmask Flags Metric Ref Use Iface
----------- ------- ------- ----- ------ --- --- -----
default 192.168.1.1 0.0.0.0 UG 0 0 0 eth0

设置和查看路由表都可以用 route 命令,设置内核路由表的命令格式是:

# route [add|del] [-net|-host] target [netmask Nm] [gw Gw] [[dev] If]

其中:

  • add : 添加一条路由规则
  • del : 删除一条路由规则
  • -net : 目的地址是一个网络
  • -host : 目的地址是一个主机
  • target : 目的网络或主机
  • netmask : 目的地址的网络掩码
  • gw : 路由数据包通过的网关
  • dev : 为路由指定的网络接口

添加到主机的路由

# route add -host 192.168.1.2 dev eth0:0
# route add -host 10.20.30.148 gw 10.20.30.40

添加到网络的路由

# route add -net 10.20.30.40 netmask 255.255.255.248 eth0
# route add -net 10.20.30.48 netmask 255.255.255.248 gw 10.20.30.41
# route add -net 192.168.1.0/24 eth1

添加默认路由

# route add default gw 192.168.1.1

删除路由

# route del -host 192.168.1.2 dev eth0:0
# route del -host 10.20.30.148 gw 10.20.30.40
# route del -net 10.20.30.40 netmask 255.255.255.248 eth0
# route del -net 10.20.30.48 netmask 255.255.255.248 gw 10.20.30.41
# route del -net 192.168.1.0/24 eth1
# route del default gw 192.168.1.1

在 CentOS 中默认的内核配置已经包含了路由功能,但默认并没有在系统启动时启用此功能。开启 Linux的路由功能可以通过调整内核的网络参数来实现。要配置和调整内核参数可以使用 sysctl 命令。例如:要开启 Linux内核的数据包转发功能可以使用如下的命令。

# sysctl -w net.ipv4.ip_forward=1

这样设置之后,当前系统就能实现包转发,但下次启动计算机时将失效。为了使在下次启动计算机时仍然有效,需要将下面的行写入配置文件/etc/sysctl.conf。

# vi /etc/sysctl.conf net.ipv4.ip_forward = 1

用户还可以使用如下的命令查看当前系统是否支持包转发。

# sysctl net.ipv4.ip_forward


===============================================================================

 

Linux路由表的结构与算法分析
黄一文
 
路由是网络栈的核心部分。路由表本身的设计很大情度上影响着路由的性能,并且好的设计 能减少系统资源的消耗,这两方面尤其体现在路由表的查找上。目前的内核路由存在两种查找算法,一种为HASH算法,另一种为LC-trie算法,前者是目 前内核使用的缺省算法,而后者更适用在超大路由表的情况,它在这种情况提高查找效率的同时,大大地增加了算法本身的复杂性和内存的消耗。综上,这两种算法 各有其适用的场合,本文分析了基于2.6.18内核路由部分的代码在HASH算法上路由表结构的实现,并且在文章最后给出了一个简单的策略路由的应用。
 
一、路由表的结构
       为了支持策略路由,Linux使用了多个路由表而不是一个,即使不使用策略路由,Linux也使用了 两个路由表,一个用于上传给本地上层协议,另一个则用于转发。Linux使用多个路由表而不是一个,使不同策略的路由存放在不同的表中,有效地被免了查找 庞大的路由表,在一定情度上提高了查找了效率。
 
       路由表本身不是由一个结构表示,而是由多个结构组合而成。路由表可以说是一个分层的结构组合。在第一 层,它先将所有的路由根据子网掩码(netmask)的长度(0~32)分成33个部分(structfn_zone),然后在同一子网掩码(同一层) 中,再根据子网的不同(如10.1.1.0/24和10.1.2.0/24),划分为第二层(struct fib_node),在同一子网中,有可能由于TOS等属性的不同而使用不同的路由,这就是第三层(structfib_alias),第三层结构表示一 个路由表项,而每个路由表项又包括一个相应的参数,如协议,下一跳路由地址等等,这就是第四层(structfib_info)。分层的好处是显而易见 的,它使路由表的更加优化,逻辑上也更加清淅,并且使数据可以共享(如structfib_info),从而减少了数据的冗余。
 

 

struct fib_table *fib_tables[RT_TABLE_MAX+1]; // RT_TABLE_MAX 为255

       图1为一个路由表的总体结构。自上而下由左向右看,它首先为一个fib_table结构指针的数组,它被定义为:

 

 

struct fib_table {
       unsigned char tb_id;
       unsigned tb_stamp;
       int           (*tb_lookup)(struct fib_table *tb, const struct flowi *flp, struct fib_result *res);
       int           (*tb_insert)(struct fib_table *table, struct rtmsg *r,
                     ……
       void        (*tb_select_default)(struct fib_table *table,
                                        const struct flowi *flp, struct fib_result *res);
 
       unsigned char tb_data[0];
};

       每个fib_table结构在内核中表示一个路由表:

       +
图1(引自[1])
这个结构中包括这个表的ID,以及主要的一些用于操作路由表的函数指针,这里我们只关心最后一个域――tb_data[0],这是一个零长的数组,它在内核中也较为常见,它表示

 

struct fn_hash {
struct fn_zone *fn_zones[33];
struct fn_zone *fn_zone_list;
};

指向这个结构的末尾。由图1可以看到,这个结构的末尾接着便是一个struct fn_hash结构,这个结构是随着fib_table结构一起分配的,所以fib_table->tb_data就是fn_hash。

 

struct fn_zone {
       struct fn_zone          *fz_next; /* Next not empty zone */
       struct hlist_head     *fz_hash;       /* Hash table pointer      */
       int                                fz_nent;   /* Number of entries      */
 
       int                                fz_divisor;      /* Hash divisor              */
       u32                             fz_hashmask; /* (fz_divisor - 1)   */
#define FZ_HASHMASK(fz)         ((fz)->fz_hashmask)
 
       int                                fz_order; /* Zone order         */
       u32                             fz_mask;
#define FZ_MASK(fz)          ((fz)->fz_mask)
  
};

       这个fn_zone域就是我们上面提前的结构,用于将路由根据子网掩码的长度分开成33个部分,其中fn_zones[0]用于默认网关。而fn_zone_list域就是将正在使用的fn_zone链成一个链表。接着再深入到struct fn_zone结构中:

 
这个结构中有两个域比较重要,一个为fz_hash域,它指向一个HASH表的表头,这个HASH的长度是fz_divisor。并且这个HASH表的长度是可变的,当表长达到一个限定值时,将重建这个HASH表,被免出现HASH冲突表过长造成查找效率降低。
 
为了提高查找的效率,内核使用了大量的HASH表,而路由表就是一个例子。在图1中可以看到,等长子网掩码的路由存放在同一个fn_zone中,而根据到不同子网(fib_node)的路由键值(fn_key),将它HASH到相应的链表中。

 

struct fib_node {
       struct hlist_node     fn_hash;
       struct list_head       fn_alias;
       u32                fn_key;
};
 
这个键值其实就是这个子网值了(如10.1.1.0/24,则子网值为 10.1.1),得到这个键值通过n =fn_hash()函数HASH之后就是这个子网对应的HASH值,然后就可以插入到相应的fz_hash[n]链表中了。冲突的fib_node由 fn_hash域相链,而fn_alias则是指向到达这个子网的路由了。

 

struct fib_alias {
       struct list_head       fa_list;
       struct rcu_head      rcu;
       struct fib_info        *fa_info;
       u8                  fa_tos;
       u8                  fa_type;
       u8                  fa_scope;
       u8                  fa_state;
};
当到达这个子网的路由由于TOS等属性的不同可存在着多个路由时,它们就通过fib_alias中fa_list域将这些路由表项链成一个链表。这个结构中的另一个域fa_info指向一个fib_info结构,这个才是存放真正重要路由信息的结构。

 

struct fib_info {
       struct hlist_node     fib_hash;
       struct hlist_node     fib_lhash;
       ……
       int                  fib_dead;
       unsigned         fib_flags;
       int                  fib_protocol;
       u32                fib_prefsrc;
       u32                fib_priority;
       ……
int                         fib_nhs;
       struct fib_nh          fib_nh[0];
#define fib_dev             fib_nh[0].nh_dev
};
 
这个结构里面是一个用于路由的标志和属性,其中最重要的一个域是fib_nh[0], 在这里,我们再次看到了零长数组的应用,它是通过零长来实现变长结构的功能的。因为,我们需要一个定长的fib_info结构,但是在这个结构末尾,我们 需要的fib_nh结构的个数是不确定的,它在运行时确定。这样,我们就可以通过这种结构组成,在运行时为fib_info分配空间的时候,同时在其末尾 分配所需的若干个fib_nh结构数组,并且这个结构数组可以通过fib_info->fib_nh[n]来访问,在完成fib_info的分配后 将fib_nhs域置为这个数组的长度。
 
另一方面,fib_info也是HASH表的一个应用,结构中存在着两个域,分别是 fib_hash和fib_lhash,它们都用于HASH链表。这个结构在完成分配后,将被用fib_hash域链入fib_info_hash表中, 如果这个路由存在首选源地址,这个fib_info将同时被用fib_lhash链入fib_info_laddrhash表中。这样,就可以根据不同目 的实现快速查找了。
 
Structfib_nh也是一个重要的结构。它存放着下一跳路由的地址 (nh_gw)。刚刚已经提到,一个路由(fib_alias)可能有多个fib_nh结构,它表示这个路由有多个下一跳地址,即它是多路径 (multipath)的。下一跳地址的选择也有多种算法,这些算法都是基于nh_weight,nh_power域的。nh_hash域则是用于将 nh_hash链入HASH表的。

 

struct fib_nh {
       struct net_device    *nh_dev;
       struct hlist_node     nh_hash;
       struct fib_info        *nh_parent;
       unsigned                nh_flags;
       unsigned char        nh_scope;
#ifdef CONFIG_IP_ROUTE_MULTIPATH
       int                  nh_weight;
       int                  nh_power;
#endif
#ifdef CONFIG_NET_CLS_ROUTE
       __u32                   nh_tclassid;
#endif
       int                  nh_oif;
       u32                nh_gw;
};
 
二、路由的查找
       路由的查找速度直接影响着路由及整个网络栈的性能。路由的查找当然首先发生在路由缓存中,当在缓存中查找失败时,它再转去路由表中查找,这是本文所关注的地方。
 
       上一节已经详细地描述了路由表的组成。当一个主要的IP层将要发送或接收到一个IP数据包时,它就要调用路由子系统完成路由的查找工作。路由表查找就是根据给定的参数,在某一个路由表中找到合适的下一跳路由的地址。
 
       上面已提到过,当一个主机不支持策略路由时,它只使用了两个路由表,一个是 ip_fib_local_table,用于本地,另一个是ip_fib_main_table,用于接发。只有在查找 ip_fib_local_table表时没有找到匹配的路由(不是发给本地的)它才会去查找ip_fib_main_table。当一个主机支持策略路 由时,它就有可能存在着多个路由表,因而路由表的选择也就是查找的一部分。路由表的选择是由策略来确定的,而策略则是由应用(用户)来指定的,如能过 iprule命令:

 

ip rule add from 10.1.1.0/24 table TR1
ip rule add iff eth0 table RT2
       如上,第一条命令创建了基于源地址路由的一条策略,这个策略使用了RT1这个路由表,第二条命令创建了基于数据包入口的一个策略,这个策略使用了RT2这个路由表。当被指定的路由表不存在时,相应的路由表将被创建。
 
       第二步就是遍历这个路由表的fn_zone,遍历是从最长前缀(子网掩码最长)的fn_zone开始的,直到找到或出错为止。因为最长前缀才是最匹配的。假设有如下一个路由表:

 

dst                 nexthop               dev
        10.1.0.0/16       10.1.1.1                     eth0
        10.1.0.0/24          10.1.0.1               eth1
 
它会先找到第二条路由,然后选择10.1.0.1作为下一跳地址。但是,如果由第二步定位到的子网(fib_node)有多个路由,如下:

 

dst                 nexthop               dev
        10.1.0.0/24       10.1.0.1                     eth1
        10.1.0.0/24          10.1.0.2               eth1
 
到达同一个子网有两个可选的路由,仅凭目的子网无法确定,这时,它就需要更多的信息来 确定路由的选择了,这就是用于查找路由的键值(structflowi)还包括其它信息(如TOS)的原因。这样,它才能定位到对应一个路由的一个 fib_alias实例。而它指向的fib_info就是路由所需的信息了。
最后一步,如果内核被编译成支持多路径(multipath)路由,则fib_info中有多个fin_nh,这样,它还要从这个fib_nh数组中选出最合适的一个fib_nh,作为下一跳路由。
 
 
三、路由的插入与删除
       路由表的插入与删除可以看看是路由查找的一个应用,插入与删除的过程本身也包含一个查找的过程,这两个操作都需要检查被插入或被删除的路由表项是否存在,插入一个已经存在的路由表项要做特殊的处理,而删除一个不存在的路由表项当然会出错。
       下面看一个路由表插入的例子:

 

ip route add 10.0.1.0/24 nexthop via 10.0.1.1  weight 1
                                nexthop via 10.0.1.2  weight 2
                                   table RT3
 
 
 
 
这个命令在内核中建立一条新的路由。它首先查找路由表RT3中的子网掩码长为24的 fn_zone,如果找不到,则创建一个fn_zone。接着,继续查找子网为10.0.1的fib_node,同样,如果不存在,创建一个 fib_node。然后它会在新建一个fib_info结构,这个结构包含2个fib_nh结构的数组(因为有两个nexthop),并根据用户空间传递 过来的信息初始化这个结构,最后内核再创建一个fib_alias结构(如果先前已经存在,则出错),并用fib_nh来创始化相应的域,最后将自己链入 fib_node的链中,这样就完成了路由的插入操作。
 
路由的删除操作是插入操作的逆过程,它包含一系列的查找与内存的释放操作,过程比较简单,这里就不再赘述了。
 
 
四、策略路由的一个简单应用
       Linux系统在策略路由开启的时候将使用多个路由表,它不同于其它某些系统,在所有情况下都只使用 单个路由表。虽然使用单个路由表也可以实现策略路由,但是如本文之前所提到的,使用多个路由表可以得到更好的性能,特别在一个大型的路由系统中。下面只通 过简单的情况说明Linux下策略路由的应用。
如图2,有如下一个应用需求,其中网关服务器上有三个网络接口。接口1的IP为 172.16.100.1,子网掩码为255.255.255.0,网关gw1为a.b.c.d,172.16.100.0/24这个网段的主机可以通过 这个网关上网;接口2的IP是172.16.10.1,子网掩码同接口一,网关gw2为e.f.g.h,172.16.10.0/24这个网段的主机可以 通过这个网关上网;接口0的IP为192.168.1.1,这个网段的主机由于网络带宽的需求需要通过e.f.g.h这个更快的网关路由出去。
 
图 2
 
步骤一:设置各个网络接口的IP,和默认网关:

 

ip addr add 172.16.100.1/24 dev eth1
ip route add default via a.b.c.d dev eth1
       其它接口IP的设置和第一个接口一样,这时,如果没有其它设置,则所有的数据通过这个默认网关路由出去。
 
步骤二:使子网172.16.10.0/24可以通过gw2路由出去

 

       ip route add 172.16.10.0/24 via e.f.g.h dev eth2

      

 
 
步骤三:添加一个路由表 

 

       echo   “250 HS_RT” >> /etc/iproute2/rt_tables
 
 
步骤四:使用策略路由使192.168.1.0/24网段的主机可以通过e.f.g.h这个网关上网
 

 

       ip rule add from 192.168.1.0/24 dev eth0 table HS_RT pref 32765
       ip route add default via e.f.g.h dev eth2
       iptables –t nat –A POSTROUTING –s 192.168.1.0/24 –j MASQUERADE
      
步骤五:刷新路由cache,使新的路由表生效
 

 

ip route flush cache 
这样就可以实现了以上要求的策略路由了,并且可以通过traceroute工具来检测上面的设置是否能正常工作。
 
===============================================================================

linux双网卡怎么设置我就不说了,我这里说的是linux双网卡的流量问题...
可能这个问题很偏们..你们也许用不上..我还是要说..


问题描述,一个linux主机,上面两个网卡..:)

route -n的输出是这样的.


Destination Gateway Genmask Flags Metric Ref Use Iface

 

61.132.43.128 0.0.0.0 255.255.255.192 U 0 0 0 eth1

127.0.0.0 0.0.0.0 255.0.0.0 U 0 0 0 lo

0.0.0.0 61.132.43.134 0.0.0.0 UG 0 0 0 eth0

 


这里解释一下...第一行是说,你要访问61.132.43.128这个网段,掩码是255.255.255.192的话..从e
th1这个网卡出去..
第二行是关于本机的,访问自己从lo这个虚拟的本地网卡走..
第三行是说你要去任何地方的话..从网关61.132.43.134出去.并且网卡是eth0

 

到这里我们看到了..我们除了去61.132.43.128这个网络是从eth1走以外..去其他地方都是从eth0

阅读(945) | 评论(0) | 转发(0) |
0

上一篇:syslog系统

下一篇:printascii函数

给主人留下些什么吧!~~