lkml.org 
[lkml]   [1999]   [Feb]   [26]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectRe: [patch] workaround for solaris 2.5.1 and 2.6 FIN bug (ID 4083814)
This bug was fixed in the 2.0.3x series about a year ago. The approach 
there didn't have any adverse side effects -- since the bug only
happens when the FIN/Data segment arrives out of order, and the
data will get ack'ed by Solaris, the approach was (on the retransmit
from the linux end) to *not* retransmit the ack'ed data. This leaves
a packet with just a FIN in it. Arguably that was what should have
been happening anyway. Once I understood what was happening,
I seem to recall that the fix was pretty trivial.

This is the bit of code from tcp_do_retransmit in 2.0.36

/* See if we need to shrink the leading packet on
* the retransmit queue. Strictly speaking, we
* should never need to do this, but some buggy TCP
* implementations get confused if you send them
* a packet that contains both old and new data. (Feh!)
* Soooo, we have this uglyness here.
*
* Is the && test needed here? If so, then it implies that
* we might be retransmitting an acked packet. This code is
* needed here to talk to Solaris 2.6 stack.
*/
if (after(sk->rcv_ack_seq,skb->seq+th->syn) &&
before(sk->rcv_ack_seq, skb->end_seq))
tcp_shrink_skb(sk,skb,sk->rcv_ack_seq);

I wonder how many other bugs have been fixed in 2.0.36ff and not yet
fixed
in 2.2.x?

Philip


Andrea Arcangeli wrote:
>
> Solaris has a stupid bug in its TCP stack that cause it to hang the
> connection between linux-2.2.x and Solaris (with linux as server) once the
> connection closes.
>
> The reason is that linux-2.2.x is smart enough to save some good packet on
> the network by setting the FIN flag in the latest packet of data if there
> is pending data in write queue. But if such last packet gets reordered by
> the network it seems that Solaris ignores the FIN flag and as first it
> will think that the last octect is full of data while it's the FIN advance
> (if I am thinking right I think this can cause some troubles), and as
> second Solaris will not send back to Linux the FIN to allow Linux to go to
> FINWAIT-2 from FINWAIT-1. So the connection will hang and the end of
> the data has no way to be transferred correctly.
>
> Sun just released a fix for Solaris but since I think there are still many
> buggy Solaris 2.6 and 2.5.1 TCP stacks on the Internet, I taken the time
> to implement a workaround for Linux.
>
> The workaround is implemented as a sysctl. As default there is no
> workaround. But if you:
>
> echo 1 >//proc/sys/net/ipv4/tcp_solaris_fin_bug_4083814_workaround
>
> you'll enable the buggy-solaris-compatibilty-mode on the Linux TCP stack.
>
> Note that this make a difference only when Linux is the server. So large
> FTP sites are likely to want to apply my patch and enable the workaround
> in the meantime the bogus Solaris tcp stack will be fixed properly
> everywhere.
>
> This is probably useful also in Unversity like mine where there are many
> old slowww Sun machines that are not likely to be patched until it will be
> discovered the next root exploit ;).
>
> Once the workaround is enabled you risk to generate 1 more packet on the
> network every time you close a TCP socket.
>
> Here the patch:
>
> Index: include/linux/sysctl.h
> ===================================================================
> RCS file: /var/cvs/linux/include/linux/sysctl.h,v
> retrieving revision 1.1.2.2
> diff -u -r1.1.2.2 sysctl.h
> --- sysctl.h 1999/02/06 16:42:46 1.1.2.2
> +++ linux/include/linux/sysctl.h 1999/02/25 14:59:34
> @@ -209,7 +209,8 @@
> 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_IPV4_IGMP_MAX_MEMBERSHIPS=65,
> + NET_IPV4_TCP_SOLARIS_FIN_BUG_4083814_WORKAROUND=66,
> };
>
> enum {
> Index: net/ipv4/sysctl_net_ipv4.c
> ===================================================================
> RCS file: /var/cvs/linux/net/ipv4/sysctl_net_ipv4.c,v
> retrieving revision 1.1.2.1
> diff -u -r1.1.2.1 sysctl_net_ipv4.c
> --- sysctl_net_ipv4.c 1999/01/18 01:34:50 1.1.2.1
> +++ linux/net/ipv4/sysctl_net_ipv4.c 1999/02/25 14:58:19
> @@ -48,6 +48,7 @@
> extern int sysctl_tcp_window_scaling;
> extern int sysctl_tcp_sack;
> extern int sysctl_tcp_retrans_collapse;
> +extern int sysctl_tcp_solaris_fin_bug_4083814_workaround;
> extern int sysctl_tcp_keepalive_time;
> extern int sysctl_tcp_keepalive_probes;
> extern int sysctl_tcp_max_ka_probes;
> @@ -107,6 +108,10 @@
> {NET_IPV4_TCP_RETRANS_COLLAPSE, "tcp_retrans_collapse",
> &sysctl_tcp_retrans_collapse, sizeof(int), 0644, NULL,
> &proc_dointvec},
> + {NET_IPV4_TCP_SOLARIS_FIN_BUG_4083814_WORKAROUND,
> + "tcp_solaris_fin_bug_4083814_workaround",
> + &sysctl_tcp_solaris_fin_bug_4083814_workaround, sizeof(int), 0644,
> + NULL, &proc_dointvec},
> {NET_IPV4_FORWARD, "ip_forward",
> &ipv4_devconf.forwarding, sizeof(int), 0644, NULL,
> &ipv4_sysctl_forward},
> Index: net/ipv4/tcp_output.c
> ===================================================================
> RCS file: /var/cvs/linux/net/ipv4/tcp_output.c,v
> retrieving revision 1.1.2.6
> diff -u -r1.1.2.6 tcp_output.c
> --- tcp_output.c 1999/02/23 17:08:43 1.1.2.6
> +++ linux/net/ipv4/tcp_output.c 1999/02/25 17:11:18
> @@ -31,6 +31,7 @@
> * during syn/ack processing.
> * David S. Miller : Output engine completely rewritten.
> * Andrea Arcangeli: SYNACK carry ts_recent in tsecr.
> + * Andrea Arcangeli: solaris_fin_bug_4083814_workaround.
> *
> */
>
> @@ -42,6 +43,17 @@
>
> /* People can turn this off for buggy TCP's found in printers etc. */
> int sysctl_tcp_retrans_collapse = 1;
> +/*
> + * People can turn this on to avoid Solaris 2.5.1 and 2.6 TCP stacks to stall
> + * upon connection termination. NOTE: you should really apply Solaris 2.6 105529
> + * patch from Sun on the client side instead of enable this sysctl on the
> + * Linux server side! This is _only_ intended as last resort and will disappear
> + * shortly beacuse if enabled doesn't allow the Linux TCP stack to be
> + * clever in decresing the network traffic while sending the FIN from the
> + * FIN_WAIT1 state.
> + * -arca
> + */
> +int sysctl_tcp_solaris_fin_bug_4083814_workaround = 0;
>
> /* Get rid of any delayed acks, we sent one already.. */
> static __inline__ void clear_delayed_acks(struct sock * sk)
> @@ -693,7 +705,8 @@
> */
> mss_now = tcp_current_mss(sk);
>
> - if((tp->send_head != NULL) && (skb->len < mss_now)) {
> + if((tp->send_head != NULL) && (skb->len < mss_now) &&
> + !sysctl_tcp_solaris_fin_bug_4083814_workaround) {
> /* tcp_write_xmit() takes care of the rest. */
> TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_FIN;
> TCP_SKB_CB(skb)->end_seq++;
>
> Just to avoid confusion I repeat: this is a silly Solaris bug and not a
> Linux bug.
>
> Andrea Arcangeli
>
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.rutgers.edu
> Please read the FAQ at http://www.tux.org/lkml/

--
Philip Gladstone +1 781 530 2461
Axent Technologies, Waltham, MA[unhandled content-type:application/x-pkcs7-signature]
\
 
 \ /
  Last update: 2005-03-22 13:50    [W:0.042 / U:0.596 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site