On Fri, Dec 08, 2023 at 11:36:31PM +0100, Alexander Bluhm wrote: > On Thu, Dec 07, 2023 at 06:14:30PM +0300, Vitaliy Makkoveev wrote: > > Here id the diff. I introduces `sc_mtx' mutex(9) to protect the most of > > pflow_softc structure. The `send_nam', `sc_flowsrc' and `sc_flowdst' are > > prtected by `sc_lock' rwlock(9). `sc_tmpl_ipfix' is immutable. > > > > Also, the pflow_sendout_ipfix_tmpl() calls pflow_get_mbuf() with NULL > > instead of `sc'. This fix also included to this diff. > > > > Please note, this diff does not fix all the problems in the pflow(4). > > The ifconfig create/destroy sequence could still break the kernel. I > > have ok'ed diff to fix this but did not commit it yet for some reason. > > Also the `pflowstats' data left unprotected. I will fix this with > > separate diff. > > > > Please test this diff and let us know the result. I will continue with > > pflow(4) after committing this. > > Your changes make sense. > > > sc->sc_gcounter=pflowstats.pflow_flows; > > Could you add some spaces around = > sc_gcounter is set without spaced twice. >
Thanks, I will fix this. > > case SIOCGETPFLOW: > > bzero(&pflowr, sizeof(pflowr)); > > > > + /* XXXSMP: enforce lock order */ > > + NET_UNLOCK(); > > + rw_enter_read(&sc->sc_lock); > > + NET_LOCK(); > > This looks ugly. I did not find the sc_lock -> NET_LOCK() seqence. > Where is it? Why do we need it? In general I think the global > NET_LOCK() should be taken before the specific sc_lock. Moving the > net lock to very narrow places within other locks makes things more > complicated. Better take a shared net lock and hold it for more > code. Not sure if this is a usable solution in this case. > The `sc_lock' rwlock(9) protects the `so' socket dereference. Since it is passed to sosend() which takes netlock within, the `sc_lock' should be taken first: void pflow_output_process(void *arg) { struct mbuf_list ml; struct pflow_softc *sc = arg; struct mbuf *m; mq_delist(&sc->sc_outputqueue, &ml); rw_enter_read(&sc->sc_lock); while ((m = ml_dequeue(&ml)) != NULL) { pflow_sendout_mbuf(sc, m); } rw_exit_read(&sc->sc_lock); } int pflow_sendout_mbuf(struct pflow_softc *sc, struct mbuf *m) { counters_pkt(sc->sc_if.if_counters, ifc_opackets, ifc_obytes, m->m_pkthdr.len); if (sc->so == NULL) { m_freem(m); return (EINVAL); } return (sosend(sc->so, sc->send_nam, NULL, m, NULL, 0)); } I want to rework netlock relocking in pflowioctl(). Guess it should be realeased and the `sc_lock' should be taken just after we enter pflowioctl(). We need to release netlock because pflowioctl() calls solcose(), socreate() and sobind(). Since the `sc_lock' will not be relocked, the `sc_dying' should rely on it. This will fix the pflowioctl() concurrency with pflow_clone_destroy(). > > pflow(4) after committing this. > > SLIST_ENTRY(pflow_softc) sc_next; > > This list is protected by net lock. Can you add an [N] here? > This is not true. The netlock is not taken while export_pflow() called from pf_purge_states(). I privately shared the diff to fix this, but not committed it yet. I will update it and share after committing this diff. > OK bluhm@ > > Feel free to address my remarks later. >