Unlocking the forwarding path will allow us to gain in latency because
the rest of the kernel will be able to run on another CPU while an
incoming packet is being processed.

However to make use of SMP to improve forwarding performances we will
have to run multiple instances of the incoming path in parallel.  This
is currently impossible because we're using a single task in a single
task queue.

Diff below is another small step in this direction.  It introduces a
per-ifp task.  These tasks are still serialized because they're still
running on a single task queue, but we do not lose the information of
which ``ifp'' a mbuf is coming from.  That mean we need fewer if_get()
per packet and we can think of batching more packets.

Comments? Oks?


Index: net/if.c
===================================================================
RCS file: /cvs/src/sys/net/if.c,v
retrieving revision 1.437
diff -u -p -r1.437 if.c
--- net/if.c    11 Aug 2016 00:58:22 -0000      1.437
+++ net/if.c    29 Aug 2016 13:25:17 -0000
@@ -223,8 +223,6 @@ int ifq_congestion;
 int             netisr;
 struct taskq   *softnettq;
 
-struct mbuf_queue if_input_queue = MBUF_QUEUE_INITIALIZER(8192, IPL_NET);
-struct task if_input_task = TASK_INITIALIZER(if_input_process, 
&if_input_queue);
 struct task if_input_task_locked = TASK_INITIALIZER(if_netisr, NULL);
 
 /*
@@ -419,6 +417,10 @@ if_attachsetup(struct ifnet *ifp)
        if_idxmap_insert(ifp);
        KASSERT(if_get(0) == NULL);
 
+       mq_init(&ifp->if_inputqueue, 8192, IPL_NET);
+       task_set(ifp->if_inputtask, if_input_process,
+           (void *)(unsigned long)ifp->if_index);
+
        /* Announce the interface. */
        rt_ifannouncemsg(ifp, IFAN_ARRIVAL);
 }
@@ -535,6 +537,8 @@ if_attach_common(struct ifnet *ifp)
            M_TEMP, M_WAITOK|M_ZERO);
        ifp->if_linkstatetask = malloc(sizeof(*ifp->if_linkstatetask),
            M_TEMP, M_WAITOK|M_ZERO);
+       ifp->if_inputtask = malloc(sizeof(*ifp->if_inputtask),
+           M_TEMP, M_WAITOK|M_ZERO);
        ifp->if_llprio = IFQ_DEFPRIO;
 
        SRPL_INIT(&ifp->if_inputs);
@@ -632,8 +636,8 @@ if_input(struct ifnet *ifp, struct mbuf_
        }
 #endif
 
-       mq_enlist(&if_input_queue, ml);
-       task_add(softnettq, &if_input_task);
+       mq_enlist(&ifp->if_inputqueue, ml);
+       task_add(softnettq, ifp->if_inputtask);
 }
 
 int
@@ -776,30 +780,28 @@ if_ih_remove(struct ifnet *ifp, int (*in
 }
 
 void
-if_input_process(void *xmq)
+if_input_process(void *xifidx)
 {
-       struct mbuf_queue *mq = xmq;
+       unsigned int ifidx = (unsigned long)xifidx;
        struct mbuf_list ml;
-       struct mbuf *m;
        struct ifnet *ifp;
+       struct mbuf *m;
        struct ifih *ifih;
        struct srp_ref sr;
        int s;
 
-       mq_delist(mq, &ml);
-       if (ml_empty(&ml))
+       ifp = if_get(ifidx);
+       if (ifp == NULL)
                return;
 
+       mq_delist(&ifp->if_inputqueue, &ml);
+       if (ml_empty(&ml))
+               goto out;
+
        add_net_randomness(ml_len(&ml));
 
        s = splnet();
        while ((m = ml_dequeue(&ml)) != NULL) {
-               ifp = if_get(m->m_pkthdr.ph_ifidx);
-               if (ifp == NULL) {
-                       m_freem(m);
-                       continue;
-               }
-
                /*
                 * Pass this mbuf to all input handlers of its
                 * interface until it is consumed.
@@ -812,10 +814,11 @@ if_input_process(void *xmq)
 
                if (ifih == NULL)
                        m_freem(m);
-
-               if_put(ifp);
        }
        splx(s);
+
+out:
+       if_put(ifp);
 }
 
 void
@@ -920,6 +923,10 @@ if_detach(struct ifnet *ifp)
        ifp->if_ioctl = if_detached_ioctl;
        ifp->if_watchdog = NULL;
 
+       /* Remove the input task */
+       task_del(systq, ifp->if_inputtask);
+       mq_purge(&ifp->if_inputqueue);
+
        /* Remove the watchdog timeout & task */
        timeout_del(ifp->if_slowtimo);
        task_del(systq, ifp->if_watchdogtask);
@@ -974,6 +981,7 @@ if_detach(struct ifnet *ifp)
        free(ifp->if_slowtimo, M_TEMP, sizeof(*ifp->if_slowtimo));
        free(ifp->if_watchdogtask, M_TEMP, sizeof(*ifp->if_watchdogtask));
        free(ifp->if_linkstatetask, M_TEMP, sizeof(*ifp->if_linkstatetask));
+       free(ifp->if_inputtask, M_TEMP, sizeof(*ifp->if_inputtask));
 
        for (i = 0; (dp = domains[i]) != NULL; i++) {
                if (dp->dom_ifdetach && ifp->if_afdata[dp->dom_family])
Index: net/if_var.h
===================================================================
RCS file: /cvs/src/sys/net/if_var.h,v
retrieving revision 1.72
diff -u -p -r1.72 if_var.h
--- net/if_var.h        10 Jun 2016 20:33:29 -0000      1.72
+++ net/if_var.h        29 Aug 2016 13:01:45 -0000
@@ -137,6 +137,8 @@ struct ifnet {                              /* and the 
entries */
        struct  task *if_linkstatetask; /* task to do route updates */
 
        /* procedure handles */
+       struct mbuf_queue if_inputqueue;
+       struct task *if_inputtask;      /* input task */
        SRPL_HEAD(, ifih) if_inputs;    /* input routines (dequeue) */
 
                                        /* output routine (enqueue) */

Reply via email to