- 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,参考:
*/
-
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);
-
}