summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordlg <dlg@openbsd.org>2015-09-09 16:01:10 +0000
committerdlg <dlg@openbsd.org>2015-09-09 16:01:10 +0000
commit1fce3e48ac9ca1ac06ad24ec6c682fb099a11e89 (patch)
tree2ebbf41526189d304b3cf518362426974a1da810
parentfix a mistake in the predefined string passed to -width (it is (diff)
downloadwireguard-openbsd-1fce3e48ac9ca1ac06ad24ec6c682fb099a11e89.tar.xz
wireguard-openbsd-1fce3e48ac9ca1ac06ad24ec6c682fb099a11e89.zip
introduce reference counts for interfaces (ie, struct ifnet *ifp).
if_get can get a reference to an ifp, but it never releases that reference. this provides an if_put function that can be used to decrement the refcount. we cannot come up with a scheme for letting the network stack run on one (or many) cpus while ioctls are pulling interfaces down on another cpu without refcounts for the interfaces. if_put is going in now so we can go through the stack and put the necessary calls to it in, and then we'll backfill this implementation to actually check the refcounts when the interface detaches. ok mpi@ mikeb@ claudio@
-rw-r--r--sys/net/if.c24
-rw-r--r--sys/net/if.h4
-rw-r--r--sys/net/if_var.h3
3 files changed, 27 insertions, 4 deletions
diff --git a/sys/net/if.c b/sys/net/if.c
index 83fc99725c5..fadedd86a96 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if.c,v 1.363 2015/09/01 04:56:55 dlg Exp $ */
+/* $OpenBSD: if.c,v 1.364 2015/09/09 16:01:10 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/atomic.h>
#include <dev/rndvar.h>
@@ -260,7 +261,8 @@ if_attachsetup(struct ifnet *ifp)
if_addgroup(ifp, IFG_ALL);
- ifindex2ifnet[if_index] = ifp;
+ ifp->if_refcnt = 0;
+ ifindex2ifnet[if_index] = if_ref(ifp);
if (ifp->if_snd.ifq_maxlen == 0)
IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
@@ -664,6 +666,7 @@ if_detach(struct ifnet *ifp)
rt_ifannouncemsg(ifp, IFAN_DEPARTURE);
ifindex2ifnet[ifp->if_index] = NULL;
+ if_put(ifp);
splx(s);
}
@@ -1231,9 +1234,26 @@ if_get(unsigned int index)
if (index < if_indexlim)
ifp = ifindex2ifnet[index];
+ return (if_ref(ifp));
+}
+
+struct ifnet *
+if_ref(struct ifnet *ifp)
+{
+ atomic_inc_int(&ifp->if_refcnt);
+
return (ifp);
}
+void
+if_put(struct ifnet *ifp)
+{
+ if (ifp == NULL)
+ return;
+
+ atomic_dec_int(&ifp->if_refcnt);
+}
+
/*
* Interface ioctls.
*/
diff --git a/sys/net/if.h b/sys/net/if.h
index c4962b8df80..741ec2be537 100644
--- a/sys/net/if.h
+++ b/sys/net/if.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if.h,v 1.165 2015/08/30 10:39:16 mpi Exp $ */
+/* $OpenBSD: if.h,v 1.166 2015/09/09 16:01:10 dlg Exp $ */
/* $NetBSD: if.h,v 1.23 1996/05/07 02:40:27 thorpej Exp $ */
/*
@@ -462,6 +462,8 @@ int if_delgroup(struct ifnet *, const char *);
void if_group_routechange(struct sockaddr *, struct sockaddr *);
struct ifnet *ifunit(const char *);
struct ifnet *if_get(unsigned int);
+struct ifnet *if_ref(struct ifnet *);
+void if_put(struct ifnet *);
void ifnewlladdr(struct ifnet *);
void if_congestion(void);
int if_congested(void);
diff --git a/sys/net/if_var.h b/sys/net/if_var.h
index 034a64e301c..ba57aa11514 100644
--- a/sys/net/if_var.h
+++ b/sys/net/if_var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_var.h,v 1.34 2015/07/02 09:40:02 mpi Exp $ */
+/* $OpenBSD: if_var.h,v 1.35 2015/09/09 16:01:10 dlg Exp $ */
/* $NetBSD: if.h,v 1.23 1996/05/07 02:40:27 thorpej Exp $ */
/*
@@ -127,6 +127,7 @@ TAILQ_HEAD(ifnet_head, ifnet); /* the actual queue head */
struct ifnet { /* and the entries */
void *if_softc; /* lower-level data for this if */
+ unsigned int if_refcnt;
TAILQ_ENTRY(ifnet) if_list; /* all struct ifnets are chained */
TAILQ_ENTRY(ifnet) if_txlist; /* list of ifnets ready to tx */
TAILQ_HEAD(, ifaddr) if_addrlist; /* linked list of addresses per if */