From 0e08a2a107eb5a7e7195a0a1150f35a233363fa1 Mon Sep 17 00:00:00 2001 From: kp Date: Fri, 2 Nov 2018 16:57:23 +0000 Subject: [PATCH] pfsync: Handle syncdev going away If the syncdev is removed we no longer need to clean up the multicast entry we've got set up for that device. Pass the ifnet detach event through pf to pfsync, and remove our multicast handle, and mark us as no longer having a syncdev. Note that this callback is always installed, even if the pfsync interface is disabled (and thus it's not a per-vnet callback pointer). MFC after: 2 weeks Sponsored by: Orange Business Services Differential Revision: https://reviews.freebsd.org/D17502 --- sys/net/pfvar.h | 2 ++ sys/netpfil/pf/if_pfsync.c | 27 +++++++++++++++++++++++++++ sys/netpfil/pf/pf_if.c | 4 ++++ sys/netpfil/pf/pf_ioctl.c | 1 + 4 files changed, 34 insertions(+) diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index 9ace26e49d0c..2924c06dbc43 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -824,6 +824,7 @@ typedef void pfsync_update_state_t(struct pf_state *); typedef void pfsync_delete_state_t(struct pf_state *); typedef void pfsync_clear_states_t(u_int32_t, const char *); typedef int pfsync_defer_t(struct pf_state *, struct mbuf *); +typedef void pfsync_detach_ifnet_t(struct ifnet *); VNET_DECLARE(pfsync_state_import_t *, pfsync_state_import_ptr); #define V_pfsync_state_import_ptr VNET(pfsync_state_import_ptr) @@ -837,6 +838,7 @@ VNET_DECLARE(pfsync_clear_states_t *, pfsync_clear_states_ptr); #define V_pfsync_clear_states_ptr VNET(pfsync_clear_states_ptr) VNET_DECLARE(pfsync_defer_t *, pfsync_defer_ptr); #define V_pfsync_defer_ptr VNET(pfsync_defer_ptr) +extern pfsync_detach_ifnet_t *pfsync_detach_ifnet_ptr; void pfsync_state_export(struct pfsync_state *, struct pf_state *); diff --git a/sys/netpfil/pf/if_pfsync.c b/sys/netpfil/pf/if_pfsync.c index 27862df53b6f..25c5715c714a 100644 --- a/sys/netpfil/pf/if_pfsync.c +++ b/sys/netpfil/pf/if_pfsync.c @@ -281,6 +281,7 @@ static void pfsync_bulk_status(u_int8_t); static void pfsync_bulk_update(void *); static void pfsync_bulk_fail(void *); +static void pfsync_detach_ifnet(struct ifnet *); #ifdef IPSEC static void pfsync_update_net_tdb(struct pfsync_tdb *); #endif @@ -2292,6 +2293,29 @@ pfsync_multicast_cleanup(struct pfsync_softc *sc) imo->imo_multicast_ifp = NULL; } +void +pfsync_detach_ifnet(struct ifnet *ifp) +{ + struct pfsync_softc *sc = V_pfsyncif; + + if (sc == NULL) + return; + + PFSYNC_LOCK(sc); + + if (sc->sc_sync_if == ifp) { + /* We don't need mutlicast cleanup here, because the interface + * is going away. We do need to ensure we don't try to do + * cleanup later. + */ + sc->sc_imo.imo_membership = NULL; + sc->sc_imo.imo_multicast_ifp = NULL; + sc->sc_sync_if = NULL; + } + + PFSYNC_UNLOCK(sc); +} + #ifdef INET extern struct domain inetdomain; static struct protosw in_pfsync_protosw = { @@ -2372,6 +2396,8 @@ pfsync_init() #ifdef INET int error; + pfsync_detach_ifnet_ptr = pfsync_detach_ifnet; + error = pf_proto_register(PF_INET, &in_pfsync_protosw); if (error) return (error); @@ -2388,6 +2414,7 @@ pfsync_init() static void pfsync_uninit() { + pfsync_detach_ifnet_ptr = NULL; #ifdef INET ipproto_unregister(IPPROTO_PFSYNC); diff --git a/sys/netpfil/pf/pf_if.c b/sys/netpfil/pf/pf_if.c index 599f80cf7f13..8e1b0e83792b 100644 --- a/sys/netpfil/pf/pf_if.c +++ b/sys/netpfil/pf/pf_if.c @@ -834,6 +834,9 @@ pfi_detach_ifnet_event(void *arg __unused, struct ifnet *ifp) { struct pfi_kif *kif = (struct pfi_kif *)ifp->if_pf_kif; + if (pfsync_detach_ifnet_ptr) + pfsync_detach_ifnet_ptr(ifp); + if (kif == NULL) return; @@ -841,6 +844,7 @@ pfi_detach_ifnet_event(void *arg __unused, struct ifnet *ifp) /* Avoid teardown race in the least expensive way. */ return; } + PF_RULES_WLOCK(); V_pfi_update++; pfi_kif_update(kif); diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c index 670b8f7e8005..3bb65ddbb2de 100644 --- a/sys/netpfil/pf/pf_ioctl.c +++ b/sys/netpfil/pf/pf_ioctl.c @@ -218,6 +218,7 @@ VNET_DEFINE(pfsync_update_state_t *, pfsync_update_state_ptr); VNET_DEFINE(pfsync_delete_state_t *, pfsync_delete_state_ptr); VNET_DEFINE(pfsync_clear_states_t *, pfsync_clear_states_ptr); VNET_DEFINE(pfsync_defer_t *, pfsync_defer_ptr); +pfsync_detach_ifnet_t *pfsync_detach_ifnet_ptr; /* pflog */ pflog_packet_t *pflog_packet_ptr = NULL;