Index: netinet/ip_carp.c =================================================================== --- netinet/ip_carp.c (revision 217802) +++ netinet/ip_carp.c (working copy) @@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -130,6 +131,7 @@ struct carp_softc { struct callout sc_ad_tmo; /* advertisement timeout */ struct callout sc_md_tmo; /* master down timeout */ struct callout sc_md6_tmo; /* master down timeout */ + struct task sc_arp_task; /* arp xmit */ LIST_ENTRY(carp_softc) sc_next; /* Interface clue */ }; @@ -206,7 +208,7 @@ static int carp_prepare_ad(struct mbuf *, struct c static void carp_send_ad_all(void); static void carp_send_ad(void *); static void carp_send_ad_locked(struct carp_softc *); -static void carp_send_arp(struct carp_softc *); +static void carp_send_arp_task(void *, int); static void carp_master_down(void *); static void carp_master_down_locked(struct carp_softc *); static int carp_ioctl(struct ifnet *, u_long, caddr_t); @@ -224,7 +226,6 @@ static int carp_del_addr(struct carp_softc *, stru static void carp_carpdev_state_locked(struct carp_if *); static void carp_sc_state_locked(struct carp_softc *); #ifdef INET6 -static void carp_send_na(struct carp_softc *); static int carp_set_addr6(struct carp_softc *, struct sockaddr_in6 *); static int carp_del_addr6(struct carp_softc *, struct sockaddr_in6 *); static void carp_multicast6_cleanup(struct carp_softc *, int dofree); @@ -422,7 +423,8 @@ carp_clone_create(struct if_clone *ifc, int unit, callout_init(&sc->sc_ad_tmo, CALLOUT_MPSAFE); callout_init(&sc->sc_md_tmo, CALLOUT_MPSAFE); callout_init(&sc->sc_md6_tmo, CALLOUT_MPSAFE); - + TASK_INIT(&sc->sc_arp_task, 0, carp_send_arp_task, sc); + ifp->if_softc = sc; if_initname(ifp, CARP_IFNAME, unit); ifp->if_mtu = ETHERMTU; @@ -483,6 +485,7 @@ carpdetach(struct carp_softc *sc, int unlock) callout_stop(&sc->sc_ad_tmo); callout_stop(&sc->sc_md_tmo); callout_stop(&sc->sc_md6_tmo); + taskqueue_cancel(taskqueue_swi, &sc->sc_arp_task, NULL); if (sc->sc_suppress) carp_suppress_preempt--; @@ -897,7 +900,7 @@ carp_send_ad_locked(struct carp_softc *sc) struct timeval tv; struct carp_header *ch_ptr; struct mbuf *m; - int len, advbase, advskew; + int error, len, advbase, advskew; CARP_SCLOCK_ASSERT(sc); @@ -972,7 +975,10 @@ carp_send_ad_locked(struct carp_softc *sc) SC2IFP(sc)->if_obytes += len; CARPSTATS_INC(carps_opackets); - if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL)) { + CARP_SCUNLOCK(sc); + error = ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL); + CARP_SCLOCK(sc); + if (error) { SC2IFP(sc)->if_oerrors++; if (sc->sc_sendad_errors < INT_MAX) sc->sc_sendad_errors++; @@ -1049,7 +1055,10 @@ carp_send_ad_locked(struct carp_softc *sc) SC2IFP(sc)->if_obytes += len; CARPSTATS_INC(carps_opackets6); - if (ip6_output(m, NULL, NULL, 0, &sc->sc_im6o, NULL, NULL)) { + CARP_SCUNLOCK(sc); + error = ip6_output(m, NULL, NULL, 0, &sc->sc_im6o, NULL, NULL); + CARP_SCLOCK(sc); + if (error) { SC2IFP(sc)->if_oerrors++; if (sc->sc_sendad_errors < INT_MAX) sc->sc_sendad_errors++; @@ -1087,42 +1096,33 @@ carp_send_ad_locked(struct carp_softc *sc) * associated with the virtual router. */ static void -carp_send_arp(struct carp_softc *sc) +carp_send_arp_task(void *arg, int pending) { + struct carp_softc *sc = arg; struct ifaddr *ifa; - - TAILQ_FOREACH(ifa, &SC2IFP(sc)->if_addrlist, ifa_list) { - - if (ifa->ifa_addr->sa_family != AF_INET) - continue; - -/* arprequest(sc->sc_carpdev, &in, &in, IF_LLADDR(sc->sc_ifp)); */ - arp_ifinit2(sc->sc_carpdev, ifa, IF_LLADDR(sc->sc_ifp)); - - DELAY(1000); /* XXX */ - } -} - #ifdef INET6 -static void -carp_send_na(struct carp_softc *sc) -{ - struct ifaddr *ifa; struct in6_addr *in6; static struct in6_addr mcast = IN6ADDR_LINKLOCAL_ALLNODES_INIT; +#endif /* INET6 */ - TAILQ_FOREACH(ifa, &SC2IFP(sc)->if_addrlist, ifa_list) { + if (sc->sc_carpdev == NULL) + return; - if (ifa->ifa_addr->sa_family != AF_INET6) - continue; - - in6 = &ifatoia6(ifa)->ia_addr.sin6_addr; - nd6_na_output(sc->sc_carpdev, &mcast, in6, - ND_NA_FLAG_OVERRIDE, 1, NULL); - DELAY(1000); /* XXX */ + TAILQ_FOREACH(ifa, &SC2IFP(sc)->if_addrlist, ifa_list) { + if (ifa->ifa_addr->sa_family == AF_INET) { + /* arprequest(sc->sc_carpdev, &in, &in, IF_LLADDR(sc->sc_ifp)); */ + arp_ifinit2(sc->sc_carpdev, ifa, IF_LLADDR(sc->sc_ifp)); + DELAY(1000); /* XXX */ +#ifdef INET6 + } else if (ifa->ifa_addr->sa_family == AF_INET6) { + in6 = &ifatoia6(ifa)->ia_addr.sin6_addr; + nd6_na_output(sc->sc_carpdev, &mcast, in6, + ND_NA_FLAG_OVERRIDE, 1, NULL); + DELAY(1000); /* XXX */ +#endif /* INET6 */ + } } } -#endif /* INET6 */ static int carp_addrcount(struct carp_if *cif, struct in_ifaddr *ia, int type) @@ -1353,10 +1353,7 @@ carp_master_down_locked(struct carp_softc *sc) case BACKUP: carp_set_state(sc, MASTER); carp_send_ad_locked(sc); - carp_send_arp(sc); -#ifdef INET6 - carp_send_na(sc); -#endif /* INET6 */ + taskqueue_enqueue(taskqueue_swi, &sc->sc_arp_task); carp_setrun(sc, 0); carp_setroute(sc, RTM_ADD); break; @@ -1393,10 +1390,7 @@ carp_setrun(struct carp_softc *sc, sa_family_t af) case INIT: if (carp_opts[CARPCTL_PREEMPT] && !carp_suppress_preempt) { carp_send_ad_locked(sc); - carp_send_arp(sc); -#ifdef INET6 - carp_send_na(sc); -#endif /* INET6 */ + taskqueue_enqueue(taskqueue_swi, &sc->sc_arp_task); CARP_LOG("%s: INIT -> MASTER (preempting)\n", SC2IFP(sc)->if_xname); carp_set_state(sc, MASTER);