diff options
author | bms <bms@FreeBSD.org> | 2007-03-19 17:52:15 +0000 |
---|---|---|
committer | bms <bms@FreeBSD.org> | 2007-03-19 17:52:15 +0000 |
commit | 21bccff9b0f1abeba3cdaab4d86f884e98e79f8d (patch) | |
tree | 6beac89d7a981d409c246d34397f105bcfd6e420 /sys | |
parent | b5f0c3495e2dcd41e0c98a429a4f3f2396d9aef9 (diff) | |
download | FreeBSD-src-21bccff9b0f1abeba3cdaab4d86f884e98e79f8d.zip FreeBSD-src-21bccff9b0f1abeba3cdaab4d86f884e98e79f8d.tar.gz |
Teach pfsync(4) that its member interfaces may go away.
This change partially resolves the issue in the PR. Further architectural
fixes, in the form of reference counting, are needed.
PR: 86848
Reviewed by: yar
MFC after: 1 month
Diffstat (limited to 'sys')
-rw-r--r-- | sys/contrib/pf/net/if_pfsync.c | 49 | ||||
-rw-r--r-- | sys/contrib/pf/net/if_pfsync.h | 1 |
2 files changed, 50 insertions, 0 deletions
diff --git a/sys/contrib/pf/net/if_pfsync.c b/sys/contrib/pf/net/if_pfsync.c index 24687de..fa35ad6 100644 --- a/sys/contrib/pf/net/if_pfsync.c +++ b/sys/contrib/pf/net/if_pfsync.c @@ -170,6 +170,9 @@ void pfsync_timeout(void *); void pfsync_send_bus(struct pfsync_softc *, u_int8_t); void pfsync_bulk_update(void *); void pfsync_bulkfail(void *); +#ifdef __FreeBSD__ +static void pfsync_ifdetach(void *, struct ifnet *); +#endif int pfsync_sync_ok; #ifndef __FreeBSD__ @@ -191,6 +194,9 @@ pfsync_clone_destroy(struct ifnet *ifp) struct pfsync_softc *sc; sc = ifp->if_softc; +#ifdef __FreeBSD__ + EVENTHANDLER_DEREGISTER(ifnet_departure_event, sc->sc_detachtag); +#endif callout_stop(&sc->sc_tmo); callout_stop(&sc->sc_bulk_tmo); callout_stop(&sc->sc_bulkfail_tmo); @@ -225,6 +231,16 @@ pfsync_clone_create(struct if_clone *ifc, int unit) return (ENOSPC); } +#ifdef __FreeBSD__ + sc->sc_detachtag = EVENTHANDLER_REGISTER(ifnet_departure_event, + pfsync_ifdetach, sc, EVENTHANDLER_PRI_ANY); + if (sc->sc_detachtag == NULL) { + if_free(ifp); + free(sc, M_PFSYNC); + return (ENOSPC); + } +#endif + pfsync_sync_ok = 1; sc->sc_mbuf = NULL; sc->sc_mbuf_net = NULL; @@ -1870,6 +1886,33 @@ pfsync_sendout(sc) #ifdef __FreeBSD__ static void +pfsync_ifdetach(void *arg, struct ifnet *ifp) +{ + struct pfsync_softc *sc = (struct pfsync_softc *)arg; + struct ip_moptions *imo; + + if (sc == NULL || sc->sc_sync_ifp != ifp) + return; /* not for us; unlocked read */ + + PF_LOCK(); + + /* Deal with a member interface going away from under us. */ + sc->sc_sync_ifp = NULL; + if (sc->sc_mbuf_net != NULL) { + m_freem(sc->sc_mbuf_net); + sc->sc_mbuf_net = NULL; + sc->sc_statep_net.s = NULL; + } + imo = &sc->sc_imo; + if (imo->imo_num_memberships > 0) { + in_delmulti(imo->imo_membership[--imo->imo_num_memberships]); + imo->imo_multicast_ifp = NULL; + } + + PF_UNLOCK(); +} + +static void pfsync_senddef(void *arg) { struct pfsync_softc *sc = (struct pfsync_softc *)arg; @@ -1879,6 +1922,12 @@ pfsync_senddef(void *arg) IF_DEQUEUE(&sc->sc_ifq, m); if (m == NULL) break; + /* Deal with a member interface going away from under us. */ + if (sc->sc_sync_ifp == NULL) { + pfsyncstats.pfsyncs_oerrors++; + m_freem(m); + continue; + } if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL)) pfsyncstats.pfsyncs_oerrors++; } diff --git a/sys/contrib/pf/net/if_pfsync.h b/sys/contrib/pf/net/if_pfsync.h index f9df354..77ef3a5 100644 --- a/sys/contrib/pf/net/if_pfsync.h +++ b/sys/contrib/pf/net/if_pfsync.h @@ -181,6 +181,7 @@ struct pfsync_softc { int sc_maxupdates; /* number of updates/state */ #ifdef __FreeBSD__ LIST_ENTRY(pfsync_softc) sc_next; + eventhandler_tag sc_detachtag; #endif }; #endif |