Hello, I've managed to get pf_test() running in parallel on forwarding path in my experimental tree. And there was some fall out. PF died on ASSERT() in pf_state_key_link_reverse() at line 7371:
7368 pf_state_key_link_reverse(struct pf_state_key *sk, ...) 7369 { 7370 /* Note that sk and skrev may be equal, then we ... */ 7371 KASSERT(sk->reverse == NULL); 7372 KASSERT(skrev->reverse == NULL); 7373 sk->reverse = pf_state_key_ref(skrev); 7374 skrev->reverse = pf_state_key_ref(sk); 7375 } pf_state_key_link_reverse() function is being called from pf_find_state() here: 1074 if (sk == NULL) { 1075 if ((sk = RB_FIND(pf_state_tree, &pf_statetbl, 1076 (struct pf_state_key *)key)) == NULL) 1077 return (PF_DROP); 1078 if (pd->dir == PF_OUT && pkt_sk && 1079 pf_compare_state_keys(pkt_sk, sk, ...) == 0) 1080 pf_state_key_link_reverse(sk, pkt_sk); 1081 else if (pd->dir == PF_OUT && pd->m->m_pkthdr.pf.inp && 1082 !pd->m->m_pkthdr.pf.inp->inp_pf_sk && !sk->inp) 1083 pf_state_key_link_inpcb(sk, pd->m->m_pkt...); 1084 } the pf_find_state() performs a look up to PF state table and as such it runs under PF_STATE_ENTER_READ() lock. So there might be actually more threads running at pf_state_key_link_reverse() function. The thread, which currently loses the race trips the assert in 7371. Patch below uses atomic ops to handle the race properly. OK? thanks and regards sashan --------8<---------------8<---------------8<------------------8<-------- diff --git a/sys/net/pf.c b/sys/net/pf.c index 9e454e5c941..6e2ec19faaa 100644 --- a/sys/net/pf.c +++ b/sys/net/pf.c @@ -7367,11 +7367,20 @@ pf_inp_unlink(struct inpcb *inp) void pf_state_key_link_reverse(struct pf_state_key *sk, struct pf_state_key *skrev) { - /* Note that sk and skrev may be equal, then we refcount twice. */ - KASSERT(sk->reverse == NULL); - KASSERT(skrev->reverse == NULL); - sk->reverse = pf_state_key_ref(skrev); - skrev->reverse = pf_state_key_ref(sk); + struct pf_state_key *old_reverse; + + old_reverse = atomic_cas_ptr(&sk->reverse, NULL, skrev); + if (old_reverse != NULL) + KASSERT(old_reverse == skrev); + else + pf_state_key_ref(skrev); + + + old_reverse = atomic_cas_ptr(&skrev->reverse, NULL, sk); + if (old_reverse != NULL) + KASSERT(old_reverse == sk); + else + pf_state_key_ref(sk); } #if NPFLOG > 0