On Tue, Jun 04, 2019 at 01:50:51AM +0200, Alexandr Nedvedicky wrote:
> 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.

Does this mean you're ending up with packets from a single flow being processed
on multiple threads at the same time?

> 
> 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
> 

Reply via email to