Commit ccb7c410ddc054b8c1ae780319bc98ae092d3854
1 parent
4399ce402c
Exists in
master
and in
7 other branches
timewait_sock: Create and use getpeer op.
The only thing AF-specific about remembering the timestamp for a time-wait TCP socket is getting the peer. Abstract that behind a new timewait_sock_ops vector. Support for real IPV6 sockets is not filled in yet, but curiously this makes timewait recycling start to work for v4-mapped ipv6 sockets. Signed-off-by: David S. Miller <davem@davemloft.net>
Showing 5 changed files with 63 additions and 37 deletions Side-by-side Diff
include/net/tcp.h
... | ... | @@ -313,6 +313,7 @@ |
313 | 313 | extern int tcp_v4_rcv(struct sk_buff *skb); |
314 | 314 | |
315 | 315 | extern struct inet_peer *tcp_v4_get_peer(struct sock *sk, bool *release_it); |
316 | +extern void *tcp_v4_tw_get_peer(struct sock *sk); | |
316 | 317 | extern int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw); |
317 | 318 | extern int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, |
318 | 319 | size_t size); |
include/net/timewait_sock.h
... | ... | @@ -21,6 +21,7 @@ |
21 | 21 | int (*twsk_unique)(struct sock *sk, |
22 | 22 | struct sock *sktw, void *twp); |
23 | 23 | void (*twsk_destructor)(struct sock *sk); |
24 | + void *(*twsk_getpeer)(struct sock *sk); | |
24 | 25 | }; |
25 | 26 | |
26 | 27 | static inline int twsk_unique(struct sock *sk, struct sock *sktw, void *twp) |
... | ... | @@ -37,6 +38,13 @@ |
37 | 38 | BUG_ON(sk->sk_prot->twsk_prot == NULL); |
38 | 39 | if (sk->sk_prot->twsk_prot->twsk_destructor != NULL) |
39 | 40 | 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; | |
40 | 48 | } |
41 | 49 | |
42 | 50 | #endif /* _TIMEWAIT_SOCK_H */ |
net/ipv4/tcp_ipv4.c
... | ... | @@ -1210,12 +1210,6 @@ |
1210 | 1210 | }; |
1211 | 1211 | #endif |
1212 | 1212 | |
1213 | -static struct timewait_sock_ops tcp_timewait_sock_ops = { | |
1214 | - .twsk_obj_size = sizeof(struct tcp_timewait_sock), | |
1215 | - .twsk_unique = tcp_twsk_unique, | |
1216 | - .twsk_destructor= tcp_twsk_destructor, | |
1217 | -}; | |
1218 | - | |
1219 | 1213 | int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) |
1220 | 1214 | { |
1221 | 1215 | struct tcp_extend_values tmp_ext; |
1222 | 1216 | |
1223 | 1217 | |
1224 | 1218 | |
... | ... | @@ -1783,25 +1777,20 @@ |
1783 | 1777 | } |
1784 | 1778 | EXPORT_SYMBOL(tcp_v4_get_peer); |
1785 | 1779 | |
1786 | -int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw) | |
1780 | +void *tcp_v4_tw_get_peer(struct sock *sk) | |
1787 | 1781 | { |
1788 | - struct inet_peer *peer = inet_getpeer_v4(tw->tw_daddr, 1); | |
1782 | + struct inet_timewait_sock *tw = inet_twsk(sk); | |
1789 | 1783 | |
1790 | - if (peer) { | |
1791 | - const struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw); | |
1792 | - | |
1793 | - if ((s32)(peer->tcp_ts - tcptw->tw_ts_recent) <= 0 || | |
1794 | - ((u32)get_seconds() - peer->tcp_ts_stamp > TCP_PAWS_MSL && | |
1795 | - peer->tcp_ts_stamp <= (u32)tcptw->tw_ts_recent_stamp)) { | |
1796 | - peer->tcp_ts_stamp = (u32)tcptw->tw_ts_recent_stamp; | |
1797 | - peer->tcp_ts = tcptw->tw_ts_recent; | |
1798 | - } | |
1799 | - inet_putpeer(peer); | |
1800 | - return 1; | |
1801 | - } | |
1802 | - | |
1803 | - return 0; | |
1784 | + return inet_getpeer_v4(tw->tw_daddr, 1); | |
1804 | 1785 | } |
1786 | +EXPORT_SYMBOL(tcp_v4_tw_get_peer); | |
1787 | + | |
1788 | +static struct timewait_sock_ops tcp_timewait_sock_ops = { | |
1789 | + .twsk_obj_size = sizeof(struct tcp_timewait_sock), | |
1790 | + .twsk_unique = tcp_twsk_unique, | |
1791 | + .twsk_destructor= tcp_twsk_destructor, | |
1792 | + .twsk_getpeer = tcp_v4_tw_get_peer, | |
1793 | +}; | |
1805 | 1794 | |
1806 | 1795 | const struct inet_connection_sock_af_ops ipv4_specific = { |
1807 | 1796 | .queue_xmit = ip_queue_xmit, |
net/ipv4/tcp_minisocks.c
... | ... | @@ -78,6 +78,27 @@ |
78 | 78 | return 0; |
79 | 79 | } |
80 | 80 | |
81 | +static int tcp_tw_remember_stamp(struct inet_timewait_sock *tw) | |
82 | +{ | |
83 | + struct sock *sk = (struct sock *) tw; | |
84 | + struct inet_peer *peer; | |
85 | + | |
86 | + peer = twsk_getpeer(sk); | |
87 | + if (peer) { | |
88 | + const struct tcp_timewait_sock *tcptw = tcp_twsk(sk); | |
89 | + | |
90 | + if ((s32)(peer->tcp_ts - tcptw->tw_ts_recent) <= 0 || | |
91 | + ((u32)get_seconds() - peer->tcp_ts_stamp > TCP_PAWS_MSL && | |
92 | + peer->tcp_ts_stamp <= (u32)tcptw->tw_ts_recent_stamp)) { | |
93 | + peer->tcp_ts_stamp = (u32)tcptw->tw_ts_recent_stamp; | |
94 | + peer->tcp_ts = tcptw->tw_ts_recent; | |
95 | + } | |
96 | + inet_putpeer(peer); | |
97 | + return 1; | |
98 | + } | |
99 | + return 0; | |
100 | +} | |
101 | + | |
81 | 102 | static __inline__ int tcp_in_window(u32 seq, u32 end_seq, u32 s_win, u32 e_win) |
82 | 103 | { |
83 | 104 | if (seq == s_win) |
... | ... | @@ -178,14 +199,9 @@ |
178 | 199 | tcptw->tw_ts_recent = tmp_opt.rcv_tsval; |
179 | 200 | } |
180 | 201 | |
181 | - /* I am shamed, but failed to make it more elegant. | |
182 | - * Yes, it is direct reference to IP, which is impossible | |
183 | - * to generalize to IPv6. Taking into account that IPv6 | |
184 | - * do not understand recycling in any case, it not | |
185 | - * a big problem in practice. --ANK */ | |
186 | - if (tw->tw_family == AF_INET && | |
187 | - tcp_death_row.sysctl_tw_recycle && tcptw->tw_ts_recent_stamp && | |
188 | - tcp_v4_tw_remember_stamp(tw)) | |
202 | + if (tcp_death_row.sysctl_tw_recycle && | |
203 | + tcptw->tw_ts_recent_stamp && | |
204 | + tcp_tw_remember_stamp(tw)) | |
189 | 205 | inet_twsk_schedule(tw, &tcp_death_row, tw->tw_timeout, |
190 | 206 | TCP_TIMEWAIT_LEN); |
191 | 207 | else |
net/ipv6/tcp_ipv6.c
... | ... | @@ -906,12 +906,6 @@ |
906 | 906 | }; |
907 | 907 | #endif |
908 | 908 | |
909 | -static struct timewait_sock_ops tcp6_timewait_sock_ops = { | |
910 | - .twsk_obj_size = sizeof(struct tcp6_timewait_sock), | |
911 | - .twsk_unique = tcp_twsk_unique, | |
912 | - .twsk_destructor= tcp_twsk_destructor, | |
913 | -}; | |
914 | - | |
915 | 909 | static void __tcp_v6_send_check(struct sk_buff *skb, |
916 | 910 | struct in6_addr *saddr, struct in6_addr *daddr) |
917 | 911 | { |
918 | 912 | |
... | ... | @@ -1818,11 +1812,29 @@ |
1818 | 1812 | goto discard_it; |
1819 | 1813 | } |
1820 | 1814 | |
1821 | -struct inet_peer *tcp_v6_get_peer(struct sock *sk, bool *release_it) | |
1815 | +static struct inet_peer *tcp_v6_get_peer(struct sock *sk, bool *release_it) | |
1822 | 1816 | { |
1823 | 1817 | /* Alas, not yet... */ |
1824 | 1818 | return NULL; |
1825 | 1819 | } |
1820 | + | |
1821 | +static void *tcp_v6_tw_get_peer(struct sock *sk) | |
1822 | +{ | |
1823 | + struct inet_timewait_sock *tw = inet_twsk(sk); | |
1824 | + | |
1825 | + if (tw->tw_family == AF_INET) | |
1826 | + return tcp_v4_tw_get_peer(sk); | |
1827 | + | |
1828 | + /* Alas, not yet... */ | |
1829 | + return NULL; | |
1830 | +} | |
1831 | + | |
1832 | +static struct timewait_sock_ops tcp6_timewait_sock_ops = { | |
1833 | + .twsk_obj_size = sizeof(struct tcp6_timewait_sock), | |
1834 | + .twsk_unique = tcp_twsk_unique, | |
1835 | + .twsk_destructor= tcp_twsk_destructor, | |
1836 | + .twsk_getpeer = tcp_v6_tw_get_peer, | |
1837 | +}; | |
1826 | 1838 | |
1827 | 1839 | static const struct inet_connection_sock_af_ops ipv6_specific = { |
1828 | 1840 | .queue_xmit = inet6_csk_xmit, |