summaryrefslogtreecommitdiff
path: root/sys/net
diff options
context:
space:
mode:
authorMike Belopuhov <mikeb@cvs.openbsd.org>2013-10-19 14:54:19 +0000
committerMike Belopuhov <mikeb@cvs.openbsd.org>2013-10-19 14:54:19 +0000
commit64b07ad94586fc0cfe3d9e9e17ccc21dd1d6651d (patch)
treeee42697740d800095b6b8cd4101ce58d1f02a774 /sys/net
parent08a743d854203c66c70496aac48e3cb6cf36a6b9 (diff)
in order to make our life a tad easier and prevent rogue accesses
to the routing table from the hardware interrupt context defer the if_link_state_change to the process context. a token (an interface index) is passed to the workq in order to make sure that if the interface would be gone by the time syswq goes around to run the task it would just fall through. ok henning, mpi, deraadt, claudio
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/if.c33
1 files changed, 27 insertions, 6 deletions
diff --git a/sys/net/if.c b/sys/net/if.c
index b65736c5c26..9c246e0df93 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if.c,v 1.270 2013/10/19 14:05:14 reyk Exp $ */
+/* $OpenBSD: if.c,v 1.271 2013/10/19 14:54:18 mikeb Exp $ */
/* $NetBSD: if.c,v 1.35 1996/05/07 05:26:04 thorpej Exp $ */
/*
@@ -81,6 +81,7 @@
#include <sys/ioctl.h>
#include <sys/domain.h>
#include <sys/sysctl.h>
+#include <sys/workq.h>
#include <net/if.h>
#include <net/if_dl.h>
@@ -154,6 +155,8 @@ struct if_clone *if_clone_lookup(const char *, int *);
void if_congestion_clear(void *);
int if_group_egress_build(void);
+void if_link_state_change_task(void *, void *);
+
int ifai_cmp(struct ifaddr_item *, struct ifaddr_item *);
void ifa_item_insert(struct sockaddr *, struct ifaddr *, struct ifnet *);
void ifa_item_remove(struct sockaddr *, struct ifaddr *, struct ifnet *);
@@ -1111,17 +1114,35 @@ if_up(struct ifnet *ifp)
}
/*
- * Process a link state change.
- * NOTE: must be called at splsoftnet or equivalent.
+ * Schedule a link state change task.
*/
void
if_link_state_change(struct ifnet *ifp)
{
- rt_ifmsg(ifp);
+ /* try to put the routing table update task on syswq */
+ workq_add_task(NULL, 0, if_link_state_change_task,
+ (void *)((unsigned long)ifp->if_index), NULL);
+}
+
+/*
+ * Process a link state change.
+ */
+void
+if_link_state_change_task(void *arg, void *unused)
+{
+ unsigned int index = (unsigned long)arg;
+ struct ifnet *ifp;
+ int s;
+
+ s = splsoftnet();
+ if ((ifp = if_get(index)) != NULL) {
+ rt_ifmsg(ifp);
#ifndef SMALL_KERNEL
- rt_if_track(ifp);
+ rt_if_track(ifp);
#endif
- dohooks(ifp->if_linkstatehooks, 0);
+ dohooks(ifp->if_linkstatehooks, 0);
+ }
+ splx(s);
}
/*