Index: sys/net/if_ethersubr.c =================================================================== --- sys/net/if_ethersubr.c +++ sys/net/if_ethersubr.c @@ -604,34 +604,35 @@ return; } eh = mtod(m, struct ether_header *); - } + } else { #if defined(INET) || defined(INET6) - /* - * Clear M_PROMISC on frame so that carp(4) will see it when the - * mbuf flows up to Layer 3. - * FreeBSD's implementation of carp(4) uses the inprotosw - * to dispatch IPPROTO_CARP. carp(4) also allocates its own - * Ethernet addresses of the form 00:00:5e:00:01:xx, which - * is outside the scope of the M_PROMISC test below. - * TODO: Maintain a hash table of ethernet addresses other than - * ether_dhost which may be active on this ifp. - */ - if (ifp->if_carp && (*carp_forus_p)(ifp, eh->ether_dhost)) { - m->m_flags &= ~M_PROMISC; - } else -#endif - { /* - * If the frame received was not for our MAC address, set the - * M_PROMISC flag on the mbuf chain. The frame may need to - * be seen by the rest of the Ethernet input path in case of - * re-entry (e.g. bridge, vlan, netgraph) but should not be - * seen by upper protocol layers. + * Clear M_PROMISC on frame so that carp(4) will see it when the + * mbuf flows up to Layer 3. + * FreeBSD's implementation of carp(4) uses the inprotosw + * to dispatch IPPROTO_CARP. carp(4) also allocates its own + * Ethernet addresses of the form 00:00:5e:00:01:xx, which + * is outside the scope of the M_PROMISC test below. + * TODO: Maintain a hash table of ethernet addresses other than + * ether_dhost which may be active on this ifp. */ - if (!ETHER_IS_MULTICAST(eh->ether_dhost) && - bcmp(IF_LLADDR(ifp), eh->ether_dhost, ETHER_ADDR_LEN) != 0) - m->m_flags |= M_PROMISC; + if (ifp->if_carp && (*carp_forus_p)(ifp, eh->ether_dhost)) { + m->m_flags &= ~M_PROMISC; + } else +#endif + { + /* + * If the frame received was not for our MAC address, set the + * M_PROMISC flag on the mbuf chain. The frame may need to + * be seen by the rest of the Ethernet input path in case of + * re-entry (e.g. bridge, vlan, netgraph) but should not be + * seen by upper protocol layers. + */ + if (!ETHER_IS_MULTICAST(eh->ether_dhost) && + bcmp(IF_LLADDR(ifp), eh->ether_dhost, ETHER_ADDR_LEN) != 0) + m->m_flags |= M_PROMISC; + } } ether_demux(ifp, m); Index: sys/netinet/ip_carp.c =================================================================== --- sys/netinet/ip_carp.c +++ sys/netinet/ip_carp.c @@ -143,7 +143,7 @@ struct ip6_moptions cif_im6o; #endif struct ifnet *cif_ifp; - struct mtx cif_mtx; + struct rwlock cif_mtx; uint32_t cif_flags; #define CIF_PROMISC 0x00000001 }; @@ -249,18 +249,19 @@ #define CARP_LOCK_ASSERT(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED) #define CARP_LOCK(sc) mtx_lock(&(sc)->sc_mtx) #define CARP_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) -#define CIF_LOCK_INIT(cif) mtx_init(&(cif)->cif_mtx, "carp_if", \ - NULL, MTX_DEF) -#define CIF_LOCK_DESTROY(cif) mtx_destroy(&(cif)->cif_mtx) -#define CIF_LOCK_ASSERT(cif) mtx_assert(&(cif)->cif_mtx, MA_OWNED) -#define CIF_LOCK(cif) mtx_lock(&(cif)->cif_mtx) -#define CIF_UNLOCK(cif) mtx_unlock(&(cif)->cif_mtx) +#define CIF_LOCK_INIT(cif) rw_init(&(cif)->cif_mtx, "carp_if") +#define CIF_LOCK_DESTROY(cif) rw_destroy(&(cif)->cif_mtx) +#define CIF_LOCK_ASSERT(cif) rw_assert(&(cif)->cif_mtx, MA_OWNED) +#define CIF_RLOCK(cif) rw_rlock(&(cif)->cif_mtx) +#define CIF_RUNLOCK(cif) rw_runlock(&(cif)->cif_mtx) +#define CIF_WLOCK(cif) rw_wlock(&(cif)->cif_mtx) +#define CIF_WUNLOCK(cif) rw_wunlock(&(cif)->cif_mtx) #define CIF_FREE(cif) do { \ - CIF_LOCK(cif); \ + CIF_WLOCK(cif); \ if (TAILQ_EMPTY(&(cif)->cif_vrs)) \ carp_free_if(cif); \ else \ - CIF_UNLOCK(cif); \ + CIF_WUNLOCK(cif); \ } while (0) #define CARP_LOG(...) do { \ @@ -1213,18 +1214,14 @@ if (ena[0] || ena[1] || ena[2] != 0x5e || ena[3] || ena[4] != 1) return (0); - CIF_LOCK(ifp->if_carp); + CIF_RLOCK(ifp->if_carp); IFNET_FOREACH_CARP(ifp, sc) { - CARP_LOCK(sc); - if (sc->sc_state == MASTER && !bcmp(dhost, LLADDR(&sc->sc_addr), - ETHER_ADDR_LEN)) { - CARP_UNLOCK(sc); - CIF_UNLOCK(ifp->if_carp); + if (sc->sc_state == MASTER && ena[5] == sc->sc_vhid) { + CIF_RUNLOCK(ifp->if_carp); return (1); } - CARP_UNLOCK(sc); } - CIF_UNLOCK(ifp->if_carp); + CIF_RUNLOCK(ifp->if_carp); return (0); } @@ -1585,9 +1582,9 @@ #endif callout_init_mtx(&sc->sc_ad_tmo, &sc->sc_mtx, CALLOUT_RETURNUNLOCKED); - CIF_LOCK(cif); + CIF_WLOCK(cif); TAILQ_INSERT_TAIL(&cif->cif_vrs, sc, sc_list); - CIF_UNLOCK(cif); + CIF_WUNLOCK(cif); mtx_lock(&carp_mtx); LIST_INSERT_HEAD(&carp_list, sc, sc_next); @@ -1622,9 +1619,9 @@ carp_demote_adj(-V_carp_ifdown_adj, "vhid removed"); CARP_UNLOCK(sc); - CIF_LOCK(cif); + CIF_WLOCK(cif); TAILQ_REMOVE(&cif->cif_vrs, sc, sc_list); - CIF_UNLOCK(cif); + CIF_WUNLOCK(cif); mtx_lock(&carp_mtx); LIST_REMOVE(sc, sc_next); @@ -1751,11 +1748,11 @@ } if (ifp->if_carp) { - CIF_LOCK(ifp->if_carp); + CIF_RLOCK(ifp->if_carp); IFNET_FOREACH_CARP(ifp, sc) if (sc->sc_vhid == carpr.carpr_vhid) break; - CIF_UNLOCK(ifp->if_carp); + CIF_RUNLOCK(ifp->if_carp); } if (sc == NULL) { sc = carp_alloc(ifp); @@ -1826,11 +1823,11 @@ priveleged = (priv_check(td, PRIV_NETINET_CARP) == 0); if (carpr.carpr_vhid != 0) { - CIF_LOCK(ifp->if_carp); + CIF_RLOCK(ifp->if_carp); IFNET_FOREACH_CARP(ifp, sc) if (sc->sc_vhid == carpr.carpr_vhid) break; - CIF_UNLOCK(ifp->if_carp); + CIF_RUNLOCK(ifp->if_carp); if (sc == NULL) { error = ENOENT; break; @@ -1841,12 +1838,12 @@ int i, count; count = 0; - CIF_LOCK(ifp->if_carp); + CIF_RLOCK(ifp->if_carp); IFNET_FOREACH_CARP(ifp, sc) count++; if (count > carpr.carpr_count) { - CIF_UNLOCK(ifp->if_carp); + CIF_RUNLOCK(ifp->if_carp); error = EMSGSIZE; break; } @@ -1858,12 +1855,12 @@ error = copyout(&carpr, ifr->ifr_data + (i * sizeof(carpr)), sizeof(carpr)); if (error) { - CIF_UNLOCK(ifp->if_carp); + CIF_RUNLOCK(ifp->if_carp); break; } i++; } - CIF_UNLOCK(ifp->if_carp); + CIF_RUNLOCK(ifp->if_carp); } break; } @@ -1918,11 +1915,11 @@ return (ENOPROTOOPT); } - CIF_LOCK(cif); + CIF_WLOCK(cif); IFNET_FOREACH_CARP(ifp, sc) if (sc->sc_vhid == vhid) break; - CIF_UNLOCK(cif); + CIF_WUNLOCK(cif); if (sc == NULL) { sx_xunlock(&carp_sx); return (ENOENT); @@ -2052,13 +2049,13 @@ { struct carp_softc *sc; - CIF_LOCK(ifp->if_carp); + CIF_RLOCK(ifp->if_carp); IFNET_FOREACH_CARP(ifp, sc) { CARP_LOCK(sc); carp_sc_state(sc); CARP_UNLOCK(sc); } - CIF_UNLOCK(ifp->if_carp); + CIF_RUNLOCK(ifp->if_carp); } static void @@ -2093,9 +2090,11 @@ static void carp_demote_adj(int adj, char *reason) { + if (adj == 0) + return; atomic_add_int(&V_carp_demotion, adj); CARP_LOG("demoted by %d to %d (%s)\n", adj, V_carp_demotion, reason); - taskqueue_enqueue(taskqueue_swi, &carp_sendall_task); + taskqueue_enqueue(taskqueue_thread, &carp_sendall_task); } static int