- 论坛徽章:
- 0
|
5可用积分
为了加快LINUX的报文转发性能,我们在路由器中做了一个快转功能。快转做在驱动层,收到一个会话的首报文之后,
首先走普转发出去,发完之后学习它的地址转换,记录到一个表中(快转表)。然后再有这个方向的同一
连接的报文,就直接查快转表,直接从另一个接口发出去,不再经过TCP/IP协议栈。当然后面为了维持
TCP/IP协议栈的连接跟踪信息,会随机地让几个报文走一下普转,刷新一下TCP/IP。
然而,快转开启时,尝试通过路由器访问外网的WEB网站,结果打开的页面面目全非,丢包相当严重。
将TCP的通讯模型简化,发现三次握手之后,TCP通讯过程中发生丢包,如下:
一个客户端与服务器建立连接,客户端向服务器发送一个数据报文(PUSH报),服务器收到之后,
发回了TCP 的ACK报文。这时,这个TCP ACK报文会被路由器丢弃。
原因分析如下,只涉及到5个报文。
第一个报文,TCP CLIENT发出的 SYN 包,走普转,TCP/IP协议栈创建连接跟踪块。
此时还不创建客户端向服务器方向的快转表项。
第二个报文,TCP SERVER回的SYN包,也走普转,TCP/IP协议栈能够看到这个报文,
便更新TCP状态机。
第三个报文,TCP CLIENT发出的ACK报文,走普转,TCP/IP协议栈刷新该连接跟踪块
的状态为ESTABLISHED。同时,普转之后根据该报文的信息生成客户端向服务器方向
的快转表项。
第四个报文,TCP CLIENT发出的PUSH报文,查快转表,OK,命中,直接走快转。没有
从普转路径中经过,TCP/IP协议栈没有看到过这个报文。
前面4个报文是正常的,发生异常的是第5个报文。
第五个报文,TCP SERVER对该PUSH报文进行ACK,这个方向的快转表尚未建立,只好走
普转。TCP/IP协议栈看到这个报文时,发现它的ACK号超过了预期的最大SEQ号,丢弃。
修改方案:
上面的第5个报文丢弃是因为tcp_in_window检查时返回了0(ip_ct_tcp_be_liberal),
修改成返回1。再测试HTTP访问,便一切正常。
现在,我们想问的是:有没有人碰到过这类问题,你们是怎么解决的?有没有补丁?
这个修改方案会不会有什么问题?
568 static int tcp_in_window(struct ip_ct_tcp *state,
569 enum ip_conntrack_dir dir,
570 unsigned int index,
571 const struct sk_buff *skb,
572 struct iphdr *iph,
573 struct tcphdr *tcph)
574 {
575 struct ip_ct_tcp_state *sender = &state->seen[dir];
576 struct ip_ct_tcp_state *receiver = &state->seen[!dir];
577 __u32 seq, ack, sack, end, win, swin;
578 int res;
752 } else {
753 if (LOG_INVALID(IPPROTO_TCP))
754 nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
755 "ip_ct_tcp: %s ",
756 before(seq, sender->td_maxend + 1) ?
757 after(end, sender->td_end - receiver->td_maxwin - 1) ?
758 before(sack, receiver->td_end + 1) ?
759 after(ack, receiver->td_end - MAXACKWINDOW(sender)) ? "BUG"
760 : "ACK is under the lower bound (possible overly delayed ACK)"
761 : "ACK is over the upper bound (ACKed data not seen yet)"
762 : "SEQ is under the lower bound (already ACKed data retransmitted)"
763 : "SEQ is over the upper bound (over the window of the receiver)");
764
765 /*res = ip_ct_tcp_be_liberal;*/
res = 1; /* 这样修改,取消ACK号的检查 */
766 } |
最佳答案
查看完整内容
由于第四个报文未经过普转,并没有经过 conntrack,所以 conntrack 并没有能够正确处理第五个报文的序号我在做 TCP 协议栈修改的时候也遇到了类似的问题
|