summaryrefslogtreecommitdiff
path: root/sys/netinet
diff options
context:
space:
mode:
authorMartin Pieuchot <mpi@cvs.openbsd.org>2015-06-02 09:38:25 +0000
committerMartin Pieuchot <mpi@cvs.openbsd.org>2015-06-02 09:38:25 +0000
commit53b03b0156ab3265b9db7e135c78458f9cf0aed8 (patch)
treeb2eb7dced00cb50fd0e523498eb92f19fa2de9f4 /sys/netinet
parente3c1ec2773df29749bb43a9dc9ae84424d088112 (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.c140
-rw-r--r--sys/netinet/ip_carp.h5
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_ */