The code currently resets the keepalive timer each time a packet is
received on a TCP session that has entered the ESTABLISHED state. This results in a lot of calls to reset the keepalive timer. This patch changes the behavior so we set the keepalive timer for the keepalive idle time (TP_KEEPIDLE). When the keepalive timer fires, it will first check to see if the session has been idle for TP_KEEPIDLE ticks. If not, it will reschedule the keepalive timer for the time the session will have been idle for TP_KEEPIDLE ticks. For a session with regular communication, the keepalive timer should fire approximately once every TP_KEEPIDLE ticks. For sessions with irregular communication, the keepalive timer might fire more often. But, the disruption from a periodic keepalive timer should be less than the regular cost of resetting the keepalive timer on every packet. (FWIW, this change saved approximately 1.73% of the busy CPU cycles on a particular test system with a heavy TCP output load. Of course, the actual impact is very specific to the particular hardware and workload.) Reviewed by: gallatin, rrs MFC after: 2 weeks Sponsored by: Netflix Differential Revision: https://reviews.freebsd.org/D8243
This commit is contained in:
parent
1899e205d1
commit
6d172f58a2
@ -1565,8 +1565,6 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
|
||||
* validation to ignore broken/spoofed segs.
|
||||
*/
|
||||
tp->t_rcvtime = ticks;
|
||||
if (TCPS_HAVEESTABLISHED(tp->t_state))
|
||||
tcp_timer_activate(tp, TT_KEEP, TP_KEEPIDLE(tp));
|
||||
|
||||
/*
|
||||
* Scale up the window into a 32-bit value.
|
||||
|
@ -1819,8 +1819,6 @@ tcp_do_segment_fastslow(struct mbuf *m, struct tcphdr *th, struct socket *so,
|
||||
* validation to ignore broken/spoofed segs.
|
||||
*/
|
||||
tp->t_rcvtime = ticks;
|
||||
if (TCPS_HAVEESTABLISHED(tp->t_state))
|
||||
tcp_timer_activate(tp, TT_KEEP, TP_KEEPIDLE(tp));
|
||||
|
||||
/*
|
||||
* Unscale the window into a 32-bit value.
|
||||
@ -2266,8 +2264,6 @@ tcp_do_segment_fastack(struct mbuf *m, struct tcphdr *th, struct socket *so,
|
||||
* validation to ignore broken/spoofed segs.
|
||||
*/
|
||||
tp->t_rcvtime = ticks;
|
||||
if (TCPS_HAVEESTABLISHED(tp->t_state))
|
||||
tcp_timer_activate(tp, TT_KEEP, TP_KEEPIDLE(tp));
|
||||
|
||||
/*
|
||||
* Unscale the window into a 32-bit value.
|
||||
|
@ -468,6 +468,26 @@ tcp_timer_keep(void *xtp)
|
||||
}
|
||||
KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0,
|
||||
("%s: tp %p tcpcb can't be stopped here", __func__, tp));
|
||||
|
||||
/*
|
||||
* Because we don't regularly reset the keepalive callout in
|
||||
* the ESTABLISHED state, it may be that we don't actually need
|
||||
* to send a keepalive yet. If that occurs, schedule another
|
||||
* call for the next time the keepalive timer might expire.
|
||||
*/
|
||||
if (TCPS_HAVEESTABLISHED(tp->t_state)) {
|
||||
u_int idletime;
|
||||
|
||||
idletime = ticks - tp->t_rcvtime;
|
||||
if (idletime < TP_KEEPIDLE(tp)) {
|
||||
callout_reset(&tp->t_timers->tt_keep,
|
||||
TP_KEEPIDLE(tp) - idletime, tcp_timer_keep, tp);
|
||||
INP_WUNLOCK(inp);
|
||||
CURVNET_RESTORE();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Keep-alive timer went off; send something
|
||||
* or drop connection if idle for too long.
|
||||
|
Loading…
Reference in New Issue
Block a user