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