Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/net Introduce deferred if_start framework



details:   https://anonhg.NetBSD.org/src/rev/a858da627502
branches:  trunk
changeset: 349342:a858da627502
user:      ozaki-r <ozaki-r%NetBSD.org@localhost>
date:      Thu Dec 08 01:06:35 2016 +0000

description:
Introduce deferred if_start framework

The framework provides a means to schedule if_start that will be executed
in softint later. It intends to be used to avoid calling if_start,
especially bpf_mtap, in hardware interrupt.

It adds a dedicated softint to a driver if the driver requests to use the
framework via if_deferred_start_init. The driver can schedule deferred
if_start by if_schedule_deferred_start.

Proposed and discussed on tech-kern and tech-net

diffstat:

 sys/net/if.c |  108 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 sys/net/if.h |    7 +++-
 2 files changed, 112 insertions(+), 3 deletions(-)

diffs (178 lines):

diff -r 21d6bd881b2b -r a858da627502 sys/net/if.c
--- a/sys/net/if.c      Wed Dec 07 22:24:44 2016 +0000
+++ b/sys/net/if.c      Thu Dec 08 01:06:35 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if.c,v 1.363 2016/12/06 01:23:01 ozaki-r Exp $ */
+/*     $NetBSD: if.c,v 1.364 2016/12/08 01:06:35 ozaki-r Exp $ */
 
 /*-
  * Copyright (c) 1999, 2000, 2001, 2008 The NetBSD Foundation, Inc.
@@ -90,7 +90,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.363 2016/12/06 01:23:01 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.364 2016/12/08 01:06:35 ozaki-r Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_inet.h"
@@ -223,6 +223,16 @@
 static void sysctl_percpuq_setup(struct sysctllog **, const char *,
     struct if_percpuq *);
 
+struct if_deferred_start {
+       struct ifnet    *ids_ifp;
+       void            (*ids_if_start)(struct ifnet *);
+       void            *ids_si;
+};
+
+static void if_deferred_start_softint(void *);
+static void if_deferred_start_common(struct ifnet *);
+static void if_deferred_start_destroy(struct ifnet *);
+
 #if defined(INET) || defined(INET6)
 static void sysctl_net_pktq_setup(struct sysctllog **, int);
 #endif
@@ -953,6 +963,99 @@
        return;
 }
 
+/*
+ * The deferred if_start framework
+ *
+ * The common APIs to defer if_start to softint when if_start is requested
+ * from a device driver running in hardware interrupt context.
+ */
+/*
+ * Call ifp->if_start (or equivalent) in a dedicated softint for
+ * deferred if_start.
+ */
+static void
+if_deferred_start_softint(void *arg)
+{
+       struct if_deferred_start *ids = arg;
+       struct ifnet *ifp = ids->ids_ifp;
+
+#ifdef DEBUG
+       log(LOG_DEBUG, "%s: deferred start on %s\n", __func__,
+           ifp->if_xname);
+#endif
+
+       ids->ids_if_start(ifp);
+}
+
+/*
+ * The default callback function for deferred if_start.
+ */
+static void
+if_deferred_start_common(struct ifnet *ifp)
+{
+
+       if_start_lock(ifp);
+}
+
+static inline bool
+if_snd_is_used(struct ifnet *ifp)
+{
+
+       return ifp->if_transmit == NULL || ifp->if_transmit == if_nulltransmit ||
+           ALTQ_IS_ENABLED(&ifp->if_snd);
+}
+
+/*
+ * Schedule deferred if_start.
+ */
+void
+if_schedule_deferred_start(struct ifnet *ifp)
+{
+
+       KASSERT(ifp->if_deferred_start != NULL);
+
+       if (if_snd_is_used(ifp) && IFQ_IS_EMPTY(&ifp->if_snd))
+               return;
+
+       softint_schedule(ifp->if_deferred_start->ids_si);
+}
+
+/*
+ * Create an instance of deferred if_start. A driver should call the function
+ * only if the driver needs deferred if_start. Drivers can setup their own
+ * deferred if_start function via 2nd argument.
+ */
+void
+if_deferred_start_init(struct ifnet *ifp, void (*func)(struct ifnet *))
+{
+       struct if_deferred_start *ids;
+
+       ids = kmem_zalloc(sizeof(*ids), KM_SLEEP);
+       if (ids == NULL)
+               panic("kmem_zalloc failed");
+
+       ids->ids_ifp = ifp;
+       ids->ids_si = softint_establish(SOFTINT_NET|SOFTINT_MPSAFE,
+           if_deferred_start_softint, ids);
+       if (func != NULL)
+               ids->ids_if_start = func;
+       else
+               ids->ids_if_start = if_deferred_start_common;
+
+       ifp->if_deferred_start = ids;
+}
+
+static void
+if_deferred_start_destroy(struct ifnet *ifp)
+{
+
+       if (ifp->if_deferred_start == NULL)
+               return;
+
+       softint_disestablish(ifp->if_deferred_start->ids_si);
+       kmem_free(ifp->if_deferred_start, sizeof(*ifp->if_deferred_start));
+       ifp->if_deferred_start = NULL;
+}
 
 /*
  * The common interface input routine that is called by device drivers,
@@ -1194,6 +1297,7 @@
                callout_destroy(ifp->if_slowtimo_ch);
                kmem_free(ifp->if_slowtimo_ch, sizeof(*ifp->if_slowtimo_ch));
        }
+       if_deferred_start_destroy(ifp);
 
        /*
         * Do an if_down() to give protocols a chance to do something.
diff -r 21d6bd881b2b -r a858da627502 sys/net/if.h
--- a/sys/net/if.h      Wed Dec 07 22:24:44 2016 +0000
+++ b/sys/net/if.h      Thu Dec 08 01:06:35 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if.h,v 1.229 2016/11/22 02:06:00 ozaki-r Exp $ */
+/*     $NetBSD: if.h,v 1.230 2016/12/08 01:06:35 ozaki-r Exp $ */
 
 /*-
  * Copyright (c) 1999, 2000, 2001 The NetBSD Foundation, Inc.
@@ -230,6 +230,7 @@
 struct callout;
 struct krwlock;
 struct if_percpuq;
+struct if_deferred_start;
 
 typedef unsigned short if_index_t;
 
@@ -342,6 +343,7 @@
        struct pslist_entry     if_pslist_entry;
        struct psref_target     if_psref;
        struct pslist_head      if_addr_pslist;
+       struct if_deferred_start        *if_deferred_start;
 #endif
 } ifnet_t;
  
@@ -989,6 +991,9 @@
 void
        if_percpuq_enqueue(struct if_percpuq *, struct mbuf *);
 
+void   if_deferred_start_init(struct ifnet *, void (*)(struct ifnet *));
+void   if_schedule_deferred_start(struct ifnet *);
+
 void ifa_insert(struct ifnet *, struct ifaddr *);
 void ifa_remove(struct ifnet *, struct ifaddr *);
 



Home | Main Index | Thread Index | Old Index