MFC: r292003
Improve tcp duplicate ack processing when SACK is present.
This commit is contained in:
parent
4c421d2677
commit
d2c2a54e08
@ -1448,7 +1448,7 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
|
||||
struct tcpcb *tp, int drop_hdrlen, int tlen, uint8_t iptos,
|
||||
int ti_locked)
|
||||
{
|
||||
int thflags, acked, ourfinisacked, needoutput = 0;
|
||||
int thflags, acked, ourfinisacked, needoutput = 0, sack_changed;
|
||||
int rstreason, todrop, win;
|
||||
u_long tiwin;
|
||||
char *s;
|
||||
@ -1469,6 +1469,7 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
|
||||
thflags = th->th_flags;
|
||||
inc = &tp->t_inpcb->inp_inc;
|
||||
tp->sackhint.last_sack_ack = 0;
|
||||
sack_changed = 0;
|
||||
|
||||
/*
|
||||
* If this is either a state-changing packet or current state isn't
|
||||
@ -2459,7 +2460,7 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
|
||||
if ((tp->t_flags & TF_SACK_PERMIT) &&
|
||||
((to.to_flags & TOF_SACK) ||
|
||||
!TAILQ_EMPTY(&tp->snd_holes)))
|
||||
tcp_sack_doack(tp, &to, th->th_ack);
|
||||
sack_changed = tcp_sack_doack(tp, &to, th->th_ack);
|
||||
else
|
||||
/*
|
||||
* Reset the value so that previous (valid) value
|
||||
@ -2471,7 +2472,9 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
|
||||
hhook_run_tcp_est_in(tp, th, &to);
|
||||
|
||||
if (SEQ_LEQ(th->th_ack, tp->snd_una)) {
|
||||
if (tlen == 0 && tiwin == tp->snd_wnd) {
|
||||
if (tlen == 0 &&
|
||||
(tiwin == tp->snd_wnd ||
|
||||
(tp->t_flags & TF_SACK_PERMIT))) {
|
||||
TCPSTAT_INC(tcps_rcvdupack);
|
||||
/*
|
||||
* If we have outstanding data (other than
|
||||
@ -2500,8 +2503,20 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
|
||||
* When using TCP ECN, notify the peer that
|
||||
* we reduced the cwnd.
|
||||
*/
|
||||
if (!tcp_timer_active(tp, TT_REXMT) ||
|
||||
th->th_ack != tp->snd_una)
|
||||
/*
|
||||
* Following 2 kinds of acks should not affect
|
||||
* dupack counting:
|
||||
* 1) Old acks
|
||||
* 2) Acks with SACK but without any new SACK
|
||||
* information in them. These could result from
|
||||
* any anomaly in the network like a switch
|
||||
* duplicating packets or a possible DoS attack.
|
||||
*/
|
||||
if (th->th_ack != tp->snd_una ||
|
||||
((tp->t_flags & TF_SACK_PERMIT) &&
|
||||
!sack_changed))
|
||||
break;
|
||||
else if (!tcp_timer_active(tp, TT_REXMT))
|
||||
tp->t_dupacks = 0;
|
||||
else if (++tp->t_dupacks > tcprexmtthresh ||
|
||||
IN_FASTRECOVERY(tp->t_flags)) {
|
||||
@ -2660,9 +2675,20 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
|
||||
tp->snd_cwnd = oldcwnd;
|
||||
goto drop;
|
||||
}
|
||||
} else
|
||||
tp->t_dupacks = 0;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
/*
|
||||
* This ack is advancing the left edge, reset the
|
||||
* counter.
|
||||
*/
|
||||
tp->t_dupacks = 0;
|
||||
/*
|
||||
* If this ack also has new SACK info, increment the
|
||||
* counter as per rfc6675.
|
||||
*/
|
||||
if ((tp->t_flags & TF_SACK_PERMIT) && sack_changed)
|
||||
tp->t_dupacks++;
|
||||
}
|
||||
|
||||
KASSERT(SEQ_GT(th->th_ack, tp->snd_una),
|
||||
@ -2681,7 +2707,6 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
|
||||
} else
|
||||
cc_post_recovery(tp, th);
|
||||
}
|
||||
tp->t_dupacks = 0;
|
||||
/*
|
||||
* If we reach this point, ACK is not a duplicate,
|
||||
* i.e., it ACKs something we sent.
|
||||
|
@ -344,17 +344,22 @@ tcp_sackhole_remove(struct tcpcb *tp, struct sackhole *hole)
|
||||
* Process cumulative ACK and the TCP SACK option to update the scoreboard.
|
||||
* tp->snd_holes is an ordered list of holes (oldest to newest, in terms of
|
||||
* the sequence space).
|
||||
* Returns 1 if incoming ACK has previously unknown SACK information,
|
||||
* 0 otherwise. Note: We treat (snd_una, th_ack) as a sack block so any changes
|
||||
* to that (i.e. left edge moving) would also be considered a change in SACK
|
||||
* information which is slightly different than rfc6675.
|
||||
*/
|
||||
void
|
||||
int
|
||||
tcp_sack_doack(struct tcpcb *tp, struct tcpopt *to, tcp_seq th_ack)
|
||||
{
|
||||
struct sackhole *cur, *temp;
|
||||
struct sackblk sack, sack_blocks[TCP_MAX_SACK + 1], *sblkp;
|
||||
int i, j, num_sack_blks;
|
||||
int i, j, num_sack_blks, sack_changed;
|
||||
|
||||
INP_WLOCK_ASSERT(tp->t_inpcb);
|
||||
|
||||
num_sack_blks = 0;
|
||||
sack_changed = 0;
|
||||
/*
|
||||
* If SND.UNA will be advanced by SEG.ACK, and if SACK holes exist,
|
||||
* treat [SND.UNA, SEG.ACK) as if it is a SACK block.
|
||||
@ -391,7 +396,7 @@ tcp_sack_doack(struct tcpcb *tp, struct tcpopt *to, tcp_seq th_ack)
|
||||
* received.
|
||||
*/
|
||||
if (num_sack_blks == 0)
|
||||
return;
|
||||
return (sack_changed);
|
||||
|
||||
/*
|
||||
* Sort the SACK blocks so we can update the scoreboard with just one
|
||||
@ -442,6 +447,7 @@ tcp_sack_doack(struct tcpcb *tp, struct tcpopt *to, tcp_seq th_ack)
|
||||
tp->snd_fack = sblkp->end;
|
||||
/* Go to the previous sack block. */
|
||||
sblkp--;
|
||||
sack_changed = 1;
|
||||
} else {
|
||||
/*
|
||||
* We failed to add a new hole based on the current
|
||||
@ -458,9 +464,11 @@ tcp_sack_doack(struct tcpcb *tp, struct tcpopt *to, tcp_seq th_ack)
|
||||
SEQ_LT(tp->snd_fack, sblkp->end))
|
||||
tp->snd_fack = sblkp->end;
|
||||
}
|
||||
} else if (SEQ_LT(tp->snd_fack, sblkp->end))
|
||||
} else if (SEQ_LT(tp->snd_fack, sblkp->end)) {
|
||||
/* fack is advanced. */
|
||||
tp->snd_fack = sblkp->end;
|
||||
sack_changed = 1;
|
||||
}
|
||||
/* We must have at least one SACK hole in scoreboard. */
|
||||
KASSERT(!TAILQ_EMPTY(&tp->snd_holes),
|
||||
("SACK scoreboard must not be empty"));
|
||||
@ -489,6 +497,7 @@ tcp_sack_doack(struct tcpcb *tp, struct tcpopt *to, tcp_seq th_ack)
|
||||
tp->sackhint.sack_bytes_rexmit -= (cur->rxmit - cur->start);
|
||||
KASSERT(tp->sackhint.sack_bytes_rexmit >= 0,
|
||||
("sackhint bytes rtx >= 0"));
|
||||
sack_changed = 1;
|
||||
if (SEQ_LEQ(sblkp->start, cur->start)) {
|
||||
/* Data acks at least the beginning of hole. */
|
||||
if (SEQ_GEQ(sblkp->end, cur->end)) {
|
||||
@ -544,6 +553,7 @@ tcp_sack_doack(struct tcpcb *tp, struct tcpopt *to, tcp_seq th_ack)
|
||||
else
|
||||
sblkp--;
|
||||
}
|
||||
return (sack_changed);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -756,7 +756,7 @@ void tcp_hc_update(struct in_conninfo *, struct hc_metrics_lite *);
|
||||
extern struct pr_usrreqs tcp_usrreqs;
|
||||
tcp_seq tcp_new_isn(struct tcpcb *);
|
||||
|
||||
void tcp_sack_doack(struct tcpcb *, struct tcpopt *, tcp_seq);
|
||||
int tcp_sack_doack(struct tcpcb *, struct tcpopt *, tcp_seq);
|
||||
void tcp_update_sack_list(struct tcpcb *tp, tcp_seq rcv_laststart, tcp_seq rcv_lastend);
|
||||
void tcp_clean_sackreport(struct tcpcb *tp);
|
||||
void tcp_sack_adjust(struct tcpcb *tp);
|
||||
|
Loading…
x
Reference in New Issue
Block a user