Skip to content

Commit

Permalink
tcp_hpts: let tcp_hpts_init() set a random CPU only once
Browse files Browse the repository at this point in the history
After d2ef52e the tcp_hpts_init() function can be called multiple
times on a tcpcb if it is switched there and back between two TCP stacks.
First, this makes existing assertion in tcp_hpts_init() incorrect.  Second,
it creates possibility to change a randomly set t_hpts_cpu to a different
random value, while a tcpcb is already in the HPTS wheel, triggering other
assertions later in tcp_hptsi().

The best approach here would be to work on the stacks to really clear a
tcpcb out of HPTS wheel in tfb_tcp_fb_fini, draining the IHPTS_MOVING
state.  But that's pretty intrusive change, so let's just get back to the
old logic (pre d2ef52e) where t_hpts_cpu was set to a random value
only once in a CPU lifetime and a newly switched stack inherits t_hpts_cpu
from the previous stack.

Reviewed by:		rrs, tuexen
Differential Revision:	https://reviews.freebsd.org/D42946
Reported-by:	syzbot+fab29fe1ab089c52998d@syzkaller.appspotmail.com
Reported-by:	syzbot+ca5f2aa0fda15dcfe6d7@syzkaller.appspotmail.com
Fixes:		2b3a774
  • Loading branch information
glebius committed Dec 7, 2023
1 parent ade05d6 commit 3f46be6
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 4 deletions.
16 changes: 12 additions & 4 deletions sys/netinet/tcp_hpts.c
Expand Up @@ -542,15 +542,23 @@ tcp_hpts_release(struct tcpcb *tp)
}

/*
* Initialize newborn tcpcb to get ready for use with HPTS.
* Initialize tcpcb to get ready for use with HPTS. We will know which CPU
* is preferred on the first incoming packet. Before that avoid crowding
* a single CPU with newborn connections and use a random one.
* This initialization is normally called on a newborn tcpcb, but potentially
* can be called once again if stack is switched. In that case we inherit CPU
* that the previous stack has set, be it random or not. In extreme cases,
* e.g. syzkaller fuzzing, a tcpcb can already be in HPTS in IHPTS_MOVING state
* and has never received a first packet.
*/
void
tcp_hpts_init(struct tcpcb *tp)
{

tp->t_hpts_cpu = hpts_random_cpu();
tp->t_lro_cpu = HPTS_CPU_NONE;
MPASS(!(tp->t_flags2 & TF2_HPTS_CPU_SET));
if (__predict_true(tp->t_hpts_cpu == HPTS_CPU_NONE)) {
tp->t_hpts_cpu = hpts_random_cpu();
MPASS(!(tp->t_flags2 & TF2_HPTS_CPU_SET));
}
}

/*
Expand Down
3 changes: 3 additions & 0 deletions sys/netinet/tcp_subr.c
Expand Up @@ -2274,6 +2274,9 @@ tcp_newtcpcb(struct inpcb *inp)
/* All mbuf queue/ack compress flags should be off */
tcp_lro_features_off(tp);

tp->t_hpts_cpu = HPTS_CPU_NONE;
tp->t_lro_cpu = HPTS_CPU_NONE;

callout_init_rw(&tp->t_callout, &inp->inp_lock, CALLOUT_RETURNUNLOCKED);
for (int i = 0; i < TT_N; i++)
tp->t_timers[i] = SBT_MAX;
Expand Down

0 comments on commit 3f46be6

Please sign in to comment.