125 lines
4.4 KiB
Diff
125 lines
4.4 KiB
Diff
From 1485348d2424e1131ea42efc033cbd9366462b01 Mon Sep 17 00:00:00 2001
|
|
From: Ben Hutchings <bhutchings@solarflare.com>
|
|
Date: Mon, 30 Jul 2012 16:11:42 +0000
|
|
Subject: [PATCH] tcp: Apply device TSO segment limit earlier
|
|
|
|
Cache the device gso_max_segs in sock::sk_gso_max_segs and use it to
|
|
limit the size of TSO skbs. This avoids the need to fall back to
|
|
software GSO for local TCP senders.
|
|
|
|
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
|
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
---
|
|
include/net/sock.h | 2 ++
|
|
net/core/sock.c | 1 +
|
|
net/ipv4/tcp.c | 4 +++-
|
|
net/ipv4/tcp_cong.c | 3 ++-
|
|
net/ipv4/tcp_output.c | 21 ++++++++++++---------
|
|
5 files changed, 20 insertions(+), 11 deletions(-)
|
|
|
|
--- linux-3.4.noarch.orig/include/net/sock.h
|
|
+++ linux-3.4.noarch/include/net/sock.h
|
|
@@ -216,6 +216,7 @@ struct cg_proto;
|
|
* @sk_route_nocaps: forbidden route capabilities (e.g NETIF_F_GSO_MASK)
|
|
* @sk_gso_type: GSO type (e.g. %SKB_GSO_TCPV4)
|
|
* @sk_gso_max_size: Maximum GSO segment size to build
|
|
+ * @sk_gso_max_segs: Maximum number of GSO segments
|
|
* @sk_lingertime: %SO_LINGER l_linger setting
|
|
* @sk_backlog: always used with the per-socket spinlock held
|
|
* @sk_callback_lock: used with the callbacks in the end of this struct
|
|
@@ -335,6 +336,7 @@ struct sock {
|
|
netdev_features_t sk_route_nocaps;
|
|
int sk_gso_type;
|
|
unsigned int sk_gso_max_size;
|
|
+ u16 sk_gso_max_segs;
|
|
int sk_rcvlowat;
|
|
unsigned long sk_lingertime;
|
|
struct sk_buff_head sk_error_queue;
|
|
--- linux-3.4.noarch.orig/net/core/sock.c
|
|
+++ linux-3.4.noarch/net/core/sock.c
|
|
@@ -1411,6 +1411,7 @@ void sk_setup_caps(struct sock *sk, stru
|
|
} else {
|
|
sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM;
|
|
sk->sk_gso_max_size = dst->dev->gso_max_size;
|
|
+ sk->sk_gso_max_segs = dst->dev->gso_max_segs;
|
|
}
|
|
}
|
|
}
|
|
--- linux-3.4.noarch.orig/net/ipv4/tcp.c
|
|
+++ linux-3.4.noarch/net/ipv4/tcp.c
|
|
@@ -740,7 +740,9 @@ static unsigned int tcp_xmit_size_goal(s
|
|
old_size_goal + mss_now > xmit_size_goal)) {
|
|
xmit_size_goal = old_size_goal;
|
|
} else {
|
|
- tp->xmit_size_goal_segs = xmit_size_goal / mss_now;
|
|
+ tp->xmit_size_goal_segs =
|
|
+ min_t(u16, xmit_size_goal / mss_now,
|
|
+ sk->sk_gso_max_segs);
|
|
xmit_size_goal = tp->xmit_size_goal_segs * mss_now;
|
|
}
|
|
}
|
|
--- linux-3.4.noarch.orig/net/ipv4/tcp_cong.c
|
|
+++ linux-3.4.noarch/net/ipv4/tcp_cong.c
|
|
@@ -291,7 +291,8 @@ int tcp_is_cwnd_limited(const struct soc
|
|
left = tp->snd_cwnd - in_flight;
|
|
if (sk_can_gso(sk) &&
|
|
left * sysctl_tcp_tso_win_divisor < tp->snd_cwnd &&
|
|
- left * tp->mss_cache < sk->sk_gso_max_size)
|
|
+ left * tp->mss_cache < sk->sk_gso_max_size &&
|
|
+ left < sk->sk_gso_max_segs)
|
|
return 1;
|
|
return left <= tcp_max_tso_deferred_mss(tp);
|
|
}
|
|
--- linux-3.4.noarch.orig/net/ipv4/tcp_output.c
|
|
+++ linux-3.4.noarch/net/ipv4/tcp_output.c
|
|
@@ -1318,21 +1318,21 @@ static void tcp_cwnd_validate(struct soc
|
|
* when we would be allowed to send the split-due-to-Nagle skb fully.
|
|
*/
|
|
static unsigned int tcp_mss_split_point(const struct sock *sk, const struct sk_buff *skb,
|
|
- unsigned int mss_now, unsigned int cwnd)
|
|
+ unsigned int mss_now, unsigned int max_segs)
|
|
{
|
|
const struct tcp_sock *tp = tcp_sk(sk);
|
|
- u32 needed, window, cwnd_len;
|
|
+ u32 needed, window, max_len;
|
|
|
|
window = tcp_wnd_end(tp) - TCP_SKB_CB(skb)->seq;
|
|
- cwnd_len = mss_now * cwnd;
|
|
+ max_len = mss_now * max_segs;
|
|
|
|
- if (likely(cwnd_len <= window && skb != tcp_write_queue_tail(sk)))
|
|
- return cwnd_len;
|
|
+ if (likely(max_len <= window && skb != tcp_write_queue_tail(sk)))
|
|
+ return max_len;
|
|
|
|
needed = min(skb->len, window);
|
|
|
|
- if (cwnd_len <= needed)
|
|
- return cwnd_len;
|
|
+ if (max_len <= needed)
|
|
+ return max_len;
|
|
|
|
return needed - needed % mss_now;
|
|
}
|
|
@@ -1560,7 +1560,8 @@ static int tcp_tso_should_defer(struct s
|
|
limit = min(send_win, cong_win);
|
|
|
|
/* If a full-sized TSO skb can be sent, do it. */
|
|
- if (limit >= sk->sk_gso_max_size)
|
|
+ if (limit >= min_t(unsigned int, sk->sk_gso_max_size,
|
|
+ sk->sk_gso_max_segs * tp->mss_cache))
|
|
goto send_now;
|
|
|
|
/* Middle in queue won't get any more data, full sendable already? */
|
|
@@ -1786,7 +1787,9 @@ static int tcp_write_xmit(struct sock *s
|
|
limit = mss_now;
|
|
if (tso_segs > 1 && !tcp_urg_mode(tp))
|
|
limit = tcp_mss_split_point(sk, skb, mss_now,
|
|
- cwnd_quota);
|
|
+ min_t(unsigned int,
|
|
+ cwnd_quota,
|
|
+ sk->sk_gso_max_segs));
|
|
|
|
if (skb->len > limit &&
|
|
unlikely(tso_fragment(sk, skb, limit, mss_now, gfp)))
|