With setup like: node1: carpnodes 1:0,10:0 carpdev vmx0 balancing arp node2: carpnodes 1:100,10:100 carped vmx0 balancing arp (eg, I forced one machine to be a master for a while in my configs)
node2 (-current) with your diff started to pollute dmesg with: duplicate IP address 192.168.78.123 sent from ethernet address 00:00:5e:00:01:64 while node1 (5.8-stable kernel) is: carp1: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500 lladdr 00:00:5e:00:01:01 <……> inet 192.168.78.123 netmask 0xffffff80 broadcast 192.168.78.127 to get rid of this I modified hostname.carp1 to remove both dual VHID (VHID 1 is what left) and balancing arp and done ‘sh /etc/netstart carp1’ after on both machines. node2 survived. //mxb > On 13 sep. 2015, at 10:34, David Gwynne <da...@gwynne.id.au> wrote: > > i did this yesterday, but havent had a chance to beat on it properly > yet. > > if anyone would like to give it a go it would be much appreciated. > im particularly interested in stability while carp configuration > is made or changed. if it happens to keep handling packets, thats > great, but not blowing up when you run ifconfig is the important > bit atm. > > Index: ip_carp.c > =================================================================== > RCS file: /cvs/src/sys/netinet/ip_carp.c,v > retrieving revision 1.271 > diff -u -p -r1.271 ip_carp.c > --- ip_carp.c 12 Sep 2015 20:51:35 -0000 1.271 > +++ ip_carp.c 12 Sep 2015 21:07:42 -0000 > @@ -48,6 +48,7 @@ > #include <sys/kernel.h> > #include <sys/sysctl.h> > #include <sys/syslog.h> > +#include <sys/refcnt.h> > > #include <net/if.h> > #include <net/if_var.h> > @@ -93,7 +94,9 @@ struct carp_mc_entry { > enum { HMAC_ORIG=0, HMAC_NOV6LL=1, HMAC_MAX=2 }; > > struct carp_vhost_entry { > - LIST_ENTRY(carp_vhost_entry) vhost_entries; > + struct srpl_entry vhost_entries; > + struct refcnt vhost_refcnt; > + > struct carp_softc *parent_sc; > int vhe_leader; > int vhid; > @@ -114,6 +117,12 @@ struct carp_vhost_entry { > struct sockaddr_dl vhe_sdl; /* for IPv6 ndp balancing */ > }; > > +void carp_vh_ref(void *, void *); > +void carp_vh_unref(void *, void *); > + > +struct srpl_rc carp_vh_rc = > + SRPL_RC_INITIALIZER(carp_vh_ref, carp_vh_unref, NULL); > + > struct carp_softc { > struct arpcom sc_ac; > #define sc_if sc_ac.ac_if > @@ -124,7 +133,9 @@ struct carp_softc { > #ifdef INET6 > struct ip6_moptions sc_im6o; > #endif /* INET6 */ > - TAILQ_ENTRY(carp_softc) sc_list; > + > + struct srpl_entry sc_list; > + struct refcnt sc_refcnt; > > int sc_suppress; > int sc_bow_out; > @@ -137,7 +148,7 @@ struct carp_softc { > > char sc_curlladdr[ETHER_ADDR_LEN]; > > - LIST_HEAD(__carp_vhosthead, carp_vhost_entry) carp_vhosts; > + struct srpl carp_vhosts; > int sc_vhe_count; > u_int8_t sc_vhids[CARP_MAXNODES]; > u_int8_t sc_advskews[CARP_MAXNODES]; > @@ -162,13 +173,19 @@ struct carp_softc { > struct carp_vhost_entry *cur_vhe; /* current active vhe */ > }; > > +void carp_sc_ref(void *, void *); > +void carp_sc_unref(void *, void *); > + > +struct srpl_rc carp_sc_rc = > + SRPL_RC_INITIALIZER(carp_sc_ref, carp_sc_unref, NULL); > + > int carp_opts[CARPCTL_MAXID] = { 0, 1, 0, LOG_CRIT }; /* XXX for now */ > struct carpstats carpstats; > > int carp_send_all_recur = 0; > > struct carp_if { > - TAILQ_HEAD(, carp_softc) vhif_vrs; > + struct srpl vhif_vrs; > }; > > #define CARP_LOG(l, sc, s) > \ > @@ -250,7 +267,9 @@ carp_hmac_prepare(struct carp_softc *sc) > struct carp_vhost_entry *vhe; > u_int8_t i; > > - LIST_FOREACH(vhe, &sc->carp_vhosts, vhost_entries) { > + KERNEL_ASSERT_LOCKED(); /* touching carp_vhosts */ > + > + SRPL_FOREACH_LOCKED(vhe, &sc->carp_vhosts, vhost_entries) { > for (i = 0; i < HMAC_MAX; i++) { > carp_hmac_prepare_ctx(vhe, i); > } > @@ -579,11 +598,12 @@ carp_proto_input_c(struct ifnet *ifp, st > else > cif = (struct carp_if *)ifp->if_carp; > > - TAILQ_FOREACH(sc, &cif->vhif_vrs, sc_list) { > + KERNEL_ASSERT_LOCKED(); /* touching vhif_vrs + carp_vhosts */ > + SRPL_FOREACH_LOCKED(sc, &cif->vhif_vrs, sc_list) { > if (af == AF_INET && > ismulti != IN_MULTICAST(sc->sc_peer.s_addr)) > continue; > - LIST_FOREACH(vhe, &sc->carp_vhosts, vhost_entries) { > + SRPL_FOREACH_LOCKED(vhe, &sc->carp_vhosts, vhost_entries) { > if (vhe->vhid == ch->carp_vhid) > goto found; > } > @@ -749,7 +769,9 @@ carp_clone_create(struct if_clone *ifc, > if (!sc) > return (ENOMEM); > > - LIST_INIT(&sc->carp_vhosts); > + refcnt_init(&sc->sc_refcnt); > + > + SRPL_INIT(&sc->carp_vhosts); > sc->sc_vhe_count = 0; > if (carp_new_vhost(sc, 0, 0)) { > free(sc, M_DEVBUF, sizeof(*sc)); > @@ -801,6 +823,8 @@ carp_new_vhost(struct carp_softc *sc, in > if (vhe == NULL) > return (ENOMEM); > > + refcnt_init(&vhe->vhost_refcnt); > + carp_sc_ref(NULL, sc); /* give a sc ref to the vhe */ > vhe->parent_sc = sc; > vhe->vhid = vhid; > vhe->advskew = advskew; > @@ -809,18 +833,23 @@ carp_new_vhost(struct carp_softc *sc, in > timeout_set(&vhe->md_tmo, carp_master_down, vhe); > timeout_set(&vhe->md6_tmo, carp_master_down, vhe); > > + KERNEL_ASSERT_LOCKED(); /* touching carp_vhosts */ > + > /* mark the first vhe as leader */ > - if (LIST_EMPTY(&sc->carp_vhosts)) { > + if (SRPL_EMPTY_LOCKED(&sc->carp_vhosts)) { > vhe->vhe_leader = 1; > - LIST_INSERT_HEAD(&sc->carp_vhosts, vhe, vhost_entries); > + SRPL_INSERT_HEAD_LOCKED(&carp_vh_rc, &sc->carp_vhosts, > + vhe, vhost_entries); > sc->sc_vhe_count = 1; > return (0); > } > > - LIST_FOREACH(vhe0, &sc->carp_vhosts, vhost_entries) > - if (LIST_NEXT(vhe0, vhost_entries) == NULL) > + SRPL_FOREACH_LOCKED(vhe0, &sc->carp_vhosts, vhost_entries) { > + if (SRPL_NEXT_LOCKED(vhe0, vhost_entries) == NULL) > break; > - LIST_INSERT_AFTER(vhe0, vhe, vhost_entries); > + } > + > + SRPL_INSERT_AFTER_LOCKED(&carp_vh_rc, vhe0, vhe, vhost_entries); > sc->sc_vhe_count++; > > return (0); > @@ -835,9 +864,9 @@ carp_clone_destroy(struct ifnet *ifp) > ether_ifdetach(ifp); > if_detach(ifp); > carp_destroy_vhosts(ifp->if_softc); > + refcnt_finalize(&sc->sc_refcnt, "carpdtor"); > free(sc->sc_imo.imo_membership, M_IPMOPTS, 0); > free(sc, M_DEVBUF, sizeof(*sc)); > - > return (0); > } > > @@ -846,7 +875,8 @@ carp_del_all_timeouts(struct carp_softc > { > struct carp_vhost_entry *vhe; > > - LIST_FOREACH(vhe, &sc->carp_vhosts, vhost_entries) { > + KERNEL_ASSERT_LOCKED(); /* touching carp_vhosts */ > + SRPL_FOREACH_LOCKED(vhe, &sc->carp_vhosts, vhost_entries) { > timeout_del(&vhe->ad_tmo); > timeout_del(&vhe->md_tmo); > timeout_del(&vhe->md6_tmo); > @@ -879,16 +909,20 @@ carpdetach(struct carp_softc *sc) > if (ifp0 == NULL) > return; > > + KERNEL_ASSERT_LOCKED(); /* touching vhif_vrs */ > + > + cif = (struct carp_if *)ifp0->if_carp; > + > /* Restore previous input handler. */ > - if_ih_remove(ifp0, carp_input, NULL); > + if_ih_remove(ifp0, carp_input, cif); > > s = splnet(); > if (sc->lh_cookie != NULL) > - hook_disestablish(ifp0->if_linkstatehooks, > - sc->lh_cookie); > - cif = (struct carp_if *)ifp0->if_carp; > - TAILQ_REMOVE(&cif->vhif_vrs, sc, sc_list); > - if (TAILQ_EMPTY(&cif->vhif_vrs)) { > + hook_disestablish(ifp0->if_linkstatehooks, sc->lh_cookie); > + > + SRPL_REMOVE_LOCKED(&carp_sc_rc, &cif->vhif_vrs, sc, > + carp_softc, sc_list); > + if (SRPL_EMPTY_LOCKED(&cif->vhif_vrs)) { > ifpromisc(ifp0, 0); > ifp0->if_carp = NULL; > free(cif, M_IFADDR, sizeof(*cif)); > @@ -904,9 +938,12 @@ carp_ifdetach(struct ifnet *ifp0) > struct carp_softc *sc, *nextsc; > struct carp_if *cif = (struct carp_if *)ifp0->if_carp; > > - for (sc = TAILQ_FIRST(&cif->vhif_vrs); sc; sc = nextsc) { > - nextsc = TAILQ_NEXT(sc, sc_list); > - carpdetach(sc); > + KERNEL_ASSERT_LOCKED(); /* touching vhif_vrs */ > + > + for (sc = SRPL_FIRST_LOCKED(&cif->vhif_vrs); sc != NULL; sc = nextsc) { > + nextsc = SRPL_NEXT_LOCKED(sc, sc_list); > + > + carpdetach(sc); /* this can free cif */ > } > } > > @@ -914,13 +951,15 @@ void > carp_destroy_vhosts(struct carp_softc *sc) > { > /* XXX bow out? */ > - struct carp_vhost_entry *vhe, *nvhe; > + struct carp_vhost_entry *vhe; > > - for (vhe = LIST_FIRST(&sc->carp_vhosts); vhe != NULL; vhe = nvhe) { > - nvhe = LIST_NEXT(vhe, vhost_entries); > - free(vhe, M_DEVBUF, sizeof(*vhe)); > + KERNEL_ASSERT_LOCKED(); /* touching carp_vhosts */ > + > + while ((vhe = SRPL_FIRST_LOCKED(&sc->carp_vhosts)) != NULL) { > + SRPL_REMOVE_LOCKED(&carp_vh_rc, &sc->carp_vhosts, vhe, > + carp_vhost_entry, vhost_entries); > + carp_vh_unref(NULL, vhe); /* drop last ref */ > } > - LIST_INIT(&sc->carp_vhosts); > sc->sc_vhe_count = 0; > } > > @@ -952,6 +991,8 @@ carp_send_ad_all(void) > struct carp_if *cif; > struct carp_softc *vh; > > + KERNEL_ASSERT_LOCKED(); /* touching vhif_vrs */ > + > if (carp_send_all_recur > 0) > return; > ++carp_send_all_recur; > @@ -960,7 +1001,7 @@ carp_send_ad_all(void) > continue; > > cif = (struct carp_if *)ifp0->if_carp; > - TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) { > + SRPL_FOREACH_LOCKED(vh, &cif->vhif_vrs, sc_list) { > if ((vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) == > (IFF_UP|IFF_RUNNING)) { > carp_vhe_send_ad_all(vh); > @@ -975,7 +1016,9 @@ carp_vhe_send_ad_all(struct carp_softc * > { > struct carp_vhost_entry *vhe; > > - LIST_FOREACH(vhe, &sc->carp_vhosts, vhost_entries) { > + KERNEL_ASSERT_LOCKED(); /* touching carp_vhosts */ > + > + SRPL_FOREACH_LOCKED(vhe, &sc->carp_vhosts, vhost_entries) { > if (vhe->state == MASTER) > carp_send_ad(vhe); > } > @@ -1302,7 +1345,8 @@ carp_update_lsmask(struct carp_softc *sc > sc->sc_lsmask = 0; > count = 0; > > - LIST_FOREACH(vhe, &sc->carp_vhosts, vhost_entries) { > + KERNEL_ASSERT_LOCKED(); /* touching carp_vhosts */ > + SRPL_FOREACH_LOCKED(vhe, &sc->carp_vhosts, vhost_entries) { > if (vhe->state == MASTER && count < sizeof(sc->sc_lsmask) * 8) > sc->sc_lsmask |= 1 << count; > count++; > @@ -1316,7 +1360,9 @@ carp_iamatch(struct in_ifaddr *ia, u_cha > u_int8_t **ether_shost) > { > struct carp_softc *sc = ia->ia_ifp->if_softc; > - struct carp_vhost_entry *vhe = LIST_FIRST(&sc->carp_vhosts); > + struct carp_vhost_entry *vhe = SRPL_FIRST_LOCKED(&sc->carp_vhosts); > + > + KERNEL_ASSERT_LOCKED(); /* touching carp_vhosts */ > > if (sc->sc_balancing == CARP_BAL_ARP) { > int lshash; > @@ -1332,7 +1378,8 @@ carp_iamatch(struct in_ifaddr *ia, u_cha > lshash = carp_hash(sc, src) % sc->sc_lscount; > if ((1 << lshash) & sc->sc_lsmask) { > int i = 0; > - LIST_FOREACH(vhe, &sc->carp_vhosts, vhost_entries) { > + SRPL_FOREACH_LOCKED(vhe, &sc->carp_vhosts, > + vhost_entries) { > if (i++ == lshash) > break; > } > @@ -1361,7 +1408,9 @@ int > carp_iamatch6(struct ifnet *ifp, u_char *src, struct sockaddr_dl **sdl) > { > struct carp_softc *sc = ifp->if_softc; > - struct carp_vhost_entry *vhe = LIST_FIRST(&sc->carp_vhosts); > + struct carp_vhost_entry *vhe = SRPL_FIRST_LOCKED(&sc->carp_vhosts); > + > + KERNEL_ASSERT_LOCKED(); /* touching carp_vhosts */ > > if (sc->sc_balancing == CARP_BAL_ARP) { > int lshash; > @@ -1380,7 +1429,8 @@ carp_iamatch6(struct ifnet *ifp, u_char > lshash = carp_hash(sc, src) % sc->sc_lscount; > if ((1 << lshash) & sc->sc_lsmask) { > int i = 0; > - LIST_FOREACH(vhe, &sc->carp_vhosts, vhost_entries) { > + SRPL_FOREACH_LOCKED(vhe, &sc->carp_vhosts, > + vhost_entries) { > if (i++ == lshash) > break; > } > @@ -1404,19 +1454,22 @@ carp_ourether(void *v, u_int8_t *ena) > struct carp_if *cif = (struct carp_if *)v; > struct carp_softc *vh; > > - TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) { > + KERNEL_ASSERT_LOCKED(); /* touching vhif_vrs + carp_vhosts */ > + > + SRPL_FOREACH_LOCKED(vh, &cif->vhif_vrs, sc_list) { > struct carp_vhost_entry *vhe; > if ((vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) != > (IFF_UP|IFF_RUNNING)) > continue; > if (vh->sc_balancing == CARP_BAL_ARP) { > - LIST_FOREACH(vhe, &vh->carp_vhosts, vhost_entries) > + SRPL_FOREACH_LOCKED(vhe, &vh->carp_vhosts, > + vhost_entries) > if (vhe->state == MASTER && > !memcmp(ena, vhe->vhe_enaddr, > ETHER_ADDR_LEN)) > return (&vh->sc_if); > } else { > - vhe = LIST_FIRST(&vh->carp_vhosts); > + vhe = SRPL_FIRST_LOCKED(&vh->carp_vhosts); > if ((vhe->state == MASTER || > vh->sc_balancing >= CARP_BAL_IP) && > !memcmp(ena, vh->sc_ac.ac_enaddr, ETHER_ADDR_LEN)) > @@ -1427,32 +1480,70 @@ carp_ourether(void *v, u_int8_t *ena) > } > > int > +carp_vhe_match(struct carp_softc *sc, uint8_t *ena) > +{ > + struct carp_vhost_entry *vhe; > + struct srpl_iter i; > + int match; > + > + if (sc->sc_balancing == CARP_BAL_ARP) { > + SRPL_FOREACH(vhe, &sc->carp_vhosts, &i, vhost_entries) { > + if (vhe->state == MASTER && > + !memcmp(ena, vhe->vhe_enaddr, ETHER_ADDR_LEN)) { > + match = 1; > + break; > + } > + } > + SRPL_LEAVE(&i, vhe); > + } else { > + vhe = SRPL_ENTER(&sc->carp_vhosts, &i); /* head */ > + match = (vhe->state == MASTER || > + sc->sc_balancing >= CARP_BAL_IP) && > + !memcmp(ena, sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN); > + SRPL_LEAVE(&i, vhe); > + } > + > + return (match); > +} > + > +int > carp_input(struct ifnet *ifp0, struct mbuf *m, void *cookie) > { > - struct carp_softc *sc; > struct ether_header *eh; > struct mbuf_list ml = MBUF_LIST_INITIALIZER(); > struct carp_if *cif; > - struct ifnet *ifp; > + struct carp_softc *sc; > + struct srpl_iter i; > > eh = mtod(m, struct ether_header *); > - cif = (struct carp_if *)ifp0->if_carp; > + cif = (struct carp_if *)cookie; > + KASSERT(cif == (struct carp_if *)ifp0->if_carp); > > - ifp = carp_ourether(cif, eh->ether_dhost); > - if (ifp == NULL && !ETHER_IS_MULTICAST(eh->ether_dhost)) > - return (0); > + SRPL_FOREACH(sc, &cif->vhif_vrs, &i, sc_list) { > + if ((sc->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) != > + (IFF_UP|IFF_RUNNING)) > + continue; > > - if (ifp == NULL) { > - struct carp_softc *vh; > - struct mbuf *m0; > + if (carp_vhe_match(sc, eh->ether_dhost)) > + break; > + } > + > + if (sc == NULL) { > + SRPL_LEAVE(&i, sc); > + > + if (!ETHER_IS_MULTICAST(eh->ether_dhost)) > + return (0); > > /* > * XXX Should really check the list of multicast addresses > * for each CARP interface _before_ copying. > */ > - TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) { > - if (!(vh->sc_if.if_flags & IFF_UP)) > + SRPL_FOREACH(sc, &cif->vhif_vrs, &i, sc_list) { > + struct mbuf *m0; > + > + if (!(sc->sc_if.if_flags & IFF_UP)) > continue; > + > m0 = m_copym2(m, 0, M_COPYALL, M_DONTWAIT); > if (m0 == NULL) > continue; > @@ -1460,8 +1551,9 @@ carp_input(struct ifnet *ifp0, struct mb > ml_init(&ml); > ml_enqueue(&ml, m0); > > - if_input(&vh->sc_if, &ml); > + if_input(&sc->sc_if, &ml); > } > + SRPL_LEAVE(&i, sc); > > return (0); > } > @@ -1469,15 +1561,14 @@ carp_input(struct ifnet *ifp0, struct mb > /* > * Clear mcast if received on a carp IP balanced address. > */ > - sc = ifp->if_softc; > if (sc->sc_balancing == CARP_BAL_IP && > ETHER_IS_MULTICAST(eh->ether_dhost)) > *(eh->ether_dhost) &= ~0x01; > > - > ml_enqueue(&ml, m); > + if_input(&sc->sc_if, &ml); > + SRPL_LEAVE(&i, sc); > > - if_input(ifp, &ml); > return (1); > } > > @@ -1554,7 +1645,9 @@ void > carp_setrun_all(struct carp_softc *sc, sa_family_t af) > { > struct carp_vhost_entry *vhe; > - LIST_FOREACH(vhe, &sc->carp_vhosts, vhost_entries) { > + > + KERNEL_ASSERT_LOCKED(); /* touching carp_vhost */ > + SRPL_FOREACH_LOCKED(vhe, &sc->carp_vhosts, vhost_entries) { > carp_setrun(vhe, af); > } > } > @@ -1671,7 +1764,7 @@ int > carp_set_ifp(struct carp_softc *sc, struct ifnet *ifp0) > { > struct carp_if *cif, *ncif = NULL; > - struct carp_softc *vr, *after = NULL; > + struct carp_softc *vr, *last = NULL, *after = NULL; > int myself = 0, error = 0; > int s; > > @@ -1693,7 +1786,7 @@ carp_set_ifp(struct carp_softc *sc, stru > return (error); > } > > - TAILQ_INIT(&ncif->vhif_vrs); > + SRPL_INIT(&ncif->vhif_vrs); > } else { > cif = (struct carp_if *)ifp0->if_carp; > if (carp_check_dup_vhids(sc, cif, NULL)) > @@ -1711,20 +1804,29 @@ carp_set_ifp(struct carp_softc *sc, stru > sc->sc_if.if_capabilities = ifp0->if_capabilities & > IFCAP_CSUM_MASK; > cif = (struct carp_if *)ifp0->if_carp; > - TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list) { > + SRPL_FOREACH_LOCKED(vr, &cif->vhif_vrs, sc_list) { > + struct carp_vhost_entry *vrhead, *schead; > + last = vr; > + > if (vr == sc) > myself = 1; > - if (LIST_FIRST(&vr->carp_vhosts)->vhid < > - LIST_FIRST(&sc->carp_vhosts)->vhid) > + > + vrhead = SRPL_FIRST_LOCKED(&vr->carp_vhosts); > + schead = SRPL_FIRST_LOCKED(&sc->carp_vhosts); > + if (vrhead->vhid < schead->vhid) > after = vr; > } > > if (!myself) { > /* We're trying to keep things in order */ > - if (after == NULL) { > - TAILQ_INSERT_TAIL(&cif->vhif_vrs, sc, sc_list); > + if (last == NULL) { > + SRPL_INSERT_HEAD_LOCKED(&carp_sc_rc, &cif->vhif_vrs, > + sc, sc_list); > + } else if (after == NULL) { > + SRPL_INSERT_AFTER_LOCKED(&carp_sc_rc, last, > + sc, sc_list); > } else { > - TAILQ_INSERT_AFTER(&cif->vhif_vrs, after, > + SRPL_INSERT_AFTER_LOCKED(&carp_sc_rc, after, > sc, sc_list); > } > } > @@ -1736,7 +1838,7 @@ carp_set_ifp(struct carp_softc *sc, stru > carp_carpdev_state, ifp0); > > /* Change input handler of the physical interface. */ > - if_ih_insert(ifp0, carp_input, NULL); > + if_ih_insert(ifp0, carp_input, cif); > > s = splnet(); > carp_carpdev_state(ifp0); > @@ -1773,10 +1875,11 @@ carp_set_enaddr(struct carp_softc *sc) > { > struct carp_vhost_entry *vhe; > > - LIST_FOREACH(vhe, &sc->carp_vhosts, vhost_entries) > + KERNEL_ASSERT_LOCKED(); /* touching carp_vhosts */ > + SRPL_FOREACH_LOCKED(vhe, &sc->carp_vhosts, vhost_entries) > carp_set_vhe_enaddr(vhe); > > - vhe = LIST_FIRST(&sc->carp_vhosts); > + vhe = SRPL_FIRST_LOCKED(&sc->carp_vhosts); > > /* > * Use the carp lladdr if the running one isn't manually set. > @@ -2009,7 +2112,8 @@ carp_ioctl(struct ifnet *ifp, u_long cmd > break; > > case SIOCSIFFLAGS: > - vhe = LIST_FIRST(&sc->carp_vhosts); > + KERNEL_ASSERT_LOCKED(); /* touching carp_vhosts */ > + vhe = SRPL_FIRST_LOCKED(&sc->carp_vhosts); > if (vhe->state != INIT && !(ifr->ifr_flags & IFF_UP)) { > carp_del_all_timeouts(sc); > > @@ -2029,7 +2133,8 @@ carp_ioctl(struct ifnet *ifp, u_long cmd > break; > > case SIOCSVH: > - vhe = LIST_FIRST(&sc->carp_vhosts); > + KERNEL_ASSERT_LOCKED(); /* touching carp_vhosts */ > + vhe = SRPL_FIRST_LOCKED(&sc->carp_vhosts); > if ((error = suser(p, 0)) != 0) > break; > if ((error = copyin(ifr->ifr_data, &carpr, sizeof carpr))) > @@ -2052,7 +2157,9 @@ carp_ioctl(struct ifnet *ifp, u_long cmd > carp_setrun_all(sc, 0); > break; > case MASTER: > - LIST_FOREACH(vhe, &sc->carp_vhosts, > + KERNEL_ASSERT_LOCKED(); > + /* touching carp_vhosts */ > + SRPL_FOREACH_LOCKED(vhe, &sc->carp_vhosts, > vhost_entries) > carp_master_down(vhe); > break; > @@ -2073,7 +2180,9 @@ carp_ioctl(struct ifnet *ifp, u_long cmd > if (memcmp(sc->sc_advskews, carpr.carpr_advskews, > sizeof(sc->sc_advskews))) { > i = 0; > - LIST_FOREACH(vhe, &sc->carp_vhosts, vhost_entries) > + KERNEL_ASSERT_LOCKED(); /* touching carp_vhosts */ > + SRPL_FOREACH_LOCKED(vhe, &sc->carp_vhosts, > + vhost_entries) > vhe->advskew = carpr.carpr_advskews[i++]; > bcopy(carpr.carpr_advskews, sc->sc_advskews, > sizeof(sc->sc_advskews)); > @@ -2103,7 +2212,8 @@ carp_ioctl(struct ifnet *ifp, u_long cmd > strlcpy(carpr.carpr_carpdev, sc->sc_carpdev->if_xname, > IFNAMSIZ); > i = 0; > - LIST_FOREACH(vhe, &sc->carp_vhosts, vhost_entries) { > + KERNEL_ASSERT_LOCKED(); /* touching carp_vhosts */ > + SRPL_FOREACH_LOCKED(vhe, &sc->carp_vhosts, vhost_entries) { > carpr.carpr_vhids[i] = vhe->vhid; > carpr.carpr_advskews[i] = vhe->advskew; > carpr.carpr_states[i] = vhe->state; > @@ -2150,17 +2260,20 @@ carp_check_dup_vhids(struct carp_softc * > struct carp_vhost_entry *vhe, *vhe0; > int i; > > - TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list) { > + KERNEL_ASSERT_LOCKED(); /* touching vhif_vrs + carp_vhosts */ > + > + SRPL_FOREACH_LOCKED(vr, &cif->vhif_vrs, sc_list) { > if (vr == sc) > continue; > - LIST_FOREACH(vhe, &vr->carp_vhosts, vhost_entries) { > + SRPL_FOREACH_LOCKED(vhe, &vr->carp_vhosts, vhost_entries) { > if (carpr) { > for (i = 0; carpr->carpr_vhids[i]; i++) { > if (vhe->vhid == carpr->carpr_vhids[i]) > return (EINVAL); > } > } > - LIST_FOREACH(vhe0, &sc->carp_vhosts, vhost_entries) { > + SRPL_FOREACH_LOCKED(vhe0, &sc->carp_vhosts, > + vhost_entries) { > if (vhe->vhid == vhe0->vhid) > return (EINVAL); > } > @@ -2312,7 +2425,9 @@ carp_output(struct ifnet *ifp, struct mb > struct carp_softc *sc = ((struct carp_softc *)ifp->if_softc); > struct carp_vhost_entry *vhe; > > - vhe = sc->cur_vhe ? sc->cur_vhe : LIST_FIRST(&sc->carp_vhosts); > + KERNEL_ASSERT_LOCKED(); /* touching carp_vhosts */ > + > + vhe = sc->cur_vhe ? sc->cur_vhe : SRPL_FIRST_LOCKED(&sc->carp_vhosts); > > if ((sc->sc_carpdev == NULL) || > (!sc->sc_balancing && vhe->state != MASTER)) { > @@ -2328,7 +2443,9 @@ carp_set_state_all(struct carp_softc *sc > { > struct carp_vhost_entry *vhe; > > - LIST_FOREACH(vhe, &sc->carp_vhosts, vhost_entries) { > + KERNEL_ASSERT_LOCKED(); /* touching carp_vhosts */ > + > + SRPL_FOREACH_LOCKED(vhe, &sc->carp_vhosts, vhost_entries) { > if (vhe->state == state) > continue; > > @@ -2444,7 +2561,9 @@ carp_carpdev_state(void *v) > > cif = (struct carp_if *)ifp0->if_carp; > > - TAILQ_FOREACH(sc, &cif->vhif_vrs, sc_list) { > + KERNEL_ASSERT_LOCKED(); /* touching vhif_vrs */ > + > + SRPL_FOREACH_LOCKED(sc, &cif->vhif_vrs, sc_list) { > int suppressed = sc->sc_suppress; > > if (sc->sc_carpdev->if_link_state == LINK_STATE_DOWN || > @@ -2590,4 +2709,39 @@ carp_ether_purgemulti(struct carp_softc > LIST_REMOVE(mc, mc_entries); > free(mc, M_DEVBUF, sizeof(*mc)); > } > +} > + > +void > +carp_vh_ref(void *null, void *v) > +{ > + struct carp_vhost_entry *vhe = v; > + > + refcnt_take(&vhe->vhost_refcnt); > +} > + > +void > +carp_vh_unref(void *null, void *v) > +{ > + struct carp_vhost_entry *vhe = v; > + > + if (refcnt_rele(&vhe->vhost_refcnt)) { > + carp_sc_unref(NULL, vhe->parent_sc); > + free(vhe, M_DEVBUF, sizeof(*vhe)); > + } > +} > + > +void > +carp_sc_ref(void *null, void *s) > +{ > + struct carp_softc *sc = s; > + > + refcnt_take(&sc->sc_refcnt); > +} > + > +void > +carp_sc_unref(void *null, void *s) > +{ > + struct carp_softc *sc = s; > + > + refcnt_rele_wake(&sc->sc_refcnt); > } >