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

netfilter: nf_conntrack_tcp: decrease timeouts while data in unacknowledged

In order to time out dead connections quicker, keep track of outstanding data
and cap the timeout.

Suggested by Herbert Xu.

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Patrick McHardy and committed by
David S. Miller
ae375044 a97a6f10

+27 -5
+3
include/linux/netfilter/nf_conntrack_tcp.h
··· 30 30 /* Be liberal in window checking */ 31 31 #define IP_CT_TCP_FLAG_BE_LIBERAL 0x08 32 32 33 + /* Has unacknowledged data */ 34 + #define IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED 0x10 35 + 33 36 struct nf_ct_tcp_flags { 34 37 u_int8_t flags; 35 38 u_int8_t mask;
+24 -5
net/netfilter/nf_conntrack_proto_tcp.c
··· 67 67 /* RFC1122 says the R2 limit should be at least 100 seconds. 68 68 Linux uses 15 packets as limit, which corresponds 69 69 to ~13-30min depending on RTO. */ 70 - static unsigned int nf_ct_tcp_timeout_max_retrans __read_mostly = 5 MINS; 70 + static unsigned int nf_ct_tcp_timeout_max_retrans __read_mostly = 5 MINS; 71 + static unsigned int nf_ct_tcp_timeout_unacknowledged __read_mostly = 5 MINS; 71 72 72 73 static unsigned int tcp_timeouts[TCP_CONNTRACK_MAX] __read_mostly = { 73 74 [TCP_CONNTRACK_SYN_SENT] = 2 MINS, ··· 626 625 swin = win + (sack - ack); 627 626 if (sender->td_maxwin < swin) 628 627 sender->td_maxwin = swin; 629 - if (after(end, sender->td_end)) 628 + if (after(end, sender->td_end)) { 630 629 sender->td_end = end; 630 + sender->flags |= IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED; 631 + } 631 632 /* 632 633 * Update receiver data. 633 634 */ ··· 640 637 if (win == 0) 641 638 receiver->td_maxend++; 642 639 } 640 + if (ack == receiver->td_end) 641 + receiver->flags &= ~IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED; 643 642 644 643 /* 645 644 * Check retransmissions. ··· 956 951 if (old_state != new_state 957 952 && new_state == TCP_CONNTRACK_FIN_WAIT) 958 953 ct->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT; 959 - timeout = ct->proto.tcp.retrans >= nf_ct_tcp_max_retrans 960 - && tcp_timeouts[new_state] > nf_ct_tcp_timeout_max_retrans 961 - ? nf_ct_tcp_timeout_max_retrans : tcp_timeouts[new_state]; 954 + 955 + if (ct->proto.tcp.retrans >= nf_ct_tcp_max_retrans && 956 + tcp_timeouts[new_state] > nf_ct_tcp_timeout_max_retrans) 957 + timeout = nf_ct_tcp_timeout_max_retrans; 958 + else if ((ct->proto.tcp.seen[0].flags | ct->proto.tcp.seen[1].flags) & 959 + IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED && 960 + tcp_timeouts[new_state] > nf_ct_tcp_timeout_unacknowledged) 961 + timeout = nf_ct_tcp_timeout_unacknowledged; 962 + else 963 + timeout = tcp_timeouts[new_state]; 962 964 write_unlock_bh(&tcp_lock); 963 965 964 966 nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb); ··· 1243 1231 { 1244 1232 .procname = "nf_conntrack_tcp_timeout_max_retrans", 1245 1233 .data = &nf_ct_tcp_timeout_max_retrans, 1234 + .maxlen = sizeof(unsigned int), 1235 + .mode = 0644, 1236 + .proc_handler = &proc_dointvec_jiffies, 1237 + }, 1238 + { 1239 + .procname = "nf_conntrack_tcp_timeout_unacknowledged", 1240 + .data = &nf_ct_tcp_timeout_unacknowledged, 1246 1241 .maxlen = sizeof(unsigned int), 1247 1242 .mode = 0644, 1248 1243 .proc_handler = &proc_dointvec_jiffies,