If stealth balancing is used in setups where the carpdev
does not share an IP in the same subnet as carp,
ARP queries will be replied through the carp interface.
arprequest() (which is also used to form replies) will
use the MAC address of the carp interface as the
ethernet source address.
This will let a switch learn the virtual MAC, and
thus break stealth balancing.

This diff extends arprequest() with an optional
ether source address argument.
Instead of extending the #ifdef maze even further,
a new function carp_arprequest() is used to handle
all the carp cases.

OK?

Index: netinet/if_ether.c
===================================================================
RCS file: /cvs/src/sys/netinet/if_ether.c,v
retrieving revision 1.93
diff -p -u -r1.93 if_ether.c
--- netinet/if_ether.c  18 Sep 2011 11:17:58 -0000      1.93
+++ netinet/if_ether.c  17 Oct 2011 21:17:11 -0000
@@ -227,7 +227,7 @@ arp_rtrequest(int req, struct rtentry *r
                        arprequest(rt->rt_ifp,
                            &SIN(rt_key(rt))->sin_addr.s_addr,
                            &SIN(rt_key(rt))->sin_addr.s_addr,
-                           (u_char *)LLADDR(SDL(gate)));
+                           (u_char *)LLADDR(SDL(gate)), NULL);
                /*FALLTHROUGH*/
        case RTM_RESOLVE:
                if (gate->sa_family != AF_LINK ||
@@ -322,7 +322,8 @@ arp_rtrequest(int req, struct rtentry *r
  *     - arp header source ethernet address
  */
 void
-arprequest(struct ifnet *ifp, u_int32_t *sip, u_int32_t *tip, u_int8_t *enaddr)
+arprequest(struct ifnet *ifp, u_int32_t *sip, u_int32_t *tip, u_int8_t *enaddr,
+    u_int8_t *eshost)
 {
        struct mbuf *m;
        struct ether_header *eh;
@@ -346,7 +347,7 @@ arprequest(struct ifnet *ifp, u_int32_t 
        ea->arp_hln = sizeof(ea->arp_sha);      /* hardware address length */
        ea->arp_pln = sizeof(ea->arp_spa);      /* protocol address length */
        ea->arp_op = htons(ARPOP_REQUEST);
-       bcopy((caddr_t)enaddr, (caddr_t)eh->ether_shost,
+       bcopy(eshost ? eshost : enaddr, (caddr_t)eh->ether_shost,
              sizeof(eh->ether_shost));
        bcopy((caddr_t)enaddr, (caddr_t)ea->arp_sha, sizeof(ea->arp_sha));
        bcopy((caddr_t)sip, (caddr_t)ea->arp_spa, sizeof(ea->arp_spa));
@@ -467,15 +468,14 @@ arpresolve(struct arpcom *ac, struct rte
                if (la->la_asked == 0 || rt->rt_expire != time_second) {
                        rt->rt_expire = time_second;
                        if (la->la_asked++ < arp_maxtries)
+#if NCARP > 0
+                               carp_arprequest(rt, ac, dst);
+#else
                                arprequest(&ac->ac_if,
                                    
&(SIN(rt->rt_ifa->ifa_addr)->sin_addr.s_addr),
-                                   &(SIN(dst)->sin_addr.s_addr),
-#if NCARP > 0
-                                   (rt->rt_ifp->if_type == IFT_CARP) ?
-                                       ((struct arpcom *) rt->rt_ifp->if_softc
-                                       )->ac_enaddr :
+                                   &(SIN(dst)->sin_addr.s_addr), ac->ac_enaddr,
+                                   NULL);
 #endif
-                                   ac->ac_enaddr);
                        else {
                                rt->rt_flags |= RTF_REJECT;
                                rt->rt_expire += arpt_down;
@@ -850,7 +850,7 @@ arp_ifinit(struct arpcom *ac, struct ifa
        arprequest(&ac->ac_if,
            &(IA_SIN(ifa)->sin_addr.s_addr),
            &(IA_SIN(ifa)->sin_addr.s_addr),
-           ac->ac_enaddr);
+           ac->ac_enaddr, NULL);
        ifa->ifa_rtrequest = arp_rtrequest;
        ifa->ifa_flags |= RTF_CLONING;
 }
Index: netinet/if_ether.h
===================================================================
RCS file: /cvs/src/sys/netinet/if_ether.h,v
retrieving revision 1.47
diff -p -u -r1.47 if_ether.h
--- netinet/if_ether.h  8 Feb 2010 13:32:50 -0000       1.47
+++ netinet/if_ether.h  17 Oct 2011 21:00:55 -0000
@@ -278,7 +278,8 @@ do {                                                        
                \
 
 extern struct ifnet *myip_ifp;
 
-void arprequest(struct ifnet *, u_int32_t *, u_int32_t *, u_int8_t *);
+void arprequest(struct ifnet *, u_int32_t *, u_int32_t *, u_int8_t *,
+    u_int8_t *);
 void revarpinput(struct mbuf *);
 void in_revarpinput(struct mbuf *);
 void revarprequest(struct ifnet *);
Index: netinet/ip_carp.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_carp.c,v
retrieving revision 1.191
diff -p -u -r1.191 ip_carp.c
--- netinet/ip_carp.c   16 Oct 2011 21:07:19 -0000      1.191
+++ netinet/ip_carp.c   27 Oct 2011 07:34:29 -0000
@@ -1333,7 +1333,7 @@ carp_send_arp(struct carp_softc *sc)
                        continue;
 
                in = ifatoia(ifa)->ia_addr.sin_addr.s_addr;
-               arprequest(sc->sc_carpdev, &in, &in, sc->sc_ac.ac_enaddr);
+               arprequest(sc->sc_carpdev, &in, &in, sc->sc_ac.ac_enaddr, NULL);
                DELAY(1000);    /* XXX */
        }
        splx(s);
@@ -1462,6 +1462,23 @@ carp_iamatch(struct in_ifaddr *ia, u_cha
        }
 
        return (0);
+}
+
+void
+carp_arprequest(struct rtentry *rt, struct arpcom *ac, struct sockaddr *dst)
+{
+       u_int8_t *enaddr = ac->ac_enaddr;
+       u_int8_t *eshost = NULL;
+
+       if (rt->rt_ifp->if_type == IFT_CARP) {
+               struct carp_softc *sc = rt->rt_ifp->if_softc;
+               enaddr = ((struct arpcom *)rt->rt_ifp->if_softc)->ac_enaddr;
+               if (sc->sc_balancing == CARP_BAL_IPSTEALTH)
+                       eshost = ac->ac_enaddr;
+       }
+       arprequest(&ac->ac_if,
+           &(satosin(rt->rt_ifa->ifa_addr)->sin_addr.s_addr),
+           &(satosin(dst)->sin_addr.s_addr), enaddr, eshost);
 }
 
 #ifdef INET6
Index: netinet/ip_carp.h
===================================================================
RCS file: /cvs/src/sys/netinet/ip_carp.h,v
retrieving revision 1.28
diff -p -u -r1.28 ip_carp.h
--- netinet/ip_carp.h   25 Apr 2010 17:38:53 -0000      1.28
+++ netinet/ip_carp.h   17 Oct 2011 20:58:48 -0000
@@ -179,5 +179,7 @@ int          carp_sysctl(int *, u_int,  void *,
 int             carp_lsdrop(struct mbuf *, sa_family_t, u_int32_t *, u_int32_t 
*);
 void            carp_rewrite_lladdr(struct ifnet *, u_int8_t *);
 int             carp_our_mcastaddr(struct ifnet *, u_int8_t *);
+void            carp_arprequest(struct rtentry *, struct arpcom *,
+                    struct sockaddr *);
 #endif /* _KERNEL */
 #endif /* _NETINET_IP_CARP_H_ */

Reply via email to