Receiver side DSACK implemenation.
This adds initial support for RFC 2883. Submitted by: Richard Scheffenegger Reviewed by: rrs@ Differential Revision: https://reviews.freebsd.org/D19334
This commit is contained in:
parent
274fb26176
commit
4730cb344f
@ -2258,6 +2258,17 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
|
||||
TCPSTAT_INC(tcps_rcvpartduppack);
|
||||
TCPSTAT_ADD(tcps_rcvpartdupbyte, todrop);
|
||||
}
|
||||
/*
|
||||
* DSACK - add SACK block for dropped range
|
||||
*/
|
||||
if (tp->t_flags & TF_SACK_PERMIT) {
|
||||
tcp_update_sack_list(tp, th->th_seq, th->th_seq+tlen);
|
||||
/*
|
||||
* ACK now, as the next in-sequence segment
|
||||
* will clear the DSACK block again
|
||||
*/
|
||||
tp->t_flags |= TF_ACKNOW;
|
||||
}
|
||||
drop_hdrlen += todrop; /* drop from the top afterwards */
|
||||
th->th_seq += todrop;
|
||||
tlen -= todrop;
|
||||
@ -2986,6 +2997,8 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
|
||||
if ((tlen || (thflags & TH_FIN) || tfo_syn) &&
|
||||
TCPS_HAVERCVDFIN(tp->t_state) == 0) {
|
||||
tcp_seq save_start = th->th_seq;
|
||||
tcp_seq save_rnxt = tp->rcv_nxt;
|
||||
int save_tlen = tlen;
|
||||
m_adj(m, drop_hdrlen); /* delayed header drop */
|
||||
/*
|
||||
* Insert segment which includes th into TCP reassembly queue
|
||||
@ -3025,11 +3038,28 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
|
||||
* m_adj() doesn't actually frees any mbufs
|
||||
* when trimming from the head.
|
||||
*/
|
||||
thflags = tcp_reass(tp, th, &save_start, &tlen, m);
|
||||
tcp_seq temp = save_start;
|
||||
thflags = tcp_reass(tp, th, &temp, &tlen, m);
|
||||
tp->t_flags |= TF_ACKNOW;
|
||||
}
|
||||
if (tlen > 0 && (tp->t_flags & TF_SACK_PERMIT))
|
||||
tcp_update_sack_list(tp, save_start, save_start + tlen);
|
||||
if (tp->t_flags & TF_SACK_PERMIT) {
|
||||
if (((tlen == 0) && (save_tlen > 0) &&
|
||||
(SEQ_LT(save_start, save_rnxt)))) {
|
||||
// DSACK actually handled in the fastpath above
|
||||
tcp_update_sack_list(tp, save_start, save_start + save_tlen);
|
||||
} else
|
||||
if ((tlen > 0) && SEQ_GT(tp->rcv_nxt, save_rnxt)) {
|
||||
// cleaning sackblks by using zero length update
|
||||
tcp_update_sack_list(tp, save_start, save_start);
|
||||
} else
|
||||
if ((tlen > 0) && (tlen >= save_tlen)) {
|
||||
// update of sackblks
|
||||
tcp_update_sack_list(tp, save_start, save_start + save_tlen);
|
||||
} else
|
||||
if (tlen > 0) {
|
||||
tcp_update_sack_list(tp, save_start, save_start+tlen);
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
/*
|
||||
* Note the amount of data that peer has sent into
|
||||
|
@ -168,7 +168,7 @@ tcp_update_sack_list(struct tcpcb *tp, tcp_seq rcv_start, tcp_seq rcv_end)
|
||||
INP_WLOCK_ASSERT(tp->t_inpcb);
|
||||
|
||||
/* Check arguments. */
|
||||
KASSERT(SEQ_LT(rcv_start, rcv_end), ("rcv_start < rcv_end"));
|
||||
KASSERT(SEQ_LEQ(rcv_start, rcv_end), ("rcv_start <= rcv_end"));
|
||||
|
||||
/* SACK block for the received segment. */
|
||||
head_blk.start = rcv_start;
|
||||
@ -193,11 +193,53 @@ tcp_update_sack_list(struct tcpcb *tp, tcp_seq rcv_start, tcp_seq rcv_end)
|
||||
* Merge this SACK block into head_blk. This SACK
|
||||
* block itself will be discarded.
|
||||
*/
|
||||
if (SEQ_GT(head_blk.start, start))
|
||||
/*
|
||||
* |-|
|
||||
* |---| merge
|
||||
*
|
||||
* |-|
|
||||
* |---| merge
|
||||
*
|
||||
* |-----|
|
||||
* |-| DSACK smaller
|
||||
*
|
||||
* |-|
|
||||
* |-----| DSACK smaller
|
||||
*/
|
||||
if (head_blk.start == end)
|
||||
head_blk.start = start;
|
||||
if (SEQ_LT(head_blk.end, end))
|
||||
else if (head_blk.end == start)
|
||||
head_blk.end = end;
|
||||
else {
|
||||
if (SEQ_LT(head_blk.start, start)) {
|
||||
tcp_seq temp = start;
|
||||
start = head_blk.start;
|
||||
head_blk.start = temp;
|
||||
}
|
||||
if (SEQ_GT(head_blk.end, end)) {
|
||||
tcp_seq temp = end;
|
||||
end = head_blk.end;
|
||||
head_blk.end = temp;
|
||||
}
|
||||
if ((head_blk.start != start) ||
|
||||
(head_blk.end != end)) {
|
||||
if ((num_saved >= 1) &&
|
||||
SEQ_GEQ(saved_blks[num_saved-1].start, start) &&
|
||||
SEQ_LEQ(saved_blks[num_saved-1].end, end))
|
||||
num_saved--;
|
||||
saved_blks[num_saved].start = start;
|
||||
saved_blks[num_saved].end = end;
|
||||
num_saved++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* This block supercedes the prior block
|
||||
*/
|
||||
if ((num_saved >= 1) &&
|
||||
SEQ_GEQ(saved_blks[num_saved-1].start, start) &&
|
||||
SEQ_LEQ(saved_blks[num_saved-1].end, end))
|
||||
num_saved--;
|
||||
/*
|
||||
* Save this SACK block.
|
||||
*/
|
||||
@ -211,7 +253,7 @@ tcp_update_sack_list(struct tcpcb *tp, tcp_seq rcv_start, tcp_seq rcv_end)
|
||||
* Update SACK list in tp->sackblks[].
|
||||
*/
|
||||
num_head = 0;
|
||||
if (SEQ_GT(head_blk.start, tp->rcv_nxt)) {
|
||||
if (SEQ_LT(rcv_start, rcv_end)) {
|
||||
/*
|
||||
* The received data segment is an out-of-order segment. Put
|
||||
* head_blk at the top of SACK list.
|
||||
|
Loading…
Reference in New Issue
Block a user