* Allocate a SACK block.
*/
static __inline struct sackblock *
-alloc_sackblock(const struct raw_sackblock *raw_sb)
+alloc_sackblock(struct scoreboard *scb, const struct raw_sackblock *raw_sb)
{
struct sackblock *sb;
- sb = kmalloc(sizeof(struct sackblock), M_SACKBLOCK, M_NOWAIT);
- if (sb != NULL) {
- sb->sblk_start = raw_sb->rblk_start;
- sb->sblk_end = raw_sb->rblk_end;
+ if (scb->freecache != NULL) {
+ sb = scb->freecache;
+ scb->freecache = NULL;
+ tcpstat.tcps_sacksbfast++;
} else {
- tcpstat.tcps_sacksbfailed++;
+ sb = kmalloc(sizeof(struct sackblock), M_SACKBLOCK, M_NOWAIT);
+ if (sb == NULL) {
+ tcpstat.tcps_sacksbfailed++;
+ return NULL;
+ }
}
+ sb->sblk_start = raw_sb->rblk_start;
+ sb->sblk_end = raw_sb->rblk_end;
return sb;
}
tcpstat.tcps_sacksboverflow++;
return NULL;
}
- return alloc_sackblock(raw_sb);
+ return alloc_sackblock(scb, raw_sb);
}
/*
* Free a SACK block.
*/
static __inline void
-free_sackblock(struct sackblock *s)
+free_sackblock(struct scoreboard *scb, struct sackblock *s)
{
+ if (scb->freecache == NULL) {
+ /* YYY Maybe use the latest freed block? */
+ scb->freecache = s;
+ return;
+ }
kfree(s, M_SACKBLOCK);
}
if (scb->lastfound == sb)
scb->lastfound = NULL;
TAILQ_REMOVE(&scb->sackblocks, sb, sblk_list);
- free_sackblock(sb);
+ free_sackblock(scb, sb);
--scb->nblocks;
KASSERT(scb->nblocks >= 0,
("SACK block count underflow: %d < 0", scb->nblocks));
struct sackblock *sb, *nb;
TAILQ_FOREACH_MUTABLE(sb, &scb->sackblocks, sblk_list, nb) {
- free_sackblock(sb);
+ free_sackblock(scb, sb);
--scb->nblocks;
}
KASSERT(scb->nblocks == 0,
}
/*
+ * Delete and free SACK blocks saved in scoreboard.
+ * Delete the one slot block cache.
+ */
+void
+tcp_sack_destroy(struct scoreboard *scb)
+{
+ tcp_sack_cleanup(scb);
+ if (scb->freecache != NULL) {
+ kfree(scb->freecache, M_SACKBLOCK);
+ scb->freecache = NULL;
+ }
+}
+
+/*
* Cleanup the reported SACK block information
*/
void
KASSERT(scb->nblocks == 0, ("emply scb w/ blocks"));
- newblock = alloc_sackblock(raw_sb);
+ newblock = alloc_sackblock(scb, raw_sb);
if (newblock == NULL)
return ENOMEM;
TAILQ_INSERT_HEAD(&scb->sackblocks, newblock, sblk_list);
scb->lastfound = NULL;
/* Remove completely overlapped block */
TAILQ_REMOVE(&scb->sackblocks, sb, sblk_list);
- free_sackblock(sb);
+ free_sackblock(scb, sb);
--scb->nblocks;
KASSERT(scb->nblocks > 0,
("removed overlapped block: %d blocks left", scb->nblocks));
if (scb->lastfound == sb)
scb->lastfound = NULL;
TAILQ_REMOVE(&scb->sackblocks, sb, sblk_list);
- free_sackblock(sb);
+ free_sackblock(scb, sb);
--scb->nblocks;
KASSERT(scb->nblocks > 0,
("removed partial right: %d blocks left", scb->nblocks));
struct sackblock_list sackblocks;
tcp_seq lostseq; /* passed SACK lost test */
struct sackblock *lastfound; /* search hint */
+ struct sackblock *freecache; /* one slot free block cache */
};
struct netmsg_tcp_timer;
u_long tcps_sacksboverflow; /* times SACK scoreboard overflowed */
u_long tcps_sacksbreused; /* times SACK sb-block reused */
u_long tcps_sacksbfailed; /* times SACK sb update failed */
+ u_long tcps_sacksbfast; /* timee SACK sb-block uses cache */
u_long tcps_sc_added; /* entry added to syncache */
u_long tcps_sc_retransmitted; /* syncache entry was retransmitted */
struct rtentry *
tcp_rtlookup (struct in_conninfo *);
int tcp_sack_bytes_below(struct scoreboard *scb, tcp_seq seq);
+void tcp_sack_destroy(struct scoreboard *scb);
void tcp_sack_cleanup(struct scoreboard *scb);
void tcp_sack_report_cleanup(struct tcpcb *tp);
int tcp_sack_ndsack_blocks(struct raw_sackblock *blocks,