linux多路路由保持长链接的问题
时间:2010-06-19
来源:互联网
由于linux默认每10分钟就清空一次路由缓存,所以在多路路由的情况下就不能保持长时间的链接。如下情形
1. 两条电信的PPPoE线路,用设备做负载均衡,均衡路由是这样的:
default
nexthop via a.a.a.a dev ppp0 weight 1
nexthop via b.b.b.b. dev ppp1 weight 1
2. telnet登录到公网的某个服务器,大概10几分钟后就可能断开;
3. Linux内核版本2.6.20
4. 路由缓冲默认每隔10分钟刷新(/proc/sys/net/ipv4/route/secret_interval)
5. telnet第一次登陆时,路由选路假设选择ppp1口;最长10分钟后,路由缓存被清除,此时telnet报文被重新路由,multipath可能选择另外的接口,即PPP0;从ppp0接口抓包,可以看到以ppp1接口地址为源地址的报文从ppp0接口发出,导致telnet断开;
在linux下有什么方法可以解决这个问题吗?
作者: 瀚海书香 发布时间: 2010-06-19
怎么没人回答啊?难道我理解的不对???
作者: 瀚海书香 发布时间: 2010-06-20

欢迎大家参与讨论该问题。
作者: Godbach 发布时间: 2010-06-21
God兄没遇到过这个问题吗?
还望大虾指点
作者: 瀚海书香 发布时间: 2010-06-21
作者: Godbach 发布时间: 2010-06-21
作者: 瀚海书香 发布时间: 2010-06-21
不过,如果LZ是做内核开发的话,应该比较好解决,与conntrack关联就可以了。
作者: ShadowStar 发布时间: 2010-06-21
conntrack与路由关联??
在查找路由的时候先查找conntrack链表??
作者: 瀚海书香 发布时间: 2010-06-21
conntrack与路由关联??
在查找路由的时候先查找conntrack链表??
瀚海书香 发表于 2010-06-21 14:51
是的。
作者: ShadowStar 发布时间: 2010-06-21
不过,如果LZ是做 ...
ShadowStar 发表于 2010-06-21 14:19
不错的办法,conntrack 往往可以帮我们解决很多问题
作者: platinum 发布时间: 2010-06-21
作者: Godbach 发布时间: 2010-06-21
难到没有人写过这个模块吗?我觉得这个应用挺广泛啊,应该早就有人写了这个模块才对啊???
作者: 瀚海书香 发布时间: 2010-06-21
作者: platinum 发布时间: 2010-06-21
作者: Godbach 发布时间: 2010-06-21
难到没有人写过这个模块吗?我觉得这个应用挺广泛啊,应该早就有人写了这个模块才对啊? ...
瀚海书香 发表于 2010-06-21 17:41
早就写完了。不过由于公司制度不能open出来。
Godbach 发表于 2010-06-21 18:02
网御也应该有这个功能吧?
作者: ShadowStar 发布时间: 2010-06-22
可以交流一下啊。
我研究了一下可以通过如下修改实现:
基于2.6.24.4内核
net/ipv4/route.c
< #include <linux/netfilter_ipv4.h>
< #include <net/netfilter/nf_conntrack.h>
< #include <net/netfilter/nf_conntrack_helper.h>
< #include <net/netfilter/nf_conntrack_l4proto.h>
< #include <net/netfilter/nf_conntrack_l3proto.h>
< #include <net/netfilter/nf_conntrack_core.h>
< #include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
75d66
1724,1727d1714
< /*if (res->fi && res->fi->fib_nhs > 1 && fl->oif == 0)
< fib_select_multipath(fl, res);*/
< // change upper two lines
1729,1740c1716
< {
< struct nf_conn *ct;
< enum ip_conntrack_info ctinfo;
< ct=nf_ct_get(skb, &ctinfo);
< if(!ct||ctinfo==IP_CT_NEW||ctinfo==IP_CT_RELATED)
< fib_select_multipath(fl, res);
< else{
< if(fib_select_multipath_ct(fl,res,ct)==0)
< fib_select_multipath(fl,res);
< }
< }
---
> fib_select_multipath(fl, res);
net/ipv4/fib_semantics.c
< //return 0 means doesn't match
< int fib_select_multipath_ct(const struct flowi *flp, struct fib_result *res,struct nf_conn *ct)
< {
< struct fib_info *fi = res->fi;
< struct in_device *in_dev;
< struct in_ifaddr *ifa;
< spin_lock_bh(&fib_multipath_lock);
< change_nexthops(fi) {
< in_dev=in_dev_get(nh->nh_dev);
< if(!in_dev)
< continue;
< rcu_read_lock();
< if (!(nh->nh_flags&RTNH_F_DEAD) &&in_dev->ifa_list){
< /*&&(in_dev->ifa_list==ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip||nh->nh_gw==ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip) {*/
< for(ifa=in_dev->ifa_list;ifa;ifa=ifa->ifa_next){
< if(ifa->ifa_local==ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip&&inet_ifa_match(nh->nh_gw,ifa))
< break;
< }
< rcu_read_unlock();
< in_dev_put(in_dev);
< if(ifa){
< printk(KERN_INFO "Match %u.%u.%u.%u\n",NIPQUAD(ifa->ifa_local));
< res->nh_sel=nhsel;
< spin_unlock_bh(&fib_multipath_lock);
< return 1;
< }
< }
< rcu_read_unlock();
< in_dev_put(in_dev);
< } endfor_nexthops(fi);
< spin_unlock_bh(&fib_multipath_lock);
< return 0;
< }
---
>
include/net/ip_fib.h
< #include <linux/netfilter_ipv4.h>
< #include <net/netfilter/nf_conntrack.h>
< #include <net/netfilter/nf_conntrack_helper.h>
< #include <net/netfilter/nf_conntrack_l4proto.h>
< #include <net/netfilter/nf_conntrack_l3proto.h>
< #include <net/netfilter/nf_conntrack_core.h>
< #include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
<
< extern int fib_select_multipath_ct(const struct flowi *flp, struct fib_result *res,struct nf_conn *ct);
作者: 瀚海书香 发布时间: 2010-06-24
作者: platinum 发布时间: 2010-06-24
可以交流一下啊。
我研究了一下可以通过如下修改实现:
基于2.6.24.4内核
net/i ...
瀚海书香 发表于 2010-06-24 14:53
你做的太复杂了,完全没必要。
作者: ShadowStar 发布时间: 2010-06-24
理论上应该是可以的,还没有具体测试呢。嘿嘿
作者: 瀚海书香 发布时间: 2010-06-24
愿闻其详。
作者: 瀚海书香 发布时间: 2010-06-24
正确的做法应该是直接获取 ip、port、protocol,通过 hash 函数计算 key,直接在 conntrack 里查表看是否存在
作者: platinum 发布时间: 2010-06-24
因为有skb,所以ct=nf_ct_get(skb,&ctinfo)获取。而ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip则应该是应答包的目的ip地址,那么你的下一跳就应该是从这个ip地址所属的接口出去的。
例如:
内口:192.168.0.1
外口1:172.16.0.2
外口2:172.16.1.2
route default via nexthop 172.16.0.1
nexthop 172.16.1.1
如果有一个连接 192.168.0.8---x.x.x.x,使用路由172.16.0.1,那么应答连接应该是 x.x.x.x---172.16.0.2;所以我们如果知道应答连接的目的ip是172.16.0.2的话,那么它的原连接的路由就应该是172.16.0.1。也就是应答的目的ip跟路由应该是同一个网段的。
作者: 瀚海书香 发布时间: 2010-06-24
2、如果本身也做了 NAT,那么可能还比较麻烦,因为 MASQUERADE 和 SNAT 是在 POSTROUTING 里做的
作者: platinum 发布时间: 2010-06-24
回复 platinum
就是因为做SNAT所以才用在reply的dip。因为如果做snat的话,reply的dip就应该是snat后的ip。
虽然snat是在postrouting,但是我们只对已建立的链接确保路由flush后再次查询的路由跟上次的不变,所以说我们处理的链接已经是做了snat的了。因为snat只对新建的链接和related的链接起作用。
作者: 瀚海书香 发布时间: 2010-06-24
另外,如果是 FTP 的 DATA 信道,在开启 nf_nat_ftp 模块的情况下,状态不是 ESTABLISHED,而是 RELATED,这个你考虑了没有?
作者: platinum 发布时间: 2010-06-24
如果从外向内请求的情况,因为向内的路由的单路的,所以应该不会做多路路由这一部分的,而对应的向外的时候应该是查询local表,不会走multipath,所以应该没问题。
本人接触的网络拓扑比较少,可能有理解不到的地方。
作者: 瀚海书香 发布时间: 2010-06-24
ShadowStar兄,不要在那偷着笑了
给点别的思路吧

作者: 瀚海书香 发布时间: 2010-06-24
就是因为做SNAT所以才用在reply的dip。因为如果做snat的话,reply的dip就应该是snat后的ip。
瀚海书香 发表于 2010-06-24 17:04
如果是从外网回来的包,是 REPLY,在 PREROUTING 阶段目的 IP 被还原,
在 ROUTING 阶段看到的应该是内网 IP,也就是 SNAT 之前的,如果是这样,那么和你说的恰好相反啊?
作者: platinum 发布时间: 2010-06-24
如果是从外网回来的包,是 REPLY,在 PREROUTING 阶段目的 IP的确 被还原,但是在nf_conn的tuplehasn中记录的是没有被还原的ip。
作者: 瀚海书香 发布时间: 2010-06-25
我的理解是这样的你看对不对
1、如果是从内网出去的请求,REPLY 状态包是从外网回来的
2、如果是从外网主动进来的请求,那么无论是 ORIGIN 还是 REPLY 都不走 route.c 中的 ROUTE_MULTIPATH 流程,因此不用考虑如何处理
如果是这样的,那么我有一个疑问
从内网出去的包的回包,根据 NAT 要做 DNAT 转换,而这个转换是在 PREROUTING 阶段完成的,那么为什么在 ROUTE 阶段看到的 DIP 却是转换前的呢?
作者: platinum 发布时间: 2010-06-25
热门阅读
-
office 2019专业增强版最新2021版激活秘钥/序列号/激活码推荐 附激活工具
阅读:74
-
如何安装mysql8.0
阅读:31
-
Word快速设置标题样式步骤详解
阅读:28
-
20+道必知必会的Vue面试题(附答案解析)
阅读:37
-
HTML如何制作表单
阅读:22
-
百词斩可以改天数吗?当然可以,4个步骤轻松修改天数!
阅读:31
-
ET文件格式和XLS格式文件之间如何转化?
阅读:24
-
react和vue的区别及优缺点是什么
阅读:121
-
支付宝人脸识别如何关闭?
阅读:21
-
腾讯微云怎么修改照片或视频备份路径?
阅读:28