aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2012-06-09 17:56:12 -0400
committerDavid S. Miller <davem@davemloft.net>2012-06-09 17:56:12 -0400
commit2397849baa7c44c242e5d5142d5d16d1e7ed53d0 (patch)
tree0ee2012361d1b0f8a92b68da7d0d92209613ecaf
parent4670fd819e7f47392c7c6fc6168ea2857c66d163 (diff)
[PATCH] tcp: Cache inetpeer in timewait socket, and only when necessary.
Since it's guarenteed that we will access the inetpeer if we're trying to do timewait recycling and TCP options were enabled on the connection, just cache the peer in the timewait socket. In the future, inetpeer lookups will be context dependent (per routing realm), and this helps facilitate that as well. Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/tcp.h3
-rw-r--r--include/net/tcp.h1
-rw-r--r--include/net/timewait_sock.h8
-rw-r--r--net/ipv4/tcp_ipv4.c10
-rw-r--r--net/ipv4/tcp_minisocks.c27
-rw-r--r--net/ipv6/tcp_ipv6.c13
6 files changed, 22 insertions, 40 deletions
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 4c5b63283377..23e8234f75a5 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -506,8 +506,9 @@ struct tcp_timewait_sock {
506 u32 tw_rcv_wnd; 506 u32 tw_rcv_wnd;
507 u32 tw_ts_recent; 507 u32 tw_ts_recent;
508 long tw_ts_recent_stamp; 508 long tw_ts_recent_stamp;
509 struct inet_peer *tw_peer;
509#ifdef CONFIG_TCP_MD5SIG 510#ifdef CONFIG_TCP_MD5SIG
510 struct tcp_md5sig_key *tw_md5_key; 511 struct tcp_md5sig_key *tw_md5_key;
511#endif 512#endif
512 /* Few sockets in timewait have cookies; in that case, then this 513 /* Few sockets in timewait have cookies; in that case, then this
513 * object holds a reference to them (tw_cookie_values->kref). 514 * object holds a reference to them (tw_cookie_values->kref).
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 424591866037..9332f342259a 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -328,7 +328,6 @@ extern void tcp_shutdown (struct sock *sk, int how);
328extern int tcp_v4_rcv(struct sk_buff *skb); 328extern int tcp_v4_rcv(struct sk_buff *skb);
329 329
330extern struct inet_peer *tcp_v4_get_peer(struct sock *sk); 330extern struct inet_peer *tcp_v4_get_peer(struct sock *sk);
331extern void *tcp_v4_tw_get_peer(struct sock *sk);
332extern int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw); 331extern int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw);
333extern int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, 332extern int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
334 size_t size); 333 size_t size);
diff --git a/include/net/timewait_sock.h b/include/net/timewait_sock.h
index 8d6689cb2c66..68f0ecad6c6e 100644
--- a/include/net/timewait_sock.h
+++ b/include/net/timewait_sock.h
@@ -22,7 +22,6 @@ struct timewait_sock_ops {
22 int (*twsk_unique)(struct sock *sk, 22 int (*twsk_unique)(struct sock *sk,
23 struct sock *sktw, void *twp); 23 struct sock *sktw, void *twp);
24 void (*twsk_destructor)(struct sock *sk); 24 void (*twsk_destructor)(struct sock *sk);
25 void *(*twsk_getpeer)(struct sock *sk);
26}; 25};
27 26
28static inline int twsk_unique(struct sock *sk, struct sock *sktw, void *twp) 27static inline int twsk_unique(struct sock *sk, struct sock *sktw, void *twp)
@@ -41,11 +40,4 @@ static inline void twsk_destructor(struct sock *sk)
41 sk->sk_prot->twsk_prot->twsk_destructor(sk); 40 sk->sk_prot->twsk_prot->twsk_destructor(sk);
42} 41}
43 42
44static inline void *twsk_getpeer(struct sock *sk)
45{
46 if (sk->sk_prot->twsk_prot->twsk_getpeer)
47 return sk->sk_prot->twsk_prot->twsk_getpeer(sk);
48 return NULL;
49}
50
51#endif /* _TIMEWAIT_SOCK_H */ 43#endif /* _TIMEWAIT_SOCK_H */
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 77f049d00dbb..fda2ca17135e 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1835,20 +1835,10 @@ struct inet_peer *tcp_v4_get_peer(struct sock *sk)
1835} 1835}
1836EXPORT_SYMBOL(tcp_v4_get_peer); 1836EXPORT_SYMBOL(tcp_v4_get_peer);
1837 1837
1838void *tcp_v4_tw_get_peer(struct sock *sk)
1839{
1840 const struct inet_timewait_sock *tw = inet_twsk(sk);
1841 struct net *net = sock_net(sk);
1842
1843 return inet_getpeer_v4(net, tw->tw_daddr, 1);
1844}
1845EXPORT_SYMBOL(tcp_v4_tw_get_peer);
1846
1847static struct timewait_sock_ops tcp_timewait_sock_ops = { 1838static struct timewait_sock_ops tcp_timewait_sock_ops = {
1848 .twsk_obj_size = sizeof(struct tcp_timewait_sock), 1839 .twsk_obj_size = sizeof(struct tcp_timewait_sock),
1849 .twsk_unique = tcp_twsk_unique, 1840 .twsk_unique = tcp_twsk_unique,
1850 .twsk_destructor= tcp_twsk_destructor, 1841 .twsk_destructor= tcp_twsk_destructor,
1851 .twsk_getpeer = tcp_v4_tw_get_peer,
1852}; 1842};
1853 1843
1854const struct inet_connection_sock_af_ops ipv4_specific = { 1844const struct inet_connection_sock_af_ops ipv4_specific = {
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index fef9dbf3af00..cb015317c9f7 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -77,20 +77,19 @@ static bool tcp_remember_stamp(struct sock *sk)
77 77
78static bool tcp_tw_remember_stamp(struct inet_timewait_sock *tw) 78static bool tcp_tw_remember_stamp(struct inet_timewait_sock *tw)
79{ 79{
80 const struct tcp_timewait_sock *tcptw;
80 struct sock *sk = (struct sock *) tw; 81 struct sock *sk = (struct sock *) tw;
81 struct inet_peer *peer; 82 struct inet_peer *peer;
82 83
83 peer = twsk_getpeer(sk); 84 tcptw = tcp_twsk(sk);
85 peer = tcptw->tw_peer;
84 if (peer) { 86 if (peer) {
85 const struct tcp_timewait_sock *tcptw = tcp_twsk(sk);
86
87 if ((s32)(peer->tcp_ts - tcptw->tw_ts_recent) <= 0 || 87 if ((s32)(peer->tcp_ts - tcptw->tw_ts_recent) <= 0 ||
88 ((u32)get_seconds() - peer->tcp_ts_stamp > TCP_PAWS_MSL && 88 ((u32)get_seconds() - peer->tcp_ts_stamp > TCP_PAWS_MSL &&
89 peer->tcp_ts_stamp <= (u32)tcptw->tw_ts_recent_stamp)) { 89 peer->tcp_ts_stamp <= (u32)tcptw->tw_ts_recent_stamp)) {
90 peer->tcp_ts_stamp = (u32)tcptw->tw_ts_recent_stamp; 90 peer->tcp_ts_stamp = (u32)tcptw->tw_ts_recent_stamp;
91 peer->tcp_ts = tcptw->tw_ts_recent; 91 peer->tcp_ts = tcptw->tw_ts_recent;
92 } 92 }
93 inet_putpeer(peer);
94 return true; 93 return true;
95 } 94 }
96 return false; 95 return false;
@@ -314,9 +313,12 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
314 const struct inet_connection_sock *icsk = inet_csk(sk); 313 const struct inet_connection_sock *icsk = inet_csk(sk);
315 const struct tcp_sock *tp = tcp_sk(sk); 314 const struct tcp_sock *tp = tcp_sk(sk);
316 bool recycle_ok = false; 315 bool recycle_ok = false;
316 bool recycle_on = false;
317 317
318 if (tcp_death_row.sysctl_tw_recycle && tp->rx_opt.ts_recent_stamp) 318 if (tcp_death_row.sysctl_tw_recycle && tp->rx_opt.ts_recent_stamp) {
319 recycle_ok = tcp_remember_stamp(sk); 319 recycle_ok = tcp_remember_stamp(sk);
320 recycle_on = true;
321 }
320 322
321 if (tcp_death_row.tw_count < tcp_death_row.sysctl_max_tw_buckets) 323 if (tcp_death_row.tw_count < tcp_death_row.sysctl_max_tw_buckets)
322 tw = inet_twsk_alloc(sk, state); 324 tw = inet_twsk_alloc(sk, state);
@@ -324,8 +326,10 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
324 if (tw != NULL) { 326 if (tw != NULL) {
325 struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw); 327 struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw);
326 const int rto = (icsk->icsk_rto << 2) - (icsk->icsk_rto >> 1); 328 const int rto = (icsk->icsk_rto << 2) - (icsk->icsk_rto >> 1);
329 struct inet_sock *inet = inet_sk(sk);
330 struct inet_peer *peer = NULL;
327 331
328 tw->tw_transparent = inet_sk(sk)->transparent; 332 tw->tw_transparent = inet->transparent;
329 tw->tw_rcv_wscale = tp->rx_opt.rcv_wscale; 333 tw->tw_rcv_wscale = tp->rx_opt.rcv_wscale;
330 tcptw->tw_rcv_nxt = tp->rcv_nxt; 334 tcptw->tw_rcv_nxt = tp->rcv_nxt;
331 tcptw->tw_snd_nxt = tp->snd_nxt; 335 tcptw->tw_snd_nxt = tp->snd_nxt;
@@ -347,6 +351,12 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
347 } 351 }
348#endif 352#endif
349 353
354 if (recycle_on)
355 peer = icsk->icsk_af_ops->get_peer(sk);
356 tcptw->tw_peer = peer;
357 if (peer)
358 atomic_inc(&peer->refcnt);
359
350#ifdef CONFIG_TCP_MD5SIG 360#ifdef CONFIG_TCP_MD5SIG
351 /* 361 /*
352 * The timewait bucket does not have the key DB from the 362 * The timewait bucket does not have the key DB from the
@@ -398,8 +408,11 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
398 408
399void tcp_twsk_destructor(struct sock *sk) 409void tcp_twsk_destructor(struct sock *sk)
400{ 410{
401#ifdef CONFIG_TCP_MD5SIG
402 struct tcp_timewait_sock *twsk = tcp_twsk(sk); 411 struct tcp_timewait_sock *twsk = tcp_twsk(sk);
412
413 if (twsk->tw_peer)
414 inet_putpeer(twsk->tw_peer);
415#ifdef CONFIG_TCP_MD5SIG
403 if (twsk->tw_md5_key) { 416 if (twsk->tw_md5_key) {
404 tcp_free_md5sig_pool(); 417 tcp_free_md5sig_pool();
405 kfree_rcu(twsk->tw_md5_key, rcu); 418 kfree_rcu(twsk->tw_md5_key, rcu);
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index b5ecf37b61a6..f91b0bfd12d5 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1746,23 +1746,10 @@ static struct inet_peer *tcp_v6_get_peer(struct sock *sk)
1746 return rt6_get_peer_create(rt); 1746 return rt6_get_peer_create(rt);
1747} 1747}
1748 1748
1749static void *tcp_v6_tw_get_peer(struct sock *sk)
1750{
1751 const struct inet6_timewait_sock *tw6 = inet6_twsk(sk);
1752 const struct inet_timewait_sock *tw = inet_twsk(sk);
1753 struct net *net = sock_net(sk);
1754
1755 if (tw->tw_family == AF_INET)
1756 return tcp_v4_tw_get_peer(sk);
1757
1758 return inet_getpeer_v6(net, &tw6->tw_v6_daddr, 1);
1759}
1760
1761static struct timewait_sock_ops tcp6_timewait_sock_ops = { 1749static struct timewait_sock_ops tcp6_timewait_sock_ops = {
1762 .twsk_obj_size = sizeof(struct tcp6_timewait_sock), 1750 .twsk_obj_size = sizeof(struct tcp6_timewait_sock),
1763 .twsk_unique = tcp_twsk_unique, 1751 .twsk_unique = tcp_twsk_unique,
1764 .twsk_destructor= tcp_twsk_destructor, 1752 .twsk_destructor= tcp_twsk_destructor,
1765 .twsk_getpeer = tcp_v6_tw_get_peer,
1766}; 1753};
1767 1754
1768static const struct inet_connection_sock_af_ops ipv6_specific = { 1755static const struct inet_connection_sock_af_ops ipv6_specific = {