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
This commit is contained in:
Bruce M Simpson 2007-03-19 17:52:15 +00:00
parent 8071ab55dc
commit 6b47cca2a7
2 changed files with 50 additions and 0 deletions

View File

@ -170,6 +170,9 @@ void pfsync_timeout(void *);
void pfsync_send_bus(struct pfsync_softc *, u_int8_t); void pfsync_send_bus(struct pfsync_softc *, u_int8_t);
void pfsync_bulk_update(void *); void pfsync_bulk_update(void *);
void pfsync_bulkfail(void *); void pfsync_bulkfail(void *);
#ifdef __FreeBSD__
static void pfsync_ifdetach(void *, struct ifnet *);
#endif
int pfsync_sync_ok; int pfsync_sync_ok;
#ifndef __FreeBSD__ #ifndef __FreeBSD__
@ -191,6 +194,9 @@ pfsync_clone_destroy(struct ifnet *ifp)
struct pfsync_softc *sc; struct pfsync_softc *sc;
sc = ifp->if_softc; sc = ifp->if_softc;
#ifdef __FreeBSD__
EVENTHANDLER_DEREGISTER(ifnet_departure_event, sc->sc_detachtag);
#endif
callout_stop(&sc->sc_tmo); callout_stop(&sc->sc_tmo);
callout_stop(&sc->sc_bulk_tmo); callout_stop(&sc->sc_bulk_tmo);
callout_stop(&sc->sc_bulkfail_tmo); callout_stop(&sc->sc_bulkfail_tmo);
@ -225,6 +231,16 @@ pfsync_clone_create(struct if_clone *ifc, int unit)
return (ENOSPC); 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; pfsync_sync_ok = 1;
sc->sc_mbuf = NULL; sc->sc_mbuf = NULL;
sc->sc_mbuf_net = NULL; sc->sc_mbuf_net = NULL;
@ -1869,6 +1885,33 @@ pfsync_sendout(sc)
} }
#ifdef __FreeBSD__ #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 static void
pfsync_senddef(void *arg) pfsync_senddef(void *arg)
{ {
@ -1879,6 +1922,12 @@ pfsync_senddef(void *arg)
IF_DEQUEUE(&sc->sc_ifq, m); IF_DEQUEUE(&sc->sc_ifq, m);
if (m == NULL) if (m == NULL)
break; 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)) if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL))
pfsyncstats.pfsyncs_oerrors++; pfsyncstats.pfsyncs_oerrors++;
} }

View File

@ -181,6 +181,7 @@ struct pfsync_softc {
int sc_maxupdates; /* number of updates/state */ int sc_maxupdates; /* number of updates/state */
#ifdef __FreeBSD__ #ifdef __FreeBSD__
LIST_ENTRY(pfsync_softc) sc_next; LIST_ENTRY(pfsync_softc) sc_next;
eventhandler_tag sc_detachtag;
#endif #endif
}; };
#endif #endif