This cleans up the timers code in TCP to start using the new
async_drain functionality. This as been tested in NF as well as by Verisign. Still to do in here is to remove all the old flags. They are currently left being maintained but probably are no longer needed. Sponsored by: Netflix Inc. Differential Revision: http://reviews.freebsd.org/D5924
This commit is contained in:
parent
329ee7e3dc
commit
e5ad64562a
@ -2386,7 +2386,6 @@ struct tcp_function_block __tcp_fastslow = {
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
0
|
||||
|
||||
@ -2403,7 +2402,6 @@ struct tcp_function_block __tcp_fastack = {
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
@ -244,7 +244,6 @@ static struct inpcb *tcp_mtudisc_notify(struct inpcb *, int);
|
||||
static void tcp_mtudisc(struct inpcb *, int);
|
||||
static char * tcp_log_addr(struct in_conninfo *inc, struct tcphdr *th,
|
||||
void *ip4hdr, const void *ip6hdr);
|
||||
static void tcp_timer_discard(struct tcpcb *, uint32_t);
|
||||
|
||||
|
||||
static struct tcp_function_block tcp_def_funcblk = {
|
||||
@ -258,7 +257,6 @@ static struct tcp_function_block tcp_def_funcblk = {
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
0
|
||||
};
|
||||
@ -528,7 +526,6 @@ register_tcp_functions(struct tcp_function_block *blk, int wait)
|
||||
return (EINVAL);
|
||||
}
|
||||
if (blk->tfb_tcp_timer_stop_all ||
|
||||
blk->tfb_tcp_timers_left ||
|
||||
blk->tfb_tcp_timer_activate ||
|
||||
blk->tfb_tcp_timer_active ||
|
||||
blk->tfb_tcp_timer_stop) {
|
||||
@ -537,7 +534,6 @@ register_tcp_functions(struct tcp_function_block *blk, int wait)
|
||||
* must have them all.
|
||||
*/
|
||||
if ((blk->tfb_tcp_timer_stop_all == NULL) ||
|
||||
(blk->tfb_tcp_timers_left == NULL) ||
|
||||
(blk->tfb_tcp_timer_activate == NULL) ||
|
||||
(blk->tfb_tcp_timer_active == NULL) ||
|
||||
(blk->tfb_tcp_timer_stop == NULL)) {
|
||||
@ -1343,13 +1339,21 @@ tcp_discardcb(struct tcpcb *tp)
|
||||
* callout, and the last discard function called will take care of
|
||||
* deleting the tcpcb.
|
||||
*/
|
||||
tp->t_timers->tt_draincnt = 0;
|
||||
tcp_timer_stop(tp, TT_REXMT);
|
||||
tcp_timer_stop(tp, TT_PERSIST);
|
||||
tcp_timer_stop(tp, TT_KEEP);
|
||||
tcp_timer_stop(tp, TT_2MSL);
|
||||
tcp_timer_stop(tp, TT_DELACK);
|
||||
if (tp->t_fb->tfb_tcp_timer_stop_all) {
|
||||
/* Call the stop-all function of the methods */
|
||||
/*
|
||||
* Call the stop-all function of the methods,
|
||||
* this function should call the tcp_timer_stop()
|
||||
* method with each of the function specific timeouts.
|
||||
* That stop will be called via the tfb_tcp_timer_stop()
|
||||
* which should use the async drain function of the
|
||||
* callout system (see tcp_var.h).
|
||||
*/
|
||||
tp->t_fb->tfb_tcp_timer_stop_all(tp);
|
||||
}
|
||||
|
||||
@ -1434,13 +1438,8 @@ tcp_discardcb(struct tcpcb *tp)
|
||||
|
||||
CC_ALGO(tp) = NULL;
|
||||
inp->inp_ppcb = NULL;
|
||||
if ((tp->t_timers->tt_flags & TT_MASK) == 0) {
|
||||
if (tp->t_timers->tt_draincnt == 0) {
|
||||
/* We own the last reference on tcpcb, let's free it. */
|
||||
if ((tp->t_fb->tfb_tcp_timers_left) &&
|
||||
(tp->t_fb->tfb_tcp_timers_left(tp))) {
|
||||
/* Some fb timers left running! */
|
||||
return;
|
||||
}
|
||||
if (tp->t_fb->tfb_tcp_fb_fini)
|
||||
(*tp->t_fb->tfb_tcp_fb_fini)(tp);
|
||||
refcount_release(&tp->t_fb->tfb_refcnt);
|
||||
@ -1453,45 +1452,12 @@ tcp_discardcb(struct tcpcb *tp)
|
||||
}
|
||||
|
||||
void
|
||||
tcp_timer_2msl_discard(void *xtp)
|
||||
{
|
||||
|
||||
tcp_timer_discard((struct tcpcb *)xtp, TT_2MSL);
|
||||
}
|
||||
|
||||
void
|
||||
tcp_timer_keep_discard(void *xtp)
|
||||
{
|
||||
|
||||
tcp_timer_discard((struct tcpcb *)xtp, TT_KEEP);
|
||||
}
|
||||
|
||||
void
|
||||
tcp_timer_persist_discard(void *xtp)
|
||||
{
|
||||
|
||||
tcp_timer_discard((struct tcpcb *)xtp, TT_PERSIST);
|
||||
}
|
||||
|
||||
void
|
||||
tcp_timer_rexmt_discard(void *xtp)
|
||||
{
|
||||
|
||||
tcp_timer_discard((struct tcpcb *)xtp, TT_REXMT);
|
||||
}
|
||||
|
||||
void
|
||||
tcp_timer_delack_discard(void *xtp)
|
||||
{
|
||||
|
||||
tcp_timer_discard((struct tcpcb *)xtp, TT_DELACK);
|
||||
}
|
||||
|
||||
void
|
||||
tcp_timer_discard(struct tcpcb *tp, uint32_t timer_type)
|
||||
tcp_timer_discard(void *ptp)
|
||||
{
|
||||
struct inpcb *inp;
|
||||
|
||||
struct tcpcb *tp;
|
||||
|
||||
tp = (struct tcpcb *)ptp;
|
||||
CURVNET_SET(tp->t_vnet);
|
||||
INP_INFO_RLOCK(&V_tcbinfo);
|
||||
inp = tp->t_inpcb;
|
||||
@ -1500,16 +1466,9 @@ tcp_timer_discard(struct tcpcb *tp, uint32_t timer_type)
|
||||
INP_WLOCK(inp);
|
||||
KASSERT((tp->t_timers->tt_flags & TT_STOPPED) != 0,
|
||||
("%s: tcpcb has to be stopped here", __func__));
|
||||
KASSERT((tp->t_timers->tt_flags & timer_type) != 0,
|
||||
("%s: discard callout should be running", __func__));
|
||||
tp->t_timers->tt_flags &= ~timer_type;
|
||||
if ((tp->t_timers->tt_flags & TT_MASK) == 0) {
|
||||
tp->t_timers->tt_draincnt--;
|
||||
if (tp->t_timers->tt_draincnt == 0) {
|
||||
/* We own the last reference on this tcpcb, let's free it. */
|
||||
if ((tp->t_fb->tfb_tcp_timers_left) &&
|
||||
(tp->t_fb->tfb_tcp_timers_left(tp))) {
|
||||
/* Some fb timers left running! */
|
||||
goto leave;
|
||||
}
|
||||
if (tp->t_fb->tfb_tcp_fb_fini)
|
||||
(*tp->t_fb->tfb_tcp_fb_fini)(tp);
|
||||
refcount_release(&tp->t_fb->tfb_refcnt);
|
||||
@ -1521,7 +1480,6 @@ tcp_timer_discard(struct tcpcb *tp, uint32_t timer_type)
|
||||
return;
|
||||
}
|
||||
}
|
||||
leave:
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_RUNLOCK(&V_tcbinfo);
|
||||
CURVNET_RESTORE();
|
||||
|
@ -927,7 +927,6 @@ void
|
||||
tcp_timer_stop(struct tcpcb *tp, uint32_t timer_type)
|
||||
{
|
||||
struct callout *t_callout;
|
||||
timeout_t *f_callout;
|
||||
uint32_t f_reset;
|
||||
|
||||
tp->t_timers->tt_flags |= TT_STOPPED;
|
||||
@ -935,27 +934,22 @@ tcp_timer_stop(struct tcpcb *tp, uint32_t timer_type)
|
||||
switch (timer_type) {
|
||||
case TT_DELACK:
|
||||
t_callout = &tp->t_timers->tt_delack;
|
||||
f_callout = tcp_timer_delack_discard;
|
||||
f_reset = TT_DELACK_RST;
|
||||
break;
|
||||
case TT_REXMT:
|
||||
t_callout = &tp->t_timers->tt_rexmt;
|
||||
f_callout = tcp_timer_rexmt_discard;
|
||||
f_reset = TT_REXMT_RST;
|
||||
break;
|
||||
case TT_PERSIST:
|
||||
t_callout = &tp->t_timers->tt_persist;
|
||||
f_callout = tcp_timer_persist_discard;
|
||||
f_reset = TT_PERSIST_RST;
|
||||
break;
|
||||
case TT_KEEP:
|
||||
t_callout = &tp->t_timers->tt_keep;
|
||||
f_callout = tcp_timer_keep_discard;
|
||||
f_reset = TT_KEEP_RST;
|
||||
break;
|
||||
case TT_2MSL:
|
||||
t_callout = &tp->t_timers->tt_2msl;
|
||||
f_callout = tcp_timer_2msl_discard;
|
||||
f_reset = TT_2MSL_RST;
|
||||
break;
|
||||
default:
|
||||
@ -971,21 +965,13 @@ tcp_timer_stop(struct tcpcb *tp, uint32_t timer_type)
|
||||
}
|
||||
|
||||
if (tp->t_timers->tt_flags & timer_type) {
|
||||
if ((callout_stop(t_callout) > 0) &&
|
||||
(tp->t_timers->tt_flags & f_reset)) {
|
||||
tp->t_timers->tt_flags &= ~(timer_type | f_reset);
|
||||
} else {
|
||||
if (callout_async_drain(t_callout, tcp_timer_discard) == 0) {
|
||||
/*
|
||||
* Can't stop the callout, defer tcpcb actual deletion
|
||||
* to the last tcp timer discard callout.
|
||||
* The TT_STOPPED flag will ensure that no tcp timer
|
||||
* callouts can be restarted on our behalf, and
|
||||
* past this point currently running callouts waiting
|
||||
* on inp lock will return right away after the
|
||||
* classical check for callout reset/stop events:
|
||||
* callout_pending() || !callout_active()
|
||||
* to the last one. We do this using the async drain
|
||||
* function and incrementing the count in
|
||||
*/
|
||||
callout_reset(t_callout, 1, f_callout, tp);
|
||||
tp->t_timers->tt_draincnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -146,7 +146,7 @@ struct tcp_timer {
|
||||
struct callout tt_2msl; /* 2*msl TIME_WAIT timer */
|
||||
struct callout tt_delack; /* delayed ACK timer */
|
||||
uint32_t tt_flags; /* Timers flags */
|
||||
uint32_t tt_spare; /* TDB */
|
||||
uint32_t tt_draincnt; /* Count being drained */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -193,17 +193,13 @@ extern int tcp_fast_finwait2_recycle;
|
||||
|
||||
void tcp_timer_init(void);
|
||||
void tcp_timer_2msl(void *xtp);
|
||||
void tcp_timer_discard(void *);
|
||||
struct tcptw *
|
||||
tcp_tw_2msl_scan(int reuse); /* XXX temporary? */
|
||||
void tcp_timer_keep(void *xtp);
|
||||
void tcp_timer_persist(void *xtp);
|
||||
void tcp_timer_rexmt(void *xtp);
|
||||
void tcp_timer_delack(void *xtp);
|
||||
void tcp_timer_2msl_discard(void *xtp);
|
||||
void tcp_timer_keep_discard(void *xtp);
|
||||
void tcp_timer_persist_discard(void *xtp);
|
||||
void tcp_timer_rexmt_discard(void *xtp);
|
||||
void tcp_timer_delack_discard(void *xtp);
|
||||
void tcp_timer_to_xtimer(struct tcpcb *tp, struct tcp_timer *timer,
|
||||
struct xtcp_timer *xtimer);
|
||||
|
||||
|
@ -106,6 +106,17 @@ struct inpcb;
|
||||
struct sockopt;
|
||||
struct socket;
|
||||
|
||||
/*
|
||||
* If defining the optional tcp_timers, in the
|
||||
* tfb_tcp_timer_stop call you must use the
|
||||
* callout_async_drain() function with the
|
||||
* tcp_timer_discard callback. You should check
|
||||
* the return of callout_async_drain() and if 0
|
||||
* increment tt_draincnt. Since the timer sub-system
|
||||
* does not know your callbacks you must provide a
|
||||
* stop_all function that loops through and calls
|
||||
* tcp_timer_stop() with each of your defined timers.
|
||||
*/
|
||||
struct tcp_function_block {
|
||||
char tfb_tcp_block_name[TCP_FUNCTION_NAME_LEN_MAX];
|
||||
int (*tfb_tcp_output)(struct tcpcb *);
|
||||
@ -120,7 +131,6 @@ struct tcp_function_block {
|
||||
void (*tfb_tcp_fb_fini)(struct tcpcb *);
|
||||
/* Optional timers, must define all if you define one */
|
||||
int (*tfb_tcp_timer_stop_all)(struct tcpcb *);
|
||||
int (*tfb_tcp_timers_left)(struct tcpcb *);
|
||||
void (*tfb_tcp_timer_activate)(struct tcpcb *,
|
||||
uint32_t, u_int);
|
||||
int (*tfb_tcp_timer_active)(struct tcpcb *, uint32_t);
|
||||
|
Loading…
Reference in New Issue
Block a user