TCP输入 之 快速路径和慢速路径

概述

快速路径:用于处理预期的,理想情况下的数据段,在这种情况下,不会对一些边缘情形进行检测,进而达到快速处理的目的;

慢速路径:用于处理那些非预期的,非理想情况下的数据段,即不满足快速路径的情况下数据段的处理;

首部预测字段格式:首页预测字段,实际上是与TCP首部中的【头部长度+保留字段+标记字段+窗口值】这个32位值完全对应的;进行快速路径判断的时候,只需要将该预测值与TCP首部中的对应部分进行比对即可,具体见tcp_rcv_established;

源码分析

tcp_fast_path_check完成对是否满足快速路径条件的检查,当没乱序队列中没有乱序数据段,接收窗口不为0,接收缓存足够,且没有紧急数据的情况下,才可以开启快速路径标记;不满足上述情况需要执行慢速路径;

 1 static inline void tcp_fast_path_check(struct sock *sk)
 2 {
 3     struct tcp_sock *tp = tcp_sk(sk);
 4 
 5     if (RB_EMPTY_ROOT(&tp->out_of_order_queue) &&
 6         tp->rcv_wnd &&
 7         atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf &&
 8         !tp->urg_data)
 9         tcp_fast_path_on(tp);
10 }

tcp_fast_path_on对含有扩大因子的窗口值进行还原,之后调用__tcp_fast_path_on;

1 static inline void tcp_fast_path_on(struct tcp_sock *tp)
2 {
3     __tcp_fast_path_on(tp, tp->snd_wnd >> tp->rx_opt.snd_wscale);
4 }

__tcp_fast_path_on则是构造与tcp头部【头部长度+保留字段+标记字段+窗口值】对应的字段;其中标记字段为含有ACK标记;

1 static inline void __tcp_fast_path_on(struct tcp_sock *tp, u32 snd_wnd)
2 {
3     tp->pred_flags = htonl((tp->tcp_header_len << 26) |
4                    ntohl(TCP_FLAG_ACK) |
5                    snd_wnd);
6 }

tcp_rcv_established在处理已连接状态下的数据段接收时,会使用tcp_flag_word(th) & TCP_HP_BITS) == tp->pred_flags将tcp首部中的字段值与预测字段进行比对,若一致,才能进入快速路径进行处理,否则执行慢速路径;

 1 void tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
 2              const struct tcphdr *th, unsigned int len)
 3 {
 4     struct tcp_sock *tp = tcp_sk(sk);
 5 
 6     tp->rx_opt.saw_tstamp = 0;
 7 
 8     /*    pred_flags is 0xS?10 << 16 + snd_wnd
 9      *    if header_prediction is to be made
10      *    'S' will always be tp->tcp_header_len >> 2
11      *    '?' will be 0 for the fast path, otherwise pred_flags is 0 to
12      *  turn it off    (when there are holes in the receive
13      *     space for instance)
14      *    PSH flag is ignored.
15      */
16 
17     /* 快路检查&& 序号正确 && ack序号正确 */
18     if ((tcp_flag_word(th) & TCP_HP_BITS) == tp->pred_flags &&
19         TCP_SKB_CB(skb)->seq == tp->rcv_nxt &&
20         !after(TCP_SKB_CB(skb)->ack_seq, tp->snd_nxt)) {
21 }

tcp_flag_word则是取TCP首部中的第4个32位字段,实际上就是上面说的【头部长度+保留字段+标记字段+窗口值】;

1 union tcp_word_hdr { 
2     struct tcphdr hdr;
3     __be32           words[5];
4 }; 
5 
6 #define tcp_flag_word(tp) ( ((union tcp_word_hdr *)(tp))->words [3])

对于保留字段和PSH标记,需要在比对之前屏蔽掉,它们不该影响快慢路的判断;

1 #define TCP_HP_BITS (~(TCP_RESERVED_BITS|TCP_FLAG_PSH))

猜你喜欢

转载自www.cnblogs.com/wanpengcoder/p/11752166.html