[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>
This commit is contained in:
parent
158a0e45b6
commit
d5ac99a648
2 changed files with 20 additions and 16 deletions
|
@ -1417,19 +1417,20 @@ tcp_nagle_check(const struct tcp_sock *tp, const struct sk_buff *skb,
|
|||
tcp_minshall_check(tp))));
|
||||
}
|
||||
|
||||
extern void tcp_set_skb_tso_segs(struct sk_buff *, unsigned int);
|
||||
extern void tcp_set_skb_tso_segs(struct sock *, struct sk_buff *);
|
||||
|
||||
/* This checks if the data bearing packet SKB (usually sk->sk_send_head)
|
||||
* should be put on the wire right now.
|
||||
*/
|
||||
static __inline__ int tcp_snd_test(const struct tcp_sock *tp,
|
||||
static __inline__ int tcp_snd_test(struct sock *sk,
|
||||
struct sk_buff *skb,
|
||||
unsigned cur_mss, int nonagle)
|
||||
{
|
||||
struct tcp_sock *tp = tcp_sk(sk);
|
||||
int pkts = tcp_skb_pcount(skb);
|
||||
|
||||
if (!pkts) {
|
||||
tcp_set_skb_tso_segs(skb, tp->mss_cache_std);
|
||||
tcp_set_skb_tso_segs(sk, skb);
|
||||
pkts = tcp_skb_pcount(skb);
|
||||
}
|
||||
|
||||
|
@ -1490,7 +1491,7 @@ static __inline__ void __tcp_push_pending_frames(struct sock *sk,
|
|||
if (skb) {
|
||||
if (!tcp_skb_is_last(sk, skb))
|
||||
nonagle = TCP_NAGLE_PUSH;
|
||||
if (!tcp_snd_test(tp, skb, cur_mss, nonagle) ||
|
||||
if (!tcp_snd_test(sk, skb, cur_mss, nonagle) ||
|
||||
tcp_write_xmit(sk, nonagle))
|
||||
tcp_check_probe_timer(sk, tp);
|
||||
}
|
||||
|
@ -1508,7 +1509,7 @@ static __inline__ int tcp_may_send_now(struct sock *sk, struct tcp_sock *tp)
|
|||
struct sk_buff *skb = sk->sk_send_head;
|
||||
|
||||
return (skb &&
|
||||
tcp_snd_test(tp, skb, tcp_current_mss(sk, 1),
|
||||
tcp_snd_test(sk, skb, tcp_current_mss(sk, 1),
|
||||
tcp_skb_is_last(sk, skb) ? TCP_NAGLE_PUSH : tp->nonagle));
|
||||
}
|
||||
|
||||
|
|
|
@ -427,7 +427,7 @@ void tcp_push_one(struct sock *sk, unsigned cur_mss)
|
|||
struct tcp_sock *tp = tcp_sk(sk);
|
||||
struct sk_buff *skb = sk->sk_send_head;
|
||||
|
||||
if (tcp_snd_test(tp, skb, cur_mss, TCP_NAGLE_PUSH)) {
|
||||
if (tcp_snd_test(sk, skb, cur_mss, TCP_NAGLE_PUSH)) {
|
||||
/* Send it out now. */
|
||||
TCP_SKB_CB(skb)->when = tcp_time_stamp;
|
||||
tcp_tso_set_push(skb);
|
||||
|
@ -440,9 +440,12 @@ void tcp_push_one(struct sock *sk, unsigned cur_mss)
|
|||
}
|
||||
}
|
||||
|
||||
void tcp_set_skb_tso_segs(struct sk_buff *skb, unsigned int mss_std)
|
||||
void tcp_set_skb_tso_segs(struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
if (skb->len <= mss_std) {
|
||||
struct tcp_sock *tp = tcp_sk(sk);
|
||||
|
||||
if (skb->len <= tp->mss_cache_std ||
|
||||
!(sk->sk_route_caps & NETIF_F_TSO)) {
|
||||
/* Avoid the costly divide in the normal
|
||||
* non-TSO case.
|
||||
*/
|
||||
|
@ -451,10 +454,10 @@ void tcp_set_skb_tso_segs(struct sk_buff *skb, unsigned int mss_std)
|
|||
} else {
|
||||
unsigned int factor;
|
||||
|
||||
factor = skb->len + (mss_std - 1);
|
||||
factor /= mss_std;
|
||||
factor = skb->len + (tp->mss_cache_std - 1);
|
||||
factor /= tp->mss_cache_std;
|
||||
skb_shinfo(skb)->tso_segs = factor;
|
||||
skb_shinfo(skb)->tso_size = mss_std;
|
||||
skb_shinfo(skb)->tso_size = tp->mss_cache_std;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -525,8 +528,8 @@ static int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len)
|
|||
}
|
||||
|
||||
/* Fix up tso_factor for both original and new SKB. */
|
||||
tcp_set_skb_tso_segs(skb, tp->mss_cache_std);
|
||||
tcp_set_skb_tso_segs(buff, tp->mss_cache_std);
|
||||
tcp_set_skb_tso_segs(sk, skb);
|
||||
tcp_set_skb_tso_segs(sk, buff);
|
||||
|
||||
if (TCP_SKB_CB(skb)->sacked & TCPCB_LOST) {
|
||||
tp->lost_out += tcp_skb_pcount(skb);
|
||||
|
@ -601,7 +604,7 @@ int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len)
|
|||
* factor and mss.
|
||||
*/
|
||||
if (tcp_skb_pcount(skb) > 1)
|
||||
tcp_set_skb_tso_segs(skb, tcp_skb_mss(skb));
|
||||
tcp_set_skb_tso_segs(sk, skb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -752,7 +755,7 @@ int tcp_write_xmit(struct sock *sk, int nonagle)
|
|||
mss_now = tcp_current_mss(sk, 1);
|
||||
|
||||
while ((skb = sk->sk_send_head) &&
|
||||
tcp_snd_test(tp, skb, mss_now,
|
||||
tcp_snd_test(sk, skb, mss_now,
|
||||
tcp_skb_is_last(sk, skb) ? nonagle :
|
||||
TCP_NAGLE_PUSH)) {
|
||||
if (skb->len > mss_now) {
|
||||
|
@ -1676,7 +1679,7 @@ int tcp_write_wakeup(struct sock *sk)
|
|||
tp->mss_cache = tp->mss_cache_std;
|
||||
}
|
||||
} else if (!tcp_skb_pcount(skb))
|
||||
tcp_set_skb_tso_segs(skb, tp->mss_cache_std);
|
||||
tcp_set_skb_tso_segs(sk, skb);
|
||||
|
||||
TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH;
|
||||
TCP_SKB_CB(skb)->when = tcp_time_stamp;
|
||||
|
|
Loading…
Reference in a new issue