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 <[email protected]> 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);
> }
>