Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/tcp_input.c
Show First 20 Lines • Show All 2,461 Lines • ▼ Show 20 Lines | #endif | ||||
case TCPS_CLOSING: | case TCPS_CLOSING: | ||||
case TCPS_LAST_ACK: | case TCPS_LAST_ACK: | ||||
if (SEQ_GT(th->th_ack, tp->snd_max)) { | if (SEQ_GT(th->th_ack, tp->snd_max)) { | ||||
TCPSTAT_INC(tcps_rcvacktoomuch); | TCPSTAT_INC(tcps_rcvacktoomuch); | ||||
goto dropafterack; | goto dropafterack; | ||||
} | } | ||||
if ((tp->t_flags & TF_SACK_PERMIT) && | if ((tp->t_flags & TF_SACK_PERMIT) && | ||||
((to.to_flags & TOF_SACK) || | ((to.to_flags & TOF_SACK) || | ||||
!TAILQ_EMPTY(&tp->snd_holes))) | !TAILQ_EMPTY(&tp->snd_holes))) { | ||||
sack_changed = tcp_sack_doack(tp, &to, th->th_ack); | sack_changed = tcp_sack_doack(tp, &to, th->th_ack); | ||||
else | LOGTCPCBSTATE; | ||||
if (TAILQ_EMPTY(&tp->snd_holes) && | |||||
!(to.to_flags & TOF_SACK) && | |||||
((tp->snd_max - th->th_ack) == sbavail(&so->so_snd)) && | |||||
SEQ_LT(th->th_ack, tp->snd_recover)) { | |||||
if (so->so_options & SO_DEBUG) | |||||
log(LOG_DEBUG,"rfc6675 rescue retransmission\n"); | |||||
} | |||||
} else { | |||||
/* | /* | ||||
* Reset the value so that previous (valid) value | * Reset the value so that previous (valid) value | ||||
* from the last ack with SACK doesn't get used. | * from the last ack with SACK doesn't get used. | ||||
*/ | */ | ||||
tp->sackhint.sacked_bytes = 0; | tp->sackhint.sacked_bytes = 0; | ||||
tp->sackhint.sacked_bytes_old = 0; | |||||
LOGTCPCBSTATE; | |||||
} | |||||
#ifdef TCP_HHOOK | #ifdef TCP_HHOOK | ||||
/* Run HHOOK_TCP_ESTABLISHED_IN helper hooks. */ | /* Run HHOOK_TCP_ESTABLISHED_IN helper hooks. */ | ||||
hhook_run_tcp_est_in(tp, th, &to); | hhook_run_tcp_est_in(tp, th, &to); | ||||
#endif | #endif | ||||
if (SEQ_LEQ(th->th_ack, tp->snd_una)) { | if (SEQ_LEQ(th->th_ack, tp->snd_una)) { | ||||
u_int maxseg; | u_int maxseg; | ||||
Show All 26 Lines | if (SEQ_LEQ(th->th_ack, tp->snd_una)) { | ||||
* Kludge snd_nxt & the congestion | * Kludge snd_nxt & the congestion | ||||
* window so we send only this one | * window so we send only this one | ||||
* packet. | * packet. | ||||
* | * | ||||
* We know we're losing at the current | * We know we're losing at the current | ||||
* window size so do congestion avoidance | * window size so do congestion avoidance | ||||
* (set ssthresh to half the current window | * (set ssthresh to half the current window | ||||
* and pull our congestion window back to | * and pull our congestion window back to | ||||
* the new ssthresh). | * the new ssthresh09). | ||||
* | * | ||||
* Dup acks mean that packets have left the | * Dup acks mean that packets have left the | ||||
* network (they're now cached at the receiver) | * network (they're now cached at the receiver) | ||||
* so bump cwnd by the amount in the receiver | * so bump cwnd by the amount in the receiver | ||||
* to keep a constant cwnd packets in the | * to keep a constant cwnd packets in the | ||||
* network. | * network. | ||||
* | * | ||||
* When using TCP ECN, notify the peer that | * When using TCP ECN, notify the peer that | ||||
* we reduced the cwnd. | * we reduced the cwnd. | ||||
*/ | */ | ||||
/* | /* | ||||
* Following 2 kinds of acks should not affect | * Following 2 kinds of acks should not affect | ||||
* dupack counting: | * dupack counting: | ||||
* 1) Old acks | * 1) Old acks | ||||
* 2) Acks with SACK but without any new SACK | * 2) Acks with SACK but without any new SACK | ||||
* information in them. These could result from | * information in them. These could result from | ||||
* any anomaly in the network like a switch | * any anomaly in the network like a switch | ||||
* duplicating packets or a possible DoS attack. | * duplicating packets or a possible DoS attack. | ||||
*/ | */ | ||||
if (th->th_ack != tp->snd_una || | if (th->th_ack != tp->snd_una || | ||||
((tp->t_flags & TF_SACK_PERMIT) && | ((tp->t_flags & TF_SACK_PERMIT) && | ||||
!sack_changed)) | !sack_changed)) { | ||||
// log(LOG_DEBUG,"tcp_input:2569 falling through here %u\n", tp->snd_fack); | |||||
// if (SEQ_LT(th->th_ack, tp->snd_recover) && | |||||
// (tp->t_flags & TF_SACK_PERMIT) && | |||||
// TAILQ_EMPTY(&tp->snd_holes) && | |||||
// ((tp->snd_max - tp->snd_una) == sbavail(&so->so_snd))) { | |||||
// log(LOG_DEBUG,"adding hole for rescue rexmit\n"); | |||||
// tcp_sackhole_insert(tp, tp->snd_una, tp->snd_max, NULL); | |||||
// } | |||||
break; | break; | ||||
else if (!tcp_timer_active(tp, TT_REXMT)) | } else if (!tcp_timer_active(tp, TT_REXMT)) | ||||
tp->t_dupacks = 0; | tp->t_dupacks = 0; | ||||
else if (++tp->t_dupacks > tcprexmtthresh || | else if (++tp->t_dupacks > tcprexmtthresh || | ||||
IN_FASTRECOVERY(tp->t_flags)) { | IN_FASTRECOVERY(tp->t_flags)) { | ||||
cc_ack_received(tp, th, nsegs, | cc_ack_received(tp, th, nsegs, | ||||
CC_DUPACK); | CC_DUPACK); | ||||
if ((tp->t_flags & TF_SACK_PERMIT) && | if ((tp->t_flags & TF_SACK_PERMIT) && | ||||
IN_FASTRECOVERY(tp->t_flags)) { | IN_FASTRECOVERY(tp->t_flags)) { | ||||
int awnd; | int awnd; | ||||
Show All 12 Lines | // } | ||||
if (awnd < tp->snd_ssthresh) { | if (awnd < tp->snd_ssthresh) { | ||||
tp->snd_cwnd += maxseg; | tp->snd_cwnd += maxseg; | ||||
if (tp->snd_cwnd > tp->snd_ssthresh) | if (tp->snd_cwnd > tp->snd_ssthresh) | ||||
tp->snd_cwnd = tp->snd_ssthresh; | tp->snd_cwnd = tp->snd_ssthresh; | ||||
} | } | ||||
} else | } else | ||||
tp->snd_cwnd += maxseg; | tp->snd_cwnd += maxseg; | ||||
(void) tp->t_fb->tfb_tcp_output(tp); | (void) tp->t_fb->tfb_tcp_output(tp); | ||||
goto drop; | goto drop; | ||||
} else if (tp->t_dupacks == tcprexmtthresh) { | } else if ((tp->t_dupacks == tcprexmtthresh) || | ||||
/* | |||||
* Add RFC6675 trigger condition of more | |||||
* than (dupthresh-1)*mss sacked data. | |||||
* If the count of holes in the | |||||
* scoreboard is >= dupthresh, we could | |||||
* also enter loss recovery, but don't | |||||
* have that value readily available. | |||||
*/ | |||||
((tp->t_flags & TF_SACK_PERMIT) && | |||||
(V_tcp_do_rfc6675_pipe) && | |||||
(tp->sackhint.sacked_bytes > | |||||
(tcprexmtthresh - 1) * maxseg))) { | |||||
tp->t_dupacks = tcprexmtthresh; | |||||
tcp_seq onxt = tp->snd_nxt; | tcp_seq onxt = tp->snd_nxt; | ||||
/* | /* | ||||
* If we're doing sack, check to | * If we're doing sack, check to | ||||
* see if we're already in sack | * see if we're already in sack | ||||
* recovery. If we're not doing sack, | * recovery. If we're not doing sack, | ||||
* check to see if we're in newreno | * check to see if we're in newreno | ||||
* recovery. | * recovery. | ||||
▲ Show 20 Lines • Show All 96 Lines • ▼ Show 20 Lines | // } | ||||
* This ack is advancing the left edge, reset the | * This ack is advancing the left edge, reset the | ||||
* counter. | * counter. | ||||
*/ | */ | ||||
tp->t_dupacks = 0; | tp->t_dupacks = 0; | ||||
/* | /* | ||||
* If this ack also has new SACK info, increment the | * If this ack also has new SACK info, increment the | ||||
* counter as per rfc6675. | * counter as per rfc6675. | ||||
*/ | */ | ||||
if ((tp->t_flags & TF_SACK_PERMIT) && sack_changed) | if ((tp->t_flags & TF_SACK_PERMIT) && sack_changed) { | ||||
tp->t_dupacks++; | tp->t_dupacks++; | ||||
rscheff: Add comment why this additional check for presence of a SACK block has been added (semantic of… | |||||
} | |||||
LOGTCPCBSTATE; | |||||
} | } | ||||
KASSERT(SEQ_GT(th->th_ack, tp->snd_una), | KASSERT(SEQ_GT(th->th_ack, tp->snd_una), | ||||
("%s: th_ack <= snd_una", __func__)); | ("%s: th_ack <= snd_una", __func__)); | ||||
/* | /* | ||||
* If the congestion window was inflated to account | * If the congestion window was inflated to account | ||||
* for the other side's cached packets, retract it. | * for the other side's cached packets, retract it. | ||||
▲ Show 20 Lines • Show All 1,122 Lines • Show Last 20 Lines |
Add comment why this additional check for presence of a SACK block has been added (semantic of variable sack_changed now tracks scoreboard changes due to partial ACKs (without SACK blocks) too, but these should be excluded from increasing the dupthesh counter.