Use callouts for SYN cache timers, rather than traversing time queues
in tcp_slowtimo().
This commit is contained in:
parent
0f63dc99dc
commit
050e9de009
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: tcp_input.c,v 1.129 2001/09/10 22:14:26 thorpej Exp $ */
|
||||
/* $NetBSD: tcp_input.c,v 1.130 2001/09/11 21:03:20 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
%%% portions-copyright-nrl-95
|
||||
@ -2578,18 +2578,19 @@ do { \
|
||||
default: \
|
||||
hash = 0; \
|
||||
} \
|
||||
} while (0)
|
||||
} while (/*CONSTCOND*/0)
|
||||
#endif /* INET6 */
|
||||
|
||||
#define SYN_CACHE_RM(sc) \
|
||||
do { \
|
||||
LIST_REMOVE((sc), sc_bucketq); \
|
||||
TAILQ_REMOVE(&tcp_syn_cache[(sc)->sc_bucketidx].sch_bucket, \
|
||||
(sc), sc_bucketq); \
|
||||
(sc)->sc_tp = NULL; \
|
||||
LIST_REMOVE((sc), sc_tpq); \
|
||||
tcp_syn_cache[(sc)->sc_bucketidx].sch_length--; \
|
||||
TAILQ_REMOVE(&tcp_syn_cache_timeq[(sc)->sc_rxtshift], (sc), sc_timeq); \
|
||||
callout_stop(&(sc)->sc_timer); \
|
||||
syn_cache_count--; \
|
||||
} while (0)
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define SYN_CACHE_PUT(sc) \
|
||||
do { \
|
||||
@ -2598,24 +2599,22 @@ do { \
|
||||
if ((sc)->sc_route4.ro_rt != NULL) \
|
||||
RTFREE((sc)->sc_route4.ro_rt); \
|
||||
pool_put(&syn_cache_pool, (sc)); \
|
||||
} while (0)
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
struct pool syn_cache_pool;
|
||||
|
||||
/*
|
||||
* We don't estimate RTT with SYNs, so each packet starts with the default
|
||||
* RTT and each timer queue has a fixed timeout value. This allows us to
|
||||
* optimize the timer queues somewhat.
|
||||
* RTT and each timer step has a fixed timeout value.
|
||||
*/
|
||||
#define SYN_CACHE_TIMER_ARM(sc) \
|
||||
do { \
|
||||
TCPT_RANGESET((sc)->sc_rxtcur, \
|
||||
TCPTV_SRTTDFLT * tcp_backoff[(sc)->sc_rxtshift], TCPTV_MIN, \
|
||||
TCPTV_REXMTMAX); \
|
||||
PRT_SLOW_ARM((sc)->sc_rexmt, (sc)->sc_rxtcur); \
|
||||
} while (0)
|
||||
|
||||
TAILQ_HEAD(, syn_cache) tcp_syn_cache_timeq[TCP_MAXRXTSHIFT + 1];
|
||||
callout_reset(&(sc)->sc_timer, \
|
||||
(sc)->sc_rxtcur * (hz / PR_SLOWHZ), syn_cache_timer, (sc)); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define SYN_CACHE_TIMESTAMP(sc) (tcp_now - (sc)->sc_timebase)
|
||||
|
||||
@ -2626,11 +2625,7 @@ syn_cache_init()
|
||||
|
||||
/* Initialize the hash buckets. */
|
||||
for (i = 0; i < tcp_syn_cache_size; i++)
|
||||
LIST_INIT(&tcp_syn_cache[i].sch_bucket);
|
||||
|
||||
/* Initialize the timer queues. */
|
||||
for (i = 0; i <= TCP_MAXRXTSHIFT; i++)
|
||||
TAILQ_INIT(&tcp_syn_cache_timeq[i]);
|
||||
TAILQ_INIT(&tcp_syn_cache[i].sch_bucket);
|
||||
|
||||
/* Initialize the syn cache pool. */
|
||||
pool_init(&syn_cache_pool, sizeof(struct syn_cache), 0, 0, 0,
|
||||
@ -2644,7 +2639,7 @@ syn_cache_insert(sc, tp)
|
||||
{
|
||||
struct syn_cache_head *scp;
|
||||
struct syn_cache *sc2;
|
||||
int s, i;
|
||||
int s;
|
||||
|
||||
/*
|
||||
* If there are no entries in the hash table, reinitialize
|
||||
@ -2670,72 +2665,67 @@ syn_cache_insert(sc, tp)
|
||||
tcpstat.tcps_sc_bucketoverflow++;
|
||||
/*
|
||||
* The bucket is full. Toss the oldest element in the
|
||||
* bucket. This will be the entry with our bucket
|
||||
* index closest to the front of the timer queue with
|
||||
* the largest timeout value.
|
||||
*
|
||||
* Note: This timer queue traversal may be expensive, so
|
||||
* we hope that this doesn't happen very often. It is
|
||||
* much more likely that we'll overflow the entire
|
||||
* cache, which is much easier to handle; see below.
|
||||
* bucket. This will be the first entry in the bucket.
|
||||
*/
|
||||
for (i = TCP_MAXRXTSHIFT; i >= 0; i--) {
|
||||
for (sc2 = TAILQ_FIRST(&tcp_syn_cache_timeq[i]);
|
||||
sc2 != NULL;
|
||||
sc2 = TAILQ_NEXT(sc2, sc_timeq)) {
|
||||
if (sc2->sc_bucketidx == sc->sc_bucketidx) {
|
||||
SYN_CACHE_RM(sc2);
|
||||
SYN_CACHE_PUT(sc2);
|
||||
goto insert; /* 2 level break */
|
||||
}
|
||||
}
|
||||
}
|
||||
sc2 = TAILQ_FIRST(&scp->sch_bucket);
|
||||
#ifdef DIAGNOSTIC
|
||||
/*
|
||||
* This should never happen; we should always find an
|
||||
* entry in our bucket.
|
||||
*/
|
||||
panic("syn_cache_insert: bucketoverflow: impossible");
|
||||
if (sc2 == NULL)
|
||||
panic("syn_cache_insert: bucketoverflow: impossible");
|
||||
#endif
|
||||
SYN_CACHE_RM(sc2);
|
||||
SYN_CACHE_PUT(sc2);
|
||||
} else if (syn_cache_count >= tcp_syn_cache_limit) {
|
||||
struct syn_cache_head *scp2, *sce;
|
||||
|
||||
tcpstat.tcps_sc_overflowed++;
|
||||
/*
|
||||
* The cache is full. Toss the oldest entry in the
|
||||
* entire cache. This is the front entry in the
|
||||
* first non-empty timer queue with the largest
|
||||
* timeout value.
|
||||
* first non-empty bucket we can find.
|
||||
*
|
||||
* XXX We would really like to toss the oldest
|
||||
* entry in the cache, but we hope that this
|
||||
* condition doesn't happen very often.
|
||||
*/
|
||||
for (i = TCP_MAXRXTSHIFT; i >= 0; i--) {
|
||||
sc2 = TAILQ_FIRST(&tcp_syn_cache_timeq[i]);
|
||||
if (sc2 == NULL)
|
||||
continue;
|
||||
SYN_CACHE_RM(sc2);
|
||||
SYN_CACHE_PUT(sc2);
|
||||
goto insert; /* symmetry with above */
|
||||
}
|
||||
scp2 = scp;
|
||||
if (TAILQ_EMPTY(&scp2->sch_bucket)) {
|
||||
sce = &tcp_syn_cache[tcp_syn_cache_size];
|
||||
for (++scp2; scp2 != scp; scp2++) {
|
||||
if (scp2 >= sce)
|
||||
scp2 = &tcp_syn_cache[0];
|
||||
if (! TAILQ_EMPTY(&scp2->sch_bucket))
|
||||
break;
|
||||
}
|
||||
#ifdef DIAGNOSTIC
|
||||
/*
|
||||
* This should never happen; we should always find an
|
||||
* entry in the cache.
|
||||
*/
|
||||
panic("syn_cache_insert: cache overflow: impossible");
|
||||
/*
|
||||
* This should never happen; we should always find a
|
||||
* non-empty bucket.
|
||||
*/
|
||||
if (scp2 == scp)
|
||||
panic("syn_cache_insert: cacheoverflow: "
|
||||
"impossible");
|
||||
#endif
|
||||
}
|
||||
sc2 = TAILQ_FIRST(&scp2->sch_bucket);
|
||||
SYN_CACHE_RM(sc2);
|
||||
SYN_CACHE_PUT(sc2);
|
||||
}
|
||||
|
||||
insert:
|
||||
/*
|
||||
* Initialize the entry's timer.
|
||||
*/
|
||||
sc->sc_rxttot = 0;
|
||||
sc->sc_rxtshift = 0;
|
||||
SYN_CACHE_TIMER_ARM(sc);
|
||||
TAILQ_INSERT_TAIL(&tcp_syn_cache_timeq[sc->sc_rxtshift], sc, sc_timeq);
|
||||
|
||||
/* Link it from tcpcb entry */
|
||||
LIST_INSERT_HEAD(&tp->t_sc, sc, sc_tpq);
|
||||
|
||||
/* Put it into the bucket. */
|
||||
LIST_INSERT_HEAD(&scp->sch_bucket, sc, sc_bucketq);
|
||||
TAILQ_INSERT_TAIL(&scp->sch_bucket, sc, sc_bucketq);
|
||||
scp->sch_length++;
|
||||
syn_cache_count++;
|
||||
|
||||
@ -2749,60 +2739,41 @@ syn_cache_insert(sc, tp)
|
||||
* that entry.
|
||||
*/
|
||||
void
|
||||
syn_cache_timer()
|
||||
syn_cache_timer(void *arg)
|
||||
{
|
||||
struct syn_cache *sc, *nsc;
|
||||
int i, s;
|
||||
struct syn_cache *sc = arg;
|
||||
int s;
|
||||
|
||||
s = splsoftnet();
|
||||
|
||||
/*
|
||||
* First, get all the entries that need to be retransmitted, or
|
||||
* must be expired due to exceeding the initial keepalive time.
|
||||
*/
|
||||
for (i = 0; i < TCP_MAXRXTSHIFT; i++) {
|
||||
for (sc = TAILQ_FIRST(&tcp_syn_cache_timeq[i]);
|
||||
sc != NULL && PRT_SLOW_ISEXPIRED(sc->sc_rexmt);
|
||||
sc = nsc) {
|
||||
nsc = TAILQ_NEXT(sc, sc_timeq);
|
||||
|
||||
/*
|
||||
* Compute the total amount of time this entry has
|
||||
* been on a queue. If this entry has been on longer
|
||||
* than the keep alive timer would allow, expire it.
|
||||
*/
|
||||
sc->sc_rxttot += sc->sc_rxtcur;
|
||||
if (sc->sc_rxttot >= TCPTV_KEEP_INIT) {
|
||||
tcpstat.tcps_sc_timed_out++;
|
||||
SYN_CACHE_RM(sc);
|
||||
SYN_CACHE_PUT(sc);
|
||||
continue;
|
||||
}
|
||||
|
||||
tcpstat.tcps_sc_retransmitted++;
|
||||
(void) syn_cache_respond(sc, NULL);
|
||||
|
||||
/* Advance this entry onto the next timer queue. */
|
||||
TAILQ_REMOVE(&tcp_syn_cache_timeq[i], sc, sc_timeq);
|
||||
sc->sc_rxtshift = i + 1;
|
||||
SYN_CACHE_TIMER_ARM(sc);
|
||||
TAILQ_INSERT_TAIL(&tcp_syn_cache_timeq[sc->sc_rxtshift],
|
||||
sc, sc_timeq);
|
||||
}
|
||||
if (__predict_false(sc->sc_rxtshift == TCP_MAXRXTSHIFT)) {
|
||||
/* Drop it -- too many retransmissions. */
|
||||
goto dropit;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now get all the entries that are expired due to too many
|
||||
* retransmissions.
|
||||
* Compute the total amount of time this entry has
|
||||
* been on a queue. If this entry has been on longer
|
||||
* than the keep alive timer would allow, expire it.
|
||||
*/
|
||||
for (sc = TAILQ_FIRST(&tcp_syn_cache_timeq[TCP_MAXRXTSHIFT]);
|
||||
sc != NULL && PRT_SLOW_ISEXPIRED(sc->sc_rexmt);
|
||||
sc = nsc) {
|
||||
nsc = TAILQ_NEXT(sc, sc_timeq);
|
||||
tcpstat.tcps_sc_timed_out++;
|
||||
SYN_CACHE_RM(sc);
|
||||
SYN_CACHE_PUT(sc);
|
||||
}
|
||||
sc->sc_rxttot += sc->sc_rxtcur;
|
||||
if (sc->sc_rxttot >= TCPTV_KEEP_INIT)
|
||||
goto dropit;
|
||||
|
||||
tcpstat.tcps_sc_retransmitted++;
|
||||
(void) syn_cache_respond(sc, NULL);
|
||||
|
||||
/* Advance the timer back-off. */
|
||||
sc->sc_rxtshift++;
|
||||
SYN_CACHE_TIMER_ARM(sc);
|
||||
|
||||
splx(s);
|
||||
return;
|
||||
|
||||
dropit:
|
||||
tcpstat.tcps_sc_timed_out++;
|
||||
SYN_CACHE_RM(sc);
|
||||
SYN_CACHE_PUT(sc);
|
||||
splx(s);
|
||||
}
|
||||
|
||||
@ -2855,8 +2826,8 @@ syn_cache_lookup(src, dst, headp)
|
||||
scp = &tcp_syn_cache[hash % tcp_syn_cache_size];
|
||||
*headp = scp;
|
||||
s = splsoftnet();
|
||||
for (sc = LIST_FIRST(&scp->sch_bucket); sc != NULL;
|
||||
sc = LIST_NEXT(sc, sc_bucketq)) {
|
||||
for (sc = TAILQ_FIRST(&scp->sch_bucket); sc != NULL;
|
||||
sc = TAILQ_NEXT(sc, sc_bucketq)) {
|
||||
if (sc->sc_hash != hash)
|
||||
continue;
|
||||
if (!bcmp(&sc->sc_src, src, src->sa_len) &&
|
||||
@ -3347,6 +3318,7 @@ syn_cache_add(src, dst, th, hlen, so, m, optp, optlen, oi)
|
||||
* Fill in the cache, and put the necessary IP and TCP
|
||||
* options into the reply.
|
||||
*/
|
||||
callout_init(&sc->sc_timer);
|
||||
bzero(sc, sizeof(struct syn_cache));
|
||||
bcopy(src, &sc->sc_src, src->sa_len);
|
||||
bcopy(dst, &sc->sc_dst, dst->sa_len);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: tcp_subr.c,v 1.118 2001/09/10 22:14:27 thorpej Exp $ */
|
||||
/* $NetBSD: tcp_subr.c,v 1.119 2001/09/11 21:03:21 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
@ -194,7 +194,6 @@ int tcp_syn_cache_size = TCP_SYN_HASH_SIZE;
|
||||
int tcp_syn_cache_limit = TCP_SYN_HASH_SIZE*TCP_SYN_BUCKET_SIZE;
|
||||
int tcp_syn_bucket_limit = 3*TCP_SYN_BUCKET_SIZE;
|
||||
struct syn_cache_head tcp_syn_cache[TCP_SYN_HASH_SIZE];
|
||||
int tcp_syn_cache_interval = 1; /* runs timer twice a second */
|
||||
|
||||
int tcp_freeq __P((struct tcpcb *));
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: tcp_timer.c,v 1.54 2001/09/10 22:45:46 thorpej Exp $ */
|
||||
/* $NetBSD: tcp_timer.c,v 1.55 2001/09/11 21:03:21 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
@ -221,17 +221,12 @@ tcp_delack(void *arg)
|
||||
void
|
||||
tcp_slowtimo()
|
||||
{
|
||||
static int syn_cache_last = 0;
|
||||
int s;
|
||||
|
||||
s = splsoftnet();
|
||||
tcp_maxidle = tcp_keepcnt * tcp_keepintvl;
|
||||
tcp_iss_seq += TCP_ISSINCR; /* increment iss */
|
||||
tcp_now++; /* for timestamps */
|
||||
if (++syn_cache_last >= tcp_syn_cache_interval) {
|
||||
syn_cache_timer();
|
||||
syn_cache_last = 0;
|
||||
}
|
||||
splx(s);
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: tcp_var.h,v 1.86 2001/09/10 22:14:28 thorpej Exp $ */
|
||||
/* $NetBSD: tcp_var.h,v 1.87 2001/09/11 21:03:21 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
%%% portions-copyright-nrl-98
|
||||
@ -352,8 +352,8 @@ union syn_cache_sa {
|
||||
};
|
||||
|
||||
struct syn_cache {
|
||||
LIST_ENTRY(syn_cache) sc_bucketq; /* link on bucket list */
|
||||
TAILQ_ENTRY(syn_cache) sc_timeq; /* link on timer queue */
|
||||
TAILQ_ENTRY(syn_cache) sc_bucketq; /* link on bucket list */
|
||||
struct callout sc_timer; /* rexmt timer */
|
||||
union { /* cached route */
|
||||
struct route route4;
|
||||
#ifdef INET6
|
||||
@ -373,7 +373,6 @@ struct syn_cache {
|
||||
union syn_cache_sa sc_dst;
|
||||
tcp_seq sc_irs;
|
||||
tcp_seq sc_iss;
|
||||
u_int sc_rexmt; /* retransmit timer */
|
||||
u_int sc_rxtcur; /* current rxt timeout */
|
||||
u_int sc_rxttot; /* total time spend on queues */
|
||||
u_short sc_rxtshift; /* for computing backoff */
|
||||
@ -393,7 +392,7 @@ struct syn_cache {
|
||||
};
|
||||
|
||||
struct syn_cache_head {
|
||||
LIST_HEAD(, syn_cache) sch_bucket; /* bucket entries */
|
||||
TAILQ_HEAD(, syn_cache) sch_bucket; /* bucket entries */
|
||||
u_short sch_length; /* # entries in bucket */
|
||||
};
|
||||
|
||||
@ -537,7 +536,9 @@ struct tcpstat {
|
||||
#define TCPCTL_MSSDFLT 4 /* default seg size */
|
||||
#define TCPCTL_SYN_CACHE_LIMIT 5 /* max size of comp. state engine */
|
||||
#define TCPCTL_SYN_BUCKET_LIMIT 6 /* max size of hash bucket */
|
||||
#if 0 /*obsoleted*/
|
||||
#define TCPCTL_SYN_CACHE_INTER 7 /* interval of comp. state timer */
|
||||
#endif
|
||||
#define TCPCTL_INIT_WIN 8 /* initial window */
|
||||
#define TCPCTL_MSS_IFMTU 9 /* mss from interface, not in_maxmtu */
|
||||
#define TCPCTL_SACK 10 /* RFC2018 selective acknowledgement */
|
||||
@ -568,7 +569,7 @@ struct tcpstat {
|
||||
{ "mssdflt", CTLTYPE_INT }, \
|
||||
{ "syn_cache_limit", CTLTYPE_INT }, \
|
||||
{ "syn_bucket_limit", CTLTYPE_INT }, \
|
||||
{ "syn_cache_interval", CTLTYPE_INT },\
|
||||
{ 0, 0 },\
|
||||
{ "init_win", CTLTYPE_INT }, \
|
||||
{ "mss_ifmtu", CTLTYPE_INT }, \
|
||||
{ "sack", CTLTYPE_INT }, \
|
||||
@ -610,7 +611,6 @@ extern int tcp_cwm_burstsize; /* burst size allowed by CWM */
|
||||
extern int tcp_ack_on_push; /* ACK immediately on PUSH */
|
||||
extern int tcp_syn_cache_limit; /* max entries for compressed state engine */
|
||||
extern int tcp_syn_bucket_limit;/* max entries per hash bucket */
|
||||
extern int tcp_syn_cache_interval; /* compressed state timer */
|
||||
extern int tcp_log_refused; /* log refused connections */
|
||||
|
||||
extern int tcp_rst_ppslim;
|
||||
@ -627,7 +627,7 @@ extern u_long syn_cache_count;
|
||||
{ 1, 0, &tcp_mssdflt }, \
|
||||
{ 1, 0, &tcp_syn_cache_limit }, \
|
||||
{ 1, 0, &tcp_syn_bucket_limit }, \
|
||||
{ 1, 0, &tcp_syn_cache_interval }, \
|
||||
{ 0 }, \
|
||||
{ 1, 0, &tcp_init_win }, \
|
||||
{ 1, 0, &tcp_mss_ifmtu }, \
|
||||
{ 1, 0, &tcp_do_sack }, \
|
||||
@ -720,7 +720,7 @@ struct syn_cache *syn_cache_lookup __P((struct sockaddr *, struct sockaddr *,
|
||||
void syn_cache_reset __P((struct sockaddr *, struct sockaddr *,
|
||||
struct tcphdr *));
|
||||
int syn_cache_respond __P((struct syn_cache *, struct mbuf *));
|
||||
void syn_cache_timer __P((void));
|
||||
void syn_cache_timer __P((void *));
|
||||
void syn_cache_cleanup __P((struct tcpcb *));
|
||||
|
||||
int tcp_newreno __P((struct tcpcb *, struct tcphdr *));
|
||||
|
Loading…
x
Reference in New Issue
Block a user