Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/tcp_timer.c
Show First 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | |||||
#include <netinet6/in6_pcb.h> | #include <netinet6/in6_pcb.h> | ||||
#endif | #endif | ||||
#include <netinet/ip_var.h> | #include <netinet/ip_var.h> | ||||
#include <netinet/tcp.h> | #include <netinet/tcp.h> | ||||
#include <netinet/tcp_fsm.h> | #include <netinet/tcp_fsm.h> | ||||
#include <netinet/tcp_log_buf.h> | #include <netinet/tcp_log_buf.h> | ||||
#include <netinet/tcp_timer.h> | #include <netinet/tcp_timer.h> | ||||
#include <netinet/tcp_var.h> | #include <netinet/tcp_var.h> | ||||
#include <netinet/tcp_seq.h> | |||||
#include <netinet/cc/cc.h> | #include <netinet/cc/cc.h> | ||||
#ifdef INET6 | #ifdef INET6 | ||||
#include <netinet6/tcp6_var.h> | #include <netinet6/tcp6_var.h> | ||||
#endif | #endif | ||||
#include <netinet/tcpip.h> | #include <netinet/tcpip.h> | ||||
#ifdef TCPDEBUG | #ifdef TCPDEBUG | ||||
#include <netinet/tcp_debug.h> | #include <netinet/tcp_debug.h> | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 302 Lines • ▼ Show 20 Lines | if (tcp_fast_finwait2_recycle && tp->t_state == TCPS_FIN_WAIT_2 && | ||||
if (tcp_inpinfo_lock_add(inp)) { | if (tcp_inpinfo_lock_add(inp)) { | ||||
tcp_inpinfo_lock_del(inp, tp); | tcp_inpinfo_lock_del(inp, tp); | ||||
goto out; | goto out; | ||||
} | } | ||||
tp = tcp_close(tp); | tp = tcp_close(tp); | ||||
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 (tcp_ts_getsbintime() - 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 { | ||||
if (tcp_inpinfo_lock_add(inp)) { | if (tcp_inpinfo_lock_add(inp)) { | ||||
tcp_inpinfo_lock_del(inp, tp); | tcp_inpinfo_lock_del(inp, tp); | ||||
goto out; | goto out; | ||||
} | } | ||||
tp = tcp_close(tp); | tp = tcp_close(tp); | ||||
▲ Show 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | #endif | ||||
* or drop connection if idle for too long. | * or drop connection if idle for too long. | ||||
*/ | */ | ||||
TCPSTAT_INC(tcps_keeptimeo); | TCPSTAT_INC(tcps_keeptimeo); | ||||
if (tp->t_state < TCPS_ESTABLISHED) | if (tp->t_state < TCPS_ESTABLISHED) | ||||
goto dropit; | goto dropit; | ||||
if ((tcp_always_keepalive || | if ((tcp_always_keepalive || | ||||
inp->inp_socket->so_options & SO_KEEPALIVE) && | inp->inp_socket->so_options & SO_KEEPALIVE) && | ||||
tp->t_state <= TCPS_CLOSING) { | tp->t_state <= TCPS_CLOSING) { | ||||
if (ticks - tp->t_rcvtime >= TP_KEEPIDLE(tp) + TP_MAXIDLE(tp)) | if (tcp_ts_getsbintime() - tp->t_rcvtime >= TP_KEEPIDLE(tp) + TP_MAXIDLE(tp)) | ||||
goto dropit; | goto dropit; | ||||
/* | /* | ||||
* Send a packet designed to force a response | * Send a packet designed to force a response | ||||
* if the peer is up and reachable: | * if the peer is up and reachable: | ||||
* either an ACK if the connection is still alive, | * either an ACK if the connection is still alive, | ||||
* or an RST if the peer has closed the connection | * or an RST if the peer has closed the connection | ||||
* due to timeout or reboot. | * due to timeout or reboot. | ||||
* Using sequence number tp->snd_una-1 | * Using sequence number tp->snd_una-1 | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | out: | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
} | } | ||||
void | void | ||||
tcp_timer_persist(void *xtp) | tcp_timer_persist(void *xtp) | ||||
{ | { | ||||
struct tcpcb *tp = xtp; | struct tcpcb *tp = xtp; | ||||
struct inpcb *inp; | struct inpcb *inp; | ||||
sbintime_t dt; | |||||
CURVNET_SET(tp->t_vnet); | CURVNET_SET(tp->t_vnet); | ||||
#ifdef TCPDEBUG | #ifdef TCPDEBUG | ||||
int ostate; | int ostate; | ||||
ostate = tp->t_state; | ostate = tp->t_state; | ||||
#endif | #endif | ||||
inp = tp->t_inpcb; | inp = tp->t_inpcb; | ||||
KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp)); | KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp)); | ||||
Show All 19 Lines | #endif | ||||
TCPSTAT_INC(tcps_persisttimeo); | TCPSTAT_INC(tcps_persisttimeo); | ||||
/* | /* | ||||
* Hack: if the peer is dead/unreachable, we do not | * Hack: if the peer is dead/unreachable, we do not | ||||
* time out if the window is closed. After a full | * time out if the window is closed. After a full | ||||
* backoff, drop the connection if the idle time | * backoff, drop the connection if the idle time | ||||
* (no responses to probes) reaches the maximum | * (no responses to probes) reaches the maximum | ||||
* backoff that we would use if retransmitting. | * backoff that we would use if retransmitting. | ||||
*/ | */ | ||||
dt = tcp_ts_getsbintime() - tp->t_rcvtime; | |||||
if (tp->t_rxtshift == TCP_MAXRXTSHIFT && | if (tp->t_rxtshift == TCP_MAXRXTSHIFT && | ||||
(ticks - tp->t_rcvtime >= tcp_maxpersistidle || | (dt >= tcp_maxpersistidle*tick_sbt || | ||||
ticks - tp->t_rcvtime >= TCP_REXMTVAL(tp) * tcp_totbackoff)) { | dt >= TCP_REXMTVAL(tp) * tcp_totbackoff)) { | ||||
TCPSTAT_INC(tcps_persistdrop); | TCPSTAT_INC(tcps_persistdrop); | ||||
if (tcp_inpinfo_lock_add(inp)) { | if (tcp_inpinfo_lock_add(inp)) { | ||||
tcp_inpinfo_lock_del(inp, tp); | tcp_inpinfo_lock_del(inp, tp); | ||||
goto out; | goto out; | ||||
} | } | ||||
tp = tcp_drop(tp, ETIMEDOUT); | tp = tcp_drop(tp, ETIMEDOUT); | ||||
tcp_inpinfo_lock_del(inp, tp); | tcp_inpinfo_lock_del(inp, tp); | ||||
goto out; | goto out; | ||||
▲ Show 20 Lines • Show All 101 Lines • ▼ Show 20 Lines | if (tp->t_state == TCPS_SYN_SENT) { | ||||
if (IN_FASTRECOVERY(tp->t_flags)) | if (IN_FASTRECOVERY(tp->t_flags)) | ||||
tp->t_flags |= TF_WASFRECOVERY; | tp->t_flags |= TF_WASFRECOVERY; | ||||
else | else | ||||
tp->t_flags &= ~TF_WASFRECOVERY; | tp->t_flags &= ~TF_WASFRECOVERY; | ||||
if (IN_CONGRECOVERY(tp->t_flags)) | if (IN_CONGRECOVERY(tp->t_flags)) | ||||
tp->t_flags |= TF_WASCRECOVERY; | tp->t_flags |= TF_WASCRECOVERY; | ||||
else | else | ||||
tp->t_flags &= ~TF_WASCRECOVERY; | tp->t_flags &= ~TF_WASCRECOVERY; | ||||
tp->t_badrxtwin = ticks + (tp->t_srtt >> (TCP_RTT_SHIFT + 1)); | tp->t_badrxtwin = tcp_ts_getsbintime() + tp->t_rxtcur; | ||||
tp->t_flags |= TF_PREVVALID; | tp->t_flags |= TF_PREVVALID; | ||||
} else | } else | ||||
tp->t_flags &= ~TF_PREVVALID; | tp->t_flags &= ~TF_PREVVALID; | ||||
TCPSTAT_INC(tcps_rexmttimeo); | TCPSTAT_INC(tcps_rexmttimeo); | ||||
if ((tp->t_state == TCPS_SYN_SENT) || | if ((tp->t_state == TCPS_SYN_SENT) || | ||||
(tp->t_state == TCPS_SYN_RECEIVED)) | (tp->t_state == TCPS_SYN_RECEIVED)) | ||||
rexmt = TCPTV_RTOBASE * tcp_syn_backoff[tp->t_rxtshift]; | rexmt = TCPTV_RTOBASE * tcp_syn_backoff[tp->t_rxtshift] * tick_sbt; | ||||
else | else | ||||
rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift]; | rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift]; | ||||
/* 1 < delack < tcp_delacktime - and should scale down with RTO/2 */ | |||||
TCPT_RANGESET(tp->t_rxtcur, rexmt, | TCPT_RANGESET(tp->t_rxtcur, rexmt, | ||||
tp->t_rttmin, TCPTV_REXMTMAX); | tp->t_rttmin, TCPTV_REXMTMAX*tick_sbt); | ||||
/* | /* | ||||
* We enter the path for PLMTUD if connection is established or, if | * We enter the path for PLMTUD if connection is established or, if | ||||
* connection is FIN_WAIT_1 status, reason for the last is that if | * connection is FIN_WAIT_1 status, reason for the last is that if | ||||
* amount of data we send is very small, we could send it in couple of | * amount of data we send is very small, we could send it in couple of | ||||
* packets and process straight to FIN. In that case we won't catch | * packets and process straight to FIN. In that case we won't catch | ||||
* ESTABLISHED state. | * ESTABLISHED state. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 142 Lines • ▼ Show 20 Lines | |||||
#endif | #endif | ||||
TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); | TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
out: | out: | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
} | } | ||||
void | void | ||||
tcp_timer_activate(struct tcpcb *tp, uint32_t timer_type, u_int delta) | tcp_timer_activate(struct tcpcb *tp, uint32_t timer_type, sbintime_t delta) | ||||
{ | { | ||||
struct callout *t_callout; | struct callout *t_callout; | ||||
timeout_t *f_callout; | timeout_t *f_callout; | ||||
struct inpcb *inp = tp->t_inpcb; | struct inpcb *inp = tp->t_inpcb; | ||||
int cpu = inp_to_cpuid(inp); | int cpu = inp_to_cpuid(inp); | ||||
sbintime_t f_precision; | |||||
#ifdef TCP_OFFLOAD | #ifdef TCP_OFFLOAD | ||||
if (tp->t_flags & TF_TOE) | if (tp->t_flags & TF_TOE) | ||||
return; | return; | ||||
#endif | #endif | ||||
if (tp->t_timers->tt_flags & TT_STOPPED) | if (tp->t_timers->tt_flags & TT_STOPPED) | ||||
return; | return; | ||||
switch (timer_type) { | switch (timer_type) { | ||||
case TT_DELACK: | case TT_DELACK: | ||||
t_callout = &tp->t_timers->tt_delack; | t_callout = &tp->t_timers->tt_delack; | ||||
f_callout = tcp_timer_delack; | f_callout = tcp_timer_delack; | ||||
f_precision = SBT_1MS; | |||||
break; | break; | ||||
case TT_REXMT: | case TT_REXMT: | ||||
t_callout = &tp->t_timers->tt_rexmt; | t_callout = &tp->t_timers->tt_rexmt; | ||||
f_callout = tcp_timer_rexmt; | f_callout = tcp_timer_rexmt; | ||||
f_precision = SBT_1US; | |||||
break; | break; | ||||
case TT_PERSIST: | case TT_PERSIST: | ||||
t_callout = &tp->t_timers->tt_persist; | t_callout = &tp->t_timers->tt_persist; | ||||
f_callout = tcp_timer_persist; | f_callout = tcp_timer_persist; | ||||
f_precision = SBT_1S; | |||||
break; | break; | ||||
case TT_KEEP: | case TT_KEEP: | ||||
t_callout = &tp->t_timers->tt_keep; | t_callout = &tp->t_timers->tt_keep; | ||||
f_callout = tcp_timer_keep; | f_callout = tcp_timer_keep; | ||||
f_precision = SBT_1S; | |||||
break; | break; | ||||
case TT_2MSL: | case TT_2MSL: | ||||
t_callout = &tp->t_timers->tt_2msl; | t_callout = &tp->t_timers->tt_2msl; | ||||
f_callout = tcp_timer_2msl; | f_callout = tcp_timer_2msl; | ||||
f_precision = SBT_1S; | |||||
break; | break; | ||||
default: | default: | ||||
if (tp->t_fb->tfb_tcp_timer_activate) { | if (tp->t_fb->tfb_tcp_timer_activate) { | ||||
tp->t_fb->tfb_tcp_timer_activate(tp, timer_type, delta); | tp->t_fb->tfb_tcp_timer_activate(tp, timer_type, delta); | ||||
return; | return; | ||||
} | } | ||||
panic("tp %p bad timer_type %#x", tp, timer_type); | panic("tp %p bad timer_type %#x", tp, timer_type); | ||||
} | } | ||||
if (delta == 0) { | if (delta == 0) { | ||||
callout_stop(t_callout); | callout_stop(t_callout); | ||||
} else { | } else { | ||||
callout_reset_on(t_callout, delta, f_callout, tp, cpu); | callout_reset_sbt_on(t_callout, delta, f_precision, f_callout, tp, cpu, 0); | ||||
} | } | ||||
} | } | ||||
int | int | ||||
tcp_timer_active(struct tcpcb *tp, uint32_t timer_type) | tcp_timer_active(struct tcpcb *tp, uint32_t timer_type) | ||||
{ | { | ||||
struct callout *t_callout; | struct callout *t_callout; | ||||
▲ Show 20 Lines • Show All 68 Lines • Show Last 20 Lines |