Customizable TCP backoff patch
Subsystems (4)
PATCH 1/1 Customizable TCP backoff patch
Here at LLNL we have a rather challenging network environment on our clusters. We basically have 1000's of gigE links attached to an oversubscribed federated network. Most of the time this network is idle but the expected workload is for regular spikes extremely heavy activity lasting a few minutes. All end-points in a highly coordinated manor, typically after exiting an MPI barrier, start pushing as much data as possible through the oversubscribed core. The result is a wave of TCP back-offs where all the TCP streams back-off in lock step. The network oscillates from highly congested for brief moments to largely idle. Given enough time TCP will settle down in to something mostly reasonable but even then it causes us a few problems:
1) It takes a long time for the network to settle in to a steady state and while it does network utilization is very poor.
2) Many of the sockets will rapidly back off to the maximum value. This can lead to application level timeouts being triggered because we also initially calibrated the timeouts with the notion that 2 minute back-offs would be the exception and not the norm.
3) Once we reach steady state there's no guarantee of fairness between TCP streams. For our workload this is particularly undesirable since the parallel job which kicked off all this activity must wait until the slowest transaction completes. This translates in to 1000's of nodes sitting idle.
By knowing this is the expected workload on this dedicated network we can safely make the back-offs more aggressive to mitigate most of these issues.
We also played around with using a random seed when selecting the back-off interval to avoid all the sockets backing-off in lock step. That worked reasonably well but was more invasive then simply adding a few more tunable.
Because these are general utility clusters we run many different programs and so trying to fix this problem in the application is not possible since there are literally hundreds if not thousands of them.
We're more than willing to consider other approaches to handling this
particular workload better. We've even considered that TCP isn't at all the right protocol but this affects several protocols including NFS and the benefits of running NFS over TCP are too great.
The original patch was prepared by Brian Behlendorf. He asked me to adapt it for current kernels keep it up to date and send upstream.
This may also help people like Andrew Athan which reported a similar problem a couple of days ago on the linux-net mailing list: http://www.uwsg.iu.edu/hypermail/linux/net/0609.3/0005.html I suspect that it is more common a case than is widely recognized.
include/linux/sysctl.h +2 -0
@@ -411,6 +411,8 @@NET_IPV4_TCP_WORKAROUND_SIGNED_WINDOWS =115 ,NET_TCP_DMA_COPYBREAK =116 ,NET_TCP_SLOW_START_AFTER_IDLE =117 , +NET_TCP_RTO_MAX =118 , + NET_TCP_RTO_INIT=119, }; enum {
Only in linux-2.6.18.new/include/linux: sysctl.h.orig Only in linux-2.6.18.new/include/linux: sysctl.h.rej
include/linux/tcp.h +4 -0
@@ -94,6 +94,8 @@#define TCP_INFO 11/* Information about this connection. */ #define TCP_QUICKACK 12/* Block/reenable quick acks */ #define TCP_CONGESTION 13/* Congestion control algorithm */ +#define TCP_BACKOFF_MAX 14/* Maximum backoff value */ +#define TCP_BACKOFF_INIT 15/* Initial backoff value */ #define TCPI_OPT_TIMESTAMPS 1#define TCPI_OPT_SACK 2
@@ -257,6 +259,8 @@__u8 frto_counter;/* Number of new acks after RTO */ __u8 nonagle;/* Disable Nagle algorithm? */ __u8 keepalive_probes;/* num of allowed keep alive probes */ +__u32 rto_max;/* Maximum backoff value */ +__u32 rto_init;/* Initial backoff value */ /* RTT measurement */ __u32 srtt;/* smoothed round trip time << 3 */
Only in linux-2.6.18.new/include/linux: tcp.h.orig
include/net/tcp.h +2 -0
@@ -227,6 +227,8 @@extern int sysctl_tcp_base_mss;extern int sysctl_tcp_workaround_signed_windows;extern int sysctl_tcp_slow_start_after_idle; +extern int sysctl_tcp_rto_max; +extern int sysctl_tcp_rto_init;extern atomic_t tcp_memory_allocated;extern atomic_t tcp_sockets_allocated;
Only in linux-2.6.18.new/include/net: tcp.h.orig
Only in linux-2.6.18.new/include/net: tcp.h.rej
net/ipv4/sysctl_net_ipv4.c +16 -0
@@ -697,6 +697,22 @@ .mode = 0644, .proc_handler = &proc_dointvec }, + { + .ctl_name = NET_TCP_RTO_MAX, + .procname = "tcp_rto_max", + .data = &sysctl_tcp_rto_max, + .maxlen = sizeof(unsigned), + .mode = 0644, + .proc_handler = &proc_dointvec + }, + { + .ctl_name = NET_TCP_RTO_INIT, + .procname = "tcp_rto_init", + .data = &sysctl_tcp_rto_init, + .maxlen = sizeof(unsigned), + .mode = 0644, + .proc_handler = &proc_dointvec + }, { .ctl_name = 0 } };
Only in linux-2.6.18.new/net/ipv4: sysctl_net_ipv4.c.orig
net/ipv4/tcp.c +21 -0
@@ -1939,6 +1939,21 @@ }break ; +case TCP_BACKOFF_MAX : +if (val <1 ) + err = -EINVAL ; +else + tp->rto_max = val *HZ ; +break ; + +case TCP_BACKOFF_INIT : +if (val <1 ) + err = -EINVAL ; +else + tp->rto_init = val *HZ ; +break ; + +default : err = -ENOPROTOOPT ;break ;
@@ -2110,6 +2125,12 @@if (copy_to_user (optval, icsk->icsk_ca_ops->name, len))return -EFAULT ;return 0 ; +case TCP_BACKOFF_MAX : + val = (tp->rto_max ? : sysctl_tcp_rto_max) /HZ ; +break ; +case TCP_BACKOFF_INIT : + val = (tp->rto_init ? : sysctl_tcp_rto_init) /HZ ; +break ;default :return -ENOPROTOOPT ; };
Only in linux-2.6.18.new/net/ipv4: tcp.c.orig
net/ipv4/tcp_timer.c +12 -6
@@ -31,6 +31,8 @@int sysctl_tcp_retries1 =TCP_RETR1 ;int sysctl_tcp_retries2 =TCP_RETR2 ;int sysctl_tcp_orphan_retries; +int sysctl_tcp_rto_max =TCP_RTO_MAX ; +int sysctl_tcp_rto_init =TCP_TIMEOUT_INIT ;static void tcp_write_timer (unsigned long );static void tcp_delack_timer (unsigned long );
@@ -71,7 +73,8 @@/* If peer does not open window for long time, or did not transmit * anything for long time, penalize it. */ -if ((s32)(tcp_time_stamp - tp->lsndtime) >2 *TCP_RTO_MAX || !do_reset) +if ((s32)(tcp_time_stamp - tp->lsndtime) > +2 * (tp->rto_max ? : sysctl_tcp_rto_max) || !do_reset) orphans <<=1 ;/* If some dubious ICMP arrived, penalize even more. */
@@ -256,8 +259,8 @@ max_probes = sysctl_tcp_retries2;if (sock_flag (sk,SOCK_DEAD )) { -const int alive = ((icsk->icsk_rto << icsk->icsk_backoff) <TCP_RTO_MAX ); - +const int alive = ((icsk->icsk_rto << icsk->icsk_backoff) < + (tp->rto_max ? : sysctl_tcp_rto_max)); max_probes =tcp_orphan_retries (sk, alive);if (tcp_out_of_resources (sk, alive || icsk->icsk_probes_out <= max_probes))
@@ -301,7 +304,8 @@ inet->num, tp->snd_una, tp->snd_nxt); }#endif -if (tcp_time_stamp - tp->rcv_tstamp >TCP_RTO_MAX ) { +if (tcp_time_stamp - tp->rcv_tstamp > + (tp->rto_max ? : sysctl_tcp_rto_max)) {tcp_write_err (sk); goto out; }
@@ -373,7 +377,8 @@ out_reset_timer: icsk->icsk_rto =min (icsk->icsk_rto <<1 ,TCP_RTO_MAX ); -inet_csk_reset_xmit_timer (sk,ICSK_TIME_RETRANS , icsk->icsk_rto,TCP_RTO_MAX ); +inet_csk_reset_xmit_timer (sk,ICSK_TIME_RETRANS , icsk->icsk_rto, + (tp->rto_max ? : sysctl_tcp_rto_max));if (icsk->icsk_retransmits > sysctl_tcp_retries1)__sk_dst_reset (sk);
@@ -428,7 +433,8 @@static void tcp_synack_timer (struct sock *sk) {inet_csk_reqsk_queue_prune (sk,TCP_SYNQ_INTERVAL , -TCP_TIMEOUT_INIT ,TCP_RTO_MAX ); +TCP_TIMEOUT_INIT , + ((tp->rto_init ? : sysctl_tcp_rto_init))); }void tcp_set_keepalive (struct sock *sk,int val)
David Miller
maintainerFrom: Ben Woodard <[email protected]>
Date: Wed, 27 Sep 2006 11:52:57 -0700
Quoted 3 lines
Because these are general utility clusters we run many different programs and so trying to fix this problem in the application is not possible since there are literally hundreds if not thousands of them.
Then why add a socket option setting as your patch does? :-)
I also object to the socket option setting being allowed for any user because this can have awful effects if allowed by arbitrary users on arbitrary networks.
Quoted 8 lines
We're more than willing to consider other approaches to handling this particular workload better. We've even considered that TCP isn't at all the right protocol but this affects several protocols including NFS and the benefits of running NFS over TCP are too great.
The original patch was prepared by Brian Behlendorf. He asked me to adapt it for current kernels keep it up to date and send upstream.
Quoted 7 lines
This may also help people like Andrew Athan which reported a similar problem a couple of days ago on the linux-net mailing list:
http://www.uwsg.iu.edu/hypermail/linux/net/0609.3/0005.html I suspect that it is more common a case than is widely recognized.Signed-off-by Ben Woodard <[email protected]>Signed-off-by Brian Behlendorf <[email protected]>
Other issues:
1) 2 "u32" in the tcp_sock is a lot of space to devote to this new state. If it can fit in 2 "u16"'s or even less space, please use that.
2) the expression "(tp->foo ? : sysctl_foo)" is repeated many times in the patch, please encapsulate it into an inline function or similar
I'm still torn on the fundamental issues of this patch. I think random backoff is a better generic solution to this kind of problem. If it works for ethernet, it might just work for TCP too :-)
Thanks.
Quoted 7 lines · On Wed, 27 Sep 2006 16:16:38 -0700 (PDT) David Miller <[email protected]>…
From: Ben Woodard <[email protected]>
Date: Wed, 27 Sep 2006 11:52:57 -0700Quoted 3 lines
Because these are general utility clusters we run many different programs and so trying to fix this problem in the application is not possible since there are literally hundreds if not thousands of them.
Quoted 5 lines
Then why add a socket option setting as your patch does? :-)
I also object to the socket option setting being allowed for any user because this can have awful effects if allowed by arbitrary users on arbitrary networks.
Setting a cwnd limit would do the same thing.
David Miller
maintainerFrom: Stephen Hemminger <[email protected]>
Date: Wed, 27 Sep 2006 16:00:44 -0700
Quoted 10 lines
Quoted 7 lines · On Wed, 27 Sep 2006 16:16:38 -0700 (PDT) David Miller <[email protected]>…
From: Ben Woodard <[email protected]>
Date: Wed, 27 Sep 2006 11:52:57 -0700Quoted 3 lines
Because these are general utility clusters we run many different programs and so trying to fix this problem in the application is not possible since there are literally hundreds if not thousands of them.
Quoted 7 lines
Quoted 5 lines
Then why add a socket option setting as your patch does? :-)
I also object to the socket option setting being allowed for any user because this can have awful effects if allowed by arbitrary users on arbitrary networks.
Setting a cwnd limit would do the same thing.
Not really :-)
It would not influence the TCP retransmit timeouts and backoff, although it would influence the congestion window handling during recovery after such timeout based losses.
Quoted 23 lines · David Miller
From: Ben Woodard <[email protected]>
Date: Wed, 27 Sep 2006 11:52:57 -0700Quoted 1 line
Because these are general utility clusters we run many different programs and so trying to fix this problem in the application is not possible since there are literally hundreds if not thousands of them.
Then why add a socket option setting as your patch does? :-)
I also object to the socket option setting being allowed for any user because this can have awful effects if allowed by arbitrary users on arbitrary networks.
Quoted 9 lines
We're more than willing to consider other approaches to handling this
particular workload better. We've even considered that TCP isn't at all the right protocol but this affects several protocols including NFS and the benefits of running NFS over TCP are too great.The original patch was prepared by Brian Behlendorf. He asked me to adapt it for current kernels keep it up to date and send upstream.
This may also help people like Andrew Athan which reported a similar problem a couple of days ago on the linux-net mailing list: http://www.uwsg.iu.edu/hypermail/linux/net/0609.3/0005.html I suspect that it is more common a case than is widely recognized.
Signed-off-by Ben Woodard <[email protected]>Signed-off-by Brian Behlendorf <[email protected]>Other issues:
Quoted 8 lines
1) 2 "u32" in the
tcp_sockis a lot of space to devote to this new state. If it can fit in 2 "u16"'s or even less space, please use that.2) the expression "(
tp->foo? :sysctl_foo)" is repeated many times in the patch, please encapsulate it into an inline function or similar
How does this look to you for answering your two complaints above.
Quoted 3 lines
I'm still torn on the fundamental issues of this patch. I think random backoff is a better generic solution to this kind of problem. If it works for ethernet, it might just work for TCP too :-)
I haven't taken this on in this patch. I'd have to think more about how to do that and I'm not sure that introducing randomness here will allow us to settle into a steady state faster than configuring a shorter timeout in the environments that need it.
Quoted 2 lines
Thanks.
include/linux/sysctl.h +2 -0
@@ -411,6 +411,8 @@NET_IPV4_TCP_WORKAROUND_SIGNED_WINDOWS =115 ,NET_TCP_DMA_COPYBREAK =116 ,NET_TCP_SLOW_START_AFTER_IDLE =117 , +NET_TCP_RTO_MAX =118 , + NET_TCP_RTO_INIT=119, }; enum {
Only in linux-2.6.18.new/include/linux: sysctl.h.orig Only in linux-2.6.18.new/include/linux: sysctl.h.rej
include/linux/tcp.h +4 -0
@@ -94,6 +94,8 @@#define TCP_INFO 11/* Information about this connection. */ #define TCP_QUICKACK 12/* Block/reenable quick acks */ #define TCP_CONGESTION 13/* Congestion control algorithm */ +#define TCP_BACKOFF_MAX 14/* Maximum backoff value */ +#define TCP_BACKOFF_INIT 15/* Initial backoff value */ #define TCPI_OPT_TIMESTAMPS 1#define TCPI_OPT_SACK 2
@@ -257,6 +259,8 @@__u8 frto_counter;/* Number of new acks after RTO */ __u8 nonagle;/* Disable Nagle algorithm? */ __u8 keepalive_probes;/* num of allowed keep alive probes */ +__u16 rto_max;/* Maximum backoff value */ +__u16 rto_init;/* Initial backoff value */ /* RTT measurement */ __u32 srtt;/* smoothed round trip time << 3 */
Only in linux-2.6.18.new/include/linux: tcp.h.orig
include/net/tcp.h +2 -0
@@ -227,6 +227,8 @@extern int sysctl_tcp_base_mss;extern int sysctl_tcp_workaround_signed_windows;extern int sysctl_tcp_slow_start_after_idle; +extern int sysctl_tcp_rto_max; +extern int sysctl_tcp_rto_init;extern atomic_t tcp_memory_allocated;extern atomic_t tcp_sockets_allocated;
Only in linux-2.6.18.new/include/net: tcp.h.orig Only in linux-2.6.18.new/include/net: tcp.h.rej
net/ipv4/sysctl_net_ipv4.c +16 -0
@@ -697,6 +697,22 @@ .mode = 0644, .proc_handler = &proc_dointvec }, + { + .ctl_name = NET_TCP_RTO_MAX, + .procname = "tcp_rto_max", + .data = &sysctl_tcp_rto_max, + .maxlen = sizeof(unsigned), + .mode = 0644, + .proc_handler = &proc_dointvec + }, + { + .ctl_name = NET_TCP_RTO_INIT, + .procname = "tcp_rto_init", + .data = &sysctl_tcp_rto_init, + .maxlen = sizeof(unsigned), + .mode = 0644, + .proc_handler = &proc_dointvec + }, { .ctl_name = 0 } };
Only in linux-2.6.18.new/net/ipv4: sysctl_net_ipv4.c.orig
net/ipv4/tcp.c +23 -0
@@ -1764,6 +1764,8 @@return err; } +#define TCP_BACKOFF_MAXVAL 65535 +/* * Socket option code for TCP. */
@@ -1939,6 +1941,21 @@ }break ; +case TCP_BACKOFF_MAX : +if (val <1 || val >TCP_BACKOFF_MAXVAL ) + err = -EINVAL ; +else + tp->rto_max = val *HZ ; +break ; + +case TCP_BACKOFF_INIT : +if (val <1 || val >TCP_BACKOFF_MAXVAL ) + err = -EINVAL ; +else + tp->rto_init = val *HZ ; +break ; + +default : err = -ENOPROTOOPT ;break ;
@@ -2110,6 +2127,12 @@if (copy_to_user (optval, icsk->icsk_ca_ops->name, len))return -EFAULT ;return 0 ; +case TCP_BACKOFF_MAX : + val = (tp->rto_max ? : sysctl_tcp_rto_max) /HZ ; +break ; +case TCP_BACKOFF_INIT : + val = (tp->rto_init ? : sysctl_tcp_rto_init) /HZ ; +break ;default :return -ENOPROTOOPT ; };
Only in linux-2.6.18.new/net/ipv4: tcp.c.orig
net/ipv4/tcp_timer.c +18 -7
@@ -31,11 +31,21 @@int sysctl_tcp_retries1 =TCP_RETR1 ;int sysctl_tcp_retries2 =TCP_RETR2 ;int sysctl_tcp_orphan_retries; +int sysctl_tcp_rto_max =TCP_RTO_MAX ; +int sysctl_tcp_rto_init =TCP_TIMEOUT_INIT ;static void tcp_write_timer (unsigned long );static void tcp_delack_timer (unsigned long );static void tcp_keepalive_timer (unsigned long data); +static inline __u16 rto_max (struct tcp_sock *tp){ +return tp->rto_max ? : sysctl_tcp_rto_max; +} + +static inline __u16 rto_init (struct tcp_sock *tp){ +return tp->rto_init ? : sysctl_tcp_rto_init; +} +void tcp_init_xmit_timers (struct sock *sk) { inet_csk_init_xmit_timers(sk, &tcp_write_timer, &tcp_delack_timer,
@@ -71,7 +81,7 @@/* If peer does not open window for long time, or did not transmit * anything for long time, penalize it. */ -if ((s32)(tcp_time_stamp - tp->lsndtime) >2 *TCP_RTO_MAX || !do_reset) +if ((s32)(tcp_time_stamp - tp->lsndtime) >2 *rto_max (tp) || !do_reset) orphans <<=1 ;/* If some dubious ICMP arrived, penalize even more. */
@@ -256,8 +266,8 @@ max_probes = sysctl_tcp_retries2;if (sock_flag (sk,SOCK_DEAD )) { -const int alive = ((icsk->icsk_rto << icsk->icsk_backoff) <TCP_RTO_MAX ); - +const int alive = ((icsk->icsk_rto << icsk->icsk_backoff) < +rto_max (tp)); max_probes =tcp_orphan_retries (sk, alive);if (tcp_out_of_resources (sk, alive || icsk->icsk_probes_out <= max_probes))
@@ -301,7 +311,7 @@ inet->num, tp->snd_una, tp->snd_nxt); }#endif -if (tcp_time_stamp - tp->rcv_tstamp >TCP_RTO_MAX ) { +if (tcp_time_stamp - tp->rcv_tstamp >rto_max (tp)) {tcp_write_err (sk); goto out; }
@@ -373,7 +383,8 @@ out_reset_timer: icsk->icsk_rto =min (icsk->icsk_rto <<1 ,TCP_RTO_MAX ); -inet_csk_reset_xmit_timer (sk,ICSK_TIME_RETRANS , icsk->icsk_rto,TCP_RTO_MAX ); +inet_csk_reset_xmit_timer (sk,ICSK_TIME_RETRANS , icsk->icsk_rto, +rto_max (tp));if (icsk->icsk_retransmits > sysctl_tcp_retries1)__sk_dst_reset (sk);
@@ -427,8 +438,8 @@static void tcp_synack_timer (struct sock *sk) { -inet_csk_reqsk_queue_prune (sk,TCP_SYNQ_INTERVAL , -TCP_TIMEOUT_INIT ,TCP_RTO_MAX ); +inet_csk_reqsk_queue_prune (sk,TCP_SYNQ_INTERVAL , +TCP_TIMEOUT_INIT ,rto_max (tcp_sk (sk))); }void tcp_set_keepalive (struct sock *sk,int val)
David Miller
maintainerFrom: Ben Woodard <[email protected]>
Date: Tue, 03 Oct 2006 11:14:38 -0700
Quoted 6 lines
Quoted 6 lines
Other issues:
1) 2 "u32" in the
tcp_sockis a lot of space to devote to this new state. If it can fit in 2 "u16"'s or even less space, please use that.
Quoted 6 lines
Quoted 4 lines
2) the expression "(
tp->foo? :sysctl_foo)" is repeated many times in the patch, please encapsulate it into an inline function or similarHow does this look to you for answering your two complaints above.
It looks a lot better. I'd like you to take #2 further, put the inline function into net/tcp.h and use it in the tcp.c instances too.
Also, please don't format code like this:
+static inline __u16 rto_max(struct tcp_sock *tp){
+ return tp->rto_max ? : sysctl_tcp_rto_max;
+}
+
+static inline __u16 rto_init(struct tcp_sock *tp){
+ return tp->rto_init ? : sysctl_tcp_rto_init;
+}
The openning brace of each functions belongs on a line by itself, thanks.
Finally, I'm not so sure "seconds" is the best unit for the socket option. In fact you use "seconds" as the unit for the socket option and the sysctl is raw jiffies. That's inconsistency is really problematic.
At the very least, seconds might not be fine enough granularity for some circumstances. Heck, the default RTO_MIN is 1/5 of a second. :-)
I also understand that going to milliseconds or microseconds would make the size of the in-socket struct members an issue again. These things are never easy are they? :-/
Any better ideas?
Quoted 7 lines · David Miller
At the very least, seconds might not be fine enough granularity for some circumstances. Heck, the default
RTO_MINis 1/5 of a second. :-)I also understand that going to milliseconds or microseconds would make the size of the in-socket struct members an issue again. These things are never easy are they? :-/
Would be, if floating point values would be allowed. Single precision would be enough in this case and its just 32 bits IIRC.
I mean floating point values just for the user->kernel ABI and NOT for the internal timer representation.
Regards
Ingo Oeser
David Miller
maintainerFrom: Ingo Oeser <[email protected]>
Date: Wed, 4 Oct 2006 10:56:12 +0200
Quoted 9 lines
Quoted 7 lines · David Miller
At the very least, seconds might not be fine enough granularity for some circumstances. Heck, the default
RTO_MINis 1/5 of a second. :-)I also understand that going to milliseconds or microseconds would make the size of the in-socket struct members an issue again. These things are never easy are they? :-/
Quoted 5 lines
Would be, if floating point values would be allowed. Single precision would be enough in this case and its just 32 bits IIRC.
I mean floating point values just for the
user->kernelABI and NOT for the internal timer representation.
We got the struct members down to 16-bits each, the problem is in fact that we'd need to make them 32-bits again.
Quoted 42 lines · On Wed, 04 Oct 2006 00:07:22 -0700 (PDT) David Miller <[email protected]>…
From: Ben Woodard <[email protected]>
Date: Tue, 03 Oct 2006 11:14:38 -0700Quoted 6 lines
Quoted 6 lines
Other issues:
1) 2 "u32" in the
tcp_sockis a lot of space to devote to this new state. If it can fit in 2 "u16"'s or even less space, please use that.Quoted 6 lines
Quoted 4 lines
2) the expression "(
tp->foo? :sysctl_foo)" is repeated many times in the patch, please encapsulate it into an inline function or similarHow does this look to you for answering your two complaints above.
It looks a lot better. I'd like you to take #2 further, put the inline function into
net/tcp.hand use it in thetcp.cinstances too.Also, please don't format code like this:
net/ipv4/tcp_timer.c +7
-0+static inline __u16 rto_max (struct tcp_sock *tp){ +return tp->rto_max ? : sysctl_tcp_rto_max; +} + +static inline __u16 rto_init (struct tcp_sock *tp){ +return tp->rto_init ? : sysctl_tcp_rto_init; +}The openning brace of each functions belongs on a line by itself, thanks.
Finally, I'm not so sure "seconds" is the best unit for the socket option. In fact you use "seconds" as the unit for the socket option and the sysctl is raw jiffies. That's inconsistency is really problematic.
At the very least, seconds might not be fine enough granularity for some circumstances. Heck, the default
RTO_MINis 1/5 of a second. :-)
Quoted 5 lines
I also understand that going to milliseconds or microseconds would make the size of the in-socket struct members an issue again. These things are never easy are they? :-/
Any better ideas?
If you are willing to do a little more work, the sysctl value can be in milliseconds, and the internal socket member in some other unit like jiffies. It does require writing your own in/out translation instead of using proc_dointvec
Signature · 1 line
Stephen Hemminger <[email protected]>
Quoted 13 lines · David Miller
From: Ben Woodard <[email protected]>
Date: Tue, 03 Oct 2006 11:14:38 -0700Quoted 10 lines
Quoted 10 lines
Other issues:
1) 2 "u32" in the
tcp_sockis a lot of space to devote to this new state. If it can fit in 2 "u16"'s or even less space, please use that.2) the expression "(
tp->foo? :sysctl_foo)" is repeated many times in the patch, please encapsulate it into an inline function or similar
Quoted 5 lines
Quoted 1 line
How does this look to you for answering your two complaints above.
It looks a lot better. I'd like you to take #2 further, put the inline function into
net/tcp.hand use it in thetcp.cinstances too.
Done. I orginally didn't want to grow the header files with two more functions that weren't use many places. Anyway this is fixed.
Quoted 11 lines
Also, please don't format code like this:
(quoted diff) +7
-0+static inline __u16 rto_max(struct tcp_sock *tp){ + return tp->rto_max ? : sysctl_tcp_rto_max; +} + +static inline __u16 rto_init(struct tcp_sock *tp){ + return tp->rto_init ? : sysctl_tcp_rto_init; +}
Quoted 2 lines
The opening brace of each functions belongs on a line by itself, thanks.
Fixed.
Quoted 10 lines
Finally, I'm not so sure "seconds" is the best unit for the socket option. In fact you use "seconds" as the unit for the socket option and the sysctl is raw jiffies. That's inconsistency is really problematic.
At the very least, seconds might not be fine enough granularity for some circumstances. Heck, the default
RTO_MINis 1/5 of a second. :-)
Quoted 5 lines
I also understand that going to milliseconds or microseconds would make the size of the in-socket struct members an issue again. These things are never easy are they? :-/
Any better ideas?
Here is what I've done. I store the values in the socket structure as ms so that they will fit into 16 bits and as jiffies in the global variables. Then I populate the global variables using proc_doulongvec_ms_jiffies()
How does that look to you?
-ben
include/linux/sysctl.h +2 -0
@@ -411,6 +411,8 @@NET_IPV4_TCP_WORKAROUND_SIGNED_WINDOWS =115 ,NET_TCP_DMA_COPYBREAK =116 ,NET_TCP_SLOW_START_AFTER_IDLE =117 , +NET_TCP_RTO_MAX =118 , + NET_TCP_RTO_INIT=119, }; enum {
include/linux/tcp.h +4 -0
@@ -94,6 +94,8 @@#define TCP_INFO 11/* Information about this connection. */ #define TCP_QUICKACK 12/* Block/reenable quick acks */ #define TCP_CONGESTION 13/* Congestion control algorithm */ +#define TCP_BACKOFF_MAX 14/* Maximum backoff value */ +#define TCP_BACKOFF_INIT 15/* Initial backoff value */ #define TCPI_OPT_TIMESTAMPS 1#define TCPI_OPT_SACK 2
@@ -257,6 +259,8 @@__u8 frto_counter;/* Number of new acks after RTO */ __u8 nonagle;/* Disable Nagle algorithm? */ __u8 keepalive_probes;/* num of allowed keep alive probes */ +__u16 rto_max;/* Maximum backoff value in ms */ +__u16 rto_init;/* Initial backoff value in ms */ /* RTT measurement */ __u32 srtt;/* smoothed round trip time << 3 */
include/net/tcp.h +12 -0
@@ -227,11 +227,23 @@extern int sysctl_tcp_base_mss;extern int sysctl_tcp_workaround_signed_windows;extern int sysctl_tcp_slow_start_after_idle; +extern unsigned long sysctl_tcp_rto_max; +extern unsigned long sysctl_tcp_rto_init;extern atomic_t tcp_memory_allocated;extern atomic_t tcp_sockets_allocated;extern int tcp_memory_pressure; +static inline unsigned long tcp_rto_max (struct tcp_sock *tp) +{ +return tp->rto_max ? tp->rto_max*HZ /1000 : sysctl_tcp_rto_max; +} + +static inline unsigned long tcp_rto_init (struct tcp_sock *tp) +{ +return tp->rto_init ? tp->rto_init*HZ /1000 : sysctl_tcp_rto_init; +} +/* * The next routines deal with comparing 32 bit unsigned ints * and worry about wraparound (automatic with unsigned arithmetic).
net/ipv4/sysctl_net_ipv4.c +22 -0
@@ -128,6 +128,8 @@return ret; } +static unsigned long tcp_rto_min=0 ; +static unsigned long tcp_rto_max=65535 ;ctl_table ipv4_table[] = { {
@@ -697,6 +699,26 @@ .mode = 0644, .proc_handler = &proc_dointvec }, + { + .ctl_name = NET_TCP_RTO_MAX, + .procname = "tcp_rto_max", + .data = &sysctl_tcp_rto_max, + .maxlen = sizeof(unsigned), + .mode = 0644, + .proc_handler = &proc_doulongvec_ms_jiffies, + .extra1 = &tcp_rto_min_constant, + .extra2 = &tcp_rto_max_constant, + }, + { + .ctl_name = NET_TCP_RTO_INIT, + .procname = "tcp_rto_init", + .data = &sysctl_tcp_rto_init, + .maxlen = sizeof(unsigned), + .mode = 0644, + .proc_handler = &proc_doulongvec_ms_jiffies, + .extra1 = &tcp_rto_min_constant, + .extra2 = &tcp_rto_max_constant, + }, { .ctl_name = 0 } };
net/ipv4/tcp.c +23 -0
@@ -1764,6 +1764,8 @@return err; } +#define TCP_BACKOFF_MAXVAL 65535 +/* * Socket option code for TCP. */
@@ -1939,6 +1941,21 @@ }break ; +case TCP_BACKOFF_MAX : +if (val <1 || val >TCP_BACKOFF_MAXVAL ) + err = -EINVAL ; +else + tp->rto_max = val; +break ; + +case TCP_BACKOFF_INIT : +if (val <1 || val >TCP_BACKOFF_MAXVAL ) + err = -EINVAL ; +else + tp->rto_init = val; +break ; + +default : err = -ENOPROTOOPT ;break ;
@@ -2110,6 +2127,12 @@if (copy_to_user (optval, icsk->icsk_ca_ops->name, len))return -EFAULT ;return 0 ; +case TCP_BACKOFF_MAX : + val =tcp_rto_max (tp)*1000 /HZ ; +break ; +case TCP_BACKOFF_INIT : + val =tcp_rto_init (tp)*1000 /HZ ; +break ;default :return -ENOPROTOOPT ; };
net/ipv4/tcp_timer.c +11 -7
@@ -31,6 +31,8 @@int sysctl_tcp_retries1 =TCP_RETR1 ;int sysctl_tcp_retries2 =TCP_RETR2 ;int sysctl_tcp_orphan_retries; +unsigned long sysctl_tcp_rto_max =TCP_RTO_MAX ; +unsigned long sysctl_tcp_rto_init =TCP_TIMEOUT_INIT ;static void tcp_write_timer (unsigned long );static void tcp_delack_timer (unsigned long );
@@ -71,7 +73,8 @@/* If peer does not open window for long time, or did not transmit * anything for long time, penalize it. */ -if ((s32)(tcp_time_stamp - tp->lsndtime) >2 *TCP_RTO_MAX || !do_reset) +if ((s32)(tcp_time_stamp - tp->lsndtime) >2 *tcp_rto_max (tp) || + !do_reset) orphans <<=1 ;/* If some dubious ICMP arrived, penalize even more. */
@@ -256,8 +259,8 @@ max_probes = sysctl_tcp_retries2;if (sock_flag (sk,SOCK_DEAD )) { -const int alive = ((icsk->icsk_rto << icsk->icsk_backoff) <TCP_RTO_MAX ); - +const int alive = ((icsk->icsk_rto << icsk->icsk_backoff) < +tcp_rto_max (tp)); max_probes =tcp_orphan_retries (sk, alive);if (tcp_out_of_resources (sk, alive || icsk->icsk_probes_out <= max_probes))
@@ -301,7 +304,7 @@ inet->num, tp->snd_una, tp->snd_nxt); }#endif -if (tcp_time_stamp - tp->rcv_tstamp >TCP_RTO_MAX ) { +if (tcp_time_stamp - tp->rcv_tstamp >tcp_rto_max (tp)) {tcp_write_err (sk); goto out; }
@@ -373,7 +376,8 @@ out_reset_timer: icsk->icsk_rto =min (icsk->icsk_rto <<1 ,TCP_RTO_MAX ); -inet_csk_reset_xmit_timer (sk,ICSK_TIME_RETRANS , icsk->icsk_rto,TCP_RTO_MAX ); +inet_csk_reset_xmit_timer (sk,ICSK_TIME_RETRANS , icsk->icsk_rto, +tcp_rto_max (tp));if (icsk->icsk_retransmits > sysctl_tcp_retries1)__sk_dst_reset (sk);
@@ -427,8 +431,8 @@static void tcp_synack_timer (struct sock *sk) { -inet_csk_reqsk_queue_prune (sk,TCP_SYNQ_INTERVAL , -TCP_TIMEOUT_INIT ,TCP_RTO_MAX ); +inet_csk_reqsk_queue_prune (sk,TCP_SYNQ_INTERVAL ,TCP_TIMEOUT_INIT , +tcp_rto_max (tcp_sk (sk))); }void tcp_set_keepalive (struct sock *sk,int val)
In article <[email protected]> (at Tue, 10 Oct 2006 18:46:58 -0700), Ben Woodard <[email protected]> says:
Quoted 28 lines
diff -ru
linux-2.6.18/net/ipv4/tcp.clinux-2.6.18.new/net/ipv4/tcp.cnet/ipv4/tcp.c +15
-0@@ -1939,6 +1941,21 @@ }break ; +case TCP_BACKOFF_MAX : +if (val <1 || val >TCP_BACKOFF_MAXVAL ) + err = -EINVAL ; +else + tp->rto_max = val; +break ; + +case TCP_BACKOFF_INIT : +if (val <1 || val >TCP_BACKOFF_MAXVAL ) + err = -EINVAL ; +else + tp->rto_init = val; +break ; + +default : err = -ENOPROTOOPT ;break ;@@ -2110,6 +2127,12 @@if (copy_to_user (optval, icsk->icsk_ca_ops->name, len))return -EFAULT ;
net/ipv4/tcp.c line 2138
Quoted 10 lines
net/ipv4/tcp.c +6
-0return 0 ; +case TCP_BACKOFF_MAX : + val =tcp_rto_max (tp)*1000 /HZ ; +break ; +case TCP_BACKOFF_INIT : + val =tcp_rto_init (tp)*1000 /HZ ; +break ;default :return -ENOPROTOOPT ; };
They look very inconsistent. Please use tp->rto_max / tp->rto_init.
--yoshfuji
David Miller
maintainerFrom: Ben Woodard <[email protected]>
Date: Tue, 10 Oct 2006 18:46:58 -0700
include/linux/tcp.h line 263
Quoted 6 lines
include/linux/tcp.h +2
-0@@ -257,6 +259,8 @@__u8 frto_counter;/* Number of new acks after RTO */ __u8 nonagle;/* Disable Nagle algorithm? */ __u8 keepalive_probes;/* num of allowed keep alive probes */ +__u16 rto_max;/* Maximum backoff value in ms */ +__u16 rto_init;/* Initial backoff value in ms */
The existing struct members are properly indented using tabs, your patch adds members which are indented using spaces. Please fix this, thanks a lot.
David Miller
maintainerActually, your entire patch uses spaces for indentation of every new line added, not just those two new struct members I pointed out. Please use tabs for all of those cases.
Thanks a lot.
Ben Woodard wrote:
------------------------------------------------------------------------
Quoted 7 lines
diff -ru
linux-2.6.18/include/net/tcp.hlinux-2.6.18.new/include/net/tcp.hinclude/net/tcp.h +0
-0@@ -227,11 +227,23 @@extern int sysctl_tcp_base_mss;extern int sysctl_tcp_workaround_signed_windows;extern int sysctl_tcp_slow_start_after_idle;
include/net/tcp.h line 239
Quoted 10 lines
include/net/tcp.h +5
-0+extern unsigned long sysctl_tcp_rto_max; +extern unsigned long sysctl_tcp_rto_init;extern atomic_t tcp_memory_allocated;extern atomic_t tcp_sockets_allocated;extern int tcp_memory_pressure; +static inline unsigned long tcp_rto_max (struct tcp_sock *tp) +{ +return tp->rto_max ? tp->rto_max*HZ /1000 : sysctl_tcp_rto_max;
^^^^^^^^^^^^^^^^^^^
That should probably be msecs_to_jiffies(tp->rto_max)
include/net/tcp.h line 244
Quoted 5 lines
include/net/tcp.h +5
-0+} + +static inline unsigned long tcp_rto_init (struct tcp_sock *tp) +{ +return tp->rto_init ? tp->rto_init*HZ /1000 : sysctl_tcp_rto_init;
Ditto.
Quoted 33 lines
include/net/tcp.h +2
-0+} +/* * The next routines deal with comparing 32 bit unsigned ints * and worry about wraparound (automatic with unsigned arithmetic). diff -ru
linux-2.6.18/net/ipv4/sysctl_net_ipv4.clinux-2.6.18.new/net/ipv4/sysctl_net_ipv4.cnet/ipv4/sysctl_net_ipv4.c +14
-0@@ -128,6 +128,8 @@return ret; } +static unsigned long tcp_rto_min=0 ; +static unsigned long tcp_rto_max=65535 ;ctl_table ipv4_table[] = { {@@ -697,6 +699,26 @@ .mode = 0644, .proc_handler = &proc_dointvec }, + { + .ctl_name = NET_TCP_RTO_MAX, + .procname = "tcp_rto_max", + .data = &sysctl_tcp_rto_max, + .maxlen = sizeof(unsigned), + .mode = 0644, + .proc_handler = &proc_doulongvec_ms_jiffies, + .extra1 = &tcp_rto_min_constant, + .extra2 = &tcp_rto_max_constant, + }, + { + .ctl_name = NET_TCP_RTO_INIT,
net/ipv4/sysctl_net_ipv4.c line 723
Quoted 10 lines
net/ipv4/sysctl_net_ipv4.c +8
-0+ .procname = "tcp_rto_init", + .data = &sysctl_tcp_rto_init, + .maxlen = sizeof(unsigned), + .mode = 0644, + .proc_handler = &proc_doulongvec_ms_jiffies, + .extra1 = &tcp_rto_min_constant, + .extra2 = &tcp_rto_max_constant, + }, { .ctl_name = 0 } };
Try as I might, I can't find proc_doulongvec_ms_jiffies() anywhere. I think you meant proc_doulongvec_ms_jiffies_minmax()?
Also, this function has a bug in that it doesn't do corrections for potentially different HZ values. Look at the msecs_to_jiffies... When I've used proc_doulongvec_ms_jiffies_minmax() before, I would seen rather interesting truncation errors such that sysctl input didn't match sysctl output.
Quoted 36 lines
diff -ru
linux-2.6.18/net/ipv4/tcp.clinux-2.6.18.new/net/ipv4/tcp.cnet/ipv4/tcp.c +17
-0@@ -1764,6 +1764,8 @@return err; } +#define TCP_BACKOFF_MAXVAL 65535 +/* * Socket option code for TCP. */ @@ -1939,6 +1941,21 @@ }break ; +case TCP_BACKOFF_MAX : +if (val <1 || val >TCP_BACKOFF_MAXVAL ) + err = -EINVAL ; +else + tp->rto_max = val; +break ; + +case TCP_BACKOFF_INIT : +if (val <1 || val >TCP_BACKOFF_MAXVAL ) + err = -EINVAL ; +else + tp->rto_init = val; +break ; + +default : err = -ENOPROTOOPT ;break ;
net/ipv4/tcp.c line 2134
Quoted 8 lines
net/ipv4/tcp.c +5
-0@@ -2110,6 +2127,12 @@if (copy_to_user (optval, icsk->icsk_ca_ops->name, len))return -EFAULT ;return 0 ; +case TCP_BACKOFF_MAX : + val =tcp_rto_max (tp)*1000 /HZ ; +break ; +case TCP_BACKOFF_INIT : + val =tcp_rto_init (tp)*1000 /HZ ;
The two divisions above introduce truncation errors such the input doesn't match the output. Better to use jiffies_to_msecs().
Regards
-vlad
Here we go again. The changes are as follows:
1) the spaces are gone and now it is tabs.
2) used msecs_to_jiffies() and jiffies_to_msecs(). I'm much happier with
that. I didn't know those functions existed.
3) changed over to proc_doulongvec_ms_jiffies_minmax(). Last night's test compile failed because I was out of disk. I figured that the code I changed had compiled. I guess not.
I really didn't understand Yoshifuji Hideaki's comment. (sorry)
-ben
Quoted 130 lines · Vlad Yasevich
Ben Woodard wrote:
------------------------------------------------------------------------Quoted 7 lines
diff -ru
linux-2.6.18/include/net/tcp.hlinux-2.6.18.new/include/net/tcp.hinclude/net/tcp.h +0
-0@@ -227,11 +227,23 @@extern int sysctl_tcp_base_mss;extern int sysctl_tcp_workaround_signed_windows;extern int sysctl_tcp_slow_start_after_idle;include/net/tcp.h line 239
Quoted 10 lines
include/net/tcp.h +5
-0+extern unsigned long sysctl_tcp_rto_max; +extern unsigned long sysctl_tcp_rto_init;extern atomic_t tcp_memory_allocated;extern atomic_t tcp_sockets_allocated;extern int tcp_memory_pressure; +static inline unsigned long tcp_rto_max (struct tcp_sock *tp) +{ +return tp->rto_max ? tp->rto_max*HZ /1000 : sysctl_tcp_rto_max;^^^^^^^^^^^^^^^^^^^That should probably be
msecs_to_jiffies(tp->rto_max)include/net/tcp.h line 244
Quoted 5 lines
include/net/tcp.h +5
-0+} + +static inline unsigned long tcp_rto_init (struct tcp_sock *tp) +{ +return tp->rto_init ? tp->rto_init*HZ /1000 : sysctl_tcp_rto_init;Ditto.
Quoted 33 lines
include/net/tcp.h +2
-0+} +/* * The next routines deal with comparing 32 bit unsigned ints * and worry about wraparound (automatic with unsigned arithmetic). diff -ru
linux-2.6.18/net/ipv4/sysctl_net_ipv4.clinux-2.6.18.new/net/ipv4/sysctl_net_ipv4.cnet/ipv4/sysctl_net_ipv4.c +14
-0@@ -128,6 +128,8 @@return ret; } +static unsigned long tcp_rto_min=0 ; +static unsigned long tcp_rto_max=65535 ;ctl_table ipv4_table[] = { {@@ -697,6 +699,26 @@ .mode = 0644, .proc_handler = &proc_dointvec }, + { + .ctl_name = NET_TCP_RTO_MAX, + .procname = "tcp_rto_max", + .data = &sysctl_tcp_rto_max, + .maxlen = sizeof(unsigned), + .mode = 0644, + .proc_handler = &proc_doulongvec_ms_jiffies, + .extra1 = &tcp_rto_min_constant, + .extra2 = &tcp_rto_max_constant, + }, + { + .ctl_name = NET_TCP_RTO_INIT,net/ipv4/sysctl_net_ipv4.c line 723
Quoted 10 lines
net/ipv4/sysctl_net_ipv4.c +8
-0+ .procname = "tcp_rto_init", + .data = &sysctl_tcp_rto_init, + .maxlen = sizeof(unsigned), + .mode = 0644, + .proc_handler = &proc_doulongvec_ms_jiffies, + .extra1 = &tcp_rto_min_constant, + .extra2 = &tcp_rto_max_constant, + }, { .ctl_name = 0 } };Try as I might, I can't find
proc_doulongvec_ms_jiffies()anywhere. I think you meantproc_doulongvec_ms_jiffies_minmax()?Also, this function has a bug in that it doesn't do corrections for potentially different HZ values. Look at the
msecs_to_jiffies... When I've usedproc_doulongvec_ms_jiffies_minmax()before, I would seen rather interesting truncation errors such that sysctl input didn't match sysctl output.Quoted 36 lines
diff -ru
linux-2.6.18/net/ipv4/tcp.clinux-2.6.18.new/net/ipv4/tcp.cnet/ipv4/tcp.c +17
-0@@ -1764,6 +1764,8 @@return err; } +#define TCP_BACKOFF_MAXVAL 65535 +/* * Socket option code for TCP. */ @@ -1939,6 +1941,21 @@ }break ; +case TCP_BACKOFF_MAX : +if (val <1 || val >TCP_BACKOFF_MAXVAL ) + err = -EINVAL ; +else + tp->rto_max = val; +break ; + +case TCP_BACKOFF_INIT : +if (val <1 || val >TCP_BACKOFF_MAXVAL ) + err = -EINVAL ; +else + tp->rto_init = val; +break ; + +default : err = -ENOPROTOOPT ;break ;net/ipv4/tcp.c line 2134
Quoted 8 lines
net/ipv4/tcp.c +5
-0@@ -2110,6 +2127,12 @@if (copy_to_user (optval, icsk->icsk_ca_ops->name, len))return -EFAULT ;return 0 ; +case TCP_BACKOFF_MAX : + val =tcp_rto_max (tp)*1000 /HZ ; +break ; +case TCP_BACKOFF_INIT : + val =tcp_rto_init (tp)*1000 /HZ ;The two divisions above introduce truncation errors such the input doesn't match the output. Better to use
jiffies_to_msecs().
Quoted 2 lines
Regards
-vlad
include/linux/sysctl.h +2 -0
@@ -411,6 +411,8 @@NET_IPV4_TCP_WORKAROUND_SIGNED_WINDOWS =115 ,NET_TCP_DMA_COPYBREAK =116 ,NET_TCP_SLOW_START_AFTER_IDLE =117 , +NET_TCP_RTO_MAX =118 , + NET_TCP_RTO_INIT=119, }; enum {
include/linux/tcp.h +4 -0
@@ -94,6 +94,8 @@#define TCP_INFO 11/* Information about this connection. */ #define TCP_QUICKACK 12/* Block/reenable quick acks */ #define TCP_CONGESTION 13/* Congestion control algorithm */ +#define TCP_BACKOFF_MAX 14/* Maximum backoff value */ +#define TCP_BACKOFF_INIT 15/* Initial backoff value */ #define TCPI_OPT_TIMESTAMPS 1#define TCPI_OPT_SACK 2
@@ -257,6 +259,8 @@__u8 frto_counter;/* Number of new acks after RTO */ __u8 nonagle;/* Disable Nagle algorithm? */ __u8 keepalive_probes;/* num of allowed keep alive probes */ +__u16 rto_max;/* Maximum backoff value in ms */ +__u16 rto_init;/* Initial backoff value in ms */ /* RTT measurement */ __u32 srtt;/* smoothed round trip time << 3 */
include/net/tcp.h +12 -0
@@ -227,11 +227,23 @@extern int sysctl_tcp_base_mss;extern int sysctl_tcp_workaround_signed_windows;extern int sysctl_tcp_slow_start_after_idle; +extern unsigned long sysctl_tcp_rto_max; +extern unsigned long sysctl_tcp_rto_init;extern atomic_t tcp_memory_allocated;extern atomic_t tcp_sockets_allocated;extern int tcp_memory_pressure; +static inline unsigned long tcp_rto_max (struct tcp_sock *tp) +{ +return tp->rto_max ?msecs_to_jiffies (tp->rto_max) : sysctl_tcp_rto_max; +} + +static inline unsigned long tcp_rto_init (struct tcp_sock *tp) +{ +return tp->rto_init ?msecs_to_jiffies (tp->rto_init) : sysctl_tcp_rto_init; +} +/* * The next routines deal with comparing 32 bit unsigned ints * and worry about wraparound (automatic with unsigned arithmetic).
Only in linux-2.6.18.new/include/net: tcp.h~
net/ipv4/sysctl_net_ipv4.c +22 -0
@@ -128,6 +128,8 @@return ret; } +static unsigned long tcp_rto_min=0 ; +static unsigned long tcp_rto_max=65535 ;ctl_table ipv4_table[] = { {
@@ -697,6 +699,26 @@ .mode = 0644, .proc_handler = &proc_dointvec }, + { + .ctl_name = NET_TCP_RTO_MAX, + .procname = "tcp_rto_max", + .data = &sysctl_tcp_rto_max, + .maxlen = sizeof(unsigned), + .mode = 0644, + .proc_handler = &proc_doulongvec_ms_jiffies_minmax, + .extra1 = &tcp_rto_min_constant, + .extra2 = &tcp_rto_max_constant, + }, + { + .ctl_name = NET_TCP_RTO_INIT, + .procname = "tcp_rto_init", + .data = &sysctl_tcp_rto_init, + .maxlen = sizeof(unsigned), + .mode = 0644, + .proc_handler = &proc_doulongvec_ms_jiffies_minmax, + .extra1 = &tcp_rto_min_constant, + .extra2 = &tcp_rto_max_constant, + }, { .ctl_name = 0 } };
net/ipv4/tcp.c +22 -0
@@ -1764,6 +1764,8 @@return err; } +#define TCP_BACKOFF_MAXVAL 65535 +/* * Socket option code for TCP. */
@@ -1939,6 +1941,20 @@ }break ; +case TCP_BACKOFF_MAX : +if (val <1 || val >TCP_BACKOFF_MAXVAL ) + err = -EINVAL ; +else + tp->rto_max = val; +break ; + +case TCP_BACKOFF_INIT : +if (val <1 || val >TCP_BACKOFF_MAXVAL ) + err = -EINVAL ; +else + tp->rto_init = val; +break ; +default : err = -ENOPROTOOPT ;break ;
@@ -2110,6 +2126,12 @@if (copy_to_user (optval, icsk->icsk_ca_ops->name, len))return -EFAULT ;return 0 ; +case TCP_BACKOFF_MAX : + val =jiffies_to_msecs (tcp_rto_max (tp)); +break ; +case TCP_BACKOFF_INIT : + val =jiffies_to_msecs (tcp_rto_init (tp)); +break ;default :return -ENOPROTOOPT ; };
net/ipv4/tcp_timer.c +11 -7
@@ -31,6 +31,8 @@int sysctl_tcp_retries1 =TCP_RETR1 ;int sysctl_tcp_retries2 =TCP_RETR2 ;int sysctl_tcp_orphan_retries; +unsigned long sysctl_tcp_rto_max =TCP_RTO_MAX ; +unsigned long sysctl_tcp_rto_init =TCP_TIMEOUT_INIT ;static void tcp_write_timer (unsigned long );static void tcp_delack_timer (unsigned long );
@@ -71,7 +73,8 @@/* If peer does not open window for long time, or did not transmit * anything for long time, penalize it. */ -if ((s32)(tcp_time_stamp - tp->lsndtime) >2 *TCP_RTO_MAX || !do_reset) +if ((s32)(tcp_time_stamp - tp->lsndtime) >2 *tcp_rto_max (tp) || + !do_reset) orphans <<=1 ;/* If some dubious ICMP arrived, penalize even more. */
@@ -256,8 +259,8 @@ max_probes = sysctl_tcp_retries2;if (sock_flag (sk,SOCK_DEAD )) { -const int alive = ((icsk->icsk_rto << icsk->icsk_backoff) <TCP_RTO_MAX ); - +const int alive = ((icsk->icsk_rto << icsk->icsk_backoff) < +tcp_rto_max (tp)); max_probes =tcp_orphan_retries (sk, alive);if (tcp_out_of_resources (sk, alive || icsk->icsk_probes_out <= max_probes))
@@ -301,7 +304,7 @@ inet->num, tp->snd_una, tp->snd_nxt); }#endif -if (tcp_time_stamp - tp->rcv_tstamp >TCP_RTO_MAX ) { +if (tcp_time_stamp - tp->rcv_tstamp >tcp_rto_max (tp)) {tcp_write_err (sk); goto out; }
@@ -373,7 +376,8 @@ out_reset_timer: icsk->icsk_rto =min (icsk->icsk_rto <<1 ,TCP_RTO_MAX ); -inet_csk_reset_xmit_timer (sk,ICSK_TIME_RETRANS , icsk->icsk_rto,TCP_RTO_MAX ); +inet_csk_reset_xmit_timer (sk,ICSK_TIME_RETRANS , icsk->icsk_rto, +tcp_rto_max (tp));if (icsk->icsk_retransmits > sysctl_tcp_retries1)__sk_dst_reset (sk);
@@ -427,8 +431,8 @@static void tcp_synack_timer (struct sock *sk) { -inet_csk_reqsk_queue_prune (sk,TCP_SYNQ_INTERVAL , -TCP_TIMEOUT_INIT ,TCP_RTO_MAX ); +inet_csk_reqsk_queue_prune (sk,TCP_SYNQ_INTERVAL ,TCP_TIMEOUT_INIT , +tcp_rto_max (tcp_sk (sk))); }void tcp_set_keepalive (struct sock *sk,int val)
In article <[email protected]> (at Wed, 11 Oct 2006 17:51:24 -0700), Ben Woodard <[email protected]> says:
Quoted 13 lines
diff -ru
linux-2.6.18/net/ipv4/sysctl_net_ipv4.clinux-2.6.18.new/net/ipv4/sysctl_net_ipv4.cnet/ipv4/sysctl_net_ipv4.c +2
-0@@ -128,6 +128,8 @@return ret; } +static unsigned long tcp_rto_min=0 ; +static unsigned long tcp_rto_max=65535 ;ctl_table ipv4_table[] = { {
net/ipv4/sysctl_net_ipv4.c line 706
Quoted 8 lines
net/ipv4/sysctl_net_ipv4.c +5
-0@@ -697,6 +699,26 @@ .mode = 0644, .proc_handler = &proc_dointvec }, + { + .ctl_name = NET_TCP_RTO_MAX, + .procname = "tcp_rto_max", + .data = &sysctl_tcp_rto_max, + .maxlen = sizeof(unsigned),
sizeof(unsigned long)
net/ipv4/sysctl_net_ipv4.c line 716
Quoted 10 lines
net/ipv4/sysctl_net_ipv4.c +10
-0+ .mode = 0644, + .proc_handler = &proc_doulongvec_ms_jiffies_minmax, + .extra1 = &tcp_rto_min_constant, + .extra2 = &tcp_rto_max_constant, + }, + { + .ctl_name = NET_TCP_RTO_INIT, + .procname = "tcp_rto_init", + .data = &sysctl_tcp_rto_init, + .maxlen = sizeof(unsigned),
sizeof(unsigned long)
Quoted 42 lines
net/ipv4/sysctl_net_ipv4.c +5
-0+ .mode = 0644, + .proc_handler = &proc_doulongvec_ms_jiffies_minmax, + .extra1 = &tcp_rto_min_constant, + .extra2 = &tcp_rto_max_constant, + }, { .ctl_name = 0 } };diff -ru
linux-2.6.18/net/ipv4/tcp.clinux-2.6.18.new/net/ipv4/tcp.cnet/ipv4/tcp.c +16
-0@@ -1764,6 +1764,8 @@return err; } +#define TCP_BACKOFF_MAXVAL 65535 +/* * Socket option code for TCP. */ @@ -1939,6 +1941,20 @@ }break ; +case TCP_BACKOFF_MAX : +if (val <1 || val >TCP_BACKOFF_MAXVAL ) + err = -EINVAL ; +else + tp->rto_max = val; +break ; + +case TCP_BACKOFF_INIT : +if (val <1 || val >TCP_BACKOFF_MAXVAL ) + err = -EINVAL ; +else + tp->rto_init = val; +break ; +default : err = -ENOPROTOOPT ;break ;
net/ipv4/tcp.c line 2131
Quoted 6 lines
net/ipv4/tcp.c +3
-0@@ -2110,6 +2126,12 @@if (copy_to_user (optval, icsk->icsk_ca_ops->name, len))return -EFAULT ;return 0 ; +case TCP_BACKOFF_MAX : + val =jiffies_to_msecs (tcp_rto_max (tp)); +break ;
tp->rto_max
net/ipv4/tcp.c line 2135
Quoted 4 lines
net/ipv4/tcp.c +3
-0+case TCP_BACKOFF_INIT : + val =jiffies_to_msecs (tcp_rto_init (tp)); +break ;default :
tp->rto_init
--yoshfuji
Quoted 4 lines · YOSHIFUJI Hideaki / 吉藤英明
Review
Quoted 2 lines
(quoted diff) +2
-0+ .data = &sysctl_tcp_rto_max, + .maxlen = sizeof(unsigned),sizeof(unsigned long)
Good catch. That would have corrupted things badly on some 64b platforms. With all the flux in the area I forgot to change the size of that but would have been OK on the ia32 boxes.
Quoted 13 lines
net/ipv4/tcp.c line 2131
Quoted 10 lines
diff -ru
linux-2.6.18/net/ipv4/tcp.clinux-2.6.18.new/net/ipv4/tcp.cnet/ipv4/tcp.c +3
-0@@ -2110,6 +2126,12 @@if (copy_to_user (optval, icsk->icsk_ca_ops->name, len))return -EFAULT ;return 0 ; +case TCP_BACKOFF_MAX : + val =jiffies_to_msecs (tcp_rto_max (tp)); +break ;
tp->rto_max
Quoted 6 lines
net/ipv4/tcp.c line 2135
Quoted 4 lines
net/ipv4/tcp.c +3
-0+case TCP_BACKOFF_INIT : + val =jiffies_to_msecs (tcp_rto_init (tp)); +break ;default :
tp->rto_init
OK I get it now.
Quoted 2 lines
--yoshfuji
include/linux/sysctl.h +2 -0
@@ -411,6 +411,8 @@NET_IPV4_TCP_WORKAROUND_SIGNED_WINDOWS =115 ,NET_TCP_DMA_COPYBREAK =116 ,NET_TCP_SLOW_START_AFTER_IDLE =117 , +NET_TCP_RTO_MAX =118 , + NET_TCP_RTO_INIT=119, }; enum {
include/linux/tcp.h +4 -0
@@ -94,6 +94,8 @@#define TCP_INFO 11/* Information about this connection. */ #define TCP_QUICKACK 12/* Block/reenable quick acks */ #define TCP_CONGESTION 13/* Congestion control algorithm */ +#define TCP_BACKOFF_MAX 14/* Maximum backoff value */ +#define TCP_BACKOFF_INIT 15/* Initial backoff value */ #define TCPI_OPT_TIMESTAMPS 1#define TCPI_OPT_SACK 2
@@ -257,6 +259,8 @@__u8 frto_counter;/* Number of new acks after RTO */ __u8 nonagle;/* Disable Nagle algorithm? */ __u8 keepalive_probes;/* num of allowed keep alive probes */ +__u16 rto_max;/* Maximum backoff value in ms */ +__u16 rto_init;/* Initial backoff value in ms */ /* RTT measurement */ __u32 srtt;/* smoothed round trip time << 3 */
Only in linux-2.6.18.new/include/linux: tcp.h~
include/net/tcp.h +12 -0
@@ -227,11 +227,23 @@extern int sysctl_tcp_base_mss;extern int sysctl_tcp_workaround_signed_windows;extern int sysctl_tcp_slow_start_after_idle; +extern unsigned long sysctl_tcp_rto_max; +extern unsigned long sysctl_tcp_rto_init;extern atomic_t tcp_memory_allocated;extern atomic_t tcp_sockets_allocated;extern int tcp_memory_pressure; +static inline unsigned long tcp_rto_max (struct tcp_sock *tp) +{ +return tp->rto_max ?msecs_to_jiffies (tp->rto_max) : sysctl_tcp_rto_max; +} + +static inline unsigned long tcp_rto_init (struct tcp_sock *tp) +{ +return tp->rto_init ?msecs_to_jiffies (tp->rto_init) : sysctl_tcp_rto_init; +} +/* * The next routines deal with comparing 32 bit unsigned ints * and worry about wraparound (automatic with unsigned arithmetic).
Only in linux-2.6.18.new/include/net: tcp.h~
net/ipv4/sysctl_net_ipv4.c +22 -0
@@ -128,6 +128,8 @@return ret; } +static unsigned long tcp_rto_min=0 ; +static unsigned long tcp_rto_max=65535 ;ctl_table ipv4_table[] = { {
@@ -697,6 +699,26 @@ .mode = 0644, .proc_handler = &proc_dointvec }, + { + .ctl_name = NET_TCP_RTO_MAX, + .procname = "tcp_rto_max", + .data = &sysctl_tcp_rto_max, + .maxlen = sizeof(unsigned long), + .mode = 0644, + .proc_handler = &proc_doulongvec_ms_jiffies_minmax, + .extra1 = &tcp_rto_min_constant, + .extra2 = &tcp_rto_max_constant, + }, + { + .ctl_name = NET_TCP_RTO_INIT, + .procname = "tcp_rto_init", + .data = &sysctl_tcp_rto_init, + .maxlen = sizeof(unsigned long), + .mode = 0644, + .proc_handler = &proc_doulongvec_ms_jiffies_minmax, + .extra1 = &tcp_rto_min_constant, + .extra2 = &tcp_rto_max_constant, + }, { .ctl_name = 0 } };
Only in linux-2.6.18.new/net/ipv4: sysctl_net_ipv4.c~
net/ipv4/tcp.c +22 -0
@@ -1764,6 +1764,8 @@return err; } +#define TCP_BACKOFF_MAXVAL 65535 +/* * Socket option code for TCP. */
@@ -1939,6 +1941,20 @@ }break ; +case TCP_BACKOFF_MAX : +if (val <1 || val >TCP_BACKOFF_MAXVAL ) + err = -EINVAL ; +else + tp->rto_max = val; +break ; + +case TCP_BACKOFF_INIT : +if (val <1 || val >TCP_BACKOFF_MAXVAL ) + err = -EINVAL ; +else + tp->rto_init = val; +break ; +default : err = -ENOPROTOOPT ;break ;
@@ -2110,6 +2126,12 @@if (copy_to_user (optval, icsk->icsk_ca_ops->name, len))return -EFAULT ;return 0 ; +case TCP_BACKOFF_MAX : + val = tp->rto_max; +break ; +case TCP_BACKOFF_INIT : + val = tp->rto_init; +break ;default :return -ENOPROTOOPT ; };
Only in linux-2.6.18.new/net/ipv4: tcp.c~
net/ipv4/tcp_timer.c +11 -7
@@ -31,6 +31,8 @@int sysctl_tcp_retries1 =TCP_RETR1 ;int sysctl_tcp_retries2 =TCP_RETR2 ;int sysctl_tcp_orphan_retries; +unsigned long sysctl_tcp_rto_max =TCP_RTO_MAX ; +unsigned long sysctl_tcp_rto_init =TCP_TIMEOUT_INIT ;static void tcp_write_timer (unsigned long );static void tcp_delack_timer (unsigned long );
@@ -71,7 +73,8 @@/* If peer does not open window for long time, or did not transmit * anything for long time, penalize it. */ -if ((s32)(tcp_time_stamp - tp->lsndtime) >2 *TCP_RTO_MAX || !do_reset) +if ((s32)(tcp_time_stamp - tp->lsndtime) >2 *tcp_rto_max (tp) || + !do_reset) orphans <<=1 ;/* If some dubious ICMP arrived, penalize even more. */
@@ -256,8 +259,8 @@ max_probes = sysctl_tcp_retries2;if (sock_flag (sk,SOCK_DEAD )) { -const int alive = ((icsk->icsk_rto << icsk->icsk_backoff) <TCP_RTO_MAX ); - +const int alive = ((icsk->icsk_rto << icsk->icsk_backoff) < +tcp_rto_max (tp)); max_probes =tcp_orphan_retries (sk, alive);if (tcp_out_of_resources (sk, alive || icsk->icsk_probes_out <= max_probes))
@@ -301,7 +304,7 @@ inet->num, tp->snd_una, tp->snd_nxt); }#endif -if (tcp_time_stamp - tp->rcv_tstamp >TCP_RTO_MAX ) { +if (tcp_time_stamp - tp->rcv_tstamp >tcp_rto_max (tp)) {tcp_write_err (sk); goto out; }
@@ -373,7 +376,8 @@ out_reset_timer: icsk->icsk_rto =min (icsk->icsk_rto <<1 ,TCP_RTO_MAX ); -inet_csk_reset_xmit_timer (sk,ICSK_TIME_RETRANS , icsk->icsk_rto,TCP_RTO_MAX ); +inet_csk_reset_xmit_timer (sk,ICSK_TIME_RETRANS , icsk->icsk_rto, +tcp_rto_max (tp));if (icsk->icsk_retransmits > sysctl_tcp_retries1)__sk_dst_reset (sk);
@@ -427,8 +431,8 @@static void tcp_synack_timer (struct sock *sk) { -inet_csk_reqsk_queue_prune (sk,TCP_SYNQ_INTERVAL , -TCP_TIMEOUT_INIT ,TCP_RTO_MAX ); +inet_csk_reqsk_queue_prune (sk,TCP_SYNQ_INTERVAL ,TCP_TIMEOUT_INIT , +tcp_rto_max (tcp_sk (sk))); }void tcp_set_keepalive (struct sock *sk,int val)