hello,

On 2023-12-08 15:09, Vitaliy Makkoveev wrote:
> On Thu, Dec 07, 2023 at 11:58:31PM -0500, Johan Huldtgren wrote:
> > hello,
> > 
>       [skip]
> > 
> > Would this apply against 7.4 or only -current? Machine is currently
> > running 7.4+syspatches (and sashan@ patch from earlier in this thread)
> > if I need to get on -current that's not a big deal it would just take
> > a few more days once I get back home tomorrow.
> > 
> > thanks,
> > 
> > .jh
> > 
> 
> Hi,
> 
> No, this diff is applicable for -CURRENT only. The diff below can be
> applied to 7.4. It also contains timeout(9) related hunks from 
> -CURRENT, but they can be assumed as non functional change.

I'm now running 7.4+syspatches and the below patch, I'll let you know
if I see any recurrence of the issue.

thanks,

.jh

> Index: sys/net/if_pflow.c
> ===================================================================
> RCS file: /cvs/src/sys/net/if_pflow.c,v
> retrieving revision 1.99
> diff -u -p -r1.99 if_pflow.c
> --- sys/net/if_pflow.c        13 Apr 2023 02:19:05 -0000      1.99
> +++ sys/net/if_pflow.c        8 Dec 2023 11:59:09 -0000
> @@ -29,6 +29,7 @@
>  #include <sys/kernel.h>
>  #include <sys/socketvar.h>
>  #include <sys/sysctl.h>
> +#include <sys/mutex.h>
>  
>  #include <net/if.h>
>  #include <net/if_types.h>
> @@ -71,7 +72,6 @@ void        pflow_output_process(void *);
>  int  pflow_clone_create(struct if_clone *, int);
>  int  pflow_clone_destroy(struct ifnet *);
>  int  pflow_set(struct pflow_softc *, struct pflowreq *);
> -void pflow_init_timeouts(struct pflow_softc *);
>  int  pflow_calc_mtu(struct pflow_softc *, int, int);
>  void pflow_setmtu(struct pflow_softc *, int);
>  int  pflowvalidsockaddr(const struct sockaddr *, int);
> @@ -148,6 +148,7 @@ pflow_clone_create(struct if_clone *ifc,
>  
>       pflowif = malloc(sizeof(*pflowif), M_DEVBUF, M_WAITOK|M_ZERO);
>       rw_init(&pflowif->sc_lock, "pflowlk");
> +     mtx_init(&pflowif->sc_mtx, IPL_MPFLOOR);
>       MGET(pflowif->send_nam, M_WAIT, MT_SONAME);
>       pflowif->sc_version = PFLOW_PROTO_DEFAULT;
>  
> @@ -255,7 +256,11 @@ pflow_clone_create(struct if_clone *ifc,
>       ifp->if_flags &= ~IFF_RUNNING;  /* not running, need receiver */
>       mq_init(&pflowif->sc_outputqueue, 8192, IPL_SOFTNET);
>       pflow_setmtu(pflowif, ETHERMTU);
> -     pflow_init_timeouts(pflowif);
> +
> +     timeout_set_proc(&pflowif->sc_tmo, pflow_timeout, pflowif);
> +     timeout_set_proc(&pflowif->sc_tmo6, pflow_timeout6, pflowif);
> +     timeout_set_proc(&pflowif->sc_tmo_tmpl, pflow_timeout_tmpl, pflowif);
> +
>       if_counters_alloc(ifp);
>       if_attach(ifp);
>       if_alloc_sadl(ifp);
> @@ -282,12 +287,10 @@ pflow_clone_destroy(struct ifnet *ifp)
>       SLIST_REMOVE(&pflowif_list, sc, pflow_softc, sc_next);
>       NET_UNLOCK();
>  
> -     if (timeout_initialized(&sc->sc_tmo))
> -             timeout_del(&sc->sc_tmo);
> -     if (timeout_initialized(&sc->sc_tmo6))
> -             timeout_del(&sc->sc_tmo6);
> -     if (timeout_initialized(&sc->sc_tmo_tmpl))
> -             timeout_del(&sc->sc_tmo_tmpl);
> +     timeout_del(&sc->sc_tmo);
> +     timeout_del(&sc->sc_tmo6);
> +     timeout_del(&sc->sc_tmo_tmpl);
> +
>       pflow_flush(sc);
>       task_del(net_tq(ifp->if_index), &sc->sc_outputtask);
>       taskq_barrier(net_tq(ifp->if_index));
> @@ -346,6 +349,8 @@ pflow_set(struct pflow_softc *sc, struct
>               }
>       }
>  
> +     rw_assert_wrlock(&sc->sc_lock);
> +
>       pflow_flush(sc);
>  
>       if (pflowr->addrmask & PFLOW_MASK_DSTIP) {
> @@ -460,12 +465,27 @@ pflow_set(struct pflow_softc *sc, struct
>               sc->so = NULL;
>       }
>  
> +     mtx_enter(&sc->sc_mtx);
> +
>       /* error check is above */
>       if (pflowr->addrmask & PFLOW_MASK_VERSION)
>               sc->sc_version = pflowr->version;
>  
>       pflow_setmtu(sc, ETHERMTU);
> -     pflow_init_timeouts(sc);
> +
> +     switch (sc->sc_version) {
> +     case PFLOW_PROTO_5:
> +             timeout_del(&sc->sc_tmo6);
> +             timeout_del(&sc->sc_tmo_tmpl);
> +             break;
> +     case PFLOW_PROTO_10:
> +             timeout_add_sec(&sc->sc_tmo_tmpl, PFLOW_TMPL_TIMEOUT);
> +             break;
> +     default: /* NOTREACHED */
> +             break;
> +     }
> +
> +     mtx_leave(&sc->sc_mtx);
>  
>       return (0);
>  }
> @@ -492,10 +512,12 @@ pflowioctl(struct ifnet *ifp, u_long cmd
>               NET_LOCK();
>               if ((ifp->if_flags & IFF_UP) && sc->so != NULL) {
>                       ifp->if_flags |= IFF_RUNNING;
> +                     mtx_enter(&sc->sc_mtx);
>                       sc->sc_gcounter=pflowstats.pflow_flows;
>                       /* send templates on startup */
>                       if (sc->sc_version == PFLOW_PROTO_10)
>                               pflow_sendout_ipfix_tmpl(sc);
> +                     mtx_leave(&sc->sc_mtx);
>               } else
>                       ifp->if_flags &= ~IFF_RUNNING;
>               rw_exit_read(&sc->sc_lock);
> @@ -507,19 +529,28 @@ pflowioctl(struct ifnet *ifp, u_long cmd
>                       ifr->ifr_mtu = MCLBYTES;
>               if (ifr->ifr_mtu < ifp->if_mtu)
>                       pflow_flush(sc);
> +             mtx_enter(&sc->sc_mtx);
>               pflow_setmtu(sc, ifr->ifr_mtu);
> +             mtx_leave(&sc->sc_mtx);
>               break;
>  
>       case SIOCGETPFLOW:
>               bzero(&pflowr, sizeof(pflowr));
>  
> +             /* XXXSMP: enforce lock order */
> +             NET_UNLOCK();
> +             rw_enter_read(&sc->sc_lock);
> +             NET_LOCK();
>               if (sc->sc_flowsrc != NULL)
>                       memcpy(&pflowr.flowsrc, sc->sc_flowsrc,
>                           sc->sc_flowsrc->sa_len);
>               if (sc->sc_flowdst != NULL)
>                       memcpy(&pflowr.flowdst, sc->sc_flowdst,
>                           sc->sc_flowdst->sa_len);
> +             rw_exit_read(&sc->sc_lock);
> +             mtx_enter(&sc->sc_mtx);
>               pflowr.version = sc->sc_version;
> +             mtx_leave(&sc->sc_mtx);
>  
>               if ((error = copyout(&pflowr, ifr->ifr_data,
>                   sizeof(pflowr))))
> @@ -545,9 +576,11 @@ pflowioctl(struct ifnet *ifp, u_long cmd
>  
>               if ((ifp->if_flags & IFF_UP) && sc->so != NULL) {
>                       ifp->if_flags |= IFF_RUNNING;
> +                     mtx_enter(&sc->sc_mtx);
>                       sc->sc_gcounter=pflowstats.pflow_flows;
>                       if (sc->sc_version == PFLOW_PROTO_10)
>                               pflow_sendout_ipfix_tmpl(sc);
> +                     mtx_leave(&sc->sc_mtx);
>               } else
>                       ifp->if_flags &= ~IFF_RUNNING;
>               rw_exit_write(&sc->sc_lock);
> @@ -560,38 +593,9 @@ pflowioctl(struct ifnet *ifp, u_long cmd
>       return (0);
>  }
>  
> -void
> -pflow_init_timeouts(struct pflow_softc *sc)
> -{
> -     switch (sc->sc_version) {
> -     case PFLOW_PROTO_5:
> -             if (timeout_initialized(&sc->sc_tmo6))
> -                     timeout_del(&sc->sc_tmo6);
> -             if (timeout_initialized(&sc->sc_tmo_tmpl))
> -                     timeout_del(&sc->sc_tmo_tmpl);
> -             if (!timeout_initialized(&sc->sc_tmo))
> -                     timeout_set_proc(&sc->sc_tmo, pflow_timeout, sc);
> -             break;
> -     case PFLOW_PROTO_10:
> -             if (!timeout_initialized(&sc->sc_tmo_tmpl))
> -                     timeout_set_proc(&sc->sc_tmo_tmpl, pflow_timeout_tmpl,
> -                         sc);
> -             if (!timeout_initialized(&sc->sc_tmo))
> -                     timeout_set_proc(&sc->sc_tmo, pflow_timeout, sc);
> -             if (!timeout_initialized(&sc->sc_tmo6))
> -                     timeout_set_proc(&sc->sc_tmo6, pflow_timeout6, sc);
> -
> -             timeout_add_sec(&sc->sc_tmo_tmpl, PFLOW_TMPL_TIMEOUT);
> -             break;
> -     default: /* NOTREACHED */
> -             break;
> -     }
> -}
> -
>  int
>  pflow_calc_mtu(struct pflow_softc *sc, int mtu, int hdrsz)
>  {
> -
>       sc->sc_maxcount4 = (mtu - hdrsz -
>           sizeof(struct udpiphdr)) / sizeof(struct pflow_ipfix_flow4);
>       sc->sc_maxcount6 = (mtu - hdrsz -
> @@ -638,6 +642,8 @@ pflow_get_mbuf(struct pflow_softc *sc, u
>       struct pflow_header      h;
>       struct mbuf             *m;
>  
> +     MUTEX_ASSERT_LOCKED(&sc->sc_mtx);
> +
>       MGETHDR(m, M_DONTWAIT, MT_DATA);
>       if (m == NULL) {
>               pflowstats.pflow_onomem++;
> @@ -807,6 +813,7 @@ export_pflow(struct pf_state *st)
>       sk = st->key[st->direction == PF_IN ? PF_SK_WIRE : PF_SK_STACK];
>  
>       SLIST_FOREACH(sc, &pflowif_list, sc_next) {
> +             mtx_enter(&sc->sc_mtx);
>               switch (sc->sc_version) {
>               case PFLOW_PROTO_5:
>                       if( sk->af == AF_INET )
> @@ -819,6 +826,7 @@ export_pflow(struct pf_state *st)
>               default: /* NOTREACHED */
>                       break;
>               }
> +             mtx_leave(&sc->sc_mtx);
>       }
>  
>       return (0);
> @@ -880,6 +888,8 @@ copy_flow_to_m(struct pflow_flow *flow, 
>  {
>       int             ret = 0;
>  
> +     MUTEX_ASSERT_LOCKED(&sc->sc_mtx);
> +
>       if (sc->sc_mbuf == NULL) {
>               if ((sc->sc_mbuf = pflow_get_mbuf(sc, 0)) == NULL)
>                       return (ENOBUFS);
> @@ -904,6 +914,8 @@ copy_flow_ipfix_4_to_m(struct pflow_ipfi
>  {
>       int             ret = 0;
>  
> +     MUTEX_ASSERT_LOCKED(&sc->sc_mtx);
> +
>       if (sc->sc_mbuf == NULL) {
>               if ((sc->sc_mbuf =
>                   pflow_get_mbuf(sc, PFLOW_IPFIX_TMPL_IPV4_ID)) == NULL) {
> @@ -931,6 +943,8 @@ copy_flow_ipfix_6_to_m(struct pflow_ipfi
>  {
>       int             ret = 0;
>  
> +     MUTEX_ASSERT_LOCKED(&sc->sc_mtx);
> +
>       if (sc->sc_mbuf6 == NULL) {
>               if ((sc->sc_mbuf6 =
>                   pflow_get_mbuf(sc, PFLOW_IPFIX_TMPL_IPV6_ID)) == NULL) {
> @@ -1027,6 +1041,7 @@ pflow_timeout(void *v)
>  {
>       struct pflow_softc      *sc = v;
>  
> +     mtx_enter(&sc->sc_mtx);
>       switch (sc->sc_version) {
>       case PFLOW_PROTO_5:
>               pflow_sendout_v5(sc);
> @@ -1037,6 +1052,7 @@ pflow_timeout(void *v)
>       default: /* NOTREACHED */
>               break;
>       }
> +     mtx_leave(&sc->sc_mtx);
>  }
>  
>  void
> @@ -1044,7 +1060,9 @@ pflow_timeout6(void *v)
>  {
>       struct pflow_softc      *sc = v;
>  
> +     mtx_enter(&sc->sc_mtx);
>       pflow_sendout_ipfix(sc, AF_INET6);
> +     mtx_leave(&sc->sc_mtx);
>  }
>  
>  void
> @@ -1052,12 +1070,15 @@ pflow_timeout_tmpl(void *v)
>  {
>       struct pflow_softc      *sc = v;
>  
> +     mtx_enter(&sc->sc_mtx);
>       pflow_sendout_ipfix_tmpl(sc);
> +     mtx_leave(&sc->sc_mtx);
>  }
>  
>  void
>  pflow_flush(struct pflow_softc *sc)
>  {
> +     mtx_enter(&sc->sc_mtx);
>       switch (sc->sc_version) {
>       case PFLOW_PROTO_5:
>               pflow_sendout_v5(sc);
> @@ -1069,6 +1090,7 @@ pflow_flush(struct pflow_softc *sc)
>       default: /* NOTREACHED */
>               break;
>       }
> +     mtx_leave(&sc->sc_mtx);
>  }
>  
>  int
> @@ -1079,6 +1101,8 @@ pflow_sendout_v5(struct pflow_softc *sc)
>       struct ifnet            *ifp = &sc->sc_if;
>       struct timespec         tv;
>  
> +     MUTEX_ASSERT_LOCKED(&sc->sc_mtx);
> +
>       timeout_del(&sc->sc_tmo);
>  
>       if (m == NULL)
> @@ -1115,6 +1139,8 @@ pflow_sendout_ipfix(struct pflow_softc *
>       u_int32_t                        count;
>       int                              set_length;
>  
> +     MUTEX_ASSERT_LOCKED(&sc->sc_mtx);
> +
>       switch (af) {
>       case AF_INET:
>               m = sc->sc_mbuf;
> @@ -1174,12 +1200,14 @@ pflow_sendout_ipfix_tmpl(struct pflow_so
>       struct pflow_v10_header         *h10;
>       struct ifnet                    *ifp = &sc->sc_if;
>  
> +     MUTEX_ASSERT_LOCKED(&sc->sc_mtx);
> +
>       timeout_del(&sc->sc_tmo_tmpl);
>  
>       if (!(ifp->if_flags & IFF_RUNNING)) {
>               return (0);
>       }
> -     m = pflow_get_mbuf(NULL, 0);
> +     m = pflow_get_mbuf(sc, 0);
>       if (m == NULL)
>               return (0);
>       if (m_copyback(m, 0, sizeof(struct pflow_ipfix_tmpl),
> @@ -1212,6 +1240,8 @@ pflow_sendout_ipfix_tmpl(struct pflow_so
>  int
>  pflow_sendout_mbuf(struct pflow_softc *sc, struct mbuf *m)
>  {
> +     rw_assert_anylock(&sc->sc_lock);
> +
>       counters_pkt(sc->sc_if.if_counters,
>                   ifc_opackets, ifc_obytes, m->m_pkthdr.len);
>  
> Index: sys/net/if_pflow.h
> ===================================================================
> RCS file: /cvs/src/sys/net/if_pflow.h,v
> retrieving revision 1.19
> diff -u -p -r1.19 if_pflow.h
> --- sys/net/if_pflow.h        23 Nov 2022 15:12:27 -0000      1.19
> +++ sys/net/if_pflow.h        8 Dec 2023 11:59:09 -0000
> @@ -171,37 +171,42 @@ struct pflow_ipfix_flow6 {
>  
>  /*
>   * Locks used to protect struct members and global data
> + *       I       immutable after creation
>   *       N       net lock
> + *       m       this pflow_softc' `sc_mtx'
>   *       p       this pflow_softc' `sc_lock'
>   */
>  
>  struct pflow_softc {
> +     struct mutex             sc_mtx;
>       struct rwlock            sc_lock;
>  
>       int                      sc_dying;      /* [N] */
>       struct ifnet             sc_if;
>  
> -     unsigned int             sc_count;
> -     unsigned int             sc_count4;
> -     unsigned int             sc_count6;
> -     unsigned int             sc_maxcount;
> -     unsigned int             sc_maxcount4;
> -     unsigned int             sc_maxcount6;
> -     u_int64_t                sc_gcounter;
> -     u_int32_t                sc_sequence;
> +     unsigned int             sc_count;      /* [m] */
> +     unsigned int             sc_count4;     /* [m] */
> +     unsigned int             sc_count6;     /* [m] */
> +     unsigned int             sc_maxcount;   /* [m] */
> +     unsigned int             sc_maxcount4;  /* [m] */
> +     unsigned int             sc_maxcount6;  /* [m] */
> +     u_int64_t                sc_gcounter;   /* [m] */
> +     u_int32_t                sc_sequence;   /* [m] */
>       struct timeout           sc_tmo;
>       struct timeout           sc_tmo6;
>       struct timeout           sc_tmo_tmpl;
>       struct mbuf_queue        sc_outputqueue;
>       struct task              sc_outputtask;
>       struct socket           *so;            /* [p] */
> -     struct mbuf             *send_nam;
> -     struct sockaddr         *sc_flowsrc;
> -     struct sockaddr         *sc_flowdst;
> -     struct pflow_ipfix_tmpl  sc_tmpl_ipfix;
> -     u_int8_t                 sc_version;
> -     struct mbuf             *sc_mbuf;       /* current cumulative mbuf */
> -     struct mbuf             *sc_mbuf6;      /* current cumulative mbuf */
> +     struct mbuf             *send_nam;      /* [p] */
> +     struct sockaddr         *sc_flowsrc;    /* [p] */
> +     struct sockaddr         *sc_flowdst;    /* [p] */
> +     struct pflow_ipfix_tmpl  sc_tmpl_ipfix; /* [I] */
> +     u_int8_t                 sc_version;    /* [m] */
> +     struct mbuf             *sc_mbuf;       /* [m] current cumulative
> +                                                 mbuf */
> +     struct mbuf             *sc_mbuf6;      /* [m] current cumulative
> +                                                 mbuf */
>       SLIST_ENTRY(pflow_softc) sc_next;
>  };
>  
> 

Reply via email to