commit efda58c0520132d72265f10d7665d1479610dc2a Author: Ryota Ozaki Date: Fri May 19 10:55:44 2017 +0900 Allow CARP call the link_state_change handler immediately If the handler is delayed because of the indirection call via softint, some operations are executed in reverse and may cause unexpected behaviors. For example, due to the issue a GARP packet wasn't sent on a transition from the BACKUP state to the MASTER state; this happened because IN_IFF_DETACHED flag wasn't cleared on arpannounce, which had been cleared in the link_state_change handler. diff --git a/sys/net/if.c b/sys/net/if.c index dff49205159..3f5ad8d524f 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -2247,16 +2247,20 @@ out: /* * Handle interface link state change notifications. - * Must be called at splnet(). */ -static void -if_link_state_change0(struct ifnet *ifp, int link_state) +void +if_link_state_change_softint(struct ifnet *ifp, int link_state) { struct domain *dp; + int s = splnet(); + + KASSERT(!cpu_intr_p()); /* Ensure the change is still valid. */ - if (ifp->if_link_state == link_state) + if (ifp->if_link_state == link_state) { + splx(s); return; + } #ifdef DEBUG log(LOG_DEBUG, "%s: link state %s (was %s)\n", ifp->if_xname, @@ -2301,6 +2305,7 @@ if_link_state_change0(struct ifnet *ifp, int link_state) if (dp->dom_if_link_state_change != NULL) dp->dom_if_link_state_change(ifp, link_state); } + splx(s); } /* @@ -2321,7 +2326,7 @@ if_link_state_change_si(void *arg) /* Pop a link state change from the queue and process it. */ LQ_POP(ifp->if_link_queue, state); - if_link_state_change0(ifp, state); + if_link_state_change_softint(ifp, state); /* If there is a link state change to come, schedule it. */ if (LQ_ITEM(ifp->if_link_queue, 0) != LINK_STATE_UNSET) diff --git a/sys/net/if.h b/sys/net/if.h index bbe5e56e23a..f99f06649a8 100644 --- a/sys/net/if.h +++ b/sys/net/if.h @@ -956,6 +956,7 @@ void if_purgeaddrs(struct ifnet *, int, void (*)(struct ifaddr *)); void if_detach(struct ifnet *); void if_down(struct ifnet *); void if_link_state_change(struct ifnet *, int); +void if_link_state_change_softint(struct ifnet *, int); void if_up(struct ifnet *); void ifinit(void); void ifinit1(void); diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c index 81cfad606a3..e7b7bf10e31 100644 --- a/sys/netinet/ip_carp.c +++ b/sys/netinet/ip_carp.c @@ -2191,7 +2191,7 @@ carp_set_state(struct carp_softc *sc, int state) link_state = LINK_STATE_UNKNOWN; break; } - if_link_state_change(&sc->sc_if, link_state); + if_link_state_change_softint(&sc->sc_if, link_state); } void