This diff is a cleanup needed for upcoming bridge(4) changes but has two
nice side effects on its own.

By moving the Ethernet header rewrite logic into carp_start(), it is now
possible to tcpdump(8) output packets on a carp(4) interface and we get
rid of the "#if NCARP > 0" in ether_output().

Moving such logic into carp_start() is the best solution I came with.
It works with all our pseudo-drivers in a unified way, will allow me
to fix some bridge(4) bugs and does not require a complex change in
the network stack like if_input().

Ok?

Index: net/if_ethersubr.c
===================================================================
RCS file: /cvs/src/sys/net/if_ethersubr.c,v
retrieving revision 1.202
diff -u -p -r1.202 if_ethersubr.c
--- net/if_ethersubr.c  2 Jun 2015 09:38:24 -0000       1.202
+++ net/if_ethersubr.c  2 Jun 2015 10:05:31 -0000
@@ -113,11 +113,6 @@ didn't get a copy, you may request one f
 #include <net/if_vlan_var.h>
 #endif /* NVLAN > 0 */
 
-#include "carp.h"
-#if NCARP > 0
-#include <netinet/ip_carp.h>
-#endif
-
 #include "pppoe.h"
 #if NPPPOE > 0
 #include <net/if_pppoe.h>
@@ -243,18 +238,17 @@ ether_addheader(struct mbuf **m, struct 
  * Assumes that ifp is actually pointer to arpcom structure.
  */
 int
-ether_output(struct ifnet *ifp0, struct mbuf *m0, struct sockaddr *dst,
+ether_output(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst,
     struct rtentry *rt)
 {
        u_int16_t etype;
-       int len, error = 0;
        u_char edst[ETHER_ADDR_LEN];
        u_char *esrc;
        struct mbuf *m = m0;
        struct mbuf *mcopy = NULL;
        struct ether_header *eh;
-       struct arpcom *ac = (struct arpcom *)ifp0;
-       struct ifnet *ifp = ifp0;
+       struct arpcom *ac = (struct arpcom *)ifp;
+       int error = 0;
 
 #ifdef DIAGNOSTIC
        if (ifp->if_rdomain != rtable_l2(m->m_pkthdr.ph_rtableid)) {
@@ -267,20 +261,6 @@ ether_output(struct ifnet *ifp0, struct 
 
        esrc = ac->ac_enaddr;
 
-#if NCARP > 0
-       if (ifp->if_type == IFT_CARP) {
-               ifp = ifp->if_carpdev;
-               ac = (struct arpcom *)ifp;
-
-               if ((ifp0->if_flags & (IFF_UP|IFF_RUNNING)) !=
-                   (IFF_UP|IFF_RUNNING))
-                       senderr(ENETDOWN);
-       }
-
-       if (ifp0 != ifp && ifp0->if_type == IFT_CARP)
-               esrc = carp_get_srclladdr(ifp0, esrc);
-#endif /* NCARP > 0 */
-
        if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
                senderr(ENETDOWN);
 
@@ -402,14 +382,7 @@ ether_output(struct ifnet *ifp0, struct 
        }
 #endif
 
-       len = m->m_pkthdr.len;
-
-       error = if_output(ifp, m);
-#if NCARP > 0
-       if (!error && ifp != ifp0)
-               ifp0->if_obytes += len;
-#endif /* NCARP > 0 */
-       return (error);
+       return (if_output(ifp, m));
 bad:
        if (m)
                m_freem(m);
Index: netinet/ip_carp.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_carp.c,v
retrieving revision 1.258
diff -u -p -r1.258 ip_carp.c
--- netinet/ip_carp.c   2 Jun 2015 09:38:24 -0000       1.258
+++ netinet/ip_carp.c   2 Jun 2015 10:05:31 -0000
@@ -745,7 +745,7 @@ carp_clone_create(struct if_clone *ifc, 
        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
        ifp->if_ioctl = carp_ioctl;
        ifp->if_start = carp_start;
-       IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
+       IFQ_SET_MAXLEN(&ifp->if_snd, 1);
        IFQ_SET_READY(&ifp->if_snd);
        if_attach(ifp);
        ether_ifattach(ifp);
@@ -2257,15 +2257,52 @@ carp_ifgattr_ioctl(struct ifnet *ifp, u_
                carp_vhe_send_ad_all(sc);
 }
 
-/*
- * Start output on carp interface. This function should never be called.
- */
 void
 carp_start(struct ifnet *ifp)
 {
-#ifdef DEBUG
-       printf("%s: start called\n", ifp->if_xname);
-#endif
+       struct carp_softc *sc = ifp->if_softc;
+       struct mbuf *m;
+
+       for (;;) {
+               IFQ_DEQUEUE(&ifp->if_snd, m);
+               if (m == NULL)
+                       break;
+
+#if NBPFILTER > 0
+               if (ifp->if_bpf)
+                       bpf_mtap_ether(ifp->if_bpf, m, BPF_DIRECTION_OUT);
+#endif /* NBPFILTER > 0 */
+
+               if ((ifp->if_carpdev->if_flags & (IFF_UP|IFF_RUNNING)) !=
+                   (IFF_UP|IFF_RUNNING)) {
+                       IF_DROP(&ifp->if_carpdev->if_snd);
+                       ifp->if_oerrors++;
+                       m_freem(m);
+                       continue;
+               }
+
+               /*
+                * Do not leak the multicast address when sending
+                * advertisements in 'ip' and 'ip-stealth' balacing
+                * modes.
+                */
+               if (sc->sc_balancing != CARP_BAL_IPSTEALTH &&
+                   sc->sc_balancing != CARP_BAL_IP &&
+                   (sc->cur_vhe && !sc->cur_vhe->vhe_leader)) {
+                       struct ether_header *eh;
+                       uint8_t *esrc;
+
+                       eh = mtod(m, struct ether_header *);
+                       esrc = sc->cur_vhe->vhe_enaddr;
+                       memcpy(eh->ether_shost, esrc, sizeof(eh->ether_shost));
+               }
+
+               if (if_output(ifp->if_carpdev, m)) {
+                       ifp->if_oerrors++;
+                       continue;
+               }
+               ifp->if_opackets++;
+       }
 }
 
 int
@@ -2283,7 +2320,7 @@ carp_output(struct ifnet *ifp, struct mb
                return (ENETUNREACH);
        }
 
-       return (sc->sc_carpdev->if_output(ifp, m, sa, rt));
+       return (ether_output(ifp, m, sa, rt));
 }
 
 void

Reply via email to