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