Index: sys/netinet/ip_carp.c =================================================================== --- sys/netinet/ip_carp.c +++ sys/netinet/ip_carp.c @@ -212,11 +212,13 @@ static VNET_DEFINE(int, carp_ifdown_adj) = CARP_MAXSKEW; #define V_carp_ifdown_adj VNET(carp_ifdown_adj) +static int carp_allow_sysctl(SYSCTL_HANDLER_ARGS); static int carp_demote_adj_sysctl(SYSCTL_HANDLER_ARGS); SYSCTL_NODE(_net_inet, IPPROTO_CARP, carp, CTLFLAG_RW, 0, "CARP"); -SYSCTL_INT(_net_inet_carp, OID_AUTO, allow, CTLFLAG_VNET | CTLFLAG_RW, - &VNET_NAME(carp_allow), 0, "Accept incoming CARP packets"); +SYSCTL_PROC(_net_inet_carp, OID_AUTO, allow, + CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW, 0, 0, carp_allow_sysctl, "I", + "Accept incoming CARP packets"); SYSCTL_INT(_net_inet_carp, OID_AUTO, preempt, CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(carp_preempt), 0, "High-priority backup preemption mode"); SYSCTL_INT(_net_inet_carp, OID_AUTO, log, CTLFLAG_VNET | CTLFLAG_RW, @@ -315,12 +317,15 @@ static void carp_ifa_addroute(struct ifaddr *); static void carp_delroute(struct carp_softc *); static void carp_ifa_delroute(struct ifaddr *); +static void carp_reset(void *, int); static void carp_send_ad_all(void *, int); static void carp_demote_adj(int, char *); static LIST_HEAD(, carp_softc) carp_list; static struct mtx carp_mtx; static struct sx carp_sx; +static struct task carp_reset_task = + TASK_INITIALIZER(0, carp_reset, NULL); static struct task carp_sendall_task = TASK_INITIALIZER(0, carp_send_ad_all, NULL); @@ -801,6 +806,29 @@ * be called directly, but scheduled via taskqueue. */ static void +carp_reset(void *ctx __unused, int pending __unused) +{ + struct carp_softc *sc; + + sx_xlock(&carp_sx); + mtx_lock(&carp_mtx); + LIST_FOREACH(sc, &carp_list, sc_next) { + CARP_LOCK(sc); + CURVNET_SET(sc->sc_carpdev->if_vnet); + if ((V_carp_allow == 0) != (sc->sc_state == INIT)) + carp_sc_state(sc); + CURVNET_RESTORE(); + CARP_UNLOCK(sc); + } + mtx_unlock(&carp_mtx); + sx_xunlock(&carp_sx); +} + +/* + * To avoid LORs and possible recursions this function shouldn't + * be called directly, but scheduled via taskqueue. + */ +static void carp_send_ad_all(void *ctx __unused, int pending __unused) { struct carp_softc *sc; @@ -1293,7 +1321,8 @@ if ((sc->sc_carpdev->if_flags & IFF_UP) == 0 || sc->sc_carpdev->if_link_state != LINK_STATE_UP || - (sc->sc_naddrs == 0 && sc->sc_naddrs6 == 0)) + (sc->sc_naddrs == 0 && sc->sc_naddrs6 == 0) || + !V_carp_allow) return; switch (sc->sc_state) { @@ -2066,7 +2095,8 @@ CARP_LOCK_ASSERT(sc); if (sc->sc_carpdev->if_link_state != LINK_STATE_UP || - !(sc->sc_carpdev->if_flags & IFF_UP)) { + !(sc->sc_carpdev->if_flags & IFF_UP) || + !V_carp_allow) { callout_stop(&sc->sc_ad_tmo); #ifdef INET callout_stop(&sc->sc_md_tmo); @@ -2097,6 +2127,24 @@ } static int +carp_allow_sysctl(SYSCTL_HANDLER_ARGS) +{ + int new, error; + + new = V_carp_allow; + error = sysctl_handle_int(oidp, &new, 0, req); + if (error || !req->newptr) + return (error); + + if(V_carp_allow != new) { + V_carp_allow = new; + taskqueue_enqueue(taskqueue_swi, &carp_reset_task); + } + + return (0); +} + +static int carp_demote_adj_sysctl(SYSCTL_HANDLER_ARGS) { int new, error; @@ -2170,6 +2218,7 @@ carp_demote_adj_p = NULL; carp_master_p = NULL; mtx_unlock(&carp_mtx); + taskqueue_drain(taskqueue_swi, &carp_reset_task); taskqueue_drain(taskqueue_swi, &carp_sendall_task); mtx_destroy(&carp_mtx); sx_destroy(&carp_sx);