diff options
author | Mike Belopuhov <mikeb@cvs.openbsd.org> | 2013-10-19 14:54:19 +0000 |
---|---|---|
committer | Mike Belopuhov <mikeb@cvs.openbsd.org> | 2013-10-19 14:54:19 +0000 |
commit | 64b07ad94586fc0cfe3d9e9e17ccc21dd1d6651d (patch) | |
tree | ee42697740d800095b6b8cd4101ce58d1f02a774 /sys/net | |
parent | 08a743d854203c66c70496aac48e3cb6cf36a6b9 (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.c | 33 |
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); } /* |