summaryrefslogtreecommitdiff
path: root/sys/net
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2015-09-10 13:32:20 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2015-09-10 13:32:20 +0000
commitfaed2bc014da50d0fb1d581ef6798f73669b2c77 (patch)
treebf1ef5074a1282e64bd2bd4c85db169cd2ed9787 /sys/net
parent8f97ac0f09ebbdf3bf00792cb555f5a19b9cb399 (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.c97
-rw-r--r--sys/net/if_bridge.c21
-rw-r--r--sys/net/if_ethersubr.c15
-rw-r--r--sys/net/if_mpw.c16
-rw-r--r--sys/net/if_trunk.c7
-rw-r--r--sys/net/if_trunk.h3
-rw-r--r--sys/net/if_var.h16
-rw-r--r--sys/net/if_vlan.c29
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);