Hi
Because of the huge changes in 2.3.15 networking
code I am posting new keepalive patch for this kernel.
It behaves the same as the previous one (but is much
simpler) and as before introduces 4 more tcp options.
Furthermore it corrects bug in setting keepalive
timer presented currently in 2.3.15 function
tcp_create_openreq_child.
Unfortunately I did not understand the need for
randomizing the interval between keepalive probes so
I have removed that. I think that sending keepalive
messages are already randomized by the fact that
it is precisely 2 hours after last received TCP segment
and they arrive at random times.
regards
Pavel
Only in linux-2.3.15.orig/drivers/net: sk_mca.h.orig
diff -ru linux-2.3.15.orig/include/linux/socket.h linux-2.3.15/include/linux/socket.h
--- linux-2.3.15.orig/include/linux/socket.h Thu Aug 26 08:29:39 1999
+++ linux-2.3.15/include/linux/socket.h Thu Aug 26 08:58:00 1999
@@ -252,6 +252,10 @@
#define TCP_NODELAY 1
#define TCP_MAXSEG 2
#define TCP_CORK 3 /* Linux specific (for use with sendfile) */
+#define TCP_KEEPIDLE 4
+#define TCP_KEEPINTVL 5
+#define TCP_KEEPCNT 6
+#define TCP_SYNCNT 7
#ifdef __KERNEL__
extern int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len);
diff -ru linux-2.3.15.orig/include/linux/sysctl.h linux-2.3.15/include/linux/sysctl.h
--- linux-2.3.15.orig/include/linux/sysctl.h Thu Aug 26 08:29:40 1999
+++ linux-2.3.15/include/linux/sysctl.h Thu Aug 26 08:59:45 1999
@@ -206,26 +206,27 @@
NET_IPV4_TCP_MAX_KA_PROBES=44,
NET_IPV4_TCP_KEEPALIVE_TIME=45,
NET_IPV4_TCP_KEEPALIVE_PROBES=46,
- NET_IPV4_TCP_RETRIES1=47,
- NET_IPV4_TCP_RETRIES2=48,
- NET_IPV4_TCP_FIN_TIMEOUT=49,
- NET_IPV4_IP_MASQ_DEBUG=50,
- NET_TCP_SYNCOOKIES=51,
- NET_TCP_STDURG=52,
- NET_TCP_RFC1337=53,
- NET_TCP_SYN_TAILDROP=54,
- NET_TCP_MAX_SYN_BACKLOG=55,
- NET_IPV4_LOCAL_PORT_RANGE=56,
- NET_IPV4_ICMP_ECHO_IGNORE_ALL=57,
- NET_IPV4_ICMP_ECHO_IGNORE_BROADCASTS=58,
- NET_IPV4_ICMP_SOURCEQUENCH_RATE=59,
- NET_IPV4_ICMP_DESTUNREACH_RATE=60,
- NET_IPV4_ICMP_TIMEEXCEED_RATE=61,
- NET_IPV4_ICMP_PARAMPROB_RATE=62,
- NET_IPV4_ICMP_ECHOREPLY_RATE=63,
- NET_IPV4_ICMP_IGNORE_BOGUS_ERROR_RESPONSES=64,
- NET_IPV4_IGMP_MAX_MEMBERSHIPS=65,
- NET_TCP_TW_RECYCLE=66
+ NET_IPV4_TCP_KEEPALIVE_INTVL=47,
+ NET_IPV4_TCP_RETRIES1=48,
+ NET_IPV4_TCP_RETRIES2=49,
+ NET_IPV4_TCP_FIN_TIMEOUT=50,
+ NET_IPV4_IP_MASQ_DEBUG=51,
+ NET_TCP_SYNCOOKIES=52,
+ NET_TCP_STDURG=53,
+ NET_TCP_RFC1337=54,
+ NET_TCP_SYN_TAILDROP=55,
+ NET_TCP_MAX_SYN_BACKLOG=56,
+ NET_IPV4_LOCAL_PORT_RANGE=57,
+ NET_IPV4_ICMP_ECHO_IGNORE_ALL=58,
+ NET_IPV4_ICMP_ECHO_IGNORE_BROADCASTS=59,
+ NET_IPV4_ICMP_SOURCEQUENCH_RATE=60,
+ NET_IPV4_ICMP_DESTUNREACH_RATE=61,
+ NET_IPV4_ICMP_TIMEEXCEED_RATE=62,
+ NET_IPV4_ICMP_PARAMPROB_RATE=63,
+ NET_IPV4_ICMP_ECHOREPLY_RATE=64,
+ NET_IPV4_ICMP_IGNORE_BOGUS_ERROR_RESPONSES=65,
+ NET_IPV4_IGMP_MAX_MEMBERSHIPS=66,
+ NET_TCP_TW_RECYCLE=67
};
enum {
diff -ru linux-2.3.15.orig/include/net/sock.h linux-2.3.15/include/net/sock.h
--- linux-2.3.15.orig/include/net/sock.h Thu Aug 26 08:29:40 1999
+++ linux-2.3.15/include/net/sock.h Fri Aug 27 16:56:06 1999
@@ -317,6 +317,11 @@
int syn_backlog; /* Backlog of received SYNs */
int write_pending;
+
+ unsigned int keepalive_time; /* time before keep alive takes
+place */
+ unsigned int keepalive_intvl; /* time interval between keep alive
+probes */
+ unsigned char keepalive_probes; /* num of allowed keep alive probes
+*/
+ unsigned char syn_retries; /* num of allowed syn retries */
};
diff -ru linux-2.3.15.orig/include/net/tcp.h linux-2.3.15/include/net/tcp.h
--- linux-2.3.15.orig/include/net/tcp.h Thu Aug 26 08:29:40 1999
+++ linux-2.3.15/include/net/tcp.h Sat Aug 28 16:23:41 1999
@@ -286,7 +286,12 @@
* there is no window */
#define TCP_KEEPALIVE_TIME (120*60*HZ) /* two hours */
#define TCP_KEEPALIVE_PROBES 9 /* Max of 9 keepalive probes */
-#define TCP_KEEPALIVE_PERIOD ((75*HZ)>>2) /* period of keepalive check */
+#define TCP_KEEPALIVE_INTVL (75*HZ)
+
+#define MAX_TCP_KEEPIDLE 32767
+#define MAX_TCP_KEEPINTVL 32767
+#define MAX_TCP_KEEPCNT 127
+#define MAX_TCP_SYNCNT 127
#define TCP_SYNACK_PERIOD (HZ/2) /* How often to run the synack slow timer */
#define TCP_QUICK_TRIES 8 /* How often we try to retransmit, until
@@ -332,6 +337,12 @@
#define TIME_PROBE0 4
#define TIME_KEEPOPEN 5
+/* sysctl variables for tcp */
+extern int sysctl_tcp_keepalive_time;
+extern int sysctl_tcp_keepalive_probes;
+extern int sysctl_tcp_keepalive_intvl;
+extern int sysctl_tcp_syn_retries;
+
struct open_request;
struct or_calltable {
@@ -611,7 +622,7 @@
extern void tcp_send_partial(struct sock *);
extern void tcp_write_wakeup(struct sock *);
extern void tcp_send_fin(struct sock *sk);
-extern void tcp_send_active_reset(struct sock *sk);
+extern void tcp_send_active_reset(struct sock *sk, int priority);
extern int tcp_send_synack(struct sock *);
extern void tcp_transmit_skb(struct sock *, struct sk_buff *);
extern void tcp_send_skb(struct sock *, struct sk_buff *, int force_queue);
@@ -1229,6 +1240,22 @@
{
if (atomic_dec_and_test(&tcp_lhash_users))
wake_up(&tcp_lhash_wait);
+}
+
+static inline int keepalive_intvl_when(struct tcp_opt *tp)
+{
+ if (tp->keepalive_intvl)
+ return tp->keepalive_intvl;
+ else
+ return sysctl_tcp_keepalive_intvl;
+}
+
+static inline int keepalive_time_when(struct tcp_opt *tp)
+{
+ if (tp->keepalive_time)
+ return tp->keepalive_time;
+ else
+ return sysctl_tcp_keepalive_time;
}
#endif /* _TCP_H */
diff -ru linux-2.3.15.orig/net/ipv4/sysctl_net_ipv4.c
linux-2.3.15/net/ipv4/sysctl_net_ipv4.c
--- linux-2.3.15.orig/net/ipv4/sysctl_net_ipv4.c Thu Aug 26 08:29:41 1999
+++ linux-2.3.15/net/ipv4/sysctl_net_ipv4.c Thu Aug 26 09:09:34 1999
@@ -150,6 +150,9 @@
{NET_IPV4_TCP_KEEPALIVE_PROBES, "tcp_keepalive_probes",
&sysctl_tcp_keepalive_probes, sizeof(int), 0644, NULL,
&proc_dointvec},
+ {NET_IPV4_TCP_KEEPALIVE_INTVL, "tcp_keepalive_intvl",
+ &sysctl_tcp_keepalive_intvl, sizeof(int), 0644, NULL,
+ &proc_dointvec_jiffies, &sysctl_jiffies},
{NET_IPV4_TCP_RETRIES1, "tcp_retries1",
&sysctl_tcp_retries1, sizeof(int), 0644, NULL, &proc_dointvec_minmax,
&sysctl_intvec, NULL, NULL, &tcp_retr1_max},
diff -ru linux-2.3.15.orig/net/ipv4/tcp.c linux-2.3.15/net/ipv4/tcp.c
--- linux-2.3.15.orig/net/ipv4/tcp.c Thu Aug 26 08:29:41 1999
+++ linux-2.3.15/net/ipv4/tcp.c Fri Aug 27 14:53:15 1999
@@ -1580,7 +1580,7 @@
if(data_was_unread != 0) {
/* Unread data was tossed, zap the connection. */
tcp_set_state(sk, TCP_CLOSE);
- tcp_send_active_reset(sk);
+ tcp_send_active_reset(sk, GFP_KERNEL);
} else if (tcp_close_state(sk,1)) {
/* We FIN if the application ate all the data before
* zapping the connection.
@@ -1658,7 +1658,7 @@
if (old_state == TCP_LISTEN) {
tcp_close_pending(sk);
} else if (tcp_connected(old_state)) {
- tcp_send_active_reset(sk);
+ tcp_send_active_reset(sk, GFP_KERNEL);
sk->err = ECONNRESET;
} else if (old_state == TCP_SYN_SENT)
sk->err = ECONNRESET;
@@ -1870,6 +1870,40 @@
tcp_push_pending_frames(sk, tp);
}
break;
+
+ case TCP_KEEPIDLE:
+ if (val < 1 || val > MAX_TCP_KEEPIDLE)
+ err = -EINVAL;
+ else {
+ tp->keepalive_time = val * HZ;
+ if (sk->keepopen) {
+ __u32 elapsed = tcp_time_stamp - tp->rcv_tstamp;
+ if (tp->keepalive_time > elapsed)
+ elapsed = tp->keepalive_time - elapsed;
+ else
+ elapsed = 0;
+ tcp_reset_keepalive_timer(sk, elapsed);
+ }
+ }
+ break;
+ case TCP_KEEPINTVL:
+ if (val < 1 || val > MAX_TCP_KEEPINTVL)
+ err = -EINVAL;
+ else
+ tp->keepalive_intvl = val * HZ;
+ break;
+ case TCP_KEEPCNT:
+ if (val < 1 || val > MAX_TCP_KEEPCNT)
+ err = -EINVAL;
+ else
+ tp->keepalive_probes = val;
+ break;
+ case TCP_SYNCNT:
+ if (val < 1 || val > MAX_TCP_SYNCNT)
+ err = -EINVAL;
+ else
+ tp->syn_retries = val;
+ break;
default:
err = -ENOPROTOOPT;
@@ -1903,6 +1937,30 @@
break;
case TCP_CORK:
val = (sk->nonagle == 2);
+ break;
+ case TCP_KEEPIDLE:
+ if (tp->keepalive_time)
+ val = tp->keepalive_time / HZ;
+ else
+ val = sysctl_tcp_keepalive_time / HZ;
+ break;
+ case TCP_KEEPINTVL:
+ if (tp->keepalive_intvl)
+ val = tp->keepalive_intvl / HZ;
+ else
+ val = sysctl_tcp_keepalive_intvl / HZ;
+ break;
+ case TCP_KEEPCNT:
+ if (tp->keepalive_probes)
+ val = tp->keepalive_probes;
+ else
+ val = sysctl_tcp_keepalive_probes;
+ break;
+ case TCP_SYNCNT:
+ if (tp->syn_retries)
+ val = tp->syn_retries;
+ else
+ val = sysctl_tcp_syn_retries;
break;
default:
return -ENOPROTOOPT;
diff -ru linux-2.3.15.orig/net/ipv4/tcp_input.c linux-2.3.15/net/ipv4/tcp_input.c
--- linux-2.3.15.orig/net/ipv4/tcp_input.c Thu Aug 26 08:29:41 1999
+++ linux-2.3.15/net/ipv4/tcp_input.c Sat Aug 28 16:22:28 1999
@@ -1779,7 +1779,7 @@
if (skb->len == 0 && !th->fin)
return(0);
-
+
/*
* If our receive queue has grown past its limits shrink it.
* Make sure to do this before moving snd_nxt, otherwise
@@ -2423,7 +2423,7 @@
newsk->timer.function = &tcp_keepalive_timer;
newsk->timer.data = (unsigned long) newsk;
if (newsk->keepopen)
- tcp_reset_keepalive_timer(sk, sysctl_tcp_keepalive_time);
+ tcp_reset_keepalive_timer(newsk, keepalive_time_when(newtp));
newsk->socket = NULL;
newsk->sleep = NULL;
diff -ru linux-2.3.15.orig/net/ipv4/tcp_output.c linux-2.3.15/net/ipv4/tcp_output.c
--- linux-2.3.15.orig/net/ipv4/tcp_output.c Thu Aug 26 08:29:42 1999
+++ linux-2.3.15/net/ipv4/tcp_output.c Thu Aug 26 09:20:33 1999
@@ -825,13 +825,13 @@
* was unread data in the receive queue. This behavior is recommended
* by draft-ietf-tcpimpl-prob-03.txt section 3.10. -DaveM
*/
-void tcp_send_active_reset(struct sock *sk)
+void tcp_send_active_reset(struct sock *sk, int priority)
{
struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
struct sk_buff *skb;
/* NOTE: No TCP options attached and we never retransmit this. */
- skb = alloc_skb(MAX_HEADER + sk->prot->max_header, GFP_KERNEL);
+ skb = alloc_skb(MAX_HEADER + sk->prot->max_header, priority);
if (!skb)
return;
diff -ru linux-2.3.15.orig/net/ipv4/tcp_timer.c linux-2.3.15/net/ipv4/tcp_timer.c
--- linux-2.3.15.orig/net/ipv4/tcp_timer.c Thu Aug 26 08:29:42 1999
+++ linux-2.3.15/net/ipv4/tcp_timer.c Fri Aug 27 16:34:18 1999
@@ -25,6 +25,7 @@
int sysctl_tcp_syn_retries = TCP_SYN_RETRIES;
int sysctl_tcp_keepalive_time = TCP_KEEPALIVE_TIME;
int sysctl_tcp_keepalive_probes = TCP_KEEPALIVE_PROBES;
+int sysctl_tcp_keepalive_intvl = TCP_KEEPALIVE_INTVL;
int sysctl_tcp_retries1 = TCP_RETR1;
int sysctl_tcp_retries2 = TCP_RETR2;
@@ -183,7 +184,9 @@
}
/* Have we tried to SYN too many times (repent repent 8)) */
- if(tp->retransmits > sysctl_tcp_syn_retries && sk->state==TCP_SYN_SENT) {
+ if (sk->state == TCP_SYN_SENT &&
+ ((!tp->syn_retries && tp->retransmits > sysctl_tcp_syn_retries) ||
+ (tp->syn_retries && tp->retransmits > tp->syn_retries))) {
tcp_write_err(sk, 1);
/* Don't FIN, we got nothing back */
} else if (tp->retransmits > sysctl_tcp_retries2) {
@@ -587,7 +590,7 @@
void tcp_set_keepalive(struct sock *sk, int val)
{
if (val && !sk->keepopen)
- tcp_reset_keepalive_timer(sk, sysctl_tcp_keepalive_time);
+ tcp_reset_keepalive_timer(sk,
+keepalive_time_when(&sk->tp_pinfo.af_tcp));
else if (!val)
tcp_delete_keepalive_timer(sk);
}
@@ -613,25 +616,29 @@
if (!sk->keepopen)
goto out;
- elapsed = sysctl_tcp_keepalive_time;
+ elapsed = keepalive_time_when(tp);
if (!((1<<sk->state) & (TCPF_ESTABLISHED|TCPF_CLOSE_WAIT|TCPF_FIN_WAIT2)))
goto resched;
elapsed = tcp_time_stamp - tp->rcv_tstamp;
- if (elapsed >= sysctl_tcp_keepalive_time) {
- if (tp->probes_out > sysctl_tcp_keepalive_probes) {
+ if (elapsed >= keepalive_time_when(tp)) {
+ if ((!tp->keepalive_probes && tp->probes_out >=
+sysctl_tcp_keepalive_probes) ||
+ (tp->keepalive_probes && tp->probes_out >= tp->keepalive_probes))
+{
+ tcp_send_active_reset(sk, GFP_ATOMIC);
tcp_write_err(sk, 1);
goto out;
}
tp->probes_out++;
tp->pending = TIME_KEEPOPEN;
tcp_write_wakeup(sk);
- /* Randomize to avoid synchronization */
- elapsed = (TCP_KEEPALIVE_PERIOD>>1) +
(net_random()%TCP_KEEPALIVE_PERIOD);
+ elapsed = keepalive_intvl_when(tp);
} else {
- /* It is tp->rcv_tstamp + sysctl_tcp_keepalive_time */
- elapsed = sysctl_tcp_keepalive_time - elapsed;
+ /* It is tp->rcv_tstamp + keepalive_time_when(tp) */
+ if (keepalive_time_when(tp) > elapsed)
+ elapsed = keepalive_time_when(tp) - elapsed;
+ else
+ elapsed = 0;
}
resched: