Messages in this thread Patch in this message | | | Date | Fri, 26 Feb 1999 11:08:18 -0500 | From | Philip Gladstone <> | Subject | Re: [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] | |