summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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
-rw-r--r--sys/netinet/ip_carp.c27
9 files changed, 126 insertions, 105 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);
diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c
index 7b8b5110e0b..dfdccbf1614 100644
--- a/sys/netinet/ip_carp.c
+++ b/sys/netinet/ip_carp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_carp.c,v 1.264 2015/07/02 09:40:03 mpi Exp $ */
+/* $OpenBSD: ip_carp.c,v 1.265 2015/09/10 13:32:19 dlg Exp $ */
/*
* Copyright (c) 2002 Michael Shalayeff. All rights reserved.
@@ -120,7 +120,6 @@ 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;
@@ -864,13 +863,10 @@ carpdetach(struct carp_softc *sc)
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_ih_remove(ifp, carp_input);
+ s = splnet();
if (sc->lh_cookie != NULL)
hook_disestablish(ifp->if_linkstatehooks,
sc->lh_cookie);
@@ -1686,18 +1682,6 @@ 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);
@@ -1734,11 +1718,10 @@ carp_set_ifp(struct carp_softc *sc, struct ifnet *ifp)
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);
+ if_ih_insert(ifp, carp_input);
+ s = splnet();
carp_carpdev_state(ifp);
splx(s);