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) */