日期:2014-05-16 浏览次数:20900 次
/* This retransmits one SKB. Policy decisions and retransmit queue * state updates are done by the caller. Returns non-zero if an * error occurred which prevented the send. */ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) { struct tcp_sock *tp = tcp_sk(sk); struct inet_connection_sock *icsk = inet_csk(sk); unsigned int cur_mss = tcp_current_mss(sk, 0); int err; /* Inconslusive MTU probe */ if (icsk->icsk_mtup.probe_size) { icsk->icsk_mtup.probe_size = 0; } /* Do not sent more than we queued. 1/4 is reserved for possible * copying overhead: fragmentation, tunneling, mangling etc. */ // 如果消耗很多的内存做其他事,那么就没有多余的来做队列的处理了~ if (atomic_read(&sk->sk_wmem_alloc) > // sk_wmem_alloc:传输队列大小 min(sk->sk_wmem_queued + (sk->sk_wmem_queued >> 2), sk->sk_sndbuf)) // sk_wmem_queud:固定的队列大小 return -EAGAIN; if (before(TCP_SKB_CB(skb)->seq, tp->snd_una)) {// 若这样,说明是有一部分数据才需要重传,形如:seq---snd_una---end_seq,前面一半已收到ACK if (before(TCP_SKB_CB(skb)->end_seq, tp->snd_una)) // 若这样,说明全部ACK,无需重传,BUG BUG(); if (tcp_trim_head(sk, skb, tp->snd_una - TCP_SKB_CB(skb)->seq)) // 一些控制信息检查 return -ENOMEM; } /* If receiver has shrunk his window, and skb is out of * new window, do not retransmit it. The exception is the * case, when window is shrunk to zero. In this case * our retransmit serves as a zero window probe. */ if (!before(TCP_SKB_CB(skb)->seq, tcp_wnd_end(tp)) // 如果数据在窗口后面,不会发送 && TCP_SKB_CB(skb)->seq != tp->snd_una) return -EAGAIN; if (skb->len > cur_mss) { // 如果skb长度 > MSS if (tcp_fragment(sk, skb, cur_mss, cur_mss)) // 先分片。再传送 return -ENOMEM; /* We'll try again later. */ } /* Collapse two adjacent packets if worthwhile and we can. */ // 我*,这么多条件 if (!(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_SYN) && // SYN包 (skb->len < (cur_mss >> 1)) && // 长度<半个MSS (tcp_write_queue_next(sk, skb) != tcp_send_head(sk)) && // 不是结尾 (!tcp_skb_is_last(sk, skb)) && // 不是最后一个 (skb_shinfo(skb)->nr_frags == 0 && // 没有分页数据 skb_shinfo(tcp_write_queue_next(sk, skb))->nr_frags == 0) && (tcp_skb_pcount(skb) == 1 && // gso_segs=1 tcp_skb_pcount(tcp_write_queue_next(sk, skb)) == 1) && (sysctl_tcp_retrans_collapse != 0)) tcp_retrans_try_collapse(sk, skb, cur_mss); // 这个函数不是很明白,待看~~~~~~~~~~~~~~~~~~~~~~~~~ if (inet_csk(sk)->icsk_af_ops->rebuild_header(sk)) // 根据目的地址等条件获取路由,如果获取路由失败就不能发送 return -EHOSTUNREACH; /* Routing failure or similar. */ /* Some Solaris stacks overoptimize and ignore the FIN on a * retransmit when old data is attached. So strip it off * since it is cheap to do so and saves bytes on the network. *///Solaris系统的协议栈有时候会忽略重传SKB上带有的FIN标志的payload,将payload全部剥离掉,节省网络流量 if (skb->len > 0 && (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN) && tp->snd_una == (TCP_SKB_CB(skb)->end_seq - 1)) {