Re: TCP window updates [Was: PROBLEM: Sending mail-attachment]

Matthias Moeller (mattes@ice.robin.de)
Mon, 8 Mar 1999 17:47:36 +0100 (CET)


On Mon, 8 Mar 1999, Andrea Arcangeli wrote:

> >> + schedule_timeout(10*HZ);
> >
> >What is this timeout supposed to do exactly?
>
> It will unblock after 10 sec if not wakenup before by the reception of
> some new packet.
>
> So after 10 sec the loop restart and you'll be inside cleanup_rbuf again
> and you'll send a new ack. Dave said it's not needed though so probably I
> missed something here too.

cleanup_rbuf() only sends a new ACK if it can advertise an increased
window. It would probably be the wrong thing anyway to send an ACK all
10 seconds. Maybe the sender has no data. The sender should probe the
receivers window. Linux has TIME_PROBE0 for this. As long as the sender
has data to send this works fine. If the receivers window is too small (in
terms of SWS avoidance?) the TIMER_PROBE0 will be started.

This works as follows:

tcp_rcv_established() calls tcp_data_send_check() for an incoming ACK:

static __inline__ void tcp_data_snd_check(struct sock *sk)
{
struct sk_buff *skb = sk->tp_pinfo.af_tcp.send_head;

if (skb != NULL)
__tcp_data_snd_check(sk, skb);
}

this calls __tcp_data_snd_check() but only if we have data to send.

__tcp_data_snd_check() now puts either data on the wire or starts
the PROBE0 timer.

This all works fine until the receiver has advertised a very small
window __and__ the sender does not have any data queued in this
moment.

Any further write() calls with small write sizes on sender side will
neither put data on the wire nor start the PROBE0 timer!

I had real deadlocks because of this and the bug in cleanup_rbuf(),
the reveiver did not advertise increased windows. Okay, with Daves
fix the receiver now does that but these ACKs could be dropped by
the network.

I think this could be fixed in tcp_v4_sendmsg():

lock_sock(sk);
retval = tcp_do_sendmsg(sk, msg->msg_iovlen, msg->msg_iov,
msg->msg_flags);
/* Push out partial tail frames if needed. */
tp = &(sk->tp_pinfo.af_tcp);
if(tp->send_head && tcp_snd_test(sk, tp->send_head))
tcp_write_xmit(sk);
+ else
+ if (tp->packets_out == 0 && !tp->pending)
+ tcp_reset_xmit_timer(sk, TIME_PROBE0, tp->rto);
release_sock(sk);

out:
return retval;

Or it could be fixed in tcp_do_sendmsg() (The stuff with copied and
queue_it, queue_it is always 1 for small write() sizes. So _no_ data
will get on the wire an the PROBE0 timer will _not_ be started).

Matthias

-
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/