Re: tcp_usrreq bug ??

2002-12-05 Thread Mike Silbersack

On Tue, 3 Dec 2002, Aniruddha Bohra wrote:

> Hello
> The following code snippet is from netinet/tcp_usrreq.c
>
> As in the comment (and presumably correct behaviour) a RST should
> be sent on close if the connection is embryonic. However,
> if (tp->t_state < TCPS_ESTABLISHED)
> tp = tcp_close(tp);
> does not do it.  One can imagine a scenario when a client would just
> do a connect() and close() and an overloaded server would have its
> listen queue crowded by connections that were not synchronized but closed.
>
> I have seen this happen in my lab test, where I use httperf  to measure
> Apache
> webserver throughput. There are several listen queue overflows and resets.
> The interesting part is that the client _NEVER_ has more than 3200 open
> descriptors
> yet a queue of 4096 on the server gets filled up.
>
> Is there a reason for not sending a RST or is it a bug? Please help.
>
> Thanks
> Aniruddha

I took a quick look, and I agree that the comment doesn't seem to match
reality.  Looking back, it appears that the code/comment have been exactly
the same since FreeBSD 2, back in 1994.  Note that I haven't actually
doublechecked this with tcpdump, so my comments are based off of what you
stated...

There are two sides to examine this problem from:  The server side, and
the client side.

Server side:

Getting flooded with SYN packets is an unfortunate reality that all OSes
must deal with these days.  Even if you're using a pre-syncache version of
FreeBSD, you shouldn't be seeing too many problems due to listen queue
overflows.  If performance is terrible, you may consider moving to FreeBSD
4.7, or doing further examination to determine if listen queue overflows
are really hurting you.

Client side:

#1 - Why is your benchmark program terminating connections before they
finish connecting?

#2 - I've been thinking about how FreBSD should handle the situation where
a connection is closed before it has become established, and I think that
silently dropping the connection is best.  Here's why:

Normal usage, single connection closed like this:
Client receives syn-ack packet, responds with reset.  Had a reset
been preemptively sent, it would have crossed with the syn-ack on
the wire, and two syn-acks would be sent.  Either way, the
connection gets reset.

Flooded server, single connection closed:
Same as above; preemptive reset wastes bandwidth.

Client used to perform a synflood:
Again, same as above.  If a reset was sent, you'd double the PPS
the server was flooded with.  That being said, I don't think that
a connect/close pair would be used for a synflood.  Such a flood
would be easily blockable and tracable with extreme ease.  Note
that FreeBSD's rst rate limiting would limit the number of
connections / second that would be reset, but the server's
built-in anti-syn flood countermeasures should do fine.

Hence, I'm not sure that we can do anything better than what we are doing
now.  Once the 5.0 codefreeze is over, I'll go in and take out the
misleading comment.

Mike "Silby" Silbersack

To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-hackers" in the body of the message



tcp_usrreq bug ??

2002-12-03 Thread Aniruddha Bohra
Hello
   The following code snippet is from netinet/tcp_usrreq.c

As in the comment (and presumably correct behaviour) a RST should
be sent on close if the connection is embryonic. However,
if (tp->t_state < TCPS_ESTABLISHED)
   tp = tcp_close(tp);
does not do it.  One can imagine a scenario when a client would just
do a connect() and close() and an overloaded server would have its
listen queue crowded by connections that were not synchronized but closed.

I have seen this happen in my lab test, where I use httperf  to measure 
Apache
webserver throughput. There are several listen queue overflows and resets.
The interesting part is that the client _NEVER_ has more than 3200 open 
descriptors
yet a queue of 4096 on the server gets filled up.

Is there a reason for not sending a RST or is it a bug? Please help.

Thanks
Aniruddha


/*
* Initiate (or continue) disconnect.
* If embryonic state, just send reset (once).
* If in ``let data drain'' option and linger null, just drop.
* Otherwise (hard), mark socket disconnecting and drop
* current input data; switch states based on user close, and
* send segment to peer (with FIN).
*/
static struct tcpcb *
tcp_disconnect(tp)
register struct tcpcb *tp;
{
struct socket *so = tp->t_inpcb->inp_socket;

if (tp->t_state < TCPS_ESTABLISHED)
tp = tcp_close(tp);
else if ((so->so_options & SO_LINGER) && so->so_linger == 0)
tp = tcp_drop(tp, 0);
else {
soisdisconnecting(so);
sbflush(&so->so_rcv);
tp = tcp_usrclosed(tp);
if (tp)
(void) tcp_output(tp);
}
return (tp);
}


To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-hackers" in the body of the message