summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/netinet/tcp_sack.c113
-rw-r--r--sys/netinet/tcp_subr.c2
-rw-r--r--sys/netinet/tcp_timewait.c2
-rw-r--r--sys/netinet/tcp_var.h7
4 files changed, 44 insertions, 80 deletions
diff --git a/sys/netinet/tcp_sack.c b/sys/netinet/tcp_sack.c
index 27fa91d..4eda008 100644
--- a/sys/netinet/tcp_sack.c
+++ b/sys/netinet/tcp_sack.c
@@ -295,7 +295,7 @@ tcp_sack_option(struct tcpcb *tp, struct tcphdr *th, u_char *cp, int optlen)
{
int tmp_olen;
u_char *tmp_cp;
- struct sackhole *cur, *p, *temp;
+ struct sackhole *cur, *temp;
INP_LOCK_ASSERT(tp->t_inpcb);
if (!tp->sack_enable)
@@ -335,54 +335,47 @@ tcp_sack_option(struct tcpcb *tp, struct tcphdr *th, u_char *cp, int optlen)
}
if (SEQ_GT(sack.end, tp->snd_max))
continue;
- if (tp->snd_holes == NULL) { /* first hole */
+ if (TAILQ_EMPTY(&tp->snd_holes)) { /* first hole */
if (tcp_sack_globalholes >= tcp_sack_globalmaxholes ||
tcp_sack_maxholes == 0) {
tcpstat.tcps_sack_sboverflow++;
continue;
}
- tp->snd_holes = (struct sackhole *)
+ cur = (struct sackhole *)
uma_zalloc(sack_hole_zone,M_NOWAIT);
- if (tp->snd_holes == NULL) {
+ if (cur == NULL) {
/* ENOBUFS, so ignore SACKed block for now*/
continue;
}
- cur = tp->snd_holes;
cur->start = th->th_ack;
cur->end = sack.start;
cur->rxmit = cur->start;
- cur->next = NULL;
tp->snd_numholes = 1;
tcp_sack_globalholes++;
tp->rcv_lastsack = sack.end;
+ TAILQ_INSERT_HEAD(&tp->snd_holes, cur, scblink);
continue; /* with next sack block */
}
- /* Go thru list of holes: p = previous, cur = current */
- p = cur = tp->snd_holes;
+ /* Go thru list of holes. */
+ cur = TAILQ_FIRST(&tp->snd_holes);
while (cur) {
if (SEQ_LEQ(sack.end, cur->start))
/* SACKs data before the current hole */
break; /* no use going through more holes */
if (SEQ_GEQ(sack.start, cur->end)) {
/* SACKs data beyond the current hole */
- p = cur;
- cur = cur->next;
+ cur = TAILQ_NEXT(cur, scblink);
continue;
}
if (SEQ_LEQ(sack.start, cur->start)) {
/* Data acks at least the beginning of hole */
if (SEQ_GEQ(sack.end, cur->end)) {
/* Acks entire hole, so delete hole */
- if (p != cur) {
- p->next = cur->next;
- uma_zfree(sack_hole_zone, cur);
- cur = p->next;
- } else {
- cur = cur->next;
- uma_zfree(sack_hole_zone, p);
- p = cur;
- tp->snd_holes = p;
- }
+ temp = cur;
+ cur = TAILQ_NEXT(cur, scblink);
+ TAILQ_REMOVE(&tp->snd_holes,
+ temp, scblink);
+ uma_zfree(sack_hole_zone, temp);
tp->snd_numholes--;
tcp_sack_globalholes--;
continue;
@@ -390,16 +383,14 @@ tcp_sack_option(struct tcpcb *tp, struct tcphdr *th, u_char *cp, int optlen)
/* otherwise, move start of hole forward */
cur->start = sack.end;
cur->rxmit = SEQ_MAX(cur->rxmit, cur->start);
- p = cur;
- cur = cur->next;
+ cur = TAILQ_NEXT(cur, scblink);
continue;
}
/* move end of hole backward */
if (SEQ_GEQ(sack.end, cur->end)) {
cur->end = sack.start;
cur->rxmit = SEQ_MIN(cur->rxmit, cur->end);
- p = cur;
- cur = cur->next;
+ cur = TAILQ_NEXT(cur, scblink);
continue;
}
if (SEQ_LT(cur->start, sack.start) &&
@@ -418,25 +409,21 @@ tcp_sack_option(struct tcpcb *tp, struct tcphdr *th, u_char *cp, int optlen)
uma_zalloc(sack_hole_zone,M_NOWAIT);
if (temp == NULL)
continue; /* ENOBUFS */
- temp->next = cur->next;
temp->start = sack.end;
temp->end = cur->end;
temp->rxmit = SEQ_MAX(cur->rxmit, temp->start);
cur->end = sack.start;
cur->rxmit = SEQ_MIN(cur->rxmit, cur->end);
- cur->next = temp;
- p = temp;
- cur = p->next;
+ TAILQ_INSERT_AFTER(&tp->snd_holes,
+ cur, temp, scblink);
+ cur = TAILQ_NEXT(temp, scblink);
tp->snd_numholes++;
tcp_sack_globalholes++;
}
}
- /* At this point, p points to the last hole on the list */
+ /* At this point, we are at the tail of the scoreboard. */
if (SEQ_LT(tp->rcv_lastsack, sack.start)) {
- /*
- * Need to append new hole at end.
- * Last hole is p (and it's not NULL).
- */
+ /* Need to append new hole at end. */
if (tp->snd_numholes >= tcp_sack_maxholes ||
tcp_sack_globalholes >= tcp_sack_globalmaxholes) {
tcpstat.tcps_sack_sboverflow++;
@@ -449,11 +436,10 @@ tcp_sack_option(struct tcpcb *tp, struct tcphdr *th, u_char *cp, int optlen)
temp->start = tp->rcv_lastsack;
temp->end = sack.start;
temp->rxmit = temp->start;
- temp->next = 0;
- p->next = temp;
tp->rcv_lastsack = sack.end;
tp->snd_numholes++;
tcp_sack_globalholes++;
+ TAILQ_INSERT_TAIL(&tp->snd_holes, temp, scblink);
}
if (SEQ_LT(tp->rcv_lastsack, sack.end))
tp->rcv_lastsack = sack.end;
@@ -476,12 +462,13 @@ tcp_del_sackholes(tp, th)
/* max because this could be an older ack just arrived */
tcp_seq lastack = SEQ_GT(th->th_ack, tp->snd_una) ?
th->th_ack : tp->snd_una;
- struct sackhole *cur = tp->snd_holes;
+ struct sackhole *cur = TAILQ_FIRST(&tp->snd_holes);
struct sackhole *prev;
while (cur)
if (SEQ_LEQ(cur->end, lastack)) {
prev = cur;
- cur = cur->next;
+ cur = TAILQ_NEXT(cur, scblink);
+ TAILQ_REMOVE(&tp->snd_holes, prev, scblink);
uma_zfree(sack_hole_zone, prev);
tp->snd_numholes--;
tcp_sack_globalholes--;
@@ -492,24 +479,20 @@ tcp_del_sackholes(tp, th)
break;
} else
break;
- tp->snd_holes = cur;
}
}
void
tcp_free_sackholes(struct tcpcb *tp)
{
- struct sackhole *p, *q;
+ struct sackhole *q;
INP_LOCK_ASSERT(tp->t_inpcb);
- q = tp->snd_holes;
- while (q != NULL) {
- p = q;
- q = q->next;
- uma_zfree(sack_hole_zone, p);
+ while ((q = TAILQ_FIRST(&tp->snd_holes)) != NULL) {
+ TAILQ_REMOVE(&tp->snd_holes, q, scblink);
+ uma_zfree(sack_hole_zone, q);
tcp_sack_globalholes--;
}
- tp->snd_holes = 0;
tp->snd_numholes = 0;
}
@@ -546,22 +529,6 @@ tcp_sack_partialack(tp, th)
(void) tcp_output(tp);
}
-#ifdef TCP_SACK_DEBUG
-void
-tcp_print_holes(struct tcpcb *tp)
-{
- struct sackhole *p = tp->snd_holes;
- if (p == 0)
- return;
- printf("Hole report: start--end dups rxmit\n");
- while (p) {
- printf("%x--%x r %x\n", p->start, p->end, p->rxmit);
- p = p->next;
- }
- printf("\n");
-}
-#endif /* TCP_SACK_DEBUG */
-
/*
* Returns pointer to a sackhole if there are any pending retransmissions;
* NULL otherwise.
@@ -569,21 +536,17 @@ tcp_print_holes(struct tcpcb *tp)
struct sackhole *
tcp_sack_output(struct tcpcb *tp, int *sack_bytes_rexmt)
{
- struct sackhole *p = NULL;
+ struct sackhole *p;
INP_LOCK_ASSERT(tp->t_inpcb);
if (!tp->sack_enable)
return (NULL);
*sack_bytes_rexmt = 0;
- for (p = tp->snd_holes; p ; p = p->next) {
+ TAILQ_FOREACH(p, &tp->snd_holes, scblink) {
if (SEQ_LT(p->rxmit, p->end)) {
if (SEQ_LT(p->rxmit, tp->snd_una)) {/* old SACK hole */
continue;
}
-#ifdef TCP_SACK_DEBUG
- if (p)
- tcp_print_holes(tp);
-#endif
*sack_bytes_rexmt += (p->rxmit - p->start);
break;
}
@@ -600,7 +563,7 @@ tcp_sack_output(struct tcpcb *tp, int *sack_bytes_rexmt)
void
tcp_sack_adjust(struct tcpcb *tp)
{
- struct sackhole *cur = tp->snd_holes;
+ struct sackhole *p, *cur = TAILQ_FIRST(&tp->snd_holes);
INP_LOCK_ASSERT(tp->t_inpcb);
if (cur == NULL)
@@ -612,13 +575,13 @@ tcp_sack_adjust(struct tcpcb *tp)
* i) snd_nxt lies between end of one hole and beginning of another
* ii) snd_nxt lies between end of last hole and rcv_lastsack
*/
- while (cur->next) {
+ while ((p = TAILQ_NEXT(cur, scblink)) != NULL) {
if (SEQ_LT(tp->snd_nxt, cur->end))
return;
- if (SEQ_GEQ(tp->snd_nxt, cur->next->start))
- cur = cur->next;
+ if (SEQ_GEQ(tp->snd_nxt, p->start))
+ cur = p;
else {
- tp->snd_nxt = cur->next->start;
+ tp->snd_nxt = p->start;
return;
}
}
@@ -638,9 +601,9 @@ int
tcp_sacked_bytes(struct tcpcb *tp, int *lost_not_rexmitted)
{
INP_LOCK_ASSERT(tp->t_inpcb);
- struct sackhole *cur = tp->snd_holes;
+ struct sackhole *cur = TAILQ_FIRST(&tp->snd_holes);
int sacked = 0;
- u_long lost = 0;
+ int lost = 0;
if (cur == NULL) /* Scoreboard empty. */
goto out;
@@ -650,7 +613,7 @@ tcp_sacked_bytes(struct tcpcb *tp, int *lost_not_rexmitted)
while (cur) {
lost += (cur->end - cur->rxmit);
sacked -= (cur->end - cur->start);
- cur = cur->next;
+ cur = TAILQ_NEXT(cur, scblink);
}
out:
if (lost_not_rexmitted)
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index 474aa52..25a9266 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -605,6 +605,8 @@ tcp_newtcpcb(inp)
if (tcp_do_rfc1323)
tp->t_flags = (TF_REQ_SCALE|TF_REQ_TSTMP);
tp->sack_enable = tcp_do_sack;
+ if (tp->sack_enable)
+ TAILQ_INIT(&tp->snd_holes);
tp->t_inpcb = inp; /* XXX */
/*
* Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no
diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c
index 474aa52..25a9266 100644
--- a/sys/netinet/tcp_timewait.c
+++ b/sys/netinet/tcp_timewait.c
@@ -605,6 +605,8 @@ tcp_newtcpcb(inp)
if (tcp_do_rfc1323)
tp->t_flags = (TF_REQ_SCALE|TF_REQ_TSTMP);
tp->sack_enable = tcp_do_sack;
+ if (tp->sack_enable)
+ TAILQ_INIT(&tp->snd_holes);
tp->t_inpcb = inp; /* XXX */
/*
* Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
index 2a727a0..84d7150 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -60,7 +60,7 @@ struct sackhole {
tcp_seq start; /* start seq no. of hole */
tcp_seq end; /* end seq no. */
tcp_seq rxmit; /* next seq. no in hole to be retransmitted */
- struct sackhole *next; /* next in list */
+ TAILQ_ENTRY(sackhole) scblink; /* scoreboard linkage */
};
struct tcptemp {
@@ -186,7 +186,7 @@ struct tcpcb {
/* SACK related state */
int sack_enable; /* enable SACK for this connection */
int snd_numholes; /* number of holes seen by sender */
- struct sackhole *snd_holes; /* linked list of holes (sorted) */
+ TAILQ_HEAD(, sackhole) snd_holes; /* SACK scoreboard (sorted) */
tcp_seq rcv_lastsack; /* last seq number(+1) sack'd by rcv'r*/
int rcv_numsacks; /* # distinct sack blks present */
struct sackblk sackblks[MAX_SACK_BLKS]; /* seq nos. of sack blocks */
@@ -582,9 +582,6 @@ void tcp_sack_partialack(struct tcpcb *, struct tcphdr *);
void tcp_free_sackholes(struct tcpcb *tp);
int tcp_newreno(struct tcpcb *, struct tcphdr *);
u_long tcp_seq_subtract(u_long, u_long );
-#ifdef TCP_SACK_DEBUG
-void tcp_print_holes(struct tcpcb *tp);
-#endif /* TCP_SACK_DEBUG */
#endif /* _KERNEL */
OpenPOWER on IntegriCloud