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