Let's take carp(4) out of ether_input().  This is quite similar to what
happened to trunk(4) and vlan(4).

I appreciate tests of any kind, reviews and oks.

Index: net/if_ethersubr.c
===================================================================
RCS file: /cvs/src/sys/net/if_ethersubr.c,v
retrieving revision 1.199
diff -u -p -r1.199 if_ethersubr.c
--- net/if_ethersubr.c  19 May 2015 11:09:24 -0000      1.199
+++ net/if_ethersubr.c  22 May 2015 13:39:44 -0000
@@ -502,18 +502,6 @@ ether_input(struct mbuf *m, void *hdr)
        }
 #endif
 
-#if NCARP > 0
-       if (ifp->if_carp) {
-               if (ifp->if_type != IFT_CARP && (carp_input(ifp, eh, m) == 0))
-                       return (1);
-               /* clear mcast if received on a carp IP balanced address */
-               else if (ifp->if_type == IFT_CARP &&
-                   m->m_flags & (M_BCAST|M_MCAST) &&
-                   carp_our_mcastaddr(ifp, (u_int8_t *)&eh->ether_dhost))
-                       m->m_flags &= ~(M_BCAST|M_MCAST);
-       }
-#endif /* NCARP > 0 */
-
        ac = (struct arpcom *)ifp;
 
        /*
Index: netinet/ip_carp.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_carp.c,v
retrieving revision 1.257
diff -u -p -r1.257 ip_carp.c
--- netinet/ip_carp.c   21 May 2015 09:17:53 -0000      1.257
+++ netinet/ip_carp.c   22 May 2015 13:39:44 -0000
@@ -120,6 +120,7 @@ struct carp_softc {
 #define        sc_carpdev      sc_ac.ac_if.if_carpdev
        void *ah_cookie;
        void *lh_cookie;
+       struct ifih *sc_ifih;
        struct ip_moptions sc_imo;
 #ifdef INET6
        struct ip6_moptions sc_im6o;
@@ -193,6 +194,7 @@ void        carp_hmac_generate(struct carp_vhos
            unsigned char *, u_int8_t);
 int    carp_hmac_verify(struct carp_vhost_entry *, u_int32_t *,
            unsigned char *);
+int    carp_input(struct mbuf *);
 void   carp_proto_input_c(struct mbuf *, struct carp_header *, int,
            sa_family_t);
 void   carpattach(int);
@@ -824,6 +826,7 @@ carp_del_all_timeouts(struct carp_softc 
 void
 carpdetach(struct carp_softc *sc)
 {
+       struct ifnet *ifp;
        struct carp_if *cif;
        int s;
 
@@ -839,20 +842,29 @@ carpdetach(struct carp_softc *sc)
        carp_setrun_all(sc, 0);
        carp_multicast_cleanup(sc);
 
-       s = splnet();
        if (sc->ah_cookie != NULL)
                hook_disestablish(sc->sc_if.if_addrhooks, sc->ah_cookie);
-       if (sc->sc_carpdev != NULL) {
-               if (sc->lh_cookie != NULL)
-                       hook_disestablish(sc->sc_carpdev->if_linkstatehooks,
-                           sc->lh_cookie);
-               cif = (struct carp_if *)sc->sc_carpdev->if_carp;
-               TAILQ_REMOVE(&cif->vhif_vrs, sc, sc_list);
-               if (!--cif->vhif_nvrs) {
-                       ifpromisc(sc->sc_carpdev, 0);
-                       sc->sc_carpdev->if_carp = NULL;
-                       free(cif, M_IFADDR, sizeof(*cif));
-               }
+
+       ifp = sc->sc_carpdev;
+       if (ifp == NULL)
+               return;
+
+       s = splnet();
+       /* Restore previous input handler. */
+       if (--sc->sc_ifih->ifih_refcnt == 0) {
+               SLIST_REMOVE(&ifp->if_inputs, sc->sc_ifih, ifih, ifih_next);
+               free(sc->sc_ifih, M_DEVBUF, sizeof(*sc->sc_ifih));
+       }
+
+       if (sc->lh_cookie != NULL)
+               hook_disestablish(ifp->if_linkstatehooks,
+                   sc->lh_cookie);
+       cif = (struct carp_if *)ifp->if_carp;
+       TAILQ_REMOVE(&cif->vhif_vrs, sc, sc_list);
+       if (!--cif->vhif_nvrs) {
+               ifpromisc(ifp, 0);
+               ifp->if_carp = NULL;
+               free(cif, M_IFADDR, sizeof(*cif));
        }
        sc->sc_carpdev = NULL;
        splx(s);
@@ -1403,27 +1415,21 @@ carp_get_srclladdr(struct ifnet *ifp, u_
 }
 
 int
-carp_our_mcastaddr(struct ifnet *ifp, u_int8_t *d_enaddr)
-{
-       struct carp_softc *sc = ifp->if_softc;
-
-       if (sc->sc_balancing != CARP_BAL_IP)
-               return (0);
-
-       return (!memcmp(sc->sc_ac.ac_enaddr, d_enaddr, ETHER_ADDR_LEN));
-}
-
-
-int
-carp_input(struct ifnet *ifp0, struct ether_header *eh0, struct mbuf *m)
+carp_input(struct mbuf *m)
 {
+       struct carp_softc *sc;
        struct ether_header *eh;
-       struct carp_if *cif = (struct carp_if *)ifp0->if_carp;
-       struct ifnet *ifp;
+       struct mbuf_list ml = MBUF_LIST_INITIALIZER();
+       struct carp_if *cif;
+       struct ifnet *ifp0, *ifp;
 
-       ifp = carp_ourether(cif, eh0->ether_dhost);
-       if (ifp == NULL && (m->m_flags & (M_BCAST|M_MCAST)) == 0)
-               return (1);
+       ifp0 = m->m_pkthdr.rcvif;
+       eh = mtod(m, struct ether_header *);
+       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);
 
        if (ifp == NULL) {
                struct carp_softc *vh;
@@ -1439,41 +1445,33 @@ carp_input(struct ifnet *ifp0, struct et
                        m0 = m_copym2(m, 0, M_COPYALL, M_DONTWAIT);
                        if (m0 == NULL)
                                continue;
-                       M_PREPEND(m0, sizeof(*eh), M_DONTWAIT);
-                       if (m0 == NULL)
-                               continue;
-                       eh = mtod(m0, struct ether_header *);
-                       memmove(eh, eh0, sizeof(*eh));
 
-                       m0->m_pkthdr.rcvif = &vh->sc_if;
-#if NBPFILTER > 0
-                       if (vh->sc_if.if_bpf)
-                               bpf_mtap_ether(vh->sc_if.if_bpf, m0,
-                                   BPF_DIRECTION_IN);
-#endif
+                       ml_init(&ml);
+                       ml_enqueue(&ml, m0);
+
+                       if_input(&vh->sc_if, &ml);
                        vh->sc_if.if_ipackets++;
-                       ether_input_mbuf(&vh->sc_if, m0);
                }
 
-               return (1);
+               return (0);
        }
 
-       M_PREPEND(m, sizeof(*eh), M_DONTWAIT);
-       if (m == NULL)
-               return (0);
-       eh = mtod(m, struct ether_header *);
-       memmove(eh, eh0, sizeof(*eh));
+       ifp0->if_ibytes += m->m_pkthdr.len;
 
-       m->m_pkthdr.rcvif = ifp;
+       /*
+        * 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;
 
-#if NBPFILTER > 0
-       if (ifp->if_bpf)
-               bpf_mtap_ether(ifp->if_bpf, m, BPF_DIRECTION_IN);
-#endif
-       ifp->if_ipackets++;
-       ether_input_mbuf(ifp, m);
 
-       return (0);
+       ml_enqueue(&ml, m);
+
+       if_input(ifp, &ml);
+       ifp->if_ipackets++;
+       return (1);
 }
 
 int
@@ -1688,6 +1686,18 @@ carp_set_ifp(struct carp_softc *sc, stru
                        return (EINVAL);
        }
 
+       /* Can we share an ifih between multiple carp(4) instances? */
+       sc->sc_ifih = SLIST_FIRST(&ifp->if_inputs);
+       if (sc->sc_ifih->ifih_input != carp_input) {
+               sc->sc_ifih = malloc(sizeof(*sc->sc_ifih), M_DEVBUF, M_NOWAIT);
+               if (sc->sc_ifih == NULL) {
+                       free(ncif, M_IFADDR, sizeof(*ncif));
+                       return (ENOMEM);
+               }
+               sc->sc_ifih->ifih_input = carp_input;
+               sc->sc_ifih->ifih_refcnt = 0;
+       }
+
        /* detach from old interface */
        if (sc->sc_carpdev != NULL)
                carpdetach(sc);
@@ -1720,9 +1730,15 @@ carp_set_ifp(struct carp_softc *sc, stru
        if (sc->sc_naddrs || sc->sc_naddrs6)
                sc->sc_if.if_flags |= IFF_UP;
        carp_set_enaddr(sc);
-       s = splnet();
+
        sc->lh_cookie = hook_establish(ifp->if_linkstatehooks, 1,
            carp_carpdev_state, ifp);
+
+       s = splnet();
+       /* Change input handler of the physical interface. */
+       if (++sc->sc_ifih->ifih_refcnt == 1)
+               SLIST_INSERT_HEAD(&ifp->if_inputs, sc->sc_ifih, ifih_next);
+
        carp_carpdev_state(ifp);
        splx(s);
 
@@ -2261,13 +2277,12 @@ carp_output(struct ifnet *ifp, struct mb
 
        vhe = sc->cur_vhe ? sc->cur_vhe : LIST_FIRST(&sc->carp_vhosts);
 
-       if (sc->sc_carpdev != NULL &&
-           (sc->sc_balancing || vhe->state == MASTER))
-               return (sc->sc_carpdev->if_output(ifp, m, sa, rt));
-       else {
+       if (!sc->sc_carpdev || (!sc->sc_balancing && vhe->state != MASTER)) {
                m_freem(m);
                return (ENETUNREACH);
        }
+
+       return (sc->sc_carpdev->if_output(ifp, m, sa, rt));
 }
 
 void
Index: netinet/ip_carp.h
===================================================================
RCS file: /cvs/src/sys/netinet/ip_carp.h,v
retrieving revision 1.32
diff -u -p -r1.32 ip_carp.h
--- netinet/ip_carp.h   19 Dec 2014 05:36:28 -0000      1.32
+++ netinet/ip_carp.h   22 May 2015 13:39:44 -0000
@@ -172,13 +172,10 @@ int                carp_iamatch(struct in_ifaddr *, u
                     u_int8_t **);
 int             carp_iamatch6(struct ifnet *, u_char *, struct sockaddr_dl **);
 struct ifnet   *carp_ourether(void *, u_int8_t *);
-int             carp_input(struct ifnet *, struct ether_header *,
-                    struct mbuf *);
 int             carp_output(struct ifnet *, struct mbuf *, struct sockaddr *,
                     struct rtentry *);
 int             carp_sysctl(int *, u_int,  void *, size_t *, void *, size_t);
 int             carp_lsdrop(struct mbuf *, sa_family_t, u_int32_t *, u_int32_t 
*);
 u_char         *carp_get_srclladdr(struct ifnet *, u_char *);
-int             carp_our_mcastaddr(struct ifnet *, u_int8_t *);
 #endif /* _KERNEL */
 #endif /* _NETINET_IP_CARP_H_ */

Reply via email to