Turns out that turning arpinput() mpsafe is more complicated than
expected because of the way carp(4) has been hooked^Whacked in it.

Depending on the load-balancing mode arpinput() will need to use
one Ethernet address or another one.  After some discussions here
at u2k15 we figured out that ARP load-balancing might no longer be
a required feature as its use cases are limited and you'd probably
better run relayd(8) nowadays.

Getting rid of the ARP load-balancing mode in carp(4) reduce the
madness to two cases: either we use the Ethernet address of the
parent interface or the one of the carp interface.

Does anybody will mourn this removal?  Manage will follow if I get
oks.

Index: netinet/if_ether.c
===================================================================
RCS file: /cvs/src/sys/netinet/if_ether.c,v
retrieving revision 1.178
diff -u -p -r1.178 if_ether.c
--- netinet/if_ether.c  27 Oct 2015 10:54:52 -0000      1.178
+++ netinet/if_ether.c  27 Oct 2015 12:03:11 -0000
@@ -515,7 +515,7 @@ in_arpinput(struct mbuf *m)
        struct mbuf *mh;
        u_int8_t *enaddr = NULL;
 #if NCARP > 0
-       u_int8_t *ether_shost = NULL;
+       uint8_t *ethshost = NULL;
 #endif
        char addr[INET_ADDRSTRLEN];
        int op, changed = 0;
@@ -554,18 +554,11 @@ in_arpinput(struct mbuf *m)
                if (itaddr.s_addr != ifatoia(ifa)->ia_addr.sin_addr.s_addr)
                        continue;
 
+               if (op == ARPOP_REPLY)
+                       break;
 #if NCARP > 0
-               if (ifp->if_type == IFT_CARP &&
-                   ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) ==
-                   (IFF_UP|IFF_RUNNING))) {
-                       if (op == ARPOP_REPLY)
-                               break;
-                       if (carp_iamatch(ifp, ea->arp_sha,
-                           &enaddr, &ether_shost))
-                               break;
-                       else
-                               goto out;
-               }
+               if (ifp->if_type == IFT_CARP && !carp_iamatch(ifp, &ethshost))
+                       goto out;
 #endif
                break;
        }
@@ -731,8 +724,8 @@ out:
        eh = (struct ether_header *)sa.sa_data;
        memcpy(eh->ether_dhost, ea->arp_tha, sizeof(eh->ether_dhost));
 #if NCARP > 0
-       if (ether_shost)
-               enaddr = ether_shost;
+       if (ethshost)
+               enaddr = ethshost;
 #endif
        memcpy(eh->ether_shost, enaddr, sizeof(eh->ether_shost));
 
Index: netinet/ip_carp.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_carp.c,v
retrieving revision 1.278
diff -u -p -r1.278 ip_carp.c
--- netinet/ip_carp.c   25 Oct 2015 11:58:11 -0000      1.278
+++ netinet/ip_carp.c   27 Oct 2015 12:11:50 -0000
@@ -236,7 +236,6 @@ int carp_set_ifp(struct carp_softc *, st
 void   carp_set_enaddr(struct carp_softc *);
 void   carp_set_vhe_enaddr(struct carp_vhost_entry *);
 void   carp_addr_updated(void *);
-u_int32_t      carp_hash(struct carp_softc *, u_char *);
 int    carp_set_addr(struct carp_softc *, struct sockaddr_in *);
 int    carp_join_multicast(struct carp_softc *);
 #ifdef INET6
@@ -1297,48 +1296,13 @@ carp_send_na(struct carp_softc *sc)
 }
 #endif /* INET6 */
 
-/*
- * Originated from bridge_hash() in if_bridge.c
- */
-#define        mix(a, b, c) do {                                               
\
-       a -= b; a -= c; a ^= (c >> 13);                                 \
-       b -= c; b -= a; b ^= (a << 8);                                  \
-       c -= a; c -= b; c ^= (b >> 13);                                 \
-       a -= b; a -= c; a ^= (c >> 12);                                 \
-       b -= c; b -= a; b ^= (a << 16);                                 \
-       c -= a; c -= b; c ^= (b >> 5);                                  \
-       a -= b; a -= c; a ^= (c >> 3);                                  \
-       b -= c; b -= a; b ^= (a << 10);                                 \
-       c -= a; c -= b; c ^= (b >> 15);                                 \
-} while (0)
-
-u_int32_t
-carp_hash(struct carp_softc *sc, u_char *src)
-{
-       u_int32_t a = 0x9e3779b9, b = sc->sc_hashkey[0], c = sc->sc_hashkey[1];
-
-       c += sc->sc_key[3] << 24;
-       c += sc->sc_key[2] << 16;
-       c += sc->sc_key[1] << 8;
-       c += sc->sc_key[0];
-       b += src[5] << 8;
-       b += src[4];
-       a += src[3] << 24;
-       a += src[2] << 16;
-       a += src[1] << 8;
-       a += src[0];
-
-       mix(a, b, c);
-       return (c);
-}
-
 void
 carp_update_lsmask(struct carp_softc *sc)
 {
        struct carp_vhost_entry *vhe;
        int count;
 
-       if (!sc->sc_balancing)
+       if (sc->sc_balancing == CARP_BAL_NONE)
                return;
 
        sc->sc_lsmask = 0;
@@ -1355,48 +1319,20 @@ carp_update_lsmask(struct carp_softc *sc
 }
 
 int
-carp_iamatch(struct ifnet *ifp, u_char *src, u_int8_t **sha,
-    u_int8_t **ether_shost)
+carp_iamatch(struct ifnet *ifp, uint8_t **ether_shost)
 {
        struct carp_softc *sc = ifp->if_softc;
        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;
-               /*
-                * We use the source MAC address to decide which virtual host
-                * should handle the request. If we're master of that virtual
-                * host, then we respond, otherwise, just drop the arp packet
-                * on the floor.
-                */
-
-               if (sc->sc_lscount == 0) /* just to be safe */
-                       return (0);
-               lshash = carp_hash(sc, src) % sc->sc_lscount;
-               if ((1 << lshash) & sc->sc_lsmask) {
-                       int i = 0;
-                       SRPL_FOREACH_LOCKED(vhe, &sc->carp_vhosts,
-                           vhost_entries) {
-                               if (i++ == lshash)
-                                       break;
-                       }
-                       if (vhe == NULL)
-                               return (0);
-                       *sha = vhe->vhe_enaddr;
-                       return (1);
-               }
-       } else if (sc->sc_balancing == CARP_BAL_IPSTEALTH ||
-           sc->sc_balancing == CARP_BAL_IP) {
-               if (vhe->state == MASTER) {
-                       *ether_shost = ((struct arpcom *)sc->sc_carpdev)->
-                           ac_enaddr;
-                       return (1);
+       if (vhe->state == MASTER) {
+               if (sc->sc_balancing == CARP_BAL_IPSTEALTH ||
+                   sc->sc_balancing == CARP_BAL_IP) {
+                       struct arpcom *ac = (struct arpcom *)sc->sc_carpdev;
+                       *ether_shost = ac->ac_enaddr;
                }
-       } else {
-               if (vhe->state == MASTER)
-                       return (1);
+               return (1);
        }
 
        return (0);
@@ -1404,44 +1340,15 @@ carp_iamatch(struct ifnet *ifp, u_char *
 
 #ifdef INET6
 int
-carp_iamatch6(struct ifnet *ifp, u_char *src, struct sockaddr_dl **sdl)
+carp_iamatch6(struct ifnet *ifp)
 {
        struct carp_softc *sc = ifp->if_softc;
        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;
-               /*
-                * We use the source MAC address to decide which virtual host
-                * should handle the request. If we're master of that virtual
-                * host, then we respond, otherwise, just drop the ndp packet
-                * on the floor.
-                */
-
-               /* can happen if optional src lladdr is not provided */
-               if (src == NULL)
-                       return (0);
-               if (sc->sc_lscount == 0) /* just to be safe */
-                       return (0);
-               lshash = carp_hash(sc, src) % sc->sc_lscount;
-               if ((1 << lshash) & sc->sc_lsmask) {
-                       int i = 0;
-                       SRPL_FOREACH_LOCKED(vhe, &sc->carp_vhosts,
-                           vhost_entries) {
-                               if (i++ == lshash)
-                                       break;
-                       }
-                       if (vhe == NULL)
-                               return (0);
-                       *sdl = &vhe->vhe_sdl;
-                       return (1);
-               }
-       } else {
-               if (vhe->state == MASTER)
-                       return (1);
-       }
+       if (vhe->state == MASTER)
+               return (1);
 
        return (0);
 }
@@ -1460,20 +1367,10 @@ carp_ourether(void *v, u_int8_t *ena)
                if ((vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
                    (IFF_UP|IFF_RUNNING))
                        continue;
-               if (vh->sc_balancing == CARP_BAL_ARP) {
-                       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 = 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))
-                               return (&vh->sc_if);
-               }
+               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))
+                       return (&vh->sc_if);
        }
        return (NULL);
 }
@@ -1485,22 +1382,10 @@ carp_vhe_match(struct carp_softc *sc, ui
        struct srpl_iter i;
        int match = 0;
 
-       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);
-       }
+       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);
 }
@@ -1583,7 +1468,7 @@ carp_lsdrop(struct mbuf *m, sa_family_t 
        KASSERT(ifp != NULL);
 
        sc = ifp->if_softc;
-       if (sc->sc_balancing < CARP_BAL_IP)
+       if (sc->sc_balancing == CARP_BAL_NONE)
                goto done;
        /*
         * Never drop carp advertisements.
@@ -2430,7 +2315,7 @@ carp_output(struct ifnet *ifp, struct mb
        vhe = sc->cur_vhe ? sc->cur_vhe : SRPL_FIRST_LOCKED(&sc->carp_vhosts);
 
        if ((sc->sc_carpdev == NULL) ||
-           (!sc->sc_balancing && vhe->state != MASTER)) {
+           (sc->sc_balancing == CARP_BAL_NONE && vhe->state != MASTER)) {
                m_freem(m);
                return (ENETUNREACH);
        }
Index: netinet/ip_carp.h
===================================================================
RCS file: /cvs/src/sys/netinet/ip_carp.h,v
retrieving revision 1.35
diff -u -p -r1.35 ip_carp.h
--- netinet/ip_carp.h   22 Oct 2015 13:30:29 -0000      1.35
+++ netinet/ip_carp.h   27 Oct 2015 12:01:17 -0000
@@ -132,13 +132,12 @@ struct carpreq {
        u_int8_t        carpr_vhids[CARP_MAXNODES];
        u_int8_t        carpr_advskews[CARP_MAXNODES];
        u_int8_t        carpr_states[CARP_MAXNODES];
-#define        CARP_BAL_MODES  "none", "arp", "ip", "ip-stealth", "ip-unicast"
+#define        CARP_BAL_MODES  "none", "ip", "ip-stealth", "ip-unicast"
 #define CARP_BAL_NONE          0
-#define CARP_BAL_ARP           1
-#define CARP_BAL_IP            2
-#define CARP_BAL_IPSTEALTH     3
-#define CARP_BAL_IPUNICAST     4
-#define CARP_BAL_MAXID         4
+#define CARP_BAL_IP            1
+#define CARP_BAL_IPSTEALTH     2
+#define CARP_BAL_IPUNICAST     3
+#define CARP_BAL_MAXID         3
        u_int8_t        carpr_balancing;
        int             carpr_advbase;
        unsigned char   carpr_key[CARP_KEY_LEN];
@@ -168,9 +167,8 @@ void                 carp_proto_input (struct mbuf *, 
 void            carp_carpdev_state(void *);
 void            carp_group_demote_adj(struct ifnet *, int, char *);
 int             carp6_proto_input(struct mbuf **, int *, int);
-int             carp_iamatch(struct ifnet *, u_char *, u_int8_t **,
-                    u_int8_t **);
-int             carp_iamatch6(struct ifnet *, u_char *, struct sockaddr_dl **);
+int             carp_iamatch(struct ifnet *, uint8_t **);
+int             carp_iamatch6(struct ifnet *);
 struct ifnet   *carp_ourether(void *, u_int8_t *);
 int             carp_output(struct ifnet *, struct mbuf *, struct sockaddr *,
                     struct rtentry *);
Index: netinet6/in6.c
===================================================================
RCS file: /cvs/src/sys/netinet6/in6.c,v
retrieving revision 1.176
diff -u -p -r1.176 in6.c
--- netinet6/in6.c      25 Oct 2015 11:58:11 -0000      1.176
+++ netinet6/in6.c      27 Oct 2015 11:50:19 -0000
@@ -1648,9 +1648,6 @@ in6_ifawithscope(struct ifnet *oifp, str
        struct ifaddr *ifa;
        struct ifnet *ifp;
        struct in6_ifaddr *ia6_best = NULL;
-#if NCARP > 0
-       struct sockaddr_dl *proxydl = NULL;
-#endif
 
        if (oifp == NULL) {
                printf("in6_ifawithscope: output interface is not specified\n");
@@ -1670,8 +1667,7 @@ in6_ifawithscope(struct ifnet *oifp, str
                 * Never use a carp address of an interface which is not
                 * the master.
                 */
-               if (ifp->if_type == IFT_CARP &&
-                   !carp_iamatch6(ifp, NULL, &proxydl))
+               if (ifp->if_type == IFT_CARP && !carp_iamatch6(ifp))
                        continue;
 #endif
 
Index: netinet6/nd6_nbr.c
===================================================================
RCS file: /cvs/src/sys/netinet6/nd6_nbr.c,v
retrieving revision 1.97
diff -u -p -r1.97 nd6_nbr.c
--- netinet6/nd6_nbr.c  22 Oct 2015 15:37:47 -0000      1.97
+++ netinet6/nd6_nbr.c  27 Oct 2015 11:50:18 -0000
@@ -215,8 +215,7 @@ nd6_ns_input(struct mbuf *m, int off, in
        /* (1) and (3) check. */
        ifa = &in6ifa_ifpwithaddr(ifp, &taddr6)->ia_ifa;
 #if NCARP > 0
-       if (ifp->if_type == IFT_CARP && ifa &&
-           !carp_iamatch6(ifp, lladdr, &proxydl))
+       if (ifp->if_type == IFT_CARP && ifa && !carp_iamatch6(ifp))
                ifa = NULL;
 #endif
 
@@ -670,14 +669,11 @@ nd6_na_input(struct mbuf *m, int off, in
 
        if (ifa) {
 #if NCARP > 0
-               struct sockaddr_dl *proxydl = NULL;
-
                /*
                 * Ignore NAs silently for carp addresses if we're not
                 * the CARP master.
                 */
-               if (ifp->if_type == IFT_CARP &&
-                   !carp_iamatch6(ifp, lladdr, &proxydl))
+               if (ifp->if_type == IFT_CARP && !carp_iamatch6(ifp))
                        goto freeit;
 #endif
                log(LOG_ERR,
@@ -923,9 +919,6 @@ nd6_na_output(struct ifnet *ifp, struct 
        int icmp6len, maxlen, error;
        caddr_t mac;
        struct route_in6 ro;
-#if NCARP > 0
-       struct sockaddr_dl *proxydl = NULL;
-#endif
 
        mac = NULL;
        bzero(&ro, sizeof(ro));
@@ -1055,7 +1048,7 @@ nd6_na_output(struct ifnet *ifp, struct 
 
 #if NCARP > 0
        /* Do not send NAs for carp addresses if we're not the CARP master. */
-       if (ifp->if_type == IFT_CARP && !carp_iamatch6(ifp, mac, &proxydl))
+       if (ifp->if_type == IFT_CARP && !carp_iamatch6(ifp))
                goto bad;
 #endif
 

Reply via email to