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

Reply via email to