- static int tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
- int push_one, gfp_t gfp)
-
{
- struct tcp_sock *tp = tcp_sk(sk);
- struct sk_buff *skb;
- unsigned int tso_segs, sent_pkts;
- int cwnd_quota;
- int result;
- sent_pkts = 0;
/* 检查是不是只发送一个skb buffer,即push one */
- if (!push_one) {
-
/*
- 如果要发送多个skb,则需要检测MTU。
- 这时会检测MTU,希望MTU可以比之前的大,提高发送效率。
- */
- /* Do MTU probing. */
- result = tcp_mtu_probe(sk);
- if (!result) {
- return 0;
- } else if (result > 0) {
- sent_pkts = 1;
- }
- }
/* 检查是否还有skb要发送 */
- while ((skb = tcp_send_head(sk))) {
- unsigned int limit;
/*
初始化TSO
*/
- tso_segs = tcp_init_tso_segs(sk, skb, mss_now);
- BUG_ON(!tso_segs);
/* 检查congestion windows, 可以发送几个segment */
- cwnd_quota = tcp_cwnd_test(tp, skb);
- if (!cwnd_quota)
- break;
/* 检查发送窗口,是否可以容纳至少一个segment */
- if (unlikely(!tcp_snd_wnd_test(tp, skb, mss_now)))
- break;
- if (tso_segs == 1) {
-
/* 根据nagle算法,计算是否需要发送数据 */
- if (unlikely(!tcp_nagle_test(tp, skb, mss_now,
- (tcp_skb_is_last(sk, skb) ?
- nonagle : TCP_NAGLE_PUSH))))
- break;
- } else {
-
/* 当不止一个skb时,通过TSO计算是否需要延时发送 */
- if (!push_one && tcp_tso_should_defer(sk, skb))
- break;
- }
- limit = mss_now;
-
/* 在TSO分片大于1的情况下,且TCP不是URG模式。通过MSS计算发送数据的limit */
- if (tso_segs > 1 && !tcp_urg_mode(tp))
- limit = tcp_mss_split_point(sk, skb, mss_now,
- cwnd_quota);
/* 当skb的长度大于限制时,需要调用tso_fragment分片 */
- if (skb->len > limit &&
- unlikely(tso_fragment(sk, skb, limit, mss_now, gfp)))
- break;
/* 更新tcp的时间戳 */
- TCP_SKB_CB(skb)->when = tcp_time_stamp;
/* 发送skb数据 */
- if (unlikely(tcp_transmit_skb(sk, skb, 1, gfp)))
- break;
- /* Advance the send_head. This one is sent out.
- * This call will increment packets_out.
- */
-
/* 更新统计,并启动重传计时器 */
- tcp_event_new_data_sent(sk, skb);
- tcp_minshall_update(tp, mss_now, skb);
- sent_pkts++;
- if (push_one)
- break;
- }
- if (likely(sent_pkts)) {
- tcp_cwnd_validate(sk);
- return 0;
- }
- return !tp->packets_out && tcp_send_head(sk);
- }