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:54:30 -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 *);
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, void *hdr)
{
+ 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_ */