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);
> }
> 


Reply via email to