Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F142059929
D4225.id10392.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
5 KB
Referenced Files
None
Subscribers
None
D4225.id10392.diff
View Options
Index: sys/netinet/tcp_input.c
===================================================================
--- sys/netinet/tcp_input.c
+++ sys/netinet/tcp_input.c
@@ -1481,7 +1481,7 @@
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;
@@ -1501,6 +1501,7 @@
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
@@ -2424,7 +2425,7 @@
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
@@ -2436,7 +2437,9 @@
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))) {
/*
* If this is the first time we've seen a
* FIN from the remote, this is not a
@@ -2478,8 +2481,20 @@
* 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 no window change and no 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) &&
+ tiwin == tp->snd_wnd && !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)) {
@@ -2608,9 +2623,20 @@
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),
@@ -2629,7 +2655,6 @@
} 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.
Index: sys/netinet/tcp_sack.c
===================================================================
--- sys/netinet/tcp_sack.c
+++ sys/netinet/tcp_sack.c
@@ -345,17 +345,20 @@
* 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.
*/
-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.
@@ -369,6 +372,7 @@
* received new blocks from the other side.
*/
if (to->to_flags & TOF_SACK) {
+ old_sacked_bytes = tp->sackhint.sacked_bytes;
tp->sackhint.sacked_bytes = 0; /* reset */
for (i = 0; i < to->to_nsacks; i++) {
bcopy((to->to_sacks + i * TCPOLEN_SACK),
@@ -392,7 +396,7 @@
* received.
*/
if (num_sack_blks == 0)
- return;
+ return (sack_changed);
/*
* Sort the SACK blocks so we can update the scoreboard with just one
@@ -443,6 +447,7 @@
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
@@ -459,9 +464,11 @@
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"));
@@ -490,6 +497,7 @@
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)) {
@@ -545,6 +553,7 @@
else
sblkp--;
}
+ return (sack_changed);
}
/*
Index: sys/netinet/tcp_var.h
===================================================================
--- sys/netinet/tcp_var.h
+++ sys/netinet/tcp_var.h
@@ -741,7 +741,7 @@
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);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Jan 16, 3:24 PM (16 h, 4 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27661718
Default Alt Text
D4225.id10392.diff (5 KB)
Attached To
Mode
D4225: Fix dupack processing to detect loss correctly.
Attached
Detach File
Event Timeline
Log In to Comment