this adds transmit mitigation back to the tree.
it is basically the same diff as last time. the big difference this
time is that all the tunnel drivers all defer ip_output calls, which
avoids having to play games with NET_LOCK in the ifq transmit paths.
tests? ok?
Index: ifq.c
===================================================================
RCS file: /cvs/src/sys/net/ifq.c,v
retrieving revision 1.22
diff -u -p -r1.22 ifq.c
--- ifq.c 25 Jan 2018 14:04:36 -0000 1.22
+++ ifq.c 14 Mar 2018 02:58:13 -0000
@@ -70,9 +70,16 @@ struct priq {
void ifq_start_task(void *);
void ifq_restart_task(void *);
void ifq_barrier_task(void *);
+void ifq_bundle_task(void *);
#define TASK_ONQUEUE 0x1
+static inline void
+ifq_run_start(struct ifqueue *ifq)
+{
+ ifq_serialize(ifq, &ifq->ifq_start);
+}
+
void
ifq_serialize(struct ifqueue *ifq, struct task *t)
{
@@ -114,6 +121,16 @@ ifq_is_serialized(struct ifqueue *ifq)
}
void
+ifq_start(struct ifqueue *ifq)
+{
+ if (ifq_len(ifq) >= min(4, ifq->ifq_maxlen)) {
+ task_del(ifq->ifq_softnet, &ifq->ifq_bundle);
+ ifq_run_start(ifq);
+ } else
+ task_add(ifq->ifq_softnet, &ifq->ifq_bundle);
+}
+
+void
ifq_start_task(void *p)
{
struct ifqueue *ifq = p;
@@ -137,11 +154,33 @@ ifq_restart_task(void *p)
}
void
+ifq_bundle_task(void *p)
+{
+ struct ifqueue *ifq = p;
+
+ ifq_run_start(ifq);
+}
+
+void
ifq_barrier(struct ifqueue *ifq)
{
struct cond c = COND_INITIALIZER();
struct task t = TASK_INITIALIZER(ifq_barrier_task, &c);
+ NET_ASSERT_UNLOCKED();
+
+ if (!task_del(ifq->ifq_softnet, &ifq->ifq_bundle)) {
+ int netlocked = (rw_status(&netlock) == RW_WRITE);
+
+ if (netlocked) /* XXXSMP breaks atomicity */
+ NET_UNLOCK();
+
+ taskq_barrier(ifq->ifq_softnet);
+
+ if (netlocked)
+ NET_LOCK();
+ }
+
if (ifq->ifq_serializer == NULL)
return;
@@ -166,6 +205,7 @@ void
ifq_init(struct ifqueue *ifq, struct ifnet *ifp, unsigned int idx)
{
ifq->ifq_if = ifp;
+ ifq->ifq_softnet = net_tq(ifp->if_index);
ifq->ifq_softc = NULL;
mtx_init(&ifq->ifq_mtx, IPL_NET);
@@ -187,6 +227,7 @@ ifq_init(struct ifqueue *ifq, struct ifn
mtx_init(&ifq->ifq_task_mtx, IPL_NET);
TAILQ_INIT(&ifq->ifq_task_list);
ifq->ifq_serializer = NULL;
+ task_set(&ifq->ifq_bundle, ifq_bundle_task, ifq);
task_set(&ifq->ifq_start, ifq_start_task, ifq);
task_set(&ifq->ifq_restart, ifq_restart_task, ifq);
@@ -237,6 +278,8 @@ void
ifq_destroy(struct ifqueue *ifq)
{
struct mbuf_list ml = MBUF_LIST_INITIALIZER();
+
+ ifq_barrier(ifq); /* ensure nothing is running with the ifq */
/* don't need to lock because this is the last use of the ifq */
Index: ifq.h
===================================================================
RCS file: /cvs/src/sys/net/ifq.h,v
retrieving revision 1.20
diff -u -p -r1.20 ifq.h
--- ifq.h 4 Jan 2018 11:02:57 -0000 1.20
+++ ifq.h 14 Mar 2018 02:58:13 -0000
@@ -25,6 +25,7 @@ struct ifq_ops;
struct ifqueue {
struct ifnet *ifq_if;
+ struct taskq *ifq_softnet;
union {
void *_ifq_softc;
/*
@@ -57,6 +58,7 @@ struct ifqueue {
struct mutex ifq_task_mtx;
struct task_list ifq_task_list;
void *ifq_serializer;
+ struct task ifq_bundle;
/* work to be serialised */
struct task ifq_start;
@@ -405,6 +407,7 @@ void ifq_attach(struct ifqueue *, cons
void ifq_destroy(struct ifqueue *);
void ifq_add_data(struct ifqueue *, struct if_data *);
int ifq_enqueue(struct ifqueue *, struct mbuf *);
+void ifq_start(struct ifqueue *);
struct mbuf *ifq_deq_begin(struct ifqueue *);
void ifq_deq_commit(struct ifqueue *, struct mbuf *);
void ifq_deq_rollback(struct ifqueue *, struct mbuf *);
@@ -438,12 +441,6 @@ static inline unsigned int
ifq_is_oactive(struct ifqueue *ifq)
{
return (ifq->ifq_oactive);
-}
-
-static inline void
-ifq_start(struct ifqueue *ifq)
-{
- ifq_serialize(ifq, &ifq->ifq_start);
}
static inline void