diff options
author | Martin Pieuchot <mpi@cvs.openbsd.org> | 2015-06-02 09:38:25 +0000 |
---|---|---|
committer | Martin Pieuchot <mpi@cvs.openbsd.org> | 2015-06-02 09:38:25 +0000 |
commit | 53b03b0156ab3265b9db7e135c78458f9cf0aed8 (patch) | |
tree | b2eb7dced00cb50fd0e523498eb92f19fa2de9f4 /sys/netinet | |
parent | e3c1ec2773df29749bb43a9dc9ae84424d088112 (diff) |
Take carp(4) out of ether_input().
Tested by <mxb AT alumni DOT chalmers DOT se>, thanks!
ok bluhm@, dlg@
Diffstat (limited to 'sys/netinet')
-rw-r--r-- | sys/netinet/ip_carp.c | 140 | ||||
-rw-r--r-- | sys/netinet/ip_carp.h | 5 |
2 files changed, 79 insertions, 66 deletions
diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c index 310b0ce8ffc..cb16a2615cf 100644 --- a/sys/netinet/ip_carp.c +++ b/sys/netinet/ip_carp.c @@ -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 diff --git a/sys/netinet/ip_carp.h b/sys/netinet/ip_carp.h index 21aa417bd50..799a7a18878 100644 --- a/sys/netinet/ip_carp.h +++ b/sys/netinet/ip_carp.h @@ -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_ */ |