Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

+22 -40
+2 -1
include/linux/tcp.h
··· 506 506 u32 tw_rcv_wnd; 507 507 u32 tw_ts_recent; 508 508 long tw_ts_recent_stamp; 509 + struct inet_peer *tw_peer; 509 510 #ifdef CONFIG_TCP_MD5SIG 510 - struct tcp_md5sig_key *tw_md5_key; 511 + struct tcp_md5sig_key *tw_md5_key; 511 512 #endif 512 513 /* Few sockets in timewait have cookies; in that case, then this 513 514 * object holds a reference to them (tw_cookie_values->kref).
-1
include/net/tcp.h
··· 328 328 extern int tcp_v4_rcv(struct sk_buff *skb); 329 329 330 330 extern struct inet_peer *tcp_v4_get_peer(struct sock *sk); 331 - extern void *tcp_v4_tw_get_peer(struct sock *sk); 332 331 extern int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw); 333 332 extern int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, 334 333 size_t size);
-8
include/net/timewait_sock.h
··· 22 22 int (*twsk_unique)(struct sock *sk, 23 23 struct sock *sktw, void *twp); 24 24 void (*twsk_destructor)(struct sock *sk); 25 - void *(*twsk_getpeer)(struct sock *sk); 26 25 }; 27 26 28 27 static inline int twsk_unique(struct sock *sk, struct sock *sktw, void *twp) ··· 38 39 BUG_ON(sk->sk_prot->twsk_prot == NULL); 39 40 if (sk->sk_prot->twsk_prot->twsk_destructor != NULL) 40 41 sk->sk_prot->twsk_prot->twsk_destructor(sk); 41 - } 42 - 43 - static inline void *twsk_getpeer(struct sock *sk) 44 - { 45 - if (sk->sk_prot->twsk_prot->twsk_getpeer) 46 - return sk->sk_prot->twsk_prot->twsk_getpeer(sk); 47 - return NULL; 48 42 } 49 43 50 44 #endif /* _TIMEWAIT_SOCK_H */
-10
net/ipv4/tcp_ipv4.c
··· 1835 1835 } 1836 1836 EXPORT_SYMBOL(tcp_v4_get_peer); 1837 1837 1838 - void *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 - } 1845 - EXPORT_SYMBOL(tcp_v4_tw_get_peer); 1846 - 1847 1838 static struct timewait_sock_ops tcp_timewait_sock_ops = { 1848 1839 .twsk_obj_size = sizeof(struct tcp_timewait_sock), 1849 1840 .twsk_unique = tcp_twsk_unique, 1850 1841 .twsk_destructor= tcp_twsk_destructor, 1851 - .twsk_getpeer = tcp_v4_tw_get_peer, 1852 1842 }; 1853 1843 1854 1844 const struct inet_connection_sock_af_ops ipv4_specific = {
+20 -7
net/ipv4/tcp_minisocks.c
··· 77 77 78 78 static bool tcp_tw_remember_stamp(struct inet_timewait_sock *tw) 79 79 { 80 + const struct tcp_timewait_sock *tcptw; 80 81 struct sock *sk = (struct sock *) tw; 81 82 struct inet_peer *peer; 82 83 83 - peer = twsk_getpeer(sk); 84 + tcptw = tcp_twsk(sk); 85 + peer = tcptw->tw_peer; 84 86 if (peer) { 85 - const struct tcp_timewait_sock *tcptw = tcp_twsk(sk); 86 - 87 87 if ((s32)(peer->tcp_ts - tcptw->tw_ts_recent) <= 0 || 88 88 ((u32)get_seconds() - peer->tcp_ts_stamp > TCP_PAWS_MSL && 89 89 peer->tcp_ts_stamp <= (u32)tcptw->tw_ts_recent_stamp)) { 90 90 peer->tcp_ts_stamp = (u32)tcptw->tw_ts_recent_stamp; 91 91 peer->tcp_ts = tcptw->tw_ts_recent; 92 92 } 93 - inet_putpeer(peer); 94 93 return true; 95 94 } 96 95 return false; ··· 313 314 const struct inet_connection_sock *icsk = inet_csk(sk); 314 315 const struct tcp_sock *tp = tcp_sk(sk); 315 316 bool recycle_ok = false; 317 + bool recycle_on = false; 316 318 317 - if (tcp_death_row.sysctl_tw_recycle && tp->rx_opt.ts_recent_stamp) 319 + if (tcp_death_row.sysctl_tw_recycle && tp->rx_opt.ts_recent_stamp) { 318 320 recycle_ok = tcp_remember_stamp(sk); 321 + recycle_on = true; 322 + } 319 323 320 324 if (tcp_death_row.tw_count < tcp_death_row.sysctl_max_tw_buckets) 321 325 tw = inet_twsk_alloc(sk, state); ··· 326 324 if (tw != NULL) { 327 325 struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw); 328 326 const int rto = (icsk->icsk_rto << 2) - (icsk->icsk_rto >> 1); 327 + struct inet_sock *inet = inet_sk(sk); 328 + struct inet_peer *peer = NULL; 329 329 330 - tw->tw_transparent = inet_sk(sk)->transparent; 330 + tw->tw_transparent = inet->transparent; 331 331 tw->tw_rcv_wscale = tp->rx_opt.rcv_wscale; 332 332 tcptw->tw_rcv_nxt = tp->rcv_nxt; 333 333 tcptw->tw_snd_nxt = tp->snd_nxt; ··· 350 346 tw->tw_ipv6only = np->ipv6only; 351 347 } 352 348 #endif 349 + 350 + if (recycle_on) 351 + peer = icsk->icsk_af_ops->get_peer(sk); 352 + tcptw->tw_peer = peer; 353 + if (peer) 354 + atomic_inc(&peer->refcnt); 353 355 354 356 #ifdef CONFIG_TCP_MD5SIG 355 357 /* ··· 408 398 409 399 void tcp_twsk_destructor(struct sock *sk) 410 400 { 411 - #ifdef CONFIG_TCP_MD5SIG 412 401 struct tcp_timewait_sock *twsk = tcp_twsk(sk); 402 + 403 + if (twsk->tw_peer) 404 + inet_putpeer(twsk->tw_peer); 405 + #ifdef CONFIG_TCP_MD5SIG 413 406 if (twsk->tw_md5_key) { 414 407 tcp_free_md5sig_pool(); 415 408 kfree_rcu(twsk->tw_md5_key, rcu);
-13
net/ipv6/tcp_ipv6.c
··· 1746 1746 return rt6_get_peer_create(rt); 1747 1747 } 1748 1748 1749 - static 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 - 1761 1749 static struct timewait_sock_ops tcp6_timewait_sock_ops = { 1762 1750 .twsk_obj_size = sizeof(struct tcp6_timewait_sock), 1763 1751 .twsk_unique = tcp_twsk_unique, 1764 1752 .twsk_destructor= tcp_twsk_destructor, 1765 - .twsk_getpeer = tcp_v6_tw_get_peer, 1766 1753 }; 1767 1754 1768 1755 static const struct inet_connection_sock_af_ops ipv6_specific = {