diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c --- a/sys/netinet/ip_carp.c +++ b/sys/netinet/ip_carp.c @@ -1112,6 +1112,16 @@ uint64_t tmp_counter; struct timeval sc_tv, ch_tv; + /* + * DF-0302: The failover state machine below reads sc_state and performs + * non-atomic transitions (callout_stop, carp_set_state, carp_setroute). + * Unlike carp_iamatch() which asserts ASSERT_NETISR0, this function + * had no such guard. CARP input must run on netisr0 to serialize + * state transitions and prevent concurrent packet processing on + * different CPUs from causing double route deletion / state corruption. + */ + ASSERT_NETISR0; + if (sc->sc_vhid != ch->carp_vhid) { /* * CARP uses multicast, however, multicast packets