Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/tcp_timer.c
Show First 20 Lines • Show All 124 Lines • ▼ Show 20 Lines | SYSCTL_PROC(_net_inet_tcp, OID_AUTO, rexmit_slop, CTLTYPE_INT|CTLFLAG_RW, | ||||
&tcp_rexmit_slop, 0, sysctl_msec_to_ticks, "I", | &tcp_rexmit_slop, 0, sysctl_msec_to_ticks, "I", | ||||
"Retransmission Timer Slop"); | "Retransmission Timer Slop"); | ||||
int tcp_always_keepalive = 1; | int tcp_always_keepalive = 1; | ||||
SYSCTL_INT(_net_inet_tcp, OID_AUTO, always_keepalive, CTLFLAG_RW, | SYSCTL_INT(_net_inet_tcp, OID_AUTO, always_keepalive, CTLFLAG_RW, | ||||
&tcp_always_keepalive , 0, "Assume SO_KEEPALIVE on all TCP connections"); | &tcp_always_keepalive , 0, "Assume SO_KEEPALIVE on all TCP connections"); | ||||
int tcp_fast_finwait2_recycle = 0; | int tcp_fast_finwait2_recycle = 0; | ||||
SYSCTL_INT(_net_inet_tcp, OID_AUTO, fast_finwait2_recycle, CTLFLAG_RW, | SYSCTL_INT(_net_inet_tcp, OID_AUTO, fast_finwait2_recycle, CTLFLAG_RW, | ||||
&tcp_fast_finwait2_recycle, 0, | &tcp_fast_finwait2_recycle, 0, | ||||
"Recycle closed FIN_WAIT_2 connections faster"); | "Recycle closed FIN_WAIT_2 connections faster"); | ||||
int tcp_finwait2_timeout; | int tcp_finwait2_timeout; | ||||
SYSCTL_PROC(_net_inet_tcp, OID_AUTO, finwait2_timeout, CTLTYPE_INT|CTLFLAG_RW, | SYSCTL_PROC(_net_inet_tcp, OID_AUTO, finwait2_timeout, CTLTYPE_INT|CTLFLAG_RW, | ||||
&tcp_finwait2_timeout, 0, sysctl_msec_to_ticks, "I", "FIN-WAIT2 timeout"); | &tcp_finwait2_timeout, 0, sysctl_msec_to_ticks, "I", "FIN-WAIT2 timeout"); | ||||
int tcp_keepcnt = TCPTV_KEEPCNT; | int tcp_keepcnt = TCPTV_KEEPCNT; | ||||
▲ Show 20 Lines • Show All 175 Lines • ▼ Show 20 Lines | #endif | ||||
* 2 MSL timeout in shutdown went off. If we're closed but | * 2 MSL timeout in shutdown went off. If we're closed but | ||||
* still waiting for peer to close and connection has been idle | * still waiting for peer to close and connection has been idle | ||||
* too long delete connection control block. Otherwise, check | * too long delete connection control block. Otherwise, check | ||||
* again in a bit. | * again in a bit. | ||||
* | * | ||||
* If in TIME_WAIT state just ignore as this timeout is handled in | * If in TIME_WAIT state just ignore as this timeout is handled in | ||||
* tcp_tw_2msl_scan(). | * tcp_tw_2msl_scan(). | ||||
* | * | ||||
* If fastrecycle of FIN_WAIT_2, in FIN_WAIT_2 and receiver has closed, | * If fastrecycle of FIN_WAIT_2, in FIN_WAIT_2 and receiver has closed, | ||||
* there's no point in hanging onto FIN_WAIT_2 socket. Just close it. | * there's no point in hanging onto FIN_WAIT_2 socket. Just close it. | ||||
* Ignore fact that there were recent incoming segments. | * Ignore fact that there were recent incoming segments. | ||||
*/ | */ | ||||
if ((inp->inp_flags & INP_TIMEWAIT) != 0) { | if ((inp->inp_flags & INP_TIMEWAIT) != 0) { | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
return; | return; | ||||
} | } | ||||
if (tcp_fast_finwait2_recycle && tp->t_state == TCPS_FIN_WAIT_2 && | if (tcp_fast_finwait2_recycle && tp->t_state == TCPS_FIN_WAIT_2 && | ||||
tp->t_inpcb && tp->t_inpcb->inp_socket && | tp->t_inpcb && tp->t_inpcb->inp_socket && | ||||
(tp->t_inpcb->inp_socket->so_rcv.sb_state & SBS_CANTRCVMORE)) { | (tp->t_inpcb->inp_socket->so_rcv.sb_state & SBS_CANTRCVMORE)) { | ||||
TCPSTAT_INC(tcps_finwait2_drops); | TCPSTAT_INC(tcps_finwait2_drops); | ||||
if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { | if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { | ||||
tcp_inpinfo_lock_del(inp, tp); | tcp_inpinfo_lock_del(inp, tp); | ||||
goto out; | goto out; | ||||
} | } | ||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ENTER(et); | ||||
tp = tcp_close(tp); | tp = tcp_close(tp); | ||||
NET_EPOCH_EXIT(et); | NET_EPOCH_EXIT(et); | ||||
tcp_inpinfo_lock_del(inp, tp); | tcp_inpinfo_lock_del(inp, tp); | ||||
goto out; | goto out; | ||||
} else { | } else { | ||||
if (ticks - tp->t_rcvtime <= TP_MAXIDLE(tp)) { | if (ticks - tp->t_rcvtime <= TP_MAXIDLE(tp)) { | ||||
callout_reset(&tp->t_timers->tt_2msl, | callout_reset(&tp->t_timers->tt_2msl, | ||||
TP_KEEPINTVL(tp), tcp_timer_2msl, tp); | TP_KEEPINTVL(tp), tcp_timer_2msl, tp); | ||||
} else { | } else { | ||||
▲ Show 20 Lines • Show All 358 Lines • ▼ Show 20 Lines | if (((tp->t_flags2 & (TF2_PLPMTU_PMTUD|TF2_PLPMTU_MAXSEGSNT)) == | ||||
*/ | */ | ||||
if ((tp->t_flags2 & TF2_PLPMTU_BLACKHOLE) == 0) { | if ((tp->t_flags2 & TF2_PLPMTU_BLACKHOLE) == 0) { | ||||
/* Record that we may have found a black hole. */ | /* Record that we may have found a black hole. */ | ||||
tp->t_flags2 |= TF2_PLPMTU_BLACKHOLE; | tp->t_flags2 |= TF2_PLPMTU_BLACKHOLE; | ||||
/* Keep track of previous MSS. */ | /* Keep track of previous MSS. */ | ||||
tp->t_pmtud_saved_maxseg = tp->t_maxseg; | tp->t_pmtud_saved_maxseg = tp->t_maxseg; | ||||
} | } | ||||
/* | /* | ||||
* Reduce the MSS to blackhole value or to the default | * Reduce the MSS to blackhole value or to the default | ||||
* in an attempt to retransmit. | * in an attempt to retransmit. | ||||
*/ | */ | ||||
#ifdef INET6 | #ifdef INET6 | ||||
isipv6 = (tp->t_inpcb->inp_vflag & INP_IPV6) ? 1 : 0; | isipv6 = (tp->t_inpcb->inp_vflag & INP_IPV6) ? 1 : 0; | ||||
if (isipv6 && | if (isipv6 && | ||||
tp->t_maxseg > V_tcp_v6pmtud_blackhole_mss) { | tp->t_maxseg > V_tcp_v6pmtud_blackhole_mss) { | ||||
/* Use the sysctl tuneable blackhole MSS. */ | /* Use the sysctl tuneable blackhole MSS. */ | ||||
▲ Show 20 Lines • Show All 190 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
/* | /* | ||||
* Stop the timer from running, and apply a flag | * Stop the timer from running, and apply a flag | ||||
* against the timer_flags that will force the | * against the timer_flags that will force the | ||||
* timer never to run. The flag is needed to assure | * timer never to run. The flag is needed to assure | ||||
* a race does not leave it running and cause | * a race does not leave it running and cause | ||||
* the timer to possibly restart itself (keep and persist | * the timer to possibly restart itself (keep and persist | ||||
* especially do this). | * especially do this). | ||||
*/ | */ | ||||
int | int | ||||
tcp_timer_suspend(struct tcpcb *tp, uint32_t timer_type) | tcp_timer_suspend(struct tcpcb *tp, uint32_t timer_type) | ||||
{ | { | ||||
struct callout *t_callout; | struct callout *t_callout; | ||||
uint32_t t_flags; | uint32_t t_flags; | ||||
switch (timer_type) { | switch (timer_type) { | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | case TT_DELACK: | ||||
break; | break; | ||||
case TT_REXMT: | case TT_REXMT: | ||||
if (tp->t_timers->tt_flags & TT_REXMT_SUS) { | if (tp->t_timers->tt_flags & TT_REXMT_SUS) { | ||||
tp->t_timers->tt_flags &= ~TT_REXMT_SUS; | tp->t_timers->tt_flags &= ~TT_REXMT_SUS; | ||||
if (SEQ_GT(tp->snd_max, tp->snd_una) && | if (SEQ_GT(tp->snd_max, tp->snd_una) && | ||||
(tcp_timer_active((tp), TT_PERSIST) == 0) && | (tcp_timer_active((tp), TT_PERSIST) == 0) && | ||||
tp->snd_wnd) { | tp->snd_wnd) { | ||||
/* We have outstanding data activate a timer */ | /* We have outstanding data activate a timer */ | ||||
tcp_timer_activate(tp, TT_REXMT, | tcp_timer_activate(tp, TT_REXMT, | ||||
tp->t_rxtcur); | tp->t_rxtcur); | ||||
} | } | ||||
} | } | ||||
break; | break; | ||||
case TT_PERSIST: | case TT_PERSIST: | ||||
if (tp->t_timers->tt_flags & TT_PERSIST_SUS) { | if (tp->t_timers->tt_flags & TT_PERSIST_SUS) { | ||||
tp->t_timers->tt_flags &= ~TT_PERSIST_SUS; | tp->t_timers->tt_flags &= ~TT_PERSIST_SUS; | ||||
if (tp->snd_wnd == 0) { | if (tp->snd_wnd == 0) { | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | switch (timer_type) { | ||||
case TT_KEEP: | case TT_KEEP: | ||||
t_callout = &tp->t_timers->tt_keep; | t_callout = &tp->t_timers->tt_keep; | ||||
break; | break; | ||||
case TT_2MSL: | case TT_2MSL: | ||||
t_callout = &tp->t_timers->tt_2msl; | t_callout = &tp->t_timers->tt_2msl; | ||||
break; | break; | ||||
default: | default: | ||||
if (tp->t_fb->tfb_tcp_timer_stop) { | if (tp->t_fb->tfb_tcp_timer_stop) { | ||||
/* | /* | ||||
* XXXrrs we need to look at this with the | * XXXrrs we need to look at this with the | ||||
* stop case below (flags). | * stop case below (flags). | ||||
*/ | */ | ||||
tp->t_fb->tfb_tcp_timer_stop(tp, timer_type); | tp->t_fb->tfb_tcp_timer_stop(tp, timer_type); | ||||
return; | return; | ||||
} | } | ||||
panic("tp %p bad timer_type %#x", tp, timer_type); | panic("tp %p bad timer_type %#x", tp, timer_type); | ||||
} | } | ||||
if (callout_async_drain(t_callout, tcp_timer_discard) == 0) { | if (callout_async_drain(t_callout, tcp_timer_discard) == 0) { | ||||
/* | /* | ||||
* Can't stop the callout, defer tcpcb actual deletion | * Can't stop the callout, defer tcpcb actual deletion | ||||
* to the last one. We do this using the async drain | * to the last one. We do this using the async drain | ||||
* function and incrementing the count in | * function and incrementing the count in | ||||
*/ | */ | ||||
tp->t_timers->tt_draincnt++; | tp->t_timers->tt_draincnt++; | ||||
} | } | ||||
} | } |