Take carp(4) out of ether_input().
authormpi <mpi@openbsd.org>
Tue, 2 Jun 2015 09:38:24 +0000 (09:38 +0000)
committermpi <mpi@openbsd.org>
Tue, 2 Jun 2015 09:38:24 +0000 (09:38 +0000)
Tested by <mxb AT alumni DOT chalmers DOT se>, thanks!

ok bluhm@, dlg@

sys/net/if_ethersubr.c
sys/netinet/ip_carp.c
sys/netinet/ip_carp.h

index 2cc6815..468a287 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_ethersubr.c,v 1.201 2015/05/26 11:39:07 mpi Exp $  */
+/*     $OpenBSD: if_ethersubr.c,v 1.202 2015/06/02 09:38:24 mpi Exp $  */
 /*     $NetBSD: if_ethersubr.c,v 1.19 1996/05/07 02:40:30 thorpej Exp $        */
 
 /*
@@ -490,18 +490,6 @@ ether_input(struct mbuf *m)
        }
 #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 310b0ce..cb16a26 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip_carp.c,v 1.257 2015/05/21 09:17:53 mpi Exp $       */
+/*     $OpenBSD: ip_carp.c,v 1.258 2015/06/02 09:38:24 mpi Exp $       */
 
 /*
  * Copyright (c) 2002 Michael Shalayeff. All rights reserved.
@@ -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_vhost_entry *, u_int32_t *,
            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 *sc)
 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_char *esrc)
 }
 
 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 ether_header *eh0, struct mbuf *m)
                        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, struct ifnet *ifp)
                        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, struct ifnet *ifp)
        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,13 @@ carp_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa,
 
        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 == NULL) ||
+           (!sc->sc_balancing && vhe->state != MASTER)) {
                m_freem(m);
                return (ENETUNREACH);
        }
+
+       return (sc->sc_carpdev->if_output(ifp, m, sa, rt));
 }
 
 void
index 21aa417..799a7a1 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip_carp.h,v 1.32 2014/12/19 05:36:28 tedu Exp $       */
+/*     $OpenBSD: ip_carp.h,v 1.33 2015/06/02 09:38:24 mpi Exp $        */
 
 /*
  * Copyright (c) 2002 Michael Shalayeff. All rights reserved.
@@ -172,13 +172,10 @@ int                carp_iamatch(struct in_ifaddr *, u_char *, u_int8_t **,
                     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_ */