Clean up delayed acks and T/TCP interactions:
- delay acks for T/TCP regardless of delack setting - fix bug where a single pass through tcp_input might not delay acks - use callout_active() instead of callout_pending() Sponsored by: DARPA, NAI Labs
This commit is contained in:
parent
ec20bdf897
commit
3bfd6421c2
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=111139
@ -153,14 +153,16 @@ do { \
|
||||
|
||||
/*
|
||||
* Indicate whether this ack should be delayed. We can delay the ack if
|
||||
* - delayed acks are enabled and
|
||||
* - there is no delayed ack timer in progress and
|
||||
* - our last ack wasn't a 0-sized window. We never want to delay
|
||||
* the ack that opens up a 0-sized window.
|
||||
* the ack that opens up a 0-sized window and
|
||||
* - delayed acks are enabled or
|
||||
* - this is a half-synchronized T/TCP connection.
|
||||
*/
|
||||
#define DELAY_ACK(tp) \
|
||||
(tcp_delack_enabled && !callout_pending(tp->tt_delack) && \
|
||||
(tp->t_flags & TF_RXWIN0SENT) == 0)
|
||||
#define DELAY_ACK(tp) \
|
||||
(((!callout_active(tp->tt_delack) && \
|
||||
(tp->t_flags & TF_RXWIN0SENT) == 0)) && \
|
||||
(tcp_delack_enabled || (tp->t_flags & TF_NEEDSYN)))
|
||||
|
||||
static int
|
||||
tcp_reass(tp, th, tlenp, m)
|
||||
@ -505,7 +507,7 @@ tcp_input(m, off0)
|
||||
th->th_urp = ntohs(th->th_urp);
|
||||
|
||||
/*
|
||||
* Delay droping TCP, IP headers, IPv6 ext headers, and TCP options,
|
||||
* Delay dropping TCP, IP headers, IPv6 ext headers, and TCP options,
|
||||
* until after ip6_savecontrol() is called and before other functions
|
||||
* which don't want those proto headers.
|
||||
* Because ip6_savecontrol() is going to parse the mbuf to
|
||||
@ -862,23 +864,16 @@ tcp_input(m, off0)
|
||||
tp->t_state = TCPS_ESTABLISHED;
|
||||
|
||||
/*
|
||||
* If there is a FIN, or if there is data and the
|
||||
* connection is local, then delay SYN,ACK(SYN) in
|
||||
* the hope of piggy-backing it on a response
|
||||
* segment. Otherwise must send ACK now in case
|
||||
* the other side is slow starting.
|
||||
* T/TCP logic:
|
||||
* If there is a FIN or if there is data, then
|
||||
* delay SYN,ACK(SYN) in the hope of piggy-backing
|
||||
* it on a response segment. Otherwise must send
|
||||
* ACK now in case the other side is slow starting.
|
||||
*/
|
||||
if (DELAY_ACK(tp) &&
|
||||
((thflags & TH_FIN) ||
|
||||
(tlen != 0 &&
|
||||
((isipv6 && in6_localaddr(&inp->in6p_faddr)) ||
|
||||
(!isipv6 && in_localaddr(inp->inp_faddr)))))) {
|
||||
callout_reset(tp->tt_delack, tcp_delacktime,
|
||||
tcp_timer_delack, tp);
|
||||
tp->t_flags |= TF_NEEDSYN;
|
||||
} else
|
||||
if (thflags & TH_FIN || tlen != 0)
|
||||
tp->t_flags |= (TF_DELACK | TF_NEEDSYN);
|
||||
else
|
||||
tp->t_flags |= (TF_ACKNOW | TF_NEEDSYN);
|
||||
|
||||
tcpstat.tcps_connects++;
|
||||
soisconnected(so);
|
||||
goto trimthenstep6;
|
||||
@ -1089,8 +1084,7 @@ tcp_input(m, off0)
|
||||
}
|
||||
sorwakeup(so);
|
||||
if (DELAY_ACK(tp)) {
|
||||
callout_reset(tp->tt_delack, tcp_delacktime,
|
||||
tcp_timer_delack, tp);
|
||||
tp->t_flags |= TF_DELACK;
|
||||
} else {
|
||||
tp->t_flags |= TF_ACKNOW;
|
||||
tcp_output(tp);
|
||||
@ -2099,8 +2093,7 @@ tcp_input(m, off0)
|
||||
LIST_EMPTY(&tp->t_segq) &&
|
||||
TCPS_HAVEESTABLISHED(tp->t_state)) {
|
||||
if (DELAY_ACK(tp))
|
||||
callout_reset(tp->tt_delack, tcp_delacktime,
|
||||
tcp_timer_delack, tp);
|
||||
tp->t_flags |= TF_DELACK;
|
||||
else
|
||||
tp->t_flags |= TF_ACKNOW;
|
||||
tp->rcv_nxt += tlen;
|
||||
@ -2143,9 +2136,8 @@ tcp_input(m, off0)
|
||||
* Otherwise, since we received a FIN then no
|
||||
* more input can be expected, send ACK now.
|
||||
*/
|
||||
if (DELAY_ACK(tp) && (tp->t_flags & TF_NEEDSYN))
|
||||
callout_reset(tp->tt_delack, tcp_delacktime,
|
||||
tcp_timer_delack, tp);
|
||||
if (tp->t_flags & TF_NEEDSYN)
|
||||
tp->t_flags |= TF_DELACK;
|
||||
else
|
||||
tp->t_flags |= TF_ACKNOW;
|
||||
tp->rcv_nxt++;
|
||||
@ -2214,6 +2206,13 @@ tcp_input(m, off0)
|
||||
*/
|
||||
if (needoutput || (tp->t_flags & TF_ACKNOW))
|
||||
(void) tcp_output(tp);
|
||||
else if (tp->t_flags & TF_DELACK) {
|
||||
tp->t_flags &= ~TF_DELACK;
|
||||
KASSERT(!callout_active(tp->tt_delack),
|
||||
("delayed ack already active"));
|
||||
callout_reset(tp->tt_delack, tcp_delacktime,
|
||||
tcp_timer_delack, tp);
|
||||
}
|
||||
INP_UNLOCK(inp);
|
||||
return;
|
||||
|
||||
|
@ -339,8 +339,9 @@ tcp_output(struct tcpcb *tp)
|
||||
* next expected input). If the difference is at least two
|
||||
* max size segments, or at least 50% of the maximum possible
|
||||
* window, then want to send a window update to peer.
|
||||
* Skip this if the connection is in T/TCP half-open state.
|
||||
*/
|
||||
if (win > 0) {
|
||||
if (win > 0 && !(tp->t_flags & TF_NEEDSYN)) {
|
||||
/*
|
||||
* "adv" is the amount we can increase the window,
|
||||
* taking into account that we are limited by
|
||||
@ -965,8 +966,8 @@ tcp_output(struct tcpcb *tp)
|
||||
if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv))
|
||||
tp->rcv_adv = tp->rcv_nxt + win;
|
||||
tp->last_ack_sent = tp->rcv_nxt;
|
||||
tp->t_flags &= ~TF_ACKNOW;
|
||||
if (tcp_delack_enabled)
|
||||
tp->t_flags &= ~(TF_ACKNOW | TF_DELACK);
|
||||
if (callout_active(tp->tt_delack))
|
||||
callout_stop(tp->tt_delack);
|
||||
#if 0
|
||||
/*
|
||||
|
@ -153,14 +153,16 @@ do { \
|
||||
|
||||
/*
|
||||
* Indicate whether this ack should be delayed. We can delay the ack if
|
||||
* - delayed acks are enabled and
|
||||
* - there is no delayed ack timer in progress and
|
||||
* - our last ack wasn't a 0-sized window. We never want to delay
|
||||
* the ack that opens up a 0-sized window.
|
||||
* the ack that opens up a 0-sized window and
|
||||
* - delayed acks are enabled or
|
||||
* - this is a half-synchronized T/TCP connection.
|
||||
*/
|
||||
#define DELAY_ACK(tp) \
|
||||
(tcp_delack_enabled && !callout_pending(tp->tt_delack) && \
|
||||
(tp->t_flags & TF_RXWIN0SENT) == 0)
|
||||
#define DELAY_ACK(tp) \
|
||||
(((!callout_active(tp->tt_delack) && \
|
||||
(tp->t_flags & TF_RXWIN0SENT) == 0)) && \
|
||||
(tcp_delack_enabled || (tp->t_flags & TF_NEEDSYN)))
|
||||
|
||||
static int
|
||||
tcp_reass(tp, th, tlenp, m)
|
||||
@ -505,7 +507,7 @@ tcp_input(m, off0)
|
||||
th->th_urp = ntohs(th->th_urp);
|
||||
|
||||
/*
|
||||
* Delay droping TCP, IP headers, IPv6 ext headers, and TCP options,
|
||||
* Delay dropping TCP, IP headers, IPv6 ext headers, and TCP options,
|
||||
* until after ip6_savecontrol() is called and before other functions
|
||||
* which don't want those proto headers.
|
||||
* Because ip6_savecontrol() is going to parse the mbuf to
|
||||
@ -862,23 +864,16 @@ tcp_input(m, off0)
|
||||
tp->t_state = TCPS_ESTABLISHED;
|
||||
|
||||
/*
|
||||
* If there is a FIN, or if there is data and the
|
||||
* connection is local, then delay SYN,ACK(SYN) in
|
||||
* the hope of piggy-backing it on a response
|
||||
* segment. Otherwise must send ACK now in case
|
||||
* the other side is slow starting.
|
||||
* T/TCP logic:
|
||||
* If there is a FIN or if there is data, then
|
||||
* delay SYN,ACK(SYN) in the hope of piggy-backing
|
||||
* it on a response segment. Otherwise must send
|
||||
* ACK now in case the other side is slow starting.
|
||||
*/
|
||||
if (DELAY_ACK(tp) &&
|
||||
((thflags & TH_FIN) ||
|
||||
(tlen != 0 &&
|
||||
((isipv6 && in6_localaddr(&inp->in6p_faddr)) ||
|
||||
(!isipv6 && in_localaddr(inp->inp_faddr)))))) {
|
||||
callout_reset(tp->tt_delack, tcp_delacktime,
|
||||
tcp_timer_delack, tp);
|
||||
tp->t_flags |= TF_NEEDSYN;
|
||||
} else
|
||||
if (thflags & TH_FIN || tlen != 0)
|
||||
tp->t_flags |= (TF_DELACK | TF_NEEDSYN);
|
||||
else
|
||||
tp->t_flags |= (TF_ACKNOW | TF_NEEDSYN);
|
||||
|
||||
tcpstat.tcps_connects++;
|
||||
soisconnected(so);
|
||||
goto trimthenstep6;
|
||||
@ -1089,8 +1084,7 @@ tcp_input(m, off0)
|
||||
}
|
||||
sorwakeup(so);
|
||||
if (DELAY_ACK(tp)) {
|
||||
callout_reset(tp->tt_delack, tcp_delacktime,
|
||||
tcp_timer_delack, tp);
|
||||
tp->t_flags |= TF_DELACK;
|
||||
} else {
|
||||
tp->t_flags |= TF_ACKNOW;
|
||||
tcp_output(tp);
|
||||
@ -2099,8 +2093,7 @@ tcp_input(m, off0)
|
||||
LIST_EMPTY(&tp->t_segq) &&
|
||||
TCPS_HAVEESTABLISHED(tp->t_state)) {
|
||||
if (DELAY_ACK(tp))
|
||||
callout_reset(tp->tt_delack, tcp_delacktime,
|
||||
tcp_timer_delack, tp);
|
||||
tp->t_flags |= TF_DELACK;
|
||||
else
|
||||
tp->t_flags |= TF_ACKNOW;
|
||||
tp->rcv_nxt += tlen;
|
||||
@ -2143,9 +2136,8 @@ tcp_input(m, off0)
|
||||
* Otherwise, since we received a FIN then no
|
||||
* more input can be expected, send ACK now.
|
||||
*/
|
||||
if (DELAY_ACK(tp) && (tp->t_flags & TF_NEEDSYN))
|
||||
callout_reset(tp->tt_delack, tcp_delacktime,
|
||||
tcp_timer_delack, tp);
|
||||
if (tp->t_flags & TF_NEEDSYN)
|
||||
tp->t_flags |= TF_DELACK;
|
||||
else
|
||||
tp->t_flags |= TF_ACKNOW;
|
||||
tp->rcv_nxt++;
|
||||
@ -2214,6 +2206,13 @@ tcp_input(m, off0)
|
||||
*/
|
||||
if (needoutput || (tp->t_flags & TF_ACKNOW))
|
||||
(void) tcp_output(tp);
|
||||
else if (tp->t_flags & TF_DELACK) {
|
||||
tp->t_flags &= ~TF_DELACK;
|
||||
KASSERT(!callout_active(tp->tt_delack),
|
||||
("delayed ack already active"));
|
||||
callout_reset(tp->tt_delack, tcp_delacktime,
|
||||
tcp_timer_delack, tp);
|
||||
}
|
||||
INP_UNLOCK(inp);
|
||||
return;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user