On Mon, Aug 26, 2013 at 13:36 +0200, Mike Belopuhov wrote:
> hi,
> 
> in order to make our life a bit easier and prevent rogue
> accesses to the routing table from the hardware interrupt
> context violating all kinds of spl assumptions we would
> like if_link_state_change that is called by network device
> drivers in their interrupt service routines to defer its
> work to the process context or thereabouts.
> 
> i did some testing here, but wouldn't mind if someone
> tries this diff in gre/vlan/ospf/anything-weird setups.
> making sure that hot-plugging/unplugging usb interfaces
> doesn't produce any undesirable effects would be superb
> as well.
> 
> please note that 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?
> 

i've got an ok from mpi, anyone else would like to test
and/or comment?

> diff --git sys/net/if.c sys/net/if.c
> index 6dafd0d..5b6800a 100644
> --- sys/net/if.c
> +++ sys/net/if.c
> @@ -79,10 +79,11 @@
>  #include <sys/protosw.h>
>  #include <sys/kernel.h>
>  #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>
>  #include <net/if_media.h>
>  #include <net/if_types.h>
> @@ -151,10 +152,12 @@ int     if_clone_list(struct if_clonereq *);
>  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 *);
>  #ifndef SMALL_KERNEL
>  void ifa_print_rb(void);
> @@ -1106,21 +1109,39 @@ if_up(struct ifnet *ifp)
>  
>       m_clinitifp(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);
>  }
>  
>  /*
>   * Handle interface watchdog timer routines.  Called
>   * from softclock, we decrement timers (if set) and

Reply via email to