diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2005-04-24 22:12:33 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2005-04-24 22:12:33 -0400 |
commit | d5ac99a648b8c61d0c7f1c32a8ab7f1dca0123d2 (patch) | |
tree | 3811d84e83dab918c57aeca1081ae343cb97df8b | |
parent | 158a0e45b69254a9ee4d7795e3b98d8c959fb799 (diff) |
[TCP]: skb pcount with MTU discovery
The problem is that when doing MTU discovery, the too-large segments in
the write queue will be calculated as having a pcount of >1. When
tcp_write_xmit() is trying to send, tcp_snd_test() fails the cwnd test
when pcount > cwnd.
The segments are eventually transmitted one at a time by keepalive, but
this can take a long time.
This patch checks if TSO is enabled when setting pcount.
Signed-off-by: John Heffner <jheffner@psc.edu>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/tcp.h | 11 | ||||
-rw-r--r-- | net/ipv4/tcp_output.c | 25 |
2 files changed, 20 insertions, 16 deletions
diff --git a/include/net/tcp.h b/include/net/tcp.h index 503810a70e21..9355ae5b1d75 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h | |||
@@ -1417,19 +1417,20 @@ tcp_nagle_check(const struct tcp_sock *tp, const struct sk_buff *skb, | |||
1417 | tcp_minshall_check(tp)))); | 1417 | tcp_minshall_check(tp)))); |
1418 | } | 1418 | } |
1419 | 1419 | ||
1420 | extern void tcp_set_skb_tso_segs(struct sk_buff *, unsigned int); | 1420 | extern void tcp_set_skb_tso_segs(struct sock *, struct sk_buff *); |
1421 | 1421 | ||
1422 | /* This checks if the data bearing packet SKB (usually sk->sk_send_head) | 1422 | /* This checks if the data bearing packet SKB (usually sk->sk_send_head) |
1423 | * should be put on the wire right now. | 1423 | * should be put on the wire right now. |
1424 | */ | 1424 | */ |
1425 | static __inline__ int tcp_snd_test(const struct tcp_sock *tp, | 1425 | static __inline__ int tcp_snd_test(struct sock *sk, |
1426 | struct sk_buff *skb, | 1426 | struct sk_buff *skb, |
1427 | unsigned cur_mss, int nonagle) | 1427 | unsigned cur_mss, int nonagle) |
1428 | { | 1428 | { |
1429 | struct tcp_sock *tp = tcp_sk(sk); | ||
1429 | int pkts = tcp_skb_pcount(skb); | 1430 | int pkts = tcp_skb_pcount(skb); |
1430 | 1431 | ||
1431 | if (!pkts) { | 1432 | if (!pkts) { |
1432 | tcp_set_skb_tso_segs(skb, tp->mss_cache_std); | 1433 | tcp_set_skb_tso_segs(sk, skb); |
1433 | pkts = tcp_skb_pcount(skb); | 1434 | pkts = tcp_skb_pcount(skb); |
1434 | } | 1435 | } |
1435 | 1436 | ||
@@ -1490,7 +1491,7 @@ static __inline__ void __tcp_push_pending_frames(struct sock *sk, | |||
1490 | if (skb) { | 1491 | if (skb) { |
1491 | if (!tcp_skb_is_last(sk, skb)) | 1492 | if (!tcp_skb_is_last(sk, skb)) |
1492 | nonagle = TCP_NAGLE_PUSH; | 1493 | nonagle = TCP_NAGLE_PUSH; |
1493 | if (!tcp_snd_test(tp, skb, cur_mss, nonagle) || | 1494 | if (!tcp_snd_test(sk, skb, cur_mss, nonagle) || |
1494 | tcp_write_xmit(sk, nonagle)) | 1495 | tcp_write_xmit(sk, nonagle)) |
1495 | tcp_check_probe_timer(sk, tp); | 1496 | tcp_check_probe_timer(sk, tp); |
1496 | } | 1497 | } |
@@ -1508,7 +1509,7 @@ static __inline__ int tcp_may_send_now(struct sock *sk, struct tcp_sock *tp) | |||
1508 | struct sk_buff *skb = sk->sk_send_head; | 1509 | struct sk_buff *skb = sk->sk_send_head; |
1509 | 1510 | ||
1510 | return (skb && | 1511 | return (skb && |
1511 | tcp_snd_test(tp, skb, tcp_current_mss(sk, 1), | 1512 | tcp_snd_test(sk, skb, tcp_current_mss(sk, 1), |
1512 | tcp_skb_is_last(sk, skb) ? TCP_NAGLE_PUSH : tp->nonagle)); | 1513 | tcp_skb_is_last(sk, skb) ? TCP_NAGLE_PUSH : tp->nonagle)); |
1513 | } | 1514 | } |
1514 | 1515 | ||
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 13c14cb6dee4..a12df6979ffd 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
@@ -427,7 +427,7 @@ void tcp_push_one(struct sock *sk, unsigned cur_mss) | |||
427 | struct tcp_sock *tp = tcp_sk(sk); | 427 | struct tcp_sock *tp = tcp_sk(sk); |
428 | struct sk_buff *skb = sk->sk_send_head; | 428 | struct sk_buff *skb = sk->sk_send_head; |
429 | 429 | ||
430 | if (tcp_snd_test(tp, skb, cur_mss, TCP_NAGLE_PUSH)) { | 430 | if (tcp_snd_test(sk, skb, cur_mss, TCP_NAGLE_PUSH)) { |
431 | /* Send it out now. */ | 431 | /* Send it out now. */ |
432 | TCP_SKB_CB(skb)->when = tcp_time_stamp; | 432 | TCP_SKB_CB(skb)->when = tcp_time_stamp; |
433 | tcp_tso_set_push(skb); | 433 | tcp_tso_set_push(skb); |
@@ -440,9 +440,12 @@ void tcp_push_one(struct sock *sk, unsigned cur_mss) | |||
440 | } | 440 | } |
441 | } | 441 | } |
442 | 442 | ||
443 | void tcp_set_skb_tso_segs(struct sk_buff *skb, unsigned int mss_std) | 443 | void tcp_set_skb_tso_segs(struct sock *sk, struct sk_buff *skb) |
444 | { | 444 | { |
445 | if (skb->len <= mss_std) { | 445 | struct tcp_sock *tp = tcp_sk(sk); |
446 | |||
447 | if (skb->len <= tp->mss_cache_std || | ||
448 | !(sk->sk_route_caps & NETIF_F_TSO)) { | ||
446 | /* Avoid the costly divide in the normal | 449 | /* Avoid the costly divide in the normal |
447 | * non-TSO case. | 450 | * non-TSO case. |
448 | */ | 451 | */ |
@@ -451,10 +454,10 @@ void tcp_set_skb_tso_segs(struct sk_buff *skb, unsigned int mss_std) | |||
451 | } else { | 454 | } else { |
452 | unsigned int factor; | 455 | unsigned int factor; |
453 | 456 | ||
454 | factor = skb->len + (mss_std - 1); | 457 | factor = skb->len + (tp->mss_cache_std - 1); |
455 | factor /= mss_std; | 458 | factor /= tp->mss_cache_std; |
456 | skb_shinfo(skb)->tso_segs = factor; | 459 | skb_shinfo(skb)->tso_segs = factor; |
457 | skb_shinfo(skb)->tso_size = mss_std; | 460 | skb_shinfo(skb)->tso_size = tp->mss_cache_std; |
458 | } | 461 | } |
459 | } | 462 | } |
460 | 463 | ||
@@ -525,8 +528,8 @@ static int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len) | |||
525 | } | 528 | } |
526 | 529 | ||
527 | /* Fix up tso_factor for both original and new SKB. */ | 530 | /* Fix up tso_factor for both original and new SKB. */ |
528 | tcp_set_skb_tso_segs(skb, tp->mss_cache_std); | 531 | tcp_set_skb_tso_segs(sk, skb); |
529 | tcp_set_skb_tso_segs(buff, tp->mss_cache_std); | 532 | tcp_set_skb_tso_segs(sk, buff); |
530 | 533 | ||
531 | if (TCP_SKB_CB(skb)->sacked & TCPCB_LOST) { | 534 | if (TCP_SKB_CB(skb)->sacked & TCPCB_LOST) { |
532 | tp->lost_out += tcp_skb_pcount(skb); | 535 | tp->lost_out += tcp_skb_pcount(skb); |
@@ -601,7 +604,7 @@ int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len) | |||
601 | * factor and mss. | 604 | * factor and mss. |
602 | */ | 605 | */ |
603 | if (tcp_skb_pcount(skb) > 1) | 606 | if (tcp_skb_pcount(skb) > 1) |
604 | tcp_set_skb_tso_segs(skb, tcp_skb_mss(skb)); | 607 | tcp_set_skb_tso_segs(sk, skb); |
605 | 608 | ||
606 | return 0; | 609 | return 0; |
607 | } | 610 | } |
@@ -752,7 +755,7 @@ int tcp_write_xmit(struct sock *sk, int nonagle) | |||
752 | mss_now = tcp_current_mss(sk, 1); | 755 | mss_now = tcp_current_mss(sk, 1); |
753 | 756 | ||
754 | while ((skb = sk->sk_send_head) && | 757 | while ((skb = sk->sk_send_head) && |
755 | tcp_snd_test(tp, skb, mss_now, | 758 | tcp_snd_test(sk, skb, mss_now, |
756 | tcp_skb_is_last(sk, skb) ? nonagle : | 759 | tcp_skb_is_last(sk, skb) ? nonagle : |
757 | TCP_NAGLE_PUSH)) { | 760 | TCP_NAGLE_PUSH)) { |
758 | if (skb->len > mss_now) { | 761 | if (skb->len > mss_now) { |
@@ -1676,7 +1679,7 @@ int tcp_write_wakeup(struct sock *sk) | |||
1676 | tp->mss_cache = tp->mss_cache_std; | 1679 | tp->mss_cache = tp->mss_cache_std; |
1677 | } | 1680 | } |
1678 | } else if (!tcp_skb_pcount(skb)) | 1681 | } else if (!tcp_skb_pcount(skb)) |
1679 | tcp_set_skb_tso_segs(skb, tp->mss_cache_std); | 1682 | tcp_set_skb_tso_segs(sk, skb); |
1680 | 1683 | ||
1681 | TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH; | 1684 | TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH; |
1682 | TCP_SKB_CB(skb)->when = tcp_time_stamp; | 1685 | TCP_SKB_CB(skb)->when = tcp_time_stamp; |