diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2015-09-10 13:32:20 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2015-09-10 13:32:20 +0000 |
commit | faed2bc014da50d0fb1d581ef6798f73669b2c77 (patch) | |
tree | bf1ef5074a1282e64bd2bd4c85db169cd2ed9787 /sys/net | |
parent | 8f97ac0f09ebbdf3bf00792cb555f5a19b9cb399 (diff) |
move the if input handler list to an SRP list.
instead of having every driver that manipulates the ifih list
understand SRPLs, this moves that processing into if_ih_insert and
if_ih_remove functions.
we rely on the kernel lock to serialise the modifications to the
list.
tested by mpi@
ok mpi@ claudio@ mikeb@
Diffstat (limited to 'sys/net')
-rw-r--r-- | sys/net/if.c | 97 | ||||
-rw-r--r-- | sys/net/if_bridge.c | 21 | ||||
-rw-r--r-- | sys/net/if_ethersubr.c | 15 | ||||
-rw-r--r-- | sys/net/if_mpw.c | 16 | ||||
-rw-r--r-- | sys/net/if_trunk.c | 7 | ||||
-rw-r--r-- | sys/net/if_trunk.h | 3 | ||||
-rw-r--r-- | sys/net/if_var.h | 16 | ||||
-rw-r--r-- | sys/net/if_vlan.c | 29 |
8 files changed, 121 insertions, 83 deletions
diff --git a/sys/net/if.c b/sys/net/if.c index 77791b35b1f..30c09edb91d 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if.c,v 1.365 2015/09/10 06:00:37 dlg Exp $ */ +/* $OpenBSD: if.c,v 1.366 2015/09/10 13:32:19 dlg Exp $ */ /* $NetBSD: if.c,v 1.35 1996/05/07 05:26:04 thorpej Exp $ */ /* @@ -80,6 +80,7 @@ #include <sys/domain.h> #include <sys/sysctl.h> #include <sys/task.h> +#include <sys/proc.h> #include <sys/atomic.h> #include <dev/rndvar.h> @@ -388,7 +389,7 @@ if_attach_common(struct ifnet *ifp) ifp->if_linkstatetask = malloc(sizeof(*ifp->if_linkstatetask), M_TEMP, M_WAITOK|M_ZERO); - SLIST_INIT(&ifp->if_inputs); + SRPL_INIT(&ifp->if_inputs); } void @@ -485,6 +486,93 @@ if_input(struct ifnet *ifp, struct mbuf_list *ml) task_add(softnettq, &if_input_task); } +struct ifih { + struct srpl_entry ifih_next; + int (*ifih_input)(struct ifnet *, struct mbuf *); + int ifih_refcnt; + int ifih_srpcnt; +}; + +void if_ih_ref(void *, void *); +void if_ih_unref(void *, void *); + +struct srpl_rc ifih_rc = SRPL_RC_INITIALIZER(if_ih_ref, if_ih_unref, NULL); + +void +if_ih_insert(struct ifnet *ifp, int (*input)(struct ifnet *, struct mbuf *)) +{ + struct ifih *ifih; + + /* the kernel lock guarantees serialised modifications to if_inputs */ + KERNEL_ASSERT_LOCKED(); + + SRPL_FOREACH_LOCKED(ifih, &ifp->if_inputs, ifih_next) { + if (ifih->ifih_input == input) { + ifih->ifih_refcnt++; + break; + } + } + + if (ifih == NULL) { + ifih = malloc(sizeof(*ifih), M_DEVBUF, M_WAITOK); + + ifih->ifih_input = input; + ifih->ifih_refcnt = 1; + ifih->ifih_srpcnt = 0; + SRPL_INSERT_HEAD_LOCKED(&ifih_rc, &ifp->if_inputs, + ifih, ifih_next); + } +} + +void +if_ih_ref(void *null, void *i) +{ + struct ifih *ifih = i; + + atomic_inc_int(&ifih->ifih_srpcnt); +} + +void +if_ih_unref(void *null, void *i) +{ + struct ifih *ifih = i; + + if (atomic_dec_int_nv(&ifih->ifih_srpcnt) == 0) + wakeup_one(&ifih->ifih_srpcnt); +} + +void +if_ih_remove(struct ifnet *ifp, int (*input)(struct ifnet *, struct mbuf *)) +{ + struct sleep_state sls; + struct ifih *ifih; + int refs; + + /* the kernel lock guarantees serialised modifications to if_inputs */ + KERNEL_ASSERT_LOCKED(); + + SRPL_FOREACH_LOCKED(ifih, &ifp->if_inputs, ifih_next) { + if (ifih->ifih_input == input) + break; + } + + KASSERT(ifih != NULL); + + if (--ifih->ifih_refcnt == 0) { + SRPL_REMOVE_LOCKED(&ifih_rc, &ifp->if_inputs, ifih, + ifih, ifih_next); + + refs = ifih->ifih_srpcnt; + while (refs) { + sleep_setup(&sls, &ifih->ifih_srpcnt, PWAIT, "ifihrm"); + refs = ifih->ifih_srpcnt; + sleep_finish(&sls, refs); + } + + free(ifih, M_DEVBUF, sizeof(*ifih)); + } +} + void if_input_process(void *xmq) { @@ -493,6 +581,7 @@ if_input_process(void *xmq) struct mbuf *m; struct ifnet *ifp; struct ifih *ifih; + struct srpl_iter i; int s; mq_delist(mq, &ml); @@ -525,10 +614,12 @@ if_input_process(void *xmq) * Pass this mbuf to all input handlers of its * interface until it is consumed. */ - SLIST_FOREACH(ifih, &ifp->if_inputs, ifih_next) { + SRPL_FOREACH(ifih, &ifp->if_inputs, &i, ifih_next) { if ((*ifih->ifih_input)(ifp, m)) break; } + SRPL_LEAVE(&i, ifih); + if (ifih == NULL) m_freem(m); } diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c index 756fcb899d0..770cf32fe4d 100644 --- a/sys/net/if_bridge.c +++ b/sys/net/if_bridge.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_bridge.c,v 1.261 2015/09/09 12:50:08 mpi Exp $ */ +/* $OpenBSD: if_bridge.c,v 1.262 2015/09/10 13:32:19 dlg Exp $ */ /* * Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net) @@ -183,7 +183,6 @@ int bridge_clone_create(struct if_clone *ifc, int unit) { struct bridge_softc *sc; - struct ifih *bridge_ifih; struct ifnet *ifp; int i; @@ -191,15 +190,8 @@ bridge_clone_create(struct if_clone *ifc, int unit) if (!sc) return (ENOMEM); - bridge_ifih = malloc(sizeof(*bridge_ifih), M_DEVBUF, M_NOWAIT); - if (bridge_ifih == NULL) { - free(sc, M_DEVBUF, 0); - return (ENOMEM); - } - sc->sc_stp = bstp_create(&sc->sc_if); if (!sc->sc_stp) { - free(bridge_ifih, M_DEVBUF, sizeof(*bridge_ifih)); free(sc, M_DEVBUF, 0); return (ENOMEM); } @@ -231,8 +223,7 @@ bridge_clone_create(struct if_clone *ifc, int unit) DLT_EN10MB, ETHER_HDR_LEN); #endif - bridge_ifih->ifih_input = ether_input; - SLIST_INSERT_HEAD(&ifp->if_inputs, bridge_ifih, ifih_next); + if_ih_insert(ifp, ether_input); return (0); } @@ -242,7 +233,6 @@ bridge_clone_destroy(struct ifnet *ifp) { struct bridge_softc *sc = ifp->if_softc; struct bridge_iflist *bif; - struct ifih *bridge_ifih; bridge_stop(sc); bridge_rtflush(sc, IFBF_FLUSHALL); @@ -258,12 +248,9 @@ bridge_clone_destroy(struct ifnet *ifp) /* Undo pseudo-driver changes. */ if_deactivate(ifp); - bridge_ifih = SLIST_FIRST(&ifp->if_inputs); - SLIST_REMOVE_HEAD(&ifp->if_inputs, ifih_next); - - KASSERT(SLIST_EMPTY(&ifp->if_inputs)); + if_ih_remove(ifp, ether_input); - free(bridge_ifih, M_DEVBUF, sizeof(*bridge_ifih)); + KASSERT(SRPL_EMPTY_LOCKED(&ifp->if_inputs)); if_detach(ifp); diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index f7845beeb80..eee6da9a2af 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_ethersubr.c,v 1.221 2015/07/29 00:04:03 rzalamena Exp $ */ +/* $OpenBSD: if_ethersubr.c,v 1.222 2015/09/10 13:32:19 dlg Exp $ */ /* $NetBSD: if_ethersubr.c,v 1.19 1996/05/07 02:40:30 thorpej Exp $ */ /* @@ -492,7 +492,6 @@ void ether_ifattach(struct ifnet *ifp) { struct arpcom *ac = (struct arpcom *)ifp; - struct ifih *ether_ifih; /* * Any interface which provides a MAC address which is obviously @@ -507,9 +506,7 @@ ether_ifattach(struct ifnet *ifp) ifp->if_mtu = ETHERMTU; ifp->if_output = ether_output; - ether_ifih = malloc(sizeof(*ether_ifih), M_DEVBUF, M_WAITOK); - ether_ifih->ifih_input = ether_input; - SLIST_INSERT_HEAD(&ifp->if_inputs, ether_ifih, ifih_next); + if_ih_insert(ifp, ether_input); if (ifp->if_hardmtu == 0) ifp->if_hardmtu = ETHERMTU; @@ -526,18 +523,14 @@ void ether_ifdetach(struct ifnet *ifp) { struct arpcom *ac = (struct arpcom *)ifp; - struct ifih *ether_ifih; struct ether_multi *enm; /* Undo pseudo-driver changes. */ if_deactivate(ifp); - ether_ifih = SLIST_FIRST(&ifp->if_inputs); - SLIST_REMOVE_HEAD(&ifp->if_inputs, ifih_next); + if_ih_remove(ifp, ether_input); - KASSERT(SLIST_EMPTY(&ifp->if_inputs)); - - free(ether_ifih, M_DEVBUF, sizeof(*ether_ifih)); + KASSERT(SRPL_EMPTY_LOCKED(&ifp->if_inputs)); for (enm = LIST_FIRST(&ac->ac_multiaddrs); enm != NULL; diff --git a/sys/net/if_mpw.c b/sys/net/if_mpw.c index c92a3f90eff..b6fe8e6b9cc 100644 --- a/sys/net/if_mpw.c +++ b/sys/net/if_mpw.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_mpw.c,v 1.3 2015/09/09 20:13:20 dlg Exp $ */ +/* $OpenBSD: if_mpw.c,v 1.4 2015/09/10 13:32:19 dlg Exp $ */ /* * Copyright (c) 2015 Rafael Zalamena <rzalamena@openbsd.org> @@ -82,18 +82,11 @@ mpw_clone_create(struct if_clone *ifc, int unit) { struct mpw_softc *sc; struct ifnet *ifp; - struct ifih *ifih; sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT | M_ZERO); if (sc == NULL) return (ENOMEM); - ifih = malloc(sizeof(*ifih), M_DEVBUF, M_NOWAIT | M_ZERO); - if (ifih == NULL) { - free(sc, M_DEVBUF, sizeof(*sc)); - return (ENOMEM); - } - ifp = &sc->sc_if; snprintf(ifp->if_xname, sizeof(ifp->if_xname), "mpw%d", unit); ifp->if_softc = sc; @@ -116,8 +109,7 @@ mpw_clone_create(struct if_clone *ifc, int unit) sc->sc_smpls.smpls_len = sizeof(sc->sc_smpls); sc->sc_smpls.smpls_family = AF_MPLS; - ifih->ifih_input = mpw_input; - SLIST_INSERT_HEAD(&ifp->if_inputs, ifih, ifih_next); + if_ih_insert(ifp, mpw_input); #if NBPFILTER > 0 bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, ETHER_HDR_LEN); @@ -130,7 +122,6 @@ int mpw_clone_destroy(struct ifnet *ifp) { struct mpw_softc *sc = ifp->if_softc; - struct ifih *ifih = SLIST_FIRST(&ifp->if_inputs); int s; ifp->if_flags &= ~IFF_RUNNING; @@ -142,8 +133,7 @@ mpw_clone_destroy(struct ifnet *ifp) splx(s); } - SLIST_REMOVE(&ifp->if_inputs, ifih, ifih, ifih_next); - free(ifih, M_DEVBUF, sizeof(*ifih)); + if_ih_remove(ifp, mpw_input); if_detach(ifp); free(sc, M_DEVBUF, sizeof(*sc)); diff --git a/sys/net/if_trunk.c b/sys/net/if_trunk.c index f51d2c0d261..b55843328d8 100644 --- a/sys/net/if_trunk.c +++ b/sys/net/if_trunk.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_trunk.c,v 1.109 2015/07/17 23:32:18 mpi Exp $ */ +/* $OpenBSD: if_trunk.c,v 1.110 2015/09/10 13:32:19 dlg Exp $ */ /* * Copyright (c) 2005, 2006, 2007 Reyk Floeter <reyk@openbsd.org> @@ -344,8 +344,7 @@ trunk_port_create(struct trunk_softc *tr, struct ifnet *ifp) ifp->if_type = IFT_IEEE8023ADLAG; /* Change input handler of the physical interface. */ - tp->tp_ifih.ifih_input = trunk_input; - SLIST_INSERT_HEAD(&ifp->if_inputs, &tp->tp_ifih, ifih_next); + if_ih_insert(ifp, trunk_input); ifp->if_tp = (caddr_t)tp; tp->tp_ioctl = ifp->if_ioctl; @@ -438,7 +437,7 @@ trunk_port_destroy(struct trunk_port *tp) ifp->if_type = tp->tp_iftype; /* Restore previous input handler. */ - SLIST_REMOVE(&ifp->if_inputs, &tp->tp_ifih, ifih, ifih_next); + if_ih_remove(ifp, trunk_input); ifp->if_watchdog = tp->tp_watchdog; ifp->if_ioctl = tp->tp_ioctl; diff --git a/sys/net/if_trunk.h b/sys/net/if_trunk.h index a5d1dea7774..e4eaffbd5da 100644 --- a/sys/net/if_trunk.h +++ b/sys/net/if_trunk.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_trunk.h,v 1.23 2015/05/26 11:39:07 mpi Exp $ */ +/* $OpenBSD: if_trunk.h,v 1.24 2015/09/10 13:32:19 dlg Exp $ */ /* * Copyright (c) 2005, 2006, 2007 Reyk Floeter <reyk@openbsd.org> @@ -137,7 +137,6 @@ struct trunk_port { u_int32_t tp_flags; /* port flags */ void *lh_cookie; /* if state hook */ void *dh_cookie; /* if detach hook */ - struct ifih tp_ifih; /* input handler */ /* Redirected callbacks */ void (*tp_watchdog)(struct ifnet *); diff --git a/sys/net/if_var.h b/sys/net/if_var.h index ba57aa11514..69e6c2e9a21 100644 --- a/sys/net/if_var.h +++ b/sys/net/if_var.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_var.h,v 1.35 2015/09/09 16:01:10 dlg Exp $ */ +/* $OpenBSD: if_var.h,v 1.36 2015/09/10 13:32:19 dlg Exp $ */ /* $NetBSD: if.h,v 1.23 1996/05/07 02:40:27 thorpej Exp $ */ /* @@ -110,15 +110,6 @@ struct ifqueue { }; /* - * Interface input hooks. - */ -struct ifih { - SLIST_ENTRY(ifih) ifih_next; - int (*ifih_input)(struct ifnet *, struct mbuf *); - int ifih_refcnt; -}; - -/* * Structure defining a queue for a network interface. * * (Would like to call this struct ``if'', but C isn't PL/1.) @@ -161,7 +152,7 @@ struct ifnet { /* and the entries */ struct task *if_linkstatetask; /* task to do route updates */ /* procedure handles */ - SLIST_HEAD(, ifih) if_inputs; /* input routines (dequeue) */ + struct srpl if_inputs; /* input routines (dequeue) */ /* output routine (enqueue) */ int (*if_output)(struct ifnet *, struct mbuf *, struct sockaddr *, @@ -449,6 +440,9 @@ void ifa_del(struct ifnet *, struct ifaddr *); void ifa_update_broadaddr(struct ifnet *, struct ifaddr *, struct sockaddr *); +void if_ih_insert(struct ifnet *, int (*)(struct ifnet *, struct mbuf *)); +void if_ih_remove(struct ifnet *, int (*)(struct ifnet *, struct mbuf *)); + void if_rxr_init(struct if_rxring *, u_int, u_int); u_int if_rxr_get(struct if_rxring *, u_int); diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c index 633c5d9ea07..4329bf0c0f6 100644 --- a/sys/net/if_vlan.c +++ b/sys/net/if_vlan.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_vlan.c,v 1.135 2015/07/20 22:16:41 rzalamena Exp $ */ +/* $OpenBSD: if_vlan.c,v 1.136 2015/09/10 13:32:19 dlg Exp $ */ /* * Copyright 1998 Massachusetts Institute of Technology @@ -357,17 +357,6 @@ vlan_config(struct ifvlan *ifv, struct ifnet *p, u_int16_t tag) if (ifv->ifv_p == p && ifv->ifv_tag == tag) /* noop */ return (0); - /* Can we share an ifih between multiple vlan(4) instances? */ - ifv->ifv_ifih = SLIST_FIRST(&p->if_inputs); - if (ifv->ifv_ifih->ifih_input != vlan_input) { - ifv->ifv_ifih = malloc(sizeof(*ifv->ifv_ifih), M_DEVBUF, - M_NOWAIT); - if (ifv->ifv_ifih == NULL) - return (ENOMEM); - ifv->ifv_ifih->ifih_input = vlan_input; - ifv->ifv_ifih->ifih_refcnt = 0; - } - /* Remember existing interface flags and reset the interface */ flags = ifv->ifv_flags; vlan_unconfig(&ifv->ifv_if, p); @@ -436,13 +425,12 @@ vlan_config(struct ifvlan *ifv, struct ifnet *p, u_int16_t tag) tagh = ifv->ifv_type == ETHERTYPE_QINQ ? svlan_tagh : vlan_tagh; s = splnet(); - /* Change input handler of the physical interface. */ - if (++ifv->ifv_ifih->ifih_refcnt == 1) - SLIST_INSERT_HEAD(&p->if_inputs, ifv->ifv_ifih, ifih_next); - LIST_INSERT_HEAD(&tagh[TAG_HASH(tag)], ifv, ifv_list); splx(s); + /* Change input handler of the physical interface. */ + if_ih_insert(p, vlan_input); + return (0); } @@ -466,13 +454,10 @@ vlan_unconfig(struct ifnet *ifp, struct ifnet *newp) s = splnet(); LIST_REMOVE(ifv, ifv_list); - - /* Restore previous input handler. */ - if (--ifv->ifv_ifih->ifih_refcnt == 0) { - SLIST_REMOVE(&p->if_inputs, ifv->ifv_ifih, ifih, ifih_next); - free(ifv->ifv_ifih, M_DEVBUF, sizeof(*ifv->ifv_ifih)); - } splx(s); + + /* Restore previous input handler. */ + if_ih_remove(p, vlan_input); hook_disestablish(p->if_linkstatehooks, ifv->lh_cookie); hook_disestablish(p->if_detachhooks, ifv->dh_cookie); |